-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[Concurrency] Allow 'nonisolated' to be applied to mutable storage of 'Sendable' type on a globally-isolated value type. #74958
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7010,18 +7010,32 @@ 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()) { | ||
// 'nonisolated' can not be applied to mutable stored properties unless | ||
// qualified as 'unsafe'. | ||
if (var->supportsMutation() && !attr->isUnsafe()) { | ||
diagnoseAndRemoveAttr(attr, diag::nonisolated_mutable_storage) | ||
.fixItInsertAfter(attr->getRange().End, "(unsafe)"); | ||
var->diagnose(diag::nonisolated_mutable_storage_note, var); | ||
return; | ||
{ | ||
// 'nonisolated' can not be applied to mutable stored properties unless | ||
// qualified as 'unsafe', or is of a Sendable type on a | ||
// globally-isolated value type. | ||
bool canBeNonisolated = false; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This can probably have a better name, for now I just put it in a scope. |
||
if (dc->isTypeContext()) { | ||
if (auto nominal = dc->getSelfStructDecl()) { | ||
if (!var->isStatic() && type->isSendableType() && | ||
AnthonyLatsis marked this conversation as resolved.
Show resolved
Hide resolved
|
||
getActorIsolation(nominal).isGlobalActor()) { | ||
canBeNonisolated = true; | ||
} | ||
} | ||
} | ||
|
||
if (var->supportsMutation() && !attr->isUnsafe() && !canBeNonisolated) { | ||
diagnoseAndRemoveAttr(attr, diag::nonisolated_mutable_storage) | ||
.fixItInsertAfter(attr->getRange().End, "(unsafe)"); | ||
var->diagnose(diag::nonisolated_mutable_storage_note, var); | ||
return; | ||
} | ||
} | ||
|
||
// 'nonisolated' without '(unsafe)' is not allowed on non-Sendable variables. | ||
auto type = var->getTypeInContext(); | ||
// 'nonisolated' without '(unsafe)' is not allowed on non-Sendable | ||
// variables. | ||
if (!attr->isUnsafe() && !type->hasError()) { | ||
bool diagnosed = diagnoseIfAnyNonSendableTypes( | ||
type, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -138,8 +138,7 @@ struct InferredFromContext { | |
get { [] } | ||
} | ||
|
||
nonisolated var status: Bool = true // expected-error {{'nonisolated' cannot be applied to mutable stored properties}}{{3-15=}}{{3-15=}}{{14-14=(unsafe)}} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Side note: This error message needs some love now that the rules have changed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree, but it's not obvious to me in what way should we change it. This case of allowing |
||
// expected-note@-1{{convert 'status' to a 'let' constant or consider declaring it 'nonisolated(unsafe)' if manually managing concurrency safety}} | ||
nonisolated var status: Bool = true // okay | ||
|
||
nonisolated let flag: Bool = false | ||
|
||
|
@@ -1243,6 +1242,12 @@ func test_conforming_actor_to_global_actor_protocol() { | |
// expected-error@-1 {{actor 'MyValue' cannot conform to global actor isolated protocol 'GloballyIsolatedProto'}} | ||
} | ||
|
||
func test_nonisolated_variable() { | ||
struct S: GloballyIsolatedProto { | ||
nonisolated var x: Int = 0 // okay | ||
} | ||
Comment on lines
+1245
to
+1248
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we have any |
||
} | ||
|
||
func test_invalid_reference_to_actor_member_without_a_call_note() { | ||
actor A { | ||
func partial() { } | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
// RUN: %empty-directory(%t/src) | ||
// RUN: split-file %s %t/src | ||
|
||
/// Build the library A | ||
// RUN: %target-swift-frontend -emit-module %t/src/A.swift \ | ||
// RUN: -disable-availability-checking \ | ||
// RUN: -module-name A -swift-version 6 \ | ||
// RUN: -emit-module-path %t/A.swiftmodule | ||
|
||
// Build the client | ||
// RUN: %target-swift-frontend -emit-module %t/src/Client.swift \ | ||
// RUN: -disable-availability-checking \ | ||
// RUN: -module-name Client -I %t -swift-version 6 \ | ||
// RUN: -emit-module-path %t/Client.swiftmodule | ||
|
||
// REQUIRES: concurrency | ||
|
||
//--- A.swift | ||
@MainActor | ||
public protocol P {} | ||
|
||
public struct S: P { | ||
nonisolated public var x: Int = 0 | ||
|
||
nonisolated public init() {} | ||
} | ||
|
||
//--- Client.swift | ||
import A | ||
|
||
actor A { | ||
func test() { | ||
var s = S() | ||
s.x += 0 // okay | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could test that we are checking a contextual vs. interface type with a type decl that conditionally conforms to
Sendable
. For example: