Skip to content

Commit 04f9efe

Browse files
committed
[Concurrency] Allow nonisolated on stored properties of non-'Sendable' type.
1 parent b4a2ee6 commit 04f9efe

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
@@ -7139,9 +7139,8 @@ void AttributeChecker::visitNonisolatedAttr(NonisolatedAttr *attr) {
71397139
auto type = var->getTypeInContext();
71407140
if (var->hasStorage()) {
71417141
{
7142-
// 'nonisolated' can not be applied to mutable stored properties unless
7143-
// qualified as 'unsafe', or is of a Sendable type on a Sendable
7144-
// value type.
7142+
// A stored property can be 'nonisolated' if it is a 'Sendable' member
7143+
// of a 'Sendable' value type.
71457144
bool canBeNonisolated = false;
71467145
if (auto nominal = dc->getSelfStructDecl()) {
71477146
if (nominal->getDeclaredTypeInContext()->isSendableType() &&
@@ -7150,26 +7149,30 @@ void AttributeChecker::visitNonisolatedAttr(NonisolatedAttr *attr) {
71507149
}
71517150
}
71527151

7152+
// Additionally, a stored property of a non-'Sendable' type can be
7153+
// explicitly marked 'nonisolated'.
7154+
if (auto parentDecl = dc->getDeclaredTypeInContext())
7155+
if (!parentDecl->isSendableType()) {
7156+
canBeNonisolated = true;
7157+
}
7158+
7159+
// Otherwise, this stored property has to be qualified as 'unsafe'.
71537160
if (var->supportsMutation() && !attr->isUnsafe() && !canBeNonisolated) {
71547161
diagnoseAndRemoveAttr(attr, diag::nonisolated_mutable_storage)
71557162
.fixItInsertAfter(attr->getRange().End, "(unsafe)");
71567163
var->diagnose(diag::nonisolated_mutable_storage_note, var);
71577164
return;
71587165
}
7159-
}
71607166

7161-
// 'nonisolated' without '(unsafe)' is not allowed on non-Sendable
7162-
// variables.
7163-
if (!attr->isUnsafe() && !type->hasError()) {
7164-
bool diagnosed = diagnoseIfAnyNonSendableTypes(
7165-
type,
7166-
SendableCheckContext(dc),
7167-
Type(),
7168-
SourceLoc(),
7169-
attr->getLocation(),
7170-
diag::nonisolated_non_sendable);
7171-
if (diagnosed)
7172-
return;
7167+
// 'nonisolated' without '(unsafe)' is not allowed on non-Sendable
7168+
// variables, unless they are a member of a non-'Sendable' type.
7169+
if (!attr->isUnsafe() && !type->hasError() && !canBeNonisolated) {
7170+
bool diagnosed = diagnoseIfAnyNonSendableTypes(
7171+
type, SendableCheckContext(dc), Type(), SourceLoc(),
7172+
attr->getLocation(), diag::nonisolated_non_sendable);
7173+
if (diagnosed)
7174+
return;
7175+
}
71737176
}
71747177

71757178
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
@@ -167,3 +167,14 @@ class KlassA {
167167
@MainActor
168168
nonisolated struct Conflict {}
169169
// expected-error@-1 {{struct 'Conflict' has multiple actor-isolation attributes ('nonisolated' and 'MainActor')}}
170+
171+
struct B: Sendable {
172+
// expected-error@+1 {{'nonisolated' can not be applied to variable with non-'Sendable' type 'NonSendable}}
173+
nonisolated let test: NonSendable
174+
}
175+
176+
final class KlassB: Sendable {
177+
// expected-note@+2 {{convert 'test' to a 'let' constant or consider declaring it 'nonisolated(unsafe)' if manually managing concurrency safety}}
178+
// expected-error@+1 {{'nonisolated' cannot be applied to mutable stored properties}}
179+
nonisolated var test: Int = 1
180+
}

0 commit comments

Comments
 (0)