Files
swift-mirror/test/Concurrency/transfernonsendable_sending_params.swift
Michael Gottesman a6edf4fb90 [rbi] Convert all rbi tests to run also in NonisolatedNonsendingByDefault.
Going to update the tests in the next commit. This just makes it easier to
review.
2025-07-02 12:13:37 -07:00

663 lines
27 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 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 transferArg(_ x: sending NonSendableKlass) {
}
func transferArgAsync(_ x: sending NonSendableKlass) async {
}
func transferArgWithOtherParam(_ x: sending NonSendableKlass, _ y: NonSendableKlass) {
}
func transferArgWithOtherParam2(_ x: NonSendableKlass, _ y: sending NonSendableKlass) {
}
func twoTransferArg(_ x: sending NonSendableKlass, _ y: sending NonSendableKlass) {}
@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)
}
@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 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: InOut Sending Tests //
///////////////////////////////
func testInOutSendingReinit(_ x: inout 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 nonisolated uses}}
} // expected-note {{'inout sending' parameter must be reinitialized before function exit with a non-actor-isolated value}}
func testInOutSendingReinit2(_ x: inout sending NonSendableKlass) async {
await transferToMain(x)
x = NonSendableKlass()
}
func testInOutSendingReinit3(_ x: inout sending NonSendableKlass) async throws {
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}}
try throwingFunction() // expected-note {{'inout sending' parameter must be reinitialized before function exit with a non-actor-isolated value}}
x = NonSendableKlass()
}
func testInOutSendingReinit4(_ x: inout sending NonSendableKlass) async throws {
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}}
do {
try throwingFunction()
x = NonSendableKlass()
} catch {
throw MyError() // expected-note {{'inout sending' parameter must be reinitialized before function exit with a non-actor-isolated value}}
}
x = NonSendableKlass()
}
func testInOutSendingReinit5(_ x: inout sending NonSendableKlass) async throws {
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}}
do {
try throwingFunction()
} catch {
throw MyError() // expected-note {{'inout sending' parameter must be reinitialized before function exit with a non-actor-isolated value}}
}
x = NonSendableKlass()
}
func testInOutSendingReinit6(_ x: inout sending NonSendableKlass) async throws {
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}}
do {
try throwingFunction()
} catch {
throw MyError() // expected-note {{'inout sending' parameter must be reinitialized before function exit with a non-actor-isolated value}}
}
} // expected-note {{'inout sending' parameter must be reinitialized before function exit with a non-actor-isolated value}}
actor InOutSendingWrongIsolationActor {
var ns = NonSendableKlass()
func testWrongIsolation(_ x: inout sending NonSendableKlass) {
x = ns
} // expected-warning {{'inout sending' parameter 'x' cannot be 'self'-isolated at end of function}}
// expected-note @-1 {{'self'-isolated 'x' risks causing races in between 'self'-isolated uses and caller uses since caller assumes value is not actor isolated}}
func testWrongIsolation2(_ x: inout sending NonSendableKlass) {
let z = ns
x = z
} // expected-warning {{'inout sending' parameter 'x' cannot be 'self'-isolated at end of function}}
// expected-note @-1 {{'self'-isolated 'x' risks causing races in between 'self'-isolated uses and caller uses since caller assumes value is not actor isolated}}
}
@MainActor
func testWrongIsolationGlobalIsolation(_ x: inout sending NonSendableKlass) {
x = globalKlass
} // expected-warning {{'inout sending' parameter 'x' cannot be main actor-isolated at end of function}}
// expected-note @-1 {{main actor-isolated 'x' risks causing races in between main actor-isolated uses and caller uses since caller assumes value is not actor isolated}}
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
}
}