mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
**Description**: This adds "task name" parameter to all task creating functions. This is done in a few ways, e.g. we can backdeploy this to 5.1 in APIs which do not accept the `TaskExecutor` but it they do we provide a version for 6.0+ etc. This was requested in the SE acceptable of this proposal [Acceptance post SE-0469](https://forums.swift.org/t/accepted-with-modifications-se-0469-task-naming/79438). This moves all these declarations to gyb since going through them one by one has become unmaintainable otherwise. **Scope/Impact**: All task creation APIs now gain a new task name parameter. **Risk:** Medium, changes existing APIs rather than adding "even more overloads" though this risk was discussed in the team and accepted. This has a potential to be source breaking it someone used Task.init and friends as function. **Testing**: CI testing, source compatibility suite testing **Reviewed by**: **Original PR:** - https://github.com/swiftlang/swift/pull/81107 build changes required for this - https://github.com/swiftlang/swift/pull/80984 **Radar:** --------- Co-authored-by: Kuba Mracek <mracek@apple.com>
2030 lines
98 KiB
Swift
2030 lines
98 KiB
Swift
// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -disable-availability-checking -verify -verify-additional-prefix tns- %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability
|
|
|
|
// This run validates that for specific test cases around closures, we properly
|
|
// emit errors in the type checker before we run sns. This ensures that we know that
|
|
// these cases can't happen when SNS is enabled.
|
|
//
|
|
// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -disable-availability-checking -verify -verify-additional-prefix typechecker-only- -DTYPECHECKER_ONLY %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability
|
|
|
|
// REQUIRES: concurrency
|
|
// REQUIRES: swift_feature_GlobalActorIsolatedTypesUsability
|
|
|
|
////////////////////////
|
|
// MARK: Declarations //
|
|
////////////////////////
|
|
|
|
/// Classes are always non-Sendable, so this is non-Sendable
|
|
class NonSendableKlass { // expected-complete-note 53{{}}
|
|
// expected-typechecker-only-note @-1 3{{}}
|
|
// expected-tns-note @-2 {{}}
|
|
var field: NonSendableKlass? = nil
|
|
var boolean: Bool = false
|
|
|
|
init() {}
|
|
init(_ x: NonSendableKlass) {
|
|
}
|
|
|
|
func asyncCall() async {}
|
|
func asyncCallWithIsolatedParameter(isolation: isolated (any Actor)? = #isolation) async {
|
|
}
|
|
|
|
func getSendableGenericStructAsync() async -> SendableGenericStruct { fatalError() }
|
|
}
|
|
|
|
nonisolated final class NonIsolatedFinalKlass {
|
|
var ns = NonSendableKlass()
|
|
}
|
|
|
|
class SendableKlass : @unchecked Sendable {}
|
|
|
|
actor MyActor {
|
|
var klass = NonSendableKlass()
|
|
// expected-typechecker-only-note @-1 7{{property declared here}}
|
|
final var finalKlass = NonSendableKlass()
|
|
|
|
func useKlass(_ x: NonSendableKlass) {}
|
|
|
|
func useSendableFunction(_: @Sendable () -> Void) {}
|
|
func useNonSendableFunction(_: () -> Void) {}
|
|
func doSomething() {}
|
|
@MainActor func useKlassMainActor(_ x: NonSendableKlass) {}
|
|
}
|
|
|
|
final actor FinalActor {
|
|
var klass = NonSendableKlass()
|
|
func useKlass(_ x: NonSendableKlass) {}
|
|
}
|
|
|
|
@MainActor
|
|
class MainActorIsolatedKlass {
|
|
var klass = NonSendableKlass()
|
|
let klassLet = NonSendableKlass()
|
|
}
|
|
|
|
@MainActor
|
|
final class FinalMainActorIsolatedKlass {
|
|
var klass = NonSendableKlass()
|
|
}
|
|
|
|
func useInOut<T>(_ x: inout T) {}
|
|
func useValue<T>(_ x: T) {}
|
|
func useValueAsync<T>(_ x: T) async {}
|
|
|
|
@MainActor func transferToMain<T>(_ t: T) async {}
|
|
|
|
var booleanFlag: Bool { false }
|
|
|
|
struct SingleFieldKlassBox { // expected-complete-note 2{{consider making struct 'SingleFieldKlassBox' conform to the 'Sendable' protocol}}
|
|
var k = NonSendableKlass()
|
|
}
|
|
|
|
struct TwoFieldKlassBox { // expected-typechecker-only-note 2{{}}
|
|
var k1 = NonSendableKlass()
|
|
var k2 = NonSendableKlass()
|
|
}
|
|
|
|
class TwoFieldKlassClassBox {
|
|
var k1 = NonSendableKlass()
|
|
var k2 = NonSendableKlass()
|
|
var recursive: TwoFieldKlassClassBox? = nil
|
|
}
|
|
|
|
struct SendableGenericStruct : Sendable {
|
|
var x = SendableKlass()
|
|
}
|
|
|
|
////////////////////////////
|
|
// MARK: Actor Self Tests //
|
|
////////////////////////////
|
|
|
|
extension MyActor {
|
|
func warningIfCallingGetter() async {
|
|
await self.klass.asyncCall() // expected-complete-warning {{passing argument of non-Sendable type 'NonSendableKlass' outside of actor-isolated context may introduce data races}}
|
|
// expected-tns-warning @-1 {{sending 'self.klass' risks causing data races}}
|
|
// expected-tns-note @-2 {{sending 'self'-isolated 'self.klass' to nonisolated instance method 'asyncCall()' risks causing data races between nonisolated and 'self'-isolated uses}}
|
|
}
|
|
|
|
func warningIfCallingAsyncOnFinalField() async {
|
|
// Since we are calling finalKlass directly, we emit a warning here.
|
|
await self.finalKlass.asyncCall() // expected-complete-warning {{passing argument of non-Sendable type 'NonSendableKlass' outside of actor-isolated context may introduce data races}}
|
|
// expected-tns-warning @-1 {{sending 'self.finalKlass' risks causing data races}}
|
|
// expected-tns-note @-2 {{sending 'self'-isolated 'self.finalKlass' to nonisolated instance method 'asyncCall()' risks causing data races between nonisolated and 'self'-isolated uses}}
|
|
}
|
|
|
|
// We do not warn on this since we warn in the caller of our getter instead.
|
|
var klassGetter: NonSendableKlass {
|
|
self.finalKlass
|
|
}
|
|
}
|
|
|
|
extension FinalActor {
|
|
func warningIfCallingAsyncOnFinalField() async {
|
|
// Since our whole class is final, we emit the error directly here.
|
|
await self.klass.asyncCall() // expected-complete-warning {{passing argument of non-Sendable type 'NonSendableKlass' outside of actor-isolated context may introduce data races}}
|
|
// expected-tns-warning @-1 {{sending 'self.klass' risks causing data races}}
|
|
// expected-tns-note @-2 {{sending 'self'-isolated 'self.klass' to nonisolated instance method 'asyncCall()' risks causing data races between nonisolated and 'self'-isolated uses}}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////
|
|
// MARK: Closure Formation //
|
|
/////////////////////////////
|
|
|
|
// This test makes sure that we can properly pattern match project_box.
|
|
func formClosureWithoutCrashing() {
|
|
var c = NonSendableKlass() // expected-warning {{variable 'c' was never mutated; consider changing to 'let' constant}}
|
|
let _ = { print(c) }
|
|
}
|
|
|
|
// In this test, closure is not promoted into its box form. As a result, we
|
|
// treat assignments into contents as a merge operation rather than an assign.
|
|
func closureInOut(_ a: MyActor) async {
|
|
var contents = NonSendableKlass()
|
|
let ns0 = NonSendableKlass()
|
|
let ns1 = NonSendableKlass()
|
|
|
|
contents = ns0
|
|
contents = ns1
|
|
|
|
var closure = {}
|
|
closure = { useInOut(&contents) }
|
|
|
|
await a.useKlass(ns0)
|
|
// expected-complete-warning @-1 {{passing argument of non-Sendable type 'NonSendableKlass'}}
|
|
// expected-tns-warning @-2 {{sending 'ns0' risks causing data races}}
|
|
// expected-tns-note @-3 {{sending 'ns0' to actor-isolated instance method 'useKlass' risks causing data races between actor-isolated and local nonisolated uses}}
|
|
|
|
if await booleanFlag {
|
|
await a.useKlass(ns1) // expected-tns-note {{access can happen concurrently}}
|
|
} else {
|
|
closure() // expected-tns-note {{access can happen concurrently}}
|
|
}
|
|
}
|
|
|
|
func closureInOutDifferentActor(_ a: MyActor, _ a2: MyActor) async {
|
|
var contents = NonSendableKlass()
|
|
let ns0 = NonSendableKlass()
|
|
let ns1 = NonSendableKlass()
|
|
|
|
contents = ns0
|
|
contents = ns1
|
|
|
|
var closure = {}
|
|
closure = { useInOut(&contents) }
|
|
|
|
await a.useKlass(ns0)
|
|
// expected-complete-warning @-1 {{passing argument of non-Sendable type 'NonSendableKlass'}}
|
|
// expected-tns-warning @-2 {{sending 'ns0' risks causing data races}}
|
|
// expected-tns-note @-3 {{sending 'ns0' to actor-isolated instance method 'useKlass' risks causing data races between actor-isolated and local nonisolated uses}}
|
|
|
|
// We only emit a warning on the first use we see, so make sure we do both
|
|
// the use and the closure.
|
|
if await booleanFlag {
|
|
await a2.useKlass(ns1) // expected-tns-note {{access can happen concurrently}}
|
|
// expected-complete-warning @-1 {{passing argument of non-Sendable type 'NonSendableKlass'}}
|
|
} else {
|
|
closure() // expected-tns-note {{access can happen concurrently}}
|
|
}
|
|
}
|
|
|
|
|
|
func closureInOut2(_ a: MyActor) async {
|
|
var contents = NonSendableKlass()
|
|
let ns0 = NonSendableKlass()
|
|
let ns1 = NonSendableKlass()
|
|
|
|
contents = ns0
|
|
contents = ns1
|
|
|
|
var closure = {}
|
|
|
|
await a.useKlass(ns0) // expected-tns-warning {{sending 'ns0' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'ns0' to actor-isolated instance method 'useKlass' risks causing data races between actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'NonSendableKlass'}}
|
|
|
|
closure = { useInOut(&contents) } // expected-tns-note {{access can happen concurrently}}
|
|
|
|
await a.useKlass(ns1) // expected-tns-warning {{sending 'ns1' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'ns1' to actor-isolated instance method 'useKlass' risks causing data races between actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'NonSendableKlass'}}
|
|
|
|
closure() // expected-tns-note {{access can happen concurrently}}
|
|
}
|
|
|
|
func closureNonInOut(_ a: MyActor) async {
|
|
var contents = NonSendableKlass()
|
|
let ns0 = NonSendableKlass()
|
|
let ns1 = NonSendableKlass()
|
|
|
|
contents = ns0
|
|
contents = ns1
|
|
|
|
var closure = {}
|
|
|
|
await a.useKlass(ns0)
|
|
// expected-complete-warning @-1 {{passing argument of non-Sendable type 'NonSendableKlass'}}
|
|
|
|
closure = { useValue(contents) }
|
|
|
|
await a.useKlass(ns1) // expected-tns-warning {{sending 'ns1' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'ns1' to actor-isolated instance method 'useKlass' risks causing data races between actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'NonSendableKlass'}}
|
|
|
|
closure() // expected-tns-note {{access can happen concurrently}}
|
|
}
|
|
|
|
// TODO: Rework the nonisolated closure so we only treat nonisolated closures
|
|
// that capture self as being nonisolated. When we capture from outside of a
|
|
// method, we cannot access the inside of the actor without using an await, so
|
|
// this is safe.
|
|
func transferNonIsolatedNonAsyncClosureTwice() async {
|
|
let a = MyActor()
|
|
|
|
// This is nonisolated and non-async... we can transfer it safely.
|
|
var actorCaptureClosure = { print(a) }
|
|
await transferToMain(actorCaptureClosure) // expected-complete-warning {{passing argument of non-Sendable type '() -> ()' into main actor-isolated context may introduce data races}}
|
|
// expected-complete-note @-1 {{a function type must be marked '@Sendable' to conform to 'Sendable'}}
|
|
|
|
actorCaptureClosure = { print(a) }
|
|
await transferToMain(actorCaptureClosure) // expected-complete-warning {{passing argument of non-Sendable type '() -> ()' into main actor-isolated context may introduce data races}}
|
|
// expected-complete-note @-1 {{a function type must be marked '@Sendable' to conform to 'Sendable'}}
|
|
}
|
|
|
|
extension MyActor {
|
|
// Simple just capture self and access field.
|
|
func simpleClosureCaptureSelfAndTransfer() async {
|
|
let closure: () -> () = {
|
|
print(self.klass)
|
|
}
|
|
await transferToMain(closure) // expected-complete-warning {{passing argument of non-Sendable type '() -> ()' into main actor-isolated context may introduce data races}}
|
|
// expected-complete-note @-1 {{a function type must be marked '@Sendable' to conform to 'Sendable'}}
|
|
// expected-tns-warning @-2 {{sending 'closure' risks causing data races}}
|
|
// expected-tns-note @-3 {{sending 'self'-isolated 'closure' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and 'self'-isolated uses}}
|
|
}
|
|
|
|
func simpleClosureCaptureSelfAndTransferThroughTuple() async {
|
|
let closure: () -> () = {
|
|
print(self.klass)
|
|
}
|
|
let x = (1, closure)
|
|
await transferToMain(x) // expected-complete-warning {{passing argument of non-Sendable type '(Int, () -> ())' into main actor-isolated context may introduce data races}}
|
|
// expected-complete-note @-1 {{a function type must be marked '@Sendable' to conform to 'Sendable'}}
|
|
// expected-tns-warning @-2 {{sending value of non-Sendable type '(Int, () -> ())' risks causing data races}}
|
|
// expected-tns-note @-3 {{sending 'self'-isolated value of non-Sendable type '(Int, () -> ())' to main actor-isolated global function 'transferToMain' risks causing races in between 'self'-isolated and main actor-isolated uses}}
|
|
}
|
|
|
|
func simpleClosureCaptureSelfAndTransferThroughTupleBackwards() async {
|
|
let closure: () -> () = {
|
|
print(self.klass)
|
|
}
|
|
|
|
let x = (closure, 1)
|
|
await transferToMain(x) // expected-tns-warning {{sending value of non-Sendable type '(() -> (), Int)' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'self'-isolated value of non-Sendable type '(() -> (), Int)' to main actor-isolated global function 'transferToMain' risks causing races in between 'self'-isolated and main actor-isolated uses}}
|
|
}
|
|
|
|
func simpleClosureCaptureSelfAndTransferThroughOptional() async {
|
|
let closure: () -> () = {
|
|
print(self.klass)
|
|
}
|
|
let x: Any? = (1, closure)
|
|
await transferToMain(x) // expected-complete-warning {{passing argument of non-Sendable type 'Any?' into main actor-isolated context may introduce data races}}
|
|
// expected-tns-warning @-1 {{sending 'x' risks causing data races}}
|
|
// expected-tns-note @-2 {{sending 'self'-isolated 'x' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and 'self'-isolated uses}}
|
|
}
|
|
|
|
func simpleClosureCaptureSelfAndTransferThroughOptionalBackwards() async {
|
|
let closure: () -> () = {
|
|
print(self.klass)
|
|
}
|
|
// In contrast to the tuple backwards case, we do error here since the value
|
|
// we are forming is an Any? so we actually form the tuple as an object and
|
|
// store it all as once.
|
|
let x: Any? = (closure, 1)
|
|
await transferToMain(x) // expected-complete-warning {{passing argument of non-Sendable type 'Any?' into main actor-isolated context may introduce data races}}
|
|
// expected-tns-warning @-1 {{sending 'x' risks causing data races}}
|
|
// expected-tns-note @-2 {{sending 'self'-isolated 'x' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and 'self'-isolated uses}}
|
|
}
|
|
|
|
func simpleClosureCaptureSelfWithReinit() async {
|
|
var closure: () -> () = {
|
|
print(self.klass)
|
|
}
|
|
|
|
// Error here.
|
|
await transferToMain(closure) // expected-complete-warning {{passing argument of non-Sendable type '() -> ()' into main actor-isolated context may introduce data races}}
|
|
// expected-complete-note @-1 {{a function type must be marked '@Sendable' to conform to 'Sendable'}}
|
|
// expected-tns-warning @-2 {{sending 'closure' risks causing data races}}
|
|
// expected-tns-note @-3 {{sending 'self'-isolated 'closure' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and 'self'-isolated uses}}
|
|
|
|
closure = {}
|
|
|
|
// But not here.
|
|
await transferToMain(closure)
|
|
// expected-complete-warning @-1 {{passing argument of non-Sendable type '() -> ()' into main actor-isolated context may introduce data races}}
|
|
// expected-complete-note @-2 {{a function type must be marked '@Sendable' to conform to 'Sendable'}}
|
|
}
|
|
|
|
func simpleClosureCaptureSelfWithReinit2() async {
|
|
var closure: () -> () = {}
|
|
|
|
// No error here.
|
|
await transferToMain(closure)
|
|
// expected-complete-warning @-1 {{passing argument of non-Sendable type '() -> ()' into main actor-isolated context may introduce data races}}
|
|
// expected-complete-note @-2 {{a function type must be marked '@Sendable' to conform to 'Sendable'}}
|
|
|
|
closure = {
|
|
print(self.klass)
|
|
}
|
|
|
|
// Error here.
|
|
await transferToMain(closure) // expected-complete-warning {{passing argument of non-Sendable type '() -> ()' into main actor-isolated context may introduce data races}}
|
|
// expected-complete-note @-1 {{a function type must be marked '@Sendable' to conform to 'Sendable'}}
|
|
// expected-tns-warning @-2 {{sending 'closure' risks causing data races}}
|
|
// expected-tns-note @-3 {{sending 'self'-isolated 'closure' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and 'self'-isolated uses}}
|
|
}
|
|
|
|
func simpleClosureCaptureSelfWithReinit3() async {
|
|
var closure: () -> () = {}
|
|
|
|
// We get a transfer after use error.
|
|
await transferToMain(closure) // expected-complete-warning {{passing argument of non-Sendable type '() -> ()' into main actor-isolated context may introduce data races}}
|
|
// expected-complete-note @-1 {{a function type must be marked '@Sendable' to conform to 'Sendable'}}
|
|
// expected-tns-warning @-2 {{sending 'closure' risks causing data races}}
|
|
// expected-tns-note @-3 {{sending 'closure' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local actor-isolated uses}}
|
|
|
|
if await booleanFlag {
|
|
closure = {
|
|
print(self.klass)
|
|
}
|
|
}
|
|
|
|
await transferToMain(closure) // expected-complete-warning {{passing argument of non-Sendable type '() -> ()' into main actor-isolated context may introduce data races}}
|
|
// expected-complete-note @-1 {{a function type must be marked '@Sendable' to conform to 'Sendable'}}
|
|
// expected-tns-note @-2 {{access can happen concurrently}}
|
|
// expected-tns-warning @-3 {{sending 'closure' risks causing data races}}
|
|
// expected-tns-note @-4 {{sending 'self'-isolated 'closure' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and 'self'-isolated uses}}
|
|
}
|
|
|
|
// In this case, we reinit along both paths, but only one has an actor derived
|
|
// thing.
|
|
func simpleClosureCaptureSelfWithReinit4() async {
|
|
var closure: () -> () = {}
|
|
|
|
await transferToMain(closure)
|
|
// expected-complete-warning @-1 {{passing argument of non-Sendable type '() -> ()' into main actor-isolated context may introduce data races}}
|
|
// expected-complete-note @-2 {{a function type must be marked '@Sendable' to conform to 'Sendable'}}
|
|
|
|
if await booleanFlag {
|
|
closure = {
|
|
print(self.klass)
|
|
}
|
|
} else {
|
|
closure = {}
|
|
}
|
|
|
|
await transferToMain(closure) // expected-complete-warning {{passing argument of non-Sendable type '() -> ()' into main actor-isolated context may introduce data races}}
|
|
// expected-complete-note @-1 {{a function type must be marked '@Sendable' to conform to 'Sendable'}}
|
|
// expected-tns-warning @-2 {{sending 'closure' risks causing data races}}
|
|
// expected-tns-note @-3 {{sending 'self'-isolated 'closure' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and 'self'-isolated uses}}
|
|
}
|
|
|
|
#if TYPECHECKER_ONLY
|
|
|
|
func simpleClosureCaptureSelfThroughTupleWithFieldAccess() async {
|
|
// In this case, we erase that we accessed self so we hit a type checker
|
|
// error. We could make this a SNS error, but since in the other cases where
|
|
// we have a nonisolated non-async we are probably going to change it to be
|
|
// async as well making these errors go away.
|
|
let x = (self, 1)
|
|
let closure: () -> () = {
|
|
print(x.0.klass) // expected-typechecker-only-error {{actor-isolated property 'klass' can not be referenced from a nonisolated context}}
|
|
}
|
|
await transferToMain(closure)
|
|
// expected-complete-warning @-1 {{passing argument of non-Sendable type '() -> ()' into main actor-isolated context may introduce data races}}
|
|
// expected-complete-note @-2 {{a function type must be marked '@Sendable' to conform to 'Sendable'}}
|
|
}
|
|
|
|
#endif
|
|
|
|
func simpleClosureCaptureSelfThroughTuple() async {
|
|
let x = (self, self.klass)
|
|
let closure: () -> () = {
|
|
print(x.1)
|
|
}
|
|
await transferToMain(closure) // expected-complete-warning {{passing argument of non-Sendable type '() -> ()' into main actor-isolated context may introduce data races}}
|
|
// expected-complete-note @-1 {{a function type must be marked '@Sendable' to conform to 'Sendable'}}
|
|
// expected-tns-warning @-2 {{sending 'closure' risks causing data races}}
|
|
// expected-tns-note @-3 {{sending 'self'-isolated 'closure' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and 'self'-isolated uses}}
|
|
}
|
|
|
|
func simpleClosureCaptureSelfThroughTuple2() async {
|
|
let x = (2, self.klass)
|
|
let closure: () -> () = {
|
|
print(x.1)
|
|
}
|
|
await transferToMain(closure) // expected-complete-warning {{passing argument of non-Sendable type '() -> ()' into main actor-isolated context may introduce data races}}
|
|
// expected-complete-note @-1 {{a function type must be marked '@Sendable' to conform to 'Sendable'}}
|
|
// expected-tns-warning @-2 {{sending 'closure' risks causing data races}}
|
|
// expected-tns-note @-3 {{sending 'self'-isolated 'closure' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and 'self'-isolated uses}}
|
|
}
|
|
|
|
func simpleClosureCaptureSelfThroughOptional() async {
|
|
let x: Any? = (2, self.klass)
|
|
let closure: () -> () = {
|
|
print(x as Any)
|
|
}
|
|
await transferToMain(closure) // expected-complete-warning {{passing argument of non-Sendable type '() -> ()' into main actor-isolated context may introduce data races}}
|
|
// expected-complete-note @-1 {{a function type must be marked '@Sendable' to conform to 'Sendable'}}
|
|
// expected-tns-warning @-2 {{sending 'closure' risks causing data races}}
|
|
// expected-tns-note @-3 {{sending 'self'-isolated 'closure' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and 'self'-isolated uses}}
|
|
}
|
|
}
|
|
|
|
func testSimpleLetClosureCaptureActor() async {
|
|
let a = MyActor()
|
|
let closure = { print(a) }
|
|
await transferToMain(closure) // expected-complete-warning {{passing argument of non-Sendable type '() -> ()' into main actor-isolated context may introduce data races}}
|
|
// expected-complete-note @-1 {{a function type must be marked '@Sendable' to conform to 'Sendable'}}
|
|
}
|
|
|
|
#if TYPECHECKER_ONLY
|
|
|
|
func testSimpleLetClosureCaptureActorField() async {
|
|
let a = MyActor()
|
|
let closure = { print(a.klass) } // expected-typechecker-only-error {{actor-isolated property 'klass' can not be referenced from a nonisolated context}}
|
|
await transferToMain(closure)
|
|
// expected-complete-warning @-1 {{passing argument of non-Sendable type '() -> ()' into main actor-isolated context may introduce data races}}
|
|
// expected-complete-note @-2 {{a function type must be marked '@Sendable' to conform to 'Sendable'}}
|
|
}
|
|
|
|
func testSimpleLetClosureCaptureActorFieldThroughTuple() async {
|
|
let a = (MyActor(), 0)
|
|
let closure = { print(a.0.klass) } // expected-typechecker-only-error {{actor-isolated property 'klass' can not be referenced from a nonisolated context}}
|
|
await transferToMain(closure)
|
|
// expected-complete-warning @-1 {{passing argument of non-Sendable type '() -> ()' into main actor-isolated context may introduce data races}}
|
|
// expected-complete-note @-2 {{a function type must be marked '@Sendable' to conform to 'Sendable'}}
|
|
}
|
|
|
|
func testSimpleLetClosureCaptureActorFieldThroughOptional() async {
|
|
let a: MyActor? = MyActor()
|
|
let closure = { print(a!.klass) } // expected-typechecker-only-error {{actor-isolated property 'klass' can not be referenced from a nonisolated context}}
|
|
await transferToMain(closure)
|
|
// expected-complete-warning @-1 {{passing argument of non-Sendable type '() -> ()' into main actor-isolated context may introduce data races}}
|
|
// expected-complete-note @-2 {{a function type must be marked '@Sendable' to conform to 'Sendable'}}
|
|
}
|
|
|
|
#endif
|
|
|
|
func testSimpleVarClosureCaptureActor() async {
|
|
let a = MyActor()
|
|
var closure = {}
|
|
closure = { print(a) }
|
|
await transferToMain(closure) // expected-complete-warning {{passing argument of non-Sendable type '() -> ()' into main actor-isolated context may introduce data races}}
|
|
// expected-complete-note @-1 {{a function type must be marked '@Sendable' to conform to 'Sendable'}}
|
|
}
|
|
|
|
#if TYPECHECKER_ONLY
|
|
|
|
func testSimpleVarClosureCaptureActorField() async {
|
|
let a = MyActor()
|
|
var closure = {}
|
|
closure = { print(a.klass) } // expected-typechecker-only-error {{actor-isolated property 'klass' can not be referenced from a nonisolated context}}
|
|
await transferToMain(closure)
|
|
// expected-complete-warning @-1 {{passing argument of non-Sendable type '() -> ()' into main actor-isolated context may introduce data races}}
|
|
// expected-complete-note @-2 {{a function type must be marked '@Sendable' to conform to 'Sendable'}}
|
|
}
|
|
|
|
func testSimpleVarClosureCaptureActorFieldThroughTuple() async {
|
|
let a = (MyActor(), 0)
|
|
var closure = {}
|
|
closure = { print(a.0.klass) } // expected-typechecker-only-error {{actor-isolated property 'klass' can not be referenced from a nonisolated context}}
|
|
await transferToMain(closure)
|
|
// expected-complete-warning @-1 {{passing argument of non-Sendable type '() -> ()' into main actor-isolated context may introduce data races}}
|
|
// expected-complete-note @-2 {{a function type must be marked '@Sendable' to conform to 'Sendable'}}
|
|
}
|
|
|
|
func testSimpleVarClosureCaptureActorFieldThroughOptional() async {
|
|
let a: MyActor? = MyActor()
|
|
var closure = {}
|
|
closure = { print(a!.klass) } // expected-typechecker-only-error {{actor-isolated property 'klass' can not be referenced from a nonisolated context}}
|
|
await transferToMain(closure)
|
|
// expected-complete-warning @-1 {{passing argument of non-Sendable type '() -> ()' into main actor-isolated context may introduce data races}}
|
|
// expected-complete-note @-2 {{a function type must be marked '@Sendable' to conform to 'Sendable'}}
|
|
}
|
|
|
|
#endif
|
|
|
|
extension MyActor {
|
|
// Make sure that we properly propagate actor derived from klass into field's
|
|
// value.
|
|
func simplePropagateNonSendableThroughMultipleProperty() async {
|
|
let f = self.klass.field!
|
|
let closure: () -> () = {
|
|
print(f)
|
|
}
|
|
await transferToMain(closure) // expected-complete-warning {{passing argument of non-Sendable type '() -> ()' into main actor-isolated context may introduce data races}}
|
|
// expected-complete-note @-1 {{a function type must be marked '@Sendable' to conform to 'Sendable'}}
|
|
// expected-tns-warning @-2 {{sending 'closure' risks causing data races}}
|
|
// expected-tns-note @-3 {{sending 'self'-isolated 'closure' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and 'self'-isolated uses}}
|
|
}
|
|
|
|
// Make sure that we properly propagate actor derived from klass into field's
|
|
// value.
|
|
func simplePropagateNonSendableThroughMultipleProperty2() async {
|
|
let f = self.klass.field!
|
|
let closure: () -> () = {
|
|
print(f.field!)
|
|
}
|
|
await transferToMain(closure) // expected-complete-warning {{passing argument of non-Sendable type '() -> ()' into main actor-isolated context may introduce data races}}
|
|
// expected-complete-note @-1 {{a function type must be marked '@Sendable' to conform to 'Sendable'}}
|
|
// expected-tns-warning @-2 {{sending 'closure' risks causing data races}}
|
|
// expected-tns-note @-3 {{sending 'self'-isolated 'closure' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and 'self'-isolated uses}}
|
|
}
|
|
}
|
|
|
|
extension MyActor {
|
|
func testVarReassignStopActorDerived() async {
|
|
var closure: () -> () = {
|
|
print(self)
|
|
}
|
|
|
|
// This should error.
|
|
await transferToMain(closure) // expected-complete-warning {{passing argument of non-Sendable type '() -> ()' into main actor-isolated context may introduce data races}}
|
|
// expected-complete-note @-1 {{a function type must be marked '@Sendable' to conform to 'Sendable'}}
|
|
// expected-tns-warning @-2 {{sending 'closure' risks causing data races}}
|
|
// expected-tns-note @-3 {{sending 'self'-isolated 'closure' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and 'self'-isolated uses}}
|
|
|
|
// This doesnt since we re-assign
|
|
closure = {}
|
|
await transferToMain(closure)
|
|
// expected-complete-warning @-1 {{passing argument of non-Sendable type '() -> ()' into main actor-isolated context may introduce data races}}
|
|
// expected-complete-note @-2 {{a function type must be marked '@Sendable' to conform to 'Sendable'}}
|
|
|
|
// This re-assignment shouldn't error.
|
|
closure = {}
|
|
// But this transfer should.
|
|
await transferToMain(closure) // expected-complete-warning {{passing argument of non-Sendable type '() -> ()' into main actor-isolated context may introduce data races}}
|
|
// expected-complete-note @-1 {{a function type must be marked '@Sendable' to conform to 'Sendable'}}
|
|
// expected-tns-warning @-2 {{sending 'closure' risks causing data races}}
|
|
// expected-tns-note @-3 {{sending 'closure' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local actor-isolated uses}}
|
|
|
|
// But this will error since we race.
|
|
closure() // expected-tns-note {{access can happen concurrently}}
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////
|
|
// MARK: Sendable Function Tests //
|
|
///////////////////////////////////
|
|
|
|
// Make sure that we do not error on function values that are Sendable... even
|
|
// if the function is converted to a non-Sendable form by a function conversion.
|
|
func testConversionsAndSendable(a: MyActor, f: @Sendable () -> Void, f2: () -> Void) async {
|
|
// No function conversion.
|
|
await a.useSendableFunction(f)
|
|
|
|
// Function conversion.
|
|
await a.useNonSendableFunction(f)
|
|
|
|
// Show that we error if we are not sendable.
|
|
await a.useNonSendableFunction(f2) // expected-complete-warning {{passing argument of non-Sendable type '() -> Void' into actor-isolated context may introduce data races}}
|
|
// expected-complete-note @-1 {{a function type must be marked '@Sendable' to conform to 'Sendable'}}
|
|
// expected-tns-warning @-2 {{sending 'f2' risks causing data races}}
|
|
// expected-tns-note @-3 {{sending task-isolated 'f2' to actor-isolated instance method 'useNonSendableFunction' risks causing data races between actor-isolated and task-isolated uses}}
|
|
}
|
|
|
|
func testSendableClosureCapturesNonSendable(a: MyActor) {
|
|
let klass = NonSendableKlass()
|
|
let _ = { @Sendable in
|
|
_ = klass // expected-warning {{capture of 'klass' with non-Sendable type 'NonSendableKlass' in a '@Sendable' closure}}
|
|
}
|
|
}
|
|
|
|
func testSendableClosureCapturesNonSendable2(a: FinalMainActorIsolatedKlass) {
|
|
let klass = NonSendableKlass()
|
|
let _ = { @Sendable @MainActor in
|
|
a.klass = klass // expected-complete-warning {{capture of 'klass' with non-Sendable type 'NonSendableKlass' in a '@Sendable' closure}}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////
|
|
// MARK: Multiple Field Var Assignment Merge Tests //
|
|
/////////////////////////////////////////////////////
|
|
|
|
func singleFieldVarMergeTest() async {
|
|
var box = SingleFieldKlassBox()
|
|
box = SingleFieldKlassBox()
|
|
|
|
// This transfers the entire region.
|
|
await transferToMain(box.k)
|
|
// expected-complete-warning @-1 {{passing argument of non-Sendable type 'NonSendableKlass' into main actor-isolated context may introduce data races}}
|
|
|
|
// But since box has only a single element, this doesn't race.
|
|
box.k = NonSendableKlass()
|
|
useValue(box.k)
|
|
useValue(box)
|
|
|
|
// We transfer the box back to main.
|
|
await transferToMain(box)
|
|
// expected-complete-warning @-1 {{passing argument of non-Sendable type 'SingleFieldKlassBox' into main actor-isolated context may introduce data races}}
|
|
|
|
// And reassign over the entire box, so again we can use it again.
|
|
box = SingleFieldKlassBox()
|
|
|
|
useValue(box)
|
|
useValue(box.k)
|
|
|
|
await transferToMain(box) // expected-tns-warning {{sending 'box' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'box' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'SingleFieldKlassBox' into main actor-isolated context may introduce data races}}
|
|
|
|
|
|
// But if we use box.k here, we emit an error since we didn't reinitialize at
|
|
// all.
|
|
useValue(box.k) // expected-tns-note {{access can happen concurrently}}
|
|
}
|
|
|
|
func multipleFieldVarMergeTest1() async {
|
|
var box = TwoFieldKlassBox()
|
|
box = TwoFieldKlassBox()
|
|
|
|
// This transfers the entire region.
|
|
await transferToMain(box.k1) // expected-tns-warning {{sending 'box.k1' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'box.k1' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'NonSendableKlass' into main actor-isolated context may introduce data races}}
|
|
|
|
|
|
// So even if we reassign over k1, since we did a merge, this should error.
|
|
box.k1 = NonSendableKlass() // expected-tns-note {{access can happen concurrently}}
|
|
useValue(box)
|
|
}
|
|
|
|
func multipleFieldVarMergeTest2() async {
|
|
var box = TwoFieldKlassBox()
|
|
box = TwoFieldKlassBox()
|
|
|
|
// This transfers the entire region.
|
|
await transferToMain(box.k1)
|
|
// expected-complete-warning @-1 {{passing argument of non-Sendable type 'NonSendableKlass' into main actor-isolated context may introduce data races}}
|
|
|
|
// But if we assign over box completely, we can use it again.
|
|
box = TwoFieldKlassBox()
|
|
|
|
useValue(box.k1)
|
|
useValue(box.k2)
|
|
useValue(box)
|
|
|
|
await transferToMain(box.k2)
|
|
// expected-complete-warning @-1 {{passing argument of non-Sendable type 'NonSendableKlass' into main actor-isolated context may introduce data races}}
|
|
|
|
// But if we assign over box completely, we can use it again.
|
|
box = TwoFieldKlassBox()
|
|
|
|
useValue(box.k1)
|
|
useValue(box.k2)
|
|
useValue(box)
|
|
}
|
|
|
|
func multipleFieldTupleMergeTest1() async {
|
|
var box = (NonSendableKlass(), NonSendableKlass())
|
|
box = (NonSendableKlass(), NonSendableKlass())
|
|
|
|
// This transfers the entire region.
|
|
await transferToMain(box.0) // expected-tns-warning {{sending 'box.0' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'box.0' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'NonSendableKlass' into main actor-isolated context may introduce data races}}
|
|
|
|
// So even if we reassign over k1, since we did a merge, this should error.
|
|
box.0 = NonSendableKlass() // expected-tns-note {{access can happen concurrently}}
|
|
useValue(box)
|
|
}
|
|
|
|
// TODO: Tuples today do not work since I need to change how we assign into
|
|
// tuple addresses to use a single instruction. Today SILGen always uses
|
|
// multiple values. I am going to fix this in a subsequent commit.
|
|
func multipleFieldTupleMergeTest2() async {
|
|
var box = (NonSendableKlass(), NonSendableKlass())
|
|
|
|
// This transfers the entire region.
|
|
await transferToMain(box.0)
|
|
// expected-complete-warning @-1 {{passing argument of non-Sendable type 'NonSendableKlass' into main actor-isolated context may introduce data races}}
|
|
|
|
let box2 = (NonSendableKlass(), NonSendableKlass())
|
|
// But if we assign over box completely, we can use it again.
|
|
box = box2
|
|
|
|
useValue(box.0)
|
|
useValue(box.1)
|
|
useValue(box)
|
|
|
|
await transferToMain(box.1)
|
|
// expected-complete-warning @-1 {{passing argument of non-Sendable type 'NonSendableKlass' into main actor-isolated context may introduce data races}}
|
|
|
|
// But if we assign over box completely, we can use it again.
|
|
box = (NonSendableKlass(), NonSendableKlass())
|
|
|
|
useValue(box.0)
|
|
useValue(box.1)
|
|
useValue(box)
|
|
}
|
|
|
|
///////////////////////////
|
|
// MARK: ClassFieldTests //
|
|
///////////////////////////
|
|
|
|
class ClassFieldTests { // expected-complete-note 6{{}}
|
|
let letSendableTrivial = 0
|
|
let letSendableNonTrivial = SendableKlass()
|
|
let letNonSendableNonTrivial = NonSendableKlass()
|
|
var varSendableTrivial = 0
|
|
var varSendableNonTrivial = SendableKlass()
|
|
var varNonSendableNonTrivial = NonSendableKlass()
|
|
}
|
|
|
|
func letSendableTrivialClassFieldTest() async {
|
|
let test = ClassFieldTests()
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'ClassFieldTests' into main actor-isolated context may introduce data races}}
|
|
_ = test.letSendableTrivial
|
|
useValue(test) // expected-tns-note {{access can happen concurrently}}
|
|
}
|
|
|
|
func letSendableNonTrivialClassFieldTest() async {
|
|
let test = ClassFieldTests()
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'ClassFieldTests' into main actor-isolated context may introduce data races}}
|
|
|
|
_ = test.letSendableNonTrivial
|
|
useValue(test) // expected-tns-note {{access can happen concurrently}}
|
|
}
|
|
|
|
func letNonSendableNonTrivialClassFieldTest() async {
|
|
let test = ClassFieldTests()
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'ClassFieldTests' into main actor-isolated context may introduce data races}}
|
|
_ = test.letNonSendableNonTrivial // expected-tns-note {{access can happen concurrently}}
|
|
useValue(test)
|
|
}
|
|
|
|
func varSendableTrivialClassFieldTest() async {
|
|
let test = ClassFieldTests()
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'ClassFieldTests' into main actor-isolated context may introduce data races}}
|
|
_ = test.varSendableTrivial // expected-tns-note {{access can happen concurrently}}
|
|
useValue(test)
|
|
}
|
|
|
|
func varSendableNonTrivialClassFieldTest() async {
|
|
let test = ClassFieldTests()
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'ClassFieldTests' into main actor-isolated context may introduce data races}}
|
|
_ = test.varSendableNonTrivial // expected-tns-note {{access can happen concurrently}}
|
|
useValue(test)
|
|
}
|
|
|
|
func varNonSendableNonTrivialClassFieldTest() async {
|
|
let test = ClassFieldTests()
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'ClassFieldTests' into main actor-isolated context may introduce data races}}
|
|
_ = test.varNonSendableNonTrivial // expected-tns-note {{access can happen concurrently}}
|
|
useValue(test)
|
|
}
|
|
|
|
////////////////////////////////
|
|
// MARK: FinalClassFieldTests //
|
|
////////////////////////////////
|
|
|
|
final class FinalClassFieldTests { // expected-complete-note 6 {{}}
|
|
let letSendableTrivial = 0
|
|
let letSendableNonTrivial = SendableKlass()
|
|
let letNonSendableNonTrivial = NonSendableKlass()
|
|
var varSendableTrivial = 0
|
|
var varSendableNonTrivial = SendableKlass()
|
|
var varNonSendableNonTrivial = NonSendableKlass()
|
|
}
|
|
|
|
func letSendableTrivialFinalClassFieldTest() async {
|
|
let test = FinalClassFieldTests()
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'FinalClassFieldTests' into main actor-isolated context may introduce data races}}
|
|
_ = test.letSendableTrivial
|
|
useValue(test) // expected-tns-note {{access can happen concurrently}}
|
|
}
|
|
|
|
func letSendableNonTrivialFinalClassFieldTest() async {
|
|
let test = FinalClassFieldTests()
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'FinalClassFieldTests' into main actor-isolated context may introduce data races}}
|
|
_ = test.letSendableNonTrivial
|
|
useValue(test) // expected-tns-note {{access can happen concurrently}}
|
|
}
|
|
|
|
func letNonSendableNonTrivialFinalClassFieldTest() async {
|
|
let test = FinalClassFieldTests()
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'FinalClassFieldTests' into main actor-isolated context may introduce data races}}
|
|
_ = test.letNonSendableNonTrivial // expected-tns-note {{access can happen concurrently}}
|
|
useValue(test)
|
|
}
|
|
|
|
func varSendableTrivialFinalClassFieldTest() async {
|
|
let test = FinalClassFieldTests()
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'FinalClassFieldTests' into main actor-isolated context may introduce data races}}
|
|
_ = test.varSendableTrivial // expected-tns-note {{access can happen concurrently}}
|
|
useValue(test)
|
|
}
|
|
|
|
func varSendableNonTrivialFinalClassFieldTest() async {
|
|
let test = FinalClassFieldTests()
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'FinalClassFieldTests' into main actor-isolated context may introduce data races}}
|
|
_ = test.varSendableNonTrivial // expected-tns-note {{access can happen concurrently}}
|
|
useValue(test)
|
|
}
|
|
|
|
func varNonSendableNonTrivialFinalClassFieldTest() async {
|
|
let test = FinalClassFieldTests()
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'FinalClassFieldTests' into main actor-isolated context may introduce data races}}
|
|
_ = test.varNonSendableNonTrivial // expected-tns-note {{access can happen concurrently}}
|
|
useValue(test)
|
|
}
|
|
|
|
////////////////////////////
|
|
// MARK: StructFieldTests //
|
|
////////////////////////////
|
|
|
|
struct StructFieldTests { // expected-complete-note 31 {{}}
|
|
let letSendableTrivial = 0
|
|
let letSendableNonTrivial = SendableKlass()
|
|
let letNonSendableNonTrivial = NonSendableKlass()
|
|
var varSendableTrivial = 0
|
|
var varSendableNonTrivial = SendableKlass()
|
|
var varNonSendableNonTrivial = NonSendableKlass()
|
|
}
|
|
|
|
func letSendableTrivialLetStructFieldTest() async {
|
|
let test = StructFieldTests()
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'StructFieldTests' into main actor-isolated context may introduce data races}}
|
|
_ = test.letSendableTrivial // expected-tns-note {{access can happen concurrently}}
|
|
useValue(test)
|
|
}
|
|
|
|
func letSendableNonTrivialLetStructFieldTest() async {
|
|
let test = StructFieldTests()
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'StructFieldTests' into main actor-isolated context may introduce data races}}
|
|
_ = test.letSendableNonTrivial // expected-tns-note {{access can happen concurrently}}
|
|
useValue(test)
|
|
}
|
|
|
|
func letNonSendableNonTrivialLetStructFieldTest() async {
|
|
let test = StructFieldTests()
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'StructFieldTests' into main actor-isolated context may introduce data races}}
|
|
let z = test.letNonSendableNonTrivial // expected-tns-note {{access can happen concurrently}}
|
|
_ = z
|
|
useValue(test)
|
|
}
|
|
|
|
func letSendableTrivialVarStructFieldTest() async {
|
|
var test = StructFieldTests()
|
|
test = StructFieldTests()
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'StructFieldTests' into main actor-isolated context may introduce data races}}
|
|
_ = test.letSendableTrivial
|
|
useValue(test) // expected-tns-note {{access can happen concurrently}}
|
|
}
|
|
|
|
func letSendableNonTrivialVarStructFieldTest() async {
|
|
var test = StructFieldTests()
|
|
test = StructFieldTests()
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'StructFieldTests' into main actor-isolated context may introduce data races}}
|
|
_ = test.letSendableNonTrivial
|
|
useValue(test) // expected-tns-note {{access can happen concurrently}}
|
|
}
|
|
|
|
func letNonSendableNonTrivialVarStructFieldTest() async {
|
|
var test = StructFieldTests()
|
|
test = StructFieldTests()
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'StructFieldTests' into main actor-isolated context may introduce data races}}
|
|
let z = test.letNonSendableNonTrivial // expected-tns-note {{access can happen concurrently}}
|
|
_ = z
|
|
useValue(test)
|
|
}
|
|
|
|
// Lets can access sendable let/var even if captured in a closure.
|
|
func letNonSendableNonTrivialLetStructFieldClosureTest() async {
|
|
let test = StructFieldTests()
|
|
let cls = {
|
|
print(test)
|
|
}
|
|
_ = cls
|
|
var cls2 = {}
|
|
cls2 = {
|
|
print(test)
|
|
}
|
|
_ = cls2
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'StructFieldTests' into main actor-isolated context may introduce data races}}
|
|
let z = test.letSendableNonTrivial // expected-tns-note {{access can happen concurrently}}
|
|
_ = z
|
|
let z2 = test.varSendableNonTrivial
|
|
_ = z2
|
|
useValue(test)
|
|
}
|
|
|
|
func varSendableTrivialLetStructFieldTest() async {
|
|
let test = StructFieldTests()
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'StructFieldTests' into main actor-isolated context may introduce data races}}
|
|
_ = test.varSendableTrivial // expected-tns-note {{access can happen concurrently}}
|
|
useValue(test)
|
|
}
|
|
|
|
func varSendableNonTrivialLetStructFieldTest() async {
|
|
let test = StructFieldTests()
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'StructFieldTests' into main actor-isolated context may introduce data races}}
|
|
_ = test.varSendableNonTrivial // expected-tns-note {{access can happen concurrently}}
|
|
useValue(test)
|
|
}
|
|
|
|
func varNonSendableNonTrivialLetStructFieldTest() async {
|
|
let test = StructFieldTests()
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'StructFieldTests' into main actor-isolated context may introduce data races}}
|
|
let z = test.varNonSendableNonTrivial // expected-tns-note {{access can happen concurrently}}
|
|
_ = z
|
|
useValue(test)
|
|
}
|
|
|
|
func varSendableTrivialVarStructFieldTest() async {
|
|
var test = StructFieldTests()
|
|
test = StructFieldTests()
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'StructFieldTests' into main actor-isolated context may introduce data races}}
|
|
_ = test.varSendableTrivial
|
|
useValue(test) // expected-tns-note {{access can happen concurrently}}
|
|
}
|
|
|
|
func varSendableNonTrivialVarStructFieldTest() async {
|
|
var test = StructFieldTests()
|
|
test = StructFieldTests()
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'StructFieldTests' into main actor-isolated context may introduce data races}}
|
|
_ = test.varSendableNonTrivial
|
|
useValue(test) // expected-tns-note {{access can happen concurrently}}
|
|
}
|
|
|
|
func varNonSendableNonTrivialVarStructFieldTest() async {
|
|
var test = StructFieldTests()
|
|
test = StructFieldTests()
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'StructFieldTests' into main actor-isolated context may introduce data races}}
|
|
let z = test.varNonSendableNonTrivial // expected-tns-note {{access can happen concurrently}}
|
|
_ = z
|
|
useValue(test)
|
|
}
|
|
|
|
// vars cannot access sendable let/var if captured in a closure.
|
|
func varNonSendableNonTrivialLetStructFieldClosureTest1() async {
|
|
var test = StructFieldTests()
|
|
test = StructFieldTests()
|
|
let cls = {
|
|
test = StructFieldTests()
|
|
}
|
|
_ = cls
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'StructFieldTests' into main actor-isolated context may introduce data races}}
|
|
let z = test.letSendableNonTrivial // expected-tns-note {{access can happen concurrently}}
|
|
_ = z
|
|
useValue(test)
|
|
}
|
|
|
|
func varNonSendableNonTrivialLetStructFieldClosureTest2() async {
|
|
var test = StructFieldTests()
|
|
test = StructFieldTests()
|
|
let cls = {
|
|
test = StructFieldTests()
|
|
}
|
|
_ = cls
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'StructFieldTests' into main actor-isolated context may introduce data races}}
|
|
let z = test.varSendableNonTrivial // expected-tns-note {{access can happen concurrently}}
|
|
_ = z
|
|
useValue(test)
|
|
}
|
|
|
|
func varNonSendableNonTrivialLetStructFieldClosureTest3() async {
|
|
var test = StructFieldTests()
|
|
test = StructFieldTests()
|
|
let cls = {
|
|
test = StructFieldTests()
|
|
}
|
|
_ = cls
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'StructFieldTests' into main actor-isolated context may introduce data races}}
|
|
test.varSendableNonTrivial = SendableKlass() // expected-tns-note {{access can happen concurrently}}
|
|
useValue(test)
|
|
}
|
|
|
|
// vars cannot access sendable let/var if captured in a closure.
|
|
func varNonSendableNonTrivialLetStructFieldClosureTest4() async {
|
|
var test = StructFieldTests()
|
|
test = StructFieldTests()
|
|
var cls = {}
|
|
cls = {
|
|
test = StructFieldTests()
|
|
}
|
|
_ = cls
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'StructFieldTests' into main actor-isolated context may introduce data races}}
|
|
let z = test.letSendableNonTrivial // expected-tns-note {{access can happen concurrently}}
|
|
_ = z
|
|
useValue(test)
|
|
}
|
|
|
|
func varNonSendableNonTrivialLetStructFieldClosureTest5() async {
|
|
var test = StructFieldTests()
|
|
test = StructFieldTests()
|
|
var cls = {}
|
|
cls = {
|
|
test = StructFieldTests()
|
|
}
|
|
_ = cls
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'StructFieldTests' into main actor-isolated context may introduce data races}}
|
|
let z = test.varSendableNonTrivial // expected-tns-note {{access can happen concurrently}}
|
|
_ = z
|
|
useValue(test)
|
|
}
|
|
|
|
func varNonSendableNonTrivialLetStructFieldClosureTest6() async {
|
|
var test = StructFieldTests()
|
|
test = StructFieldTests()
|
|
var cls = {}
|
|
cls = {
|
|
test = StructFieldTests()
|
|
}
|
|
_ = cls
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'StructFieldTests' into main actor-isolated context may introduce data races}}
|
|
test.varSendableNonTrivial = SendableKlass() // expected-tns-note {{access can happen concurrently}}
|
|
useValue(test)
|
|
}
|
|
|
|
func varNonSendableNonTrivialLetStructFieldClosureTest7() async {
|
|
var test = StructFieldTests()
|
|
test = StructFieldTests()
|
|
var cls = {}
|
|
cls = {
|
|
test.varSendableNonTrivial = SendableKlass()
|
|
}
|
|
_ = cls
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'StructFieldTests' into main actor-isolated context may introduce data races}}
|
|
test.varSendableNonTrivial = SendableKlass() // expected-tns-note {{access can happen concurrently}}
|
|
useValue(test)
|
|
}
|
|
|
|
func varNonSendableNonTrivialLetStructFieldClosureTest8() async {
|
|
var test = StructFieldTests()
|
|
test = StructFieldTests()
|
|
var cls = {}
|
|
cls = {
|
|
useInOut(&test)
|
|
}
|
|
_ = cls
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'StructFieldTests' into main actor-isolated context may introduce data races}}
|
|
test.varSendableNonTrivial = SendableKlass() // expected-tns-note {{access can happen concurrently}}
|
|
useValue(test)
|
|
}
|
|
|
|
func varNonSendableNonTrivialLetStructFieldClosureTest9() async {
|
|
var test = StructFieldTests()
|
|
test = StructFieldTests()
|
|
var cls = {}
|
|
cls = {
|
|
useInOut(&test.varSendableNonTrivial)
|
|
}
|
|
_ = cls
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'StructFieldTests' into main actor-isolated context may introduce data races}}
|
|
test.varSendableNonTrivial = SendableKlass() // expected-tns-note {{access can happen concurrently}}
|
|
useValue(test)
|
|
}
|
|
|
|
func varNonSendableNonTrivialLetStructFieldClosureFlowSensitive1() async {
|
|
var test = StructFieldTests()
|
|
test = StructFieldTests()
|
|
var cls = {}
|
|
|
|
if await booleanFlag {
|
|
cls = {
|
|
useInOut(&test.varSendableNonTrivial)
|
|
}
|
|
_ = cls
|
|
} else {
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'StructFieldTests' into main actor-isolated context may introduce data races}}
|
|
|
|
test.varSendableNonTrivial = SendableKlass()
|
|
}
|
|
|
|
useValue(test) // expected-tns-note {{access can happen concurrently}}
|
|
}
|
|
|
|
func varNonSendableNonTrivialLetStructFieldClosureFlowSensitive2() async {
|
|
var test = StructFieldTests()
|
|
test = StructFieldTests()
|
|
var cls = {}
|
|
|
|
if await booleanFlag {
|
|
cls = {
|
|
useInOut(&test.varSendableNonTrivial)
|
|
}
|
|
_ = cls
|
|
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'StructFieldTests' into main actor-isolated context may introduce data races}}
|
|
}
|
|
|
|
test.varSendableNonTrivial = SendableKlass() // expected-tns-note {{access can happen concurrently}}
|
|
useValue(test)
|
|
}
|
|
|
|
// We do not error when accessing the sendable field in this example since the
|
|
// transfer is not reachable from the closure. Instead we emit an error on test.
|
|
func varNonSendableNonTrivialLetStructFieldClosureFlowSensitive3() async {
|
|
var test = StructFieldTests()
|
|
test = StructFieldTests()
|
|
var cls = {}
|
|
|
|
if await booleanFlag {
|
|
cls = {
|
|
useInOut(&test.varSendableNonTrivial)
|
|
}
|
|
_ = cls
|
|
} else {
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'StructFieldTests' into main actor-isolated context may introduce data races}}
|
|
}
|
|
|
|
test.varSendableNonTrivial = SendableKlass()
|
|
useValue(test) // expected-tns-note {{access can happen concurrently}}
|
|
}
|
|
|
|
func varNonSendableNonTrivialLetStructFieldClosureFlowSensitive4() async {
|
|
var test = StructFieldTests()
|
|
test = StructFieldTests()
|
|
var cls = {}
|
|
|
|
for _ in 0..<1024 {
|
|
// TODO: The error here is b/c of the loop carry. We should probably store
|
|
// the operand instead of just the require inst, so we can better separate a
|
|
// loop carry use and an error due to multiple params. Then we could emit
|
|
// the error on test below. This is still correct though, just not as
|
|
// good... that is QoI though.
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-tns-note @-2 {{access can happen concurrently}}
|
|
|
|
// This is treated as a use since test is in box form and is mutable. So we
|
|
// treat assignment as a merge.
|
|
test = StructFieldTests()
|
|
cls = {
|
|
useInOut(&test.varSendableNonTrivial)
|
|
}
|
|
_ = cls
|
|
}
|
|
|
|
test.varSendableNonTrivial = SendableKlass()
|
|
useValue(test)
|
|
}
|
|
|
|
func varNonSendableNonTrivialLetStructFieldClosureFlowSensitive5() async {
|
|
var test = StructFieldTests()
|
|
test = StructFieldTests()
|
|
|
|
// The reason why we error here is that even though we reassign at the end of
|
|
// the for loop and currently understand that test has a new value different
|
|
// from the value assigned to test at the beginning of the for loop, when we
|
|
// merge back through the for loop, we have to merge the regions due to the
|
|
// union operation we perform. So the conservatism of the dataflow creates
|
|
// this. This is a case where we are going to need to be able to have the
|
|
// compiler explain the regions well.
|
|
for _ in 0..<1024 {
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-tns-note @-2 {{access can happen concurrently}}
|
|
// expected-complete-warning @-3 {{passing argument of non-Sendable type 'StructFieldTests' into main actor-isolated context may introduce data races}}
|
|
test = StructFieldTests()
|
|
}
|
|
|
|
test.varSendableNonTrivial = SendableKlass()
|
|
useValue(test)
|
|
}
|
|
|
|
func varNonSendableNonTrivialLetStructFieldClosureFlowSensitive6() async {
|
|
var test = StructFieldTests()
|
|
test = StructFieldTests()
|
|
var cls = {}
|
|
|
|
// In this test case, the first transfer errors on the
|
|
// test.varSendableNonTrivial b/c of the cls. Since we don't have cls on the
|
|
// else path, it emits on useValue(test).
|
|
if await booleanFlag {
|
|
cls = {
|
|
useInOut(&test.varSendableNonTrivial)
|
|
}
|
|
_ = cls
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'StructFieldTests' into main actor-isolated context may introduce data races}}
|
|
} else {
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'StructFieldTests' into main actor-isolated context may introduce data races}}
|
|
}
|
|
|
|
test.varSendableNonTrivial = SendableKlass() // expected-tns-note {{access can happen concurrently}}
|
|
useValue(test) // expected-tns-note {{access can happen concurrently}}
|
|
}
|
|
|
|
// In this case since we are tracking the transfer from the else statement, we
|
|
// track the closure.
|
|
func varNonSendableNonTrivialLetStructFieldClosureFlowSensitive7() async {
|
|
var test = StructFieldTests()
|
|
test = StructFieldTests()
|
|
var cls = {}
|
|
|
|
if await booleanFlag {
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'StructFieldTests' into main actor-isolated context may introduce data races}}
|
|
} else {
|
|
cls = {
|
|
useInOut(&test.varSendableNonTrivial)
|
|
}
|
|
_ = cls
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'StructFieldTests' into main actor-isolated context may introduce data races}}
|
|
}
|
|
|
|
test.varSendableNonTrivial = SendableKlass() // expected-tns-note {{access can happen concurrently}}
|
|
useValue(test) // expected-tns-note {{access can happen concurrently}}
|
|
}
|
|
|
|
////////////////////////////
|
|
// MARK: TupleFieldTests //
|
|
////////////////////////////
|
|
|
|
func varSendableTrivialLetTupleFieldTest() async {
|
|
let test = (0, SendableKlass(), NonSendableKlass())
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type '(Int, SendableKlass, NonSendableKlass)' into main actor-isolated context may introduce data races}}
|
|
let z = test.0
|
|
useValue(z)
|
|
useValue(test) // expected-tns-note {{access can happen concurrently}}
|
|
}
|
|
|
|
func varSendableNonTrivialLetTupleFieldTest() async {
|
|
let test = (0, SendableKlass(), NonSendableKlass())
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type '(Int, SendableKlass, NonSendableKlass)' into main actor-isolated context may introduce data races}}
|
|
let z = test.1
|
|
useValue(z)
|
|
useValue(test) // expected-tns-note {{access can happen concurrently}}
|
|
}
|
|
|
|
func varNonSendableNonTrivialLetTupleFieldTest() async {
|
|
let test = (0, SendableKlass(), NonSendableKlass())
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type '(Int, SendableKlass, NonSendableKlass)' into main actor-isolated context may introduce data races}}
|
|
let z = test.2 // expected-tns-note {{access can happen concurrently}}
|
|
useValue(z)
|
|
useValue(test)
|
|
}
|
|
|
|
func varSendableTrivialVarTupleFieldTest() async {
|
|
var test = (0, SendableKlass(), NonSendableKlass())
|
|
test = (0, SendableKlass(), NonSendableKlass())
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type '(Int, SendableKlass, NonSendableKlass)' into main actor-isolated context may introduce data races}}
|
|
_ = test.0
|
|
useValue(test) // expected-tns-note {{access can happen concurrently}}
|
|
}
|
|
|
|
func varSendableTrivialVarTupleFieldTest2() async {
|
|
var test = (0, SendableKlass(), NonSendableKlass())
|
|
test = (0, SendableKlass(), NonSendableKlass())
|
|
await transferToMain(test.2) // expected-tns-warning {{sending 'test.2' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test.2' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'NonSendableKlass' into main actor-isolated context may introduce data races}}
|
|
_ = test.0
|
|
useValue(test) // expected-tns-note {{access can happen concurrently}}
|
|
}
|
|
|
|
func varSendableNonTrivialVarTupleFieldTest() async {
|
|
var test = (0, SendableKlass(), NonSendableKlass())
|
|
test = (0, SendableKlass(), NonSendableKlass())
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type '(Int, SendableKlass, NonSendableKlass)' into main actor-isolated context may introduce data races}}
|
|
_ = test.1
|
|
useValue(test) // expected-tns-note {{access can happen concurrently}}
|
|
}
|
|
|
|
func varNonSendableNonTrivialVarTupleFieldTest() async {
|
|
var test = (0, SendableKlass(), NonSendableKlass())
|
|
test = (0, SendableKlass(), NonSendableKlass())
|
|
await transferToMain(test) // expected-tns-warning {{sending 'test' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'test' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type '(Int, SendableKlass, NonSendableKlass)' into main actor-isolated context may introduce data races}}
|
|
let z = test.2 // expected-tns-note {{access can happen concurrently}}
|
|
useValue(z)
|
|
useValue(test)
|
|
}
|
|
|
|
//////////////////////////////
|
|
// MARK: Control Flow Tests //
|
|
//////////////////////////////
|
|
|
|
func controlFlowTest1() async {
|
|
let x = NonSendableKlass()
|
|
|
|
if await booleanFlag {
|
|
await transferToMain(x) // expected-tns-warning {{sending 'x' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'NonSendableKlass' into main actor-isolated context may introduce data races}}
|
|
} else {
|
|
await transferToMain(x) // expected-tns-warning {{sending 'x' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'NonSendableKlass' into main actor-isolated context may introduce data races}}
|
|
}
|
|
|
|
useValue(x) // expected-tns-note 2{{access can happen concurrently}}
|
|
}
|
|
|
|
// This test seems like something that we should not error upon. What is
|
|
// happening here is that when we get to the bottom of the for loop, we realize
|
|
// that x's old value and x/x's new value are in different regions. But when we
|
|
// merge back into the loop header, we note that the loop entry block has x/x's
|
|
// old value in the same region so when we merge, we get that x/x's old
|
|
// value/x's new value are all in the same region. We emit the error on useValue
|
|
// as well afterwards since if we exit from the loop header, we have that large
|
|
// merge region leave the for loop.
|
|
func controlFlowTest2() async {
|
|
var x = NonSendableKlass()
|
|
|
|
for _ in 0..<1024 {
|
|
await transferToMain(x) // expected-tns-warning {{sending 'x' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
// expected-tns-note @-2 {{access can happen concurrently}}
|
|
// expected-complete-warning @-3 {{passing argument of non-Sendable type 'NonSendableKlass' into main actor-isolated context may introduce data races}}
|
|
|
|
x = NonSendableKlass()
|
|
}
|
|
|
|
useValue(x)
|
|
}
|
|
|
|
////////////////////////
|
|
// MARK: Actor Setter //
|
|
////////////////////////
|
|
|
|
actor ActorWithSetter {
|
|
var field = NonSendableKlass()
|
|
var twoFieldBox = TwoFieldKlassBox()
|
|
var twoFieldBoxInTuple = (NonSendableKlass(), TwoFieldKlassBox())
|
|
var recursive: ActorWithSetter? = nil
|
|
var classBox = TwoFieldKlassClassBox()
|
|
|
|
func test1() async {
|
|
let x = NonSendableKlass()
|
|
self.field = x
|
|
await transferToMain(x) // expected-tns-warning {{sending 'x' risks causing data races}}
|
|
// expected-tns-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}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'NonSendableKlass' into main actor-isolated context may introduce data races}}
|
|
}
|
|
|
|
func test2() async {
|
|
let x = NonSendableKlass()
|
|
self.twoFieldBox.k1 = x
|
|
await transferToMain(x) // expected-tns-warning {{sending 'x' risks causing data races}}
|
|
// expected-tns-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}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'NonSendableKlass' into main actor-isolated context may introduce data races}}
|
|
}
|
|
|
|
func test3() async {
|
|
let x = NonSendableKlass()
|
|
self.twoFieldBoxInTuple.1.k1 = x
|
|
await transferToMain(x) // expected-tns-warning {{sending 'x' risks causing data races}}
|
|
// expected-tns-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}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'NonSendableKlass' into main actor-isolated context may introduce data races}}
|
|
}
|
|
|
|
// This triggers a crash in SILGen with tns enabled.
|
|
#if TYPECHECKER_ONLY
|
|
func recursive() async {
|
|
let x = NonSendableKlass()
|
|
await self.recursive!.twoFieldBoxInTuple.1.k2 = x
|
|
// expected-typechecker-only-warning @-1 {{non-Sendable type '(NonSendableKlass, TwoFieldKlassBox)' of property 'twoFieldBoxInTuple' cannot exit actor-isolated context}}
|
|
// expected-typechecker-only-warning @-2 {{non-Sendable type '(NonSendableKlass, TwoFieldKlassBox)' of property 'twoFieldBoxInTuple' cannot exit actor-isolated context}}
|
|
|
|
await transferToMain(x) // xpected-tns-warning {{call site passes `self` or a non-Sendable argument of this function to another thread, potentially yielding a race with the caller}}
|
|
// expected-complete-warning @-1 {{passing argument of non-Sendable type 'NonSendableKlass' into main actor-isolated context may introduce data races}}
|
|
}
|
|
#endif
|
|
|
|
func classBox() async {
|
|
let x = NonSendableKlass()
|
|
self.classBox.k1 = x
|
|
await transferToMain(x) // expected-tns-warning {{sending 'x' risks causing data races}}
|
|
// expected-tns-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}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'NonSendableKlass' into main actor-isolated context may introduce data races}}
|
|
}
|
|
}
|
|
|
|
final actor FinalActorWithSetter {
|
|
var field = NonSendableKlass()
|
|
var twoFieldBox = TwoFieldKlassBox()
|
|
var twoFieldBoxInTuple = (NonSendableKlass(), TwoFieldKlassBox())
|
|
var recursive: ActorWithSetter? = nil
|
|
var classBox = TwoFieldKlassClassBox()
|
|
|
|
func test1() async {
|
|
let x = NonSendableKlass()
|
|
self.field = x
|
|
await transferToMain(x) // expected-tns-warning {{sending 'x' risks causing data races}}
|
|
// expected-tns-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}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'NonSendableKlass' into main actor-isolated context may introduce data races}}
|
|
}
|
|
|
|
func test2() async {
|
|
let x = NonSendableKlass()
|
|
self.twoFieldBox.k1 = x
|
|
await transferToMain(x) // expected-tns-warning {{sending 'x' risks causing data races}}
|
|
// expected-tns-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}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'NonSendableKlass' into main actor-isolated context may introduce data races}}
|
|
}
|
|
|
|
func test3() async {
|
|
let x = NonSendableKlass()
|
|
self.twoFieldBoxInTuple.1.k1 = x
|
|
await transferToMain(x) // expected-tns-warning {{sending 'x' risks causing data races}}
|
|
// expected-tns-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}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'NonSendableKlass' into main actor-isolated context may introduce data races}}
|
|
}
|
|
|
|
// This triggers a crash in SILGen with tns enabled.
|
|
#if TYPECHECKER_ONLY
|
|
func recursive() async {
|
|
let x = NonSendableKlass()
|
|
await self.recursive!.twoFieldBoxInTuple.1.k2 = x
|
|
// expected-typechecker-only-warning @-1 {{non-Sendable type '(NonSendableKlass, TwoFieldKlassBox)' of property 'twoFieldBoxInTuple' cannot exit actor-isolated context}}
|
|
// expected-typechecker-only-warning @-2 {{non-Sendable type '(NonSendableKlass, TwoFieldKlassBox)' of property 'twoFieldBoxInTuple' cannot exit actor-isolated context}}
|
|
|
|
await transferToMain(x) // xpected-tns-warning {{call site passes `self` or a non-Sendable argument of this function to another thread, potentially yielding a race with the caller}}
|
|
// expected-complete-warning @-1 {{passing argument of non-Sendable type 'NonSendableKlass' into main actor-isolated context may introduce data races}}
|
|
}
|
|
#endif
|
|
|
|
func classBox() async {
|
|
let x = NonSendableKlass()
|
|
self.classBox.k1 = x
|
|
await transferToMain(x) // expected-tns-warning {{sending 'x' risks causing data races}}
|
|
// expected-tns-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}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'NonSendableKlass' into main actor-isolated context may introduce data races}}
|
|
}
|
|
}
|
|
|
|
func functionArgumentIntoClosure(_ x: @escaping () -> ()) async {
|
|
let _ = { @MainActor in
|
|
let _ = x // expected-tns-warning {{sending 'x' risks causing data races}}
|
|
// expected-tns-note @-1 {{task-isolated 'x' is captured by a main actor-isolated closure. main actor-isolated uses in closure may race against later nonisolated uses}}
|
|
// expected-complete-warning @-2 {{capture of 'x' with non-Sendable type '() -> ()' in a '@Sendable' closure}}
|
|
// expected-complete-note @-3 {{a function type must be marked '@Sendable' to conform to 'Sendable'}}
|
|
}
|
|
}
|
|
|
|
// Make sure we handle the merge of the actor isolated and disconnected state
|
|
// appropriately.
|
|
//
|
|
// TODO: Since we are accessing the var field, we miss an
|
|
// error. rdar://126170563.
|
|
@MainActor func actorMergeInLoopVar() async {
|
|
let a = MainActorIsolatedKlass()
|
|
var c = NonSendableKlass()
|
|
for _ in 0..<1024 {
|
|
await useValueAsync(c) // expected-tns-warning {{sending 'c' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending main actor-isolated 'c' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'NonSendableKlass' outside of main actor-isolated context may introduce data races}}
|
|
c = a.klass
|
|
}
|
|
}
|
|
|
|
@MainActor func actorMergeInLoopLet() async {
|
|
let a = MainActorIsolatedKlass()
|
|
var c = NonSendableKlass()
|
|
for _ in 0..<1024 {
|
|
await useValueAsync(c) // expected-tns-warning {{sending 'c' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending main actor-isolated 'c' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'NonSendableKlass' outside of main actor-isolated context may introduce data races}}
|
|
c = a.klassLet
|
|
}
|
|
}
|
|
|
|
func testGetActorName() async {
|
|
let a = MyActor()
|
|
let x = NonSendableKlass()
|
|
await a.useKlass(x) // expected-tns-warning {{sending 'x' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'x' to actor-isolated instance method 'useKlass' risks causing data races between actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'NonSendableKlass' into actor-isolated context may introduce data races}}
|
|
useValue(x) // expected-tns-note {{access can happen concurrently}}
|
|
}
|
|
|
|
extension MyActor {
|
|
func testCallBangIsolatedMethod(other: MyActor) async {
|
|
await klass.asyncCallWithIsolatedParameter(isolation: other) // expected-tns-warning {{sending 'self.klass' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'self'-isolated 'self.klass' to actor-isolated instance method 'asyncCallWithIsolatedParameter(isolation:)' risks causing data races between actor-isolated and 'self'-isolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'NonSendableKlass' into actor-isolated context may introduce data races}}
|
|
}
|
|
}
|
|
|
|
extension FinalActor {
|
|
func testCallBangIsolatedMethod(other: MyActor) async {
|
|
await klass.asyncCallWithIsolatedParameter(isolation: other) // expected-tns-warning {{sending 'self.klass' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'self'-isolated 'self.klass' to actor-isolated instance method 'asyncCallWithIsolatedParameter(isolation:)' risks causing data races between actor-isolated and 'self'-isolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'NonSendableKlass' into actor-isolated context may introduce data races}}
|
|
}
|
|
}
|
|
|
|
extension NonSendableKlass {
|
|
func directAsyncCallWithIsolatedParameter(isolation: isolated (any Actor)? = #isolation) async {
|
|
}
|
|
}
|
|
|
|
extension MyActor {
|
|
func testCallBangIsolatedDirectMethod(other: MyActor) async {
|
|
await klass.directAsyncCallWithIsolatedParameter(isolation: other) // expected-tns-warning {{sending 'self.klass' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'self'-isolated 'self.klass' to actor-isolated instance method 'directAsyncCallWithIsolatedParameter(isolation:)' risks causing data races between actor-isolated and 'self'-isolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'NonSendableKlass' into actor-isolated context may introduce data races}}
|
|
}
|
|
}
|
|
|
|
extension FinalActor {
|
|
func testCallBangIsolatedDirectMethod(other: MyActor) async {
|
|
await klass.directAsyncCallWithIsolatedParameter(isolation: other) // expected-tns-warning {{sending 'self.klass' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'self'-isolated 'self.klass' to actor-isolated instance method 'directAsyncCallWithIsolatedParameter(isolation:)' risks causing data races between actor-isolated and 'self'-isolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'NonSendableKlass' into actor-isolated context may introduce data races}}
|
|
}
|
|
}
|
|
|
|
actor DictionaryActorTest {
|
|
var data: [Int: Int] = [:]
|
|
|
|
// We used to crash on this due to isolation merging.
|
|
func doSomething(_ key: Int) {
|
|
assert(self.data[key] == 0)
|
|
}
|
|
}
|
|
|
|
extension MyActor {
|
|
// Make sure that we properly infer information from isolated parameters that
|
|
// aren't self.
|
|
func isolationInferenceFromNonSelfIsolatedParameters() {
|
|
useValue {
|
|
self.doSomething()
|
|
}
|
|
}
|
|
|
|
func isolationInferenceFromNonSelfIsolatedParameters2() {
|
|
useValue {
|
|
self.doSomething()
|
|
let x = NonSendableKlass()
|
|
self.useKlass(x)
|
|
await transferToMain(x)
|
|
// expected-tns-warning @-1 {{sending 'x' risks causing data races}}
|
|
// expected-tns-note @-2 {{sending 'self'-isolated 'x' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and 'self'-isolated uses}}
|
|
// expected-complete-warning @-3 {{passing argument of non-Sendable type 'NonSendableKlass' into main actor-isolated context may introduce data races}}
|
|
}
|
|
}
|
|
}
|
|
|
|
func initAccessorTests() {
|
|
@available(SwiftStdlib 5.1, *)
|
|
actor NonisolatedAccessors {
|
|
nonisolated var a: Int = 0 {
|
|
init {
|
|
}
|
|
|
|
get { 0 }
|
|
set {}
|
|
}
|
|
|
|
init(value: Int) {
|
|
let escapingSelf: (NonisolatedAccessors) -> Void = { _ in }
|
|
|
|
// a is initialized here via default value
|
|
|
|
escapingSelf(self)
|
|
|
|
self.a = value // Ok (nonisolated)
|
|
print(a) // Ok (nonisolated)
|
|
}
|
|
}
|
|
|
|
@available(SwiftStdlib 5.1, *)
|
|
actor NonSendableInit {
|
|
var first: NonSendableKlass
|
|
var second: NonSendableKlass? = nil {
|
|
@storageRestrictions(initializes: first)
|
|
init(initialValue) {
|
|
first = initialValue!
|
|
}
|
|
|
|
get { fatalError() }
|
|
set { fatalError() }
|
|
}
|
|
|
|
@MainActor
|
|
var third: NonSendableKlass
|
|
@MainActor
|
|
var fourth: NonSendableKlass? = nil {
|
|
@storageRestrictions(initializes: third)
|
|
init(initialValue) {
|
|
third = initialValue!
|
|
}
|
|
|
|
get { fatalError() }
|
|
set { fatalError() }
|
|
}
|
|
}
|
|
}
|
|
|
|
func differentInstanceTest(_ a: MyActor, _ b: MyActor) async {
|
|
let x = NonSendableKlass()
|
|
await a.useKlass(x)
|
|
// expected-tns-warning @-1 {{sending 'x' risks causing data races}}
|
|
// expected-tns-note @-2 {{sending 'x' to actor-isolated instance method 'useKlass' risks causing data races between actor-isolated and local nonisolated uses}}
|
|
// expected-complete-warning @-3 {{passing argument of non-Sendable type 'NonSendableKlass' into actor-isolated context may introduce data races}}
|
|
await b.useKlass(x) // expected-tns-note {{access can happen concurrently}}
|
|
// expected-complete-warning @-1 {{passing argument of non-Sendable type 'NonSendableKlass' into actor-isolated context may introduce data races}}
|
|
}
|
|
|
|
protocol AssociatedTypeTestProtocol {
|
|
associatedtype A: Actor
|
|
}
|
|
|
|
func associatedTypeTestBasic<T: AssociatedTypeTestProtocol>(_: T, _: isolated T.A) {
|
|
}
|
|
|
|
func associatedTypeTestBasic2<T: AssociatedTypeTestProtocol>(_: T, iso: isolated T.A, x: NonSendableKlass) async {
|
|
await transferToMain(x) // expected-tns-warning {{sending 'x' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'iso'-isolated 'x' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and 'iso'-isolated uses}}
|
|
// expected-complete-warning @-2 {{passing argument of non-Sendable type 'NonSendableKlass' into main actor-isolated context may introduce data races}}
|
|
}
|
|
|
|
func sendableGlobalActorIsolated() {
|
|
let x = NonSendableKlass()
|
|
let _ = { @Sendable @MainActor in
|
|
print(x) // expected-tns-warning {{sending 'x' risks causing data races}}
|
|
// expected-tns-note @-1 {{'x' is captured by a main actor-isolated closure. main actor-isolated uses in closure may race against later nonisolated uses}}
|
|
// expected-complete-warning @-2 {{capture of 'x' with non-Sendable type 'NonSendableKlass' in a '@Sendable' closure}}
|
|
}
|
|
print(x) // expected-tns-note {{access can happen concurrently}}
|
|
}
|
|
|
|
// We do not get an error here since we are transferring x both times to a main
|
|
// actor isolated thing function. We used to emit an error when using region
|
|
// isolation since we would trip on the store_borrow we used to materialize the
|
|
// value.
|
|
func testIndirectParameterSameIsolationNoError() async {
|
|
let x = NonSendableKlass()
|
|
await transferToMain(x) // expected-tns-warning {{sending 'x' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}}
|
|
await transferToMain(x) // expected-tns-note {{access can happen concurrently}}
|
|
}
|
|
|
|
extension MyActor {
|
|
func testNonSendableCaptures(sc: NonSendableKlass) {
|
|
Task {
|
|
_ = self
|
|
_ = sc
|
|
|
|
Task { [sc,self] in
|
|
_ = self
|
|
_ = sc
|
|
|
|
Task { // expected-tns-warning {{sending value of non-Sendable type '() async -> ()' risks causing data races}}
|
|
// expected-tns-note @-1 {{Passing value of non-Sendable type '() async -> ()' as a 'sending' argument to initializer 'init(name:priority:operation:)' risks causing races in between local and caller code}}
|
|
_ = sc
|
|
}
|
|
|
|
Task { // expected-tns-note {{access can happen concurrently}}
|
|
_ = sc
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public struct TimeoutError: Error, CustomStringConvertible {
|
|
public var description: String { "Timed out" }
|
|
}
|
|
|
|
// We used to not merge the isolation below correctly causing us to emit a crash
|
|
// due to undefined behavior. Make sure we do not crash or emit an unhandled
|
|
// pattern error.
|
|
public func doNotCrashOrEmitUnhandledPatternErrors<T: Sendable>(
|
|
_ duration: Duration,
|
|
_ body: @escaping @Sendable () async throws -> T
|
|
) async throws -> T {
|
|
try await withThrowingTaskGroup(of: T.self) { taskGroup in
|
|
taskGroup.addTask {
|
|
try await Task.sleep(for: duration)
|
|
throw TimeoutError()
|
|
}
|
|
taskGroup.addTask {
|
|
return try await body()
|
|
}
|
|
for try await value in taskGroup {
|
|
taskGroup.cancelAll()
|
|
return value
|
|
}
|
|
throw CancellationError()
|
|
}
|
|
}
|
|
|
|
/// The following makes sure that when we have a function like test2 with an
|
|
/// assigned isolation that returns a Sendable value... we treat the value as
|
|
/// actually Sendable. This occurs in this example via the result of the default
|
|
/// parameter function for string.
|
|
///
|
|
/// We shouldn't emit any diagnostic here.
|
|
actor FunctionWithSendableResultAndIsolationActor {
|
|
func foo() -> String {
|
|
return string()
|
|
}
|
|
func string(someCondition: Bool = false) -> String {
|
|
return ""
|
|
}
|
|
}
|
|
|
|
// This was a test case that we used to emit an "pattern the compiler doesn't
|
|
// understand" error. We now accept it, so lets make sure we keep doing so!
|
|
@MainActor
|
|
func previouslyBrokenTestCase(ns: NonSendableKlass) async -> SendableGenericStruct? {
|
|
return await { () -> SendableGenericStruct? in
|
|
return await ns.getSendableGenericStructAsync() // expected-tns-warning {{sending 'ns' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending main actor-isolated 'ns' to nonisolated instance method 'getSendableGenericStructAsync()' risks causing data races between nonisolated and main actor-isolated uses}}
|
|
}()
|
|
}
|
|
|
|
@MainActor
|
|
func testThatGlobalActorTakesPrecedenceOverActorIsolationOnMethods() async {
|
|
let a = MyActor()
|
|
let ns = NonSendableKlass()
|
|
|
|
// 'ns' should be main actor isolated since useKlassMainActor is @MainActor
|
|
// isolated. Previously we would let MyActor take precedence here...
|
|
a.useKlassMainActor(ns)
|
|
|
|
// Meaning we would get an error here.
|
|
Task { @MainActor in print(ns) }
|
|
}
|
|
|
|
// Shouldn't get any errors from x.
|
|
//
|
|
// We used to look through the access to x.boolean and think that the closure
|
|
// was capturing x instead of y.
|
|
func testBooleanCapture(_ x: inout NonSendableKlass) {
|
|
let y = x.boolean
|
|
Task.detached { @MainActor [z = y] in
|
|
print(z)
|
|
}
|
|
}
|
|
|
|
public class Context {
|
|
let value: Int
|
|
|
|
init(value: Int) {
|
|
self.value = value
|
|
}
|
|
}
|
|
|
|
extension MyActor {
|
|
public func withContext<T>(_ block: sending (NonSendableKlass) throws -> T) async throws -> sending T {
|
|
return try block(klass) // expected-tns-warning {{returning 'self'-isolated 'self.klass' as a 'sending' result risks causing data races}}
|
|
// expected-tns-note @-1 {{returning 'self'-isolated 'self.klass' risks causing data races since the caller assumes that 'self.klass' can be safely sent to other isolation domains}}
|
|
}
|
|
}
|
|
|
|
func nonSendableAllocBoxConsumingParameter(x: consuming SendableKlass) async throws {
|
|
try await withThrowingTaskGroup(of: Void.self) { group in
|
|
group.addTask { // expected-tns-warning {{passing closure as a 'sending' parameter risks causing data races between code in the current task and concurrent execution of the closure}}
|
|
useValue(x) // expected-tns-note {{closure captures reference to mutable parameter 'x' which is accessible to code in the current task}}
|
|
}
|
|
|
|
try await group.waitForAll()
|
|
}
|
|
}
|
|
|
|
func nonSendableAllocBoxConsumingVar() async throws {
|
|
var x = SendableKlass()
|
|
x = SendableKlass()
|
|
|
|
try await withThrowingTaskGroup(of: Void.self) { group in
|
|
group.addTask { // expected-tns-warning {{passing closure as a 'sending' parameter risks causing data races between code in the current task and concurrent execution of the closure}}
|
|
useValue(x) // expected-tns-note {{closure captures reference to mutable var 'x' which is accessible to code in the current task}}
|
|
}
|
|
|
|
try await group.waitForAll()
|
|
}
|
|
}
|
|
|
|
func offByOneWithImplicitPartialApply() {
|
|
class A {
|
|
var description = ""
|
|
}
|
|
|
|
class B {
|
|
let a = A()
|
|
|
|
func b() {
|
|
let asdf = ""
|
|
Task { @MainActor in
|
|
a.description = asdf // expected-tns-warning {{sending 'self' risks causing data races}}
|
|
// expected-tns-note @-1 {{task-isolated 'self' is captured by a main actor-isolated closure. main actor-isolated uses in closure may race against later nonisolated uses}}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// We should not error in either of the cases below due to sending.
|
|
func testIndirectAndDirectSendingResultsWithGlobalActor() async {
|
|
@MainActor
|
|
struct S {
|
|
let ns = NonSendableKlass()
|
|
|
|
func getNonSendableKlassIndirect<T>() -> sending T {
|
|
fatalError()
|
|
}
|
|
func getNonSendableKlassDirect() -> sending NonSendableKlass {
|
|
fatalError()
|
|
}
|
|
}
|
|
|
|
let s = await S()
|
|
let ns: NonSendableKlass = await s.getNonSendableKlassDirect()
|
|
|
|
Task.detached {
|
|
_ = ns
|
|
}
|
|
|
|
let ns2: NonSendableKlass = await s.getNonSendableKlassIndirect()
|
|
Task.detached {
|
|
_ = ns2
|
|
}
|
|
}
|
|
|
|
// We used to not check if bodies were not empty when emitting the error for
|
|
// using result in the throwing task group. Make sure we do not crash.
|
|
func testFunctionIsNotEmpty(input: SendableKlass) async throws {
|
|
var result: [SendableKlass] = []
|
|
try await withThrowingTaskGroup(of: Void.self) { taskGroup in // expected-warning {{no calls to throwing functions occur within 'try' expression}}
|
|
taskGroup.addTask { // expected-tns-warning {{passing closure as a 'sending' parameter risks causing data races between code in the current task and concurrent execution of the closure}}
|
|
result.append(input) // expected-tns-note {{closure captures reference to mutable var 'result' which is accessible to code in the current task}}
|
|
}
|
|
}
|
|
}
|
|
|
|
func unsafeNonIsolatedAppliesToAssignToOutParam(ns: NonSendableKlass) -> sending NonSendableKlass {
|
|
func withUnsafeValue<T>(_ block: (NonSendableKlass) throws -> sending T) rethrows -> sending T {
|
|
fatalError()
|
|
}
|
|
|
|
return withUnsafeValue {
|
|
nonisolated(unsafe) let obj = $0
|
|
return obj
|
|
}
|
|
}
|
|
|
|
extension NonIsolatedFinalKlass {
|
|
// We used to crash while computing the isolation of the ref_element_addr
|
|
// here. Make sure we do not crash.
|
|
func testGetIsolationInfoOfField() async {
|
|
await transferToMain(ns) // expected-tns-warning {{sending 'self.ns' risks causing data races}}
|
|
// expected-tns-note @-1 {{sending task-isolated 'self.ns' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and task-isolated uses}}
|
|
}
|
|
}
|
|
|
|
func mutableLocalCaptureDataRace() async {
|
|
var x = 0
|
|
x = 0
|
|
_ = x
|
|
|
|
Task.detached { x = 1 } // expected-tns-warning {{sending value of non-Sendable type '() async -> ()' risks causing data races}}
|
|
// expected-tns-note @-1 {{Passing value of non-Sendable type '() async -> ()' as a 'sending' argument to static method 'detached(name:priority:operation:)' risks causing races in between local and caller code}}
|
|
|
|
x = 2 // expected-tns-note {{access can happen concurrently}}
|
|
}
|
|
|
|
func mutableLocalCaptureDataRace2() async {
|
|
var x = 0
|
|
x = 0
|
|
|
|
Task.detached { x = 1 } // expected-tns-warning {{sending value of non-Sendable type '() async -> ()' risks causing data races}}
|
|
// expected-tns-note @-1 {{Passing value of non-Sendable type '() async -> ()' as a 'sending' argument to static method 'detached(name:priority:operation:)' risks causing races in between local and caller code}}
|
|
|
|
print(x) // expected-tns-note {{access can happen concurrently}}
|
|
}
|
|
|
|
func localCaptureDataRace3() async {
|
|
let x = 0
|
|
|
|
Task.detached { print(x) }
|
|
|
|
print(x)
|
|
}
|
|
|
|
nonisolated func localCaptureDataRace4() {
|
|
var x = 0
|
|
_ = x
|
|
|
|
Task.detached { @MainActor in x = 1 } // expected-tns-warning {{sending 'x' risks causing data races}}
|
|
// expected-tns-note @-1 {{'x' is captured by a main actor-isolated closure. main actor-isolated uses in closure may race against later nonisolated uses}}
|
|
|
|
x = 2 // expected-tns-note {{access can happen concurrently}}
|
|
}
|
|
|
|
// We shouldn't error here since every time around, we are using the same
|
|
// isolation.
|
|
func testIsolatedParamInference() {
|
|
class S : @unchecked Sendable {}
|
|
|
|
final class B {
|
|
var s = S()
|
|
var b: Bool = false
|
|
|
|
func foo(isolation: isolated Actor = #isolation) async {
|
|
while !b {
|
|
await withTaskGroup(of: Int.self) { group in
|
|
_ = isolation
|
|
self.s = S()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|