diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 232144ebd4a9f..6e005e032dc69 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -5234,8 +5234,8 @@ ERROR(concurrent_access_local,none, "use of local %kind0 in concurrently-executing code", (const ValueDecl *)) ERROR(actor_isolated_keypath_component,none, - "cannot form key path to%select{| distributed}0 actor-isolated %kind1", - (bool, const ValueDecl *)) + "cannot form key path to %0 %kind1", + (ActorIsolation, const ValueDecl *)) ERROR(effectful_keypath_component,none, "cannot form key path to %0 with 'throws' or 'async'", (DescriptiveDeclKind)) diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index 6287e6ded386b..2fdddb2079805 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -3319,8 +3319,8 @@ namespace { for (const auto &component : keyPath->getComponents()) { // The decl referred to by the path component cannot be within an actor. if (component.hasDeclRef()) { - auto concDecl = component.getDeclRef(); - auto decl = concDecl.getDecl(); + auto declRef = component.getDeclRef(); + auto decl = declRef.getDecl(); auto isolation = getActorIsolationForReference( decl, getDeclContext()); switch (isolation) { @@ -3330,13 +3330,22 @@ namespace { break; case ActorIsolation::GlobalActor: - case ActorIsolation::GlobalActorUnsafe: - // Disable global actor checking for now. - if (isolation.isGlobalActor() && - !ctx.LangOpts.isSwiftVersionAtLeast(6)) + case ActorIsolation::GlobalActorUnsafe: { + // Perform the check only in `complete` mode or + // stricter. + if (ctx.LangOpts.StrictConcurrencyLevel < + StrictConcurrency::Complete) + break; + + auto result = ActorReferenceResult::forReference( + declRef, component.getLoc(), getDeclContext(), + kindOfUsage(decl, keyPath)); + + if (result == ActorReferenceResult::SameConcurrencyDomain) break; LLVM_FALLTHROUGH; + } case ActorIsolation::ActorInstance: // If this entity is always accessible across actors, just check @@ -3352,11 +3361,17 @@ namespace { break; } - ctx.Diags.diagnose(component.getLoc(), - diag::actor_isolated_keypath_component, - isolation.isDistributedActor(), - decl); - diagnosed = true; + { + auto diagnostic = ctx.Diags.diagnose( + component.getLoc(), diag::actor_isolated_keypath_component, + isolation, decl); + + if (isolation == ActorIsolation::ActorInstance) + diagnosed = true; + else + diagnostic.warnUntilSwiftVersion(6); + } + break; } } diff --git a/test/Concurrency/actor_keypath_isolation.swift b/test/Concurrency/actor_keypath_isolation.swift index de8d70ab1d65b..840a807b2412c 100644 --- a/test/Concurrency/actor_keypath_isolation.swift +++ b/test/Concurrency/actor_keypath_isolation.swift @@ -58,7 +58,7 @@ func tryKeyPathsMisc(d : Door) { func tryKeyPathsFromAsync() async { _ = \Door.unsafeGlobActor_immutable - _ = \Door.unsafeGlobActor_mutable // okay for now + _ = \Door.unsafeGlobActor_mutable // expected-warning {{cannot form key path to main actor-isolated property 'unsafeGlobActor_mutable'; this is an error in Swift 6}} } func tryNonSendable() { @@ -69,7 +69,7 @@ func tryNonSendable() { func tryKeypaths() { _ = \Door.unsafeGlobActor_immutable - _ = \Door.unsafeGlobActor_mutable // okay for now + _ = \Door.unsafeGlobActor_mutable // expected-warning {{cannot form key path to main actor-isolated property 'unsafeGlobActor_mutable'; this is an error in Swift 6}} _ = \Door.immutable _ = \Door.globActor_immutable @@ -84,7 +84,13 @@ func tryKeypaths() { let _ : PartialKeyPath = \.mutable // expected-error{{cannot form key path to actor-isolated property 'mutable'}} let _ : AnyKeyPath = \Door.mutable // expected-error{{cannot form key path to actor-isolated property 'mutable'}} - _ = \Door.globActor_mutable // okay for now + _ = \Door.globActor_mutable // expected-warning {{cannot form key path to main actor-isolated property 'globActor_mutable'; this is an error in Swift 6}} _ = \Door.[0] // expected-error{{cannot form key path to actor-isolated subscript 'subscript(_:)'}} - _ = \Door.["hello"] // okay for now + _ = \Door.["hello"] // expected-warning {{cannot form key path to main actor-isolated subscript 'subscript(_:)'; this is an error in Swift 6}} +} + +@MainActor func testGlobalActorRefInSameContext() { + _ = \Door.unsafeGlobActor_mutable // Ok + _ = \Door.globActor_mutable // Ok + _ = \Door.["hello"] // Ok } diff --git a/test/Concurrency/actor_keypath_isolation_swift6.swift b/test/Concurrency/actor_keypath_isolation_swift6.swift index 0a314d411c441..60f7bacdae1ad 100644 --- a/test/Concurrency/actor_keypath_isolation_swift6.swift +++ b/test/Concurrency/actor_keypath_isolation_swift6.swift @@ -57,7 +57,7 @@ func tryKeyPathsMisc(d : Door) { func tryKeyPathsFromAsync() async { _ = \Door.unsafeGlobActor_immutable - _ = \Door.unsafeGlobActor_mutable // expected-error {{cannot form key path to actor-isolated property 'unsafeGlobActor_mutable'}} + _ = \Door.unsafeGlobActor_mutable // expected-error {{cannot form key path to main actor-isolated property 'unsafeGlobActor_mutable'}} } func tryNonSendable() { @@ -68,7 +68,7 @@ func tryNonSendable() { func tryKeypaths() { _ = \Door.unsafeGlobActor_immutable - _ = \Door.unsafeGlobActor_mutable // expected-error {{cannot form key path to actor-isolated property 'unsafeGlobActor_mutable'}} + _ = \Door.unsafeGlobActor_mutable // expected-error {{cannot form key path to main actor-isolated property 'unsafeGlobActor_mutable'}} _ = \Door.immutable _ = \Door.globActor_immutable @@ -83,7 +83,13 @@ func tryKeypaths() { let _ : PartialKeyPath = \.mutable // expected-error{{cannot form key path to actor-isolated property 'mutable'}} let _ : AnyKeyPath = \Door.mutable // expected-error{{cannot form key path to actor-isolated property 'mutable'}} - _ = \Door.globActor_mutable // expected-error{{cannot form key path to actor-isolated property 'globActor_mutable'}} + _ = \Door.globActor_mutable // expected-error{{cannot form key path to main actor-isolated property 'globActor_mutable'}} _ = \Door.[0] // expected-error{{cannot form key path to actor-isolated subscript 'subscript(_:)'}} - _ = \Door.["hello"] // expected-error {{cannot form key path to actor-isolated subscript 'subscript(_:)'}} + _ = \Door.["hello"] // expected-error {{cannot form key path to main actor-isolated subscript 'subscript(_:)'}} +} + +@MainActor func testGlobalActorRefInSameContext() { + _ = \Door.unsafeGlobActor_mutable // Ok + _ = \Door.globActor_mutable // Ok + _ = \Door.["hello"] // Ok } diff --git a/test/Concurrency/global_actor_keypath_non_strict.swift b/test/Concurrency/global_actor_keypath_non_strict.swift new file mode 100644 index 0000000000000..d9c5f86f6655c --- /dev/null +++ b/test/Concurrency/global_actor_keypath_non_strict.swift @@ -0,0 +1,25 @@ +// RUN: %target-swift-frontend -disable-availability-checking %s -emit-sil -o /dev/null -verify + +// REQUIRES: concurrency && asserts + +actor Door { + @MainActor var globActor_mutable : Int = 0 + @MainActor(unsafe) var unsafeGlobActor_mutable : Int = 0 + @MainActor subscript(byName: String) -> Int { 0 } +} + +func tryKeyPathsFromAsync() async { + _ = \Door.unsafeGlobActor_mutable // no warning +} + +func tryKeypaths() { + _ = \Door.unsafeGlobActor_mutable // no warning + _ = \Door.globActor_mutable // no warning + _ = \Door.["hello"] // no warning +} + +@MainActor func testGlobalActorRefInSameContext() { + _ = \Door.unsafeGlobActor_mutable // Ok + _ = \Door.globActor_mutable // Ok + _ = \Door.["hello"] // Ok +}