Skip to content

Commit 26cc99d

Browse files
authored
Merge pull request #70735 from DougGregor/associated-type-availability
Enable availability attributes for associated types
2 parents 96faeb5 + 57f431d commit 26cc99d

10 files changed

+136
-3
lines changed

include/swift/AST/Attr.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ DECL_ATTR(_silgen_name, SILGenName,
108108
OnAbstractFunction | OnVar | LongAttribute | UserInaccessible | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
109109
0)
110110
DECL_ATTR(available, Available,
111-
OnAbstractFunction | OnGenericType | OnVar | OnSubscript | OnEnumElement | OnMacro | OnExtension | AllowMultipleAttributes | LongAttribute | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
111+
OnAbstractFunction | OnAssociatedType | OnGenericType | OnVar | OnSubscript | OnEnumElement | OnMacro | OnExtension | AllowMultipleAttributes | LongAttribute | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
112112
1)
113113
DECL_ATTR(objc, ObjC,
114114
OnAbstractFunction | OnClass | OnProtocol | OnExtension | OnVar | OnSubscript | OnEnum | OnEnumElement | ABIBreakingToAdd | ABIBreakingToRemove | APIStableToAdd | APIStableToRemove,

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2851,7 +2851,6 @@ WARNING(assoc_type_default_conformance_failed,none,
28512851
NOTE(assoc_type_default_here,none,
28522852
"associated type %0 has default type %1 written here",
28532853
(const AssociatedTypeDecl *, Type))
2854-
28552854
ERROR(protocol_access,none,
28562855
"%select{protocol must be declared %select{"
28572856
"%select{private|fileprivate|internal|package|%error|%error}1"
@@ -6837,6 +6836,10 @@ ERROR(inlinable_decl_not_public,
68376836
ERROR(inlinable_resilient_deinit,
68386837
none, "deinitializer can only be '@inlinable' if the class is '@_fixed_layout'", ())
68396838

6839+
ERROR(resilient_associated_type_less_available_requires_default,none,
6840+
"associated type %0 that is less available than its protocol must have a "
6841+
"default", (const AssociatedTypeDecl *))
6842+
68406843
//------------------------------------------------------------------------------
68416844
// MARK: @_specialize diagnostics
68426845
//------------------------------------------------------------------------------

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3874,10 +3874,16 @@ class TypeReprAvailabilityWalker : public ASTWalker {
38743874
DeclAvailabilityFlags flags;
38753875

38763876
bool checkIdentTypeRepr(IdentTypeRepr *ITR) {
3877+
ArrayRef<AssociatedTypeDecl *> primaryAssociatedTypes;
3878+
38773879
if (auto *typeDecl = ITR->getBoundDecl()) {
38783880
auto range = ITR->getNameLoc().getSourceRange();
38793881
if (diagnoseDeclAvailability(typeDecl, range, nullptr, where, flags))
38803882
return true;
3883+
3884+
if (auto protocol = dyn_cast<ProtocolDecl>(typeDecl)) {
3885+
primaryAssociatedTypes = protocol->getPrimaryAssociatedTypes();
3886+
}
38813887
}
38823888

38833889
bool foundAnyIssues = false;
@@ -3889,6 +3895,17 @@ class TypeReprAvailabilityWalker : public ASTWalker {
38893895
for (auto *genericArg : GTR->getGenericArgs()) {
38903896
if (diagnoseTypeReprAvailability(genericArg, where, genericFlags))
38913897
foundAnyIssues = true;
3898+
3899+
// The associated type that is being specified must be available as
3900+
// well.
3901+
if (!primaryAssociatedTypes.empty()) {
3902+
auto primaryAssociatedType = primaryAssociatedTypes.front();
3903+
primaryAssociatedTypes = primaryAssociatedTypes.drop_front();
3904+
if (diagnoseDeclAvailability(
3905+
primaryAssociatedType, genericArg->getSourceRange(),
3906+
nullptr, where, genericFlags))
3907+
foundAnyIssues = true;
3908+
}
38923909
}
38933910
}
38943911

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2866,6 +2866,16 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
28662866
AT->diagnose(diag::kind_declared_here, DescriptiveDeclKind::Type);
28672867
}
28682868
}
2869+
2870+
// An associated type that was introduced after the protocol
2871+
auto module = AT->getDeclContext()->getParentModule();
2872+
if (!defaultType &&
2873+
module->getResilienceStrategy() == ResilienceStrategy::Resilient &&
2874+
AvailabilityInference::availableRange(proto, Ctx)
2875+
.isSupersetOf(AvailabilityInference::availableRange(AT, Ctx))) {
2876+
AT->diagnose(
2877+
diag::resilient_associated_type_less_available_requires_default, AT);
2878+
}
28692879
}
28702880

28712881
void checkUnsupportedNestedType(NominalTypeDecl *NTD) {

test/IRGen/weak_import_associated_conformance_descriptor.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@ public protocol StrongProtoWithWeakLinkedAssoc {
1919
@_weakLinked associatedtype Assoc: P
2020
}
2121

22+
public struct LibConformsToP: P { }
23+
24+
public protocol StrongProtoWithNewAssoc {
25+
@available(macOS 10.50, *)
26+
associatedtype NewerAssoc: P = LibConformsToP
27+
}
28+
2229
@available(macOS 10.50, *)
2330
public protocol WeakProtoWithAssoc {
2431
associatedtype Assoc: P
@@ -40,11 +47,18 @@ struct ConformsToStrongProtoWithAssoc: StrongProtoWithAssoc {
4047
typealias Assoc = ConformsToP
4148
}
4249

50+
4351
// CHECK: @"$s7Library30StrongProtoWithWeakLinkedAssocP0G0AC_AA1PTn" = extern_weak global %swift.protocol_requirement, align 4
4452
struct ConformsToStrongProtoWithWeakLinkedAssoc: StrongProtoWithWeakLinkedAssoc {
4553
typealias Assoc = ConformsToP
4654
}
4755

56+
// CHECK: @"$s7Library23StrongProtoWithNewAssocP05NewerF0AC_AA1PTn" = extern_weak global %swift.protocol_requirement, align 4
57+
// CHECK: @"$s10NewerAssoc7Library018StrongProtoWithNewB0PTl" = extern_weak global %swift.protocol_requirement, align 4
58+
struct ConformsToStrongProtoWithNewAssoc: StrongProtoWithNewAssoc {
59+
typealias NewAssoc = ConformsToP
60+
}
61+
4862
// CHECK: @"$s7Library18WeakProtoWithAssocP0E0AC_AA1PTn" = extern_weak global %swift.protocol_requirement, align 4
4963
@available(macOS 10.50, *)
5064
struct ConformsToWeakProtoWithAssoc: WeakProtoWithAssoc {

test/Parse/invalid.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,5 +148,5 @@ class C_50734<@NSApplicationMain T: AnyObject> {} // expected-error {{@NSApplica
148148
func f6_50734<@discardableResult T>(x: T) {} // expected-error {{'@discardableResult' attribute cannot be applied to this declaration}}
149149
enum E_50734<@indirect T> {} // expected-error {{'indirect' is a declaration modifier, not an attribute}} expected-error {{'indirect' modifier cannot be applied to this declaration}}
150150
protocol P {
151-
@available(swift, introduced: 4.2) associatedtype Assoc // expected-error {{'@available' attribute cannot be applied to this declaration}}
151+
@available(swift, introduced: 4) associatedtype Assoc
152152
}

test/api-digester/Outputs/Cake-abi.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ cake: Accessor GlobalLetChangedToVar.Modify() is a new API without @available at
6161
cake: Accessor GlobalLetChangedToVar.Set() is a new API without @available attribute
6262
cake: Accessor fixedLayoutStruct2.BecomeFixedBinaryOrder.Modify() is a new API without @available attribute
6363
cake: Accessor fixedLayoutStruct2.BecomeFixedBinaryOrder.Set() is a new API without @available attribute
64+
cake: AssociatedType RequirementChanges.addedTypeWithDefault is a new API without @available attribute
65+
cake: AssociatedType RequirementChanges.addedTypeWithoutDefault is a new API without @available attribute
6466
cake: Class C0 is a new API without @available attribute
6567
cake: Class C8 is a new API without @available attribute
6668
cake: Constructor AddingNewDesignatedInit.init(_:) is a new API without @available attribute

test/attr/attr_inlinable_available.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1467,8 +1467,11 @@ public protocol NoAvailableProtoWithAssoc { // expected-note 3 {{add @available
14671467
associatedtype B: BeforeInliningTargetProto
14681468
associatedtype C: AtInliningTargetProto
14691469
associatedtype D: BetweenTargetsProto // expected-error {{'BetweenTargetsProto' is only available in macOS 10.14.5 or newer; clients of 'Test' may have a lower deployment target}}
1470+
// expected-note@-1{{add @available attribute to enclosing associated type}}
14701471
associatedtype E: AtDeploymentTargetProto // expected-error {{'AtDeploymentTargetProto' is only available in macOS 10.15 or newer; clients of 'Test' may have a lower deployment target}}
1472+
// expected-note@-1{{add @available attribute to enclosing associated type}}
14711473
associatedtype F: AfterDeploymentTargetProto // expected-error {{'AfterDeploymentTargetProto' is only available in}}
1474+
// expected-note@-1{{add @available attribute to enclosing associated type}}
14721475
}
14731476

14741477
@available(macOS 10.9, *)
@@ -1477,8 +1480,11 @@ public protocol BeforeInliningTargetProtoWithAssoc {
14771480
associatedtype B: BeforeInliningTargetProto
14781481
associatedtype C: AtInliningTargetProto
14791482
associatedtype D: BetweenTargetsProto // expected-error {{'BetweenTargetsProto' is only available in macOS 10.14.5 or newer; clients of 'Test' may have a lower deployment target}}
1483+
// expected-note@-1{{add @available attribute to enclosing associated type}}
14801484
associatedtype E: AtDeploymentTargetProto // expected-error {{'AtDeploymentTargetProto' is only available in macOS 10.15 or newer; clients of 'Test' may have a lower deployment target}}
1485+
// expected-note@-1{{add @available attribute to enclosing associated type}}
14811486
associatedtype F: AfterDeploymentTargetProto // expected-error {{'AfterDeploymentTargetProto' is only available in}}
1487+
// expected-note@-1{{add @available attribute to enclosing associated type}}
14821488
}
14831489

14841490
@available(macOS 10.10, *)
@@ -1487,8 +1493,11 @@ public protocol AtInliningTargetProtoWithAssoc {
14871493
associatedtype B: BeforeInliningTargetProto
14881494
associatedtype C: AtInliningTargetProto
14891495
associatedtype D: BetweenTargetsProto // expected-error {{'BetweenTargetsProto' is only available in macOS 10.14.5 or newer; clients of 'Test' may have a lower deployment target}}
1496+
// expected-note@-1{{add @available attribute to enclosing associated type}}
14901497
associatedtype E: AtDeploymentTargetProto // expected-error {{'AtDeploymentTargetProto' is only available in macOS 10.15 or newer; clients of 'Test' may have a lower deployment target}}
1498+
// expected-note@-1{{add @available attribute to enclosing associated type}}
14911499
associatedtype F: AfterDeploymentTargetProto // expected-error {{'AfterDeploymentTargetProto' is only available in}}
1500+
// expected-note@-1{{add @available attribute to enclosing associated type}}
14921501
}
14931502

14941503
@available(macOS 10.14.5, *)
@@ -1498,7 +1507,9 @@ public protocol BetweenTargetsProtoWithAssoc {
14981507
associatedtype C: AtInliningTargetProto
14991508
associatedtype D: BetweenTargetsProto
15001509
associatedtype E: AtDeploymentTargetProto // expected-error {{'AtDeploymentTargetProto' is only available in macOS 10.15 or newer; clients of 'Test' may have a lower deployment target}}
1510+
// expected-note@-1{{add @available attribute to enclosing associated type}}
15011511
associatedtype F: AfterDeploymentTargetProto // expected-error {{'AfterDeploymentTargetProto' is only available in}}
1512+
// expected-note@-1{{add @available attribute to enclosing associated type}}
15021513
}
15031514

15041515
@available(macOS 10.15, *)
@@ -1509,6 +1520,7 @@ public protocol AtDeploymentTargetProtoWithAssoc {
15091520
associatedtype D: BetweenTargetsProto
15101521
associatedtype E: AtDeploymentTargetProto
15111522
associatedtype F: AfterDeploymentTargetProto // expected-error {{'AfterDeploymentTargetProto' is only available in}}
1523+
// expected-note@-1{{add @available attribute to enclosing associated type}}
15121524
}
15131525

15141526
@available(macOS 11, *)
@@ -1529,6 +1541,7 @@ public protocol UnavailableProtoWithAssoc {
15291541
associatedtype D: BetweenTargetsProto
15301542
associatedtype E: AtDeploymentTargetProto
15311543
associatedtype F: AfterDeploymentTargetProto // expected-error {{'AfterDeploymentTargetProto' is only available in}}
1544+
// expected-note@-1{{add @available attribute to enclosing associated type}}
15321545
associatedtype G: UnavailableProto
15331546
}
15341547

@@ -1540,6 +1553,7 @@ public protocol SPINoAvailableProtoWithAssoc { // expected-note 1 {{add @availab
15401553
associatedtype D: BetweenTargetsProto
15411554
associatedtype E: AtDeploymentTargetProto
15421555
associatedtype F: AfterDeploymentTargetProto // expected-error {{'AfterDeploymentTargetProto' is only available in}}
1556+
// expected-note@-1{{add @available attribute to enclosing associated type}}
15431557
}
15441558

15451559
// MARK: - Type aliases
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// RUN: %swift -typecheck -verify -target %target-cpu-apple-macosx12 %s
2+
// REQUIRES: OS=macosx
3+
4+
5+
protocol P { }
6+
extension Int: P { }
7+
8+
protocol P1<A, B> {
9+
associatedtype A
10+
11+
@available(macOS 13, *)
12+
associatedtype B: P
13+
}
14+
15+
@available(macOS 13, *)
16+
struct ModelP1<A, B: P>: P1 {
17+
}
18+
19+
// Associated types in where clauses
20+
func testWhereBad<T: P1, U>(_: T) where T.B == U { }
21+
// expected-error@-1{{'B' is only available in macOS 13 or newer}}
22+
// expected-note@-2{{add @available attribute to enclosing global function}}
23+
24+
@available(macOS 13, *)
25+
func testWhereGood<T: P1, U>(_: T) where T.B == U { }
26+
27+
// Associated types in opaque parameter position
28+
func testPrimaryOpaqueParamBad<U>(_: some P1<some Any, U>) {}
29+
// expected-error@-1 2{{'B' is only available in macOS 13 or newer}}
30+
// expected-note@-2 2{{add @available attribute to enclosing global function}}
31+
32+
@available(macOS 13, *)
33+
func testPrimaryOpaqueParamGood<U: P>(_: some P1<some Any, U>) {}
34+
35+
// Associated types in opaque result position
36+
func testPrimaryOpaqueResultBad<U: P>() -> some P1<String, U> {
37+
// expected-error@-1{{'B' is only available in macOS 13 or newer}}
38+
// expected-note@-2 2{{add @available attribute to enclosing global function}}
39+
return ModelP1<String, U>()
40+
// expected-error@-1{{'ModelP1' is only available in macOS 13 or newer}}
41+
// expected-note@-2{{add 'if #available' version check}}
42+
}
43+
44+
@available(macOS 13, *)
45+
func testPrimaryOpaqueResultGood<U: P>() -> some P1<String, U> {
46+
return ModelP1<String, U>()
47+
}
48+
49+
// Associated types in existentials
50+
func testPrimaryExistentialBad<U>(_: any P1<Int, U>) {}
51+
// expected-error@-1{{'B' is only available in macOS 13 or newer}}
52+
// expected-note@-2{{add @available attribute to enclosing global function}}
53+
54+
@available(macOS 13, *)
55+
func testPrimaryExistentialGood<U>(_: any P1<Int, U>) {}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// RUN: %swift -typecheck -verify -target %target-cpu-apple-macosx12 %s -enable-library-evolution
2+
// REQUIRES: OS=macosx
3+
4+
5+
protocol P { }
6+
extension Int: P { }
7+
8+
@available(macOS 12, *)
9+
protocol P1 {
10+
associatedtype A
11+
12+
@available(macOS 13, *)
13+
associatedtype B: P
14+
// expected-error@-1{{associated type 'B' that is less available than its protocol must have a default}}
15+
16+
@available(macOS 13, *)
17+
associatedtype C: P = Int
18+
}

0 commit comments

Comments
 (0)