AST: Allow obsoletion in Swift version to disambiguate overloads consistently.

It must be possible to disambiguate overloads using the module-wide Swift
language version, even in contexts that are themselves obsolete in the current
Swift language version.

Resolves rdar://158620835.
This commit is contained in:
Allan Shortlidge
2025-08-18 15:37:14 -07:00
parent de82e315a5
commit 5ae0ad6a8f
3 changed files with 69 additions and 54 deletions

View File

@@ -155,20 +155,20 @@ static bool canIgnoreConstraintInUnavailableContexts(
const AvailabilityConstraintFlags flags) {
auto domain = constraint.getDomain();
switch (constraint.getReason()) {
case AvailabilityConstraint::Reason::UnavailableUnconditionally:
if (flags.contains(AvailabilityConstraintFlag::
AllowUniversallyUnavailableInCompatibleContexts))
return true;
// Always reject uses of universally unavailable declarations, regardless
// of context, since there are no possible compilation configurations in
// which they are available. However, make an exception for types and
// conformances, which can sometimes be awkward to avoid references to.
// Always reject uses of universally unavailable declarations, regardless
// of context, since there are no possible compilation configurations in
// which they are available. However, make an exception for types and
// conformances, which can sometimes be awkward to avoid references to.
if (!flags.contains(AvailabilityConstraintFlag::
AllowUniversallyUnavailableInCompatibleContexts)) {
if (!isa<TypeDecl>(decl) && !isa<ExtensionDecl>(decl)) {
if (domain.isUniversal() || domain.isSwiftLanguage())
return false;
}
}
switch (constraint.getReason()) {
case AvailabilityConstraint::Reason::UnavailableUnconditionally:
return true;
case AvailabilityConstraint::Reason::Unintroduced:

View File

@@ -52,19 +52,34 @@ public class BeforeAndAfter {
// Make sure we can generate calls to these overloads, too
_ = BeforeAndAfter(foo: ())
_ = try BeforeAndAfter()
_ = try BeforeAndAfter.foo()
_ = BeforeAndAfter.computed
BeforeAndAfter.computed = 10
_ = try BeforeAndAfter().computed
try BeforeAndAfter().computed = 10
public func testLocal() throws {
_ = BeforeAndAfter(foo: ())
_ = try BeforeAndAfter()
_ = try BeforeAndAfter.foo()
_ = BeforeAndAfter.computed
BeforeAndAfter.computed = 10
_ = try BeforeAndAfter().computed
try BeforeAndAfter().computed = 10
}
@available(swift, obsoleted: 4.0)
public func testLocalObsoleted() throws {
_ = BeforeAndAfter(foo: ())
_ = try BeforeAndAfter()
_ = try BeforeAndAfter.foo()
_ = BeforeAndAfter.computed
BeforeAndAfter.computed = 10
_ = try BeforeAndAfter().computed
try BeforeAndAfter().computed = 10
}
// Same thing but in a different module
_ = BeforeAndAfterOther(foo: ())
_ = try BeforeAndAfterOther()
_ = try BeforeAndAfterOther.foo()
_ = BeforeAndAfterOther.computed
BeforeAndAfterOther.computed = 10
_ = try BeforeAndAfterOther().computed
try BeforeAndAfterOther().computed = 10
public func testOtherModule() throws {
_ = BeforeAndAfterOther(foo: ())
_ = try BeforeAndAfterOther()
_ = try BeforeAndAfterOther.foo()
_ = BeforeAndAfterOther.computed
BeforeAndAfterOther.computed = 10
_ = try BeforeAndAfterOther().computed
try BeforeAndAfterOther().computed = 10
}

View File

@@ -59,8 +59,8 @@ func never_available_func(
) {
always()
never() // expected-error {{'never()' is unavailable}}
unavailableInSwift4()
availableInFutureSwift()
unavailableInSwift4() // expected-error {{'unavailableInSwift4()' is unavailable}}
availableInFutureSwift() // expected-error {{'availableInFutureSwift()' is unavailable in Swift}}
}
@available(swift, obsoleted: 4)
@@ -72,8 +72,8 @@ func unavailable_in_swift4_func(
) {
always()
never() // expected-error {{'never()' is unavailable}}
unavailableInSwift4()
availableInFutureSwift()
unavailableInSwift4() // expected-error {{'unavailableInSwift4()' is unavailable}}
availableInFutureSwift() // expected-error {{'availableInFutureSwift()' is unavailable in Swift}}
}
@available(swift, introduced: 99)
@@ -85,8 +85,8 @@ func introduced_in_future_swift_func(
) {
always()
never() // expected-error {{'never()' is unavailable}}
unavailableInSwift4()
availableInFutureSwift()
unavailableInSwift4() // expected-error {{'unavailableInSwift4()' is unavailable}}
availableInFutureSwift() // expected-error {{'availableInFutureSwift()' is unavailable in Swift}}
}
// MARK: Global vars
@@ -112,8 +112,8 @@ var never_var: (
) = (
always(),
never(), // expected-error {{'never()' is unavailable}}
unavailableInSwift4(),
availableInFutureSwift(),
unavailableInSwift4(), // expected-error {{'unavailableInSwift4()' is unavailable}}
availableInFutureSwift(), // expected-error {{'availableInFutureSwift()' is unavailable in Swift}}
)
@available(swift, obsoleted: 4)
@@ -125,8 +125,8 @@ var unavailable_in_swift4_var: (
) = (
always(),
never(), // expected-error {{'never()' is unavailable}}
unavailableInSwift4(),
availableInFutureSwift(),
unavailableInSwift4(), // expected-error {{'unavailableInSwift4()' is unavailable}}
availableInFutureSwift(), // expected-error {{'availableInFutureSwift()' is unavailable in Swift}}
)
@available(swift, introduced: 99)
@@ -138,8 +138,8 @@ var available_in_future_swift_var: (
) = (
always(),
never(), // expected-error {{'never()' is unavailable}}
unavailableInSwift4(),
availableInFutureSwift(),
unavailableInSwift4(), // expected-error {{'unavailableInSwift4()' is unavailable}}
availableInFutureSwift(), // expected-error {{'availableInFutureSwift()' is unavailable in Swift}}
)
@@ -159,8 +159,8 @@ struct AlwaysAvailableContainer {
struct NeverAvailableContainer { // expected-note 3 {{'NeverAvailableContainer' has been explicitly marked unavailable here}}
let always_var: AlwaysAvailable = always()
let never_var: NeverAvailable = never() // expected-error {{'never()' is unavailable}}
let unavailable_in_swift4_var: UnavailableInSwift4 = unavailableInSwift4()
let available_in_future_swift_var: AvailableInFutureSwift = availableInFutureSwift()
let unavailable_in_swift4_var: UnavailableInSwift4 = unavailableInSwift4() // expected-error {{'unavailableInSwift4()' is unavailable}}
let available_in_future_swift_var: AvailableInFutureSwift = availableInFutureSwift() // expected-error {{'availableInFutureSwift()' is unavailable in Swift}}
}
@available(swift, obsoleted: 4)
@@ -168,8 +168,8 @@ struct UnavailableInSwift4Container { // expected-note {{'UnavailableInSwift4Con
let always_var: AlwaysAvailable = always()
let never_var: NeverAvailable = never() // expected-error {{'never()' is unavailable}}
// expected-error@-1 {{'NeverAvailable' is unavailable}}
let unavailable_in_swift4_var: UnavailableInSwift4 = unavailableInSwift4()
let available_in_future_swift_var: AvailableInFutureSwift = availableInFutureSwift()
let unavailable_in_swift4_var: UnavailableInSwift4 = unavailableInSwift4() // expected-error {{'unavailableInSwift4()' is unavailable}}
let available_in_future_swift_var: AvailableInFutureSwift = availableInFutureSwift() // expected-error {{'availableInFutureSwift()' is unavailable in Swift}}
}
@available(swift, introduced: 99)
@@ -177,8 +177,8 @@ struct AvailableInFutureSwiftContainer { // expected-note {{'AvailableInFutureSw
let always_var: AlwaysAvailable = always()
let never_var: NeverAvailable = never() // expected-error {{'never()' is unavailable}}
// expected-error@-1 {{'NeverAvailable' is unavailable}}
let unavailable_in_swift4_var: UnavailableInSwift4 = unavailableInSwift4()
let available_in_future_swift_var: AvailableInFutureSwift = availableInFutureSwift()
let unavailable_in_swift4_var: UnavailableInSwift4 = unavailableInSwift4() // expected-error {{'unavailableInSwift4()' is unavailable}}
let available_in_future_swift_var: AvailableInFutureSwift = availableInFutureSwift() // expected-error {{'availableInFutureSwift()' is unavailable in Swift}}
}
// MARK: Extensions
@@ -229,8 +229,8 @@ extension ExtendMe {
) {
always()
never() // expected-error {{'never()' is unavailable}}
unavailableInSwift4()
availableInFutureSwift()
unavailableInSwift4() // expected-error {{'unavailableInSwift4()' is unavailable}}
availableInFutureSwift() // expected-error {{'availableInFutureSwift()' is unavailable in Swift}}
}
@available(*, unavailable)
@@ -242,8 +242,8 @@ extension ExtendMe {
) {
always()
never() // expected-error {{'never()' is unavailable}}
unavailableInSwift4()
availableInFutureSwift()
unavailableInSwift4() // expected-error {{'unavailableInSwift4()' is unavailable}}
availableInFutureSwift() // expected-error {{'availableInFutureSwift()' is unavailable in Swift}}
}
@available(swift, obsoleted: 4)
@@ -255,8 +255,8 @@ extension ExtendMe {
) {
always()
never() // expected-error {{'never()' is unavailable}}
unavailableInSwift4()
availableInFutureSwift()
unavailableInSwift4() // expected-error {{'unavailableInSwift4()' is unavailable}}
availableInFutureSwift() // expected-error {{'availableInFutureSwift()' is unavailable in Swift}}
}
@available(swift, introduced: 99)
@@ -268,8 +268,8 @@ extension ExtendMe {
) {
always()
never() // expected-error {{'never()' is unavailable}}
unavailableInSwift4()
availableInFutureSwift()
unavailableInSwift4() // expected-error {{'unavailableInSwift4()' is unavailable}}
availableInFutureSwift() // expected-error {{'availableInFutureSwift()' is unavailable in Swift}}
}
}
@@ -286,8 +286,8 @@ extension ExtendMe {
) {
always()
never() // expected-error {{'never()' is unavailable}}
unavailableInSwift4()
availableInFutureSwift()
unavailableInSwift4() // expected-error {{'unavailableInSwift4()' is unavailable}}
availableInFutureSwift() // expected-error {{'availableInFutureSwift()' is unavailable in Swift}}
}
}
@@ -304,8 +304,8 @@ extension ExtendMe {
) {
always()
never() // expected-error {{'never()' is unavailable}}
unavailableInSwift4()
availableInFutureSwift()
unavailableInSwift4() // expected-error {{'unavailableInSwift4()' is unavailable}}
availableInFutureSwift() // expected-error {{'availableInFutureSwift()' is unavailable in Swift}}
}
}