Skip to content

Commit 8bc5373

Browse files
authored
Merge pull request #73568 from ktoso/wip-fix-last-_unsafeInheritExecutor-usage
[Concurrency] Remove last usages of @_unsafeInheritExecutor
2 parents 78b0fd7 + c413893 commit 8bc5373

12 files changed

+234
-35
lines changed

stdlib/public/Concurrency/Clock.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ extension Clock {
7777
}
7878

7979
@available(SwiftStdlib 5.7, *)
80-
@_unsafeInheritExecutor
80+
@_unsafeInheritExecutor // for ABI compatibility
8181
@usableFromInline
8282
internal func measure(
8383
_ work: () async throws -> Void

stdlib/public/Concurrency/DiscardingTaskGroup.swift

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,37 @@ import Swift
6868
///
6969
/// - SeeAlso: ``withThrowingDiscardingTaskGroup(returning:body:)
7070
@available(SwiftStdlib 5.9, *)
71+
@backDeployed(before: SwiftStdlib 6.0)
7172
@inlinable
72-
@_unsafeInheritExecutor
7373
public func withDiscardingTaskGroup<GroupResult>(
74+
returning returnType: GroupResult.Type = GroupResult.self,
75+
isolation: isolated (any Actor)? = #isolation,
76+
body: (inout DiscardingTaskGroup) async -> GroupResult
77+
) async -> GroupResult {
78+
#if compiler(>=5.5) && $BuiltinCreateTaskGroupWithFlags
79+
let flags = taskGroupCreateFlags(
80+
discardResults: true
81+
)
82+
83+
let _group = Builtin.createTaskGroupWithFlags(flags, GroupResult.self)
84+
var group = DiscardingTaskGroup(group: _group)
85+
defer { Builtin.destroyTaskGroup(_group) }
86+
87+
let result = await body(&group)
88+
89+
try! await group.awaitAllRemainingTasks() // try!-safe, cannot throw since this is a non throwing group
90+
91+
return result
92+
#else
93+
fatalError("Swift compiler is incompatible with this SDK version")
94+
#endif
95+
}
96+
97+
@available(SwiftStdlib 5.9, *)
98+
@usableFromInline
99+
@_unsafeInheritExecutor // for ABI compatibility
100+
@_silgen_name("$ss23withDiscardingTaskGroup9returning4bodyxxm_xs0bcD0VzYaXEtYalF")
101+
internal func __abi_withDiscardingTaskGroup<GroupResult>(
74102
returning returnType: GroupResult.Type = GroupResult.self,
75103
body: (inout DiscardingTaskGroup) async -> GroupResult
76104
) async -> GroupResult {
@@ -709,9 +737,46 @@ extension DiscardingTaskGroup: Sendable { }
709737
/// }
710738
/// ```
711739
@available(SwiftStdlib 5.9, *)
740+
@backDeployed(before: SwiftStdlib 6.0)
712741
@inlinable
713-
@_unsafeInheritExecutor
714742
public func withThrowingDiscardingTaskGroup<GroupResult>(
743+
returning returnType: GroupResult.Type = GroupResult.self,
744+
isolation: isolated (any Actor)? = #isolation,
745+
body: (inout ThrowingDiscardingTaskGroup<Error>) async throws -> GroupResult
746+
) async throws -> GroupResult {
747+
#if compiler(>=5.5) && $BuiltinCreateTaskGroupWithFlags
748+
let flags = taskGroupCreateFlags(
749+
discardResults: true
750+
)
751+
752+
let _group = Builtin.createTaskGroupWithFlags(flags, GroupResult.self)
753+
var group = ThrowingDiscardingTaskGroup<Error>(group: _group)
754+
defer { Builtin.destroyTaskGroup(_group) }
755+
756+
let result: GroupResult
757+
do {
758+
result = try await body(&group)
759+
} catch {
760+
group.cancelAll()
761+
762+
try await group.awaitAllRemainingTasks(bodyError: error)
763+
764+
throw error
765+
}
766+
767+
try await group.awaitAllRemainingTasks(bodyError: nil)
768+
769+
return result
770+
#else
771+
fatalError("Swift compiler is incompatible with this SDK version")
772+
#endif
773+
}
774+
775+
@available(SwiftStdlib 5.9, *)
776+
@usableFromInline
777+
@_unsafeInheritExecutor // for ABI compatibility
778+
@_silgen_name("$ss31withThrowingDiscardingTaskGroup9returning4bodyxxm_xs0bcdE0Vys5Error_pGzYaKXEtYaKlF")
779+
internal func __abi_withThrowingDiscardingTaskGroup<GroupResult>(
715780
returning returnType: GroupResult.Type = GroupResult.self,
716781
body: (inout ThrowingDiscardingTaskGroup<Error>) async throws -> GroupResult
717782
) async throws -> GroupResult {

stdlib/public/Concurrency/Task+TaskExecutor.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ public func withTaskExecutorPreference<T, Failure>(
161161

162162
@_unavailableInEmbedded
163163
@available(SwiftStdlib 6.0, *)
164-
@_unsafeInheritExecutor // calling withTaskExecutor MUST NOT perform the "usual" hop to global
164+
@_unsafeInheritExecutor // for ABI compatibility
165165
@_silgen_name("$ss26withTaskExecutorPreference_9operationxSch_pSg_xyYaYbKXEtYaKs8SendableRzlF")
166166
public func __abi__withTaskExecutorPreference<T: Sendable>(
167167
_ taskExecutor: (any TaskExecutor)?,

stdlib/public/Concurrency/TaskCancellation.swift

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,26 @@ import Swift
6767
/// as resuming a continuation, may acquire these same internal locks.
6868
/// Therefore, if a cancellation handler must acquire a lock, other code should
6969
/// not cancel tasks or resume continuations while holding that lock.
70-
@_unsafeInheritExecutor // the operation runs on the same executor as we start out with
7170
@available(SwiftStdlib 5.1, *)
72-
@backDeployed(before: SwiftStdlib 5.8)
71+
@backDeployed(before: SwiftStdlib 6.0)
7372
public func withTaskCancellationHandler<T>(
73+
operation: () async throws -> T,
74+
onCancel handler: @Sendable () -> Void,
75+
isolation: isolated (any Actor)? = #isolation
76+
) async rethrows -> T {
77+
// unconditionally add the cancellation record to the task.
78+
// if the task was already cancelled, it will be executed right away.
79+
let record = _taskAddCancellationHandler(handler: handler)
80+
defer { _taskRemoveCancellationHandler(record: record) }
81+
82+
return try await operation()
83+
}
84+
85+
@_unsafeInheritExecutor // ABI compatibility with Swift 5.1
86+
@available(SwiftStdlib 5.1, *)
87+
@usableFromInline
88+
@_silgen_name("$ss27withTaskCancellationHandler9operation8onCancelxxyYaKXE_yyYbXEtYaKlF")
89+
internal func __abi_withTaskCancellationHandler<T>(
7490
operation: () async throws -> T,
7591
onCancel handler: @Sendable () -> Void
7692
) async rethrows -> T {

stdlib/public/Concurrency/TaskGroup.swift

Lines changed: 66 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,36 @@ import Swift
6363
/// such as returning the work completed so far, returning an empty result, or returning `nil`.
6464
/// For tasks that need to handle cancellation by throwing an error,
6565
/// use the `withThrowingTaskGroup(of:returning:body:)` method instead.
66+
@available(SwiftStdlib 5.1, *)
67+
@backDeployed(before: SwiftStdlib 6.0, *)
68+
@inlinable
69+
public func withTaskGroup<ChildTaskResult, GroupResult>(
70+
of childTaskResultType: ChildTaskResult.Type,
71+
returning returnType: GroupResult.Type = GroupResult.self,
72+
isolation: isolated (any Actor)? = #isolation,
73+
body: (inout TaskGroup<ChildTaskResult>) async -> GroupResult
74+
) async -> GroupResult {
75+
#if compiler(>=5.5) && $BuiltinTaskGroupWithArgument
76+
77+
let _group = Builtin.createTaskGroup(ChildTaskResult.self)
78+
var group = TaskGroup<ChildTaskResult>(group: _group)
79+
80+
// Run the withTaskGroup body.
81+
let result = await body(&group)
82+
83+
await group.awaitAllRemainingTasks()
84+
85+
Builtin.destroyTaskGroup(_group)
86+
return result
87+
88+
#else
89+
fatalError("Swift compiler is incompatible with this SDK version")
90+
#endif
91+
}
92+
6693
@available(SwiftStdlib 5.1, *)
6794
@_silgen_name("$ss13withTaskGroup2of9returning4bodyq_xm_q_mq_ScGyxGzYaXEtYar0_lF")
68-
@_unsafeInheritExecutor
95+
@_unsafeInheritExecutor // for ABI compatibility
6996
@inlinable
7097
public func withTaskGroup<ChildTaskResult, GroupResult>(
7198
of childTaskResultType: ChildTaskResult.Type,
@@ -80,7 +107,6 @@ public func withTaskGroup<ChildTaskResult, GroupResult>(
80107
// Run the withTaskGroup body.
81108
let result = await body(&group)
82109

83-
// TODO(concurrency): should get isolation from param from withThrowingTaskGroup
84110
await group.awaitAllRemainingTasks()
85111

86112
Builtin.destroyTaskGroup(_group)
@@ -167,10 +193,46 @@ public func withTaskGroup<ChildTaskResult, GroupResult>(
167193
/// which gives you a chance to handle the individual error
168194
/// or to let the group rethrow the error.
169195
@available(SwiftStdlib 5.1, *)
170-
@_silgen_name("$ss21withThrowingTaskGroup2of9returning4bodyq_xm_q_mq_Scgyxs5Error_pGzYaKXEtYaKr0_lF")
171-
@_unsafeInheritExecutor
196+
@backDeployed(before: SwiftStdlib 6.0)
172197
@inlinable
173198
public func withThrowingTaskGroup<ChildTaskResult, GroupResult>(
199+
of childTaskResultType: ChildTaskResult.Type,
200+
returning returnType: GroupResult.Type = GroupResult.self,
201+
isolation: isolated (any Actor)? = #isolation,
202+
body: (inout ThrowingTaskGroup<ChildTaskResult, Error>) async throws -> GroupResult
203+
) async rethrows -> GroupResult {
204+
#if compiler(>=5.5) && $BuiltinTaskGroupWithArgument
205+
206+
let _group = Builtin.createTaskGroup(ChildTaskResult.self)
207+
var group = ThrowingTaskGroup<ChildTaskResult, Error>(group: _group)
208+
209+
do {
210+
// Run the withTaskGroup body.
211+
let result = try await body(&group)
212+
213+
await group.awaitAllRemainingTasks()
214+
Builtin.destroyTaskGroup(_group)
215+
216+
return result
217+
} catch {
218+
group.cancelAll()
219+
220+
await group.awaitAllRemainingTasks()
221+
Builtin.destroyTaskGroup(_group)
222+
223+
throw error
224+
}
225+
226+
#else
227+
fatalError("Swift compiler is incompatible with this SDK version")
228+
#endif
229+
}
230+
231+
@available(SwiftStdlib 5.1, *)
232+
@_silgen_name("$ss21withThrowingTaskGroup2of9returning4bodyq_xm_q_mq_Scgyxs5Error_pGzYaKXEtYaKr0_lF")
233+
@_unsafeInheritExecutor // for ABI compatibility
234+
@usableFromInline
235+
internal func withThrowingTaskGroup<ChildTaskResult, GroupResult>(
174236
of childTaskResultType: ChildTaskResult.Type,
175237
returning returnType: GroupResult.Type = GroupResult.self,
176238
body: (inout ThrowingTaskGroup<ChildTaskResult, Error>) async throws -> GroupResult
@@ -184,15 +246,13 @@ public func withThrowingTaskGroup<ChildTaskResult, GroupResult>(
184246
// Run the withTaskGroup body.
185247
let result = try await body(&group)
186248

187-
// TODO(concurrency): should get isolation from param from withThrowingTaskGroup
188249
await group.awaitAllRemainingTasks()
189250
Builtin.destroyTaskGroup(_group)
190251

191252
return result
192253
} catch {
193254
group.cancelAll()
194255

195-
// TODO(concurrency): should get isolation from param from withThrowingTaskGroup
196256
await group.awaitAllRemainingTasks()
197257
Builtin.destroyTaskGroup(_group)
198258

stdlib/public/Concurrency/TaskLocal.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ public final class TaskLocal<Value: Sendable>: Sendable, CustomStringConvertible
260260

261261
@inlinable
262262
@discardableResult
263-
@_unsafeInheritExecutor
263+
@_unsafeInheritExecutor // internal for backwards compatibility; though may be able to be removed safely?
264264
@available(SwiftStdlib 5.1, *)
265265
@backDeployed(before: SwiftStdlib 5.9)
266266
internal func withValueImpl<R>(_ valueDuringOperation: __owned Value,

test/Concurrency/actor_withCancellationHandler.swift

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
// REQUIRES: concurrency
88
// REQUIRES: asserts
99

10-
actor foo {
10+
actor Foo {
1111
var t: Task<Void, Error>?
1212

1313
func access() {}
@@ -22,3 +22,25 @@ actor foo {
2222
}
2323
}
2424
}
25+
26+
actor Container {
27+
var num: Int = 0 // expected-note{{mutation of this property is only permitted within the actor}}
28+
func test() async {
29+
30+
// no warnings:
31+
await withTaskCancellationHandler {
32+
num += 1
33+
} onCancel: {
34+
// nothing
35+
}
36+
}
37+
38+
func errors() async {
39+
await withTaskCancellationHandler {
40+
num += 1 // no error, this runs synchronously on caller context
41+
} onCancel: {
42+
// this should error because cancellation is invoked concurrently
43+
num += 10 // expected-error{{actor-isolated property 'num' can not be mutated from a Sendable closure}}
44+
}
45+
}
46+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// RUN: %target-swift-frontend -emit-sil -verify -o /dev/null -disable-availability-checking %s -swift-version 6 -strict-concurrency=complete
2+
3+
// REQUIRES: concurrency
4+
// REQUIRES: asserts
5+
6+
actor A {
7+
func g() { }
8+
func h() throws { }
9+
10+
func f() async throws {
11+
await withTaskGroup(of: Int.self, returning: Void.self) { group in
12+
self.g()
13+
}
14+
15+
try await withThrowingTaskGroup(of: String.self, returning: Void.self) { group in
16+
try self.h()
17+
}
18+
19+
await withDiscardingTaskGroup(returning: Void.self) { group in
20+
self.g()
21+
}
22+
23+
try await withThrowingDiscardingTaskGroup(returning: Void.self) { group in
24+
try self.h()
25+
}
26+
}
27+
}

test/Concurrency/unsafe_inherit_executor_lib.swift

Lines changed: 0 additions & 19 deletions
This file was deleted.

test/abi/macOS/arm64/concurrency.swift

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,19 @@ Added: _$sScf13checkIsolatedyyFTj
316316
// method descriptor for Swift.SerialExecutor.checkIsolated() -> ()
317317
Added: _$sScf13checkIsolatedyyFTq
318318

319-
// #isolated adoption in TaskLocal.withValue
319+
// #isolated adoption in multiple APIs
320+
// withTaskCancellationHandler gains #isolated
321+
Added: _$ss27withTaskCancellationHandler9operation8onCancel9isolationxxyYaKXE_yyYbXEScA_pSgYitYaKlF
322+
Added: _$ss27withTaskCancellationHandler9operation8onCancel9isolationxxyYaKXE_yyYbXEScA_pSgYitYaKlFTu
323+
// TaskGroup.with... APIs gain #isolated
324+
Added: _$ss23withDiscardingTaskGroup9returning9isolation4bodyxxm_ScA_pSgYixs0bcD0VzYaXEtYalF
325+
Added: _$ss23withDiscardingTaskGroup9returning9isolation4bodyxxm_ScA_pSgYixs0bcD0VzYaXEtYalFTu
326+
Added: _$ss13withTaskGroup2of9returning9isolation4bodyq_xm_q_mScA_pSgYiq_ScGyxGzYaXEtYas8SendableRzr0_lF
327+
Added: _$ss13withTaskGroup2of9returning9isolation4bodyq_xm_q_mScA_pSgYiq_ScGyxGzYaXEtYas8SendableRzr0_lFTu
328+
Added: _$ss31withThrowingDiscardingTaskGroup9returning9isolation4bodyxxm_ScA_pSgYixs0bcdE0Vys5Error_pGzYaKXEtYaKlF
329+
Added: _$ss31withThrowingDiscardingTaskGroup9returning9isolation4bodyxxm_ScA_pSgYixs0bcdE0Vys5Error_pGzYaKXEtYaKlFTu
330+
Added: _$ss21withThrowingTaskGroup2of9returning9isolation4bodyq_xm_q_mScA_pSgYiq_Scgyxs5Error_pGzYaKXEtYaKs8SendableRzr0_lF
331+
Added: _$ss21withThrowingTaskGroup2of9returning9isolation4bodyq_xm_q_mScA_pSgYiq_Scgyxs5Error_pGzYaKXEtYaKs8SendableRzr0_lFTu
320332
// Swift.TaskLocal.withValueImpl<A>(_: __owned A, operation: () async throws -> A1, isolation: isolated Swift.Actor?, file: Swift.String, line: Swift.UInt) async throws -> A1
321333
Added: _$ss9TaskLocalC13withValueImpl_9operation9isolation4file4lineqd__xn_qd__yYaKXEScA_pSgYiSSSutYaKlF
322334
Added: _$ss9TaskLocalC13withValueImpl_9operation9isolation4file4lineqd__xn_qd__yYaKXEScA_pSgYiSSSutYaKlFTu

test/abi/macOS/x86_64/concurrency.swift

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,19 @@ Added: _$sScf13checkIsolatedyyFTj
316316
// method descriptor for Swift.SerialExecutor.checkIsolated() -> ()
317317
Added: _$sScf13checkIsolatedyyFTq
318318

319-
// #isolated adoption in TaskLocal.withValue
319+
// #isolated adoption in multiple APis
320+
// withTaskCancellationHandler gains #isolated
321+
Added: _$ss27withTaskCancellationHandler9operation8onCancel9isolationxxyYaKXE_yyYbXEScA_pSgYitYaKlF
322+
Added: _$ss27withTaskCancellationHandler9operation8onCancel9isolationxxyYaKXE_yyYbXEScA_pSgYitYaKlFTu
323+
// TaskGroup.with... APIs gain #isolated
324+
Added: _$ss23withDiscardingTaskGroup9returning9isolation4bodyxxm_ScA_pSgYixs0bcD0VzYaXEtYalF
325+
Added: _$ss23withDiscardingTaskGroup9returning9isolation4bodyxxm_ScA_pSgYixs0bcD0VzYaXEtYalFTu
326+
Added: _$ss13withTaskGroup2of9returning9isolation4bodyq_xm_q_mScA_pSgYiq_ScGyxGzYaXEtYas8SendableRzr0_lF
327+
Added: _$ss13withTaskGroup2of9returning9isolation4bodyq_xm_q_mScA_pSgYiq_ScGyxGzYaXEtYas8SendableRzr0_lFTu
328+
Added: _$ss31withThrowingDiscardingTaskGroup9returning9isolation4bodyxxm_ScA_pSgYixs0bcdE0Vys5Error_pGzYaKXEtYaKlF
329+
Added: _$ss31withThrowingDiscardingTaskGroup9returning9isolation4bodyxxm_ScA_pSgYixs0bcdE0Vys5Error_pGzYaKXEtYaKlFTu
330+
Added: _$ss21withThrowingTaskGroup2of9returning9isolation4bodyq_xm_q_mScA_pSgYiq_Scgyxs5Error_pGzYaKXEtYaKs8SendableRzr0_lF
331+
Added: _$ss21withThrowingTaskGroup2of9returning9isolation4bodyq_xm_q_mScA_pSgYiq_Scgyxs5Error_pGzYaKXEtYaKs8SendableRzr0_lFTu
320332
// Swift.TaskLocal.withValueImpl<A>(_: __owned A, operation: () async throws -> A1, isolation: isolated Swift.Actor?, file: Swift.String, line: Swift.UInt) async throws -> A1
321333
Added: _$ss9TaskLocalC13withValueImpl_9operation9isolation4file4lineqd__xn_qd__yYaKXEScA_pSgYiSSSutYaKlF
322334
Added: _$ss9TaskLocalC13withValueImpl_9operation9isolation4file4lineqd__xn_qd__yYaKXEScA_pSgYiSSSutYaKlFTu

test/api-digester/stability-concurrency-abi.test

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ Func withCheckedThrowingContinuation(function:_:) has mangled name changing from
8585
Func withCheckedThrowingContinuation(function:_:) has parameter 0 type change from Swift.String to (any _Concurrency.Actor)?
8686
Func withCheckedThrowingContinuation(function:_:) has parameter 1 type change from (_Concurrency.CheckedContinuation<τ_0_0, any Swift.Error>) -> () to Swift.String
8787

88+
// #isolation adoption for cancellation handlers; old APIs are kept ABI compatible
89+
Func withTaskCancellationHandler(operation:onCancel:) has been renamed to Func withTaskCancellationHandler(operation:onCancel:isolation:)
90+
Func withTaskCancellationHandler(operation:onCancel:) has mangled name changing from '_Concurrency.withTaskCancellationHandler<A>(operation: () async throws -> A, onCancel: @Sendable () -> ()) async throws -> A' to '_Concurrency.withTaskCancellationHandler<A>(operation: () async throws -> A, onCancel: @Sendable () -> (), isolation: isolated Swift.Optional<Swift.Actor>) async throws -> A'
91+
8892
// #isolated was adopted and the old methods kept: $ss31withCheckedThrowingContinuation8function_xSS_yScCyxs5Error_pGXEtYaKlF
8993
Func withCheckedContinuation(function:_:) has been renamed to Func withCheckedContinuation(isolation:function:_:)
9094
Func withCheckedContinuation(function:_:) has mangled name changing from '_Concurrency.withCheckedContinuation<A>(function: Swift.String, _: (Swift.CheckedContinuation<A, Swift.Never>) -> ()) async -> A' to '_Concurrency.withCheckedContinuation<A>(isolation: isolated Swift.Optional<Swift.Actor>, function: Swift.String, _: (Swift.CheckedContinuation<A, Swift.Never>) -> ()) async -> A'

0 commit comments

Comments
 (0)