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:
Allan Shortlidge
2024-08-23 14:05:31 -07:00
parent 4921eaf92f
commit 1c9b6eb723
3 changed files with 50 additions and 2 deletions

View File

@@ -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);

View File

@@ -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}}
}

View File

@@ -4,4 +4,10 @@ struct IdentifiableValue: Identifiable {
let id = 42
}
class IdentifiableClass: Identifiable {}
class IdentifiableClass: Identifiable {}
extension IdentifiableValue {
var nextID: ID {
return id + 1
}
}