Skip to content

Commit 9346ad8

Browse files
committed
[Sema] When walking a member reference expression, if the member is provided by a protocol conformance be sure to check the availability of conformance.
Expands conformance availability tests to include test cases covering member references and key paths. Resolves rdar://87795154.
1 parent 7dc36c3 commit 9346ad8

File tree

3 files changed

+64
-13
lines changed

3 files changed

+64
-13
lines changed

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2950,15 +2950,15 @@ class ExprAvailabilityWalker : public ASTWalker {
29502950
// writeback. The AST should have this information.
29512951
walkInContext(E, E->getBase(), MemberAccessContext::Getter);
29522952

2953-
ValueDecl *D = E->getMember().getDecl();
2953+
ConcreteDeclRef DR = E->getMember();
29542954
// Diagnose for the member declaration itself.
2955-
if (diagnoseDeclAvailability(D, E->getNameLoc().getSourceRange(),
2956-
nullptr, Where))
2955+
if (diagnoseDeclRefAvailability(DR, E->getNameLoc().getSourceRange(),
2956+
getEnclosingApplyExpr(), None))
29572957
return;
29582958

29592959
// Diagnose for appropriate accessors, given the access context.
29602960
auto *DC = Where.getDeclContext();
2961-
maybeDiagStorageAccess(D, E->getSourceRange(), DC);
2961+
maybeDiagStorageAccess(DR.getDecl(), E->getSourceRange(), DC);
29622962
}
29632963

29642964
/// Walk a keypath expression, checking all of its components for

test/Sema/conformance_availability.swift

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ func takesHorse<T : Horse>(_: T) {}
77

88
extension Horse {
99
func giddyUp() {}
10+
var isGalloping: Bool { true }
1011
}
1112

1213
struct UsesHorse<T : Horse> {}
@@ -16,18 +17,22 @@ public struct HasUnavailableConformance1 {}
1617

1718
@available(*, unavailable)
1819
extension HasUnavailableConformance1 : Horse {}
19-
// expected-note@-1 4{{conformance of 'HasUnavailableConformance1' to 'Horse' has been explicitly marked unavailable here}}
20+
// expected-note@-1 6{{conformance of 'HasUnavailableConformance1' to 'Horse' has been explicitly marked unavailable here}}
2021

2122
func passUnavailableConformance1(x: HasUnavailableConformance1) {
2223
takesHorse(x) // expected-error {{conformance of 'HasUnavailableConformance1' to 'Horse' is unavailable}}
2324
x.giddyUp() // expected-error {{conformance of 'HasUnavailableConformance1' to 'Horse' is unavailable}}
25+
_ = x.isGalloping // expected-error {{conformance of 'HasUnavailableConformance1' to 'Horse' is unavailable}}
26+
_ = x[keyPath: \.isGalloping] // expected-error {{conformance of 'HasUnavailableConformance1' to 'Horse' is unavailable}}
2427
_ = UsesHorse<HasUnavailableConformance1>.self // expected-error {{conformance of 'HasUnavailableConformance1' to 'Horse' is unavailable}}
2528
}
2629

2730
@available(*, unavailable)
2831
func passUnavailableConformance1a(x: HasUnavailableConformance1) {
2932
takesHorse(x)
3033
x.giddyUp()
34+
_ = x.isGalloping
35+
_ = x[keyPath: \.isGalloping]
3136
_ = UsesHorse<HasUnavailableConformance1>.self
3237
}
3338

@@ -36,11 +41,13 @@ public struct HasUnavailableConformance2 {}
3641

3742
@available(macOS, unavailable)
3843
extension HasUnavailableConformance2 : Horse {}
39-
// expected-note@-1 3{{conformance of 'HasUnavailableConformance2' to 'Horse' has been explicitly marked unavailable here}}
44+
// expected-note@-1 5{{conformance of 'HasUnavailableConformance2' to 'Horse' has been explicitly marked unavailable here}}
4045

4146
func passUnavailableConformance2(x: HasUnavailableConformance2) {
4247
takesHorse(x) // expected-error {{conformance of 'HasUnavailableConformance2' to 'Horse' is unavailable in macOS}}
4348
x.giddyUp() // expected-error {{conformance of 'HasUnavailableConformance2' to 'Horse' is unavailable in macOS}}
49+
_ = x.isGalloping // expected-error {{conformance of 'HasUnavailableConformance2' to 'Horse' is unavailable in macOS}}
50+
_ = x[keyPath: \.isGalloping] // expected-error {{conformance of 'HasUnavailableConformance2' to 'Horse' is unavailable in macOS}}
4451
_ = UsesHorse<HasUnavailableConformance2>.self // expected-error {{conformance of 'HasUnavailableConformance2' to 'Horse' is unavailable in macOS}}
4552
}
4653

@@ -49,25 +56,31 @@ func passUnavailableConformance2a(x: HasUnavailableConformance2) {
4956
// This is allowed
5057
takesHorse(x)
5158
x.giddyUp()
59+
_ = x.isGalloping
60+
_ = x[keyPath: \.isGalloping]
5261
}
5362

5463
// Swift version unavailability
5564
public struct HasUnavailableConformance3 {}
5665

5766
@available(swift 12)
5867
extension HasUnavailableConformance3 : Horse {}
59-
// expected-note@-1 6{{conformance of 'HasUnavailableConformance3' to 'Horse' was introduced in Swift 12}}
68+
// expected-note@-1 10{{conformance of 'HasUnavailableConformance3' to 'Horse' was introduced in Swift 12}}
6069

6170
func passUnavailableConformance3(x: HasUnavailableConformance3) {
6271
takesHorse(x) // expected-error {{conformance of 'HasUnavailableConformance3' to 'Horse' is unavailable}}
6372
x.giddyUp() // expected-error {{conformance of 'HasUnavailableConformance3' to 'Horse' is unavailable}}
73+
_ = x.isGalloping // expected-error {{conformance of 'HasUnavailableConformance3' to 'Horse' is unavailable}}
74+
_ = x[keyPath: \.isGalloping] // expected-error {{conformance of 'HasUnavailableConformance3' to 'Horse' is unavailable}}
6475
_ = UsesHorse<HasUnavailableConformance3>.self // expected-error {{conformance of 'HasUnavailableConformance3' to 'Horse' is unavailable}}
6576
}
6677

6778
@available(swift 12)
6879
func passUnavailableConformance3a(x: HasUnavailableConformance3) {
6980
takesHorse(x) // expected-error {{conformance of 'HasUnavailableConformance3' to 'Horse' is unavailable}}
7081
x.giddyUp() // expected-error {{conformance of 'HasUnavailableConformance3' to 'Horse' is unavailable}}
82+
_ = x.isGalloping // expected-error {{conformance of 'HasUnavailableConformance3' to 'Horse' is unavailable}}
83+
_ = x[keyPath: \.isGalloping] // expected-error {{conformance of 'HasUnavailableConformance3' to 'Horse' is unavailable}}
7184
_ = UsesHorse<HasUnavailableConformance3>.self // expected-error {{conformance of 'HasUnavailableConformance3' to 'Horse' is unavailable}}
7285
}
7386

@@ -76,18 +89,22 @@ public struct HasUnavailableConformance4 {}
7689

7790
@available(macOS, obsoleted: 10.1)
7891
extension HasUnavailableConformance4 : Horse {}
79-
// expected-note@-1 6{{conformance of 'HasUnavailableConformance4' to 'Horse' was obsoleted in macOS 10.1}}
92+
// expected-note@-1 10{{conformance of 'HasUnavailableConformance4' to 'Horse' was obsoleted in macOS 10.1}}
8093

8194
func passUnavailableConformance4(x: HasUnavailableConformance4) {
8295
takesHorse(x) // expected-error {{conformance of 'HasUnavailableConformance4' to 'Horse' is unavailable in macOS}}
8396
x.giddyUp() // expected-error {{conformance of 'HasUnavailableConformance4' to 'Horse' is unavailable in macOS}}
97+
_ = x.isGalloping // expected-error {{conformance of 'HasUnavailableConformance4' to 'Horse' is unavailable}}
98+
_ = x[keyPath: \.isGalloping] // expected-error {{conformance of 'HasUnavailableConformance4' to 'Horse' is unavailable}}
8499
_ = UsesHorse<HasUnavailableConformance4>.self // expected-error {{conformance of 'HasUnavailableConformance4' to 'Horse' is unavailable in macOS}}
85100
}
86101

87102
@available(macOS, obsoleted: 10.1)
88103
func passUnavailableConformance4a(x: HasUnavailableConformance4) {
89104
takesHorse(x) // expected-error {{conformance of 'HasUnavailableConformance4' to 'Horse' is unavailable in macOS}}
90105
x.giddyUp() // expected-error {{conformance of 'HasUnavailableConformance4' to 'Horse' is unavailable in macOS}}
106+
_ = x.isGalloping // expected-error {{conformance of 'HasUnavailableConformance4' to 'Horse' is unavailable}}
107+
_ = x[keyPath: \.isGalloping] // expected-error {{conformance of 'HasUnavailableConformance4' to 'Horse' is unavailable}}
91108
_ = UsesHorse<HasUnavailableConformance4>.self // expected-error {{conformance of 'HasUnavailableConformance4' to 'Horse' is unavailable in macOS}}
92109
}
93110

@@ -96,18 +113,22 @@ public struct HasUnavailableConformance5 {}
96113

97114
@available(swift, obsoleted: 4)
98115
extension HasUnavailableConformance5 : Horse {}
99-
// expected-note@-1 6{{conformance of 'HasUnavailableConformance5' to 'Horse' was obsoleted in Swift 4}}
116+
// expected-note@-1 10{{conformance of 'HasUnavailableConformance5' to 'Horse' was obsoleted in Swift 4}}
100117

101118
func passUnavailableConformance5(x: HasUnavailableConformance5) {
102119
takesHorse(x) // expected-error {{conformance of 'HasUnavailableConformance5' to 'Horse' is unavailable}}
103120
x.giddyUp() // expected-error {{conformance of 'HasUnavailableConformance5' to 'Horse' is unavailable}}
121+
_ = x.isGalloping // expected-error {{conformance of 'HasUnavailableConformance5' to 'Horse' is unavailable}}
122+
_ = x[keyPath: \.isGalloping] // expected-error {{conformance of 'HasUnavailableConformance5' to 'Horse' is unavailable}}
104123
_ = UsesHorse<HasUnavailableConformance5>.self // expected-error {{conformance of 'HasUnavailableConformance5' to 'Horse' is unavailable}}
105124
}
106125

107126
@available(swift, obsoleted: 4)
108127
func passUnavailableConformance5a(x: HasUnavailableConformance5) {
109128
takesHorse(x) // expected-error {{conformance of 'HasUnavailableConformance5' to 'Horse' is unavailable}}
110129
x.giddyUp() // expected-error {{conformance of 'HasUnavailableConformance5' to 'Horse' is unavailable}}
130+
_ = x.isGalloping // expected-error {{conformance of 'HasUnavailableConformance5' to 'Horse' is unavailable}}
131+
_ = x[keyPath: \.isGalloping] // expected-error {{conformance of 'HasUnavailableConformance5' to 'Horse' is unavailable}}
111132
_ = UsesHorse<HasUnavailableConformance5>.self // expected-error {{conformance of 'HasUnavailableConformance5' to 'Horse' is unavailable}}
112133
}
113134

@@ -116,11 +137,13 @@ public struct HasUnavailableConformance6 {}
116137

117138
@available(*, unavailable, message: "This conformance is bad")
118139
extension HasUnavailableConformance6 : Horse {}
119-
// expected-note@-1 3{{conformance of 'HasUnavailableConformance6' to 'Horse' has been explicitly marked unavailable here}}
140+
// expected-note@-1 5{{conformance of 'HasUnavailableConformance6' to 'Horse' has been explicitly marked unavailable here}}
120141

