Skip to content

Commit 072d541

Browse files
committed
[flow-isolation] Allow for initialization of fields of a Global Actor isolated class in its nonisolated inits
This just involved loosening some checks in the type checker so we stopped erroring in the type checker and instead deferred to SIL level checks. rdar://131136194
1 parent c287f53 commit 072d541

File tree

2 files changed

+84
-3
lines changed

2 files changed

+84
-3
lines changed

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7870,6 +7870,19 @@ ActorReferenceResult ActorReferenceResult::forReference(
78707870
(!actorInstance || actorInstance->isSelf())) {
78717871
auto type = fromDC->mapTypeIntoContext(decl->getInterfaceType());
78727872
if (!type->isSendableType()) {
7873+
// If we have an actor instance and our declIsolation is global actor
7874+
// isolated, but our context isolation is nonisolated... defer to flow
7875+
// isolation for additional checking.
7876+
//
7877+
// NOTE: We also require this to pass additional restrictions validated
7878+
// by checkedByFlowIsolation (e.x.: the initializer's nominal type has
7879+
// to be isolated).
7880+
if (actorInstance &&
7881+
declIsolation.isGlobalActor() && contextIsolation.isNonisolated() &&
7882+
checkedByFlowIsolation(fromDC, *actorInstance, decl, declRefLoc, useKind)) {
7883+
return forSameConcurrencyDomain(declIsolation, options);
7884+
}
7885+
78737886
// Treat the decl isolation as 'preconcurrency' to downgrade violations
78747887
// to warnings, because violating Sendable here is accepted by the
78757888
// Swift 5.9 compiler.

test/Concurrency/flow_isolation.swift

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,13 @@ struct Money {
3232
}
3333
}
3434

35+
actor OtherActorBackingActor { }
36+
37+
@globalActor
38+
struct OtherActor {
39+
static let shared = OtherActorBackingActor()
40+
}
41+
3542
@available(SwiftStdlib 5.1, *)
3643
func takeBob(_ b: Bob) {}
3744

@@ -832,17 +839,78 @@ func testActorWithInitAccessorInit() {
832839

833840
@available(SwiftStdlib 5.1, *)
834841
actor TestNonisolatedUnsafe {
835-
private nonisolated(unsafe) var child: OtherActor!
842+
private nonisolated(unsafe) var child: MyOtherActor!
836843
init() {
837-
child = OtherActor(parent: self)
844+
child = MyOtherActor(parent: self)
838845
}
839846
}
840847

841848
@available(SwiftStdlib 5.1, *)
842-
actor OtherActor {
849+
actor MyOtherActor {
843850
unowned nonisolated let parent: any Actor
844851

845852
init(parent: any Actor) {
846853
self.parent = parent
847854
}
848855
}
856+
857+
func globalActorNonIsolatedInitializerTests() {
858+
@MainActor
859+
class C {
860+
let ns: NonSendableType
861+
862+
nonisolated init() {
863+
self.ns = NonSendableType()
864+
}
865+
866+
nonisolated init(x: NonSendableType) {
867+
self.ns = x
868+
}
869+
870+
nonisolated func doSomething() {}
871+
872+
nonisolated init(x2 x: NonSendableType) {
873+
self.ns = x
874+
doSomething() // expected-note {{after calling instance method 'doSomething()', only nonisolated properties of 'self' can be accessed from this init}}
875+
print(self.ns) // expected-warning {{cannot access property 'ns' here in nonisolated initializer}}
876+
}
877+
}
878+
879+
// Make sure this does not apply in cases where self is not actor isolated.
880+
class D {
881+
@MainActor let ns: NonSendableType // expected-note {{mutation of this property is only permitted within the actor}}
882+
883+
nonisolated init() {
884+
self.ns = NonSendableType() // expected-warning {{main actor-isolated property 'ns' can not be mutated from a nonisolated context}}
885+
}
886+
}
887+
888+
actor A {
889+
@MainActor let ns: NonSendableType
890+
891+
init() {
892+
self.ns = NonSendableType()
893+
}
894+
}
895+
896+
@MainActor
897+
class C2 {
898+
@OtherActor let ns: NonSendableType
899+
900+
nonisolated init() {
901+
self.ns = NonSendableType()
902+
}
903+
904+
nonisolated init(_ x: NonSendableType) {
905+
self.ns = x
906+
}
907+
908+
nonisolated func doSomething() {}
909+
910+
nonisolated init(x2 x: NonSendableType) {
911+
self.ns = x
912+
doSomething() // expected-note {{after calling instance method 'doSomething()', only nonisolated properties of 'self' can be accessed from this init}}
913+
print(self.ns) // expected-warning {{cannot access property 'ns' here in nonisolated initializer}}
914+
}
915+
}
916+
}

0 commit comments

Comments
 (0)