// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -swift-version 6 -verify -verify-additional-prefix ni- %s -o /dev/null // RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -swift-version 6 -verify -verify-additional-prefix ni-ns- %s -o /dev/null -enable-upcoming-feature NonisolatedNonsendingByDefault // REQUIRES: concurrency // REQUIRES: asserts // REQUIRES: swift_feature_NonisolatedNonsendingByDefault // This test validates the behavior of transfernonsendable around initializers. //////////////////////// // MARK: Declarations // //////////////////////// class NonSendableKlass {} @MainActor func transferToMain(_ t: T) async {} actor CustomActorInstance {} @globalActor struct CustomActor { static let shared = CustomActorInstance() } ///////////////// // MARK: Tests // ///////////////// actor ActorWithSynchronousNonIsolatedInit { let k: NonSendableKlass init(_ newK: NonSendableKlass) { k = NonSendableKlass() helper(newK) // TODO: This should say actor isolated. let _ = { @MainActor in print(newK) // expected-error {{sending 'newK' risks causing data races}} // expected-ni-note @-1 {{task-isolated 'newK' is captured by a main actor-isolated closure. main actor-isolated uses in closure may race against later nonisolated uses}} // expected-ni-ns-note @-2 {{task-isolated 'newK' is captured by a main actor-isolated closure. main actor-isolated uses in closure may race against later nonisolated uses}} } } init(x newK: NonSendableKlass) { k = newK helper(newK) let _ = { @MainActor in // TODO: Second part should say later 'self'-isolated uses print(newK) // expected-error {{sending 'newK' risks causing data races}} // expected-note @-1 {{'self'-isolated 'newK' is captured by a main actor-isolated closure. main actor-isolated uses in closure may race against later nonisolated uses}} } } init(ns: NonSendableKlass) async { self.k = NonSendableKlass() self.isolatedHelper(ns) } nonisolated func helper(_ newK: NonSendableKlass) {} func isolatedHelper(_ newK: NonSendableKlass) {} } func initActorWithSyncNonIsolatedInit() { let k = NonSendableKlass() // TODO: This should say actor isolated. _ = ActorWithSynchronousNonIsolatedInit(k) // expected-error {{sending 'k' risks causing data races}} // expected-note @-1 {{sending 'k' to actor-isolated initializer 'init(_:)' risks causing data races between actor-isolated and local nonisolated uses}} let _ = { @MainActor in // expected-note {{access can happen concurrently}} print(k) } } func initActorWithSyncNonIsolatedInit2(_ k: NonSendableKlass) { // TODO: This should say actor isolated. _ = ActorWithSynchronousNonIsolatedInit(k) // expected-error {{sending 'k' risks causing data races}} // expected-note @-1 {{sending task-isolated 'k' to actor-isolated initializer 'init(_:)' risks causing data races between actor-isolated and task-isolated uses}} let _ = { @MainActor in print(k) // expected-error {{sending 'k' risks causing data races}} // expected-note @-1 {{task-isolated 'k' is captured by a main actor-isolated closure. main actor-isolated uses in closure may race against later nonisolated uses}} } } actor ActorWithAsyncIsolatedInit { init(_ newK: NonSendableKlass) async { let _ = { @MainActor in print(newK) // expected-error {{sending 'newK' risks causing data races}} // expected-note @-1 {{'self'-isolated 'newK' is captured by a main actor-isolated closure. main actor-isolated uses in closure may race against later actor-isolated uses}} } } } func initActorWithAsyncIsolatedInit() async { let k = NonSendableKlass() // TODO: This should say actor isolated. _ = await ActorWithAsyncIsolatedInit(k) // expected-error {{sending 'k' risks causing data races}} // expected-note @-1 {{sending 'k' to actor-isolated initializer 'init(_:)' risks causing data races between actor-isolated and local nonisolated uses}} let _ = { @MainActor in // expected-note {{access can happen concurrently}} print(k) } } func initActorWithAsyncIsolatedInit2(_ k: NonSendableKlass) async { // TODO: This should say actor isolated. _ = await ActorWithAsyncIsolatedInit(k) // expected-error {{sending 'k' risks causing data races}} // expected-note @-1 {{sending task-isolated 'k' to actor-isolated initializer 'init(_:)' risks causing data races between actor-isolated and task-isolated uses}} let _ = { @MainActor in print(k) // expected-error {{sending 'k' risks causing data races}} // expected-note @-1 {{task-isolated 'k' is captured by a main actor-isolated closure. main actor-isolated uses in closure may race against later nonisolated uses}} } } //////////////////////////////// // MARK: Actor Isolated Class // //////////////////////////////// @CustomActor class ClassWithSynchronousNonIsolatedInit { nonisolated init(_ newK: NonSendableKlass) { // We do not error on this since helper is nonisolated and newK is // considered task isolated. helper(newK) let _ = { @MainActor in print(newK) // expected-error {{sending 'newK' risks causing data races}} // expected-note @-1 {{task-isolated 'newK' is captured by a main actor-isolated closure. main actor-isolated uses in closure may race against later nonisolated uses}} } } nonisolated func helper(_ newK: NonSendableKlass) {} } func initClassWithSyncNonIsolatedInit() { let k = NonSendableKlass() _ = ClassWithSynchronousNonIsolatedInit(k) let _ = { @MainActor in print(k) } } func initClassWithSyncNonIsolatedInit2(_ k: NonSendableKlass) { _ = ClassWithSynchronousNonIsolatedInit(k) let _ = { @MainActor in print(k) // expected-error {{sending 'k' risks causing data races}} // expected-note @-1 {{task-isolated 'k' is captured by a main actor-isolated closure. main actor-isolated uses in closure may race against later nonisolated uses}} } } @CustomActor class ClassWithAsyncIsolatedInit { init(_ newK: NonSendableKlass) async { let _ = { @MainActor in print(newK) // expected-error {{sending 'newK' risks causing data races}} // expected-note @-1 {{global actor 'CustomActor'-isolated 'newK' is captured by a main actor-isolated closure. main actor-isolated uses in closure may race against later global actor 'CustomActor'-isolated uses}} } } } func initClassWithAsyncIsolatedInit() async { let k = NonSendableKlass() // TODO: Might make sense to emit a more specific error here since the closure // is MainActor isolated. The actual capture is initially not isolated to // MainActor. _ = await ClassWithAsyncIsolatedInit(k) // expected-error {{sending 'k' risks causing data races}} // expected-note @-1 {{sending 'k' to global actor 'CustomActor'-isolated initializer 'init(_:)' risks causing data races between global actor 'CustomActor'-isolated and local nonisolated uses}} let _ = { @MainActor in // expected-note {{access can happen concurrently}} print(k) } } func initClassWithAsyncIsolatedInit2(_ k: NonSendableKlass) async { _ = await ClassWithAsyncIsolatedInit(k) // expected-error {{sending 'k' risks causing data races}} // expected-note @-1 {{sending task-isolated 'k' to global actor 'CustomActor'-isolated initializer 'init(_:)' risks causing data races between global actor 'CustomActor'-isolated and task-isolated uses}} let _ = { @MainActor in print(k) // expected-error {{sending 'k' risks causing data races}} // expected-note @-1 {{task-isolated 'k' is captured by a main actor-isolated closure. main actor-isolated uses in closure may race against later nonisolated uses}} } }