mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Sema: Relax availability of typealiases for inferred type witness.
Only constrain the availability of the synthesized typealias for an inferred
type witness by the availability of the associated type if the associated type
is less available than its protocol. Without this, source compatibility is
broken for some conformances. For example:
```
struct IdentifiableValue: Identifiable {
let id = 42
}
extension IdentifiableValue {
// error: 'ID' is only available in macOS 10.15 or newer
var nextID: ID {
return id + 1
}
}
```
Fixes a regression introduced by https://github.com/swiftlang/swift/pull/71496.
Resolves rdar://134584323
This commit is contained in:
@@ -331,7 +331,18 @@ static void recordTypeWitness(NormalProtocolConformance *conformance,
|
||||
|
||||
// Construct the availability of the type witnesses based on the
|
||||
// availability of the enclosing type and the associated type.
|
||||
const Decl *availabilitySources[2] = { dc->getAsDecl(), assocType };
|
||||
llvm::SmallVector<Decl *, 2> availabilitySources = {dc->getAsDecl()};
|
||||
|
||||
// Only constrain the availability of the typealias by the availability of
|
||||
// the associated type if the associated type is less available than its
|
||||
// protocol. This is required for source compatibility.
|
||||
auto protoAvailability = AvailabilityInference::availableRange(proto, ctx);
|
||||
auto assocTypeAvailability =
|
||||
AvailabilityInference::availableRange(assocType, ctx);
|
||||
if (protoAvailability.isSupersetOf(assocTypeAvailability)) {
|
||||
availabilitySources.push_back(assocType);
|
||||
}
|
||||
|
||||
AvailabilityInference::applyInferredAvailableAttrs(
|
||||
aliasDecl, availabilitySources, ctx);
|
||||
|
||||
|
||||
@@ -53,3 +53,34 @@ func testPrimaryExistentialBad<U>(_: any P1<Int, U>) {}
|
||||
|
||||
@available(macOS 13, *)
|
||||
func testPrimaryExistentialGood<U>(_: any P1<Int, U>) {}
|
||||
|
||||
|
||||
@available(macOS 13, *)
|
||||
protocol P2 {
|
||||
associatedtype A
|
||||
|
||||
@available(macOS 14, *)
|
||||
associatedtype B
|
||||
|
||||
var a: A { get }
|
||||
|
||||
@available(macOS 14, *)
|
||||
var b: B { get }
|
||||
}
|
||||
|
||||
struct ModelP2: P2 {
|
||||
var a: Int
|
||||
var b: Double
|
||||
}
|
||||
|
||||
extension ModelP2 {
|
||||
// expected-note@-1{{add @available attribute to enclosing extension}}
|
||||
|
||||
// Ok, the inferred typealias for A is always available.
|
||||
func takesA(_ a: A) {}
|
||||
|
||||
// Bad, the inferred typealias for B is introduced with associated type B.
|
||||
func takesB(_ b: B) {}
|
||||
// expected-error@-1{{'B' is only available in macOS 14 or newer}}
|
||||
// expected-note@-2{{add @available attribute to enclosing instance method}}
|
||||
}
|
||||
|
||||
@@ -4,4 +4,10 @@ struct IdentifiableValue: Identifiable {
|
||||
let id = 42
|
||||
}
|
||||
|
||||
class IdentifiableClass: Identifiable {}
|
||||
class IdentifiableClass: Identifiable {}
|
||||
|
||||
extension IdentifiableValue {
|
||||
var nextID: ID {
|
||||
return id + 1
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user