Files
swift-mirror/test/Concurrency/transfernonsendable_sending_params.swift
Michael Gottesman 13e8eed3a8 [rbi] Cleanup handling of how we send parameters to fix issues with inout sending.
We previously were not "unsending" inout sending parameters after sending them
so they could not be used again in the caller and could not be forwarded into
other 'inout sending' parameters. While looking at the code I
realized it was pretty obtuse/confusing so I cleaned up the logic and fixed a
few other issues in the process.

Now we follow the following pattern in the non-isolation crossing case:

1. We first require the callee operand.
2. We then merge/require all of the non-explicitly sent parameters.
3. We then through all of the parameters and require/send all of the sending parameters.
4. At the end of processing, we unsend all of the sending parameters that were
'inout sending' parameters.

In the case of isolation crossing applies we:

1. Require all parameters that are not explicitly marked as sending and then
send them all at once. We are really just saving a little work by not merging
them into one large region and then requiring/sending that region once.

2. Then for each sending parameter, we require/send them one by one interleaving
the requires/sends. This ensures that if a value is passed to different
explicitly sending parameters, we get an error.

3. Then once we have finished processing results, we perform an undo send on all
of the 'inout sending' params.

rdar://154440896
2025-10-10 15:58:11 -07:00

623 lines
25 KiB
Swift

