Files
swift-mirror/test/Concurrency/transfernonsendable_initializers.swift
Michael Gottesman 399bb5d9a1 [rbi] Replace "task-isolated" with "code in the current isolation context" in diagnostics
"Task-isolated" is an internal implementation term that is not meaningful
to users. Replace it with the user-facing "code in the current isolation context"
formulation throughout region-based isolation diagnostics.

Diagnostic definitions in DiagnosticsSIL.def are updated to accept an
additional bool parameter for task-isolation and use %select to choose
between the actor-isolation string and "code in the current isolation context".
Emission sites in SendNonSendable.cpp are updated to pass
isTaskIsolated() at each call site. All affected test expectations are
updated to match the new output.

rdar://178534037
2026-06-02 09:29:58 -07:00

247 lines
9.2 KiB
Swift

// 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: 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 {{'self'-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 {{'self'-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
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 'k' to actor-isolated initializer 'init(_:)' risks causing data races between actor-isolated code and code in the current isolation context}}
let _ = { @MainActor in
print(k) // expected-error {{sending 'k' risks causing data races}}
// expected-note @-1 {{'k' is captured by a main actor-isolated closure. main actor-isolated uses in closure may race against code in the current isolation context}}
}
}
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 'k' to actor-isolated initializer 'init(_:)' risks causing data races between actor-isolated code and code in the current isolation context}}
let _ = { @MainActor in
print(k) // expected-error {{sending 'k' risks causing data races}}
// expected-note @-1 {{'k' is captured by a main actor-isolated closure. main actor-isolated uses in closure may race against code in the current isolation context}}
}
}
////////////////////////////////
// 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 {{'newK' is captured by a main actor-isolated closure. main actor-isolated uses in closure may race against code in the current isolation context}}
}
}
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 {{'k' is captured by a main actor-isolated closure. main actor-isolated uses in closure may race against code in the current isolation context}}
}
}
@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 'k' to global actor 'CustomActor'-isolated initializer 'init(_:)' risks causing data races between global actor 'CustomActor'-isolated code and code in the current isolation context}}
let _ = { @MainActor in
print(k) // expected-error {{sending 'k' risks causing data races}}
// expected-note @-1 {{'k' is captured by a main actor-isolated closure. main actor-isolated uses in closure may race against code in the current isolation context}}
}
}
// Iterating over an existential sequence parameter must not produce false
// positive RBI errors in any of these isolation contexts.
actor ActorWithExistentialSequenceInit {
init(sequence: any Sequence<Int>) {
for element in sequence {
_ = element
}
}
}
@MainActor
class MainActorClassWithExistentialSequenceInit {
init(sequence: any Sequence<Int>) {
for element in sequence {
_ = element
}
}
}
@CustomActor
class CustomActorClassWithExistentialSequenceInit {
init(sequence: any Sequence<Int>) async {
for element in sequence {
_ = element
}
}
}
func nonisolatedFuncWithExistentialSequence(sequence: any Sequence<Int>) {
for element in sequence {
_ = element
}
}
// Class-constrained variant: the iterator associated type is AnyObject-constrained,
// so erasing it into an existential uses init_existential_ref (not init_existential_addr).
// This exercises the visitInitExistentialRefInst fix path.
protocol FakeClassIterator: AnyObject {
func nextElement()
}
protocol FakeClassSequence {
associatedtype Iterator: FakeClassIterator
func makeIterator() -> Iterator
}
actor ActorWithClassExistentialSequenceInit {
init(sequence: any FakeClassSequence) {
let iter: any FakeClassIterator = sequence.makeIterator()
iter.nextElement()
}
}
@MainActor
class MainActorClassWithClassExistentialSequenceInit {
init(sequence: any FakeClassSequence) {
let iter: any FakeClassIterator = sequence.makeIterator()
iter.nextElement()
}
}
func nonisolatedFuncWithClassExistentialSequence(sequence: any FakeClassSequence) {
let iter: any FakeClassIterator = sequence.makeIterator()
iter.nextElement()
}