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
|
// RUN: %target-swift-frontend -disable-availability-checking %s -emit-sil -o /dev/null -verify
// RUN: %target-swift-frontend -disable-availability-checking %s -emit-sil -o /dev/null -verify -strict-concurrency=targeted
// RUN: %target-swift-frontend -disable-availability-checking %s -emit-sil -o /dev/null -verify -strict-concurrency=complete
// RUN: %target-swift-frontend -disable-availability-checking %s -emit-sil -o /dev/null -verify -strict-concurrency=complete -enable-upcoming-feature RegionBasedIsolation
// REQUIRES: concurrency
// REQUIRES: asserts
// These tests cover various interactions with async functions that are
// either throws or rethrows.
// See rdar://70813762 and rdar://70751405
enum InvocationError : Error {
case ErrVal
}
func asyncThrows() async throws {
throw InvocationError.ErrVal
}
// T = Int
func asyncRethrows(fn : () async throws -> Int) async rethrows -> Int {
return try await fn()
}
// T = String
func asyncRethrows(fn : () async throws -> String) async rethrows -> String {
return try await fn()
}
// Generic. NOTE the 'rethrows'
func invoke<T>(fn : () async throws -> T) async rethrows -> T {
return try await fn()
}
// NOTE the 'rethrows'
func invokeAuto<T>(_ val : @autoclosure () async throws -> T) async rethrows -> T {
return try await val()
}
func normalTask() async -> Int {
return 42
}
func throwingTask() async throws -> String {
if 1.0 / 3.0 == 0.33 {
throw InvocationError.ErrVal
}
return "ok!"
}
// expected-note@+1 7 {{add 'async' to function 'syncTest()' to make it asynchronous}} {{16-16= async}}
func syncTest() {
let _ = invoke(fn: normalTask) // expected-error{{'async' call in a function that does not support concurrency}}
let _ = invokeAuto(42) // expected-error{{'async' call in a function that does not support concurrency}}
let _ = invokeAuto("intuitive") // expected-error{{'async' call in a function that does not support concurrency}}
let _ = try! asyncRethrows(fn: throwingTask) // expected-error{{'async' call in a function that does not support concurrency}}
let _ = try? invoke(fn: throwingTask) // expected-error{{'async' call in a function that does not support concurrency}}
do {
let _ = try invoke(fn: throwingTask) // expected-error{{'async' call in a function that does not support concurrency}}
let _ = try asyncThrows() // expected-error{{'async' call in a function that does not support concurrency}}
} catch {
// ignore it
}
}
func asyncTest() async {
///////////
// tests that also omit await
// expected-error@+2{{expression is 'async' but is not marked with 'await'}}{{11-11=await }}
// expected-note@+1{{call is 'async'}}
let _ = invoke(fn: normalTask)
// expected-error@+2{{expression is 'async' but is not marked with 'await'}}{{11-11=await }}
// expected-note@+1{{call is 'async'}}
let _ = asyncRethrows(fn: normalTask)
// expected-error@+2{{expression is 'async' but is not marked with 'await'}}{{11-11=await }}
// expected-note@+1{{call is 'async'}}
let _ = invokeAuto(42)
// expected-error@+3 {{call can throw, but it is not marked with 'try' and the error is not handled}}
// expected-error@+2 {{expression is 'async' but is not marked with 'await'}}{{11-11=await }}
// expected-note@+1 {{call is 'async'}}
let _ = asyncThrows()
// expected-note@+4{{call is to 'rethrows' function, but argument function can throw}}
// expected-error@+3{{call can throw, but it is not marked with 'try' and the error is not handled}}
// expected-error@+2{{expression is 'async' but is not marked with 'await'}}{{11-11=await }}
// expected-note@+1:11{{call is 'async'}}
let _ = invoke(fn: throwingTask)
///////////
// tests that use await and handles the exceptions
// expected-note@+2{{call is to 'rethrows' function, but argument function can throw}}
// expected-error@+1{{call can throw, but it is not marked with 'try' and the error is not handled}}
let _ = await invoke(fn: throwingTask)
let _ = await invoke(fn: normalTask) // ok
let _ = await asyncRethrows(fn: normalTask)
let _ = try! await asyncRethrows(fn: normalTask) // expected-warning{{no calls to throwing functions occur within 'try' expression}}
let _ = try? await asyncRethrows(fn: normalTask) // expected-warning{{no calls to throwing functions occur within 'try' expression}}
let _ = try! await asyncRethrows(fn: throwingTask)
let _ = try? await asyncRethrows(fn: throwingTask)
let _ = try! await asyncThrows()
let _ = try? await asyncThrows()
//////////
// some auto-closure tests
let _ = await invokeAuto("intuitive")
let _ = try! await invokeAuto(await throwingTask())
let _ = try? await invokeAuto(await throwingTask())
let _ = await invokeAuto(try! await throwingTask())
let _ = await invokeAuto(try? await throwingTask())
// expected-error@+1{{expression is 'async' but is not marked with 'await'}}{{33-33=await }}
let _ = await invokeAuto(try! throwingTask()) // expected-note@:33{{call is 'async' in an autoclosure argument}}
// expected-error@+1{{expression is 'async' but is not marked with 'await'}}{{33-33=await }}
let _ = await invokeAuto(try? throwingTask()) // expected-note@:33{{call is 'async' in an autoclosure argument}}
let _ = await invokeAuto(try! await throwingTask())
let _ = await invokeAuto(try? await throwingTask())
/////////
do {
let _ = try await asyncThrows()
let _ = try await asyncRethrows(fn: throwingTask)
//////
// more auto-closure tests
// expected-note@+7 {{did you mean to disable error propagation?}}
// expected-note@+6 {{did you mean to handle error as optional value?}}
// expected-note@+5 {{did you mean to use 'try'?}}
// expected-note@+4 {{call is to 'rethrows' function, but argument function can throw}}
// expected-note@+3 {{call is 'async' in an autoclosure argument}}
// expected-error@+2 {{expression is 'async' but is not marked with 'await'}}{{30-30=await }}
// expected-error@+1 2 {{call can throw but is not marked with 'try'}}
let _ = await invokeAuto(throwingTask())
// expected-error@+1:34{{expression is 'async' but is not marked with 'await'}}{{34-34=await }}
let _ = try await invokeAuto("hello" + throwingTask()) // expected-note@:44{{call is 'async' in an autoclosure argument}}
// expected-error@+1{{expression is 'async' but is not marked with 'await'}}{{17-17=await }}
let _ = try invokeAuto(await throwingTask()) // expected-note{{call is 'async'}}
let _ = try await invokeAuto(await throwingTask())
} catch {
// ignore
}
}
// rdar://123356909 - spurious error - `call can throw, but it is not marked with 'try' and the error is not handled`
do {
struct AsyncTestSequence<Element>: AsyncSequence {
typealias Element = Element
let stream: AsyncMapSequence<AsyncStream<[String : Any]>, Element>
init(stream: AsyncMapSequence<AsyncStream<[String : Any]>, Element>) {
self.stream = stream
}
func makeAsyncIterator() -> AsyncIterator {
.init(iterator: stream.makeAsyncIterator())
}
struct AsyncIterator: AsyncIteratorProtocol {
var iterator: AsyncMapSequence<AsyncStream<[String : Any]>, Element>.AsyncIterator
mutating func next() async -> Element? {
await iterator.next() // Ok
}
}
}
}
|