Skip to content

Commit ea17a92

Browse files
committed
[Concurrency] Adopt typed throws in Task creation APIs
1 parent d653b0c commit ea17a92

File tree

3 files changed

+32
-19
lines changed

3 files changed

+32
-19
lines changed

stdlib/public/Concurrency/Task+init.swift.gyb

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import Swift
2626
% [ # PARAMS
2727
% 'name: String? = nil',
2828
% 'priority: TaskPriority? = nil',
29-
% '@_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async throws -> Success',
29+
% '@_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async throws(Failure) -> Success',
3030
% ]),
3131
% # ==== --------------------------------------------------------------------
3232
% ([ # METHOD_VARIANT
@@ -40,7 +40,7 @@ import Swift
4040
% [ # PARAMS
4141
% 'name: String? = nil',
4242
% 'priority: TaskPriority? = nil',
43-
% 'operation: sending @escaping @isolated(any) () async throws -> Success',
43+
% 'operation: sending @escaping @isolated(any) () async throws(Failure) -> Success',
4444
% ]),
4545
% # ==== -------------------------------------------------------------------------------------------------------------
4646
% # ==== With task executor, but available only since 6.0
@@ -56,7 +56,7 @@ import Swift
5656
% 'name: String? = nil',
5757
% 'executorPreference taskExecutor: (any TaskExecutor)?',
5858
% 'priority: TaskPriority? = nil',
59-
% 'operation: sending @escaping () async throws -> Success',
59+
% 'operation: sending @escaping () async throws(Failure) -> Success',
6060
% ]),
6161
% # ==== --------------------------------------------------------------------
6262
% ([ # METHOD_VARIANT
@@ -71,7 +71,7 @@ import Swift
7171
% 'name: String? = nil',
7272
% 'executorPreference taskExecutor: (any TaskExecutor)?',
7373
% 'priority: TaskPriority? = nil',
74-
% 'operation: sending @escaping () async throws -> Success',
74+
% 'operation: sending @escaping () async throws(Failure) -> Success',
7575
% ]),
7676
% # !!!! -------------------------------------------------------------------------------------------------------------
7777
% # !!!! Legacy / Source Compatibility "Shims"
@@ -91,6 +91,7 @@ import Swift
9191
% ],
9292
% [ # PARAMS
9393
% 'priority: TaskPriority? = nil',
94+
% # detach does not support typed throws, it's a legacy api for compat only
9495
% '@_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping @isolated(any) () async throws -> Success',
9596
% ]),
9697
% # ==== Legacy API: runDetached
@@ -105,6 +106,7 @@ import Swift
105106
% ],
106107
% [ # PARAMS
107108
% 'priority: TaskPriority? = nil',
109+
% # runDetached does not support typed throws, it's a legacy api for compat only
108110
% '@_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping @isolated(any) () async throws -> Success',
109111
% ]),
110112
% # ==== Legacy API: asyncDetached
@@ -119,6 +121,7 @@ import Swift
119121
% ],
120122
% [ # PARAMS
121123
% 'priority: TaskPriority? = nil',
124+
% # asyncDetached does not support typed throws, it's a legacy api for compat only
122125
% '@_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping @isolated(any) () async throws -> Success',
123126
% ]),
124127
% # ==== Legacy API: async
@@ -133,6 +136,7 @@ import Swift
133136
% ],
134137
% [ # PARAMS
135138
% 'priority: TaskPriority? = nil',
139+
% # async does not support typed throws, it's a legacy api for compat only
136140
% '@_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping @isolated(any) () async throws -> Success',
137141
% ]),
138142
% ]:
@@ -149,8 +153,10 @@ import Swift
149153
% HAS_ISOLATED_ANY = any('@isolated(any)' in param for param in PARAMS)
150154
% IS_DEPRECATED = any('deprecated' in a for a in ALL_AVAILABILITY)
151155
%
152-
% if IS_THROWING:
153-
% FAILURE_TYPE = 'Error'
156+
% if IS_THROWING and IS_TOP_LEVEL_FUNC:
157+
% FAILURE_TYPE = 'Error' # the legacy top-level funcs don't have a generic Failure, so we keep the un-typed throw
158+
% elif IS_THROWING:
159+
% FAILURE_TYPE = 'Failure' # use typed throws, the thrown type is Failure of the Task<_, Failure> type
154160
% else:
155161
% FAILURE_TYPE = 'Never'
156162
% end
@@ -162,6 +168,7 @@ def adjust_params_for_kind(params):
162168
for p in params:
163169
np = p
164170
if not IS_THROWING:
171+
np = np.replace("throws(Failure)", "")
165172
np = np.replace("throws", "")
166173
res.append(np)
167174
return res
@@ -184,8 +191,12 @@ else:
184191

