Skip to content

Commit 92a1eda

Browse files
committed
[Concurrency] Allow nonisolated to be used on protocols, extensions, classes, structs, and enums.
1 parent 0e2a8bd commit 92a1eda

File tree

4 files changed

+122
-33
lines changed

4 files changed

+122
-33
lines changed

include/swift/AST/DeclAttr.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,7 @@ SIMPLE_DECL_ATTR(reasync, Reasync,
441441
OnFunc | OnConstructor | RejectByParser | ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove,
442442
109)
443443
CONTEXTUAL_DECL_ATTR(nonisolated, Nonisolated,
444-
DeclModifier | OnFunc | OnConstructor | OnVar | OnSubscript | ABIStableToAdd | ABIStableToRemove | APIBreakingToAdd | APIStableToRemove,
444+
DeclModifier | OnFunc | OnConstructor | OnVar | OnSubscript | OnProtocol | OnExtension | OnClass | OnStruct | OnEnum | ABIStableToAdd | ABIStableToRemove | APIBreakingToAdd | APIStableToRemove,
445445
112)
446446
CONTEXTUAL_SIMPLE_DECL_ATTR(distributed, DistributedActor,
447447
DeclModifier | OnClass | OnFunc | OnAccessor | OnVar | ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove,

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5425,11 +5425,12 @@ static void checkDeclWithIsolatedParameter(ValueDecl *value) {
54255425
InferredActorIsolation ActorIsolationRequest::evaluate(
54265426
Evaluator &evaluator, ValueDecl *value) const {
54275427
auto &ctx = value->getASTContext();
5428+
auto dc = value->getDeclContext();
54285429

54295430
// If this declaration has actor-isolated "self", it's isolated to that
54305431
// actor.
54315432
if (evaluateOrDefault(evaluator, HasIsolatedSelfRequest{value}, false)) {
5432-
auto actor = value->getDeclContext()->getSelfNominalTypeDecl();
5433+
auto actor = dc->getSelfNominalTypeDecl();
54335434
assert(actor && "could not find the actor that 'self' is isolated to");
54345435
return {
54355436
ActorIsolation::forActorInstanceSelf(value),
@@ -5466,6 +5467,14 @@ InferredActorIsolation ActorIsolationRequest::evaluate(
54665467
value->getAttrs().add(preconcurrency);
54675468
}
54685469

5470+
// If this declaration is non-isolated, we are done.
5471+
auto ctxIsolation = getActorIsolationOfContext(dc);
5472+
if (ctxIsolation.isNonisolated()) {
5473+
return {
5474+
ctxIsolation,
5475+
IsolationSource(dc->getAsDecl(), IsolationSource::LexicalContext)};
5476+
}
5477+
54695478
if (FuncDecl *fd = dyn_cast<FuncDecl>(value)) {
54705479
// Main.main() and Main.$main are implicitly MainActor-protected.
54715480
// Any other isolation is an error.
@@ -5511,7 +5520,7 @@ InferredActorIsolation ActorIsolationRequest::evaluate(
55115520
}
55125521

55135522
// When no other isolation applies, an actor's non-async init is independent
5514-
if (auto nominal = value->getDeclContext()->getSelfNominalTypeDecl())
5523+
if (auto nominal = dc->getSelfNominalTypeDecl())
55155524
if (nominal->isAnyActor())
55165525
if (auto ctor = dyn_cast<ConstructorDecl>(value))
55175526
if (!ctor->hasAsync())
@@ -5681,7 +5690,7 @@ InferredActorIsolation ActorIsolationRequest::evaluate(
56815690
}
56825691
}
56835692

5684-
if (shouldInferAttributeInContext(value->getDeclContext())) {
5693+
if (shouldInferAttributeInContext(dc)) {
56855694
// If the declaration witnesses a protocol requirement that is isolated,
56865695
// use that.
56875696
if (auto witnessedIsolation = getIsolationFromWitnessedRequirements(value)) {
@@ -5767,7 +5776,7 @@ InferredActorIsolation ActorIsolationRequest::evaluate(
57675776

57685777
// If the declaration is in an extension that has one of the isolation
57695778
// attributes, use that.
5770-
if (auto ext = dyn_cast<ExtensionDecl>(value->getDeclContext())) {
5779+
if (auto ext = dyn_cast<ExtensionDecl>(dc)) {
57715780
if (auto isolationFromAttr = getIsolationFromAttributes(ext)) {
57725781
return {
57735782
inferredIsolation(*isolationFromAttr, onlyGlobal),
@@ -5778,7 +5787,7 @@ InferredActorIsolation ActorIsolationRequest::evaluate(
57785787

57795788
// If the declaration is in a nominal type (or extension thereof) that
57805789
// has isolation, use that.
5781-
if (auto selfTypeDecl = value->getDeclContext()->getSelfNominalTypeDecl()) {
5790+
if (auto selfTypeDecl = dc->getSelfNominalTypeDecl()) {
57825791
auto selfTypeIsolation = getInferredActorIsolation(selfTypeDecl);
57835792
if (selfTypeIsolation.isolation) {
57845793
return {

test/Concurrency/mutable_storage_nonisolated.swift

Lines changed: 0 additions & 27 deletions
This file was deleted.
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
// RUN: %target-swift-frontend -disable-availability-checking -swift-version 6 -parse-as-library %s -emit-sil -o /dev/null -verify
2+
// RUN: %target-swift-frontend -disable-availability-checking -swift-version 6 -parse-as-library %s -emit-sil -o /dev/null -verify -strict-concurrency=complete
3+
4+
// REQUIRES: concurrency
5+
// REQUIRES: asserts
6+
7+
@MainActor
8+
protocol GloballyIsolated {}
9+
10+
// expected-note@+1 {{class 'NonSendable' does not conform to the 'Sendable' protocol}}
11+
class NonSendable {}
12+
13+
// MARK: - Structs
14+
15+
@MainActor
16+
struct ImplicitlySendable {
17+
var x: Int
18+
nonisolated var y: Int // okay
19+
}
20+
21+
@MainActor
22+
struct ImplicitlyNonSendable {
23+
let x: NonSendable
24+
nonisolated var y: Int // okay
25+
}
26+
27+
nonisolated struct NonisolatedStruct: GloballyIsolated {
28+
var x: NonSendable
29+
var y: Int = 1
30+
31+
init(x: NonSendable) {
32+
self.x = x // okay
33+
}
34+
35+
struct Nested: GloballyIsolated {
36+
// expected-note@+1 {{mutation of this property is only permitted within the actor}}
37+
var z: NonSendable
38+
nonisolated init(z: NonSendable) {
39+
// expected-error@+1 {{main actor-isolated property 'z' can not be mutated from a nonisolated context}}
40+
self.z = z
41+
}
42+
}
43+
}
44+
45+
@MainActor struct S {
46+
var value: NonSendable // globally-isolated
47+
struct Nested {} // 'Nested' is not @MainActor-isolated
48+
}
49+
50+
// MARK: - Protocols
51+
52+
nonisolated protocol Refined: GloballyIsolated {}
53+
54+
struct A: Refined {
55+
var x: NonSendable
56+
init(x: NonSendable) {
57+
self.x = x // okay
58+
}
59+
}
60+
61+
// MARK: - Extensions
62+
63+
nonisolated extension GloballyIsolated {
64+
var x: NonSendable { .init () }
65+
func implicitlyNonisolated() {}
66+
}
67+
68+
struct C: GloballyIsolated {
69+
nonisolated func explicitlyNonisolated() {
70+
let _ = x // okay
71+
implicitlyNonisolated() // okay
72+
}
73+
}
74+
75+
// MARK: - Enums
76+
77+
nonisolated enum E: GloballyIsolated {
78+
func implicitlyNonisolated() {}
79+
init() {}
80+
}
81+
82+
struct TestEnum {
83+
nonisolated func call() {
84+
E().implicitlyNonisolated() // okay
85+
}
86+
}
87+
88+
// MARK: - Classes
89+
90+
nonisolated class K: GloballyIsolated {
91+
var x: NonSendable
92+
init(x: NonSendable) {
93+
self.x = x // okay
94+
}
95+
}
96+
97+
// MARK: - Storage of non-Sendable
98+
99+
class KlassA {
100+
nonisolated var test: NonSendable = NonSendable()
101+
}
102+
103+
// MARK: - Restrictions
104+
105+
@MainActor
106+
nonisolated struct Conflict {}
107+
// expected-error@-1 {{struct 'Conflict' has multiple actor-isolation attributes ('nonisolated' and 'MainActor')}}

0 commit comments

Comments
 (0)