From 34b3d12e70468e0db0e891637616152bb6654b00 Mon Sep 17 00:00:00 2001 From: Konrad 'ktoso' Malawski Date: Tue, 22 Apr 2025 19:59:18 +0900 Subject: [PATCH 1/7] [Concurrency] Update how we add parameters to Task.init, change the AEIC funcs --- Runtimes/Core/Concurrency/CMakeLists.txt | 1 + stdlib/public/Concurrency/CMakeLists.txt | 1 + .../Concurrency/Task+TaskExecutor.swift | 14 +- stdlib/public/Concurrency/Task+init.swift.gyb | 224 ++++++++++ stdlib/public/Concurrency/Task.swift | 389 +----------------- .../pretty-printed-diagnostics.swift | 13 +- 6 files changed, 259 insertions(+), 383 deletions(-) create mode 100644 stdlib/public/Concurrency/Task+init.swift.gyb diff --git a/Runtimes/Core/Concurrency/CMakeLists.txt b/Runtimes/Core/Concurrency/CMakeLists.txt index 4af3a52b0f80e..8ae44c681ee45 100644 --- a/Runtimes/Core/Concurrency/CMakeLists.txt +++ b/Runtimes/Core/Concurrency/CMakeLists.txt @@ -1,5 +1,6 @@ add_subdirectory(InternalShims) +gyb_expand(Task+init.swift.gyb Task+init.swift) gyb_expand(TaskGroup+addTask.swift.gyb TaskGroup+addTask.swift) gyb_expand(Task+startSynchronously.swift.gyb Task+startSynchronously.swift) diff --git a/stdlib/public/Concurrency/CMakeLists.txt b/stdlib/public/Concurrency/CMakeLists.txt index 66f5bea20eb4e..a578a009b6ba6 100644 --- a/stdlib/public/Concurrency/CMakeLists.txt +++ b/stdlib/public/Concurrency/CMakeLists.txt @@ -212,6 +212,7 @@ add_swift_target_library(swift_Concurrency ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} I ${SWIFT_RUNTIME_CONCURRENCY_NONEMBEDDED_SWIFT_SOURCES} GYB_SOURCES + Task+init.swift.gyb TaskGroup+addTask.swift.gyb Task+startSynchronously.swift.gyb diff --git a/stdlib/public/Concurrency/Task+TaskExecutor.swift b/stdlib/public/Concurrency/Task+TaskExecutor.swift index 611fe9265630f..11eae75ef1824 100644 --- a/stdlib/public/Concurrency/Task+TaskExecutor.swift +++ b/stdlib/public/Concurrency/Task+TaskExecutor.swift @@ -237,10 +237,14 @@ extension Task where Failure == Never { } // Set up the job flags for a new task. let flags = taskCreateFlags( - priority: priority, isChildTask: false, copyTaskLocals: true, - inheritContext: true, enqueueJob: true, + priority: priority, + isChildTask: false, + copyTaskLocals: true, + inheritContext: true, + enqueueJob: true, addPendingGroupTaskUnconditionally: false, - isDiscardingTask: false, isSynchronousStart: false) + isDiscardingTask: false, + isSynchronousStart: false) #if $BuiltinCreateAsyncTaskOwnedTaskExecutor let (task, _) = Builtin.createTask( @@ -328,7 +332,7 @@ extension Task where Failure == Never { /// Runs the given nonthrowing operation asynchronously /// as part of a new top-level task. /// - /// Don't use a detached task if it's possible + /// Don't use a detached unstructured task if it's possible /// to model the operation using structured concurrency features like child tasks. /// Child tasks inherit the parent task's priority and task-local storage, /// and canceling a parent task automatically cancels all of its child tasks. @@ -389,7 +393,7 @@ extension Task where Failure == Error { /// /// If the operation throws an error, this method propagates that error. /// - /// Don't use a detached task if it's possible + /// Don't use a detached unstructured task if it's possible /// to model the operation using structured concurrency features like child tasks. /// Child tasks inherit the parent task's priority and task-local storage, /// and canceling a parent task automatically cancels all of its child tasks. diff --git a/stdlib/public/Concurrency/Task+init.swift.gyb b/stdlib/public/Concurrency/Task+init.swift.gyb new file mode 100644 index 0000000000000..8da330f2b9d60 --- /dev/null +++ b/stdlib/public/Concurrency/Task+init.swift.gyb @@ -0,0 +1,224 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +import Swift + +// ==== Task.init ------------------------------------------------ + +% for (METHOD_VARIANTS, ALL_AVAILABILITY, PARAMS) in [ +% ( +% [ # METHOD_VARIANT +% '', +% 'THROWING', +% ], +% [ # ALL_AVAILABILITY +% '@_alwaysEmitIntoClient', +% '@available(SwiftStdlib 5.1, *)', +% ], +% [ # PARAMS +% 'name: String?', +% 'priority: TaskPriority? = nil', +% '@_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async throws -> Success', +% ]), +% # ==== +% ( +% [ # METHOD_VARIANT +% 'DETACHED', +% 'DETACHED THROWING', +% ], +% [ +% '@_alwaysEmitIntoClient', +% '@available(SwiftStdlib 5.1, *)', +% ], +% [ # PARAMS +% 'name: String?', +% 'priority: TaskPriority? = nil', +% 'operation: sending @escaping @isolated(any) () async throws -> Success', +% ]), +% ]: +% for METHOD_VARIANT in METHOD_VARIANTS: + +% IS_DETACHED = 'DETACHED' in METHOD_VARIANT +% IS_THROWING = 'THROWING' in METHOD_VARIANT +% if IS_THROWING: +% FAILURE_TYPE = 'Error' +% else: +% FAILURE_TYPE = 'Never' +% end + +% +% def adjust_params_for_kind(params): +% res = [] +% for p in params: +% np = p +% if not IS_THROWING: +% np = np.replace("throws", "") +% res.append(np) +% return res +% +% +% HAS_TASK_PRIORITY = any('priority:' in param for param in PARAMS) +% HAS_TASK_NAME = any('name:' in param for param in PARAMS) +% HAS_TASK_EXECUTOR = any('taskExecutor:' in param for param in PARAMS) + +% if IS_DETACHED: +% ARROW_RETURN_TYPE = f'-> Task' +% else: +% ARROW_RETURN_TYPE = '' # init does not spell out return type +% end + +% if IS_DETACHED: +% THE_FUNC = 'public static func detached' +% else: +% THE_FUNC = 'public init' +% end + +% # ==================================================================================================================== +@available(SwiftStdlib 5.1, *) +extension Task where Failure == ${FAILURE_TYPE} { + +% # -------------------------------------------------------------------------------------------------------------------- +#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY + @discardableResult + @_alwaysEmitIntoClient + @available(*, unavailable, message: "Unavailable in task-to-thread concurrency model") + ${THE_FUNC}( + ${",\n ".join(adjust_params_for_kind(PARAMS))} + ) ${ARROW_RETURN_TYPE}{ + fatalError("Unavailable in task-to-thread concurrency model.") + } + +% # -------------------------------------------------------------------------------------------------------------------- +#elseif $Embedded + @discardableResult + @_alwaysEmitIntoClient + @available(SwiftStdlib 5.1, *) + ${THE_FUNC}( + ${",\n ".join(adjust_params_for_kind(PARAMS))} + ) ${ARROW_RETURN_TYPE}{ + // Set up the job flags for a new task. + let flags = taskCreateFlags( + priority: priority, + isChildTask: false, + copyTaskLocals: ${'true' if not IS_DETACHED else 'false /* detached */'}, + inheritContext: true, + enqueueJob: true, + addPendingGroupTaskUnconditionally: false, + isDiscardingTask: false, + isSynchronousStart: false) + + // Create the asynchronous task. + let (task, _) = Builtin.createAsyncTask(flags, operation) + + self._task = task + } + +% # -------------------------------------------------------------------------------------------------------------------- +#else +% if IS_THROWING: + /// Runs the given throwing operation asynchronously +% else: + /// Runs the given nonthrowing operation asynchronously +% end +% if IS_DETACHED: + /// as part of a new _unstructured_ _detached_ top-level task. +% else: + /// as part of a new _unstructured_ top-level task. +% end + /// +% if IS_THROWING: + /// If the `operation` throws an error, it is caught by the `Task` and will be + /// rethrown only when the task's `value` is awaited. Take care to not accidentally + /// dismiss errors by not awaiting on the task's resulting value. +% end + /// +% if IS_DETACHED: + /// Don't use a detached unstructured task if it's possible + /// to model the operation using structured concurrency features like child tasks. + /// Child tasks inherit the parent task's priority and task-local storage, + /// and canceling a parent task automatically cancels all of its child tasks. + /// You need to handle these considerations manually with a detached task. +% end + /// + /// You need to keep a reference to the task + /// if you want to cancel it by calling the `Task.cancel()` method. + /// Discarding your reference to a task + /// doesn't implicitly cancel that task, + /// it only makes it impossible for you to explicitly cancel the task. + /// + /// - Parameters: + % if HAS_TASK_NAME: + /// - name: Human readable name of the task. + % end + % if HAS_TASK_NAME: + /// - taskExecutor: the preferred task executor for this task, + /// and any child tasks created by it. Explicitly passing `nil` is + /// interpreted as "no preference". + % end + /// - priority: The priority of the task. + /// - operation: The operation to perform. + /// + /// - Returns: A reference to the task. + ${"\n ".join(ALL_AVAILABILITY)} + @discardableResult + ${THE_FUNC}( + ${",\n ".join(adjust_params_for_kind(PARAMS))} + ) ${ARROW_RETURN_TYPE}{ + + // Set up the job flags for a new task. + let flags = taskCreateFlags( + priority: priority, + isChildTask: false, + copyTaskLocals: ${'true' if not IS_DETACHED else 'false'}, + inheritContext: false, + enqueueJob: true, + addPendingGroupTaskUnconditionally: false, + isDiscardingTask: false, + isSynchronousStart: false) + + // Create the asynchronous task. + let builtinSerialExecutor = + unsafe Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor + + var task: Builtin.NativeObject? + #if $BuiltinCreateAsyncTaskName + if let name { + task = + unsafe name.utf8CString.withUnsafeBufferPointer { nameBytes in + Builtin.createTask( + flags: flags, + initialSerialExecutor: builtinSerialExecutor, + taskName: nameBytes.baseAddress!._rawValue, + operation: operation).0 + } + } + #endif + if task == nil { + // either no task name was set, or names are unsupported + task = Builtin.createTask( + flags: flags, + initialSerialExecutor: builtinSerialExecutor, + operation: operation).0 + } + +% if IS_DETACHED: + return Task(task!) +% else: + self._task = task! +% end + } + +#endif +} // extension Task ... + +% end +% end diff --git a/stdlib/public/Concurrency/Task.swift b/stdlib/public/Concurrency/Task.swift index 8c398ff5a666d..3e9d8797baf97 100644 --- a/stdlib/public/Concurrency/Task.swift +++ b/stdlib/public/Concurrency/Task.swift @@ -644,115 +644,6 @@ extension Task where Failure == Never { #endif } -@available(SwiftStdlib 6.2, *) -extension Task where Failure == Never { -#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY - @discardableResult - @_alwaysEmitIntoClient - @available(*, unavailable, message: "Unavailable in task-to-thread concurrency model") - public init( - name: String?, - priority: TaskPriority? = nil, - @_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async -> Success - ) { - fatalError("Unavailable in task-to-thread concurrency model.") - } -#elseif $Embedded - @discardableResult - @_alwaysEmitIntoClient - @available(SwiftStdlib 6.2, *) - public init( - name: String?, - // TaskExecutor is unavailable in embedded - priority: TaskPriority? = nil, - @_inheritActorContext @_implicitSelfCapture operation: sending @escaping () async -> Success - ) { - // Set up the job flags for a new task. - let flags = taskCreateFlags( - priority: priority, - isChildTask: false, - copyTaskLocals: true, - inheritContext: true, - enqueueJob: true, - addPendingGroupTaskUnconditionally: false, - isDiscardingTask: false, - isSynchronousStart: false) - - // Create the asynchronous task. - let (task, _) = Builtin.createAsyncTask(flags, operation) - - self._task = task - } -#else - /// Runs the given nonthrowing operation asynchronously - /// as part of a new top-level task on behalf of the current actor. - /// - /// Use this function when creating asynchronous work - /// that operates on behalf of the synchronous function that calls it. - /// Like `Task.detached(priority:operation:)`, - /// this function creates a separate, top-level task. - /// Unlike `Task.detached(priority:operation:)`, - /// the task created by `Task.init(priority:operation:)` - /// inherits the priority and actor context of the caller, - /// so the operation is treated more like an asynchronous extension - /// to the synchronous operation. - /// - /// You need to keep a reference to the task - /// if you want to cancel it by calling the `Task.cancel()` method. - /// Discarding your reference to a detached task - /// doesn't implicitly cancel that task, - /// it only makes it impossible for you to explicitly cancel the task. - /// - /// - Parameters: - /// - name: The high-level human-readable name given for this task - /// - priority: The priority of the task. - /// Pass `nil` to use the priority from `Task.currentPriority`. - /// - operation: The operation to perform. - @discardableResult - @_alwaysEmitIntoClient - @available(SwiftStdlib 6.2, *) - public init( - name: String?, - priority: TaskPriority? = nil, - @_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async -> Success - ) { - // Set up the job flags for a new task. - let flags = taskCreateFlags( - priority: priority, isChildTask: false, copyTaskLocals: true, - inheritContext: true, enqueueJob: true, - addPendingGroupTaskUnconditionally: false, - isDiscardingTask: false, isSynchronousStart: false) - - // Create the asynchronous task. - let builtinSerialExecutor = - unsafe Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor - - var task: Builtin.NativeObject? - #if $BuiltinCreateAsyncTaskName - if let name { - task = - unsafe name.utf8CString.withUnsafeBufferPointer { nameBytes in - Builtin.createTask( - flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskName: nameBytes.baseAddress!._rawValue, - operation: operation).0 - } - } - #endif - if task == nil { - // either no task name was set, or names are unsupported - task = Builtin.createTask( - flags: flags, - initialSerialExecutor: builtinSerialExecutor, - operation: operation).0 - } - - self._task = task! - } -#endif -} - @available(SwiftStdlib 5.1, *) extension Task where Failure == Error { #if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY @@ -815,112 +706,6 @@ extension Task where Failure == Error { #endif } - -@available(SwiftStdlib 6.2, *) -extension Task where Failure == Error { - #if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY - @discardableResult - @_alwaysEmitIntoClient - @available(*, unavailable, message: "Unavailable in task-to-thread concurrency model") - public init( - name: String?, - priority: TaskPriority? = nil, - @_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async throws -> Success -) { - fatalError("Unavailable in task-to-thread concurrency model.") -} - #elseif $Embedded - @discardableResult - @_alwaysEmitIntoClient - @available(SwiftStdlib 6.2, *) - public init( - name: String?, - // TaskExecutor is unavailable in embedded - priority: TaskPriority? = nil, - @_inheritActorContext @_implicitSelfCapture operation: sending @escaping () async throws -> Success -) { - // Set up the job flags for a new task. - let flags = taskCreateFlags( - priority: priority, isChildTask: false, copyTaskLocals: true, - inheritContext: true, enqueueJob: true, - addPendingGroupTaskUnconditionally: false, - isDiscardingTask: false, isSynchronousStart: false) - - // Create the asynchronous task. - let (task, _) = Builtin.createAsyncTask(flags, operation) - -self._task = task -} - #else - /// Runs the given nonthrowing operation asynchronously - /// as part of a new top-level task on behalf of the current actor. - /// - /// Use this function when creating asynchronous work - /// that operates on behalf of the synchronous function that calls it. - /// Like `Task.detached(priority:operation:)`, - /// this function creates a separate, top-level task. - /// Unlike `Task.detached(priority:operation:)`, - /// the task created by `Task.init(priority:operation:)` - /// inherits the priority and actor context of the caller, - /// so the operation is treated more like an asynchronous extension - /// to the synchronous operation. - /// - /// You need to keep a reference to the task - /// if you want to cancel it by calling the `Task.cancel()` method. - /// Discarding your reference to a detached task - /// doesn't implicitly cancel that task, - /// it only makes it impossible for you to explicitly cancel the task. - /// - /// - Parameters: - /// - name: The high-level human-readable name given for this task - /// - priority: The priority of the task. - /// Pass `nil` to use the priority from `Task.currentPriority`. - /// - operation: The operation to perform. - @discardableResult - @_alwaysEmitIntoClient - @available(SwiftStdlib 6.2, *) - public init( - name: String?, - priority: TaskPriority? = nil, - @_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async throws -> Success -) { - // Set up the job flags for a new task. - let flags = taskCreateFlags( - priority: priority, isChildTask: false, copyTaskLocals: true, - inheritContext: true, enqueueJob: true, - addPendingGroupTaskUnconditionally: false, - isDiscardingTask: false, isSynchronousStart: false) - - // Create the asynchronous task. - let builtinSerialExecutor = - unsafe Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor - - var task: Builtin.NativeObject? - #if $BuiltinCreateAsyncTaskName - if let name { - task = - unsafe name.utf8CString.withUnsafeBufferPointer { nameBytes in - Builtin.createTask( - flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskName: nameBytes.baseAddress!._rawValue, - operation: operation).0 - } - } - #endif - if task == nil { - // either no task name was set, or names are unsupported - task = Builtin.createTask( - flags: flags, - initialSerialExecutor: builtinSerialExecutor, - operation: operation).0 - } - - self._task = task! - } - #endif -} - // ==== Detached Tasks --------------------------------------------------------- @available(SwiftStdlib 5.1, *) @@ -939,7 +724,7 @@ extension Task where Failure == Never { /// Runs the given nonthrowing operation asynchronously /// as part of a new top-level task. /// - /// Don't use a detached task if it's possible + /// Don't use a detached unstructured task if it's possible /// to model the operation using structured concurrency features like child tasks. /// Child tasks inherit the parent task's priority and task-local storage, /// and canceling a parent task automatically cancels all of its child tasks. @@ -983,85 +768,6 @@ extension Task where Failure == Never { #endif } -@available(SwiftStdlib 6.2, *) -extension Task where Failure == Never { -#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY - @discardableResult - @_alwaysEmitIntoClient - @available(*, unavailable, message: "Unavailable in task-to-thread concurrency model") - public static func detached( - name: String?, - priority: TaskPriority? = nil, - operation: sending @escaping @isolated(any) () async -> Success - ) -> Task { - fatalError("Unavailable in task-to-thread concurrency model") - } -#else - /// Runs the given nonthrowing operation asynchronously - /// as part of a new top-level task. - /// - /// Don't use a detached task if it's possible - /// to model the operation using structured concurrency features like child tasks. - /// Child tasks inherit the parent task's priority and task-local storage, - /// and canceling a parent task automatically cancels all of its child tasks. - /// You need to handle these considerations manually with a detached task. - /// - /// You need to keep a reference to the detached task - /// if you want to cancel it by calling the `Task.cancel()` method. - /// Discarding your reference to a detached task - /// doesn't implicitly cancel that task, - /// it only makes it impossible for you to explicitly cancel the task. - /// - /// - Parameters: - /// - name: Human readable name of the task. - /// - priority: The priority of the task. - /// - operation: The operation to perform. - /// - /// - Returns: A reference to the task. - @discardableResult - @_alwaysEmitIntoClient - public static func detached( - name: String?, - priority: TaskPriority? = nil, - operation: sending @escaping @isolated(any) () async -> Success - ) -> Task { - // Set up the job flags for a new task. - let flags = taskCreateFlags( - priority: priority, isChildTask: false, copyTaskLocals: false, - inheritContext: false, enqueueJob: true, - addPendingGroupTaskUnconditionally: false, - isDiscardingTask: false, isSynchronousStart: false) - - // Create the asynchronous task. - let builtinSerialExecutor = - unsafe Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor - - var task: Builtin.NativeObject? - #if $BuiltinCreateAsyncTaskName - if let name { - task = - unsafe name.utf8CString.withUnsafeBufferPointer { nameBytes in - Builtin.createTask( - flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskName: nameBytes.baseAddress!._rawValue, - operation: operation).0 - } - } - #endif - if task == nil { - // either no task name was set, or names are unsupported - task = Builtin.createTask( - flags: flags, - initialSerialExecutor: builtinSerialExecutor, - operation: operation).0 - } - - return Task(task!) - } -#endif -} - @available(SwiftStdlib 5.1, *) extension Task where Failure == Error { #if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY @@ -1078,9 +784,11 @@ extension Task where Failure == Error { /// Runs the given throwing operation asynchronously /// as part of a new top-level task. /// - /// If the operation throws an error, this method propagates that error. + /// If the `operation` throws an error, it is caught by the `Task` and will be + /// rethrown only when the task's `value` is awaited. Take care to not accidentally + /// dismiss errors by not awaiting on the task's resulting value. /// - /// Don't use a detached task if it's possible + /// Don't use a detached unstructured task if it's possible /// to model the operation using structured concurrency features like child tasks. /// Child tasks inherit the parent task's priority and task-local storage, /// and canceling a parent task automatically cancels all of its child tasks. @@ -1124,86 +832,6 @@ extension Task where Failure == Error { #endif } -@available(SwiftStdlib 6.2, *) -extension Task where Failure == Error { -#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY - @discardableResult - @_alwaysEmitIntoClient - @available(*, unavailable, message: "Unavailable in task-to-thread concurrency model") - public static func detached( - name: String?, - priority: TaskPriority? = nil, - operation: sending @escaping @isolated(any) () async throws -> Success - ) -> Task { - fatalError("Unavailable in task-to-thread concurrency model") - } -#else - /// Runs the given throwing operation asynchronously - /// as part of a new top-level task. - /// - /// If the operation throws an error, this method propagates that error. - /// - /// Don't use a detached task if it's possible - /// to model the operation using structured concurrency features like child tasks. - /// Child tasks inherit the parent task's priority and task-local storage, - /// and canceling a parent task automatically cancels all of its child tasks. - /// You need to handle these considerations manually with a detached task. - /// - /// You need to keep a reference to the detached task - /// if you want to cancel it by calling the `Task.cancel()` method. - /// Discarding your reference to a detached task - /// doesn't implicitly cancel that task, - /// it only makes it impossible for you to explicitly cancel the task. - /// - /// - Parameters: - /// - priority: The priority of the task. - /// - operation: The operation to perform. - /// - /// - Returns: A reference to the task. - @discardableResult - @_alwaysEmitIntoClient - public static func detached( - name: String?, - priority: TaskPriority? = nil, - operation: sending @escaping @isolated(any) () async throws -> Success - ) -> Task { - // Set up the job flags for a new task. - let flags = taskCreateFlags( - priority: priority, isChildTask: false, copyTaskLocals: false, - inheritContext: false, enqueueJob: true, - addPendingGroupTaskUnconditionally: false, - isDiscardingTask: false, isSynchronousStart: false) - - // Create the asynchronous task future. - let builtinSerialExecutor = - unsafe Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor - - var task: Builtin.NativeObject? - #if $BuiltinCreateAsyncTaskName - if let name { - task = - unsafe name.utf8CString.withUnsafeBufferPointer { nameBytes in - Builtin.createTask( - flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskName: nameBytes.baseAddress!._rawValue, - operation: operation).0 - } - } - #endif - if task == nil { - // either no task name was set, or names are unsupported - task = Builtin.createTask( - flags: flags, - initialSerialExecutor: builtinSerialExecutor, - operation: operation).0 - } - - return Task(task!) - } -#endif -} - // ==== Task Name -------------------------------------------------------------- @available(SwiftStdlib 6.2, *) @@ -1224,6 +852,13 @@ extension Task where Success == Never, Failure == Never { /// } /// } /// } + /// + /// ### Task name availability + /// The task name is only available when running with a recent runtime (Swift 6.2+). + /// + /// ``Task`` initializers which may accept a task name are more available than this property, + /// for convenience purposes, in order to not have to set task names conditionally + /// however their effect is runtime dependent, and is reflected in the availability of this property. @available(SwiftStdlib 6.2, *) public static var name: String? { return _getCurrentTaskNameString() diff --git a/test/diagnostics/pretty-printed-diagnostics.swift b/test/diagnostics/pretty-printed-diagnostics.swift index 222cd441329a8..6d4095f46295d 100644 --- a/test/diagnostics/pretty-printed-diagnostics.swift +++ b/test/diagnostics/pretty-printed-diagnostics.swift @@ -1,4 +1,4 @@ -// RUN: not %target-swift-frontend -diagnostic-style=swift -typecheck %/s 2>&1 | %FileCheck %s +// RUN: not %target-swift-frontend -diagnostic-style=swift -typecheck %/s 2>&1 | %FileCheck %s --dump-input=always // REQUIRES: swift_swift_parser @@ -70,6 +70,11 @@ foo(b: func test(a: Int) {} func test(a: Int) {} +struct DuplicateInits { + init(a: Int) {} + init(a: Int) {} +} + // Test fallback for non-ASCII characters. // CHECK: SOURCE_DIR{{[/\]+}}test{{[/\]+}}diagnostics{{[/\]+}}pretty-printed-diagnostics.swift:[[#LINE:]]:11 // CHECK: [[#LINE-2]] | @@ -94,3 +99,9 @@ func test(a: Int) {} // CHECK: | `- note: 'test(a:)' previously declared here // CHECK: [[#LINE]] | func test(a: Int) {} // CHECL: [[#LINE+1]] | `- error: invalid redeclaration of 'test(a:)' + +// CHECK: SOURCE_DIR{{[/\]+}}test{{[/\]+}}diagnostics{{[/\]+}}pretty-printed-diagnostics.swift:[[#LINE:]]:3 +// CHECK: [[#LINE-1]] | init(a: Int) {} +// CHECK: | `- note: 'init(a:)' previously declared here +// CHECK: [[#LINE]] | init(a: Int) {} +// CHECL: [[#LINE+1]] | `- error: invalid redeclaration of 'init(a:)' From 742f3428c0fb5f5ddd2818eed40100d2604a9d87 Mon Sep 17 00:00:00 2001 From: Konrad 'ktoso' Malawski Date: Tue, 22 Apr 2025 22:51:06 +0900 Subject: [PATCH 2/7] [Concurrency] Lower availability for task names + addTask --- stdlib/public/Concurrency/Task+init.swift.gyb | 109 ++++++++++++------ .../Concurrency/TaskGroup+addTask.swift.gyb | 44 ++++++- .../task_naming_availability.swift | 73 ++++++++++++ .../pretty-printed-diagnostics.swift | 13 +-- 4 files changed, 189 insertions(+), 50 deletions(-) create mode 100644 test/Concurrency/task_naming_availability.swift diff --git a/stdlib/public/Concurrency/Task+init.swift.gyb b/stdlib/public/Concurrency/Task+init.swift.gyb index 8da330f2b9d60..22950f1c4d630 100644 --- a/stdlib/public/Concurrency/Task+init.swift.gyb +++ b/stdlib/public/Concurrency/Task+init.swift.gyb @@ -15,8 +15,8 @@ import Swift // ==== Task.init ------------------------------------------------ % for (METHOD_VARIANTS, ALL_AVAILABILITY, PARAMS) in [ -% ( -% [ # METHOD_VARIANT +% # ==== Without task executor, but available ever since 5.1 +% ([ # METHOD_VARIANT % '', % 'THROWING', % ], @@ -29,9 +29,7 @@ import Swift % 'priority: TaskPriority? = nil', % '@_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async throws -> Success', % ]), -% # ==== -% ( -% [ # METHOD_VARIANT +% ([ # METHOD_VARIANT % 'DETACHED', % 'DETACHED THROWING', % ], @@ -44,46 +42,83 @@ import Swift % 'priority: TaskPriority? = nil', % 'operation: sending @escaping @isolated(any) () async throws -> Success', % ]), +% # ==== With task executor, but available only since 6.0 +% ([ # METHOD_VARIANT +% '', +% 'THROWING', +% ], +% [ # ALL_AVAILABILITY +% '@_alwaysEmitIntoClient', +% '@available(SwiftStdlib 6.0, *)', +% ], +% [ # PARAMS +% 'name: String?', +% 'executorPreference taskExecutor: (any TaskExecutor)? = nil', +% 'priority: TaskPriority? = nil', +% '@_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async throws -> Success', +% ]), +% ([ # METHOD_VARIANT +% 'DETACHED', +% 'DETACHED THROWING', +% ], +% [ +% '@_alwaysEmitIntoClient', +% '@available(SwiftStdlib 6.0, *)', +% ], +% [ # PARAMS +% 'name: String?', +% 'executorPreference taskExecutor: (any TaskExecutor)? = nil', +% 'priority: TaskPriority? = nil', +% 'operation: sending @escaping @isolated(any) () async throws -> Success', +% ]), % ]: % for METHOD_VARIANT in METHOD_VARIANTS: % IS_DETACHED = 'DETACHED' in METHOD_VARIANT % IS_THROWING = 'THROWING' in METHOD_VARIANT +% HAS_TASK_PRIORITY = any('priority:' in param for param in PARAMS) +% HAS_TASK_NAME = any('name:' in param for param in PARAMS) +% HAS_TASK_EXECUTOR = any('taskExecutor:' in param for param in PARAMS) +% % if IS_THROWING: % FAILURE_TYPE = 'Error' % else: % FAILURE_TYPE = 'Never' % end -% -% def adjust_params_for_kind(params): -% res = [] -% for p in params: -% np = p -% if not IS_THROWING: -% np = np.replace("throws", "") -% res.append(np) -% return res -% -% -% HAS_TASK_PRIORITY = any('priority:' in param for param in PARAMS) -% HAS_TASK_NAME = any('name:' in param for param in PARAMS) -% HAS_TASK_EXECUTOR = any('taskExecutor:' in param for param in PARAMS) +%{ -% if IS_DETACHED: -% ARROW_RETURN_TYPE = f'-> Task' -% else: -% ARROW_RETURN_TYPE = '' # init does not spell out return type -% end +def adjust_params_for_kind(params): + res = [] + for p in params: + np = p + if not IS_THROWING: + np = np.replace("throws", "") + res.append(np) + return res -% if IS_DETACHED: -% THE_FUNC = 'public static func detached' -% else: -% THE_FUNC = 'public init' -% end +def adjust_availability(avails): + res = [] + for av in avails: + adjusted = av + if HAS_TASK_EXECUTOR: + adjusted = adjusted.replace("SwiftStdlib 5.1", "SwiftStdlib 6.0") + res.append(adjusted) + return res + +if IS_DETACHED: + ARROW_RETURN_TYPE = f'-> Task' +else: + ARROW_RETURN_TYPE = '' # init does not spell out return type + +if IS_DETACHED: + THE_FUNC = 'public static func detached' +else: + THE_FUNC = 'public init' + +}% % # ==================================================================================================================== -@available(SwiftStdlib 5.1, *) extension Task where Failure == ${FAILURE_TYPE} { % # -------------------------------------------------------------------------------------------------------------------- @@ -101,7 +136,7 @@ extension Task where Failure == ${FAILURE_TYPE} { #elseif $Embedded @discardableResult @_alwaysEmitIntoClient - @available(SwiftStdlib 5.1, *) + ${" \n".join(adjust_availability(['@available(SwiftStdlib 5.1, *)']))} ${THE_FUNC}( ${",\n ".join(adjust_params_for_kind(PARAMS))} ) ${ARROW_RETURN_TYPE}{ @@ -159,16 +194,18 @@ extension Task where Failure == ${FAILURE_TYPE} { % if HAS_TASK_NAME: /// - name: Human readable name of the task. % end - % if HAS_TASK_NAME: - /// - taskExecutor: the preferred task executor for this task, - /// and any child tasks created by it. Explicitly passing `nil` is - /// interpreted as "no preference". + % if HAS_TASK_EXECUTOR: + /// - taskExecutor: + /// - taskExecutor: The task executor that the child task should be started on and keep using. + /// Explicitly passing `nil` as the executor preference is equivalent to no preference, + /// and effectively means to inherit the outer context's executor preference. + /// You can also pass the ``globalConcurrentExecutor`` global executor explicitly. % end /// - priority: The priority of the task. /// - operation: The operation to perform. /// /// - Returns: A reference to the task. - ${"\n ".join(ALL_AVAILABILITY)} + ${"\n ".join(adjust_availability(ALL_AVAILABILITY))} @discardableResult ${THE_FUNC}( ${",\n ".join(adjust_params_for_kind(PARAMS))} diff --git a/stdlib/public/Concurrency/TaskGroup+addTask.swift.gyb b/stdlib/public/Concurrency/TaskGroup+addTask.swift.gyb index 298faf73dacb8..5baad01019026 100644 --- a/stdlib/public/Concurrency/TaskGroup+addTask.swift.gyb +++ b/stdlib/public/Concurrency/TaskGroup+addTask.swift.gyb @@ -31,7 +31,7 @@ import Swift % 'ThrowingDiscardingTaskGroup' % ], % [ -% '@available(SwiftStdlib 6.2, *)', +% '@available(SwiftStdlib 6.0, *)', # because task executor % '@_unavailableInEmbedded', # since TaskExecutor is not available on embedded % ], % ['addTask', 'addTaskUnlessCancelled'], @@ -43,6 +43,42 @@ import Swift % 'operation: sending @escaping @isolated(any) () async throws -> ChildTaskResult' % ], % ), +% ( +% '', # no #if condition +% [ +% 'TaskGroup', +% 'ThrowingTaskGroup', +% ], +% [ +% '@available(SwiftStdlib 5.1, *)', +% ], +% ['addTask', 'addTaskUnlessCancelled'], +% [ +% 'name: String?', +% # without task executor +% 'priority: TaskPriority? = nil', +% # throws and ChildTaskResult will be adjusted per task group type +% 'operation: sending @escaping @isolated(any) () async throws -> ChildTaskResult' +% ], +% ), +% ( +% '', # no #if condition +% [ +% 'DiscardingTaskGroup', +% 'ThrowingDiscardingTaskGroup' +% ], +% [ +% '@available(SwiftStdlib 5.9, *)', # because Discarding task groups +% ], +% ['addTask', 'addTaskUnlessCancelled'], +% [ +% 'name: String?', +% # without task executor +% 'priority: TaskPriority? = nil', +% # throws and ChildTaskResult will be adjusted per task group type +% 'operation: sending @escaping @isolated(any) () async throws -> ChildTaskResult' +% ], +% ), % # ----------------------------------------------------------------------- % # === Added TaskExecutor % ( @@ -170,7 +206,9 @@ import Swift #if ${IFDEF} % end -% if IS_DISCARDING: +% if HAS_TASK_EXECUTOR: +@available(SwiftStdlib 6.0, *) +% elif IS_DISCARDING: @available(SwiftStdlib 5.9, *) % else: @available(SwiftStdlib 5.1, *) @@ -267,7 +305,9 @@ extension ${TYPE} { flags: flags, initialSerialExecutor: builtinSerialExecutor, taskGroup: _group, + % if HAS_TASK_EXECUTOR: initialTaskExecutorConsuming: taskExecutor, + % end taskName: nameBytes.baseAddress!._rawValue, operation: operation).0 } diff --git a/test/Concurrency/task_naming_availability.swift b/test/Concurrency/task_naming_availability.swift new file mode 100644 index 0000000000000..c7c45d67e8216 --- /dev/null +++ b/test/Concurrency/task_naming_availability.swift @@ -0,0 +1,73 @@ +// RUN: %target-swift-frontend -emit-sil -verify -o /dev/null -verify %s + +struct Boom: Error {} + +@available(SwiftStdlib 6.2, *) +func testName() { + _ = Task.name +} + +@available(SwiftStdlib 6.0, *) +func taskExecutor() async { + Task(name: "name", executorPreference: nil) { } + Task(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) { + () + } + } + await withThrowingTaskGroup(of: Void.self) { group in + group.addTask(name: "name", executorPreference: nil) { + () + } + } + + await withDiscardingTaskGroup { group in + group.addTask(name: "name", executorPreference: nil) { + () + } + } + try! await withThrowingDiscardingTaskGroup { group in + group.addTask(name: "name", executorPreference: nil) { + () + } + } +} + +@available(SwiftStdlib 5.1, *) +func backDeployedNames() async { + Task(name: "name") { } + Task(name: "name") { throw Boom() } + + Task.detached(name: "name") { } + Task.detached(name: "name") { throw Boom() } + + await withTaskGroup(of: Void.self) { group in + group.addTask(name: "name") { + () + } + } + await withThrowingTaskGroup(of: Void.self) { group in + group.addTask(name: "name") { + () + } + } +} + +@available(SwiftStdlib 5.9, *) +func backDeployedDiscarding() async { + await withDiscardingTaskGroup { group in + group.addTask(name: "name") { + () + } + } + try! await withThrowingDiscardingTaskGroup { group in + group.addTask(name: "name") { + () + } + } +} + diff --git a/test/diagnostics/pretty-printed-diagnostics.swift b/test/diagnostics/pretty-printed-diagnostics.swift index 6d4095f46295d..222cd441329a8 100644 --- a/test/diagnostics/pretty-printed-diagnostics.swift +++ b/test/diagnostics/pretty-printed-diagnostics.swift @@ -1,4 +1,4 @@ -// RUN: not %target-swift-frontend -diagnostic-style=swift -typecheck %/s 2>&1 | %FileCheck %s --dump-input=always +// RUN: not %target-swift-frontend -diagnostic-style=swift -typecheck %/s 2>&1 | %FileCheck %s // REQUIRES: swift_swift_parser @@ -70,11 +70,6 @@ foo(b: func test(a: Int) {} func test(a: Int) {} -struct DuplicateInits { - init(a: Int) {} - init(a: Int) {} -} - // Test fallback for non-ASCII characters. // CHECK: SOURCE_DIR{{[/\]+}}test{{[/\]+}}diagnostics{{[/\]+}}pretty-printed-diagnostics.swift:[[#LINE:]]:11 // CHECK: [[#LINE-2]] | @@ -99,9 +94,3 @@ struct DuplicateInits { // CHECK: | `- note: 'test(a:)' previously declared here // CHECK: [[#LINE]] | func test(a: Int) {} // CHECL: [[#LINE+1]] | `- error: invalid redeclaration of 'test(a:)' - -// CHECK: SOURCE_DIR{{[/\]+}}test{{[/\]+}}diagnostics{{[/\]+}}pretty-printed-diagnostics.swift:[[#LINE:]]:3 -// CHECK: [[#LINE-1]] | init(a: Int) {} -// CHECK: | `- note: 'init(a:)' previously declared here -// CHECK: [[#LINE]] | init(a: Int) {} -// CHECL: [[#LINE+1]] | `- error: invalid redeclaration of 'init(a:)' From 0eaad8a535bf6932a66564ed352f63c9cd14faf2 Mon Sep 17 00:00:00 2001 From: Konrad 'ktoso' Malawski Date: Wed, 23 Apr 2025 18:21:32 +0900 Subject: [PATCH 3/7] WIP on changing the always emit into client funcs --- .../SourceCompatibilityShims.swift | 373 +++++++++--------- .../Concurrency/Task+TaskExecutor.swift | 261 ------------ stdlib/public/Concurrency/Task+init.swift.gyb | 130 ++++-- stdlib/public/Concurrency/Task.swift | 252 ------------ 4 files changed, 287 insertions(+), 729 deletions(-) diff --git a/stdlib/public/Concurrency/SourceCompatibilityShims.swift b/stdlib/public/Concurrency/SourceCompatibilityShims.swift index 75242f0421b1f..b63e84c795131 100644 --- a/stdlib/public/Concurrency/SourceCompatibilityShims.swift +++ b/stdlib/public/Concurrency/SourceCompatibilityShims.swift @@ -14,6 +14,7 @@ //===----------------------------------------------------------------------===// import Swift +import _Concurrency @available(SwiftStdlib 5.1, *) extension Task where Success == Never, Failure == Never { @@ -87,192 +88,192 @@ extension Task where Success == Never, Failure == Never { } } -@available(SwiftStdlib 5.1, *) -extension Task where Failure == Error { - #if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY - @discardableResult - @_alwaysEmitIntoClient - @available(*, unavailable, message: "Unavailable in task-to-thread concurrency model") - public static func runDetached( - priority: TaskPriority? = nil, - operation: __owned @Sendable @escaping () async throws -> Success - ) -> Task { - fatalError("Unavailable in task-to-thread concurrency model") - } - #else - @discardableResult - @_alwaysEmitIntoClient - @available(*, deprecated, message: "`Task.runDetached` was replaced by `Task.detached` and will be removed shortly.") - public static func runDetached( - priority: TaskPriority? = nil, - operation: __owned @Sendable @escaping () async throws -> Success - ) -> Task { - detached(priority: priority, operation: operation) - } - #endif -} - -#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY -@discardableResult -@available(SwiftStdlib 5.1, *) -@available(*, unavailable, message: "Unavailable in task-to-thread concurrency model") -@_alwaysEmitIntoClient -public func detach( - priority: TaskPriority? = nil, - operation: __owned @Sendable @escaping () async -> T -) -> Task { - fatalError("Unavailable in task-to-thread concurrency model") -} -#else -@discardableResult -@available(SwiftStdlib 5.1, *) -@available(*, deprecated, message: "`detach` was replaced by `Task.detached` and will be removed shortly.") -@_alwaysEmitIntoClient -public func detach( - priority: TaskPriority? = nil, - operation: __owned @Sendable @escaping () async -> T -) -> Task { - Task.detached(priority: priority, operation: operation) -} -#endif - -#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY -@discardableResult -@available(SwiftStdlib 5.1, *) -@available(*, unavailable, message: "Unavailable in task-to-thread concurrency model") -@_alwaysEmitIntoClient -public func detach( - priority: TaskPriority? = nil, - operation: __owned @Sendable @escaping () async throws -> T -) -> Task { - fatalError("Unavailable in task-to-thread concurrency model") -} -#else -@discardableResult -@available(SwiftStdlib 5.1, *) -@available(*, deprecated, message: "`detach` was replaced by `Task.detached` and will be removed shortly.") -@_alwaysEmitIntoClient -public func detach( - priority: TaskPriority? = nil, - operation: __owned @Sendable @escaping () async throws -> T -) -> Task { - Task.detached(priority: priority, operation: operation) -} -#endif - -#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY -@discardableResult -@available(SwiftStdlib 5.1, *) -@available(*, unavailable, message: "Unavailable in task-to-thread concurrency model") -@_alwaysEmitIntoClient -public func asyncDetached( - priority: TaskPriority? = nil, - @_implicitSelfCapture operation: __owned @Sendable @escaping () async -> T -) -> Task { - fatalError("Unavailable in task-to-thread concurrency model") -} -#else -@discardableResult -@available(SwiftStdlib 5.1, *) -@available(*, deprecated, message: "`asyncDetached` was replaced by `Task.detached` and will be removed shortly.") -@_alwaysEmitIntoClient -public func asyncDetached( - priority: TaskPriority? = nil, - @_implicitSelfCapture operation: __owned @Sendable @escaping () async -> T -) -> Task { - return Task.detached(priority: priority, operation: operation) -} -#endif - -#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY -@discardableResult -@available(SwiftStdlib 5.1, *) -@available(*, unavailable, message: "Unavailable in task-to-thread concurrency model") -@_alwaysEmitIntoClient -public func asyncDetached( - priority: TaskPriority? = nil, - @_implicitSelfCapture operation: __owned @Sendable @escaping () async throws -> T -) -> Task { - fatalError("Unavailable in task-to-thread concurrency model") -} -#else -@discardableResult -@available(SwiftStdlib 5.1, *) -@available(*, deprecated, message: "`asyncDetached` was replaced by `Task.detached` and will be removed shortly.") -@_alwaysEmitIntoClient -public func asyncDetached( - priority: TaskPriority? = nil, - @_implicitSelfCapture operation: __owned @Sendable @escaping () async throws -> T -) -> Task { - return Task.detached(priority: priority, operation: operation) -} -#endif - -#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY -@available(SwiftStdlib 5.1, *) -@available(*, unavailable, message: "Unavailable in task-to-thread concurrency model") -@discardableResult -@_alwaysEmitIntoClient -public func async( - priority: TaskPriority? = nil, - @_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping () async -> T -) -> Task { - fatalError("Unavailable in task-to-thread concurrency model") -} -#else -@available(SwiftStdlib 5.1, *) -@available(*, deprecated, message: "`async` was replaced by `Task.init` and will be removed shortly.") -@discardableResult -@_alwaysEmitIntoClient -public func async( - priority: TaskPriority? = nil, - @_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping () async -> T -) -> Task { - .init(priority: priority, operation: operation) -} -#endif - -#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY -@available(SwiftStdlib 5.1, *) -@available(*, unavailable, message: "Unavailable in task-to-thread concurrency model") -@discardableResult -@_alwaysEmitIntoClient -public func async( - priority: TaskPriority? = nil, - @_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping () async throws -> T -) -> Task { - fatalError("Unavailable in task-to-thread concurrency model") -} -#else -@available(SwiftStdlib 5.1, *) -@available(*, deprecated, message: "`async` was replaced by `Task.init` and will be removed shortly.") -@discardableResult -@_alwaysEmitIntoClient -public func async( - priority: TaskPriority? = nil, - @_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping () async throws -> T -) -> Task { - .init(priority: priority, operation: operation) -} -#endif - -@available(SwiftStdlib 5.1, *) -extension Task where Success == Never, Failure == Never { - @available(*, deprecated, message: "`Task.Group` was replaced by `ThrowingTaskGroup` and `TaskGroup` and will be removed shortly.") - public typealias Group = ThrowingTaskGroup - - @available(*, deprecated, message: "`Task.withGroup` was replaced by `withThrowingTaskGroup` and `withTaskGroup` and will be removed shortly.") - @_alwaysEmitIntoClient - public static func withGroup( - resultType: TaskResult.Type, - returning returnType: BodyResult.Type = BodyResult.self, - body: (inout Task.Group) async throws -> BodyResult - ) async rethrows -> BodyResult { - try await withThrowingTaskGroup(of: resultType) { group in - try await body(&group) - } - } -} +//@available(SwiftStdlib 5.1, *) +//extension Task where Failure == Error { +// #if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY +// @discardableResult +// @_alwaysEmitIntoClient +// @available(*, unavailable, message: "Unavailable in task-to-thread concurrency model") +// public static func runDetached( +// priority: TaskPriority? = nil, +// operation: __owned @Sendable @escaping () async throws -> Success +// ) -> Task { +// fatalError("Unavailable in task-to-thread concurrency model") +// } +// #else +// @discardableResult +// @_alwaysEmitIntoClient +// @available(*, deprecated, message: "`Task.runDetached` was replaced by `Task.detached` and will be removed shortly.") +// public static func runDetached( +// priority: TaskPriority? = nil, +// operation: __owned @Sendable @escaping () async throws -> Success +// ) -> Task { +// detached(priority: priority, operation: operation) +// } +// #endif +//} +// +//#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY +//@discardableResult +//@available(SwiftStdlib 5.1, *) +//@available(*, unavailable, message: "Unavailable in task-to-thread concurrency model") +//@_alwaysEmitIntoClient +//public func detach( +// priority: TaskPriority? = nil, +// operation: __owned @Sendable @escaping () async -> T +//) -> Task { +// fatalError("Unavailable in task-to-thread concurrency model") +//} +//#else +//@discardableResult +//@available(SwiftStdlib 5.1, *) +//@available(*, deprecated, message: "`detach` was replaced by `Task.detached` and will be removed shortly.") +//@_alwaysEmitIntoClient +//public func detach( +// priority: TaskPriority? = nil, +// operation: __owned @Sendable @escaping () async -> T +//) -> Task { +// Task.detached(priority: priority, operation: operation) +//} +//#endif +// +//#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY +//@discardableResult +//@available(SwiftStdlib 5.1, *) +//@available(*, unavailable, message: "Unavailable in task-to-thread concurrency model") +//@_alwaysEmitIntoClient +//public func detach( +// priority: TaskPriority? = nil, +// operation: __owned @Sendable @escaping () async throws -> T +//) -> Task { +// fatalError("Unavailable in task-to-thread concurrency model") +//} +//#else +//@discardableResult +//@available(SwiftStdlib 5.1, *) +//@available(*, deprecated, message: "`detach` was replaced by `Task.detached` and will be removed shortly.") +//@_alwaysEmitIntoClient +//public func detach( +// priority: TaskPriority? = nil, +// operation: __owned @Sendable @escaping () async throws -> T +//) -> Task { +// Task.detached(priority: priority, operation: operation) +//} +//#endif +// +//#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY +//@discardableResult +//@available(SwiftStdlib 5.1, *) +//@available(*, unavailable, message: "Unavailable in task-to-thread concurrency model") +//@_alwaysEmitIntoClient +//public func asyncDetached( +// priority: TaskPriority? = nil, +// @_implicitSelfCapture operation: __owned @Sendable @escaping () async -> T +//) -> Task { +// fatalError("Unavailable in task-to-thread concurrency model") +//} +//#else +//@discardableResult +//@available(SwiftStdlib 5.1, *) +//@available(*, deprecated, message: "`asyncDetached` was replaced by `Task.detached` and will be removed shortly.") +//@_alwaysEmitIntoClient +//public func asyncDetached( +// priority: TaskPriority? = nil, +// @_implicitSelfCapture operation: __owned @Sendable @escaping () async -> T +//) -> Task { +// return Task.detached(priority: priority, operation: operation) +//} +//#endif +// +//#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY +//@discardableResult +//@available(SwiftStdlib 5.1, *) +//@available(*, unavailable, message: "Unavailable in task-to-thread concurrency model") +//@_alwaysEmitIntoClient +//public func asyncDetached( +// priority: TaskPriority? = nil, +// @_implicitSelfCapture operation: __owned @Sendable @escaping () async throws -> T +//) -> Task { +// fatalError("Unavailable in task-to-thread concurrency model") +//} +//#else +//@discardableResult +//@available(SwiftStdlib 5.1, *) +//@available(*, deprecated, message: "`asyncDetached` was replaced by `Task.detached` and will be removed shortly.") +//@_alwaysEmitIntoClient +//public func asyncDetached( +// priority: TaskPriority? = nil, +// @_implicitSelfCapture operation: __owned @Sendable @escaping () async throws -> T +//) -> Task { +// return Task.detached(priority: priority, operation: operation) +//} +//#endif +// +//#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY +//@available(SwiftStdlib 5.1, *) +//@available(*, unavailable, message: "Unavailable in task-to-thread concurrency model") +//@discardableResult +//@_alwaysEmitIntoClient +//public func async( +// priority: TaskPriority? = nil, +// @_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping () async -> T +//) -> Task { +// fatalError("Unavailable in task-to-thread concurrency model") +//} +//#else +//@available(SwiftStdlib 5.1, *) +//@available(*, deprecated, message: "`async` was replaced by `Task.init` and will be removed shortly.") +//@discardableResult +//@_alwaysEmitIntoClient +//public func async( +// priority: TaskPriority? = nil, +// @_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping () async -> T +//) -> Task { +// .init(priority: priority, operation: operation) +//} +//#endif +// +//#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY +//@available(SwiftStdlib 5.1, *) +//@available(*, unavailable, message: "Unavailable in task-to-thread concurrency model") +//@discardableResult +//@_alwaysEmitIntoClient +//public func async( +// priority: TaskPriority? = nil, +// @_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping () async throws -> T +//) -> Task { +// fatalError("Unavailable in task-to-thread concurrency model") +//} +//#else +//@available(SwiftStdlib 5.1, *) +//@available(*, deprecated, message: "`async` was replaced by `Task.init` and will be removed shortly.") +//@discardableResult +//@_alwaysEmitIntoClient +//public func async( +// priority: TaskPriority? = nil, +// @_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping () async throws -> T +//) -> Task { +// .init(priority: priority, operation: operation) +//} +//#endif +// +//@available(SwiftStdlib 5.1, *) +//extension Task where Success == Never, Failure == Never { +// @available(*, deprecated, message: "`Task.Group` was replaced by `ThrowingTaskGroup` and `TaskGroup` and will be removed shortly.") +// public typealias Group = ThrowingTaskGroup +// +// @available(*, deprecated, message: "`Task.withGroup` was replaced by `withThrowingTaskGroup` and `withTaskGroup` and will be removed shortly.") +// @_alwaysEmitIntoClient +// public static func withGroup( +// resultType: TaskResult.Type, +// returning returnType: BodyResult.Type = BodyResult.self, +// body: (inout Task.Group) async throws -> BodyResult +// ) async rethrows -> BodyResult { +// try await withThrowingTaskGroup(of: resultType) { group in +// try await body(&group) +// } +// } +//} @available(SwiftStdlib 5.1, *) extension Task { diff --git a/stdlib/public/Concurrency/Task+TaskExecutor.swift b/stdlib/public/Concurrency/Task+TaskExecutor.swift index 11eae75ef1824..ca04d74c63afe 100644 --- a/stdlib/public/Concurrency/Task+TaskExecutor.swift +++ b/stdlib/public/Concurrency/Task+TaskExecutor.swift @@ -187,267 +187,6 @@ public func _unsafeInheritExecutor_withTaskExecutorPreference( return try await operation() } -/// Task with specified executor ----------------------------------------------- - -@available(SwiftStdlib 6.0, *) -@_unavailableInEmbedded -extension Task where Failure == Never { - /// Runs the given nonthrowing operation asynchronously - /// as part of a new top-level task on behalf of the current actor. - /// - /// This overload allows specifying a preferred ``TaskExecutor`` on which - /// the `operation`, as well as all child tasks created from this task will be - /// executing whenever possible. Refer to ``TaskExecutor`` for a detailed discussion - /// of the effect of task executors on execution semantics of asynchronous code. - /// - /// Use this function when creating asynchronous work - /// that operates on behalf of the synchronous function that calls it. - /// Like `Task.detached(priority:operation:)`, - /// this function creates a separate, top-level task. - /// Unlike `Task.detached(priority:operation:)`, - /// the task created by `Task.init(priority:operation:)` - /// inherits the priority and actor context of the caller, - /// so the operation is treated more like an asynchronous extension - /// to the synchronous operation. - /// - /// You need to keep a reference to the task - /// if you want to cancel it by calling the `Task.cancel()` method. - /// Discarding your reference to a detached task - /// doesn't implicitly cancel that task, - /// it only makes it impossible for you to explicitly cancel the task. - /// - /// - Parameters: - /// - taskExecutor: the preferred task executor for this task, - /// and any child tasks created by it. Explicitly passing `nil` is - /// interpreted as "no preference". - /// - priority: The priority of the task. - /// Pass `nil` to use the priority from `Task.currentPriority`. - /// - operation: The operation to perform. - /// - SeeAlso: ``withTaskExecutorPreference(_:operation:)`` - @discardableResult - @_alwaysEmitIntoClient - public init( - executorPreference taskExecutor: consuming (any TaskExecutor)?, - priority: TaskPriority? = nil, - operation: sending @escaping () async -> Success - ) { - guard let taskExecutor else { - self = Self.init(priority: priority, operation: operation) - return - } - // Set up the job flags for a new task. - let flags = taskCreateFlags( - priority: priority, - isChildTask: false, - copyTaskLocals: true, - inheritContext: true, - enqueueJob: true, - addPendingGroupTaskUnconditionally: false, - isDiscardingTask: false, - isSynchronousStart: false) - -#if $BuiltinCreateAsyncTaskOwnedTaskExecutor - let (task, _) = Builtin.createTask( - flags: flags, - initialTaskExecutorConsuming: taskExecutor, - operation: operation) -#else - let executorBuiltin: Builtin.Executor = - taskExecutor.asUnownedTaskExecutor().executor - let (task, _) = Builtin.createAsyncTaskWithExecutor( - flags, executorBuiltin, operation) -#endif - self._task = task - } -} - -@available(SwiftStdlib 6.0, *) -@_unavailableInEmbedded -extension Task where Failure == Error { - /// Runs the given throwing operation asynchronously - /// as part of a new top-level task on behalf of the current actor. - /// - /// Use this function when creating asynchronous work - /// that operates on behalf of the synchronous function that calls it. - /// Like `Task.detached(priority:operation:)`, - /// this function creates a separate, top-level task. - /// Unlike `detach(priority:operation:)`, - /// the task created by `Task.init(priority:operation:)` - /// inherits the priority and actor context of the caller, - /// so the operation is treated more like an asynchronous extension - /// to the synchronous operation. - /// - /// You need to keep a reference to the task - /// if you want to cancel it by calling the `Task.cancel()` method. - /// Discarding your reference to a detached task - /// doesn't implicitly cancel that task, - /// it only makes it impossible for you to explicitly cancel the task. - /// - /// - Parameters: - /// - taskExecutor: the preferred task executor for this task, - /// and any child tasks created by it. Explicitly passing `nil` is - /// interpreted as "no preference". - /// - priority: The priority of the task. - /// Pass `nil` to use the priority from `Task.currentPriority`. - /// - operation: The operation to perform. - /// - SeeAlso: ``withTaskExecutorPreference(_:operation:)`` - @discardableResult - @_alwaysEmitIntoClient - public init( - executorPreference taskExecutor: consuming (any TaskExecutor)?, - priority: TaskPriority? = nil, - operation: sending @escaping () async throws -> Success - ) { - guard let taskExecutor else { - self = Self.init(priority: priority, operation: operation) - return - } - // Set up the job flags for a new task. - let flags = taskCreateFlags( - priority: priority, isChildTask: false, copyTaskLocals: true, - inheritContext: true, enqueueJob: true, - addPendingGroupTaskUnconditionally: false, - isDiscardingTask: false, isSynchronousStart: false) - -#if $BuiltinCreateAsyncTaskOwnedTaskExecutor - let (task, _) = Builtin.createTask( - flags: flags, - initialTaskExecutorConsuming: taskExecutor, - operation: operation) -#else - let executorBuiltin: Builtin.Executor = - taskExecutor.asUnownedTaskExecutor().executor - let (task, _) = Builtin.createAsyncTaskWithExecutor( - flags, executorBuiltin, operation) -#endif - self._task = task - } -} - -// ==== Detached tasks --------------------------------------------------------- - -@available(SwiftStdlib 6.0, *) -@_unavailableInEmbedded -extension Task where Failure == Never { - /// Runs the given nonthrowing operation asynchronously - /// as part of a new top-level task. - /// - /// Don't use a detached unstructured task if it's possible - /// to model the operation using structured concurrency features like child tasks. - /// Child tasks inherit the parent task's priority and task-local storage, - /// and canceling a parent task automatically cancels all of its child tasks. - /// You need to handle these considerations manually with a detached task. - /// - /// You need to keep a reference to the detached task - /// if you want to cancel it by calling the `Task.cancel()` method. - /// Discarding your reference to a detached task - /// doesn't implicitly cancel that task, - /// it only makes it impossible for you to explicitly cancel the task. - /// - /// - Parameters: - /// - taskExecutor: the preferred task executor for this task, - /// and any child tasks created by it. Explicitly passing `nil` is - /// interpreted as "no preference". - /// - priority: The priority of the task. - /// Pass `nil` to use the priority from `Task.currentPriority`. - /// - operation: The operation to perform. - /// - Returns: A reference to the newly created task. - /// - SeeAlso: ``withTaskExecutorPreference(_:operation:)`` - @discardableResult - @_alwaysEmitIntoClient - public static func detached( - executorPreference taskExecutor: (any TaskExecutor)?, - priority: TaskPriority? = nil, - operation: sending @escaping () async -> Success - ) -> Task { - guard let taskExecutor else { - return Self.detached(priority: priority, operation: operation) - } - // Set up the job flags for a new task. - let flags = taskCreateFlags( - priority: priority, isChildTask: false, copyTaskLocals: false, - inheritContext: false, enqueueJob: true, - addPendingGroupTaskUnconditionally: false, - isDiscardingTask: false, isSynchronousStart: false) - -#if $BuiltinCreateAsyncTaskOwnedTaskExecutor - let (task, _) = Builtin.createTask( - flags: flags, - initialTaskExecutorConsuming: taskExecutor, - operation: operation) -#else - let executorBuiltin: Builtin.Executor = - taskExecutor.asUnownedTaskExecutor().executor - let (task, _) = Builtin.createAsyncTaskWithExecutor( - flags, executorBuiltin, operation) -#endif - return Task(task) - } -} - -@available(SwiftStdlib 6.0, *) -@_unavailableInEmbedded -extension Task where Failure == Error { - /// Runs the given throwing operation asynchronously - /// as part of a new top-level task. - /// - /// If the operation throws an error, this method propagates that error. - /// - /// Don't use a detached unstructured task if it's possible - /// to model the operation using structured concurrency features like child tasks. - /// Child tasks inherit the parent task's priority and task-local storage, - /// and canceling a parent task automatically cancels all of its child tasks. - /// You need to handle these considerations manually with a detached task. - /// - /// You need to keep a reference to the detached task - /// if you want to cancel it by calling the `Task.cancel()` method. - /// Discarding your reference to a detached task - /// doesn't implicitly cancel that task, - /// it only makes it impossible for you to explicitly cancel the task. - /// - /// - Parameters: - /// - taskExecutor: the preferred task executor for this task, - /// and any child tasks created by it. Explicitly passing `nil` is - /// interpreted as "no preference". - /// - priority: The priority of the task. - /// Pass `nil` to use the priority from `Task.currentPriority`. - /// - operation: The operation to perform. - /// - Returns: A reference to the newly created task. - /// - SeeAlso: ``withTaskExecutorPreference(_:operation:)`` - @discardableResult - @_alwaysEmitIntoClient - public static func detached( - executorPreference taskExecutor: (any TaskExecutor)?, - priority: TaskPriority? = nil, - operation: sending @escaping () async throws -> Success - ) -> Task { - guard let taskExecutor else { - return Self.detached(priority: priority, operation: operation) - } - // Set up the job flags for a new task. - let flags = taskCreateFlags( - priority: priority, isChildTask: false, copyTaskLocals: false, - inheritContext: false, enqueueJob: true, - addPendingGroupTaskUnconditionally: false, - isDiscardingTask: false, isSynchronousStart: false) - -#if $BuiltinCreateAsyncTaskOwnedTaskExecutor - let (task, _) = Builtin.createTask( - flags: flags, - initialTaskExecutorConsuming: taskExecutor, - operation: operation) -#else - let executorBuiltin: Builtin.Executor = - taskExecutor.asUnownedTaskExecutor().executor - let (task, _) = Builtin.createAsyncTaskWithExecutor( - flags, executorBuiltin, operation) -#endif - return Task(task) - } -} - -// ==== Unsafe Current Task ---------------------------------------------------- - @available(SwiftStdlib 6.0, *) @_unavailableInEmbedded extension UnsafeCurrentTask { diff --git a/stdlib/public/Concurrency/Task+init.swift.gyb b/stdlib/public/Concurrency/Task+init.swift.gyb index 22950f1c4d630..2c4f544f2f172 100644 --- a/stdlib/public/Concurrency/Task+init.swift.gyb +++ b/stdlib/public/Concurrency/Task+init.swift.gyb @@ -12,70 +12,135 @@ import Swift -// ==== Task.init ------------------------------------------------ - % for (METHOD_VARIANTS, ALL_AVAILABILITY, PARAMS) in [ +% # ==== ------------------------------------------------------------------------------------------------------------- % # ==== Without task executor, but available ever since 5.1 % ([ # METHOD_VARIANT -% '', -% 'THROWING', +% 'init', +% 'init/*throws*/', % ], % [ # ALL_AVAILABILITY % '@_alwaysEmitIntoClient', % '@available(SwiftStdlib 5.1, *)', % ], % [ # PARAMS -% 'name: String?', +% 'name: String? = nil', % 'priority: TaskPriority? = nil', % '@_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async throws -> Success', % ]), +% # ==== -------------------------------------------------------------------- % ([ # METHOD_VARIANT -% 'DETACHED', -% 'DETACHED THROWING', +% 'static func detached', +% 'static func detached/*throws*/', % ], % [ % '@_alwaysEmitIntoClient', % '@available(SwiftStdlib 5.1, *)', % ], % [ # PARAMS -% 'name: String?', +% 'name: String? = nil', % 'priority: TaskPriority? = nil', % 'operation: sending @escaping @isolated(any) () async throws -> Success', % ]), +% # ==== ------------------------------------------------------------------------------------------------------------- % # ==== With task executor, but available only since 6.0 % ([ # METHOD_VARIANT -% '', -% 'THROWING', +% 'init', +% 'init/*throws*/', % ], % [ # ALL_AVAILABILITY % '@_alwaysEmitIntoClient', % '@available(SwiftStdlib 6.0, *)', % ], % [ # PARAMS -% 'name: String?', +% 'name: String? = nil', % 'executorPreference taskExecutor: (any TaskExecutor)? = nil', % 'priority: TaskPriority? = nil', % '@_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async throws -> Success', % ]), +% # ==== -------------------------------------------------------------------- % ([ # METHOD_VARIANT -% 'DETACHED', -% 'DETACHED THROWING', +% 'static func detached', +% 'static func detached/*throws*/', % ], % [ % '@_alwaysEmitIntoClient', % '@available(SwiftStdlib 6.0, *)', % ], % [ # PARAMS -% 'name: String?', +% 'name: String? = nil', % 'executorPreference taskExecutor: (any TaskExecutor)? = nil', % 'priority: TaskPriority? = nil', % 'operation: sending @escaping @isolated(any) () async throws -> Success', % ]), +% # !!!! ------------------------------------------------------------------------------------------------------------- +% # !!!! Legacy / Source compatibility APIs +% # !!!! ------------------------------------------------------------------------------------------------------------- +% # ==== Legacy API: Global 'detach' function +% ([ # METHOD_VARIANT +% 'func detach', +% 'func detach/*throws*/', +% ], +% [ # ALL_AVAILABILITY +% '@_alwaysEmitIntoClient', +% '@available(SwiftStdlib 5.1, *)', +% '@available(*, deprecated, message: "`detach` was replaced by `Task.detached` and will be removed shortly.")', +% ], +% [ # PARAMS +% 'priority: TaskPriority? = nil', +% # FIXME: THOSE MUST NOT HAVE isolated(any) !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +% '@_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping @isolated(any) () async throws -> Success', +% ]), +% # ==== Legacy API: runDetached +% ([ # METHOD_VARIANT +% 'static func runDetached', +% 'static func runDetached/*throws*/', +% ], +% [ # ALL_AVAILABILITY +% '@_alwaysEmitIntoClient', +% '@available(SwiftStdlib 5.1, *)', +% '@available(*, deprecated, message: "`Task.runDetached` was replaced by `Task.detached` and will be removed shortly.")', +% ], +% [ # PARAMS +% 'priority: TaskPriority? = nil', +% '@_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping @isolated(any) () async throws -> Success', +% ]), +% # ==== Legacy API: asyncDetached +% ([ # METHOD_VARIANT +% 'func asyncDetached', +% 'func asyncDetached/*throws*/', +% ], +% [ # ALL_AVAILABILITY +% '@_alwaysEmitIntoClient', +% '@available(SwiftStdlib 5.1, *)', +% '@available(*, deprecated, message: "`asyncDetached` was replaced by `Task.detached` and will be removed shortly.")', +% ], +% [ # PARAMS +% 'priority: TaskPriority? = nil', +% '@_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping @isolated(any) () async throws -> Success', +% ]), +% # ==== Legacy API: async +% ([ # METHOD_VARIANT +% 'func async', +% 'func async/*throws*/', +% ], +% [ # ALL_AVAILABILITY +% '@_alwaysEmitIntoClient', +% '@available(SwiftStdlib 5.1, *)', +% '@available(*, deprecated, message: "`async` was replaced by `Task.init` and will be removed shortly.")', +% ], +% [ # PARAMS +% 'priority: TaskPriority? = nil', +% '@_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping @isolated(any) () async throws -> Success', +% ]), % ]: % for METHOD_VARIANT in METHOD_VARIANTS: -% IS_DETACHED = 'DETACHED' in METHOD_VARIANT -% IS_THROWING = 'THROWING' in METHOD_VARIANT +% IS_TOP_LEVEL_FUNC = (not ('init' in METHOD_VARIANT)) and (not ('static' in METHOD_VARIANT)) +% IS_INIT = 'init' in METHOD_VARIANT +% IS_DETACHED = 'detached' in METHOD_VARIANT +% IS_THROWING = 'throws' in METHOD_VARIANT +% % HAS_TASK_PRIORITY = any('priority:' in param for param in PARAMS) % HAS_TASK_NAME = any('name:' in param for param in PARAMS) % HAS_TASK_EXECUTOR = any('taskExecutor:' in param for param in PARAMS) @@ -106,27 +171,24 @@ def adjust_availability(avails): res.append(adjusted) return res -if IS_DETACHED: - ARROW_RETURN_TYPE = f'-> Task' -else: +if IS_INIT: ARROW_RETURN_TYPE = '' # init does not spell out return type - -if IS_DETACHED: - THE_FUNC = 'public static func detached' else: - THE_FUNC = 'public init' + ARROW_RETURN_TYPE = f'-> Task' }% % # ==================================================================================================================== +% if not IS_TOP_LEVEL_FUNC: extension Task where Failure == ${FAILURE_TYPE} { +% end % # -------------------------------------------------------------------------------------------------------------------- #if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY @discardableResult @_alwaysEmitIntoClient @available(*, unavailable, message: "Unavailable in task-to-thread concurrency model") - ${THE_FUNC}( + public ${METHOD_VARIANT}( ${",\n ".join(adjust_params_for_kind(PARAMS))} ) ${ARROW_RETURN_TYPE}{ fatalError("Unavailable in task-to-thread concurrency model.") @@ -137,7 +199,7 @@ extension Task where Failure == ${FAILURE_TYPE} { @discardableResult @_alwaysEmitIntoClient ${" \n".join(adjust_availability(['@available(SwiftStdlib 5.1, *)']))} - ${THE_FUNC}( + public ${METHOD_VARIANT}( ${",\n ".join(adjust_params_for_kind(PARAMS))} ) ${ARROW_RETURN_TYPE}{ // Set up the job flags for a new task. @@ -195,7 +257,6 @@ extension Task where Failure == ${FAILURE_TYPE} { /// - name: Human readable name of the task. % end % if HAS_TASK_EXECUTOR: - /// - taskExecutor: /// - taskExecutor: The task executor that the child task should be started on and keep using. /// Explicitly passing `nil` as the executor preference is equivalent to no preference, /// and effectively means to inherit the outer context's executor preference. @@ -207,7 +268,7 @@ extension Task where Failure == ${FAILURE_TYPE} { /// - Returns: A reference to the task. ${"\n ".join(adjust_availability(ALL_AVAILABILITY))} @discardableResult - ${THE_FUNC}( + public ${METHOD_VARIANT}( ${",\n ".join(adjust_params_for_kind(PARAMS))} ) ${ARROW_RETURN_TYPE}{ @@ -227,6 +288,7 @@ extension Task where Failure == ${FAILURE_TYPE} { unsafe Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor var task: Builtin.NativeObject? +% if HAS_TASK_NAME: #if $BuiltinCreateAsyncTaskName if let name { task = @@ -239,6 +301,8 @@ extension Task where Failure == ${FAILURE_TYPE} { } } #endif +% end + if task == nil { // either no task name was set, or names are unsupported task = Builtin.createTask( @@ -247,15 +311,21 @@ extension Task where Failure == ${FAILURE_TYPE} { operation: operation).0 } -% if IS_DETACHED: - return Task(task!) -% else: +% if IS_INIT: self._task = task! +% else: + return Task(task!) % end } #endif + +% if not IS_TOP_LEVEL_FUNC: } // extension Task ... +% end % end % end + +// ===================================================================================================================== +// ===================================================================================================================== diff --git a/stdlib/public/Concurrency/Task.swift b/stdlib/public/Concurrency/Task.swift index 3e9d8797baf97..a43607d56b95f 100644 --- a/stdlib/public/Concurrency/Task.swift +++ b/stdlib/public/Concurrency/Task.swift @@ -580,258 +580,6 @@ func taskCreateFlags( return bits } -// ==== Task Creation ---------------------------------------------------------- - -@available(SwiftStdlib 5.1, *) -extension Task where Failure == Never { -#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY - @discardableResult - @_alwaysEmitIntoClient - @available(*, unavailable, message: "Unavailable in task-to-thread concurrency model") - public init( - priority: TaskPriority? = nil, - @_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async -> Success - ) { - fatalError("Unavailable in task-to-thread concurrency model.") - } -#else - /// Runs the given nonthrowing operation asynchronously - /// as part of a new top-level task on behalf of the current actor. - /// - /// Use this function when creating asynchronous work - /// that operates on behalf of the synchronous function that calls it. - /// Like `Task.detached(priority:operation:)`, - /// this function creates a separate, top-level task. - /// Unlike `Task.detached(priority:operation:)`, - /// the task created by `Task.init(priority:operation:)` - /// inherits the priority and actor context of the caller, - /// so the operation is treated more like an asynchronous extension - /// to the synchronous operation. - /// - /// You need to keep a reference to the task - /// if you want to cancel it by calling the `Task.cancel()` method. - /// Discarding your reference to a detached task - /// doesn't implicitly cancel that task, - /// it only makes it impossible for you to explicitly cancel the task. - /// - /// - Parameters: - /// - priority: The priority of the task. - /// Pass `nil` to use the priority from `Task.currentPriority`. - /// - operation: The operation to perform. - @discardableResult - @_alwaysEmitIntoClient - public init( - priority: TaskPriority? = nil, - @_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async -> Success - ) { - // Set up the job flags for a new task. - let flags = taskCreateFlags( - priority: priority, isChildTask: false, copyTaskLocals: true, - inheritContext: true, enqueueJob: true, - addPendingGroupTaskUnconditionally: false, - isDiscardingTask: false, isSynchronousStart: false) - - // Create the asynchronous task. - let builtinSerialExecutor = - unsafe Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor - - let (task, _) = Builtin.createTask(flags: flags, - initialSerialExecutor: builtinSerialExecutor, - operation: operation) - - self._task = task - } -#endif -} - -@available(SwiftStdlib 5.1, *) -extension Task where Failure == Error { -#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY - @discardableResult - @_alwaysEmitIntoClient - @available(*, unavailable, message: "Unavailable in task-to-thread concurrency model") - public init( - priority: TaskPriority? = nil, - @_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async throws -> Success - ) { - fatalError("Unavailable in task-to-thread concurrency model") - } -#else - /// Runs the given throwing operation asynchronously - /// as part of a new top-level task on behalf of the current actor. - /// - /// Use this function when creating asynchronous work - /// that operates on behalf of the synchronous function that calls it. - /// Like `Task.detached(priority:operation:)`, - /// this function creates a separate, top-level task. - /// Unlike `detach(priority:operation:)`, - /// the task created by `Task.init(priority:operation:)` - /// inherits the priority and actor context of the caller, - /// so the operation is treated more like an asynchronous extension - /// to the synchronous operation. - /// - /// You need to keep a reference to the task - /// if you want to cancel it by calling the `Task.cancel()` method. - /// Discarding your reference to a detached task - /// doesn't implicitly cancel that task, - /// it only makes it impossible for you to explicitly cancel the task. - /// - /// - Parameters: - /// - priority: The priority of the task. - /// Pass `nil` to use the priority from `Task.currentPriority`. - /// - operation: The operation to perform. - @discardableResult - @_alwaysEmitIntoClient - public init( - priority: TaskPriority? = nil, - @_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async throws -> Success - ) { - // Set up the task flags for a new task. - let flags = taskCreateFlags( - priority: priority, isChildTask: false, copyTaskLocals: true, - inheritContext: true, enqueueJob: true, - addPendingGroupTaskUnconditionally: false, - isDiscardingTask: false, isSynchronousStart: false) - - // Create the asynchronous task future. - let builtinSerialExecutor = - unsafe Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor - - let (task, _) = Builtin.createTask(flags: flags, - initialSerialExecutor: builtinSerialExecutor, - operation: operation) - - self._task = task - } -#endif -} - -// ==== Detached Tasks --------------------------------------------------------- - -@available(SwiftStdlib 5.1, *) -extension Task where Failure == Never { -#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY - @discardableResult - @_alwaysEmitIntoClient - @available(*, unavailable, message: "Unavailable in task-to-thread concurrency model") - public static func detached( - priority: TaskPriority? = nil, - operation: sending @escaping @isolated(any) () async -> Success - ) -> Task { - fatalError("Unavailable in task-to-thread concurrency model") - } -#else - /// Runs the given nonthrowing operation asynchronously - /// as part of a new top-level task. - /// - /// Don't use a detached unstructured task if it's possible - /// to model the operation using structured concurrency features like child tasks. - /// Child tasks inherit the parent task's priority and task-local storage, - /// and canceling a parent task automatically cancels all of its child tasks. - /// You need to handle these considerations manually with a detached task. - /// - /// You need to keep a reference to the detached task - /// if you want to cancel it by calling the `Task.cancel()` method. - /// Discarding your reference to a detached task - /// doesn't implicitly cancel that task, - /// it only makes it impossible for you to explicitly cancel the task. - /// - /// - Parameters: - /// - priority: The priority of the task. - /// - operation: The operation to perform. - /// - /// - Returns: A reference to the task. - @discardableResult - @_alwaysEmitIntoClient - public static func detached( - priority: TaskPriority? = nil, - operation: sending @escaping @isolated(any) () async -> Success - ) -> Task { - // Set up the job flags for a new task. - let flags = taskCreateFlags( - priority: priority, isChildTask: false, copyTaskLocals: false, - inheritContext: false, enqueueJob: true, - addPendingGroupTaskUnconditionally: false, - isDiscardingTask: false, isSynchronousStart: false) - - // Create the asynchronous task future. - let builtinSerialExecutor = - unsafe Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor - - let (task, _) = Builtin.createTask(flags: flags, - initialSerialExecutor: - builtinSerialExecutor, - operation: operation) - - return Task(task) - } -#endif -} - -@available(SwiftStdlib 5.1, *) -extension Task where Failure == Error { -#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY - @discardableResult - @_alwaysEmitIntoClient - @available(*, unavailable, message: "Unavailable in task-to-thread concurrency model") - public static func detached( - priority: TaskPriority? = nil, - operation: sending @escaping @isolated(any) () async throws -> Success - ) -> Task { - fatalError("Unavailable in task-to-thread concurrency model") - } -#else - /// Runs the given throwing operation asynchronously - /// as part of a new top-level task. - /// - /// If the `operation` throws an error, it is caught by the `Task` and will be - /// rethrown only when the task's `value` is awaited. Take care to not accidentally - /// dismiss errors by not awaiting on the task's resulting value. - /// - /// Don't use a detached unstructured task if it's possible - /// to model the operation using structured concurrency features like child tasks. - /// Child tasks inherit the parent task's priority and task-local storage, - /// and canceling a parent task automatically cancels all of its child tasks. - /// You need to handle these considerations manually with a detached task. - /// - /// You need to keep a reference to the detached task - /// if you want to cancel it by calling the `Task.cancel()` method. - /// Discarding your reference to a detached task - /// doesn't implicitly cancel that task, - /// it only makes it impossible for you to explicitly cancel the task. - /// - /// - Parameters: - /// - priority: The priority of the task. - /// - operation: The operation to perform. - /// - /// - Returns: A reference to the task. - @discardableResult - @_alwaysEmitIntoClient - public static func detached( - priority: TaskPriority? = nil, - operation: sending @escaping @isolated(any) () async throws -> Success - ) -> Task { - // Set up the job flags for a new task. - let flags = taskCreateFlags( - priority: priority, isChildTask: false, copyTaskLocals: false, - inheritContext: false, enqueueJob: true, - addPendingGroupTaskUnconditionally: false, - isDiscardingTask: false, isSynchronousStart: false) - - // Create the asynchronous task future. - let builtinSerialExecutor = - unsafe Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor - - let (task, _) = Builtin.createTask(flags: flags, - initialSerialExecutor: - builtinSerialExecutor, - operation: operation) - - return Task(task) - } -#endif -} - // ==== Task Name -------------------------------------------------------------- @available(SwiftStdlib 6.2, *) From 8605347675b20ca47e49df546fe0ac1ac352629c Mon Sep 17 00:00:00 2001 From: Konrad 'ktoso' Malawski Date: Thu, 24 Apr 2025 16:53:27 +0900 Subject: [PATCH 4/7] [Concurrency] Update Task.init and TaskGroup+addTask gyb for TaskExecutor --- stdlib/public/Concurrency/Task+init.swift.gyb | 101 ++++++++++++++++-- .../Concurrency/TaskGroup+addTask.swift.gyb | 2 +- 2 files changed, 92 insertions(+), 11 deletions(-) diff --git a/stdlib/public/Concurrency/Task+init.swift.gyb b/stdlib/public/Concurrency/Task+init.swift.gyb index 2c4f544f2f172..86463b9f756dc 100644 --- a/stdlib/public/Concurrency/Task+init.swift.gyb +++ b/stdlib/public/Concurrency/Task+init.swift.gyb @@ -56,7 +56,8 @@ import Swift % 'name: String? = nil', % 'executorPreference taskExecutor: (any TaskExecutor)? = nil', % 'priority: TaskPriority? = nil', -% '@_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async throws -> Success', +% # '@_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async throws -> Success', +% 'operation: sending @escaping () async throws -> Success', % ]), % # ==== -------------------------------------------------------------------- % ([ # METHOD_VARIANT @@ -71,10 +72,13 @@ import Swift % 'name: String? = nil', % 'executorPreference taskExecutor: (any TaskExecutor)? = nil', % 'priority: TaskPriority? = nil', -% 'operation: sending @escaping @isolated(any) () async throws -> Success', +% 'operation: sending @escaping () async throws -> Success', % ]), % # !!!! ------------------------------------------------------------------------------------------------------------- -% # !!!! Legacy / Source compatibility APIs +% # !!!! Legacy / Source Compatibility "Shims" +% # !!!! +% # !!!! These legacy APIs technically did not have @isolated(any) but since they're all emit-into-client, +% # !!!! we just allow them to become slightly better here. It makes source generation simpler, and doesn't really hurt. % # !!!! ------------------------------------------------------------------------------------------------------------- % # ==== Legacy API: Global 'detach' function % ([ # METHOD_VARIANT @@ -88,7 +92,6 @@ import Swift % ], % [ # PARAMS % 'priority: TaskPriority? = nil', -% # FIXME: THOSE MUST NOT HAVE isolated(any) !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! % '@_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping @isolated(any) () async throws -> Success', % ]), % # ==== Legacy API: runDetached @@ -144,6 +147,8 @@ import Swift % HAS_TASK_PRIORITY = any('priority:' in param for param in PARAMS) % HAS_TASK_NAME = any('name:' in param for param in PARAMS) % HAS_TASK_EXECUTOR = any('taskExecutor:' in param for param in PARAMS) +% 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' @@ -195,6 +200,7 @@ extension Task where Failure == ${FAILURE_TYPE} { } % # -------------------------------------------------------------------------------------------------------------------- +% if not HAS_TASK_EXECUTOR: #elseif $Embedded @discardableResult @_alwaysEmitIntoClient @@ -213,14 +219,19 @@ extension Task where Failure == ${FAILURE_TYPE} { isDiscardingTask: false, isSynchronousStart: false) - // Create the asynchronous task. let (task, _) = Builtin.createAsyncTask(flags, operation) self._task = task } +% end # not HAS_TASK_EXECUTOR % # -------------------------------------------------------------------------------------------------------------------- #else + +% if IS_DEPRECATED: +/// Deprecated, available only for source compatibility reasons. +% else: +% # We skip documentation for the legacy APIs which are just here for source compatibility reasons. % if IS_THROWING: /// Runs the given throwing operation asynchronously % else: @@ -262,10 +273,14 @@ extension Task where Failure == ${FAILURE_TYPE} { /// and effectively means to inherit the outer context's executor preference. /// You can also pass the ``globalConcurrentExecutor`` global executor explicitly. % end - /// - priority: The priority of the task. + /// - priority: The priority of the operation task. + % if IS_DETACHED: + /// Omit this parameter or pass `nil` to inherit the enclosing context's base priority. + % end /// - operation: The operation to perform. /// /// - Returns: A reference to the task. +% end # IS_DEPRECATED ${"\n ".join(adjust_availability(ALL_AVAILABILITY))} @discardableResult public ${METHOD_VARIANT}( @@ -277,37 +292,103 @@ extension Task where Failure == ${FAILURE_TYPE} { priority: priority, isChildTask: false, copyTaskLocals: ${'true' if not IS_DETACHED else 'false'}, - inheritContext: false, + inheritContext: ${'true' if not IS_DETACHED else 'false'}, enqueueJob: true, addPendingGroupTaskUnconditionally: false, isDiscardingTask: false, isSynchronousStart: false) - // Create the asynchronous task. +% if HAS_ISOLATED_ANY: let builtinSerialExecutor = unsafe Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor +% end # HAS_ISOLATED_ANY var task: Builtin.NativeObject? % if HAS_TASK_NAME: #if $BuiltinCreateAsyncTaskName if let name { + % if HAS_TASK_EXECUTOR: + #if $BuiltinCreateAsyncTaskOwnedTaskExecutor + task = + unsafe name.utf8CString.withUnsafeBufferPointer { nameBytes in + Builtin.createTask( + flags: flags, + % if HAS_ISOLATED_ANY: + initialSerialExecutor: builtinSerialExecutor, + % end + % if HAS_TASK_EXECUTOR: + initialTaskExecutorConsuming: taskExecutor, + % end + taskName: nameBytes.baseAddress!._rawValue, + operation: operation).0 + } + #else // no $BuiltinCreateAsyncTaskOwnedTaskExecutor + // legacy branch for the non-consuming task executor + let executorBuiltin: Builtin.Executor = + taskExecutor.asUnownedTaskExecutor().executor task = unsafe name.utf8CString.withUnsafeBufferPointer { nameBytes in Builtin.createTask( flags: flags, + % if HAS_ISOLATED_ANY: initialSerialExecutor: builtinSerialExecutor, + % end + initialTaskExecutor: executorBuiltin, taskName: nameBytes.baseAddress!._rawValue, operation: operation).0 } + #endif // $BuiltinCreateAsyncTaskOwnedTaskExecutor + % else: # if no TASK_EXECUTOR + task = + unsafe name.utf8CString.withUnsafeBufferPointer { nameBytes in + Builtin.createTask( + flags: flags, + % if HAS_ISOLATED_ANY: + initialSerialExecutor: builtinSerialExecutor, + % end + taskName: nameBytes.baseAddress!._rawValue, + operation: operation).0 + } + % end # if no HAS_TASK_EXECUTOR + } // let name + #endif // $BuiltinCreateAsyncTaskName +% end # HAS_TASK_NAME + +% if HAS_TASK_EXECUTOR: + // Task name was not set, or task name createTask is unavailable + if task == nil { + assert(name == nil) + #if $BuiltinCreateAsyncTaskOwnedTaskExecutor + task = Builtin.createTask( + flags: flags, + % if HAS_ISOLATED_ANY: + initialSerialExecutor: builtinSerialExecutor, + % end + initialTaskExecutorConsuming: taskExecutor, + operation: operation).0 + #else + // legacy branch for the non-consuming task executor + let executorBuiltin: Builtin.Executor = + taskExecutor.asUnownedTaskExecutor().executor + + task = Builtin.createTask( + flags: flags, + % if HAS_ISOLATED_ANY: + initialSerialExecutor: builtinSerialExecutor, + % end + initialTaskExecutor: executorBuiltin, + operation: operation).0 + #endif } - #endif -% end +% end # HAS_TASK_EXECUTOR if task == nil { // either no task name was set, or names are unsupported task = Builtin.createTask( flags: flags, + % if HAS_ISOLATED_ANY: initialSerialExecutor: builtinSerialExecutor, + % end operation: operation).0 } diff --git a/stdlib/public/Concurrency/TaskGroup+addTask.swift.gyb b/stdlib/public/Concurrency/TaskGroup+addTask.swift.gyb index 5baad01019026..f6f4351ac25bc 100644 --- a/stdlib/public/Concurrency/TaskGroup+addTask.swift.gyb +++ b/stdlib/public/Concurrency/TaskGroup+addTask.swift.gyb @@ -315,8 +315,8 @@ extension ${TYPE} { #endif // $BuiltinCreateAsyncTaskName % end # HAS_TASK_NAME - // Task name was not set, or task name createTask is unavailable % if HAS_TASK_EXECUTOR: + // Task name was not set, or task name createTask is unavailable if task == nil, let taskExecutor { #if $BuiltinCreateAsyncTaskOwnedTaskExecutor task = ${TASK_CREATE_FN}( From e63f797ff8da84f8af24911216399bf6d616b399 Mon Sep 17 00:00:00 2001 From: Konrad 'ktoso' Malawski Date: Thu, 24 Apr 2025 18:01:14 +0900 Subject: [PATCH 5/7] [Concurrency] Adjust tests for renamed initializer --- test/Concurrency/transfernonsendable.swift | 6 +++--- test/Concurrency/transfernonsendable_typed_errors.swift | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/Concurrency/transfernonsendable.swift b/test/Concurrency/transfernonsendable.swift index 5f9a4a033f489..a3e48677f2990 100644 --- a/test/Concurrency/transfernonsendable.swift +++ b/test/Concurrency/transfernonsendable.swift @@ -1767,7 +1767,7 @@ extension MyActor { _ = sc Task { // expected-tns-warning {{sending value of non-Sendable type '() async -> ()' risks causing data races}} - // expected-tns-note @-1 {{Passing value of non-Sendable type '() async -> ()' as a 'sending' argument to initializer 'init(priority:operation:)' risks causing races in between local and caller code}} + // expected-tns-note @-1 {{Passing value of non-Sendable type '() async -> ()' as a 'sending' argument to initializer 'init(name:priority:operation:)' risks causing races in between local and caller code}} _ = sc } @@ -1975,7 +1975,7 @@ func mutableLocalCaptureDataRace() async { _ = x Task.detached { x = 1 } // expected-tns-warning {{sending value of non-Sendable type '() async -> ()' risks causing data races}} - // expected-tns-note @-1 {{Passing value of non-Sendable type '() async -> ()' as a 'sending' argument to static method 'detached(priority:operation:)' risks causing races in between local and caller code}} + // expected-tns-note @-1 {{Passing value of non-Sendable type '() async -> ()' as a 'sending' argument to static method 'detached(name:priority:operation:)' risks causing races in between local and caller code}} x = 2 // expected-tns-note {{access can happen concurrently}} } @@ -1985,7 +1985,7 @@ func mutableLocalCaptureDataRace2() async { x = 0 Task.detached { x = 1 } // expected-tns-warning {{sending value of non-Sendable type '() async -> ()' risks causing data races}} - // expected-tns-note @-1 {{Passing value of non-Sendable type '() async -> ()' as a 'sending' argument to static method 'detached(priority:operation:)' risks causing races in between local and caller code}} + // expected-tns-note @-1 {{Passing value of non-Sendable type '() async -> ()' as a 'sending' argument to static method 'detached(name:priority:operation:)' risks causing races in between local and caller code}} print(x) // expected-tns-note {{access can happen concurrently}} } diff --git a/test/Concurrency/transfernonsendable_typed_errors.swift b/test/Concurrency/transfernonsendable_typed_errors.swift index 72d45bac13cb5..cade1abcc2e03 100644 --- a/test/Concurrency/transfernonsendable_typed_errors.swift +++ b/test/Concurrency/transfernonsendable_typed_errors.swift @@ -60,7 +60,7 @@ extension MyActor { _ = sc Task { // expected-error {{sending value of non-Sendable type '() async -> ()' risks causing data races}} - // expected-note @-1 {{Passing value of non-Sendable type '() async -> ()' as a 'sending' argument to initializer 'init(priority:operation:)' risks causing races in between local and caller code}} + // expected-note @-1 {{Passing value of non-Sendable type '() async -> ()' as a 'sending' argument to initializer 'init(name:priority:operation:)' risks causing races in between local and caller code}} _ = sc } From 6c87489f9a8f3ee5053c2a06a60e93033c01cd9a Mon Sep 17 00:00:00 2001 From: Konrad 'ktoso' Malawski Date: Thu, 24 Apr 2025 19:38:13 +0900 Subject: [PATCH 6/7] [Embedded][Concurrency] Workaround for Gyb+concurrency module+embedded --- cmake/modules/SwiftSetIfArchBitness.cmake | 64 +++++++++++++---------- 1 file changed, 35 insertions(+), 29 deletions(-) diff --git a/cmake/modules/SwiftSetIfArchBitness.cmake b/cmake/modules/SwiftSetIfArchBitness.cmake index cbf16c7e754d3..70f109b14b220 100644 --- a/cmake/modules/SwiftSetIfArchBitness.cmake +++ b/cmake/modules/SwiftSetIfArchBitness.cmake @@ -6,39 +6,45 @@ function(set_if_arch_bitness var_name) "" # multi-value args ${ARGN}) - if("${SIA_ARCH}" STREQUAL "avr") + # FIXME: This is a workaround for Concurrency/CMakeLists.txt setting the GYB_SOURCES in embedded-concurrency + # Need to figure out why the SIA_ARCH we get from there isn't right, and undo this workaround. + # Extract first part of the SIA_ARCH (e.g., "x86_64" from "x86_64-apple-macos") + string(REPLACE "-" ";" SIA_ARCH_LIST "${SIA_ARCH}") + list(GET SIA_ARCH_LIST 0 SIA_ARCH_HEAD) + + if("${SIA_ARCH_HEAD}" STREQUAL "avr") set("${var_name}" "${SIA_CASE_16_BIT}" PARENT_SCOPE) - elseif("${SIA_ARCH}" STREQUAL "i386" OR - "${SIA_ARCH}" STREQUAL "i686" OR - "${SIA_ARCH}" STREQUAL "x86" OR - "${SIA_ARCH}" STREQUAL "armv4t" OR - "${SIA_ARCH}" STREQUAL "armv5" OR - "${SIA_ARCH}" STREQUAL "armv6" OR - "${SIA_ARCH}" STREQUAL "armv6m" OR - "${SIA_ARCH}" STREQUAL "armv7" OR - "${SIA_ARCH}" STREQUAL "armv7k" OR - "${SIA_ARCH}" STREQUAL "arm64_32" OR - "${SIA_ARCH}" STREQUAL "armv7m" OR - "${SIA_ARCH}" STREQUAL "armv7em" OR - "${SIA_ARCH}" STREQUAL "armv7s" OR - "${SIA_ARCH}" STREQUAL "m68k" OR - "${SIA_ARCH}" STREQUAL "riscv32" OR - "${SIA_ARCH}" STREQUAL "wasm32" OR - "${SIA_ARCH}" STREQUAL "powerpc") + elseif("${SIA_ARCH_HEAD}" STREQUAL "i386" OR + "${SIA_ARCH_HEAD}" STREQUAL "i686" OR + "${SIA_ARCH_HEAD}" STREQUAL "x86" OR + "${SIA_ARCH_HEAD}" STREQUAL "armv4t" OR + "${SIA_ARCH_HEAD}" STREQUAL "armv5" OR + "${SIA_ARCH_HEAD}" STREQUAL "armv6" OR + "${SIA_ARCH_HEAD}" STREQUAL "armv6m" OR + "${SIA_ARCH_HEAD}" STREQUAL "armv7" OR + "${SIA_ARCH_HEAD}" STREQUAL "armv7k" OR + "${SIA_ARCH_HEAD}" STREQUAL "arm64_32" OR + "${SIA_ARCH_HEAD}" STREQUAL "armv7m" OR + "${SIA_ARCH_HEAD}" STREQUAL "armv7em" OR + "${SIA_ARCH_HEAD}" STREQUAL "armv7s" OR + "${SIA_ARCH_HEAD}" STREQUAL "m68k" OR + "${SIA_ARCH_HEAD}" STREQUAL "riscv32" OR + "${SIA_ARCH_HEAD}" STREQUAL "wasm32" OR + "${SIA_ARCH_HEAD}" STREQUAL "powerpc") set("${var_name}" "${SIA_CASE_32_BIT}" PARENT_SCOPE) - elseif("${SIA_ARCH}" STREQUAL "x86_64" OR - "${SIA_ARCH}" STREQUAL "amd64" OR - "${SIA_ARCH}" STREQUAL "arm64" OR - "${SIA_ARCH}" STREQUAL "arm64e" OR - "${SIA_ARCH}" STREQUAL "aarch64" OR - "${SIA_ARCH}" STREQUAL "powerpc64" OR - "${SIA_ARCH}" STREQUAL "powerpc64le" OR - "${SIA_ARCH}" STREQUAL "s390x" OR - "${SIA_ARCH}" STREQUAL "riscv64" OR - "${SIA_ARCH}" STREQUAL "wasm64") + elseif("${SIA_ARCH_HEAD}" STREQUAL "x86_64" OR + "${SIA_ARCH_HEAD}" STREQUAL "amd64" OR + "${SIA_ARCH_HEAD}" STREQUAL "arm64" OR + "${SIA_ARCH_HEAD}" STREQUAL "arm64e" OR + "${SIA_ARCH_HEAD}" STREQUAL "aarch64" OR + "${SIA_ARCH_HEAD}" STREQUAL "powerpc64" OR + "${SIA_ARCH_HEAD}" STREQUAL "powerpc64le" OR + "${SIA_ARCH_HEAD}" STREQUAL "s390x" OR + "${SIA_ARCH_HEAD}" STREQUAL "riscv64" OR + "${SIA_ARCH_HEAD}" STREQUAL "wasm64") set("${var_name}" "${SIA_CASE_64_BIT}" PARENT_SCOPE) else() - message(FATAL_ERROR "Unknown architecture: ${SIA_ARCH}") + message(FATAL_ERROR "Unknown architecture: ${SIA_ARCH_HEAD} (prefix of ${SIA})") endif() endfunction() From 32e1b67af4dba2a5cd6943898b73c3831702e64b Mon Sep 17 00:00:00 2001 From: Konrad 'ktoso' Malawski Date: Thu, 24 Apr 2025 21:50:17 +0900 Subject: [PATCH 7/7] Add Task+init gyb to embedded; Remove TaskGroup+Embedded.swift workaround --- Runtimes/Core/Concurrency/CMakeLists.txt | 2 +- stdlib/public/Concurrency/CMakeLists.txt | 14 +- .../SourceCompatibilityShims.swift | 204 ++----------- stdlib/public/Concurrency/Task+init.swift.gyb | 8 +- .../Concurrency/TaskGroup+Embedded.swift | 283 ------------------ 5 files changed, 34 insertions(+), 477 deletions(-) delete mode 100644 stdlib/public/Concurrency/TaskGroup+Embedded.swift diff --git a/Runtimes/Core/Concurrency/CMakeLists.txt b/Runtimes/Core/Concurrency/CMakeLists.txt index 8ae44c681ee45..7c299621c55f0 100644 --- a/Runtimes/Core/Concurrency/CMakeLists.txt +++ b/Runtimes/Core/Concurrency/CMakeLists.txt @@ -91,10 +91,10 @@ add_library(swift_Concurrency Task+TaskExecutor.swift TaskCancellation.swift TaskGroup.swift - TaskGroup+Embedded.swift TaskLocal.swift TaskSleep.swift TaskSleepDuration.swift + "${CMAKE_CURRENT_BINARY_DIR}/Task+init.swift" "${CMAKE_CURRENT_BINARY_DIR}/TaskGroup+addTask.swift" "${CMAKE_CURRENT_BINARY_DIR}/Task+startSynchronously.swift") diff --git a/stdlib/public/Concurrency/CMakeLists.txt b/stdlib/public/Concurrency/CMakeLists.txt index a578a009b6ba6..415ac5a1e37da 100644 --- a/stdlib/public/Concurrency/CMakeLists.txt +++ b/stdlib/public/Concurrency/CMakeLists.txt @@ -129,7 +129,6 @@ set(SWIFT_RUNTIME_CONCURRENCY_SWIFT_SOURCES Task+TaskExecutor.swift TaskCancellation.swift TaskGroup.swift - TaskGroup+Embedded.swift DiscardingTaskGroup.swift TaskLocal.swift TaskSleep.swift @@ -204,6 +203,12 @@ set(LLVM_OPTIONAL_SOURCES DispatchGlobalExecutor.cpp ) +set(SWIFT_CONCURRENCY_GYB_SOURCES + Task+init.swift.gyb + TaskGroup+addTask.swift.gyb + Task+startSynchronously.swift.gyb +) + add_swift_target_library(swift_Concurrency ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} IS_STDLIB ${SWIFT_RUNTIME_CONCURRENCY_C_SOURCES} ${SWIFT_RUNTIME_CONCURRENCY_EXECUTOR_SOURCES} @@ -212,9 +217,7 @@ add_swift_target_library(swift_Concurrency ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} I ${SWIFT_RUNTIME_CONCURRENCY_NONEMBEDDED_SWIFT_SOURCES} GYB_SOURCES - Task+init.swift.gyb - TaskGroup+addTask.swift.gyb - Task+startSynchronously.swift.gyb + ${SWIFT_CONCURRENCY_GYB_SOURCES} SWIFT_MODULE_DEPENDS_ANDROID Android SWIFT_MODULE_DEPENDS_LINUX Glibc @@ -310,6 +313,9 @@ if(SWIFT_SHOULD_BUILD_EMBEDDED_STDLIB AND SWIFT_SHOULD_BUILD_EMBEDDED_CONCURRENC ${SWIFT_RUNTIME_CONCURRENCY_SWIFT_SOURCES} ${SWIFT_RUNTIME_CONCURRENCY_EMBEDDED_SWIFT_SOURCES} + GYB_SOURCES + ${SWIFT_CONCURRENCY_GYB_SOURCES} + SWIFT_COMPILE_FLAGS ${extra_swift_compile_flags} -enable-experimental-feature Embedded -parse-stdlib -DSWIFT_CONCURRENCY_EMBEDDED diff --git a/stdlib/public/Concurrency/SourceCompatibilityShims.swift b/stdlib/public/Concurrency/SourceCompatibilityShims.swift index b63e84c795131..46364319adf99 100644 --- a/stdlib/public/Concurrency/SourceCompatibilityShims.swift +++ b/stdlib/public/Concurrency/SourceCompatibilityShims.swift @@ -14,7 +14,6 @@ //===----------------------------------------------------------------------===// import Swift -import _Concurrency @available(SwiftStdlib 5.1, *) extension Task where Success == Never, Failure == Never { @@ -88,192 +87,23 @@ extension Task where Success == Never, Failure == Never { } } -//@available(SwiftStdlib 5.1, *) -//extension Task where Failure == Error { -// #if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY -// @discardableResult -// @_alwaysEmitIntoClient -// @available(*, unavailable, message: "Unavailable in task-to-thread concurrency model") -// public static func runDetached( -// priority: TaskPriority? = nil, -// operation: __owned @Sendable @escaping () async throws -> Success -// ) -> Task { -// fatalError("Unavailable in task-to-thread concurrency model") -// } -// #else -// @discardableResult -// @_alwaysEmitIntoClient -// @available(*, deprecated, message: "`Task.runDetached` was replaced by `Task.detached` and will be removed shortly.") -// public static func runDetached( -// priority: TaskPriority? = nil, -// operation: __owned @Sendable @escaping () async throws -> Success -// ) -> Task { -// detached(priority: priority, operation: operation) -// } -// #endif -//} -// -//#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY -//@discardableResult -//@available(SwiftStdlib 5.1, *) -//@available(*, unavailable, message: "Unavailable in task-to-thread concurrency model") -//@_alwaysEmitIntoClient -//public func detach( -// priority: TaskPriority? = nil, -// operation: __owned @Sendable @escaping () async -> T -//) -> Task { -// fatalError("Unavailable in task-to-thread concurrency model") -//} -//#else -//@discardableResult -//@available(SwiftStdlib 5.1, *) -//@available(*, deprecated, message: "`detach` was replaced by `Task.detached` and will be removed shortly.") -//@_alwaysEmitIntoClient -//public func detach( -// priority: TaskPriority? = nil, -// operation: __owned @Sendable @escaping () async -> T -//) -> Task { -// Task.detached(priority: priority, operation: operation) -//} -//#endif -// -//#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY -//@discardableResult -//@available(SwiftStdlib 5.1, *) -//@available(*, unavailable, message: "Unavailable in task-to-thread concurrency model") -//@_alwaysEmitIntoClient -//public func detach( -// priority: TaskPriority? = nil, -// operation: __owned @Sendable @escaping () async throws -> T -//) -> Task { -// fatalError("Unavailable in task-to-thread concurrency model") -//} -//#else -//@discardableResult -//@available(SwiftStdlib 5.1, *) -//@available(*, deprecated, message: "`detach` was replaced by `Task.detached` and will be removed shortly.") -//@_alwaysEmitIntoClient -//public func detach( -// priority: TaskPriority? = nil, -// operation: __owned @Sendable @escaping () async throws -> T -//) -> Task { -// Task.detached(priority: priority, operation: operation) -//} -//#endif -// -//#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY -//@discardableResult -//@available(SwiftStdlib 5.1, *) -//@available(*, unavailable, message: "Unavailable in task-to-thread concurrency model") -//@_alwaysEmitIntoClient -//public func asyncDetached( -// priority: TaskPriority? = nil, -// @_implicitSelfCapture operation: __owned @Sendable @escaping () async -> T -//) -> Task { -// fatalError("Unavailable in task-to-thread concurrency model") -//} -//#else -//@discardableResult -//@available(SwiftStdlib 5.1, *) -//@available(*, deprecated, message: "`asyncDetached` was replaced by `Task.detached` and will be removed shortly.") -//@_alwaysEmitIntoClient -//public func asyncDetached( -// priority: TaskPriority? = nil, -// @_implicitSelfCapture operation: __owned @Sendable @escaping () async -> T -//) -> Task { -// return Task.detached(priority: priority, operation: operation) -//} -//#endif -// -//#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY -//@discardableResult -//@available(SwiftStdlib 5.1, *) -//@available(*, unavailable, message: "Unavailable in task-to-thread concurrency model") -//@_alwaysEmitIntoClient -//public func asyncDetached( -// priority: TaskPriority? = nil, -// @_implicitSelfCapture operation: __owned @Sendable @escaping () async throws -> T -//) -> Task { -// fatalError("Unavailable in task-to-thread concurrency model") -//} -//#else -//@discardableResult -//@available(SwiftStdlib 5.1, *) -//@available(*, deprecated, message: "`asyncDetached` was replaced by `Task.detached` and will be removed shortly.") -//@_alwaysEmitIntoClient -//public func asyncDetached( -// priority: TaskPriority? = nil, -// @_implicitSelfCapture operation: __owned @Sendable @escaping () async throws -> T -//) -> Task { -// return Task.detached(priority: priority, operation: operation) -//} -//#endif -// -//#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY -//@available(SwiftStdlib 5.1, *) -//@available(*, unavailable, message: "Unavailable in task-to-thread concurrency model") -//@discardableResult -//@_alwaysEmitIntoClient -//public func async( -// priority: TaskPriority? = nil, -// @_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping () async -> T -//) -> Task { -// fatalError("Unavailable in task-to-thread concurrency model") -//} -//#else -//@available(SwiftStdlib 5.1, *) -//@available(*, deprecated, message: "`async` was replaced by `Task.init` and will be removed shortly.") -//@discardableResult -//@_alwaysEmitIntoClient -//public func async( -// priority: TaskPriority? = nil, -// @_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping () async -> T -//) -> Task { -// .init(priority: priority, operation: operation) -//} -//#endif -// -//#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY -//@available(SwiftStdlib 5.1, *) -//@available(*, unavailable, message: "Unavailable in task-to-thread concurrency model") -//@discardableResult -//@_alwaysEmitIntoClient -//public func async( -// priority: TaskPriority? = nil, -// @_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping () async throws -> T -//) -> Task { -// fatalError("Unavailable in task-to-thread concurrency model") -//} -//#else -//@available(SwiftStdlib 5.1, *) -//@available(*, deprecated, message: "`async` was replaced by `Task.init` and will be removed shortly.") -//@discardableResult -//@_alwaysEmitIntoClient -//public func async( -// priority: TaskPriority? = nil, -// @_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping () async throws -> T -//) -> Task { -// .init(priority: priority, operation: operation) -//} -//#endif -// -//@available(SwiftStdlib 5.1, *) -//extension Task where Success == Never, Failure == Never { -// @available(*, deprecated, message: "`Task.Group` was replaced by `ThrowingTaskGroup` and `TaskGroup` and will be removed shortly.") -// public typealias Group = ThrowingTaskGroup -// -// @available(*, deprecated, message: "`Task.withGroup` was replaced by `withThrowingTaskGroup` and `withTaskGroup` and will be removed shortly.") -// @_alwaysEmitIntoClient -// public static func withGroup( -// resultType: TaskResult.Type, -// returning returnType: BodyResult.Type = BodyResult.self, -// body: (inout Task.Group) async throws -> BodyResult -// ) async rethrows -> BodyResult { -// try await withThrowingTaskGroup(of: resultType) { group in -// try await body(&group) -// } -// } -//} +@available(SwiftStdlib 5.1, *) +extension Task where Success == Never, Failure == Never { + @available(*, deprecated, message: "`Task.Group` was replaced by `ThrowingTaskGroup` and `TaskGroup` and will be removed shortly.") + public typealias Group = ThrowingTaskGroup + + @available(*, deprecated, message: "`Task.withGroup` was replaced by `withThrowingTaskGroup` and `withTaskGroup` and will be removed shortly.") + @_alwaysEmitIntoClient + public static func withGroup( + resultType: TaskResult.Type, + returning returnType: BodyResult.Type = BodyResult.self, + body: (inout Task.Group) async throws -> BodyResult + ) async rethrows -> BodyResult { + try await withThrowingTaskGroup(of: resultType) { group in + try await body(&group) + } + } +} @available(SwiftStdlib 5.1, *) extension Task { diff --git a/stdlib/public/Concurrency/Task+init.swift.gyb b/stdlib/public/Concurrency/Task+init.swift.gyb index 86463b9f756dc..a26d43f0ad3d0 100644 --- a/stdlib/public/Concurrency/Task+init.swift.gyb +++ b/stdlib/public/Concurrency/Task+init.swift.gyb @@ -141,7 +141,7 @@ import Swift % IS_TOP_LEVEL_FUNC = (not ('init' in METHOD_VARIANT)) and (not ('static' in METHOD_VARIANT)) % IS_INIT = 'init' in METHOD_VARIANT -% IS_DETACHED = 'detached' in METHOD_VARIANT +% IS_DETACHED = 'detach' in METHOD_VARIANT.lower() % IS_THROWING = 'throws' in METHOD_VARIANT % % HAS_TASK_PRIORITY = any('priority:' in param for param in PARAMS) @@ -221,7 +221,11 @@ extension Task where Failure == ${FAILURE_TYPE} { let (task, _) = Builtin.createAsyncTask(flags, operation) + % if IS_INIT: self._task = task + % else: + return Task(task) + % end } % end # not HAS_TASK_EXECUTOR @@ -283,7 +287,7 @@ extension Task where Failure == ${FAILURE_TYPE} { % end # IS_DEPRECATED ${"\n ".join(adjust_availability(ALL_AVAILABILITY))} @discardableResult - public ${METHOD_VARIANT}( + public ${METHOD_VARIANT}( // Task ${METHOD_VARIANT} ${",\n ".join(adjust_params_for_kind(PARAMS))} ) ${ARROW_RETURN_TYPE}{ diff --git a/stdlib/public/Concurrency/TaskGroup+Embedded.swift b/stdlib/public/Concurrency/TaskGroup+Embedded.swift deleted file mode 100644 index 7aed41f538eb5..0000000000000 --- a/stdlib/public/Concurrency/TaskGroup+Embedded.swift +++ /dev/null @@ -1,283 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2025 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// - -import Swift - -// FIXME: This is a workaround for trouble including gyb-generated sources - -#if SWIFT_CONCURRENCY_EMBEDDED - -@available(SwiftStdlib 5.1, *) -extension TaskGroup { - - @available(SwiftStdlib 5.1, *) - @_alwaysEmitIntoClient - public mutating func addTask( - priority: TaskPriority? = nil, - operation: sending @escaping @isolated(any) () async -> ChildTaskResult - ) { - let flags = taskCreateFlags( - priority: priority, - isChildTask: true, - copyTaskLocals: false, - inheritContext: false, - enqueueJob: true, - addPendingGroupTaskUnconditionally: true, - isDiscardingTask: false, - isSynchronousStart: false - ) - - let builtinSerialExecutor = - unsafe Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor - - _ = Builtin.createTask( - flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskGroup: _group, - operation: operation).0 - } - - @available(SwiftStdlib 5.1, *) - @_alwaysEmitIntoClient - public mutating func addTaskUnlessCancelled( - priority: TaskPriority? = nil, - operation: sending @escaping @isolated(any) () async -> ChildTaskResult - ) -> Bool { - let canAdd = _taskGroupAddPendingTask(group: _group, unconditionally: false) - - guard canAdd else { - return false - } - - let flags = taskCreateFlags( - priority: priority, - isChildTask: true, - copyTaskLocals: false, - inheritContext: false, - enqueueJob: true, - addPendingGroupTaskUnconditionally: false, - isDiscardingTask: true, - isSynchronousStart: false - ) - - let builtinSerialExecutor = - unsafe Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor - - _ = Builtin.createTask( - flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskGroup: _group, - operation: operation).0 - - return true - } -} - -@available(SwiftStdlib 5.1, *) -extension ThrowingTaskGroup { - - @available(SwiftStdlib 5.1, *) - @_alwaysEmitIntoClient - public mutating func addTask( - priority: TaskPriority? = nil, - operation: sending @escaping @isolated(any) () async throws -> ChildTaskResult - ) { - let flags = taskCreateFlags( - priority: priority, - isChildTask: true, - copyTaskLocals: false, - inheritContext: false, - enqueueJob: true, - addPendingGroupTaskUnconditionally: true, - isDiscardingTask: false, - isSynchronousStart: false - ) - - let builtinSerialExecutor = - unsafe Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor - - _ = Builtin.createTask( - flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskGroup: _group, - operation: operation).0 - } - - @available(SwiftStdlib 5.1, *) - @_alwaysEmitIntoClient - public mutating func addTaskUnlessCancelled( - priority: TaskPriority? = nil, - operation: sending @escaping @isolated(any) () async throws -> ChildTaskResult - ) -> Bool { - let canAdd = _taskGroupAddPendingTask(group: _group, unconditionally: false) - - guard canAdd else { - return false - } - - let flags = taskCreateFlags( - priority: priority, - isChildTask: true, - copyTaskLocals: false, - inheritContext: false, - enqueueJob: true, - addPendingGroupTaskUnconditionally: false, - isDiscardingTask: true, - isSynchronousStart: false - ) - - let builtinSerialExecutor = - unsafe Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor - - _ = Builtin.createTask( - flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskGroup: _group, - operation: operation).0 - - return true - } -} - -@available(SwiftStdlib 5.9, *) -extension DiscardingTaskGroup { - - @available(SwiftStdlib 5.9, *) - @_alwaysEmitIntoClient - public mutating func addTask( - priority: TaskPriority? = nil, - operation: sending @escaping @isolated(any) () async -> Void - ) { - let flags = taskCreateFlags( - priority: priority, - isChildTask: true, - copyTaskLocals: false, - inheritContext: false, - enqueueJob: true, - addPendingGroupTaskUnconditionally: true, - isDiscardingTask: true, - isSynchronousStart: false - ) - - let builtinSerialExecutor = - unsafe Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor - - _ = Builtin.createTask( - flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskGroup: _group, - operation: operation).0 - } - - @available(SwiftStdlib 5.9, *) - @_alwaysEmitIntoClient - public mutating func addTaskUnlessCancelled( - priority: TaskPriority? = nil, - operation: sending @escaping @isolated(any) () async -> Void - ) -> Bool { - let canAdd = _taskGroupAddPendingTask(group: _group, unconditionally: false) - - guard canAdd else { - return false - } - - let flags = taskCreateFlags( - priority: priority, - isChildTask: true, - copyTaskLocals: false, - inheritContext: false, - enqueueJob: true, - addPendingGroupTaskUnconditionally: false, - isDiscardingTask: true, - isSynchronousStart: false - ) - - let builtinSerialExecutor = - unsafe Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor - - _ = Builtin.createTask( - flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskGroup: _group, - operation: operation).0 - - return true - } -} - -@available(SwiftStdlib 5.9, *) -extension ThrowingDiscardingTaskGroup { - - @available(SwiftStdlib 5.9, *) - @_alwaysEmitIntoClient - public mutating func addTask( - priority: TaskPriority? = nil, - operation: sending @escaping @isolated(any) () async throws -> Void - ) { - let flags = taskCreateFlags( - priority: priority, - isChildTask: true, - copyTaskLocals: false, - inheritContext: false, - enqueueJob: true, - addPendingGroupTaskUnconditionally: true, - isDiscardingTask: true, - isSynchronousStart: false - ) - - let builtinSerialExecutor = - unsafe Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor - - _ = Builtin.createTask( - flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskGroup: _group, - operation: operation).0 - } - - @available(SwiftStdlib 5.9, *) - @_alwaysEmitIntoClient - public mutating func addTaskUnlessCancelled( - priority: TaskPriority? = nil, - operation: sending @escaping @isolated(any) () async throws -> Void - ) -> Bool { - let canAdd = _taskGroupAddPendingTask(group: _group, unconditionally: false) - - guard canAdd else { - return false - } - - let flags = taskCreateFlags( - priority: priority, - isChildTask: true, - copyTaskLocals: false, - inheritContext: false, - enqueueJob: true, - addPendingGroupTaskUnconditionally: false, - isDiscardingTask: true, - isSynchronousStart: false - ) - - let builtinSerialExecutor = - unsafe Builtin.extractFunctionIsolation(operation)?.unownedExecutor.executor - - _ = Builtin.createTask( - flags: flags, - initialSerialExecutor: builtinSerialExecutor, - taskGroup: _group, - operation: operation).0 - - return true - } -} - -#endif