Skip to content

Commit d32c027

Browse files
authored
Merge pull request #62239 from ktoso/wip-withLocal-warnings
[Concurrency] TaskLocal.withValue closure should produce no warnings inside Actor
2 parents 8fc94b8 + f9c2bc0 commit d32c027

File tree

4 files changed

+58
-0
lines changed

4 files changed

+58
-0
lines changed

stdlib/public/BackDeployConcurrency/TaskLocal.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ public final class TaskLocal<Value: Sendable>: Sendable, CustomStringConvertible
102102
self.defaultValue = defaultValue
103103
}
104104

105+
@_alwaysEmitIntoClient
105106
var key: Builtin.RawPointer {
106107
unsafeBitCast(self, to: Builtin.RawPointer.self)
107108
}
@@ -135,6 +136,10 @@ public final class TaskLocal<Value: Sendable>: Sendable, CustomStringConvertible
135136
/// If the value is a reference type, it will be retained for the duration of
136137
/// the operation closure.
137138
@discardableResult
139+
@inlinable
140+
@_unsafeInheritExecutor
141+
@available(SwiftStdlib 5.1, *) // back deploy requires we declare the availability explicitly on this method
142+
@_backDeploy(before: SwiftStdlib 5.8)
138143
public func withValue<R>(_ valueDuringOperation: Value, operation: () async throws -> R,
139144
file: String = #file, line: UInt = #line) async rethrows -> R {
140145
// check if we're not trying to bind a value from an illegal context; this may crash
@@ -159,6 +164,7 @@ public final class TaskLocal<Value: Sendable>: Sendable, CustomStringConvertible
159164
///
160165
/// If the value is a reference type, it will be retained for the duration of
161166
/// the operation closure.
167+
@inlinable
162168
@discardableResult
163169
public func withValue<R>(_ valueDuringOperation: Value, operation: () throws -> R,
164170
file: String = #file, line: UInt = #line) rethrows -> R {
@@ -212,13 +218,15 @@ public final class TaskLocal<Value: Sendable>: Sendable, CustomStringConvertible
212218
// ==== ------------------------------------------------------------------------
213219

214220
@available(SwiftStdlib 5.1, *)
221+
@usableFromInline
215222
@_silgen_name("swift_task_localValuePush")
216223
func _taskLocalValuePush<Value>(
217224
key: Builtin.RawPointer/*: Key*/,
218225
value: __owned Value
219226
) // where Key: TaskLocal
220227

221228
@available(SwiftStdlib 5.1, *)
229+
@usableFromInline
222230
@_silgen_name("swift_task_localValuePop")
223231
func _taskLocalValuePop()
224232

stdlib/public/Concurrency/TaskLocal.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ public final class TaskLocal<Value: Sendable>: Sendable, CustomStringConvertible
102102
self.defaultValue = defaultValue
103103
}
104104

105+
@_alwaysEmitIntoClient
105106
var key: Builtin.RawPointer {
106107
unsafeBitCast(self, to: Builtin.RawPointer.self)
107108
}
@@ -134,7 +135,11 @@ public final class TaskLocal<Value: Sendable>: Sendable, CustomStringConvertible
134135
///
135136
/// If the value is a reference type, it will be retained for the duration of
136137
/// the operation closure.
138+
@inlinable
137139
@discardableResult
140+
@_unsafeInheritExecutor
141+
@available(SwiftStdlib 5.1, *) // back deploy requires we declare the availability explicitly on this method
142+
@_backDeploy(before: SwiftStdlib 5.8)
138143
public func withValue<R>(_ valueDuringOperation: Value, operation: () async throws -> R,
139144
file: String = #fileID, line: UInt = #line) async rethrows -> R {
140145
// check if we're not trying to bind a value from an illegal context; this may crash
@@ -159,6 +164,7 @@ public final class TaskLocal<Value: Sendable>: Sendable, CustomStringConvertible
159164
///
160165
/// If the value is a reference type, it will be retained for the duration of
161166
/// the operation closure.
167+
@inlinable
162168
@discardableResult
163169
public func withValue<R>(_ valueDuringOperation: Value, operation: () throws -> R,
164170
file: String = #fileID, line: UInt = #line) rethrows -> R {
@@ -212,13 +218,15 @@ public final class TaskLocal<Value: Sendable>: Sendable, CustomStringConvertible
212218
// ==== ------------------------------------------------------------------------
213219

214220
@available(SwiftStdlib 5.1, *)
221+
@usableFromInline
215222
@_silgen_name("swift_task_localValuePush")
216223
func _taskLocalValuePush<Value>(
217224
key: Builtin.RawPointer/*: Key*/,
218225
value: __owned Value
219226
) // where Key: TaskLocal
220227

221228
@available(SwiftStdlib 5.1, *)
229+
@usableFromInline
222230
@_silgen_name("swift_task_localValuePop")
223231
func _taskLocalValuePop()
224232

test/Concurrency/Runtime/async_task_locals_basic.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,24 @@ func withLocal_body_mustNotEscape() async {
199199
_ = something // silence not used warning
200200
}
201201

202+
@available(SwiftStdlib 5.1, *)
203+
actor Worker {
204+
@TaskLocal
205+
static var declaredInActor: String = "<default-value>"
206+
207+
func setAndRead() async {
208+
print("setAndRead") // CHECK: setAndRead
209+
await Worker.$declaredInActor.withValue("value-1") {
210+
await printTaskLocalAsync(Worker.$declaredInActor) // CHECK-NEXT: TaskLocal<String>(defaultValue: <default-value>) (value-1)
211+
}
212+
}
213+
}
214+
215+
@available(SwiftStdlib 5.1, *)
216+
func inside_actor() async {
217+
await Worker().setAndRead()
218+
}
219+
202220
@available(SwiftStdlib 5.1, *)
203221
@main struct Main {
204222
static func main() async {
@@ -210,5 +228,6 @@ func withLocal_body_mustNotEscape() async {
210228
await nested_3_onlyTopContributes()
211229
await nested_3_onlyTopContributesAsync()
212230
await nested_3_onlyTopContributesMixed()
231+
await inside_actor()
213232
}
214233
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -emit-module -emit-module-path %t/OtherActors.swiftmodule -module-name OtherActors %S/Inputs/OtherActors.swift -disable-availability-checking
3+
// RUN: %target-typecheck-verify-swift -I %t -disable-availability-checking -warn-concurrency -parse-as-library
4+
// REQUIRES: concurrency
5+
6+
// REQUIRES: concurrency
7+
8+
@available(SwiftStdlib 5.1, *)
9+
actor Test {
10+
11+
@TaskLocal static var local: Int?
12+
13+
func run() async {
14+
// This should NOT produce any warnings, the closure withValue uses is @Sendable:
15+
await Test.$local.withValue(42) {
16+
await work()
17+
}
18+
}
19+
20+
func work() async {
21+
print("Hello \(Test.local ?? 0)")
22+
}
23+
}

0 commit comments

Comments
 (0)