185192
% # ====================================================================================================================
186193
% if not IS_TOP_LEVEL_FUNC:
194+
% if IS_THROWING:
195+
extension Task { // throwing Failure error type
196+
% else:
187197
extension Task where Failure == ${FAILURE_TYPE} {
188198
% end
199+
% end
189200

190201
% # --------------------------------------------------------------------------------------------------------------------
191202
#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
@@ -285,8 +296,10 @@ extension Task where Failure == ${FAILURE_TYPE} {
285296
/// - Returns: A reference to the task.
286297
% end # IS_DEPRECATED
287298
${"\n ".join(adjust_availability(ALL_AVAILABILITY))}
299+
% if not IS_THROWING:
288300
@discardableResult
289-
public ${METHOD_VARIANT}( // Task ${METHOD_VARIANT}
301+
% end
302+
public ${METHOD_VARIANT}(
290303
${",\n ".join(adjust_params_for_kind(PARAMS))}
291304
) ${ARROW_RETURN_TYPE}{
292305

@@ -323,7 +336,7 @@ extension Task where Failure == ${FAILURE_TYPE} {
323336
initialTaskExecutorConsuming: taskExecutor,
324337
% end
325338
taskName: nameBytes.baseAddress!._rawValue,
326-
operation: operation).0
339+
operation: operation).0 // Task ${METHOD_VARIANT}
327340
}
328341
#else // no $BuiltinCreateAsyncTaskOwnedTaskExecutor
329342
// legacy branch for the non-consuming task executor
@@ -338,7 +351,7 @@ extension Task where Failure == ${FAILURE_TYPE} {
338351
% end
339352
initialTaskExecutor: executorBuiltin,
340353
taskName: nameBytes.baseAddress!._rawValue,
341-
operation: operation).0
354+
operation: operation).0 // Task ${METHOD_VARIANT}
342355
}
343356
#endif // $BuiltinCreateAsyncTaskOwnedTaskExecutor
344357
% else: # if no TASK_EXECUTOR
@@ -350,7 +363,7 @@ extension Task where Failure == ${FAILURE_TYPE} {
350363
initialSerialExecutor: builtinSerialExecutor,
351364
% end
352365
taskName: nameBytes.baseAddress!._rawValue,
353-
operation: operation).0
366+
operation: operation).0 // Task ${METHOD_VARIANT}
354367
}
355368
% end # if no HAS_TASK_EXECUTOR
356369
} // let name
@@ -368,7 +381,7 @@ extension Task where Failure == ${FAILURE_TYPE} {
368381
initialSerialExecutor: builtinSerialExecutor,
369382
% end
370383
initialTaskExecutorConsuming: taskExecutor,
371-
operation: operation).0
384+
operation: operation).0 // Task ${METHOD_VARIANT}
372385
#else
373386
// legacy branch for the non-consuming task executor
374387
let executorBuiltin: Builtin.Executor =
@@ -380,7 +393,7 @@ extension Task where Failure == ${FAILURE_TYPE} {
380393
initialSerialExecutor: builtinSerialExecutor,
381394
% end
382395
initialTaskExecutor: executorBuiltin,
383-
operation: operation).0
396+
operation: operation).0 // Task ${METHOD_VARIANT}
384397
#endif
385398
}
386399
% end # HAS_TASK_EXECUTOR
@@ -392,7 +405,7 @@ extension Task where Failure == ${FAILURE_TYPE} {
392405
% if HAS_ISOLATED_ANY:
393406
initialSerialExecutor: builtinSerialExecutor,
394407
% end
395-
operation: operation).0
408+
operation: operation).0 // Task ${METHOD_VARIANT}
396409
}
397410

398411
% if IS_INIT:

test/Concurrency/sendable_metatype_typecheck.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,15 +190,15 @@ func f<T: P>(_: T.Type) {
190190
}
191191

192192
func sendableSequence<S: AsyncSequence & Sendable>(_ s: S) throws {
193-
Task.detached {
193+
_ = Task.detached {
194194
for try await i in s {
195195
print(i)
196196
}
197197
}
198198
}
199199

200200
func nonSendableSequence<S: AsyncSequence>(_ s: S) throws {
201-
Task.detached {
201+
_ = Task.detached {
202202
for try await i in s { // expected-warning{{capture of non-Sendable type 'S.AsyncIterator.Type' in an isolated closure}}
203203
// expected-warning@-1{{capture of non-Sendable type 'S.Type' in an isolated closure}}
204204
print(i)

test/Concurrency/task_naming_availability.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ func testName() {
1010
@available(SwiftStdlib 6.0, *)
1111
func taskExecutor() async {
1212
Task(name: "name", executorPreference: nil) { }
13-
Task(name: "name", executorPreference: nil) { throw Boom() }
13+
_ = Task(name: "name", executorPreference: nil) { throw Boom() }
1414

15-
Task.detached(name: "name", executorPreference: nil) { throw Boom() }
15+
_ = Task.detached(name: "name", executorPreference: nil) { throw Boom() }
1616

1717
await withTaskGroup(of: Void.self) { group in
1818
group.addTask(name: "name", executorPreference: nil) {
@@ -40,10 +40,10 @@ func taskExecutor() async {
4040
@available(SwiftStdlib 5.1, *)
4141
func backDeployedNames() async {
4242
Task(name: "name") { }
43-
Task(name: "name") { throw Boom() }
43+
_ = Task(name: "name") { throw Boom() }
4444

4545
Task.detached(name: "name") { }
46-
Task.detached(name: "name") { throw Boom() }
46+
_ = Task.detached(name: "name") { throw Boom() }
4747

4848
await withTaskGroup(of: Void.self) { group in
4949
group.addTask(name: "name") {

0 commit comments

Comments
 (0)