Skip to content

Commit 0f7d39d

Browse files
committed
[Concurrency] Allow explicit 'nonisolated' on lazy properties and properties with property wrappers if they are a member of a non-'Sendable' type.
1 parent 8f7af45 commit 0f7d39d

File tree

8 files changed

+68
-62
lines changed

8 files changed

+68
-62
lines changed

include/swift/AST/DiagnosticsSema.def

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

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

lib/Sema/TypeCheckAttr.cpp

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7787,31 +7787,50 @@ void AttributeChecker::visitNonisolatedAttr(NonisolatedAttr *attr) {
77877787
if (auto var = dyn_cast<VarDecl>(D)) {
77887788
// stored properties have limitations as to when they can be nonisolated.
77897789
auto type = var->getTypeInContext();
7790-
if (var->hasStorage()) {
7790+
if (var->hasStorage() || var->hasAttachedPropertyWrapper() ||
7791+
var->getAttrs().hasAttribute<LazyAttr>()) {
77917792
{
77927793
// A stored property can be 'nonisolated' if it is a 'Sendable' member
77937794
// of a 'Sendable' value type.
7795+
// The above rule does not apply to lazy properties and properties with
7796+
// property wrappers, because backing storage is a stored
7797+
// 'var' that is part of the internal state of the actor which could
7798+
// only be accessed in actor's isolation context.
77947799
bool canBeNonisolated = false;
77957800
if (auto nominal = dc->getSelfStructDecl()) {
7796-
if (nominal->getDeclaredTypeInContext()->isSendableType() &&
7801+
if (var->hasStorage() &&
7802+
nominal->getDeclaredTypeInContext()->isSendableType() &&
77977803
!var->isStatic() && type->isSendableType()) {
77987804
canBeNonisolated = true;
77997805
}
78007806
}
78017807

7802-
// Additionally, a stored property of a non-'Sendable' type can be
7803-
// explicitly marked 'nonisolated'.
7804-
if (auto parentDecl = dc->getDeclaredTypeInContext())
7805-
if (!parentDecl->isSendableType()) {
7806-
canBeNonisolated = true;
7807-
}
7808+
// Additionally, a stored property of a non-'Sendable' type can be
7809+
// explicitly marked 'nonisolated'.
7810+
if (auto parentDecl = dc->getDeclaredTypeInContext())
7811+
if (!parentDecl->isSendableType()) {
7812+
canBeNonisolated = true;
7813+
}
78087814

78097815
// Otherwise, this stored property has to be qualified as 'unsafe'.
78107816
if (var->supportsMutation() && !attr->isUnsafe() && !canBeNonisolated) {
7811-
diagnoseAndRemoveAttr(attr, diag::nonisolated_mutable_storage)
7817+
if (var->hasAttachedPropertyWrapper()) {
7818+
diagnoseAndRemoveAttr(attr, diag::nonisolated_mutable_storage)
7819+
.warnUntilSwiftVersionIf(attr->isImplicit(), 6)
78127820
.fixItInsertAfter(attr->getRange().End, "(unsafe)");
7813-
var->diagnose(diag::nonisolated_mutable_storage_note, var);
7814-
return;
7821+
return;
7822+
} else if (var->getAttrs().hasAttribute<LazyAttr>()) {
7823+
diagnoseAndRemoveAttr(attr, diag::nonisolated_mutable_storage)
7824+
.warnUntilSwiftVersion(6)
7825+
.fixItInsertAfter(attr->getRange().End, "(unsafe)");
7826+
return;
7827+
} else {
7828+
diagnoseAndRemoveAttr(attr, diag::nonisolated_mutable_storage)
7829+
.fixItInsertAfter(attr->getRange().End, "(unsafe)");
7830+
if (var->hasStorage())
7831+
var->diagnose(diag::nonisolated_mutable_storage_note, var);
7832+
return;
7833+
}
78157834
}
78167835

78177836
// 'nonisolated' without '(unsafe)' is not allowed on non-Sendable
@@ -7877,22 +7896,6 @@ void AttributeChecker::visitNonisolatedAttr(NonisolatedAttr *attr) {
78777896
}
78787897
}
78797898

7880-
// Using 'nonisolated' with lazy properties and wrapped properties is
7881-
// unsupported, because backing storage is a stored 'var' that is part
7882-
// of the internal state of the actor which could only be accessed in
7883-
// actor's isolation context.
7884-
if (var->hasAttachedPropertyWrapper()) {
7885-
diagnoseAndRemoveAttr(attr, diag::nonisolated_wrapped_property)
7886-
.warnUntilSwiftVersionIf(attr->isImplicit(), 6);
7887-
return;
7888-
}
7889-
7890-
if (var->getAttrs().hasAttribute<LazyAttr>()) {
7891-
diagnose(attr->getLocation(), diag::nonisolated_lazy)
7892-
.warnUntilSwiftVersion(6);
7893-
return;
7894-
}
7895-
78967899
// nonisolated can not be applied to local properties unless qualified as
78977900
// 'unsafe'.
78987901
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' cannot be applied to mutable stored properties}}
57+
@P nonisolated var b = 0 // expected-error {{'nonisolated' cannot be applied to mutable stored properties}}
58+
5259
}
5360

5461
func invalidIsolatedCall<DA: DistributedActor> (

0 commit comments

Comments
 (0)