Skip to content

Commit 7122a11

Browse files
authored
Merge pull request #79895 from simanerush/allow-explicit-nonisolated-for-lazy-and-prop-wrappers
[Concurrency] Allow explicit 'nonisolated' on lazy properties and properties with property wrappers if they are a member of a non-'Sendable' type.
2 parents 8fdde43 + c10bdf1 commit 7122a11

File tree

8 files changed

+86
-79
lines changed

8 files changed

+86
-79
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6067,12 +6067,6 @@ ERROR(nonisolated_local_var,none,
60676067
ERROR(nonisolated_actor_sync_init,none,
60686068
"'nonisolated' on an actor's synchronous initializer is invalid",
60696069
())
6070-
ERROR(nonisolated_wrapped_property,none,
6071-
"'nonisolated' is not supported on properties with property wrappers",
6072-
())
6073-
ERROR(nonisolated_lazy,none,
6074-
"'nonisolated' is not supported on lazy properties",
6075-
())
60766070

60776071
ERROR(non_sendable_from_deinit,none,
60786072
"cannot access %kind1 with a non-Sendable type %0 from nonisolated "

lib/Sema/TypeCheckAttr.cpp

Lines changed: 48 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -7810,31 +7810,68 @@ void AttributeChecker::visitNonisolatedAttr(NonisolatedAttr *attr) {
78107810
if (auto var = dyn_cast<VarDecl>(D)) {
78117811
// stored properties have limitations as to when they can be nonisolated.
78127812
auto type = var->getTypeInContext();
7813-
if (var->hasStorage()) {
7813+
if (var->hasStorage() || var->hasAttachedPropertyWrapper() ||
7814+
var->getAttrs().hasAttribute<LazyAttr>()) {
7815+
7816+
if (auto nominal = dyn_cast<NominalTypeDecl>(dc)) {
7817+
// 'nonisolated' can not be applied to stored properties inside
7818+
// distributed actors. Attempts of nonisolated access would be
7819+
// cross-actor, which means they might be accessing on a remote actor,
7820+
// in which case the stored property storage does not exist.
7821+
//
7822+
// The synthesized "id" and "actorSystem" are the only exceptions,
7823+
// because the implementation mirrors them.
7824+
if (nominal->isDistributedActor() &&
7825+
!(var->getName() == Ctx.Id_id ||
7826+
var->getName() == Ctx.Id_actorSystem)) {
7827+
diagnoseAndRemoveAttr(attr,
7828+
diag::nonisolated_distributed_actor_storage);
7829+
return;
7830+
}
7831+
}
7832+
78147833
{
78157834
// A stored property can be 'nonisolated' if it is a 'Sendable' member
78167835
// of a 'Sendable' value type.
7836+
// The above rule does not apply to lazy properties and properties with
7837+
// property wrappers, because backing storage is a stored
7838+
// 'var' that is part of the internal state of the actor which could
7839+
// only be accessed in actor's isolation context.
78177840
bool canBeNonisolated = false;
78187841
if (auto nominal = dc->getSelfStructDecl()) {
7819-
if (nominal->getDeclaredTypeInContext()->isSendableType() &&
7842+
if (var->hasStorage() &&
7843+
nominal->getDeclaredTypeInContext()->isSendableType() &&
78207844
!var->isStatic() && type->isSendableType()) {
78217845
canBeNonisolated = true;
78227846
}
78237847
}
78247848

7825-
// Additionally, a stored property of a non-'Sendable' type can be
7826-
// explicitly marked 'nonisolated'.
7827-
if (auto parentDecl = dc->getDeclaredTypeInContext())
7828-
if (!parentDecl->isSendableType()) {
7829-
canBeNonisolated = true;
7830-
}
7849+
// Additionally, a stored property of a non-'Sendable' type can be
7850+
// explicitly marked 'nonisolated'.
7851+
if (auto parentDecl = dc->getDeclaredTypeInContext())
7852+
if (!parentDecl->isSendableType()) {
7853+
canBeNonisolated = true;
7854+
}
78317855

78327856
// Otherwise, this stored property has to be qualified as 'unsafe'.
78337857
if (var->supportsMutation() && !attr->isUnsafe() && !canBeNonisolated) {
7834-
diagnoseAndRemoveAttr(attr, diag::nonisolated_mutable_storage)
7858+
if (var->hasAttachedPropertyWrapper()) {
7859+
diagnoseAndRemoveAttr(attr, diag::nonisolated_mutable_storage)
7860+
.warnUntilSwiftVersionIf(attr->isImplicit(), 6)
78357861
.fixItInsertAfter(attr->getRange().End, "(unsafe)");
7836-
var->diagnose(diag::nonisolated_mutable_storage_note, var);
7837-
return;
7862+
return;
7863+
} else if (var->getAttrs().hasAttribute<LazyAttr>()) {
7864+
diagnoseAndRemoveAttr(attr, diag::nonisolated_mutable_storage)
7865+
.warnUntilSwiftVersion(6)
7866+
.fixItInsertAfter(attr->getRange().End, "(unsafe)");
7867+
return;
7868+
} else {
7869+
diagnoseAndRemoveAttr(attr, diag::nonisolated_mutable_storage)
7870+
.fixItInsertAfter(attr->getRange().End, "(unsafe)");
7871+
if (var->hasStorage())
7872+
var->diagnose(diag::nonisolated_mutable_storage_note, var);
7873+
return;
7874+
}
78387875
}
78397876

78407877
// 'nonisolated' without '(unsafe)' is not allowed on non-Sendable
@@ -7848,23 +7885,6 @@ void AttributeChecker::visitNonisolatedAttr(NonisolatedAttr *attr) {
78487885
}
78497886
}
78507887

7851-
if (auto nominal = dyn_cast<NominalTypeDecl>(dc)) {
7852-
// 'nonisolated' can not be applied to stored properties inside
7853-
// distributed actors. Attempts of nonisolated access would be
7854-
// cross-actor, which means they might be accessing on a remote actor,
7855-
// in which case the stored property storage does not exist.
7856-
//
7857-
// The synthesized "id" and "actorSystem" are the only exceptions,
7858-
// because the implementation mirrors them.
7859-
if (nominal->isDistributedActor() &&
7860-
!(var->getName() == Ctx.Id_id ||
7861-
var->getName() == Ctx.Id_actorSystem)) {
7862-
diagnoseAndRemoveAttr(attr,
7863-
diag::nonisolated_distributed_actor_storage);
7864-
return;
7865-
}
7866-
}
7867-
78687888
// 'nonisolated(unsafe)' is redundant for 'Sendable' immutables.
78697889
if (attr->isUnsafe() &&
78707890
type->isSendableType() &&
@@ -7900,22 +7920,6 @@ void AttributeChecker::visitNonisolatedAttr(NonisolatedAttr *attr) {
79007920
}
79017921
}
79027922

7903-
// Using 'nonisolated' with lazy properties and wrapped properties is
7904-
// unsupported, because backing storage is a stored 'var' that is part
7905-
// of the internal state of the actor which could only be accessed in
7906-
// actor's isolation context.
7907-
if (var->hasAttachedPropertyWrapper()) {
7908-
diagnoseAndRemoveAttr(attr, diag::nonisolated_wrapped_property)
7909-
.warnUntilSwiftVersionIf(attr->isImplicit(), 6);
7910-
return;
7911-
}
7912-
7913-
if (var->getAttrs().hasAttribute<LazyAttr>()) {
7914-
diagnose(attr->getLocation(), diag::nonisolated_lazy)
7915-
.warnUntilSwiftVersion(6);
7916-
return;
7917-
}
7918-
79197923
// nonisolated can not be applied to local properties unless qualified as
79207924
// 'unsafe'.
79217925
if (dc->isLocalContext() && !attr->isUnsafe()) {

test/Concurrency/actor_isolation.swift

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -813,31 +813,29 @@ actor LazyActor {
813813
lazy var l25: Int = { [unowned self] in self.l }()
814814

815815
nonisolated lazy var l31: Int = { v }()
816-
// expected-warning@-1 {{'nonisolated' is not supported on lazy properties; this is an error in the Swift 6 language mode}}
816+
// expected-warning@-1 {{'nonisolated' cannot be applied to mutable stored properties; this is an error in the Swift 6 language mode}}
817817
// expected-warning@-2 {{actor-isolated default value in a nonisolated context; this is an error in the Swift 6 language mode}}
818818
nonisolated lazy var l32: Int = v
819-
// expected-warning@-1 {{'nonisolated' is not supported on lazy properties; this is an error in the Swift 6 language mode}}
820-
// expected-warning@-2 {{actor-isolated default value in a nonisolated context; this is an error in the Swift 6 language mode}}
819+
// expected-warning@-1 {{'nonisolated' cannot be applied to mutable stored properties; this is an error in the Swift 6 language mode}}
821820
nonisolated lazy var l33: Int = { self.v }()
822-
// expected-warning@-1 {{'nonisolated' is not supported on lazy properties; this is an error in the Swift 6 language mode}}
821+
// expected-warning@-1 {{'nonisolated' cannot be applied to mutable stored properties; this is an error in the Swift 6 language mode}}
823822
// expected-warning@-2 {{actor-isolated default value in a nonisolated context; this is an error in the Swift 6 language mode}}
824823
nonisolated lazy var l34: Int = self.v
825-
// expected-warning@-1 {{'nonisolated' is not supported on lazy properties; this is an error in the Swift 6 language mode}}
826-
// expected-warning@-2 {{actor-isolated default value in a nonisolated context; this is an error in the Swift 6 language mode}}
824+
// expected-warning@-1 {{'nonisolated' cannot be applied to mutable stored properties; this is an error in the Swift 6 language mode}}
827825
nonisolated lazy var l35: Int = { [unowned self] in self.v }()
828-
// expected-warning@-1 {{'nonisolated' is not supported on lazy properties; this is an error in the Swift 6 language mode}}
826+
// expected-warning@-1 {{'nonisolated' cannot be applied to mutable stored properties; this is an error in the Swift 6 language mode}}
829827
// expected-warning@-2 {{actor-isolated default value in a nonisolated context; this is an error in the Swift 6 language mode}}
830828

831829
nonisolated lazy var l41: Int = { l }()
832-
// expected-warning@-1 {{'nonisolated' is not supported on lazy properties; this is an error in the Swift 6 language mode}}
830+
// expected-warning@-1 {{'nonisolated' cannot be applied to mutable stored properties; this is an error in the Swift 6 language mode}}
833831
nonisolated lazy var l42: Int = l
834-
// expected-warning@-1 {{'nonisolated' is not supported on lazy properties; this is an error in the Swift 6 language mode}}
832+
// expected-warning@-1 {{'nonisolated' cannot be applied to mutable stored properties; this is an error in the Swift 6 language mode}}
835833
nonisolated lazy var l43: Int = { self.l }()
836-
// expected-warning@-1 {{'nonisolated' is not supported on lazy properties; this is an error in the Swift 6 language mode}}
834+
// expected-warning@-1 {{'nonisolated' cannot be applied to mutable stored properties; this is an error in the Swift 6 language mode}}
837835
nonisolated lazy var l44: Int = self.l
838-
// expected-warning@-1 {{'nonisolated' is not supported on lazy properties; this is an error in the Swift 6 language mode}}
836+
// expected-warning@-1 {{'nonisolated' cannot be applied to mutable stored properties; this is an error in the Swift 6 language mode}}
839837
nonisolated lazy var l45: Int = { [unowned self] in self.l }()
840-
// expected-warning@-1 {{'nonisolated' is not supported on lazy properties; this is an error in the Swift 6 language mode}}
838+
// expected-warning@-1 {{'nonisolated' cannot be applied to mutable stored properties; this is an error in the Swift 6 language mode}}
841839
}
842840

843841
// Infer global actors from context only for instance members.

test/Concurrency/actor_isolation_objc.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,5 +65,7 @@ actor Pumpkin: NSObject {}
6565

6666
actor Bad {
6767
@objc nonisolated lazy var invalid = 0
68-
// expected-warning@-1 {{'nonisolated' is not supported on lazy properties; this is an error in the Swift 6 language mode}}
68+
// expected-warning@-1 {{'nonisolated' cannot be applied to mutable stored properties; this is an error in the Swift 6 language mode}}
69+
// expected-error@-2 {{actor-isolated setter for property 'invalid' cannot be '@objc'}}
70+
// expected-error@-3 {{actor-isolated getter for property 'invalid' cannot be '@objc'}}
6971
}

test/Concurrency/global_actor_inference.swift

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -400,8 +400,7 @@ struct HasWrapperOnActor {
400400
synced = 17
401401
}
402402

403-
@WrapperActor var actorSynced: Int = 0 // expected-warning{{'nonisolated' is not supported on properties with property wrappers}}
404-
403+
@WrapperActor var actorSynced: Int = 0 // expected-warning {{'nonisolated' cannot be applied to mutable stored properties}}
405404
func testActorSynced() {
406405
_ = actorSynced
407406
_ = $actorSynced
@@ -499,9 +498,8 @@ struct SimplePropertyWrapper {
499498

500499
@MainActor
501500
class WrappedContainsNonisolatedAttr {
502-
@SimplePropertyWrapper nonisolated var value
503-
// expected-error@-1 {{'nonisolated' is not supported on properties with property wrappers}}
504-
// expected-note@-2 {{property declared here}}
501+
@SimplePropertyWrapper nonisolated var value
502+
// expected-note@-1 {{property declared here}}
505503

506504
nonisolated func test() {
507505
_ = value

test/Concurrency/global_actor_inference_swift6.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ struct HasWrapperOnActor {
115115
synced = 17
116116
}
117117

118-
@WrapperActor var actorSynced: Int = 0 // expected-error{{'nonisolated' is not supported on properties with property wrappers}}
118+
@WrapperActor var actorSynced: Int = 0 // expected-error {{'nonisolated' cannot be applied to mutable stored properties}}
119119

120120
func testActorSynced() {
121121
_ = actorSynced

test/Concurrency/nonisolated_rules.swift

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ struct ImplicitlySendable {
3636
nonisolated var d = 0
3737

3838
// never okay
39-
nonisolated lazy var e = 0 // expected-error {{'nonisolated' is not supported on lazy properties}}
40-
@P nonisolated var f = 0 // expected-error {{'nonisolated' is not supported on properties with property wrappers}}
39+
nonisolated lazy var e = 0 // expected-error {{'nonisolated' cannot be applied to mutable stored properties}}
40+
@P nonisolated var f = 0 // expected-error {{'nonisolated' cannot be applied to mutable stored properties}}
4141
}
4242

4343
struct ImplicitlyNonSendable {
@@ -48,9 +48,9 @@ struct ImplicitlyNonSendable {
4848
nonisolated var c: Int { 0 }
4949
nonisolated var d = 0
5050

51-
// never okay
52-
nonisolated lazy var e = 0 // expected-error {{'nonisolated' is not supported on lazy properties}}
53-
@P nonisolated var f = 0 // expected-error {{'nonisolated' is not supported on properties with property wrappers}}
51+
// okay, the type is non-'Sendable'
52+
nonisolated lazy var e = 0
53+
@P nonisolated var f = 0
5454
}
5555

5656
public struct PublicSendable: Sendable {
@@ -60,8 +60,8 @@ public struct PublicSendable: Sendable {
6060
nonisolated var d = 0
6161

6262
// never okay
63-
nonisolated lazy var e = 0 // expected-error {{'nonisolated' is not supported on lazy properties}}
64-
@P nonisolated var f = 0 // expected-error {{'nonisolated' is not supported on properties with property wrappers}}
63+
nonisolated lazy var e = 0 // expected-error {{'nonisolated' cannot be applied to mutable stored properties}}
64+
@P nonisolated var f = 0 // expected-error {{'nonisolated' cannot be applied to mutable stored properties}}
6565
}
6666

6767
public struct PublicNonSendable {
@@ -70,9 +70,9 @@ public struct PublicNonSendable {
7070
nonisolated var c: Int { 0 }
7171
nonisolated var d = 0
7272

73-
// never okay
74-
nonisolated lazy var e = 0 // expected-error {{'nonisolated' is not supported on lazy properties}}
75-
@P nonisolated var f = 0 // expected-error {{'nonisolated' is not supported on properties with property wrappers}}
73+
// okay, the type is non-'Sendable'
74+
nonisolated lazy var e = 0
75+
@P nonisolated var f = 0
7676
}
7777

7878

@@ -96,6 +96,8 @@ nonisolated struct StructRemovesGlobalActor: GloballyIsolated {
9696

9797
@MainActor struct S {
9898
var value: NonSendable // globally-isolated
99+
@P nonisolated var x = 0 // expected-error {{'nonisolated' cannot be applied to mutable stored properties}}
100+
nonisolated lazy var y = 1 // expected-error {{'nonisolated' cannot be applied to mutable stored properties}}
99101
struct Nested {} // 'Nested' is not @MainActor-isolated
100102
}
101103

@@ -104,6 +106,8 @@ nonisolated struct StructRemovesGlobalActor: GloballyIsolated {
104106

105107
nonisolated struct S1: GloballyIsolated {
106108
var x: NonSendable
109+
@P nonisolated var y = 0 // okay
110+
nonisolated lazy var z = 1 // okay
107111
func f() {
108112
// expected-error@+1 {{call to main actor-isolated global function 'requireMain()' in a synchronous nonisolated context}}
109113
requireMain()

test/Distributed/distributed_actor_nonisolated.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ import FakeDistributedActorSystems
1010
@available(SwiftStdlib 5.5, *)
1111
typealias DefaultDistributedActorSystem = FakeActorSystem
1212

13+
@propertyWrapper struct P {
14+
var wrappedValue = 0
15+
}
16+
1317
distributed actor DA {
1418

1519
let local: Int = 42
@@ -49,6 +53,9 @@ distributed actor DA {
4953
fatalError()
5054
}
5155

56+
nonisolated lazy var a = 0 // expected-error {{'nonisolated' can not be applied to distributed actor stored properties}}
57+
@P nonisolated var b = 0 // expected-error {{'nonisolated' can not be applied to distributed actor stored properties}}
58+
5259
}
5360

5461
func invalidIsolatedCall<DA: DistributedActor> (

0 commit comments

Comments
 (0)