Skip to content

Commit 9d2f528

Browse files
authored
Merge pull request #85518 from DougGregor/task-cancellation-rethrows-nonisolated-nonsending
[Concurrency] Adopt typed throws and nonisolated(nonsending) in withTaskCancellationHandler
2 parents a8ef103 + 9504056 commit 9d2f528

File tree

5 files changed

+38
-11
lines changed

5 files changed

+38
-11
lines changed

stdlib/public/Concurrency/TaskCancellation.swift

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,28 @@ import Swift
7474
/// Therefore, if a cancellation handler must acquire a lock, other code should
7575
/// not cancel tasks or resume continuations while holding that lock.
7676
@available(SwiftStdlib 5.1, *)
77+
@_alwaysEmitIntoClient
78+
nonisolated(nonsending)
79+
public func withTaskCancellationHandler<Return, Failure>(
80+
operation: nonisolated(nonsending) () async throws(Failure) -> Return,
81+
onCancel handler: sending () -> Void
82+
) async throws(Failure) -> Return {
83+
// unconditionally add the cancellation record to the task.
84+
// if the task was already cancelled, it will be executed right away.
85+
let record = unsafe Builtin.taskAddCancellationHandler(handler: handler)
86+
defer { unsafe Builtin.taskRemoveCancellationHandler(record: record) }
87+
return try await operation()
88+
}
89+
7790
#if !$Embedded
78-
@backDeployed(before: SwiftStdlib 6.0)
79-
#endif
80-
public func withTaskCancellationHandler<T>(
91+
@available(SwiftStdlib 6.0, *)
92+
@usableFromInline
93+
@abi(func withTaskCancellationHandler<T>(
94+
operation: () async throws -> T,
95+
onCancel handler: @Sendable () -> Void,
96+
isolation: isolated (any Actor)?,
97+
) async rethrows -> T)
98+
func __abi_withTaskCancellationHandler<T>(
8199
operation: () async throws -> T,
82100
onCancel handler: @Sendable () -> Void,
83101
isolation: isolated (any Actor)? = #isolation
@@ -93,6 +111,7 @@ public func withTaskCancellationHandler<T>(
93111
#endif
94112
return try await operation()
95113
}
114+
#endif
96115

97116
// Note: hack to stage out @_unsafeInheritExecutor forms of various functions
98117
// in favor of #isolation. The _unsafeInheritExecutor_ prefix is meaningful

stdlib/public/Observation/Sources/Observation/Observations.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ public struct Observations<Element: Sendable, Failure: Error>: AsyncSequence, Se
240240
}, onCancel: {
241241
// ensure to clean out our continuation uon cancellation
242242
State.cancel(state, id: id)
243-
}, isolation: iterationIsolation)
243+
})
244244
return try await trackEmission(isolation: iterationIsolation, state: state, id: id)
245245
}
246246
} catch {

test/Concurrency/actor_withCancellationHandler.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ actor Container {
3838
num += 1 // no error, this runs synchronously on caller context
3939
} onCancel: {
4040
// this should error because cancellation is invoked concurrently
41-
num += 10 // expected-error{{actor-isolated property 'num' can not be mutated from a Sendable closure}}
41+
num += 10 // expected-error{{actor-isolated property 'num' can not be mutated from a nonisolated context}}
4242
}
4343
}
4444
}

test/Concurrency/async_cancellation.swift

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,23 @@ struct SomeFile: Sendable {
2828
func close() {}
2929
}
3030

31+
enum HomeworkError: Error {
32+
case dogAteIt
33+
}
34+
3135
@available(SwiftStdlib 5.1, *)
3236
func test_cancellation_withTaskCancellationHandler(_ anything: Any) async -> PictureData? {
3337
let handle: Task<PictureData, Error> = .init {
3438
let file = SomeFile()
3539

36-
return await withTaskCancellationHandler {
37-
await test_cancellation_guard_isCancelled(file)
38-
} onCancel: {
39-
file.close()
40+
do throws(HomeworkError) {
41+
return try await withTaskCancellationHandler { () throws(HomeworkError) in
42+
await test_cancellation_guard_isCancelled(file)
43+
} onCancel: {
44+
file.close()
45+
}
46+
} catch .dogAteIt {
47+
return PictureData.value("...")
4048
}
4149
}
4250

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,8 @@ Func withCheckedThrowingContinuation(function:_:) has parameter 0 type change fr
8989
Func withCheckedThrowingContinuation(function:_:) has parameter 1 type change from (_Concurrency.CheckedContinuation<τ_0_0, any Swift.Error>) -> () to Swift.String
9090

9191
// #isolation adoption for cancellation handlers; old APIs are kept ABI compatible
92-
Func withTaskCancellationHandler(operation:onCancel:) has been renamed to Func withTaskCancellationHandler(operation:onCancel:isolation:)
93-
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'
92+
Func withTaskCancellationHandler(operation:onCancel:) has been renamed to Func __abi_withTaskCancellationHandler(operation:onCancel:isolation:)
93+
Func withTaskCancellationHandler(operation:onCancel:) has mangled name changing from '_Concurrency.withTaskCancellationHandler<A>(operation: () async throws -> A, onCancel: @Sendable () -> ()) async throws -> A' to '_Concurrency.__abi_withTaskCancellationHandler<A>(operation: () async throws -> A, onCancel: @Sendable () -> (), isolation: isolated Swift.Optional<Swift.Actor>) async throws -> A'
9494

9595
// #isolated was adopted and the old methods kept: $ss31withCheckedThrowingContinuation8function_xSS_yScCyxs5Error_pGXEtYaKlF
9696
Func withCheckedContinuation(function:_:) has been renamed to Func withCheckedContinuation(isolation:function:_:)

0 commit comments

Comments
 (0)