Skip to content

Commit 1f32e83

Browse files
committed
[Sema] Diagnose use of unavailable protocols in type erasing expressions (e.g. let x: P = S where S conforms to P).
Resolves rdar://83731428.
1 parent f6d095d commit 1f32e83

File tree

3 files changed

+41
-8
lines changed

3 files changed

+41
-8
lines changed

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2863,6 +2863,12 @@ class ExprAvailabilityWalker : public ASTWalker {
28632863
return skipChildren();
28642864
}
28652865
}
2866+
2867+
if (auto EE = dyn_cast<ErasureExpr>(E)) {
2868+
for (ProtocolConformanceRef C : EE->getConformances()) {
2869+
diagnoseConformanceAvailability(E->getLoc(), C, Where);
2870+
}
2871+
}
28662872

28672873
return visitChildren();
28682874
}

test/Sema/conformance_availability.swift

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
public protocol Horse {}
66
func takesHorse<T : Horse>(_: T) {}
7+
func takesHorseExistential(_: Horse) {}
78

89
extension Horse {
910
func giddyUp() {}
@@ -17,10 +18,11 @@ public struct HasUnavailableConformance1 {}
1718

1819
@available(*, unavailable)
1920
extension HasUnavailableConformance1 : Horse {}
20-
// expected-note@-1 6{{conformance of 'HasUnavailableConformance1' to 'Horse' has been explicitly marked unavailable here}}
21+
// expected-note@-1 7{{conformance of 'HasUnavailableConformance1' to 'Horse' has been explicitly marked unavailable here}}
2122

2223
func passUnavailableConformance1(x: HasUnavailableConformance1) {
2324
takesHorse(x) // expected-error {{conformance of 'HasUnavailableConformance1' to 'Horse' is unavailable}}
25+
takesHorseExistential(x) // expected-error {{conformance of 'HasUnavailableConformance1' to 'Horse' is unavailable}}
2426
x.giddyUp() // expected-error {{conformance of 'HasUnavailableConformance1' to 'Horse' is unavailable}}
2527
_ = x.isGalloping // expected-error {{conformance of 'HasUnavailableConformance1' to 'Horse' is unavailable}}
2628
_ = x[keyPath: \.isGalloping] // expected-error {{conformance of 'HasUnavailableConformance1' to 'Horse' is unavailable}}
@@ -30,6 +32,7 @@ func passUnavailableConformance1(x: HasUnavailableConformance1) {
3032
@available(*, unavailable)
3133
func passUnavailableConformance1a(x: HasUnavailableConformance1) {
3234
takesHorse(x)
35+
takesHorseExistential(x)
3336
x.giddyUp()
3437
_ = x.isGalloping
3538
_ = x[keyPath: \.isGalloping]
@@ -41,10 +44,11 @@ public struct HasUnavailableConformance2 {}
4144

4245
@available(macOS, unavailable)
4346
extension HasUnavailableConformance2 : Horse {}
44-
// expected-note@-1 5{{conformance of 'HasUnavailableConformance2' to 'Horse' has been explicitly marked unavailable here}}
47+
// expected-note@-1 6{{conformance of 'HasUnavailableConformance2' to 'Horse' has been explicitly marked unavailable here}}
4548

4649
func passUnavailableConformance2(x: HasUnavailableConformance2) {
4750
takesHorse(x) // expected-error {{conformance of 'HasUnavailableConformance2' to 'Horse' is unavailable in macOS}}
51+
takesHorseExistential(x) // expected-error {{conformance of 'HasUnavailableConformance2' to 'Horse' is unavailable in macOS}}
4852
x.giddyUp() // expected-error {{conformance of 'HasUnavailableConformance2' to 'Horse' is unavailable in macOS}}
4953
_ = x.isGalloping // expected-error {{conformance of 'HasUnavailableConformance2' to 'Horse' is unavailable in macOS}}
5054
_ = x[keyPath: \.isGalloping] // expected-error {{conformance of 'HasUnavailableConformance2' to 'Horse' is unavailable in macOS}}
@@ -55,6 +59,7 @@ func passUnavailableConformance2(x: HasUnavailableConformance2) {
5559
func passUnavailableConformance2a(x: HasUnavailableConformance2) {
5660
// This is allowed
5761
takesHorse(x)
62+
takesHorseExistential(x)
5863
x.giddyUp()
5964
_ = x.isGalloping
6065
_ = x[keyPath: \.isGalloping]
@@ -65,10 +70,11 @@ public struct HasUnavailableConformance3 {}
6570

6671
@available(swift 12)
6772
extension HasUnavailableConformance3 : Horse {}
68-
// expected-note@-1 10{{conformance of 'HasUnavailableConformance3' to 'Horse' was introduced in Swift 12}}
73+
// expected-note@-1 12{{conformance of 'HasUnavailableConformance3' to 'Horse' was introduced in Swift 12}}
6974

7075
func passUnavailableConformance3(x: HasUnavailableConformance3) {
7176
takesHorse(x) // expected-error {{conformance of 'HasUnavailableConformance3' to 'Horse' is unavailable}}
77+
takesHorseExistential(x) // expected-error {{conformance of 'HasUnavailableConformance3' to 'Horse' is unavailable}}
7278
x.giddyUp() // expected-error {{conformance of 'HasUnavailableConformance3' to 'Horse' is unavailable}}
7379
_ = x.isGalloping // expected-error {{conformance of 'HasUnavailableConformance3' to 'Horse' is unavailable}}
7480
_ = x[keyPath: \.isGalloping] // expected-error {{conformance of 'HasUnavailableConformance3' to 'Horse' is unavailable}}
@@ -78,6 +84,7 @@ func passUnavailableConformance3(x: HasUnavailableConformance3) {
7884
@available(swift 12)
7985
func passUnavailableConformance3a(x: HasUnavailableConformance3) {
8086
takesHorse(x) // expected-error {{conformance of 'HasUnavailableConformance3' to 'Horse' is unavailable}}
87+
takesHorseExistential(x) // expected-error {{conformance of 'HasUnavailableConformance3' to 'Horse' is unavailable}}
8188
x.giddyUp() // expected-error {{conformance of 'HasUnavailableConformance3' to 'Horse' is unavailable}}
8289
_ = x.isGalloping // expected-error {{conformance of 'HasUnavailableConformance3' to 'Horse' is unavailable}}
8390
_ = x[keyPath: \.isGalloping] // expected-error {{conformance of 'HasUnavailableConformance3' to 'Horse' is unavailable}}
@@ -89,10 +96,11 @@ public struct HasUnavailableConformance4 {}
8996

9097
@available(macOS, obsoleted: 10.1)
9198
extension HasUnavailableConformance4 : Horse {}
92-
// expected-note@-1 10{{conformance of 'HasUnavailableConformance4' to 'Horse' was obsoleted in macOS 10.1}}
99+
// expected-note@-1 12{{conformance of 'HasUnavailableConformance4' to 'Horse' was obsoleted in macOS 10.1}}
93100

94101
func passUnavailableConformance4(x: HasUnavailableConformance4) {
95102
takesHorse(x) // expected-error {{conformance of 'HasUnavailableConformance4' to 'Horse' is unavailable in macOS}}
103+
takesHorseExistential(x) // expected-error {{conformance of 'HasUnavailableConformance4' to 'Horse' is unavailable in macOS}}
96104
x.giddyUp() // expected-error {{conformance of 'HasUnavailableConformance4' to 'Horse' is unavailable in macOS}}
97105
_ = x.isGalloping // expected-error {{conformance of 'HasUnavailableConformance4' to 'Horse' is unavailable}}
98106
_ = x[keyPath: \.isGalloping] // expected-error {{conformance of 'HasUnavailableConformance4' to 'Horse' is unavailable}}
@@ -102,6 +110,7 @@ func passUnavailableConformance4(x: HasUnavailableConformance4) {
102110
@available(macOS, obsoleted: 10.1)
103111
func passUnavailableConformance4a(x: HasUnavailableConformance4) {
104112
takesHorse(x) // expected-error {{conformance of 'HasUnavailableConformance4' to 'Horse' is unavailable in macOS}}
113+
takesHorseExistential(x) // expected-error {{conformance of 'HasUnavailableConformance4' to 'Horse' is unavailable in macOS}}
105114
x.giddyUp() // expected-error {{conformance of 'HasUnavailableConformance4' to 'Horse' is unavailable in macOS}}
106115
_ = x.isGalloping // expected-error {{conformance of 'HasUnavailableConformance4' to 'Horse' is unavailable}}
107116
_ = x[keyPath: \.isGalloping] // expected-error {{conformance of 'HasUnavailableConformance4' to 'Horse' is unavailable}}
@@ -113,10 +122,11 @@ public struct HasUnavailableConformance5 {}
113122

114123
@available(swift, obsoleted: 4)
115124
extension HasUnavailableConformance5 : Horse {}
116-
// expected-note@-1 10{{conformance of 'HasUnavailableConformance5' to 'Horse' was obsoleted in Swift 4}}
125+
// expected-note@-1 12{{conformance of 'HasUnavailableConformance5' to 'Horse' was obsoleted in Swift 4}}
117126

118127
func passUnavailableConformance5(x: HasUnavailableConformance5) {
119128
takesHorse(x) // expected-error {{conformance of 'HasUnavailableConformance5' to 'Horse' is unavailable}}
129+
takesHorseExistential(x) // expected-error {{conformance of 'HasUnavailableConformance5' to 'Horse' is unavailable}}
120130
x.giddyUp() // expected-error {{conformance of 'HasUnavailableConformance5' to 'Horse' is unavailable}}
121131
_ = x.isGalloping // expected-error {{conformance of 'HasUnavailableConformance5' to 'Horse' is unavailable}}
122132
_ = x[keyPath: \.isGalloping] // expected-error {{conformance of 'HasUnavailableConformance5' to 'Horse' is unavailable}}
@@ -126,6 +136,7 @@ func passUnavailableConformance5(x: HasUnavailableConformance5) {
126136
@available(swift, obsoleted: 4)
127137
func passUnavailableConformance5a(x: HasUnavailableConformance5) {
128138
takesHorse(x) // expected-error {{conformance of 'HasUnavailableConformance5' to 'Horse' is unavailable}}
139+
takesHorseExistential(x) // expected-error {{conformance of 'HasUnavailableConformance5' to 'Horse' is unavailable}}
129140
x.giddyUp() // expected-error {{conformance of 'HasUnavailableConformance5' to 'Horse' is unavailable}}
130141
_ = x.isGalloping // expected-error {{conformance of 'HasUnavailableConformance5' to 'Horse' is unavailable}}
131142
_ = x[keyPath: \.isGalloping] // expected-error {{conformance of 'HasUnavailableConformance5' to 'Horse' is unavailable}}
@@ -137,10 +148,11 @@ public struct HasUnavailableConformance6 {}
137148

138149
@available(*, unavailable, message: "This conformance is bad")
139150
extension HasUnavailableConformance6 : Horse {}
140-
// expected-note@-1 5{{conformance of 'HasUnavailableConformance6' to 'Horse' has been explicitly marked unavailable here}}
151+
// expected-note@-1 6{{conformance of 'HasUnavailableConformance6' to 'Horse' has been explicitly marked unavailable here}}
141152

142153
func passUnavailableConformance6(x: HasUnavailableConformance6) {
143154
takesHorse(x) // expected-error {{conformance of 'HasUnavailableConformance6' to 'Horse' is unavailable: This conformance is bad}}
155+
takesHorseExistential(x) // expected-error {{conformance of 'HasUnavailableConformance6' to 'Horse' is unavailable: This conformance is bad}}
144156
x.giddyUp() // expected-error {{conformance of 'HasUnavailableConformance6' to 'Horse' is unavailable: This conformance is bad}}
145157
_ = x.isGalloping // expected-error {{conformance of 'HasUnavailableConformance6' to 'Horse' is unavailable: This conformance is bad}}
146158
_ = x[keyPath: \.isGalloping] // expected-error {{conformance of 'HasUnavailableConformance6' to 'Horse' is unavailable: This conformance is bad}}
@@ -155,6 +167,7 @@ extension HasDeprecatedConformance1 : Horse {}
155167

156168
func passDeprecatedConformance1(x: HasDeprecatedConformance1) {
157169
takesHorse(x) // expected-warning {{conformance of 'HasDeprecatedConformance1' to 'Horse' is deprecated}}
170+
takesHorseExistential(x) // expected-warning {{conformance of 'HasDeprecatedConformance1' to 'Horse' is deprecated}}
158171
x.giddyUp() // expected-warning {{conformance of 'HasDeprecatedConformance1' to 'Horse' is deprecated}}
159172
_ = x.isGalloping // expected-warning {{conformance of 'HasDeprecatedConformance1' to 'Horse' is deprecated}}
160173
_ = x[keyPath: \.isGalloping] // expected-warning {{conformance of 'HasDeprecatedConformance1' to 'Horse' is deprecated}}
@@ -164,6 +177,7 @@ func passDeprecatedConformance1(x: HasDeprecatedConformance1) {
164177
@available(*, deprecated)
165178
func passDeprecatedConformance1a(x: HasDeprecatedConformance1) {
166179
takesHorse(x)
180+
takesHorseExistential(x)
167181
x.giddyUp()
168182
_ = x.isGalloping
169183
_ = x[keyPath: \.isGalloping]
@@ -178,6 +192,7 @@ extension HasDeprecatedConformance2 : Horse {}
178192

179193
func passDeprecatedConformance2(x: HasDeprecatedConformance2) {
180194
takesHorse(x) // expected-warning {{conformance of 'HasDeprecatedConformance2' to 'Horse' is deprecated: This conformance is deprecated}}
195+
takesHorseExistential(x) // expected-warning {{conformance of 'HasDeprecatedConformance2' to 'Horse' is deprecated: This conformance is deprecated}}
181196
x.giddyUp() // expected-warning {{conformance of 'HasDeprecatedConformance2' to 'Horse' is deprecated: This conformance is deprecated}}
182197
_ = x.isGalloping // expected-warning {{conformance of 'HasDeprecatedConformance2' to 'Horse' is deprecated: This conformance is deprecated}}
183198
_ = x[keyPath: \.isGalloping] // expected-warning {{conformance of 'HasDeprecatedConformance2' to 'Horse' is deprecated: This conformance is deprecated}}
@@ -187,6 +202,7 @@ func passDeprecatedConformance2(x: HasDeprecatedConformance2) {
187202
@available(*, deprecated)
188203
func passDeprecatedConformance2a(x: HasDeprecatedConformance2) {
189204
takesHorse(x)
205+
takesHorseExistential(x)
190206
x.giddyUp()
191207
_ = x.isGalloping
192208
_ = x[keyPath: \.isGalloping]
@@ -201,6 +217,7 @@ extension HasDeprecatedConformance3 : Horse {}
201217

202218
func passDeprecatedConformance3(x: HasDeprecatedConformance3) {
203219
takesHorse(x) // expected-warning {{conformance of 'HasDeprecatedConformance3' to 'Horse' was deprecated in macOS 10.8}}
220+
takesHorseExistential(x) // expected-warning {{conformance of 'HasDeprecatedConformance3' to 'Horse' was deprecated in macOS 10.8}}
204221
x.giddyUp() // expected-warning {{conformance of 'HasDeprecatedConformance3' to 'Horse' was deprecated in macOS 10.8}}
205222
_ = x.isGalloping // expected-warning {{conformance of 'HasDeprecatedConformance3' to 'Horse' was deprecated in macOS 10.8}}
206223
_ = x[keyPath: \.isGalloping] // expected-warning {{conformance of 'HasDeprecatedConformance3' to 'Horse' was deprecated in macOS 10.8}}
@@ -213,6 +230,7 @@ func passDeprecatedConformance3a(x: HasDeprecatedConformance3) {
213230
// This branch is dead with our minimum deployment target, so don't emit
214231
// deprecation diagnostics in it.
215232
takesHorse(x)
233+
takesHorseExistential(x)
216234
x.giddyUp()
217235
_ = x.isGalloping
218236
_ = x[keyPath: \.isGalloping]
@@ -231,10 +249,13 @@ extension HasAvailableConformance1 : Horse {}
231249
// in test/Sema/conformance_availability_warn.swift for the same example
232250
// but without this flag.
233251

234-
func passAvailableConformance1(x: HasAvailableConformance1) { // expected-note 5{{add @available attribute to enclosing global function}}
252+
func passAvailableConformance1(x: HasAvailableConformance1) { // expected-note 6{{add @available attribute to enclosing global function}}
235253
takesHorse(x) // expected-error {{conformance of 'HasAvailableConformance1' to 'Horse' is only available in macOS 100 or newer}}
236254
// expected-note@-1 {{add 'if #available' version check}}
237255

256+
takesHorseExistential(x) // expected-error {{conformance of 'HasAvailableConformance1' to 'Horse' is only available in macOS 100 or newer}}
257+
// expected-note@-1 {{add 'if #available' version check}}
258+
238259
x.giddyUp() // expected-error {{conformance of 'HasAvailableConformance1' to 'Horse' is only available in macOS 100 or newer}}
239260
// expected-note@-1 {{add 'if #available' version check}}
240261

@@ -251,6 +272,7 @@ func passAvailableConformance1(x: HasAvailableConformance1) { // expected-note 5
251272
@available(macOS 100, *)
252273
func passAvailableConformance1a(x: HasAvailableConformance1) {
253274
takesHorse(x)
275+
takesHorseExistential(x)
254276
x.giddyUp()
255277
_ = x.isGalloping
256278
_ = x[keyPath: \.isGalloping]

test/Sema/conformance_availability_warn.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
public protocol Horse {}
66
func takesHorse<T : Horse>(_: T) {}
7+
func takesHorseExistential(_: Horse) {}
78

89
extension Horse {
910
func giddyUp() {}
@@ -23,10 +24,13 @@ extension HasAvailableConformance1 : Horse {}
2324
// test case in test/Sema/conformance_availability.swift for the same
2425
// example but with this flag.
2526

26-
func passAvailableConformance1(x: HasAvailableConformance1) { // expected-note 5{{add @available attribute to enclosing global function}}
27+
func passAvailableConformance1(x: HasAvailableConformance1) { // expected-note 6{{add @available attribute to enclosing global function}}
2728
takesHorse(x) // expected-warning {{conformance of 'HasAvailableConformance1' to 'Horse' is only available in macOS 100 or newer}}
2829
// expected-note@-1 {{add 'if #available' version check}}
2930

31+
takesHorseExistential(x) // expected-warning {{conformance of 'HasAvailableConformance1' to 'Horse' is only available in macOS 100 or newer}}
32+
// expected-note@-1 {{add 'if #available' version check}}
33+
3034
x.giddyUp() // expected-warning {{conformance of 'HasAvailableConformance1' to 'Horse' is only available in macOS 100 or newer}}
3135
// expected-note@-1 {{add 'if #available' version check}}
3236

@@ -43,6 +47,7 @@ func passAvailableConformance1(x: HasAvailableConformance1) { // expected-note 5
4347
@available(macOS 100, *)
4448
func passAvailableConformance1a(x: HasAvailableConformance1) {
4549
takesHorse(x)
50+
takesHorseExistential(x)
4651
x.giddyUp()
4752
_ = x.isGalloping
4853
_ = UsesHorse<HasAvailableConformance1>.self

0 commit comments

Comments
 (0)