1+ // RUN: %target-typecheck-verify-swift -enable-experimental-concurrency
2+ // REQUIRES: concurrency
3+
4+ // These tests cover various interactions with async functions that are
5+ // either throws or rethrows.
6+ // See rdar://70813762 and rdar://70751405
7+
8+ enum InvocationError : Error {
9+ case ErrVal
10+ }
11+
12+ func asyncThrows( ) async throws {
13+ throw InvocationError . ErrVal
14+ }
15+
16+ // T = Int
17+ func asyncRethrows( fn : ( ) async throws -> Int ) async rethrows -> Int {
18+ return await try fn ( )
19+ }
20+
21+ // T = String
22+ func asyncRethrows( fn : ( ) async throws -> String ) async rethrows -> String {
23+ return await try fn ( )
24+ }
25+
26+ // Generic. NOTE the 'rethrows'
27+ func invoke< T> ( fn : ( ) async throws -> T ) async rethrows -> T {
28+ return await try fn ( )
29+ }
30+
31+ // NOTE the 'rethrows'
32+ func invokeAuto< T> ( _ val : @autoclosure ( ) async throws -> T ) async rethrows -> T {
33+ return await try val ( )
34+ }
35+
36+ func normalTask( ) async -> Int {
37+ return 42
38+ }
39+
40+ func throwingTask( ) async throws -> String {
41+ if 1.0 / 3.0 == 0.33 {
42+ throw InvocationError . ErrVal
43+ }
44+ return " ok! "
45+ }
46+
47+ // expected-note@+2 7 {{add '@asyncHandler' to function 'syncTest()' to create an implicit asynchronous context}}
48+ // expected-note@+1 7 {{add 'async' to function 'syncTest()' to make it asynchronous}}
49+ func syncTest( ) {
50+ let _ = invoke ( fn: normalTask) // expected-error{{'async' in a function that does not support concurrency}}
51+ let _ = invokeAuto ( 42 ) // expected-error{{'async' in a function that does not support concurrency}}
52+ let _ = invokeAuto ( " intuitive " ) // expected-error{{'async' in a function that does not support concurrency}}
53+
54+ let _ = try ! asyncRethrows ( fn: throwingTask) // expected-error{{'async' in a function that does not support concurrency}}
55+ let _ = try ? invoke ( fn: throwingTask) // expected-error{{'async' in a function that does not support concurrency}}
56+ do {
57+ let _ = try invoke ( fn: throwingTask) // expected-error{{'async' in a function that does not support concurrency}}
58+ let _ = try asyncThrows ( ) // expected-error{{'async' in a function that does not support concurrency}}
59+ } catch {
60+ // ignore it
61+ }
62+ }
63+
64+
65+ func asyncTest( ) async {
66+ ///////////
67+ // tests that also omit await
68+
69+ let _ = invoke ( fn: normalTask) // expected-error{{call is 'async' but is not marked with 'await'}}
70+ let _ = asyncRethrows ( fn: normalTask) // expected-error{{call is 'async' but is not marked with 'await'}}
71+ let _ = invokeAuto ( 42 ) // expected-error{{call is 'async' but is not marked with 'await'}}
72+
73+ // expected-error@+2 {{call can throw, but it is not marked with 'try' and the error is not handled}}
74+ // expected-error@+1 {{call is 'async' but is not marked with 'await'}}
75+ let _ = asyncThrows ( )
76+
77+ // expected-note@+3{{call is to 'rethrows' function, but argument function can throw}}
78+ // expected-error@+2{{call can throw, but it is not marked with 'try' and the error is not handled}}
79+ // expected-error@+1{{call is 'async' but is not marked with 'await'}}
80+ let _ = invoke ( fn: throwingTask)
81+
82+ ///////////
83+ // tests that use await and handles the exceptions
84+
85+ // expected-note@+2{{call is to 'rethrows' function, but argument function can throw}}
86+ // expected-error@+1{{call can throw, but it is not marked with 'try' and the error is not handled}}
87+ let _ = await invoke ( fn: throwingTask)
88+ let _ = await invoke ( fn: normalTask) // ok
89+
90+ let _ = await asyncRethrows ( fn: normalTask)
91+ let _ = await try ! asyncRethrows ( fn: normalTask) // expected-warning{{no calls to throwing functions occur within 'try' expression}}
92+ let _ = await try ? asyncRethrows ( fn: normalTask) // expected-warning{{no calls to throwing functions occur within 'try' expression}}
93+
94+ let _ = await try ! asyncRethrows ( fn: throwingTask)
95+ let _ = await try ? asyncRethrows ( fn: throwingTask)
96+ let _ = await try ! asyncThrows ( )
97+ let _ = await try ? asyncThrows ( )
98+
99+ //////////
100+ // some auto-closure tests
101+
102+ let _ = await invokeAuto ( " intuitive " )
103+ let _ = await try ! invokeAuto ( await throwingTask ( ) )
104+ let _ = await try ? invokeAuto ( await throwingTask ( ) )
105+ let _ = await invokeAuto ( await try ! throwingTask ( ) )
106+ let _ = await invokeAuto ( await try ? throwingTask ( ) )
107+
108+ // FIXME: we currently emit a less-helpful error message here.
109+ // it would be better if we said "call is 'async' in an autoclosure argument that is not marked with 'await'"
110+ let _ = await invokeAuto ( try ! throwingTask ( ) ) // expected-error{{call is 'async' but is not marked with 'await'}}
111+ let _ = await invokeAuto ( try ? throwingTask ( ) ) // expected-error{{call is 'async' but is not marked with 'await'}}
112+
113+ let _ = await invokeAuto ( await try ! throwingTask ( ) )
114+ let _ = await invokeAuto ( await try ? throwingTask ( ) )
115+ /////////
116+
117+ do {
118+ let _ = await try asyncThrows ( )
119+ let _ = await try asyncRethrows ( fn: throwingTask)
120+
121+ //////
122+ // more auto-closure tests
123+
124+ // expected-note@+6 {{did you mean to disable error propagation?}}
125+ // expected-note@+5 {{did you mean to handle error as optional value?}}
126+ // expected-note@+4 {{did you mean to use 'try'?}}
127+ // expected-note@+3 {{call is to 'rethrows' function, but argument function can throw}}
128+ // expected-error@+2 {{call is 'async' in an autoclosure argument that is not marked with 'await'}}
129+ // expected-error@+1 2 {{call can throw but is not marked with 'try'}}
130+ let _ = await invokeAuto ( throwingTask ( ) )
131+
132+ let _ = await try invokeAuto ( throwingTask ( ) ) // expected-error{{call is 'async' in an autoclosure argument that is not marked with 'await'}}
133+ let _ = try invokeAuto ( await throwingTask ( ) ) // expected-error{{call is 'async' but is not marked with 'await'}}
134+ let _ = await try invokeAuto ( await throwingTask ( ) )
135+ } catch {
136+ // ignore
137+ }
138+ }
0 commit comments