Files
swift-mirror/test/Availability/availability_scopes.swift
Allan Shortlidge a3fbe3d530 AST: Introduce queries on Decl for active @available attrs.
Use these queries to replace some duplicated code. Also, move the
`attr_inlinable_available.swift` test to the `Availability` sub-directory since
the test has more to do with availability checking than it has to do
specifically with the `@inlinable` attr.
2025-07-18 13:27:08 -07:00

478 lines
15 KiB
Swift

// RUN: %target-swift-frontend -typecheck -dump-availability-scopes %s -target %target-cpu-apple-macos50 -swift-version 5 > %t.dump 2>&1
// RUN: %FileCheck --strict-whitespace %s < %t.dump
// REQUIRES: OS=macosx
// CHECK: {{^}}(root version=50
// CHECK-NEXT: {{^}} (decl version=51 decl=SomeClass
// CHECK-NEXT: {{^}} (decl version=52 decl=someMethod()
// CHECK-NEXT: {{^}} (decl version=53 decl=someInnerFunc()
// CHECK-NEXT: {{^}} (decl version=53 decl=InnerClass
// CHECK-NEXT: {{^}} (decl version=54 decl=innerClassMethod
// CHECK-NEXT: {{^}} (decl_implicit version=51 decl=someStaticProperty
// CHECK-NEXT: {{^}} (decl version=52 decl=someStaticProperty
// CHECK-NEXT: {{^}} (decl_implicit version=51 decl=someStaticPropertyInferredType
// CHECK-NEXT: {{^}} (decl version=52 decl=someStaticPropertyInferredType
// CHECK-NEXT: {{^}} (decl_implicit version=51 decl=multiPatternStaticPropertyA
// CHECK-NEXT: {{^}} (decl version=52 decl=multiPatternStaticPropertyA
// CHECK-NEXT: {{^}} (decl_implicit version=51 decl=someComputedProperty
// CHECK-NEXT: {{^}} (decl version=52 decl=someComputedProperty
// CHECK-NEXT: {{^}} (decl version=52 decl=someOtherMethod()
@available(OSX 51, *)
class SomeClass {
@available(OSX 52, *)
func someMethod() {
@available(OSX 53, *)
func someInnerFunc() { }
@available(OSX 53, *)
class InnerClass {
@available(OSX 54, *)
func innerClassMethod() { }
}
}
func someUnrefinedMethod() { }
@available(OSX 52, *)
static var someStaticProperty: Int = 7
@available(OSX 52, *)
static var someStaticPropertyInferredType = 7
@available(OSX 52, *)
static var multiPatternStaticPropertyA = 7,
multiPatternStaticPropertyB = 8
@available(OSX 52, *)
var someComputedProperty: Int {
get { }
set(v) { }
}
@available(OSX 52, *)
func someOtherMethod() { }
}
// CHECK-NEXT: {{^}} (decl version=51 decl=someFunction()
@available(OSX 51, *)
func someFunction() { }
// CHECK-NEXT: {{^}} (decl version=51 decl=SomeProtocol
// CHECK-NEXT: {{^}} (decl version=52 decl=protoMethod()
// CHECK-NEXT: {{^}} (decl_implicit version=51 decl=protoProperty
// CHECK-NEXT: {{^}} (decl version=52 decl=protoProperty
@available(OSX 51, *)
protocol SomeProtocol {
@available(OSX 52, *)
func protoMethod() -> Int
@available(OSX 52, *)
var protoProperty: Int { get }
}
// CHECK-NEXT: {{^}} (decl_implicit version=50 decl=extension.SomeClass
// CHECK-NEXT: {{^}} (decl version=51 decl=extension.SomeClass
// CHECK-NEXT: {{^}} (decl version=52 decl=someExtensionFunction()
@available(OSX 51, *)
extension SomeClass {
@available(OSX 52, *)
func someExtensionFunction() { }
}
// CHECK-NEXT: {{^}} (decl version=51 decl=functionWithStmtCondition
// CHECK-NEXT: {{^}} (condition_following_availability version=52
// CHECK-NEXT: {{^}} (condition_following_availability version=53
// CHECK-NEXT: {{^}} (if_then version=53
// CHECK-NEXT: {{^}} (condition_following_availability version=54
// CHECK-NEXT: {{^}} (if_then version=54
// CHECK-NEXT: {{^}} (condition_following_availability version=55
// CHECK-NEXT: {{^}} (decl version=55 decl=funcInGuardElse()
// CHECK-NEXT: {{^}} (guard_fallthrough version=55
// CHECK-NEXT: {{^}} (condition_following_availability version=56
// CHECK-NEXT: {{^}} (guard_fallthrough version=56
// CHECK-NEXT: {{^}} (decl version=57 decl=funcInInnerIfElse()
// CHECK-NEXT: {{^}} (decl version=53 decl=funcInOuterIfElse()
@available(OSX 51, *)
func functionWithStmtCondition() {
if #available(OSX 52, *),
let x = (nil as Int?),
#available(OSX 53, *) {
if #available(OSX 54, *) {
guard #available(OSX 55, *) else {
@available(OSX 55, *)
func funcInGuardElse() { }
}
guard #available(OSX 56, *) else { }
} else {
@available(OSX 57, *)
func funcInInnerIfElse() { }
}
} else {
@available(OSX 53, *)
func funcInOuterIfElse() { }
}
}
// CHECK-NEXT: {{^}} (decl version=51 decl=functionWithUnnecessaryStmtCondition
// CHECK-NEXT: {{^}} (condition_following_availability version=53
// CHECK-NEXT: {{^}} (if_then version=53
// CHECK-NEXT: {{^}} (condition_following_availability version=54
// CHECK-NEXT: {{^}} (if_then version=54
@available(OSX 51, *)
func functionWithUnnecessaryStmtCondition() {
// Shouldn't introduce availability scope for then branch when unnecessary
if #available(OSX 51, *) {
}
if #available(OSX 10.9, *) {
}
// Nested in conjunctive statement condition
if #available(OSX 53, *),
let x = (nil as Int?),
#available(OSX 52, *) {
}
if #available(OSX 54, *),
#available(OSX 54, *) {
}
// Wildcard is same as minimum deployment target
if #available(iOS 7.0, *) {
}
}
// CHECK-NEXT: {{^}} (decl version=51 decl=functionWithUnnecessaryStmtConditionsHavingElseBranch
// CHECK-NEXT: {{^}} (if_else version=none
// CHECK-NEXT: {{^}} (decl version=none decl=funcInInnerIfElse()
// CHECK-NEXT: {{^}} (if_else version=none
// CHECK-NEXT: {{^}} (guard_else version=none
// CHECK-NEXT: {{^}} (guard_else version=none
// CHECK-NEXT: {{^}} (if_else version=none
@available(OSX 51, *)
func functionWithUnnecessaryStmtConditionsHavingElseBranch(p: Int?) {
// Else branch context version is bottom when check is unnecessary
if #available(OSX 51, *) {
} else {
if #available(OSX 52, *) {
}
@available(OSX 52, *)
func funcInInnerIfElse() { }
if #available(iOS 7.0, *) {
} else {
}
}
if #available(iOS 7.0, *) {
} else {
}
guard #available(iOS 8.0, *) else { }
// Else branch will execute if p is nil, so it is not dead.
if #available(iOS 7.0, *),
let x = p {
} else {
}
if #available(iOS 7.0, *),
let x = p,
#available(iOS 7.0, *) {
} else {
}
// Else branch is dead
guard #available(iOS 7.0, *),
#available(iOS 8.0, *) else { }
if #available(OSX 51, *),
#available(OSX 51, *) {
} else {
}
}
// CHECK-NEXT: {{^}} (decl version=51 decl=functionWithWhile()
// CHECK-NEXT: {{^}} (condition_following_availability version=52
// CHECK-NEXT: {{^}} (while_body version=52
// CHECK-NEXT: {{^}} (decl version=54 decl=funcInWhileBody()
@available(OSX 51, *)
func functionWithWhile() {
while #available(OSX 52, *),
let x = (nil as Int?) {
@available(OSX 54, *)
func funcInWhileBody() { }
}
}
// CHECK-NEXT: {{^}} (decl version=51 decl=functionWithDefer()
// CHECK-NEXT: {{^}} (condition_following_availability version=52
// CHECK-NEXT: {{^}} (if_then version=52
@available(OSX 51, *)
func functionWithDefer() {
defer {
if #available(OSX 52, *) {}
}
}
// CHECK-NEXT: {{^}} (decl_implicit version=50 decl=extension.SomeClass
// CHECK-NEXT: {{^}} (decl version=51 decl=extension.SomeClass
// CHECK-NEXT: {{^}} (decl_implicit version=51 decl=someStaticPropertyWithClosureInit
// CHECK-NEXT: {{^}} (decl version=52 decl=someStaticPropertyWithClosureInit
// CHECK-NEXT: {{^}} (condition_following_availability version=54
// CHECK-NEXT: {{^}} (if_then version=54
// CHECK-NEXT: {{^}} (decl_implicit version=51 decl=someStaticPropertyWithClosureInitInferred
// CHECK-NEXT: {{^}} (decl version=52 decl=someStaticPropertyWithClosureInitInferred
// CHECK-NEXT: {{^}} (condition_following_availability version=54
// CHECK-NEXT: {{^}} (if_then version=54
@available(OSX 51, *)
extension SomeClass {
@available(OSX 52, *)
static var someStaticPropertyWithClosureInit: Int = {
if #available(OSX 54, *) {
return 54
}
return 53
}()
@available(OSX 52, *)
static var someStaticPropertyWithClosureInitInferred = {
if #available(OSX 54, *) {
return 54
}
return 53
}()
}
// CHECK-NEXT: {{^}} (decl_implicit version=50 decl=extension.SomeClass
// CHECK-NEXT: {{^}} (decl version=50 unavailable=macOS decl=extension.SomeClass
// CHECK-NEXT: {{^}} (decl version=50 unavailable=macOS decl=functionWithStmtConditionsInUnavailableExt()
// CHECK-NEXT: {{^}} (condition_following_availability version=52 unavailable=macOS
// CHECK-NEXT: {{^}} (condition_following_availability version=53 unavailable=macOS
// CHECK-NEXT: {{^}} (if_then version=53 unavailable=macOS
// CHECK-NEXT: {{^}} (condition_following_availability version=54 unavailable=macOS
// CHECK-NEXT: {{^}} (if_then version=54 unavailable=macOS
// CHECK-NEXT: {{^}} (condition_following_availability version=55 unavailable=macOS
// CHECK-NEXT: {{^}} (decl version=54 unavailable=macOS decl=funcInGuardElse()
// CHECK-NEXT: {{^}} (guard_fallthrough version=55 unavailable=macOS
// CHECK-NEXT: {{^}} (condition_following_availability version=56 unavailable=macOS
// CHECK-NEXT: {{^}} (guard_fallthrough version=56 unavailable=macOS
// CHECK-NEXT: {{^}} (decl version=53 unavailable=macOS decl=funcInInnerIfElse()
// CHECK-NEXT: {{^}} (decl version=50 unavailable=macOS decl=funcInOuterIfElse()
@available(OSX, unavailable)
extension SomeClass {
@available(OSX 51, *)
func functionWithStmtConditionsInUnavailableExt() {
if #available(OSX 52, *),
let x = (nil as Int?),
#available(OSX 53, *) {
if #available(OSX 54, *) {
guard #available(OSX 55, *) else {
@available(OSX 55, *)
func funcInGuardElse() { }
}
guard #available(OSX 56, *) else { }
} else {
@available(OSX 57, *)
func funcInInnerIfElse() { }
}
} else {
@available(OSX 53, *)
func funcInOuterIfElse() { }
}
}
}
// CHECK-NEXT: {{^}} (decl_implicit version=50 decl=wrappedValue
@propertyWrapper
struct Wrapper<T> {
var wrappedValue: T
}
// CHECK-NEXT: {{^}} (decl version=51 decl=SomeStruct
// CHECK-NEXT: {{^}} (decl_implicit version=51 decl=someLazyVar
// CHECK-NEXT: {{^}} (condition_following_availability version=52
// CHECK-NEXT: {{^}} (guard_fallthrough version=52
// CHECK-NEXT: {{^}} (decl_implicit version=51 decl=someWrappedVar
// CHECK-NEXT: {{^}} (condition_following_availability version=52
// CHECK-NEXT: {{^}} (guard_fallthrough version=52
// CHECK-NEXT: {{^}} (decl version=52 decl=someMethodAvailable52()
@available(OSX 51, *)
struct SomeStruct {
lazy var someLazyVar = {
guard #available(OSX 52, *) else {
return someMethod()
}
return someMethodAvailable52()
}()
@Wrapper var someWrappedVar = {
guard #available(OSX 52, *) else {
return 51
}
return 52
}()
func someMethod() -> Int { return 51 }
@available(OSX 52, *)
func someMethodAvailable52() -> Int { return 52 }
}
// CHECK-NEXT: {{^}} (decl version=51 decl=SomeEnum
// CHECK-NEXT: {{^}} (decl version=52 decl=a
// CHECK-NEXT: {{^}} (decl version=53 decl=b
@available(OSX 51, *)
enum SomeEnum {
@available(OSX 52, *)
case a
@available(OSX 53, *)
case b, c
}
// CHECK-NEXT: {{^}} (decl_implicit version=50 decl=someComputedGlobalVar
// CHECK-NEXT: {{^}} (decl version=51 decl=_
// CHECK-NEXT: {{^}} (decl version=52 decl=_
var someComputedGlobalVar: Int {
@available(OSX 51, *)
get { 1 }
@available(OSX 52, *)
set { }
}
// CHECK-NEXT: {{^}} (decl_implicit version=50 decl=interpolated
// CHECK-NEXT: {{^}} (decl_implicit version=50 decl=string
func testStringInterpolation() {
let interpolated = """
\([""].map {
let string = $0
return string
})
"""
}
// CHECK-NEXT: {{^}} (decl_implicit version=50 decl=result
// CHECK-NEXT: {{^}} (decl_implicit version=50 decl=unusedA
// CHECK-NEXT: {{^}} (decl_implicit version=50 decl=unusedB
func testSequenceExprs(b: Bool, x: Int?) {
let result = b
? x.map {
let unusedA: Int
return $0
}
: x.map {
let unusedB: Int
return $0
}
}
// CHECK-NEXT: {{^}} (decl version=50 unavailable=macOS decl=unavailableOnMacOS()
// CHECK-NEXT: {{^}} (decl_implicit version=50 unavailable=macOS decl=x
@available(macOS, unavailable)
func unavailableOnMacOS() {
let x = 1
}
// CHECK-NEXT: {{^}} (decl_implicit version=50 decl=extension.SomeEnum
// CHECK-NEXT: {{^}} (decl version=51 decl=extension.SomeEnum
// CHECK-NEXT: {{^}} (decl_implicit version=51 decl=unavailableOnMacOS
// CHECK-NEXT: {{^}} (decl version=51 unavailable=macOS decl=unavailableOnMacOS
@available(OSX 51, *)
extension SomeEnum {
@available(macOS, unavailable)
var unavailableOnMacOS: Int { 1 }
}
// CHECK-NEXT: {{^}} (decl_implicit version=50 decl=extension.SomeEnum
// CHECK-NEXT: {{^}} (decl version=50 unavailable=macOS decl=extension.SomeEnum
// CHECK-NEXT: {{^}} (decl_implicit version=50 unavailable=macOS decl=availableMacOS_52
// CHECK-NEXT: {{^}} (decl version=50 unavailable=macOS decl=availableMacOS_52
// CHECK-NEXT: {{^}} (decl version=50 unavailable=* decl=neverAvailable()
@available(macOS, unavailable)
extension SomeEnum {
@available(OSX 52, *)
var availableMacOS_52: Int { 1 }
@available(macOSApplicationExtension, unavailable)
func unavailableInAppExtensions() {}
@available(*, unavailable)
func neverAvailable() {}
}
// CHECK-NEXT: {{^}} (decl version=50 unavailable=macOS decl=unavailableOnMacOSAndIntroduced()
@available(macOS, unavailable)
@available(macOS, introduced: 52)
func unavailableOnMacOSAndIntroduced() {
}
// CHECK-NEXT: {{^}} (decl version=50 unavailable=macOS decl=introducedOnMacOSAndUnavailable()
@available(macOS, introduced: 53)
@available(macOS, unavailable)
func introducedOnMacOSAndUnavailable() {
}
// CHECK-NEXT: {{^}} (decl version=50 unavailable=macOS decl=unavailableOnMacOSAndIntroducedSameAttr()
@available(macOS, unavailable, introduced: 54)
func unavailableOnMacOSAndIntroducedSameAttr() {
}
// CHECK-NEXT: {{^}} (decl version=50 unavailable=* decl=NeverAvailable
// CHECK-NEXT: {{^}} (decl version=50 unavailable=* decl=unavailableOnMacOS()
@available(*, unavailable)
struct NeverAvailable {
@available(macOS, unavailable)
func unavailableOnMacOS() {}
}
// CHECK-NEXT: {{^}} (decl version=50 deprecated decl=deprecatedOnMacOS()
// CHECK-NEXT: {{^}} (decl_implicit version=50 deprecated decl=x
@available(macOS, deprecated)
func deprecatedOnMacOS() {
let x = 1
}
// Since availableOniOS() doesn't have any active @available attributes it
// shouldn't create a scope.
// CHECK-NOT: availableOniOS
@available(iOS, introduced: 53)
func availableOniOS() { }
// CHECK-NEXT: {{^}} (decl version=50 decl=availableInSwift5
@available(swift 5)
func availableInSwift5() { }
// CHECK-NEXT: {{^}} (decl version=50 unavailable=swift decl=availableInSwift6
@available(swift 6)
func availableInSwift6() { }
// CHECK-NEXT: {{^}} (decl version=51 decl=FinalDecl
@available(OSX 51, *)
typealias FinalDecl = Int