Skip to content

Commit 6b80399

Browse files
authored
Merge pull request swiftlang#36034 from ktoso/wip-fix-withLocal-non-escape
2 parents 5e9d4d8 + fc1da16 commit 6b80399

File tree

2 files changed

+28
-32
lines changed

2 files changed

+28
-32
lines changed

stdlib/public/Concurrency/TaskLocal.swift

Lines changed: 6 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -89,48 +89,22 @@ extension Task {
8989
///
9090
/// - Parameters:
9191
/// - keyPath: key path to the `TaskLocalKey` to be used for lookup
92-
/// - value:
93-
/// - body:
92+
/// - value: value to bind the task local to for the scope of `operation`
93+
/// - operation: the operation to run with the task local value bound
9494
/// - Returns: the value returned by the `body` function.
9595
public static func withLocal<Key, BodyResult>(
9696
_ keyPath: KeyPath<TaskLocalValues, Key>,
9797
boundTo value: Key.Value,
98-
body: @escaping () async -> BodyResult
99-
) async -> BodyResult where Key: TaskLocalKey {
98+
operation: () async throws -> BodyResult
99+
) async rethrows -> BodyResult where Key: TaskLocalKey {
100100
let task = Builtin.getCurrentAsyncTask()
101101

102102
_taskLocalValuePush(task, keyType: Key.self, value: value)
103-
104-
defer {
105-
_taskLocalValuePop(task)
106-
}
103+
defer { _taskLocalValuePop(task) }
107104

108-
return await body()
105+
return try await operation()
109106
}
110107

111-
/// Bind the task local key to the given value for the scope of the `body` function.
112-
/// Any child tasks spawned within this scope will inherit the binding.
113-
///
114-
/// - Parameters:
115-
/// - key:
116-
/// - value:
117-
/// - body:
118-
/// - Returns: the value returned by the `body` function, or throws.
119-
public static func withLocal<Key, BodyResult>(
120-
_ keyPath: KeyPath<TaskLocalValues, Key>,
121-
boundTo value: Key.Value,
122-
body: @escaping () async throws -> BodyResult
123-
) async throws -> BodyResult where Key: TaskLocalKey {
124-
let task = Builtin.getCurrentAsyncTask()
125-
126-
_taskLocalValuePush(task, keyType: Key.self, value: value)
127-
128-
defer {
129-
_taskLocalValuePop(task)
130-
}
131-
132-
return try! await body()
133-
}
134108
}
135109

136110
// ==== ------------------------------------------------------------------------

test/Concurrency/Runtime/task_locals_basic.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,20 @@ func simple_deinit() async {
7979
try! await printTaskLocal(\.clazz) // CHECK: ClazzKey: nil {{.*}}
8080
}
8181

82+
struct Boom: Error {
83+
let value: String
84+
}
85+
func simple_throw() async {
86+
do {
87+
try await Task.withLocal(\.clazz, boundTo: ClassTaskLocal()) {
88+
throw Boom(value: "oh no!")
89+
}
90+
} catch {
91+
//CHECK: error: Boom(value: "oh no!")
92+
print("error: \(error)")
93+
}
94+
}
95+
8296
func nested() async {
8397
try! await printTaskLocal(\.string) // CHECK: StringKey: <undefined> {{.*}}
8498
await Task.withLocal(\.string, boundTo: "hello") {
@@ -127,10 +141,18 @@ func nested_3_onlyTopContributes() async {
127141
try! await printTaskLocal(\.string) // CHECK-NEXT: StringKey: <undefined> {{.*}}
128142
}
129143

144+
func withLocal_body_mustNotEscape() async {
145+
var something = "Nice"
146+
await Task.withLocal(\.string, boundTo: "xxx") {
147+
something = "very nice"
148+
}
149+
}
150+
130151
@main struct Main {
131152
static func main() async {
132153
await simple()
133154
await simple_deinit()
155+
await simple_throw()
134156
await nested()
135157
await nested_allContribute()
136158
await nested_3_onlyTopContributes()

0 commit comments

Comments
 (0)