mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[Concurrency] Add missing Task.immediateDetached, which drops task locals
This commit is contained in:
@@ -13,15 +13,15 @@
|
||||
import Swift
|
||||
@_implementationOnly import SwiftConcurrencyInternalShims
|
||||
|
||||
// ==== Task.immediate ---------------------------------------------------------
|
||||
// ==== Task.startSynchronously ------------------------------------------------
|
||||
|
||||
% METHOD_VARIANTS = [
|
||||
% 'THROWING',
|
||||
% 'NON_THROWING',
|
||||
% ]
|
||||
% for METHOD_VARIANT in METHOD_VARIANTS:
|
||||
% for THROWING_VARIANT in METHOD_VARIANTS:
|
||||
|
||||
% IS_THROWING = METHOD_VARIANT == 'THROWING'
|
||||
% IS_THROWING = THROWING_VARIANT == 'THROWING'
|
||||
% if IS_THROWING:
|
||||
% FAILURE_TYPE = 'Error'
|
||||
% THROWS = 'throws '
|
||||
@@ -51,8 +51,38 @@ extension Task where Failure == ${FAILURE_TYPE} {
|
||||
) -> Task<Success, ${FAILURE_TYPE}> {
|
||||
immediate(name: name, priority: priority, operation: operation)
|
||||
}
|
||||
}
|
||||
|
||||
% end
|
||||
|
||||
// ==== Task.immediate(Detached) ---------------------------------------------------------
|
||||
|
||||
% METHOD_VARIANTS = [
|
||||
% ('immediate', 'THROWING'),
|
||||
% ('immediate', 'NON_THROWING'),
|
||||
% ('immediateDetached', 'THROWING'),
|
||||
% ('immediateDetached', 'NON_THROWING'),
|
||||
% ]
|
||||
% for (METHOD_NAME, THROWING_VARIANT) in METHOD_VARIANTS:
|
||||
|
||||
% IS_THROWING = THROWING_VARIANT == 'THROWING'
|
||||
% IS_DETACHED = 'Detached' in METHOD_NAME
|
||||
% if IS_THROWING:
|
||||
% FAILURE_TYPE = 'Error'
|
||||
% THROWS = 'throws '
|
||||
% else:
|
||||
% FAILURE_TYPE = 'Never'
|
||||
% THROWS = ''
|
||||
% end
|
||||
|
||||
@available(SwiftStdlib 6.2, *)
|
||||
extension Task where Failure == ${FAILURE_TYPE} {
|
||||
|
||||
% if IS_DETACHED:
|
||||
/// Create and immediately start running a new task in the context of the calling thread/task.
|
||||
% else:
|
||||
/// Create and immediately start running a new detached task in the context of the calling thread/task.
|
||||
% end # IS_DETACHED
|
||||
///
|
||||
/// This function _starts_ the created task on the calling context.
|
||||
/// The task will continue executing on the caller's context until it suspends,
|
||||
@@ -65,8 +95,12 @@ extension Task where Failure == ${FAILURE_TYPE} {
|
||||
/// a synchronous manner.
|
||||
///
|
||||
/// Other than the execution semantics discussed above, the created task
|
||||
/// is semantically equivalent to its basic version which can be
|
||||
/// created using ``Task/init``.
|
||||
/// is semantically equivalent to a task created using
|
||||
% if IS_DETACHED:
|
||||
/// the ``Task/detached`` function.
|
||||
% else:
|
||||
/// the ``Task/init`` initializer.
|
||||
% end
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - name: The high-level human-readable name given for this task
|
||||
@@ -81,7 +115,7 @@ extension Task where Failure == ${FAILURE_TYPE} {
|
||||
@available(SwiftStdlib 6.2, *)
|
||||
@_alwaysEmitIntoClient
|
||||
@discardableResult
|
||||
public static func immediate(
|
||||
public static func ${METHOD_NAME}(
|
||||
name: String? = nil,
|
||||
priority: TaskPriority? = nil,
|
||||
executorPreference taskExecutor: consuming (any TaskExecutor)? = nil,
|
||||
@@ -98,14 +132,14 @@ extension Task where Failure == ${FAILURE_TYPE} {
|
||||
if let builtinSerialExecutor {
|
||||
_taskIsCurrentExecutor(executor: builtinSerialExecutor, flags: flagsMustNotCrash)
|
||||
} else {
|
||||
true // if there is not target executor, we can run synchronously
|
||||
true // if there is no target executor, we can run synchronously
|
||||
}
|
||||
|
||||
let flags = taskCreateFlags(
|
||||
priority: priority,
|
||||
isChildTask: false,
|
||||
copyTaskLocals: true,
|
||||
inheritContext: true,
|
||||
copyTaskLocals: ${'true' if not IS_DETACHED else 'false /* detached */'},
|
||||
inheritContext: ${'true' if not IS_DETACHED else 'false /* detached */'},
|
||||
enqueueJob: !canRunSynchronously,
|
||||
addPendingGroupTaskUnconditionally: false,
|
||||
isDiscardingTask: false,
|
||||
@@ -369,9 +403,9 @@ extension ${GROUP_TYPE} {
|
||||
% 'THROWING',
|
||||
% 'NON_THROWING',
|
||||
% ]
|
||||
% for METHOD_VARIANT in METHOD_VARIANTS:
|
||||
% for THROWING_VARIANT in METHOD_VARIANTS:
|
||||
|
||||
% IS_THROWING = METHOD_VARIANT == 'THROWING'
|
||||
% IS_THROWING = THROWING_VARIANT == 'THROWING'
|
||||
% if IS_THROWING:
|
||||
% FAILURE_TYPE = 'Error'
|
||||
% THROWS = 'throws '
|
||||
|
||||
@@ -212,7 +212,7 @@ extension Task where Failure == ${FAILURE_TYPE} {
|
||||
priority: priority,
|
||||
isChildTask: false,
|
||||
copyTaskLocals: ${'true' if not IS_DETACHED else 'false /* detached */'},
|
||||
inheritContext: true,
|
||||
inheritContext: ${'true' if not IS_DETACHED else 'false /* detached */'},
|
||||
enqueueJob: true,
|
||||
addPendingGroupTaskUnconditionally: false,
|
||||
isDiscardingTask: false,
|
||||
@@ -294,8 +294,8 @@ extension Task where Failure == ${FAILURE_TYPE} {
|
||||
let flags = taskCreateFlags(
|
||||
priority: priority,
|
||||
isChildTask: false,
|
||||
copyTaskLocals: ${'true' if not IS_DETACHED else 'false'},
|
||||
inheritContext: ${'true' if not IS_DETACHED else 'false'},
|
||||
copyTaskLocals: ${'true' if not IS_DETACHED else 'false /* detached */'},
|
||||
inheritContext: ${'true' if not IS_DETACHED else 'false /* detached */'},
|
||||
enqueueJob: true,
|
||||
addPendingGroupTaskUnconditionally: false,
|
||||
isDiscardingTask: false,
|
||||
|
||||
@@ -459,6 +459,9 @@ await call_startSynchronously_insideActor()
|
||||
print("\n\n==== ------------------------------------------------------------------")
|
||||
print("call_taskImmediate_taskExecutor()")
|
||||
|
||||
@TaskLocal
|
||||
nonisolated(unsafe) var niceTaskLocalValueYouGotThere: String = ""
|
||||
|
||||
func call_taskImmediate_taskExecutor(taskExecutor: NaiveQueueExecutor) async {
|
||||
await Task.immediate(executorPreference: taskExecutor) {
|
||||
print("Task.immediate(executorPreference:)")
|
||||
@@ -474,6 +477,20 @@ func call_taskImmediate_taskExecutor(taskExecutor: NaiveQueueExecutor) async {
|
||||
dispatchPrecondition(condition: .notOnQueue(taskExecutor.queue)) // since @MainActor requirement > preference
|
||||
}.value
|
||||
|
||||
await $niceTaskLocalValueYouGotThere.withValue("value") {
|
||||
assert(niceTaskLocalValueYouGotThere == "value")
|
||||
|
||||
// Task.immediate copies task locals
|
||||
await Task.immediate(executorPreference: taskExecutor) {
|
||||
assert(niceTaskLocalValueYouGotThere == "value")
|
||||
}.value
|
||||
|
||||
// Task.immediateDetached does not copy task locals
|
||||
await Task.immediateDetached(executorPreference: taskExecutor) {
|
||||
assert(niceTaskLocalValueYouGotThere == "")
|
||||
}.value
|
||||
}
|
||||
|
||||
await withTaskGroup { group in
|
||||
print("withTaskGroup { group.addTask(executorPreference:) { ... } }")
|
||||
group.addImmediateTask(executorPreference: taskExecutor) {
|
||||
|
||||
@@ -14,6 +14,11 @@ func async() async throws {
|
||||
return ""
|
||||
}
|
||||
let _: String = await t1.value
|
||||
|
||||
let td1 = Task.immediateDetached {
|
||||
return ""
|
||||
}
|
||||
let _: String = await td1.value
|
||||
|
||||
let t2: Task<String, Error> = Task.immediate {
|
||||
throw CancellationError()
|
||||
|
||||
Reference in New Issue
Block a user