// RUN: %target-swift-frontend -emit-sil -parse-as-library -target %target-swift-5.1-abi-triple -strict-concurrency=complete -verify -verify-additional-prefix ni- %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability
// RUN: %target-swift-frontend -emit-sil -parse-as-library -target %target-swift-5.1-abi-triple -strict-concurrency=complete -verify -verify-additional-prefix ni-ns- %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability -enable-upcoming-feature NonisolatedNonsendingByDefault
// REQUIRES: concurrency
// REQUIRES: swift_feature_GlobalActorIsolatedTypesUsability
// REQUIRES: swift_feature_NonisolatedNonsendingByDefault
////////////////////////
// MARK: Declarations //
////////////////////////
class NonSendableKlass {
func use() {}
}
struct NonSendableStruct {
var first = NonSendableKlass()
var second = NonSendableKlass()
}
class KlassWithNonSendableStructPair {
var ns1: NonSendableStruct
var ns2: (NonSendableStruct, NonSendableStruct)
init() {
ns1 = NonSendableStruct()
ns2 = (ns1, ns1)
}
}
final class FinalKlassWithNonSendableStructPair {
var ns1: NonSendableStruct
var ns2: (NonSendableStruct, NonSendableStruct)
init() {
ns1 = NonSendableStruct()
ns2 = (ns1, ns1)
}
}
func useValue<T>(_ t: T) {}
func useValueAndReturnGeneric<T>(_ t: T) -> T { t }
func useNonSendableKlassAndReturn(_ t: NonSendableKlass) -> NonSendableKlass { t }
func getAny() -> Any { fatalError() }
actor Custom {
}
@globalActor
struct CustomActor {
static var shared: Custom {
return Custom()
}
}
@MainActor func transferToMain<T>(_ t: T) {}
@CustomActor func transferToCustom<T>(_ t: T) {}
func throwingFunction() throws { fatalError() }
func getBool() -> Bool { false }
func transferArg(_ x: sending NonSendableKlass) {
}
func transferArgAsync(_ x: sending NonSendableKlass) async {
}
func transferArgWithOtherParam(_ x: sending NonSendableKlass, _ y: NonSendableKlass) {
}
@MainActor
func transferArgWithOtherParamIsolationCrossing(_ x: sending NonSendableKlass, _ y: NonSendableKlass) async {
}
func transferArgWithOtherParam2(_ x: NonSendableKlass, _ y: sending NonSendableKlass) {
}
@MainActor
func transferArgWithOtherParam2IsolationCrossing(_ x: NonSendableKlass, _ y: sending NonSendableKlass) async {
}
func twoTransferArg(_ x: sending NonSendableKlass, _ y: sending NonSendableKlass) {}
@MainActor
func twoTransferArgIsolationCrossing(_ x: sending NonSendableKlass, _ y: sending NonSendableKlass) async {}
@MainActor var globalKlass = NonSendableKlass()
struct MyError : Error {}
func takeClosure(_ x: sending () -> ()) {}
func takeClosureAndParam(_ x: NonSendableKlass, _ y: sending () -> ()) {}
/////////////////
// MARK: Tests //
/////////////////
func testSimpleTransferLet() {
let k = NonSendableKlass()
transferArg(k) // expected-warning {{sending 'k' risks causing data races}}
// expected-note @-1 {{'k' used after being passed as a 'sending' parameter}}
useValue(k) // expected-note {{access can happen concurrently}}
}
func testSimpleTransferVar() {
var k = NonSendableKlass()
k = NonSendableKlass()
transferArg(k) // expected-warning {{sending 'k' risks causing data races}}
// expected-note @-1 {{'k' used after being passed as a 'sending' parameter}}
useValue(k) // expected-note {{access can happen concurrently}}
}
func testSimpleTransferUseOfOtherParamNoError() {
let k = NonSendableKlass()
let k2 = NonSendableKlass()
transferArgWithOtherParam(k, k2)
useValue(k2)
}
func testSimpleTransferUseOfOtherParamNoError2() {
let k = NonSendableKlass()
let k2 = NonSendableKlass()
transferArgWithOtherParam2(k, k2)
useValue(k)
}
func testSimpleTransferUseOfOtherParamError() async {
let k = NonSendableKlass()
await transferArgWithOtherParamIsolationCrossing(k, k) // expected-warning {{sending 'k' risks causing data races}}
// expected-note @-1 {{sending 'k' to main actor-isolated global function 'transferArgWithOtherParamIsolationCrossing' risks causing data races between main actor-isolated and local nonisolated uses}}
// expected-note @-2 {{access can happen concurrently}}
}
// TODO: Improve this error message. We should say that we are emitting an
// error. Also need to add SILLocation to ApplyInst.
func testSimpleTransferUseOfOtherParam2Error() async {
let k = NonSendableKlass()
await transferArgWithOtherParam2IsolationCrossing(k, k) // expected-warning {{sending 'k' risks causing data races}}
// expected-note @-1 {{sending 'k' to main actor-isolated global function 'transferArgWithOtherParam2IsolationCrossing' risks causing data races between main actor-isolated and local nonisolated uses}}
// expected-note @-2 {{access can happen concurrently}}
}
@MainActor func transferToMain2(_ x: sending NonSendableKlass, _ y: NonSendableKlass, _ z: NonSendableKlass) async {
}
// TODO: How to test this?
func testNonStrongTransferDoesntMerge() async {
}
//////////////////////////////////
// MARK: Transferring Parameter //
//////////////////////////////////
func testTransferringParameter_canTransfer(_ x: sending NonSendableKlass, _ y: NonSendableKlass) async {
await transferToMain(x)
await transferToMain(y) // expected-warning {{sending 'y' risks causing data races}}
// expected-note @-1 {{sending task-isolated 'y' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and task-isolated uses}}
}
func testTransferringParameter_cannotTransferTwice(_ x: sending NonSendableKlass, _ y: NonSendableKlass) async {
await transferToMain(x) // expected-warning {{sending 'x' risks causing data races}}
// expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
// TODO: We should not error on this since we are sending to the same place.
await transferToMain(x) // expected-note {{access can happen concurrently}}
}
func testTransferringParameter_cannotUseAfterTransfer(_ x: sending NonSendableKlass, _ y: NonSendableKlass) async {
await transferToMain(x) // expected-warning {{sending 'x' risks causing data races}}
// expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
useValue(x) // expected-note {{access can happen concurrently}}
}
actor MyActor {
var field = NonSendableKlass()
func canTransferWithTransferringMethodArg(_ x: sending NonSendableKlass, _ y: NonSendableKlass) async {
await transferToMain(x)
await transferToMain(y) // expected-warning {{sending 'y' risks causing data races}}
// expected-note @-1 {{sending 'self'-isolated 'y' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and 'self'-isolated uses}}
}
func getNormalErrorIfTransferTwice(_ x: sending NonSendableKlass) async {
await transferToMain(x) // expected-warning {{sending 'x' risks causing data races}}
// expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local actor-isolated uses}}
await transferToMain(x) // expected-note {{access can happen concurrently}}
}
func getNormalErrorIfUseAfterTransfer(_ x: sending NonSendableKlass) async {
await transferToMain(x) // expected-warning {{sending 'x' risks causing data races}}
// expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local actor-isolated uses}}
useValue(x) // expected-note {{access can happen concurrently}}
}
// After assigning into the actor, we can still use x in the actor as long as
// we don't transfer it.
func assignTransferringIntoActor(_ x: sending NonSendableKlass) async {
field = x
useValue(x)
}
// Once we assign into the actor, we cannot transfer further.
func assignTransferringIntoActor2(_ x: sending NonSendableKlass) async {
field = x
await transferToMain(x) // expected-warning {{sending 'x' risks causing data races}}
// expected-note @-1 {{sending 'self'-isolated 'x' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and 'self'-isolated uses}}
}
}
@MainActor func canAssignTransferringIntoGlobalActor(_ x: sending NonSendableKlass) async {
globalKlass = x
}
@MainActor func canAssignTransferringIntoGlobalActor2(_ x: sending NonSendableKlass) async {
globalKlass = x
// TODO: This is incorrect! sending should be independent of @MainActor.
await transferToCustom(x) // expected-warning {{sending 'x' risks causing data races}}
// expected-note @-1 {{sending main actor-isolated 'x' to global actor 'CustomActor'-isolated global function 'transferToCustom' risks causing data races between global actor 'CustomActor'-isolated and main actor-isolated uses}}
}
@MainActor func canAssignTransferringIntoGlobalActor3(_ x: sending NonSendableKlass) async {
await transferToCustom(globalKlass) // expected-warning {{sending value of non-Sendable type 'NonSendableKlass' risks causing data races}}
// expected-note @-1 {{sending main actor-isolated value of non-Sendable type 'NonSendableKlass' to global actor 'CustomActor'-isolated global function 'transferToCustom' risks causing races in between main actor-isolated and global actor 'CustomActor'-isolated uses}}
}
func canTransferAssigningIntoLocal(_ x: sending NonSendableKlass) async {
let _ = x
await transferToMain(x)
}
func canTransferAssigningIntoLocal2(_ x: sending NonSendableKlass) async {
let _ = x
await transferToMain(x)
// We do not error here since we just load the value and do not do anything
// with it.
//
// TODO: We should change let _ = x so that it has a move_value '_' or
// something like that. It will also help move checking as well.
let _ = x
}
func canTransferAssigningIntoLocal2a(_ x: sending NonSendableKlass) async {
let _ = x
await transferToMain(x)
// We do not error here since we just load the value and do not do anything
// with it.
//
// TODO: We should change let _ = x so that it has a move_value '_' or
// something like that. It will also help move checking as well.
_ = x
}
func canTransferAssigningIntoLocal3(_ x: sending NonSendableKlass) async {
let _ = x
await transferToMain(x) // expected-warning {{sending 'x' risks causing data races}}
// expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
let y = x // expected-note {{access can happen concurrently}}
_ = y
}
//////////////////////////////////////
// MARK: Transferring is "var" like //
//////////////////////////////////////
// Assigning into a 'sending' parameter is a merge.
func assigningIsAMerge(_ x: sending NonSendableKlass) async {
let y = NonSendableKlass()
x = y
// We can still transfer y since x is disconnected.
await transferToMain(y)
}
func assigningIsAMergeError(_ x: sending NonSendableKlass) async {
let y = NonSendableKlass()
x = y
// We can still transfer y since x is disconnected.
await transferToMain(y) // expected-warning {{sending 'y' risks causing data races}}
// expected-note @-1 {{sending 'y' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
useValue(x) // expected-note {{access can happen concurrently}}
}
func assigningIsAMergeAny(_ x: sending Any) async {
// Ok, this is disconnected.
let y = getAny()
x = y
await transferToMain(y)
}
func assigningIsAMergeAnyError(_ x: sending Any) async {
// Ok, this is disconnected.
let y = getAny()
x = y
await transferToMain(y) // expected-warning {{sending 'y' risks causing data races}}
// expected-note @-1 {{sending 'y' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
useValue(x) // expected-note {{access can happen concurrently}}
}
func canTransferAfterAssign(_ x: sending Any) async {
// Ok, this is disconnected.
let y = getAny()
// y is transferred into x.
await transferToMain(x)
x = y
useValue(x)
}
func canTransferAfterAssignButUseIsError(_ x: sending Any) async {
// Ok, this is disconnected.
let y = getAny()
// y is transferred into x.
x = y
// TODO: This should refer to the sending parameter.
await transferToMain(x) // expected-warning {{sending 'x' risks causing data races}}
// expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
useValue(x) // expected-note {{access can happen concurrently}}
}
func assignToEntireValueEliminatesEarlierTransfer(_ x: sending Any) async {
// Ok, this is disconnected.
let y = getAny()
useValue(x)
// Transfer x
await transferToMain(x)
// y is transferred into x. This shouldn't error.
x = y
useValue(x)
}
func mergeDoesNotEliminateEarlierTransfer(_ x: sending NonSendableStruct) async {
// Ok, this is disconnected.
let y = NonSendableKlass()
useValue(x)
// Transfer x
await transferToMain(x) // expected-warning {{sending 'x' risks causing data races}}
// expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
// y is assigned into a field of x.
x.first = y // expected-note {{access can happen concurrently}}
useValue(x)
}
func mergeDoesNotEliminateEarlierTransfer2(_ x: sending NonSendableStruct) async {
// Ok, this is disconnected.
let y = NonSendableKlass()
useValue(x)
// Transfer x
await transferToMain(x) // expected-warning {{sending 'x' risks causing data races}}
// expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
x.first = y // expected-note {{access can happen concurrently}}
}
func doubleArgument() async {
let x = NonSendableKlass()
twoTransferArg(x, x) // expected-warning {{sending 'x' risks causing data races}}
// expected-note @-1 {{'x' used after being passed as a 'sending' parameter}}
// expected-note @-2 {{access can happen concurrently}}
}
func doubleArgumentIsolationCrossing() async {
let x = NonSendableKlass()
await twoTransferArgIsolationCrossing(x, x) // expected-warning {{sending 'x' risks causing data races}}
// expected-note @-1 {{'x' used after being passed as a 'sending' parameter}}
// expected-note @-2 {{access can happen concurrently}}
}
func testTransferSrc(_ x: sending NonSendableKlass) async {
let y = NonSendableKlass()
await transferToMain(y) // expected-warning {{sending 'y' risks causing data races}}
// expected-note @-1 {{sending 'y' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
x = y // expected-note {{access can happen concurrently}}
}
func testTransferOtherParam(_ x: sending NonSendableKlass, y: NonSendableKlass) async {
x = y
}
func testTransferOtherParamTuple(_ x: sending NonSendableKlass, y: (NonSendableKlass, NonSendableKlass)) async {
x = y.0
}
func fakeInitOutside(operation: sending @escaping () async -> ()) {}
func taskIsolatedOutsideError(_ x: @escaping @MainActor () async -> ()) {
fakeInitOutside(operation: x) // okay; x is @Sendable
}
@MainActor func actorIsolatedOutsideError(_ x: @escaping @MainActor () async -> ()) {
fakeInitOutside(operation: x) // okay; x is @Sendable
}
func taskIsolatedInsideError(_ x: @escaping @MainActor () async -> ()) {
func fakeInit(operation: sending @escaping () async -> ()) {}
fakeInit(operation: x) // okay; x is @Sendable
}
@MainActor func actorIsolatedInsideError(_ x: @escaping @MainActor () async -> ()) {
func fakeInit(operation: sending @escaping () async -> ()) {}
// We do not get an error here since fakeInit is MainActor isolated since it
// is defined within this function. As a result, we are sending a @MainActor
// isolated thing to a MainActor-isolated thing.
fakeInit(operation: x)
}
// Make sure we error here on only the second since x by being assigned a part
// of y becomes task-isolated
func testMergeWithTaskIsolated(_ x: sending NonSendableKlass, y: NonSendableKlass) async {
await transferToMain(x)
x = y
await transferToMain(x) // expected-warning {{sending 'x' risks causing data races}}
// expected-note @-1 {{sending task-isolated 'x' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and task-isolated uses}}
}
@MainActor func testMergeWithActorIsolated(_ x: sending NonSendableKlass, y: NonSendableKlass) async {
x = y
await transferToCustom(x) // expected-warning {{sending 'x' risks causing data races}}
// expected-note @-1 {{sending main actor-isolated 'x' to global actor 'CustomActor'-isolated global function 'transferToCustom' risks causing data races between global actor 'CustomActor'-isolated and main actor-isolated uses}}
}
@available(SwiftStdlib 5.1, *)
actor NonSendableInit {
var first: NonSendableKlass
var second: NonSendableKlass? = nil {
@storageRestrictions(initializes: first)
init(initialValue) {
transferArg(initialValue!) // expected-warning {{sending 'initialValue' risks causing data races}}
// expected-note @-1 {{'self'-isolated 'initialValue' is passed as a 'sending' parameter}}
first = initialValue!
}
get { fatalError() }
set { fatalError() }
}
}
func testNoCrashWhenSendingNoEscapeClosure() async {
func test(_ x: sending () -> ()) async {}
let c = NonSendableKlass()
await test { print(c) }
}
//////////////////////
// MARK: Misc Tests //
//////////////////////
func taskIsolatedCaptureInSendingClosureLiteral(_ x: NonSendableKlass) {
Task { // expected-warning {{passing closure as a 'sending' parameter risks causing data races between code in the current task and concurrent execution of the closure}}
print(x) // expected-note {{closure captures 'x' which is accessible to code in the current task}}
}
Task { // expected-warning {{passing closure as a 'sending' parameter risks causing data races between code in the current task and concurrent execution of the closure}}
{
print(x) // expected-note {{closure captures 'x' which is accessible to code in the current task}}
}()
}
Task { // expected-warning {{passing closure as a 'sending' parameter risks causing data races between code in the current task and concurrent execution of the closure}}
{ // expected-note {{closure captures 'x' which is accessible to code in the current task}}
print($0)
}(x)
}
takeClosure { // expected-warning {{passing closure as a 'sending' parameter risks causing data races between code in the current task and concurrent execution of the closure}}
print(x) // expected-note {{closure captures 'x' which is accessible to code in the current task}}
}
takeClosureAndParam(NonSendableKlass()) { // expected-warning {{passing closure as a 'sending' parameter risks causing data races between code in the current task and concurrent execution of the closure}}
print(x) // expected-note {{closure captures 'x' which is accessible to code in the current task}}
}
let y = (x, x)
Task { // expected-warning {{passing closure as a 'sending' parameter risks causing data races between code in the current task and concurrent execution of the closure}}
print(y) // expected-note {{closure captures 'y' which is accessible to code in the current task}}
}
let z = (x, y)
Task { // expected-warning {{passing closure as a 'sending' parameter risks causing data races between code in the current task and concurrent execution of the closure}}
print(y, z) // expected-note @:11 {{closure captures non-Sendable 'y'}}
// expected-note @-1:14 {{closure captures non-Sendable 'z'}}
}
}
extension MyActor {
func actorIsolatedCaptureInSendingClosureLiteral(_ x: NonSendableKlass) {
Task { // expected-warning {{passing closure as a 'sending' parameter risks causing data races between 'self'-isolated code and concurrent execution of the closure}}
print(x) // expected-note {{closure captures 'self'-isolated 'x'}}
}
takeClosure { // expected-warning {{passing closure as a 'sending' parameter risks causing data races between 'self'-isolated code and concurrent execution of the closure}}
print(x) // expected-note {{closure captures 'self'-isolated 'x'}}
}
takeClosureAndParam(NonSendableKlass()) { // expected-warning {{passing closure as a 'sending' parameter risks causing data races between 'self'-isolated code and concurrent execution of the closure}}
print(x) // expected-note {{closure captures 'self'-isolated 'x'}}
}
let y = (x, x)
Task { // expected-warning {{passing closure as a 'sending' parameter risks causing data races between 'self'-isolated code and concurrent execution of the closure}}
print(y) // expected-note {{closure captures 'y' which is accessible to 'self'-isolated code}}
}
let z = (x, y)
Task { // expected-warning {{passing closure as a 'sending' parameter risks causing data races between 'self'-isolated code and concurrent execution of the closure}}
print(y, z) // expected-note @:13 {{closure captures non-Sendable 'y'}}
// expected-note @-1:16 {{closure captures non-Sendable 'z'}}
}
}
}
// We would normally not error here since transferArg is nonisolated and c is
// disconnected. Since c is passed as sending, we shouldn't squelch this.
func disconnectedPassedSendingToNonIsolatedCallee(
) async -> Void {
let c = NonSendableKlass()
transferArg(c) // expected-warning {{sending 'c' risks causing data races}}
// expected-note @-1 {{'c' used after being passed as a 'sending' parameter}}
c.use() // expected-note {{access can happen concurrently}}
}
// We would normally not error here since transferArg is nonisolated and c is
// disconnected. Since c is passed as sending, we shouldn't squelch this.
func disconnectedPassedSendingToAsyncNonIsolatedCallee(
) async -> Void {
let c = NonSendableKlass()
await transferArgAsync(c) // expected-warning {{sending 'c' risks causing data races}}
// expected-note @-1 {{'c' used after being passed as a 'sending' parameter}}
c.use() // expected-note {{access can happen concurrently}}
}
// We would normally not error here since transferArg is nonisolated and c is
// disconnected. Since c is passed as sending, we shouldn't squelch this.
func disconnectedPassedSendingToNonIsolatedCalleeIsolatedParam2(
isolation: isolated (any Actor)? = nil
) async -> Void {
let c = NonSendableKlass()
transferArg(c) // expected-warning {{sending 'c' risks causing data races}}
// expected-note @-1 {{'c' used after being passed as a 'sending' parameter}}
c.use() // expected-note {{access can happen concurrently}}
}
// We would normally not error here since transferArg is nonisolated and c is
// disconnected. Since c is passed as sending, we shouldn't squelch this.
func disconnectedPassedSendingToAsyncNonIsolatedCalleeIsolatedParam2(
isolation: isolated (any Actor)? = nil
) async -> Void {
let c = NonSendableKlass()
await transferArgAsync(c) // expected-warning {{sending 'c' risks causing data races}}
// expected-note @-1 {{'c' used after being passed as a 'sending' parameter}}
c.use() // expected-note {{access can happen concurrently}}
}
// We would normally not error here since transferArg is nonisolated and c is
// disconnected. Since c is passed as sending, we shouldn't squelch this.
func disconnectedPassedSendingToNonIsolatedCalleeIsolatedParam3(
isolation: isolated (any Actor)? = nil
) -> Void {
let c = NonSendableKlass()
transferArg(c) // expected-warning {{sending 'c' risks causing data races}}
// expected-note @-1 {{'c' used after being passed as a 'sending' parameter}}
c.use() // expected-note {{access can happen concurrently}}
}
// In all of the below, we don't know that 'a' is the same isolation as the
// closure isolation.
func testNonSendableCaptures(ns: NonSendableKlass, a: isolated MyActor) {
Task {
_ = a
_ = ns
}
Task { [a] in // expected-warning {{passing closure as a 'sending' parameter risks causing data races between 'a'-isolated code and concurrent execution of the closure}}
_ = a
_ = ns // expected-note {{closure captures 'a'-isolated 'ns'}}
}
Task {
let _ = a
let _ = ns
}
Task { [a] in // expected-warning {{passing closure as a 'sending' parameter risks causing data races between 'a'-isolated code and concurrent execution of the closure}}
let _ = a
let _ = ns // expected-note {{closure captures 'a'-isolated 'ns'}}
}
Task { [a] in // expected-warning {{passing closure as a 'sending' parameter risks causing data races between 'a'-isolated code and concurrent execution of the closure}}
let (_, _) = (a, ns) // expected-note {{closure captures 'a'-isolated 'ns'}}
let _ = ns
}
}