Skip to content

Commit b0d4ba0

Browse files
authored
Merge pull request swiftlang#70285 from xedin/keypath-with-global-actors
[Concurrency] Key paths and global actors
2 parents d36173a + e561ac4 commit b0d4ba0

File tree

6 files changed

+110
-21
lines changed

6 files changed

+110
-21
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5410,8 +5410,8 @@ ERROR(concurrent_access_local,none,
54105410
"use of local %kind0 in concurrently-executing code",
54115411
(const ValueDecl *))
54125412
ERROR(actor_isolated_keypath_component,none,
5413-
"cannot form key path to%select{| distributed}0 actor-isolated %kind1",
5414-
(bool, const ValueDecl *))
5413+
"cannot form key path to %0 %kind1",
5414+
(ActorIsolation, const ValueDecl *))
54155415
ERROR(effectful_keypath_component,none,
54165416
"cannot form key path to %0 with 'throws' or 'async'",
54175417
(DescriptiveDeclKind))

lib/Sema/ConstraintSystem.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7494,6 +7494,11 @@ ConstraintSystem::inferKeyPathLiteralCapability(KeyPathExpr *keyPath) {
74947494
auto *sendable = Context.getProtocol(KnownProtocolKind::Sendable);
74957495

74967496
for (const auto &arg : *args) {
7497+
// No need to check more or delay since we already known
7498+
// that the type is not Sendable.
7499+
if (!isSendable)
7500+
break;
7501+
74977502
auto argTy = simplifyType(getType(arg.getExpr()));
74987503

74997504
// Sendability cannot be determined until the argument
@@ -7546,6 +7551,20 @@ ConstraintSystem::inferKeyPathLiteralCapability(KeyPathExpr *keyPath) {
75467551
if (!storage)
75477552
return fail();
75487553

7554+
switch (getActorIsolation(storage)) {
7555+
case ActorIsolation::Unspecified:
7556+
case ActorIsolation::Nonisolated:
7557+
case ActorIsolation::NonisolatedUnsafe:
7558+
break;
7559+
7560+
// A reference to an actor isolated state make key path non-Sendable.
7561+
case ActorIsolation::ActorInstance:
7562+
case ActorIsolation::GlobalActor:
7563+
case ActorIsolation::GlobalActorUnsafe:
7564+
isSendable = false;
7565+
break;
7566+
}
7567+
75497568
if (isReadOnlyKeyPathComponent(storage, component.getLoc())) {
75507569
mutability = KeyPathMutability::ReadOnly;
75517570
continue;

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3355,8 +3355,8 @@ namespace {
33553355
for (const auto &component : keyPath->getComponents()) {
33563356
// The decl referred to by the path component cannot be within an actor.
33573357
if (component.hasDeclRef()) {
3358-
auto concDecl = component.getDeclRef();
3359-
auto decl = concDecl.getDecl();
3358+
auto declRef = component.getDeclRef();
3359+
auto decl = declRef.getDecl();
33603360
auto isolation = getActorIsolationForReference(
33613361
decl, getDeclContext());
33623362
switch (isolation) {
@@ -3366,13 +3366,16 @@ namespace {
33663366
break;
33673367

33683368
case ActorIsolation::GlobalActor:
3369-
case ActorIsolation::GlobalActorUnsafe:
3370-
// Disable global actor checking for now.
3371-
if (isolation.isGlobalActor() &&
3372-
!ctx.LangOpts.isSwiftVersionAtLeast(6))
3369+
case ActorIsolation::GlobalActorUnsafe: {
3370+
auto result = ActorReferenceResult::forReference(
3371+
declRef, component.getLoc(), getDeclContext(),
3372+
kindOfUsage(decl, keyPath));
3373+
3374+
if (result == ActorReferenceResult::SameConcurrencyDomain)
33733375
break;
33743376

33753377
LLVM_FALLTHROUGH;
3378+
}
33763379

33773380
case ActorIsolation::ActorInstance:
33783381
// If this entity is always accessible across actors, just check
@@ -3388,11 +3391,17 @@ namespace {
33883391
break;
33893392
}
33903393

3391-
ctx.Diags.diagnose(component.getLoc(),
3392-
diag::actor_isolated_keypath_component,
3393-
isolation.isDistributedActor(),
3394-
decl);
3395-
diagnosed = true;
3394+
{
3395+
auto diagnostic = ctx.Diags.diagnose(
3396+
component.getLoc(), diag::actor_isolated_keypath_component,
3397+
isolation, decl);
3398+
3399+
if (isolation == ActorIsolation::ActorInstance)
3400+
diagnosed = true;
3401+
else
3402+
diagnostic.warnUntilSwiftVersion(6);
3403+
}
3404+
33963405
break;
33973406
}
33983407
}

test/Concurrency/actor_keypath_isolation.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ func tryKeyPathsMisc(d : Door) {
5858

5959
func tryKeyPathsFromAsync() async {
6060
_ = \Door.unsafeGlobActor_immutable
61-
_ = \Door.unsafeGlobActor_mutable // okay for now
61+
_ = \Door.unsafeGlobActor_mutable // expected-warning {{cannot form key path to main actor-isolated property 'unsafeGlobActor_mutable'; this is an error in Swift 6}}
6262
}
6363

6464
func tryNonSendable() {
@@ -69,7 +69,7 @@ func tryNonSendable() {
6969

7070
func tryKeypaths() {
7171
_ = \Door.unsafeGlobActor_immutable
72-
_ = \Door.unsafeGlobActor_mutable // okay for now
72+
_ = \Door.unsafeGlobActor_mutable // expected-warning {{cannot form key path to main actor-isolated property 'unsafeGlobActor_mutable'; this is an error in Swift 6}}
7373

7474
_ = \Door.immutable
7575
_ = \Door.globActor_immutable
@@ -84,7 +84,7 @@ func tryKeypaths() {
8484
let _ : PartialKeyPath<Door> = \.mutable // expected-error{{cannot form key path to actor-isolated property 'mutable'}}
8585
let _ : AnyKeyPath = \Door.mutable // expected-error{{cannot form key path to actor-isolated property 'mutable'}}
8686

87-
_ = \Door.globActor_mutable // okay for now
87+
_ = \Door.globActor_mutable // expected-warning {{cannot form key path to main actor-isolated property 'globActor_mutable'; this is an error in Swift 6}}
8888
_ = \Door.[0] // expected-error{{cannot form key path to actor-isolated subscript 'subscript(_:)'}}
89-
_ = \Door.["hello"] // okay for now
89+
_ = \Door.["hello"] // expected-warning {{cannot form key path to main actor-isolated subscript 'subscript(_:)'; this is an error in Swift 6}}
9090
}

test/Concurrency/actor_keypath_isolation_swift6.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func tryKeyPathsMisc(d : Door) {
5757

5858
func tryKeyPathsFromAsync() async {
5959
_ = \Door.unsafeGlobActor_immutable
60-
_ = \Door.unsafeGlobActor_mutable // expected-error {{cannot form key path to actor-isolated property 'unsafeGlobActor_mutable'}}
60+
_ = \Door.unsafeGlobActor_mutable // expected-error {{cannot form key path to main actor-isolated property 'unsafeGlobActor_mutable'}}
6161
}
6262

6363
func tryNonSendable() {
@@ -68,7 +68,7 @@ func tryNonSendable() {
6868

6969
func tryKeypaths() {
7070
_ = \Door.unsafeGlobActor_immutable
71-
_ = \Door.unsafeGlobActor_mutable // expected-error {{cannot form key path to actor-isolated property 'unsafeGlobActor_mutable'}}
71+
_ = \Door.unsafeGlobActor_mutable // expected-error {{cannot form key path to main actor-isolated property 'unsafeGlobActor_mutable'}}
7272

7373
_ = \Door.immutable
7474
_ = \Door.globActor_immutable
@@ -83,7 +83,7 @@ func tryKeypaths() {
8383
let _ : PartialKeyPath<Door> = \.mutable // expected-error{{cannot form key path to actor-isolated property 'mutable'}}
8484
let _ : AnyKeyPath = \Door.mutable // expected-error{{cannot form key path to actor-isolated property 'mutable'}}
8585

86-
_ = \Door.globActor_mutable // expected-error{{cannot form key path to actor-isolated property 'globActor_mutable'}}
86+
_ = \Door.globActor_mutable // expected-error{{cannot form key path to main actor-isolated property 'globActor_mutable'}}
8787
_ = \Door.[0] // expected-error{{cannot form key path to actor-isolated subscript 'subscript(_:)'}}
88-
_ = \Door.["hello"] // expected-error {{cannot form key path to actor-isolated subscript 'subscript(_:)'}}
88+
_ = \Door.["hello"] // expected-error {{cannot form key path to main actor-isolated subscript 'subscript(_:)'}}
8989
}

test/Concurrency/sendable_keypaths.swift

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,64 @@ do {
138138

139139
_ = Test(obj: "Hello").utf8.count // Ok
140140
}
141+
142+
// Global actor isolated properties.
143+
func testGlobalActorIsolatedReferences() {
144+
@MainActor struct Isolated {
145+
var data: Int = 42
146+
subscript(v: Int) -> Bool { false }
147+
}
148+
149+
let dataKP = \Isolated.data
150+
// expected-warning@-1 {{cannot form key path to main actor-isolated property 'data'; this is an error in Swift 6}}
151+
let subscriptKP = \Isolated.[42]
152+
// expected-warning@-1 {{cannot form key path to main actor-isolated subscript 'subscript(_:)'; this is an error in Swift 6}}
153+
154+
let _: KeyPath<Isolated, Int> & Sendable = dataKP
155+
// expected-warning@-1 {{type 'WritableKeyPath<Isolated, Int>' does not conform to the 'Sendable' protocol}}
156+
let _: KeyPath<Isolated, Bool> & Sendable = subscriptKP
157+
// expected-warning@-1 {{type 'KeyPath<Isolated, Bool>' does not conform to the 'Sendable' protocol}}
158+
159+
func testNonIsolated() {
160+
_ = \Isolated.data
161+
// expected-warning@-1 {{cannot form key path to main actor-isolated property 'data'; this is an error in Swift 6}}
162+
}
163+
164+
@MainActor func testIsolated() {
165+
_ = \Isolated.data // Ok
166+
}
167+
}
168+
169+
@available(SwiftStdlib 5.1, *)
170+
actor SomeActor {
171+
}
172+
173+
@available(SwiftStdlib 5.1, *)
174+
@globalActor
175+
actor GlobalActor {
176+
static let shared: SomeActor = SomeActor()
177+
}
178+
179+
@available(SwiftStdlib 5.1, *)
180+
func testReferencesToDifferentGlobalActorIsolatedMembers() {
181+
struct Info {
182+
@MainActor var name: String { "" }
183+
}
184+
185+
struct Isolated {
186+
@GlobalActor var info: Info { Info() }
187+
}
188+
189+
@MainActor func testIsolatedToMain() {
190+
_ = \Info.name // Ok
191+
_ = \Isolated.info.name
192+
// expected-warning@-1 {{cannot form key path to global actor 'GlobalActor'-isolated property 'info'; this is an error in Swift 6}}
193+
}
194+
195+
@GlobalActor func testIsolatedToCustom() {
196+
_ = \Info.name // Ok
197+
// expected-warning@-1 {{cannot form key path to main actor-isolated property 'name'; this is an error in Swift 6}}
198+
_ = \Isolated.info.name
199+
// expected-warning@-1 {{cannot form key path to main actor-isolated property 'name'; this is an error in Swift 6}}
200+
}
201+
}

0 commit comments

Comments
 (0)