1
+ // RUN: %target-typecheck-verify-swift -enable-experimental-concurrency
2
+
3
+ // REQUIRES: concurrency
4
+
5
+ /////
6
+ // This test is focused on checking protocol conformance and constraint checking
7
+
8
+ protocol None {
9
+ associatedtype V
10
+ // expected-note@+2 {{protocol requires property 'someProp' with type 'CA_N.V' (aka 'Int'); do you want to add a stub?}}
11
+ // expected-note@+1 2 {{protocol requires property 'someProp' with type 'Self.V'; do you want to add a stub?}}
12
+ var someProp : V { get }
13
+ }
14
+
15
+ protocol T {
16
+ associatedtype V
17
+ // expected-note@+2 {{protocol requires property 'someProp' with type 'CAT_T.V' (aka 'Int'); do you want to add a stub?}}
18
+ // expected-note@+1 {{protocol requires property 'someProp' with type 'Self.V'; do you want to add a stub?}}
19
+ var someProp : V { get throws }
20
+ }
21
+
22
+ protocol A {
23
+ associatedtype V
24
+ // expected-note@+1 2 {{protocol requires property 'someProp' with type 'Self.V'; do you want to add a stub?}}
25
+ var someProp : V { get async }
26
+ }
27
+
28
+ protocol AT {
29
+ associatedtype V
30
+ var someProp : V { get async throws }
31
+ }
32
+
33
+ /////
34
+ // exercise the space of conformances to a property with effects
35
+ // The naming scheme here is:
36
+ // CN_K
37
+ // where
38
+ // C = "conformer"
39
+ // N = candidate witness's effect abbreviation
40
+ // K = protocol requirement's effect abbreviation
41
+ // "effect abbreviation" = [
42
+ // N -> <none>, T -> throws, A -> async, AT -> async throws
43
+ // ]
44
+
45
+ // First group here also demonstrates that stored or mutable properties can
46
+ // witness a protocol requirement that allows for effects.
47
+ class CN_N : None { typealias V = Int ; var someProp : Int { get { 0 } } }
48
+ class CN_T : T { typealias V = Int ; var someProp : Int = 0 }
49
+ class CN_T_v2 : T { typealias V = Int ; var someProp : Int { get { 0 } } }
50
+ class CN_A : A { typealias V = Int ; var someProp : Int { get { 0 } set { } } }
51
+ class CN_AT : AT { typealias V = Int ; var someProp : Int { _read { yield 0 } } }
52
+ // ------ ------ ------ ------ ------ ------ ------ ------ ------ ------
53
+
54
+ // Remaining conformances test the limit check for kinds of effects allowed
55
+
56
+ // expected-note@+2 3 {{candidate throws, but protocol does not allow it}}
57
+ // expected-error@+1 {{type 'CT_N' does not conform to protocol 'None'}}
58
+ class CT_N : None { typealias V = Int ; var someProp : Int { get throws { 0 } } }
59
+ class CT_T : T { typealias V = Int ; var someProp : Int { get throws { 0 } } }
60
+
61
+ // expected-note@+2 {{candidate throws, but protocol does not allow it}}
62
+ // expected-error@+1{{type 'CT_A' does not conform to protocol 'A'}}
63
+ class CT_A : A { typealias V = Int ; var someProp : Int { get throws { 0 } } }
64
+ class CT_AT : AT { typealias V = Int ; var someProp : Int { get throws { 0 } } }
65
+ // ------ ------ ------ ------ ------ ------ ------ ------ ------ ------
66
+
67
+ // expected-note@+2 3 {{candidate is 'async', but protocol requirement is not}}
68
+ // expected-error@+1 {{type 'CA_N' does not conform to protocol 'None'}}
69
+ struct CA_N : None { typealias V = Int ; var someProp : Int { get async { 0 } } }
70
+
71
+ // expected-note@+2 {{candidate is 'async', but protocol requirement is not}}
72
+ // expected-error@+1 {{type 'CA_T' does not conform to protocol 'T'}}
73
+ class CA_T : T { typealias V = Int ; var someProp : Int { get async { 0 } } }
74
+
75
+ struct CA_A : A { typealias V = Int ; var someProp : Int { get async { 0 } } }
76
+ enum CA_AT : AT { typealias V = Int ; var someProp : Int { get async { 0 } } }
77
+ // ------ ------ ------ ------ ------ ------ ------ ------ ------ ------
78
+
79
+ // I put these on separate lines to ensure diagnostics point to the right thing.
80
+
81
+ // expected-error@+1 {{type 'CAT_N' does not conform to protocol 'None'}}
82
+ class CAT_N : None { typealias V = Int ;
83
+ // expected-note@+2 {{candidate throws, but protocol does not allow it}}
84
+ // expected-note@+1 2 {{candidate is 'async', but protocol requirement is not}}
85
+ var someProp : Int { get async throws { 0 } }
86
+ }
87
+ // expected-error@+1 {{type 'CAT_T' does not conform to protocol 'T'}}
88
+ enum CAT_T : T { typealias V = Int ;
89
+ // expected-note@+2 {{candidate throws, but protocol does not allow it}}
90
+ // expected-note@+1 2 {{candidate is 'async', but protocol requirement is not}}
91
+ var someProp : Int { get async throws { 0 } }
92
+ }
93
+ // expected-error@+1 {{type 'CAT_A' does not conform to protocol 'A'}}
94
+ class CAT_A : A { typealias V = Int ;
95
+ // expected-note@+1 {{candidate throws, but protocol does not allow it}}
96
+ var someProp : Int { get async throws { 0 } }
97
+ }
98
+ class CAT_AT : AT { typealias V = Int ;
99
+ var someProp : Int { get async throws { 0 } }
100
+ }
101
+
102
+ // because the protocols above are generic over a type (i.e.,
103
+ // have an associatedtype), we can't express the constraints
104
+ // below with just 'as'.
105
+
106
+ func asNone< U : None > ( u : U ) async throws {
107
+ _ = u. someProp
108
+ }
109
+
110
+ func asAsync< U : A > ( u : U ) async {
111
+ _ = u. someProp // expected-error {{property access is 'async' but is not marked with 'await'}}
112
+
113
+ _ = await u. someProp
114
+ }
115
+
116
+ func asThrows< U : T > ( u : U ) throws {
117
+ // expected-note@+3 {{did you mean to handle error as optional value?}}
118
+ // expected-note@+2 {{did you mean to disable error propagation?}}
119
+ // expected-note@+1 {{did you mean to use 'try'?}}
120
+ _ = u. someProp // expected-error {{property access can throw but is not marked with 'try'}}
121
+
122
+ _ = try u. someProp
123
+ }
124
+
125
+ func asAsyncThrows< U : AT > ( u : U ) async throws {
126
+ // expected-note@+5 {{did you mean to handle error as optional value?}}
127
+ // expected-note@+4 {{did you mean to disable error propagation?}}
128
+ // expected-note@+3 {{did you mean to use 'try'?}}
129
+ // expected-error@+2 {{property access is 'async' but is not marked with 'await'}}
130
+ // expected-error@+1 {{property access can throw but is not marked with 'try'}}
131
+ _ = u. someProp
132
+
133
+ _ = try await u. someProp
134
+ }
135
+
136
+
137
+ ////////
138
+ // specific conformance coverage for subscripts
139
+
140
+ protocol NoneSub {
141
+ // expected-note@+1 3 {{protocol requires subscript with type '(Int) -> Bool'}}
142
+ subscript( _ i : Int ) -> Bool { get }
143
+ }
144
+
145
+ protocol AsyncSub {
146
+ // expected-note@+1 2 {{protocol requires subscript with type '(Int) -> Bool'}}
147
+ subscript( _ i : Int ) -> Bool { get async }
148
+ }
149
+
150
+ protocol ThrowsSub {
151
+ // expected-note@+1 2 {{protocol requires subscript with type '(Int) -> Bool'}}
152
+ subscript( _ i : Int ) -> Bool { get throws }
153
+ }
154
+
155
+ protocol AsyncThrowsSub {
156
+ subscript( _ i : Int ) -> Bool { get async throws }
157
+ }
158
+
159
+ // "S" stands for "subscript", but otherwise the convention above applies:
160
+ // Sx_y ==> witness x trying to conform to y. A = async, T = throws, AT = async throws
161
+ // I peppered some enums and structs in there for flavor.
162
+
163
+ struct SN_N : NoneSub
164
+ { subscript( _ i : Int ) -> Bool { get { true } } }
165
+ class SA_N : NoneSub // expected-error{{type 'SA_N' does not conform to protocol 'NoneSub'}}
166
+ { subscript( _ i : Int ) -> Bool { get async { true } } } // expected-note{{candidate is 'async', but protocol requirement is not}}
167
+ class ST_N : NoneSub // expected-error{{type 'ST_N' does not conform to protocol 'NoneSub'}}
168
+ { subscript( _ i : Int ) -> Bool { get throws { true } } } // expected-note{{candidate throws, but protocol does not allow it}}
169
+ class SAT_N : NoneSub // expected-error{{type 'SAT_N' does not conform to protocol 'NoneSub'}}
170
+ { subscript( _ i : Int ) -> Bool { get async throws { true } } } // expected-note{{candidate is 'async', but protocol requirement is not}}
171
+
172
+ class SN_A : AsyncSub
173
+ { subscript( _ i : Int ) -> Bool { get { true } } }
174
+ struct SA_A : AsyncSub
175
+ { subscript( _ i : Int ) -> Bool { get async { true } } }
176
+ enum ST_A : AsyncSub // expected-error{{type 'ST_A' does not conform to protocol 'AsyncSub'}}
177
+ { subscript( _ i : Int ) -> Bool { get throws { true } } } // expected-note{{candidate throws, but protocol does not allow it}}
178
+ class SAT_A : AsyncSub // expected-error{{type 'SAT_A' does not conform to protocol 'AsyncSub'}}
179
+ { subscript( _ i : Int ) -> Bool { get async throws { true } } } // expected-note{{candidate throws, but protocol does not allow it}}
180
+
181
+ class SN_T : ThrowsSub
182
+ { subscript( _ i : Int ) -> Bool { get { true } } }
183
+ class SA_T : ThrowsSub // expected-error{{type 'SA_T' does not conform to protocol 'ThrowsSub'}}
184
+ { subscript( _ i : Int ) -> Bool { get async { true } } } // expected-note{{candidate is 'async', but protocol requirement is not}}
185
+ struct ST_T : ThrowsSub
186
+ { subscript( _ i : Int ) -> Bool { get throws { true } } }
187
+ struct SAT_T : ThrowsSub // expected-error{{type 'SAT_T' does not conform to protocol 'ThrowsSub'}}
188
+ { subscript( _ i : Int ) -> Bool { get async throws { true } } } // expected-note{{candidate is 'async', but protocol requirement is not}}
189
+
190
+ class SN_AT : AsyncThrowsSub
191
+ { subscript( _ i : Int ) -> Bool { get { true } } }
192
+ enum SA_AT : AsyncThrowsSub
193
+ { subscript( _ i : Int ) -> Bool { get async { true } } }
194
+ class ST_AT : AsyncThrowsSub
195
+ { subscript( _ i : Int ) -> Bool { get throws { true } } }
196
+ struct SAT_AT : AsyncThrowsSub
197
+ { subscript( _ i : Int ) -> Bool { get async throws { true } } }
198
+
199
+
200
+ ////////
201
+ // protocol composition & inheritance
202
+
203
+ func composed1< U : A & T > ( u : U ) async throws {
204
+ // expected-note@+4 {{did you mean to handle error as optional value?}}
205
+ // expected-note@+3 {{did you mean to disable error propagation?}}
206
+ // expected-note@+2 {{did you mean to use 'try'?}}
207
+ // expected-error@+1 {{property access can throw but is not marked with 'try'}}
208
+ _ = u. someProp
209
+
210
+ // FIXME: this ^ should raise property access is 'async' but is not marked with 'await'
211
+
212
+ _ = try u. someProp
213
+ }
214
+
215
+ func composed2< U : None & A > ( u : U ) async {
216
+ _ = u. someProp
217
+ // FIXME: this ^ should raise "property access is 'async' but is not marked with 'await'""
218
+
219
+ _ = await u. someProp // expected-warning {{no 'async' operations occur within 'await' expression}}
220
+ }
221
+
222
+ func composed3< U : T & None > ( u : U ) throws {
223
+ // expected-note@+3 {{did you mean to handle error as optional value?}}
224
+ // expected-note@+2 {{did you mean to disable error propagation?}}
225
+ // expected-note@+1 {{did you mean to use 'try'?}}
226
+ _ = u. someProp // expected-error {{property access can throw but is not marked with 'try'}}
227
+
228
+ _ = try u. someProp
229
+ }
230
+
231
+ func composed4< U : T & None > ( u : U ) {
232
+ _ = u. someProp // expected-error {{property access can throw, but it is not marked with 'try' and the error is not handled}}
233
+
234
+ _ = try ! u. someProp
235
+ }
236
+
237
+
238
+ /////////////////
239
+ // redefining the protocols to make sure the fix-its are matched
240
+
241
+ protocol NoEffects {
242
+ // expected-note@+1 2 {{protocol requires property 'someProp' with type 'Int'; do you want to add a stub?}}
243
+ var someProp : Int { get }
244
+ }
245
+
246
+ protocol Throws {
247
+ // expected-note@+1 2 {{protocol requires property 'someProp' with type 'Int'; do you want to add a stub?}}
248
+ var someProp : Int { get throws }
249
+ }
250
+
251
+ protocol Async {
252
+ // expected-note@+1 3 {{protocol requires property 'someProp' with type 'Int'; do you want to add a stub?}}
253
+ var someProp : Int { get async }
254
+ }
255
+
256
+ protocol AsyncThrowsByInheritance : Async , Throws { }
257
+ protocol AsyncByInheritance : Async , NoEffects { }
258
+ protocol ThrowsByInheritance : Throws , NoEffects { }
259
+
260
+ extension CN_N : AsyncByInheritance , ThrowsByInheritance , AsyncThrowsByInheritance { }
261
+ extension CN_T : AsyncByInheritance , ThrowsByInheritance , AsyncThrowsByInheritance { }
262
+ extension CN_A : AsyncByInheritance , ThrowsByInheritance , AsyncThrowsByInheritance { }
263
+ extension CN_AT : AsyncByInheritance , ThrowsByInheritance , AsyncThrowsByInheritance { }
264
+
265
+ // ----- -----
266
+
267
+ extension CT_N : Throws { }
268
+
269
+ // expected-error@+1 {{type 'CT_N' does not conform to protocol 'NoEffects'}}
270
+ extension CT_N : ThrowsByInheritance { }
271
+
272
+ // expected-error@+1 {{type 'CT_N' does not conform to protocol 'Async'}}
273
+ extension CT_N : AsyncByInheritance { }
274
+
275
+ // ----- -----
276
+
277
+ extension CA_N : Async { }
278
+
279
+ // expected-error@+1 {{type 'CA_N' does not conform to protocol 'NoEffects'}}
280
+ extension CA_N : AsyncByInheritance { }
281
+
282
+ // expected-error@+1 {{type 'CA_N' does not conform to protocol 'Throws'}}
283
+ extension CA_N : ThrowsByInheritance { }
284
+
285
+ // ----- -----
286
+
287
+ // expected-error@+1 {{type 'CAT_N' does not conform to protocol 'Async'}}
288
+ extension CAT_N : Async { }
289
+
290
+ // expected-error@+1 {{type 'CAT_N' does not conform to protocol 'Throws'}}
291
+ extension CAT_N : Throws { }
292
+
293
+ // expected-error@+2 {{type 'CAT_T' does not conform to protocol 'Async'}}
294
+ // expected-error@+1 {{type 'CAT_T' does not conform to protocol 'Throws'}}
295
+ extension CAT_T : AsyncThrowsByInheritance { }
296
+
297
+
298
+ struct S : Async , Throws {
299
+ var someProp : Int { 3 }
300
+ }
301
+
302
+ func play( s : S ) async throws {
303
+ _ = s. someProp
304
+ _ = await ( s as Async ) . someProp
305
+ _ = try ( s as Throws ) . someProp
306
+ }
307
+
308
+ //////////
309
+ /// Check protocol overrides. Cannot override with more effects.
310
+
311
+ protocol HammeredDulcimer {
312
+ subscript( _ note : Int ) -> Int { get }
313
+ var bridges : Int { get async throws }
314
+ }
315
+
316
+ protocol Santur : HammeredDulcimer {
317
+ override subscript( _ note : Int ) -> Int { get throws } // expected-error{{cannot override non-'throws' subscript with 'throws' subscript}}
318
+ override var bridges : Int { get throws }
319
+ }
320
+
321
+ protocol Santoor : Santur {
322
+ override var bridges : Int { get async throws } // expected-error{{cannot override non-'async' property with 'async' property}}
323
+ }
324
+
325
+ protocol Yangqin : HammeredDulcimer {
326
+ override var bridges : Int { get async throws } // same effects are OK
327
+ }
328
+
329
+ protocol Hackbrett : HammeredDulcimer {
330
+ override var bridges : Int { get } // no effects are OK
331
+ override subscript( _ note : Int ) -> Int { get async throws } // expected-error {{cannot override non-'async' subscript with 'async' subscript}}
332
+ }
0 commit comments