Skip to content

Commit cfd2e86

Browse files
committed
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 #71496. Resolves rdar://134584323
1 parent 6e27990 commit cfd2e86

File tree

3 files changed

+50
-2
lines changed

3 files changed

+50
-2
lines changed

lib/Sema/AssociatedTypeInference.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,18 @@ static void recordTypeWitness(NormalProtocolConformance *conformance,
331331

332332
// Construct the availability of the type witnesses based on the
333333
// availability of the enclosing type and the associated type.
334-
const Decl *availabilitySources[2] = { dc->getAsDecl(), assocType };
334+
llvm::SmallVector<Decl *, 2> availabilitySources = {dc->getAsDecl()};
335+
336+
// Only constrain the availability of the typealias by the availability of
337+
// the associated type if the associated type is less available than its
338+
// protocol. This is required for source compatibility.
339+
auto protoAvailability = AvailabilityInference::availableRange(proto, ctx);
340+
auto assocTypeAvailability =
341+
AvailabilityInference::availableRange(assocType, ctx);
342+
if (protoAvailability.isSupersetOf(assocTypeAvailability)) {
343+
availabilitySources.push_back(assocType);
344+
}
345+
335346
AvailabilityInference::applyInferredAvailableAttrs(
336347
aliasDecl, availabilitySources, ctx);
337348

test/decl/protocol/associated_type_availability.swift

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,34 @@ func testPrimaryExistentialBad<U>(_: any P1<Int, U>) {}
5353

5454
@available(macOS 13, *)
5555
func testPrimaryExistentialGood<U>(_: any P1<Int, U>) {}
56+
57+
58+
@available(macOS 13, *)
59+
protocol P2 {
60+
associatedtype A
61+
62+
@available(macOS 14, *)
63+
associatedtype B
64+
65+
var a: A { get }
66+
67+
@available(macOS 14, *)
68+
var b: B { get }
69+
}
70+
71+
struct ModelP2: P2 {
72+
var a: Int
73+
var b: Double
74+
}
75+
76+
extension ModelP2 {
77+
// expected-note@-1{{add @available attribute to enclosing extension}}
78+
79+
// Ok, the inferred typealias for A is always available.
80+
func takesA(_ a: A) {}
81+
82+
// Bad, the inferred typealias for B is introduced with associated type B.
83+
func takesB(_ b: B) {}
84+
// expected-error@-1{{'B' is only available in macOS 14 or newer}}
85+
// expected-note@-2{{add @available attribute to enclosing instance method}}
86+
}

test/stdlib/Identifiable.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,10 @@ struct IdentifiableValue: Identifiable {
44
let id = 42
55
}
66

7-
class IdentifiableClass: Identifiable {}
7+
class IdentifiableClass: Identifiable {}
8+
9+
extension IdentifiableValue {
10+
var nextID: ID {
11+
return id + 1
12+
}
13+
}

0 commit comments

Comments
 (0)