Skip to content

Commit ca2599d

Browse files
committed
[sending] Mark Task.init,detached, and friends as sending methods instead of __owned @sendable so we can capture non-isolated values.
1 parent 852f05e commit ca2599d

11 files changed

+293
-158
lines changed

stdlib/public/Concurrency/Task.swift

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,7 @@ extension Task where Failure == Never {
608608
@available(*, unavailable, message: "Unavailable in task-to-thread concurrency model")
609609
public init(
610610
priority: TaskPriority? = nil,
611-
@_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping @isolated(any) () async -> Success
611+
@_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async -> Success
612612
) {
613613
fatalError("Unavailable in task-to-thread concurrency model.")
614614
}
@@ -617,7 +617,7 @@ extension Task where Failure == Never {
617617
@_alwaysEmitIntoClient
618618
public init(
619619
priority: TaskPriority? = nil,
620-
@_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping () async -> Success
620+
@_inheritActorContext @_implicitSelfCapture operation: sending @escaping () async -> Success
621621
) {
622622
#if compiler(>=5.5) && $BuiltinCreateAsyncTaskInGroup
623623
// Set up the job flags for a new task.
@@ -664,7 +664,7 @@ extension Task where Failure == Never {
664664
@_allowFeatureSuppression(IsolatedAny)
665665
public init(
666666
priority: TaskPriority? = nil,
667-
@_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping @isolated(any) () async -> Success
667+
@_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async -> Success
668668
) {
669669
#if compiler(>=5.5) && $BuiltinCreateAsyncTaskInGroup
670670
// Set up the job flags for a new task.
@@ -704,7 +704,7 @@ extension Task where Failure == Error {
704704
@available(*, unavailable, message: "Unavailable in task-to-thread concurrency model")
705705
public init(
706706
priority: TaskPriority? = nil,
707-
@_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping @isolated(any) () async throws -> Success
707+
@_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async throws -> Success
708708
) {
709709
fatalError("Unavailable in task-to-thread concurrency model")
710710
}
@@ -713,7 +713,7 @@ extension Task where Failure == Error {
713713
@_alwaysEmitIntoClient
714714
public init(
715715
priority: TaskPriority? = nil,
716-
@_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping () async throws -> Success
716+
@_inheritActorContext @_implicitSelfCapture operation: sending @escaping () async throws -> Success
717717
) {
718718
#if compiler(>=5.5) && $BuiltinCreateAsyncTaskInGroup
719719
// Set up the task flags for a new task.
@@ -760,7 +760,7 @@ extension Task where Failure == Error {
760760
@_allowFeatureSuppression(IsolatedAny)
761761
public init(
762762
priority: TaskPriority? = nil,
763-
@_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping @isolated(any) () async throws -> Success
763+
@_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async throws -> Success
764764
) {
765765
#if compiler(>=5.5) && $BuiltinCreateAsyncTaskInGroup
766766
// Set up the task flags for a new task.
@@ -802,7 +802,7 @@ extension Task where Failure == Never {
802802
@available(*, unavailable, message: "Unavailable in task-to-thread concurrency model")
803803
public static func detached(
804804
priority: TaskPriority? = nil,
805-
operation: __owned @Sendable @escaping @isolated(any) () async -> Success
805+
operation: sending @escaping @isolated(any) () async -> Success
806806
) -> Task<Success, Failure> {
807807
fatalError("Unavailable in task-to-thread concurrency model")
808808
}
@@ -811,7 +811,7 @@ extension Task where Failure == Never {
811811
@_alwaysEmitIntoClient
812812
public static func detached(
813813
priority: TaskPriority? = nil,
814-
operation: __owned @Sendable @escaping () async -> Success
814+
operation: sending @escaping () async -> Success
815815
) -> Task<Success, Failure> {
816816
#if compiler(>=5.5) && $BuiltinCreateAsyncTaskInGroup
817817
// Set up the job flags for a new task.
@@ -855,7 +855,7 @@ extension Task where Failure == Never {
855855
@_allowFeatureSuppression(IsolatedAny)
856856
public static func detached(
857857
priority: TaskPriority? = nil,
858-
operation: __owned @Sendable @escaping @isolated(any) () async -> Success
858+
operation: sending @escaping @isolated(any) () async -> Success
859859
) -> Task<Success, Failure> {
860860
#if compiler(>=5.5) && $BuiltinCreateAsyncTaskInGroup
861861
// Set up the job flags for a new task.
@@ -895,7 +895,7 @@ extension Task where Failure == Error {
895895
@available(*, unavailable, message: "Unavailable in task-to-thread concurrency model")
896896
public static func detached(
897897
priority: TaskPriority? = nil,
898-
operation: __owned @Sendable @escaping @isolated(any) () async throws -> Success
898+
operation: sending @escaping @isolated(any) () async throws -> Success
899899
) -> Task<Success, Failure> {
900900
fatalError("Unavailable in task-to-thread concurrency model")
901901
}
@@ -904,7 +904,7 @@ extension Task where Failure == Error {
904904
@_alwaysEmitIntoClient
905905
public static func detached(
906906
priority: TaskPriority? = nil,
907-
operation: __owned @Sendable @escaping () async throws -> Success
907+
operation: sending @escaping () async throws -> Success
908908
) -> Task<Success, Failure> {
909909
#if compiler(>=5.5) && $BuiltinCreateAsyncTaskInGroup
910910
// Set up the job flags for a new task.
@@ -950,7 +950,7 @@ extension Task where Failure == Error {
950950
@_allowFeatureSuppression(IsolatedAny)
951951
public static func detached(
952952
priority: TaskPriority? = nil,
953-
operation: __owned @Sendable @escaping @isolated(any) () async throws -> Success
953+
operation: sending @escaping @isolated(any) () async throws -> Success
954954
) -> Task<Success, Failure> {
955955
#if compiler(>=5.5) && $BuiltinCreateAsyncTaskInGroup
956956
// Set up the job flags for a new task.
@@ -1353,7 +1353,7 @@ extension Task where Failure == Error {
13531353
@available(SwiftStdlib 5.1, *)
13541354
@_alwaysEmitIntoClient
13551355
@usableFromInline
1356-
internal func _runTaskForBridgedAsyncMethod(@_inheritActorContext _ body: __owned @Sendable @escaping () async -> Void) {
1356+
internal func _runTaskForBridgedAsyncMethod(@_inheritActorContext _ body: sending @escaping () async -> Void) {
13571357
#if compiler(>=5.6)
13581358
Task(operation: body)
13591359
#else

test/Concurrency/actor_isolation.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
// RUN: %target-swift-frontend -emit-module -emit-module-path %t/GlobalVariables.swiftmodule -module-name GlobalVariables %S/Inputs/GlobalVariables.swift -disable-availability-checking -parse-as-library
55

66
// RUN: %target-swift-frontend -I %t -disable-availability-checking -strict-concurrency=complete -parse-as-library -emit-sil -o /dev/null -verify -enable-upcoming-feature GlobalActorIsolatedTypesUsability %s
7-
// RUN: %target-swift-frontend -I %t -disable-availability-checking -strict-concurrency=complete -parse-as-library -emit-sil -o /dev/null -verify -enable-upcoming-feature RegionBasedIsolation -enable-upcoming-feature GlobalActorIsolatedTypesUsability %s
87

98
// REQUIRES: concurrency
109
// REQUIRES: asserts
@@ -1305,11 +1304,11 @@ actor Counter {
13051304
class C2 { }
13061305

13071306
@SomeGlobalActor
1308-
class C3: C2 { // expected-note {{class 'C3' does not conform to the 'Sendable' protocol}}
1307+
class C3: C2 {
13091308
func requireSendableSelf() {
1309+
// self is Sendable here.
13101310
Task.detached {
13111311
_ = self
1312-
// expected-warning@-1 {{capture of 'self' with non-sendable type 'C3' in a `@Sendable` closure; this is an error in the Swift 6 language mode}}
13131312
}
13141313
}
13151314
}
@@ -1538,8 +1537,10 @@ extension MyActor {
15381537
_ = self
15391538
_ = sc
15401539

1540+
// A test that validates that we treat this as a true send was added
1541+
// into transfernonsendable.swift.
15411542
Task {
1542-
_ = sc // expected-warning{{capture of 'sc' with non-sendable type 'SomeClass' in a `@Sendable` closure}}
1543+
_ = sc
15431544
}
15441545
}
15451546
}

test/Concurrency/async_tasks.swift

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
// RUN: %target-swift-frontend -strict-concurrency=targeted -disable-availability-checking %s -o /dev/null -verify -emit-sil
2-
// RUN: %target-swift-frontend -strict-concurrency=strict -disable-availability-checking %s -o /dev/null -verify -emit-sil
3-
// RUN: %target-swift-frontend -strict-concurrency=strict -disable-availability-checking %s -o /dev/null -verify -emit-sil -enable-upcoming-feature RegionBasedIsolation
1+
// RUN: %target-swift-frontend -strict-concurrency=targeted -disable-availability-checking %s -o /dev/null -verify -emit-sil -DALLOW_TYPECHECKER_ERRORS -verify-additional-prefix typechecker-
2+
// RUN: %target-swift-frontend -strict-concurrency=complete -disable-availability-checking %s -o /dev/null -verify -emit-sil -DALLOW_TYPECHECKER_ERRORS -verify-additional-prefix typechecker-
3+
// RUN: %target-swift-frontend -strict-concurrency=complete -disable-availability-checking %s -o /dev/null -verify -emit-sil -verify-additional-prefix tns-
44

55
// REQUIRES: concurrency
66
// REQUIRES: asserts
@@ -51,21 +51,25 @@ func buyVegetables(shoppingList: [String]) async throws -> [Vegetable] {
5151
func test_unsafeContinuations() async {
5252
// the closure should not allow async operations;
5353
// after all: if you have async code, just call it directly, without the unsafe continuation
54-
let _: String = withUnsafeContinuation { continuation in // expected-error{{cannot pass function of type '(UnsafeContinuation<String, Never>) async -> Void' to parameter expecting synchronous function type}}
55-
let s = await someAsyncFunc() // expected-note {{'async' inferred from asynchronous operation used here}}
54+
#if ALLOW_TYPECHECKER_ERRORS
55+
let _: String = withUnsafeContinuation { continuation in // expected-typechecker-error{{cannot pass function of type '(UnsafeContinuation<String, Never>) async -> Void' to parameter expecting synchronous function type}}
56+
let s = await someAsyncFunc() // expected-typechecker-note {{'async' inferred from asynchronous operation used here}}
5657
continuation.resume(returning: s)
5758
}
59+
#endif
5860

5961
let _: String = await withUnsafeContinuation { continuation in
6062
continuation.resume(returning: "")
6163
}
6264

6365
// rdar://76475495 - suppress warnings for invalid expressions
66+
#if ALLOW_TYPECHECKER_ERRORS
6467
func test_invalid_async_no_warnings() async -> Int {
6568
return await withUnsafeContinuation {
66-
$0.resume(throwing: 1) // expected-error {{cannot convert value of type 'Int' to expected argument type 'Never'}}
69+
$0.resume(throwing: 1) // expected-typechecker-error {{cannot convert value of type 'Int' to expected argument type 'Never'}}
6770
}
6871
}
72+
#endif
6973
}
7074

7175
@available(SwiftStdlib 5.1, *)
@@ -130,13 +134,15 @@ func test_detached_throwing() async -> String {
130134
} catch {
131135
print("caught: \(error)")
132136
}
137+
138+
return ""
133139
}
134140

135141
// ==== Detached Tasks with inout Params---------------------------------------
136142
@available(SwiftStdlib 5.1, *)
137-
func printOrderNumber(n: inout Int) async {
138-
Task.detached {
139-
n+=1 //expected-error {{mutable capture of 'inout' parameter 'n' is not allowed in concurrently-executing code}}
140-
print(n) //expected-error {{mutable capture of 'inout' parameter 'n' is not allowed in concurrently-executing code}}
143+
func printOrderNumber(n: inout Int) async { // expected-tns-note {{parameter 'n' is declared 'inout'}}
144+
Task.detached { // expected-tns-error {{escaping closure captures 'inout' parameter 'n'}}
145+
n+=1 // expected-tns-note {{captured here}}
146+
print(n) // expected-tns-note {{captured here}}
141147
}
142148
}

test/Concurrency/builtin_silgen.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ func suspend() async {}
1010
// Builtin.hopToActor should generate a mandatory hop_to_executor
1111
// before releasing the actor and reaching a suspend.
1212
//
13-
// CHECK-LABEL: sil private @$s14builtin_silgen11runDetachedyyFyyYaYbcfU_ : $@convention(thin) @Sendable @async @substituted <τ_0_0> (@guaranteed Optional<any Actor>) -> @out τ_0_0 for <()>
13+
// CHECK-LABEL: sil private @$s14builtin_silgen11runDetachedyyFyyYacfU_ : $@convention(thin) @async @substituted <τ_0_0> (@guaranteed Optional<any Actor>) -> @out τ_0_0 for <()> {
1414
// CHECK: [[ACTOR:%.*]] = apply {{%.*}}({{%.*}}) : $@convention(method) (@thick MainActor.Type) -> @owned MainActor
1515
// CHECK: hop_to_executor [mandatory] [[ACTOR]] : $MainActor
1616
// CHECK: strong_release [[ACTOR]] : $MainActor

0 commit comments

Comments
 (0)