-
Notifications
You must be signed in to change notification settings - Fork 10.4k
/
Copy pathasync_await.swift
241 lines (194 loc) · 9.56 KB
/
async_await.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
// RUN: %target-swift-frontend -typecheck -verify %s -disable-availability-checking
// REQUIRES: concurrency
func test1(asyncfp : () async -> Int, fp : () -> Int) async {
_ = await asyncfp()
_ = await asyncfp() + asyncfp()
_ = await asyncfp() + fp()
_ = await fp() + 42 // expected-warning {{no 'async' operations occur within 'await' expression}}
_ = 32 + asyncfp() + asyncfp() // expected-error {{expression is 'async' but is not marked with 'await'}}{{7-7=await }}
// expected-note@-1:12{{call is 'async'}}
// expected-note@-2:24{{call is 'async'}}
}
func getInt() async -> Int { return 5 }
// Locations where "await" is prohibited.
func test2(
defaulted: Int = await getInt() // expected-error{{'async' call cannot occur in a default argument}}
) async {
defer {
_ = await getInt() // expected-error{{'async' call cannot occur in a defer body}}
}
print("foo")
}
func test3() { // expected-note{{add 'async' to function 'test3()' to make it asynchronous}} {{13-13= async}}
_ = await getInt() // expected-error{{'async' call in a function that does not support concurrency}}
}
func test4()throws { // expected-note{{add 'async' to function 'test4()' to make it asynchronous}} {{13-19=async throws}}
_ = await getInt() // expected-error{{'async' call in a function that does not support concurrency}}
}
func test5<T>(_ f : () async throws -> T) rethrows->T { // expected-note{{add 'async' to function 'test5' to make it asynchronous}} {{44-52=async rethrows}}
return try await f() // expected-error{{'async' call in a function that does not support concurrency}}
}
enum SomeEnum: Int {
case foo = await 5 // expected-error{{raw value for enum case must be a literal}}
}
struct SomeStruct {
var x = await getInt() // expected-error{{'async' call cannot occur in a property initializer}}
static var y = await getInt() // expected-error{{'async' call cannot occur in a global variable initializer}}
}
func acceptAutoclosureNonAsync(_: @autoclosure () -> Int) async { }
func acceptAutoclosureAsync(_: @autoclosure () async -> Int) async { }
func acceptAutoclosureAsyncThrows(_: @autoclosure () async throws -> Int) async { }
func acceptAutoclosureAsyncThrowsRethrows(_: @autoclosure () async throws -> Int) async rethrows { }
func acceptAutoclosureNonAsyncBad(_: @autoclosure () async -> Int) -> Int { 0 }
// expected-error@-1{{'async' autoclosure parameter in a non-'async' function}}
// expected-note@-2{{add 'async' to function 'acceptAutoclosureNonAsyncBad' to make it asynchronous}} {{67-67= async}}
struct HasAsyncBad {
init(_: @autoclosure () async -> Int) { }
// expected-error@-1{{'async' autoclosure parameter in a non-'async' function}}
}
func testAutoclosure() async {
await acceptAutoclosureAsync(await getInt())
await acceptAutoclosureNonAsync(await getInt()) // expected-error{{'async' call in an autoclosure that does not support concurrency}}
await acceptAutoclosureAsync(42 + getInt())
// expected-error@-1:32{{expression is 'async' but is not marked with 'await'}}{{32-32=await }}
// expected-note@-2:37{{call is 'async' in an autoclosure argument}}
await acceptAutoclosureNonAsync(getInt()) // expected-error{{'async' call in an autoclosure that does not support concurrency}}
}
// Test inference of 'async' from the body of a closure.
func testClosure() {
let closure = {
await getInt()
}
let _: () -> Int = closure // expected-error{{invalid conversion from 'async' function of type '() async -> Int' to synchronous function type '() -> Int'}}
let closure2 = { () async -> Int in
print("here")
return await getInt()
}
let _: () -> Int = closure2 // expected-error{{invalid conversion from 'async' function of type '() async -> Int' to synchronous function type '() -> Int'}}
}
// Nesting async and await together
func throwingAndAsync() async throws -> Int { return 0 }
enum HomeworkError : Error {
case dogAteIt
}
func testThrowingAndAsync() async throws {
_ = try await throwingAndAsync()
_ = await try throwingAndAsync() // expected-warning{{'try' must precede 'await'}}{{7-13=}}{{17-17=await }}
_ = await (try throwingAndAsync())
_ = try (await throwingAndAsync())
// Errors
_ = await throwingAndAsync() // expected-error{{call can throw but is not marked with 'try'}}
// expected-note@-1{{did you mean to use 'try'?}}{{7-7=try }}
// expected-note@-2{{did you mean to handle error as optional value?}}{{7-7=try? }}
// expected-note@-3{{did you mean to disable error propagation?}}{{7-7=try! }}
_ = try throwingAndAsync()
// expected-error@-1{{expression is 'async' but is not marked with 'await'}}{{11-11=await }}
// expected-note@-2{{call is 'async'}}
}
func testExhaustiveDoCatch() async {
do {
_ = try await throwingAndAsync()
} catch {
}
do {
_ = try await throwingAndAsync()
// expected-error@-1{{errors thrown from here are not handled because the enclosing catch is not exhaustive}}
} catch let e as HomeworkError {
}
// Ensure that we infer 'async' through an exhaustive do-catch.
let fn = {
do {
_ = try await throwingAndAsync()
} catch {
}
}
let _: Int = fn // expected-error{{cannot convert value of type '() async -> ()'}}
// Ensure that we infer 'async' through a non-exhaustive do-catch.
let fn2 = {
do {
_ = try await throwingAndAsync()
} catch let e as HomeworkError {
}
}
let _: Int = fn2 // expected-error{{cannot convert value of type '() async throws -> ()'}}
}
// String interpolation
func testStringInterpolation() async throws {
// expected-error@+2:30{{expression is 'async' but is not marked with 'await'}}{{30-30=await }}
// expected-note@+1:35{{call is 'async'}}
_ = "Eventually produces \(32 + getInt())"
_ = "Eventually produces \(await getInt())"
_ = await "Eventually produces \(getInt())"
}
func invalidAsyncFunction() async {
_ = try await throwingAndAsync() // expected-error {{errors thrown from here are not handled}}
}
func validAsyncFunction() async throws {
_ = try await throwingAndAsync()
}
// Async let checking
func mightThrow() throws { }
func getIntUnsafely() throws -> Int { 0 }
func getIntUnsafelyAsync() async throws -> Int { 0 }
extension Error {
var number: Int { 0 }
}
func testAsyncLet() async throws {
async let x = await getInt()
print(x) // expected-error{{expression is 'async' but is not marked with 'await'}}
// expected-note@-1:9{{reference to async let 'x' is 'async'}}
print(await x)
do {
try mightThrow()
} catch let e where e.number == x { // expected-error{{async let 'x' cannot be referenced in a catch guard expression}}
} catch {
}
defer {
async let deferX: Int = await getInt() // expected-error {{'async let' cannot be used on declarations in a defer body}}
_ = await deferX // expected-error {{async let 'deferX' cannot be referenced in a defer body}}
async let _: Int = await getInt() // expected-error {{'async let' cannot be used on declarations in a defer body}}
async let _ = await getInt() // expected-error {{'async let' cannot be used on declarations in a defer body}}
}
async let x1 = getIntUnsafely() // okay, try is implicit here
async let x2 = getInt() // okay, await is implicit here
async let x3 = try getIntUnsafely()
async let x4 = try! getIntUnsafely()
async let x5 = try? getIntUnsafely()
_ = await x1 // expected-error{{reading 'async let' can throw but is not marked with 'try'}}
_ = await x2
_ = try await x3
_ = await x4
_ = await x5
}
func search(query: String) async throws -> [String] {
let entities: [String] = []
async let r = entities.filter { $0.contains(query) }.map { String($0) }
return await r
}
// expected-note@+1 3{{add 'async' to function 'testAsyncLetOutOfAsync()' to make it asynchronous}} {{30-30= async}}
func testAsyncLetOutOfAsync() {
async let x = 1 // expected-error{{'async let' in a function that does not support concurrency}}
_ = await x // expected-error{{'async let' in a function that does not support concurrency}}
_ = x // expected-error{{'async let' in a function that does not support concurrency}}
}
class A {}
class B: A {}
func f(_ x: String) async -> String? { x }
func testAsyncExprWithoutAwait() async {
async let result: B? = nil
if let result: A = result {} // expected-error {{expression is 'async' but is not marked with 'await'}} {{22-22=await }}
// expected-warning@-1 {{immutable value 'result' was never used; consider replacing with '_' or removing it}}
// expected-note@-2 {{reference to async let 'result' is 'async'}}
if let result: A {} // expected-error {{expression is 'async' but is not marked with 'await'}} {{18-18=await }}
// expected-warning@-1 {{immutable value 'result' was never used; consider replacing with '_' or removing it}}
// expected-note@-2 {{reference to async let 'result' is 'async'}}
if let result = result {} // expected-error {{expression is 'async' but is not marked with 'await'}} {{19-19=await }}
// expected-warning@-1 {{value 'result' was defined but never used; consider replacing with boolean test}}
// expected-note@-2 {{reference to async let 'result' is 'async'}}
if let result {} // expected-error {{expression is 'async' but is not marked with 'await'}} {{10-10=await }}
// expected-warning@-1 {{value 'result' was defined but never used; consider replacing with boolean test}}
// expected-note@-2 {{reference to async let 'result' is 'async'}}
let a = f("a") // expected-error {{expression is 'async' but is not marked with 'await'}} {{11-11=await }}
// expected-warning@-1 {{initialization of immutable value 'a' was never used; consider replacing with assignment to '_' or removing it}}
// expected-note@-2 {{call is 'async'}}
}