Skip to content

Commit d41695a

Browse files
committed
[Concurrency] Allow nonisolated on stored properties of non-'Sendable' type.
1 parent 92a1eda commit d41695a

File tree

2 files changed

+30
-16
lines changed

2 files changed

+30
-16
lines changed

lib/Sema/TypeCheckAttr.cpp

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7093,9 +7093,8 @@ void AttributeChecker::visitNonisolatedAttr(NonisolatedAttr *attr) {
70937093
auto type = var->getTypeInContext();
70947094
if (var->hasStorage()) {
70957095
{
7096-
// 'nonisolated' can not be applied to mutable stored properties unless
7097-
// qualified as 'unsafe', or is of a Sendable type on a Sendable
7098-
// value type.
7096+
// A stored property can be 'nonisolated' if it is a 'Sendable' member
7097+
// of a 'Sendable' value type.
70997098
bool canBeNonisolated = false;
71007099
if (auto nominal = dc->getSelfStructDecl()) {
71017100
if (nominal->getDeclaredTypeInContext()->isSendableType() &&
@@ -7104,26 +7103,30 @@ void AttributeChecker::visitNonisolatedAttr(NonisolatedAttr *attr) {
71047103
}
71057104
}
71067105

7106+
// Additionally, a stored property of a non-'Sendable' type can be
7107+
// explicitly marked 'nonisolated'.
7108+
if (auto parentDecl = dc->getDeclaredTypeInContext())
7109+
if (!parentDecl->isSendableType()) {
7110+
canBeNonisolated = true;
7111+
}
7112+
7113+
// Otherwise, this stored property has to be qualified as 'unsafe'.
71077114
if (var->supportsMutation() && !attr->isUnsafe() && !canBeNonisolated) {
71087115
diagnoseAndRemoveAttr(attr, diag::nonisolated_mutable_storage)
71097116
.fixItInsertAfter(attr->getRange().End, "(unsafe)");
71107117
var->diagnose(diag::nonisolated_mutable_storage_note, var);
71117118
return;
71127119
}
7113-
}
71147120

7115-
// 'nonisolated' without '(unsafe)' is not allowed on non-Sendable
7116-
// variables.
7117-
if (!attr->isUnsafe() && !type->hasError()) {
7118-
bool diagnosed = diagnoseIfAnyNonSendableTypes(
7119-
type,
7120-
SendableCheckContext(dc),
7121-
Type(),
7122-
SourceLoc(),
7123-
attr->getLocation(),
7124-
diag::nonisolated_non_sendable);
7125-
if (diagnosed)
7126-
return;
7121+
// 'nonisolated' without '(unsafe)' is not allowed on non-Sendable
7122+
// variables, unless they are a member of a non-'Sendable' type.
7123+
if (!attr->isUnsafe() && !type->hasError() && !canBeNonisolated) {
7124+
bool diagnosed = diagnoseIfAnyNonSendableTypes(
7125+
type, SendableCheckContext(dc), Type(), SourceLoc(),
7126+
attr->getLocation(), diag::nonisolated_non_sendable);
7127+
if (diagnosed)
7128+
return;
7129+
}
71277130
}
71287131

71297132
if (auto nominal = dyn_cast<NominalTypeDecl>(dc)) {

test/Concurrency/nonisolated_rules.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,14 @@ class KlassA {
105105
@MainActor
106106
nonisolated struct Conflict {}
107107
// expected-error@-1 {{struct 'Conflict' has multiple actor-isolation attributes ('nonisolated' and 'MainActor')}}
108+
109+
struct B: Sendable {
110+
// expected-error@+1 {{'nonisolated' can not be applied to variable with non-'Sendable' type 'NonSendable}}
111+
nonisolated let test: NonSendable
112+
}
113+
114+
final class KlassB: Sendable {
115+
// expected-note@+2 {{convert 'test' to a 'let' constant or consider declaring it 'nonisolated(unsafe)' if manually managing concurrency safety}}
116+
// expected-error@+1 {{'nonisolated' cannot be applied to mutable stored properties}}
117+
nonisolated var test: Int = 1
118+
}

0 commit comments

Comments
 (0)