Skip to content

Commit 549566e

Browse files
authored
Merge pull request #74958 from simanerush/130992526
[Concurrency] Allow 'nonisolated' to be applied to mutable storage of 'Sendable' type on a globally-isolated value type.
2 parents 1a75fd1 + f726e7e commit 549566e

File tree

5 files changed

+71
-17
lines changed

5 files changed

+71
-17
lines changed

lib/Sema/TypeCheckAttr.cpp

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7010,18 +7010,32 @@ void AttributeChecker::visitNonisolatedAttr(NonisolatedAttr *attr) {
70107010

70117011
if (auto var = dyn_cast<VarDecl>(D)) {
70127012
// stored properties have limitations as to when they can be nonisolated.
7013+
auto type = var->getTypeInContext();
70137014
if (var->hasStorage()) {
7014-
// 'nonisolated' can not be applied to mutable stored properties unless
7015-
// qualified as 'unsafe'.
7016-
if (var->supportsMutation() && !attr->isUnsafe()) {
7017-
diagnoseAndRemoveAttr(attr, diag::nonisolated_mutable_storage)
7018-
.fixItInsertAfter(attr->getRange().End, "(unsafe)");
7019-
var->diagnose(diag::nonisolated_mutable_storage_note, var);
7020-
return;
7015+
{
7016+
// 'nonisolated' can not be applied to mutable stored properties unless
7017+
// qualified as 'unsafe', or is of a Sendable type on a
7018+
// globally-isolated value type.
7019+
bool canBeNonisolated = false;
7020+
if (dc->isTypeContext()) {
7021+
if (auto nominal = dc->getSelfStructDecl()) {
7022+
if (!var->isStatic() && type->isSendableType() &&
7023+
getActorIsolation(nominal).isGlobalActor()) {
7024+
canBeNonisolated = true;
7025+
}
7026+
}
7027+
}
7028+
7029+
if (var->supportsMutation() && !attr->isUnsafe() && !canBeNonisolated) {
7030+
diagnoseAndRemoveAttr(attr, diag::nonisolated_mutable_storage)
7031+
.fixItInsertAfter(attr->getRange().End, "(unsafe)");
7032+
var->diagnose(diag::nonisolated_mutable_storage_note, var);
7033+
return;
7034+
}
70217035
}
70227036

7023-
// 'nonisolated' without '(unsafe)' is not allowed on non-Sendable variables.
7024-
auto type = var->getTypeInContext();
7037+
// 'nonisolated' without '(unsafe)' is not allowed on non-Sendable
7038+
// variables.
70257039
if (!attr->isUnsafe() && !type->hasError()) {
70267040
bool diagnosed = diagnoseIfAnyNonSendableTypes(
70277041
type,

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -516,11 +516,10 @@ static bool varIsSafeAcrossActors(const ModuleDecl *fromModule,
516516
// A mutable storage of a value type accessed from within the module is
517517
// okay.
518518
if (dyn_cast_or_null<StructDecl>(var->getDeclContext()->getAsDecl()) &&
519-
!var->isStatic() &&
520-
var->hasStorage() &&
521-
var->getTypeInContext()->isSendableType() &&
522-
accessWithinModule) {
523-
return true;
519+
!var->isStatic() && var->hasStorage() &&
520+
var->getTypeInContext()->isSendableType()) {
521+
if (accessWithinModule || varIsolation.isNonisolated())
522+
return true;
524523
}
525524
// Otherwise, must be immutable.
526525
return false;

test/Concurrency/actor_isolation.swift

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,7 @@ struct InferredFromContext {
138138
get { [] }
139139
}
140140

141-
nonisolated var status: Bool = true // expected-error {{'nonisolated' cannot be applied to mutable stored properties}}{{3-15=}}{{3-15=}}{{14-14=(unsafe)}}
142-
// expected-note@-1{{convert 'status' to a 'let' constant or consider declaring it 'nonisolated(unsafe)' if manually managing concurrency safety}}
141+
nonisolated var status: Bool = true // okay
143142

144143
nonisolated let flag: Bool = false
145144

@@ -1243,6 +1242,12 @@ func test_conforming_actor_to_global_actor_protocol() {
12431242
// expected-error@-1 {{actor 'MyValue' cannot conform to global actor isolated protocol 'GloballyIsolatedProto'}}
12441243
}
12451244

1245+
func test_nonisolated_variable() {
1246+
struct S: GloballyIsolatedProto {
1247+
nonisolated var x: Int = 0 // okay
1248+
}
1249+
}
1250+
12461251
func test_invalid_reference_to_actor_member_without_a_call_note() {
12471252
actor A {
12481253
func partial() { }

test/Concurrency/derived_conformances_nonisolated.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ struct X1: Equatable, Hashable, Codable {
1414
@MainActor
1515
struct X2: Equatable, Hashable, Codable {
1616
let x: Int
17-
var y: String
17+
nonisolated var y: String // okay
1818
}
1919

2020
class NonSendable {
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// RUN: %empty-directory(%t/src)
2+
// RUN: split-file %s %t/src
3+
4+
/// Build the library A
5+
// RUN: %target-swift-frontend -emit-module %t/src/A.swift \
6+
// RUN: -disable-availability-checking \
7+
// RUN: -module-name A -swift-version 6 \
8+
// RUN: -emit-module-path %t/A.swiftmodule
9+
10+
// Build the client
11+
// RUN: %target-swift-frontend -emit-module %t/src/Client.swift \
12+
// RUN: -disable-availability-checking \
13+
// RUN: -module-name Client -I %t -swift-version 6 \
14+
// RUN: -emit-module-path %t/Client.swiftmodule
15+
16+
// REQUIRES: concurrency
17+
18+
//--- A.swift
19+
@MainActor
20+
public protocol P {}
21+
22+
public struct S: P {
23+
nonisolated public var x: Int = 0
24+
25+
nonisolated public init() {}
26+
}
27+
28+
//--- Client.swift
29+
import A
30+
31+
actor A {
32+
func test() {
33+
var s = S()
34+
s.x += 0 // okay
35+
}
36+
}

0 commit comments

Comments
 (0)