121142
func passUnavailableConformance6(x: HasUnavailableConformance6) {
122143
takesHorse(x) // expected-error {{conformance of 'HasUnavailableConformance6' to 'Horse' is unavailable: This conformance is bad}}
123144
x.giddyUp() // expected-error {{conformance of 'HasUnavailableConformance6' to 'Horse' is unavailable: This conformance is bad}}
145+
_ = x.isGalloping // expected-error {{conformance of 'HasUnavailableConformance6' to 'Horse' is unavailable: This conformance is bad}}
146+
_ = x[keyPath: \.isGalloping] // expected-error {{conformance of 'HasUnavailableConformance6' to 'Horse' is unavailable: This conformance is bad}}
124147
_ = UsesHorse<HasUnavailableConformance6>.self // expected-error {{conformance of 'HasUnavailableConformance6' to 'Horse' is unavailable: This conformance is bad}}
125148
}
126149

@@ -133,13 +156,17 @@ extension HasDeprecatedConformance1 : Horse {}
133156
func passDeprecatedConformance1(x: HasDeprecatedConformance1) {
134157
takesHorse(x) // expected-warning {{conformance of 'HasDeprecatedConformance1' to 'Horse' is deprecated}}
135158
x.giddyUp() // expected-warning {{conformance of 'HasDeprecatedConformance1' to 'Horse' is deprecated}}
159+
_ = x.isGalloping // expected-warning {{conformance of 'HasDeprecatedConformance1' to 'Horse' is deprecated}}
160+
_ = x[keyPath: \.isGalloping] // expected-warning {{conformance of 'HasDeprecatedConformance1' to 'Horse' is deprecated}}
136161
_ = UsesHorse<HasDeprecatedConformance1>.self // expected-warning {{conformance of 'HasDeprecatedConformance1' to 'Horse' is deprecated}}
137162
}
138163

139164
@available(*, deprecated)
140165
func passDeprecatedConformance1a(x: HasDeprecatedConformance1) {
141166
takesHorse(x)
142167
x.giddyUp()
168+
_ = x.isGalloping
169+
_ = x[keyPath: \.isGalloping]
143170
_ = UsesHorse<HasDeprecatedConformance1>.self
144171
}
145172

@@ -152,13 +179,17 @@ extension HasDeprecatedConformance2 : Horse {}
152179
func passDeprecatedConformance2(x: HasDeprecatedConformance2) {
153180
takesHorse(x) // expected-warning {{conformance of 'HasDeprecatedConformance2' to 'Horse' is deprecated: This conformance is deprecated}}
154181
x.giddyUp() // expected-warning {{conformance of 'HasDeprecatedConformance2' to 'Horse' is deprecated: This conformance is deprecated}}
182+
_ = x.isGalloping // expected-warning {{conformance of 'HasDeprecatedConformance2' to 'Horse' is deprecated: This conformance is deprecated}}
183+
_ = x[keyPath: \.isGalloping] // expected-warning {{conformance of 'HasDeprecatedConformance2' to 'Horse' is deprecated: This conformance is deprecated}}
155184
_ = UsesHorse<HasDeprecatedConformance2>.self // expected-warning {{conformance of 'HasDeprecatedConformance2' to 'Horse' is deprecated: This conformance is deprecated}}
156185
}
157186

158187
@available(*, deprecated)
159188
func passDeprecatedConformance2a(x: HasDeprecatedConformance2) {
160189
takesHorse(x)
161190
x.giddyUp()
191+
_ = x.isGalloping
192+
_ = x[keyPath: \.isGalloping]
162193
_ = UsesHorse<HasDeprecatedConformance2>.self
163194
}
164195

@@ -171,6 +202,8 @@ extension HasDeprecatedConformance3 : Horse {}
171202
func passDeprecatedConformance3(x: HasDeprecatedConformance3) {
172203
takesHorse(x) // expected-warning {{conformance of 'HasDeprecatedConformance3' to 'Horse' was deprecated in macOS 10.8}}
173204
x.giddyUp() // expected-warning {{conformance of 'HasDeprecatedConformance3' to 'Horse' was deprecated in macOS 10.8}}
205+
_ = x.isGalloping // expected-warning {{conformance of 'HasDeprecatedConformance3' to 'Horse' was deprecated in macOS 10.8}}
206+
_ = x[keyPath: \.isGalloping] // expected-warning {{conformance of 'HasDeprecatedConformance3' to 'Horse' was deprecated in macOS 10.8}}
174207
_ = UsesHorse<HasDeprecatedConformance3>.self // expected-warning {{conformance of 'HasDeprecatedConformance3' to 'Horse' was deprecated in macOS 10.8}}
175208
}
176209

