mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[Concurrency] Allow explicit 'nonisolated' on lazy properties and properties with property wrappers if they are a member of a non-'Sendable' type.
This commit is contained in:
@@ -6068,12 +6068,6 @@ ERROR(nonisolated_local_var,none,
|
||||
ERROR(nonisolated_actor_sync_init,none,
|
||||
"'nonisolated' on an actor's synchronous initializer is invalid",
|
||||
())
|
||||
ERROR(nonisolated_wrapped_property,none,
|
||||
"'nonisolated' is not supported on properties with property wrappers",
|
||||
())
|
||||
ERROR(nonisolated_lazy,none,
|
||||
"'nonisolated' is not supported on lazy properties",
|
||||
())
|
||||
|
||||
ERROR(non_sendable_from_deinit,none,
|
||||
"cannot access %kind1 with a non-Sendable type %0 from nonisolated "
|
||||
|
||||
@@ -7787,31 +7787,50 @@ void AttributeChecker::visitNonisolatedAttr(NonisolatedAttr *attr) {
|
||||
if (auto var = dyn_cast<VarDecl>(D)) {
|
||||
// stored properties have limitations as to when they can be nonisolated.
|
||||
auto type = var->getTypeInContext();
|
||||
if (var->hasStorage()) {
|
||||
if (var->hasStorage() || var->hasAttachedPropertyWrapper() ||
|
||||
var->getAttrs().hasAttribute<LazyAttr>()) {
|
||||
{
|
||||
// A stored property can be 'nonisolated' if it is a 'Sendable' member
|
||||
// of a 'Sendable' value type.
|
||||
// The above rule does not apply to lazy properties and properties with
|
||||
// property wrappers, because backing storage is a stored
|
||||
// 'var' that is part of the internal state of the actor which could
|
||||
// only be accessed in actor's isolation context.
|
||||
bool canBeNonisolated = false;
|
||||
if (auto nominal = dc->getSelfStructDecl()) {
|
||||
if (nominal->getDeclaredTypeInContext()->isSendableType() &&
|
||||
if (var->hasStorage() &&
|
||||
nominal->getDeclaredTypeInContext()->isSendableType() &&
|
||||
!var->isStatic() && type->isSendableType()) {
|
||||
canBeNonisolated = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Additionally, a stored property of a non-'Sendable' type can be
|
||||
// explicitly marked 'nonisolated'.
|
||||
if (auto parentDecl = dc->getDeclaredTypeInContext())
|
||||
if (!parentDecl->isSendableType()) {
|
||||
canBeNonisolated = true;
|
||||
}
|
||||
// Additionally, a stored property of a non-'Sendable' type can be
|
||||
// explicitly marked 'nonisolated'.
|
||||
if (auto parentDecl = dc->getDeclaredTypeInContext())
|
||||
if (!parentDecl->isSendableType()) {
|
||||
canBeNonisolated = true;
|
||||
}
|
||||
|
||||
// Otherwise, this stored property has to be qualified as 'unsafe'.
|
||||
if (var->supportsMutation() && !attr->isUnsafe() && !canBeNonisolated) {
|
||||
diagnoseAndRemoveAttr(attr, diag::nonisolated_mutable_storage)
|
||||
if (var->hasAttachedPropertyWrapper()) {
|
||||
diagnoseAndRemoveAttr(attr, diag::nonisolated_mutable_storage)
|
||||
.warnUntilSwiftVersionIf(attr->isImplicit(), 6)
|
||||
.fixItInsertAfter(attr->getRange().End, "(unsafe)");
|
||||
var->diagnose(diag::nonisolated_mutable_storage_note, var);
|
||||
return;
|
||||
return;
|
||||
} else if (var->getAttrs().hasAttribute<LazyAttr>()) {
|
||||
diagnoseAndRemoveAttr(attr, diag::nonisolated_mutable_storage)
|
||||
.warnUntilSwiftVersion(6)
|
||||
.fixItInsertAfter(attr->getRange().End, "(unsafe)");
|
||||
return;
|
||||
} else {
|
||||
diagnoseAndRemoveAttr(attr, diag::nonisolated_mutable_storage)
|
||||
.fixItInsertAfter(attr->getRange().End, "(unsafe)");
|
||||
if (var->hasStorage())
|
||||
var->diagnose(diag::nonisolated_mutable_storage_note, var);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 'nonisolated' without '(unsafe)' is not allowed on non-Sendable
|
||||
@@ -7877,22 +7896,6 @@ void AttributeChecker::visitNonisolatedAttr(NonisolatedAttr *attr) {
|
||||
}
|
||||
}
|
||||
|
||||
// Using 'nonisolated' with lazy properties and wrapped properties is
|
||||
// unsupported, because backing storage is a stored 'var' that is part
|
||||
// of the internal state of the actor which could only be accessed in
|
||||
// actor's isolation context.
|
||||
if (var->hasAttachedPropertyWrapper()) {
|
||||
diagnoseAndRemoveAttr(attr, diag::nonisolated_wrapped_property)
|
||||
.warnUntilSwiftVersionIf(attr->isImplicit(), 6);
|
||||
return;
|
||||
}
|
||||
|
||||
if (var->getAttrs().hasAttribute<LazyAttr>()) {
|
||||
diagnose(attr->getLocation(), diag::nonisolated_lazy)
|
||||
.warnUntilSwiftVersion(6);
|
||||
return;
|
||||
}
|
||||
|
||||
// nonisolated can not be applied to local properties unless qualified as
|
||||
// 'unsafe'.
|
||||
if (dc->isLocalContext() && !attr->isUnsafe()) {
|
||||
|
||||
@@ -813,31 +813,29 @@ actor LazyActor {
|
||||
lazy var l25: Int = { [unowned self] in self.l }()
|
||||
|
||||
nonisolated lazy var l31: Int = { v }()
|
||||
// expected-warning@-1 {{'nonisolated' is not supported on lazy properties; this is an error in the Swift 6 language mode}}
|
||||
// expected-warning@-1 {{'nonisolated' cannot be applied to mutable stored properties; this is an error in the Swift 6 language mode}}
|
||||
// expected-warning@-2 {{actor-isolated default value in a nonisolated context; this is an error in the Swift 6 language mode}}
|
||||
nonisolated lazy var l32: Int = v
|
||||
// expected-warning@-1 {{'nonisolated' is not supported on lazy properties; this is an error in the Swift 6 language mode}}
|
||||
// expected-warning@-2 {{actor-isolated default value in a nonisolated context; this is an error in the Swift 6 language mode}}
|
||||
// expected-warning@-1 {{'nonisolated' cannot be applied to mutable stored properties; this is an error in the Swift 6 language mode}}
|
||||
nonisolated lazy var l33: Int = { self.v }()
|
||||
// expected-warning@-1 {{'nonisolated' is not supported on lazy properties; this is an error in the Swift 6 language mode}}
|
||||
// expected-warning@-1 {{'nonisolated' cannot be applied to mutable stored properties; this is an error in the Swift 6 language mode}}
|
||||
// expected-warning@-2 {{actor-isolated default value in a nonisolated context; this is an error in the Swift 6 language mode}}
|
||||
nonisolated lazy var l34: Int = self.v
|
||||
// expected-warning@-1 {{'nonisolated' is not supported on lazy properties; this is an error in the Swift 6 language mode}}
|
||||
// expected-warning@-2 {{actor-isolated default value in a nonisolated context; this is an error in the Swift 6 language mode}}
|
||||
// expected-warning@-1 {{'nonisolated' cannot be applied to mutable stored properties; this is an error in the Swift 6 language mode}}
|
||||
nonisolated lazy var l35: Int = { [unowned self] in self.v }()
|
||||
// expected-warning@-1 {{'nonisolated' is not supported on lazy properties; this is an error in the Swift 6 language mode}}
|
||||
// expected-warning@-1 {{'nonisolated' cannot be applied to mutable stored properties; this is an error in the Swift 6 language mode}}
|
||||
// expected-warning@-2 {{actor-isolated default value in a nonisolated context; this is an error in the Swift 6 language mode}}
|
||||
|
||||
nonisolated lazy var l41: Int = { l }()
|
||||
// expected-warning@-1 {{'nonisolated' is not supported on lazy properties; this is an error in the Swift 6 language mode}}
|
||||
// expected-warning@-1 {{'nonisolated' cannot be applied to mutable stored properties; this is an error in the Swift 6 language mode}}
|
||||
nonisolated lazy var l42: Int = l
|
||||
// expected-warning@-1 {{'nonisolated' is not supported on lazy properties; this is an error in the Swift 6 language mode}}
|
||||
// expected-warning@-1 {{'nonisolated' cannot be applied to mutable stored properties; this is an error in the Swift 6 language mode}}
|
||||
nonisolated lazy var l43: Int = { self.l }()
|
||||
// expected-warning@-1 {{'nonisolated' is not supported on lazy properties; this is an error in the Swift 6 language mode}}
|
||||
// expected-warning@-1 {{'nonisolated' cannot be applied to mutable stored properties; this is an error in the Swift 6 language mode}}
|
||||
nonisolated lazy var l44: Int = self.l
|
||||
// expected-warning@-1 {{'nonisolated' is not supported on lazy properties; this is an error in the Swift 6 language mode}}
|
||||
// expected-warning@-1 {{'nonisolated' cannot be applied to mutable stored properties; this is an error in the Swift 6 language mode}}
|
||||
nonisolated lazy var l45: Int = { [unowned self] in self.l }()
|
||||
// expected-warning@-1 {{'nonisolated' is not supported on lazy properties; this is an error in the Swift 6 language mode}}
|
||||
// expected-warning@-1 {{'nonisolated' cannot be applied to mutable stored properties; this is an error in the Swift 6 language mode}}
|
||||
}
|
||||
|
||||
// Infer global actors from context only for instance members.
|
||||
|
||||
@@ -65,5 +65,7 @@ actor Pumpkin: NSObject {}
|
||||
|
||||
actor Bad {
|
||||
@objc nonisolated lazy var invalid = 0
|
||||
// expected-warning@-1 {{'nonisolated' is not supported on lazy properties; this is an error in the Swift 6 language mode}}
|
||||
// expected-warning@-1 {{'nonisolated' cannot be applied to mutable stored properties; this is an error in the Swift 6 language mode}}
|
||||
// expected-error@-2 {{actor-isolated setter for property 'invalid' cannot be @objc}}
|
||||
// expected-error@-3 {{actor-isolated getter for property 'invalid' cannot be @objc}}
|
||||
}
|
||||
|
||||
@@ -400,8 +400,7 @@ struct HasWrapperOnActor {
|
||||
synced = 17
|
||||
}
|
||||
|
||||
@WrapperActor var actorSynced: Int = 0 // expected-warning{{'nonisolated' is not supported on properties with property wrappers}}
|
||||
|
||||
@WrapperActor var actorSynced: Int = 0 // expected-warning {{'nonisolated' cannot be applied to mutable stored properties}}
|
||||
func testActorSynced() {
|
||||
_ = actorSynced
|
||||
_ = $actorSynced
|
||||
@@ -499,9 +498,8 @@ struct SimplePropertyWrapper {
|
||||
|
||||
@MainActor
|
||||
class WrappedContainsNonisolatedAttr {
|
||||
@SimplePropertyWrapper nonisolated var value
|
||||
// expected-error@-1 {{'nonisolated' is not supported on properties with property wrappers}}
|
||||
// expected-note@-2 {{property declared here}}
|
||||
@SimplePropertyWrapper nonisolated var value
|
||||
// expected-note@-1 {{property declared here}}
|
||||
|
||||
nonisolated func test() {
|
||||
_ = value
|
||||
|
||||
@@ -115,7 +115,7 @@ struct HasWrapperOnActor {
|
||||
synced = 17
|
||||
}
|
||||
|
||||
@WrapperActor var actorSynced: Int = 0 // expected-error{{'nonisolated' is not supported on properties with property wrappers}}
|
||||
@WrapperActor var actorSynced: Int = 0 // expected-error {{'nonisolated' cannot be applied to mutable stored properties}}
|
||||
|
||||
func testActorSynced() {
|
||||
_ = actorSynced
|
||||
|
||||
@@ -36,8 +36,8 @@ struct ImplicitlySendable {
|
||||
nonisolated var d = 0
|
||||
|
||||
// never okay
|
||||
nonisolated lazy var e = 0 // expected-error {{'nonisolated' is not supported on lazy properties}}
|
||||
@P nonisolated var f = 0 // expected-error {{'nonisolated' is not supported on properties with property wrappers}}
|
||||
nonisolated lazy var e = 0 // expected-error {{'nonisolated' cannot be applied to mutable stored properties}}
|
||||
@P nonisolated var f = 0 // expected-error {{'nonisolated' cannot be applied to mutable stored properties}}
|
||||
}
|
||||
|
||||
struct ImplicitlyNonSendable {
|
||||
@@ -48,9 +48,9 @@ struct ImplicitlyNonSendable {
|
||||
nonisolated var c: Int { 0 }
|
||||
nonisolated var d = 0
|
||||
|
||||
// never okay
|
||||
nonisolated lazy var e = 0 // expected-error {{'nonisolated' is not supported on lazy properties}}
|
||||
@P nonisolated var f = 0 // expected-error {{'nonisolated' is not supported on properties with property wrappers}}
|
||||
// okay, the type is non-'Sendable'
|
||||
nonisolated lazy var e = 0
|
||||
@P nonisolated var f = 0
|
||||
}
|
||||
|
||||
public struct PublicSendable: Sendable {
|
||||
@@ -60,8 +60,8 @@ public struct PublicSendable: Sendable {
|
||||
nonisolated var d = 0
|
||||
|
||||
// never okay
|
||||
nonisolated lazy var e = 0 // expected-error {{'nonisolated' is not supported on lazy properties}}
|
||||
@P nonisolated var f = 0 // expected-error {{'nonisolated' is not supported on properties with property wrappers}}
|
||||
nonisolated lazy var e = 0 // expected-error {{'nonisolated' cannot be applied to mutable stored properties}}
|
||||
@P nonisolated var f = 0 // expected-error {{'nonisolated' cannot be applied to mutable stored properties}}
|
||||
}
|
||||
|
||||
public struct PublicNonSendable {
|
||||
@@ -70,9 +70,9 @@ public struct PublicNonSendable {
|
||||
nonisolated var c: Int { 0 }
|
||||
nonisolated var d = 0
|
||||
|
||||
// never okay
|
||||
nonisolated lazy var e = 0 // expected-error {{'nonisolated' is not supported on lazy properties}}
|
||||
@P nonisolated var f = 0 // expected-error {{'nonisolated' is not supported on properties with property wrappers}}
|
||||
// okay, the type is non-'Sendable'
|
||||
nonisolated lazy var e = 0
|
||||
@P nonisolated var f = 0
|
||||
}
|
||||
|
||||
|
||||
@@ -96,6 +96,8 @@ nonisolated struct StructRemovesGlobalActor: GloballyIsolated {
|
||||
|
||||
@MainActor struct S {
|
||||
var value: NonSendable // globally-isolated
|
||||
@P nonisolated var x = 0 // expected-error {{'nonisolated' cannot be applied to mutable stored properties}}
|
||||
nonisolated lazy var y = 1 // expected-error {{'nonisolated' cannot be applied to mutable stored properties}}
|
||||
struct Nested {} // 'Nested' is not @MainActor-isolated
|
||||
}
|
||||
|
||||
@@ -104,6 +106,8 @@ nonisolated struct StructRemovesGlobalActor: GloballyIsolated {
|
||||
|
||||
nonisolated struct S1: GloballyIsolated {
|
||||
var x: NonSendable
|
||||
@P nonisolated var y = 0 // okay
|
||||
nonisolated lazy var z = 1 // okay
|
||||
func f() {
|
||||
// expected-error@+1 {{call to main actor-isolated global function 'requireMain()' in a synchronous nonisolated context}}
|
||||
requireMain()
|
||||
|
||||
@@ -10,6 +10,10 @@ import FakeDistributedActorSystems
|
||||
@available(SwiftStdlib 5.5, *)
|
||||
typealias DefaultDistributedActorSystem = FakeActorSystem
|
||||
|
||||
@propertyWrapper struct P {
|
||||
var wrappedValue = 0
|
||||
}
|
||||
|
||||
distributed actor DA {
|
||||
|
||||
let local: Int = 42
|
||||
@@ -49,6 +53,9 @@ distributed actor DA {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
nonisolated lazy var a = 0 // expected-error {{'nonisolated' cannot be applied to mutable stored properties}}
|
||||
@P nonisolated var b = 0 // expected-error {{'nonisolated' cannot be applied to mutable stored properties}}
|
||||
|
||||
}
|
||||
|
||||
func invalidIsolatedCall<DA: DistributedActor> (
|
||||
|
||||
Reference in New Issue
Block a user