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