@@ -181,6 +214,8 @@ func passDeprecatedConformance3a(x: HasDeprecatedConformance3) {
181214
// deprecation diagnostics in it.
182215
takesHorse(x)
183216
x.giddyUp()
217+
_ = x.isGalloping
218+
_ = x[keyPath: \.isGalloping]
184219
_ = UsesHorse<HasDeprecatedConformance3>.self
185220
}
186221
}
@@ -196,13 +231,19 @@ extension HasAvailableConformance1 : Horse {}
196231
// in test/Sema/conformance_availability_warn.swift for the same example
197232
// but without this flag.
198233

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

203238
x.giddyUp() // expected-error {{conformance of 'HasAvailableConformance1' to 'Horse' is only available in macOS 100 or newer}}
204239
// expected-note@-1 {{add 'if #available' version check}}
205240

241+
_ = x.isGalloping // expected-error {{conformance of 'HasAvailableConformance1' to 'Horse' is only available in macOS 100 or newer}}
242+
// expected-note@-1 {{add 'if #available' version check}}
243+
244+
_ = x[keyPath: \.isGalloping] // expected-error {{conformance of 'HasAvailableConformance1' to 'Horse' is only available in macOS 100 or newer}}
245+
// expected-note@-1 {{add 'if #available' version check}}
246+
206247
_ = UsesHorse<HasAvailableConformance1>.self // expected-error {{conformance of 'HasAvailableConformance1' to 'Horse' is only available in macOS 100 or newer}}
207248
// expected-note@-1 {{add 'if #available' version check}}
208249
}
@@ -211,6 +252,8 @@ func passAvailableConformance1(x: HasAvailableConformance1) { // expected-note 3
211252
func passAvailableConformance1a(x: HasAvailableConformance1) {
212253
takesHorse(x)
213254
x.giddyUp()
255+
_ = x.isGalloping
256+
_ = x[keyPath: \.isGalloping]
214257
_ = UsesHorse<HasAvailableConformance1>.self
215258
}
216259

test/Sema/conformance_availability_warn.swift

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ func takesHorse<T : Horse>(_: T) {}
77

88
extension Horse {
99
func giddyUp() {}
10+
var isGalloping: Bool { true }
1011
}
1112

1213
struct UsesHorse<T : Horse> {}
@@ -22,12 +23,18 @@ extension HasAvailableConformance1 : Horse {}
2223
// test case in test/Sema/conformance_availability.swift for the same
2324
// example but with this flag.
2425

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

2930
x.giddyUp() // expected-warning {{conformance of 'HasAvailableConformance1' to 'Horse' is only available in macOS 100 or newer}}
3031
// expected-note@-1 {{add 'if #available' version check}}
32+
33+
_ = x.isGalloping // expected-warning {{conformance of 'HasAvailableConformance1' to 'Horse' is only available in macOS 100 or newer}}
34+
// expected-note@-1 {{add 'if #available' version check}}
35+
36+
_ = x[keyPath: \.isGalloping] // expected-warning {{conformance of 'HasAvailableConformance1' to 'Horse' is only available in macOS 100 or newer}}
37+
// expected-note@-1 {{add 'if #available' version check}}
3138

3239
_ = UsesHorse<HasAvailableConformance1>.self // expected-warning {{conformance of 'HasAvailableConformance1' to 'Horse' is only available in macOS 100 or newer}}
3340
// expected-note@-1 {{add 'if #available' version check}}
@@ -37,5 +44,6 @@ func passAvailableConformance1(x: HasAvailableConformance1) { // expected-note 3
3744
func passAvailableConformance1a(x: HasAvailableConformance1) {
3845
takesHorse(x)
3946
x.giddyUp()
47+
_ = x.isGalloping
4048
_ = UsesHorse<HasAvailableConformance1>.self
41-
}
49+
}

0 commit comments

Comments
 (0)