Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 26 additions & 13 deletions stdlib/public/Concurrency/Task+init.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import Swift
% [ # PARAMS
% 'name: String? = nil',
% 'priority: TaskPriority? = nil',
% '@_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async throws -> Success',
% '@_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async throws(Failure) -> Success',
% ]),
% # ==== --------------------------------------------------------------------
% ([ # METHOD_VARIANT
Expand All @@ -40,7 +40,7 @@ import Swift
% [ # PARAMS
% 'name: String? = nil',
% 'priority: TaskPriority? = nil',
% 'operation: sending @escaping @isolated(any) () async throws -> Success',
% 'operation: sending @escaping @isolated(any) () async throws(Failure) -> Success',
% ]),
% # ==== -------------------------------------------------------------------------------------------------------------
% # ==== With task executor, but available only since 6.0
Expand All @@ -56,7 +56,7 @@ import Swift
% 'name: String? = nil',
% 'executorPreference taskExecutor: (any TaskExecutor)?',
% 'priority: TaskPriority? = nil',
% 'operation: sending @escaping () async throws -> Success',
% 'operation: sending @escaping () async throws(Failure) -> Success',
% ]),
% # ==== --------------------------------------------------------------------
% ([ # METHOD_VARIANT
Expand All @@ -71,7 +71,7 @@ import Swift
% 'name: String? = nil',
% 'executorPreference taskExecutor: (any TaskExecutor)?',
% 'priority: TaskPriority? = nil',
% 'operation: sending @escaping () async throws -> Success',
% 'operation: sending @escaping () async throws(Failure) -> Success',
% ]),
% # !!!! -------------------------------------------------------------------------------------------------------------
% # !!!! Legacy / Source Compatibility "Shims"
Expand All @@ -91,6 +91,7 @@ import Swift
% ],
% [ # PARAMS
% 'priority: TaskPriority? = nil',
% # detach does not support typed throws, it's a legacy api for compat only
% '@_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping @isolated(any) () async throws -> Success',
% ]),
% # ==== Legacy API: runDetached
Expand All @@ -105,6 +106,7 @@ import Swift
% ],
% [ # PARAMS
% 'priority: TaskPriority? = nil',
% # runDetached does not support typed throws, it's a legacy api for compat only
% '@_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping @isolated(any) () async throws -> Success',
% ]),
% # ==== Legacy API: asyncDetached
Expand All @@ -119,6 +121,7 @@ import Swift
% ],
% [ # PARAMS
% 'priority: TaskPriority? = nil',
% # asyncDetached does not support typed throws, it's a legacy api for compat only
% '@_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping @isolated(any) () async throws -> Success',
% ]),
% # ==== Legacy API: async
Expand All @@ -133,6 +136,7 @@ import Swift
% ],
% [ # PARAMS
% 'priority: TaskPriority? = nil',
% # async does not support typed throws, it's a legacy api for compat only
% '@_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping @isolated(any) () async throws -> Success',
% ]),
% ]:
Expand All @@ -149,8 +153,10 @@ import Swift
% HAS_ISOLATED_ANY = any('@isolated(any)' in param for param in PARAMS)
% IS_DEPRECATED = any('deprecated' in a for a in ALL_AVAILABILITY)
%
% if IS_THROWING:
% FAILURE_TYPE = 'Error'
% if IS_THROWING and IS_TOP_LEVEL_FUNC:
% FAILURE_TYPE = 'Error' # the legacy top-level funcs don't have a generic Failure, so we keep the un-typed throw
% elif IS_THROWING:
% FAILURE_TYPE = 'Failure' # use typed throws, the thrown type is Failure of the Task<_, Failure> type
% else:
% FAILURE_TYPE = 'Never'
% end
Expand All @@ -162,6 +168,7 @@ def adjust_params_for_kind(params):
for p in params:
np = p
if not IS_THROWING:
np = np.replace("throws(Failure)", "")
np = np.replace("throws", "")
res.append(np)
return res
Expand All @@ -184,8 +191,12 @@ else:

% # ====================================================================================================================
% if not IS_TOP_LEVEL_FUNC:
% if IS_THROWING:
extension Task { // throwing Failure error type
% else:
extension Task where Failure == ${FAILURE_TYPE} {
% end
% end

% # --------------------------------------------------------------------------------------------------------------------
#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
Expand Down Expand Up @@ -285,8 +296,10 @@ extension Task where Failure == ${FAILURE_TYPE} {
/// - Returns: A reference to the task.
% end # IS_DEPRECATED
${"\n ".join(adjust_availability(ALL_AVAILABILITY))}
% if not IS_THROWING:
@discardableResult
public ${METHOD_VARIANT}( // Task ${METHOD_VARIANT}
% end
public ${METHOD_VARIANT}(
${",\n ".join(adjust_params_for_kind(PARAMS))}
) ${ARROW_RETURN_TYPE}{

Expand Down Expand Up @@ -323,7 +336,7 @@ extension Task where Failure == ${FAILURE_TYPE} {
initialTaskExecutorConsuming: taskExecutor,
% end
taskName: nameBytes.baseAddress!._rawValue,
operation: operation).0
operation: operation).0 // Task ${METHOD_VARIANT}
}
#else // no $BuiltinCreateAsyncTaskOwnedTaskExecutor
// legacy branch for the non-consuming task executor
Expand All @@ -338,7 +351,7 @@ extension Task where Failure == ${FAILURE_TYPE} {
% end
initialTaskExecutor: executorBuiltin,
taskName: nameBytes.baseAddress!._rawValue,
operation: operation).0
operation: operation).0 // Task ${METHOD_VARIANT}
}
#endif // $BuiltinCreateAsyncTaskOwnedTaskExecutor
% else: # if no TASK_EXECUTOR
Expand All @@ -350,7 +363,7 @@ extension Task where Failure == ${FAILURE_TYPE} {
initialSerialExecutor: builtinSerialExecutor,
% end
taskName: nameBytes.baseAddress!._rawValue,
operation: operation).0
operation: operation).0 // Task ${METHOD_VARIANT}
}
% end # if no HAS_TASK_EXECUTOR
} // let name
Expand All @@ -368,7 +381,7 @@ extension Task where Failure == ${FAILURE_TYPE} {
initialSerialExecutor: builtinSerialExecutor,
% end
initialTaskExecutorConsuming: taskExecutor,
operation: operation).0
operation: operation).0 // Task ${METHOD_VARIANT}
#else
// legacy branch for the non-consuming task executor
let executorBuiltin: Builtin.Executor =
Expand All @@ -380,7 +393,7 @@ extension Task where Failure == ${FAILURE_TYPE} {
initialSerialExecutor: builtinSerialExecutor,
% end
initialTaskExecutor: executorBuiltin,
operation: operation).0
operation: operation).0 // Task ${METHOD_VARIANT}
#endif
}
% end # HAS_TASK_EXECUTOR
Expand All @@ -392,7 +405,7 @@ extension Task where Failure == ${FAILURE_TYPE} {
% if HAS_ISOLATED_ANY:
initialSerialExecutor: builtinSerialExecutor,
% end
operation: operation).0
operation: operation).0 // Task ${METHOD_VARIANT}
}

% if IS_INIT:
Expand Down
10 changes: 7 additions & 3 deletions stdlib/public/Concurrency/Task.swift
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,12 @@ extension Task {
///
/// - Returns: The task's result.
public var value: Success {
get async throws {
return try await _taskFutureGetThrowing(_task)
get async throws(Failure) {
do {
return try await _taskFutureGetThrowing(_task)
} catch {
throw (error as! Failure) // as!-safe, because typed throw on the operation closure
}
}
}

Expand All @@ -189,7 +193,7 @@ extension Task {
do {
return .success(try await value)
} catch {
return .failure(error as! Failure) // as!-safe, guaranteed to be Failure
return .failure(error) // as!-safe, guaranteed to be Failure
Comment on lines -192 to +196
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment now refers to a force cast that has moved elsewhere.

}
}
}
Expand Down
11 changes: 10 additions & 1 deletion test/Concurrency/Runtime/task_creation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ enum SomeError: Error {
return 7
}

let t2f = Task { () throws(SomeError) -> Int in
throw SomeError.bad
}
do {
try await t2f.value
} catch {
let err: SomeError = error // confirm it was a typed throw
}

let t3 = Task.detached {
return 9
}
Expand All @@ -43,7 +52,7 @@ enum SomeError: Error {
return 11
}

let result = try! await t1.get() + t2.get() + t3.get() + t4.get()
let result = try! await t1.value + t2.value + t3.value + t4.value
assert(result == 32)
}
}
4 changes: 2 additions & 2 deletions test/Concurrency/sendable_metatype_typecheck.swift
Original file line number Diff line number Diff line change
Expand Up @@ -190,15 +190,15 @@ func f<T: P>(_: T.Type) {
}

func sendableSequence<S: AsyncSequence & Sendable>(_ s: S) throws {
Task.detached {
_ = Task.detached {
for try await i in s {
print(i)
}
}
}

func nonSendableSequence<S: AsyncSequence>(_ s: S) throws {
Task.detached {
_ = Task.detached {
for try await i in s { // expected-warning{{capture of non-Sendable type 'S.AsyncIterator.Type' in an isolated closure}}
// expected-warning@-1{{capture of non-Sendable type 'S.Type' in an isolated closure}}
print(i)
Expand Down
8 changes: 4 additions & 4 deletions test/Concurrency/task_naming_availability.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ func testName() {
@available(SwiftStdlib 6.0, *)
func taskExecutor() async {
Task(name: "name", executorPreference: nil) { }
Task(name: "name", executorPreference: nil) { throw Boom() }
_ = Task(name: "name", executorPreference: nil) { throw Boom() }

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

await withTaskGroup(of: Void.self) { group in
group.addTask(name: "name", executorPreference: nil) {
Expand Down Expand Up @@ -40,10 +40,10 @@ func taskExecutor() async {
@available(SwiftStdlib 5.1, *)
func backDeployedNames() async {
Task(name: "name") { }
Task(name: "name") { throw Boom() }
_ = Task(name: "name") { throw Boom() }

Task.detached(name: "name") { }
Task.detached(name: "name") { throw Boom() }
_ = Task.detached(name: "name") { throw Boom() }

await withTaskGroup(of: Void.self) { group in
group.addTask(name: "name") {
Expand Down