Skip to content

Commit c93f853

Browse files
committed
[Concurrency] Allow nonisolated to be used on protocols, extensions, classes, structs, and enums.
1 parent 4bb9a58 commit c93f853

File tree

4 files changed

+176
-74
lines changed

4 files changed

+176
-74
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: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5417,11 +5417,12 @@ static void checkDeclWithIsolatedParameter(ValueDecl *value) {
54175417
InferredActorIsolation ActorIsolationRequest::evaluate(
54185418
Evaluator &evaluator, ValueDecl *value) const {
54195419
auto &ctx = value->getASTContext();
5420+
auto dc = value->getDeclContext();
54205421

54215422
// If this declaration has actor-isolated "self", it's isolated to that
54225423
// actor.
54235424
if (evaluateOrDefault(evaluator, HasIsolatedSelfRequest{value}, false)) {
5424-
auto actor = value->getDeclContext()->getSelfNominalTypeDecl();
5425+
auto actor = dc->getSelfNominalTypeDecl();
54255426
assert(actor && "could not find the actor that 'self' is isolated to");
54265427
return {
54275428
ActorIsolation::forActorInstanceSelf(value),
@@ -5503,7 +5504,7 @@ InferredActorIsolation ActorIsolationRequest::evaluate(
55035504
}
55045505

55055506
// When no other isolation applies, an actor's non-async init is independent
5506-
if (auto nominal = value->getDeclContext()->getSelfNominalTypeDecl())
5507+
if (auto nominal = dc->getSelfNominalTypeDecl())
55075508
if (nominal->isAnyActor())
55085509
if (auto ctor = dyn_cast<ConstructorDecl>(value))
55095510
if (!ctor->hasAsync())
@@ -5673,7 +5674,7 @@ InferredActorIsolation ActorIsolationRequest::evaluate(
56735674
}
56745675
}
56755676

5676-
if (shouldInferAttributeInContext(value->getDeclContext())) {
5677+
if (shouldInferAttributeInContext(dc)) {
56775678
// If the declaration witnesses a protocol requirement that is isolated,
56785679
// use that.
56795680
if (auto witnessedIsolation = getIsolationFromWitnessedRequirements(value)) {
@@ -5759,7 +5760,7 @@ InferredActorIsolation ActorIsolationRequest::evaluate(
57595760

57605761
// If the declaration is in an extension that has one of the isolation
57615762
// attributes, use that.
5762-
if (auto ext = dyn_cast<ExtensionDecl>(value->getDeclContext())) {
5763+
if (auto ext = dyn_cast<ExtensionDecl>(dc)) {
57635764
if (auto isolationFromAttr = getIsolationFromAttributes(ext)) {
57645765
return {
57655766
inferredIsolation(*isolationFromAttr, onlyGlobal),
@@ -5770,7 +5771,7 @@ InferredActorIsolation ActorIsolationRequest::evaluate(
57705771

57715772
// If the declaration is in a nominal type (or extension thereof) that
57725773
// has isolation, use that.
5773-
if (auto selfTypeDecl = value->getDeclContext()->getSelfNominalTypeDecl()) {
5774+
if (auto selfTypeDecl = dc->getSelfNominalTypeDecl()) {
57745775
auto selfTypeIsolation = getInferredActorIsolation(selfTypeDecl);
57755776
if (selfTypeIsolation.isolation) {
57765777
return {

test/Concurrency/mutable_storage_nonisolated.swift

Lines changed: 0 additions & 68 deletions
This file was deleted.
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
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+
@propertyWrapper struct P {
14+
var wrappedValue = 0
15+
}
16+
17+
// MARK: - Structs
18+
19+
struct ImplicitlySendable {
20+
var a: Int
21+
22+
// always okay
23+
nonisolated let b = 0
24+
nonisolated var c: Int { 0 }
25+
26+
// okay
27+
nonisolated var d = 0
28+
29+
// never okay
30+
nonisolated lazy var e = 0 // expected-error {{'nonisolated' is not supported on lazy properties}}
31+
@P nonisolated var f = 0 // expected-error {{'nonisolated' is not supported on properties with property wrappers}}
32+
}
33+
34+
struct ImplicitlyNonSendable {
35+
let a: NonSendable
36+
37+
// always okay
38+
nonisolated let b = 0
39+
nonisolated var c: Int { 0 }
40+
41+
// not okay
42+
nonisolated var d = 0 // expected-error {{'nonisolated' cannot be applied to mutable stored properties}}
43+
// expected-note@-1 {{convert 'd' to a 'let' constant or consider declaring it 'nonisolated(unsafe)' if manually managing concurrency safety}}
44+
45+
// never okay
46+
nonisolated lazy var e = 0 // expected-error {{'nonisolated' is not supported on lazy properties}}
47+
@P nonisolated var f = 0 // expected-error {{'nonisolated' is not supported on properties with property wrappers}}
48+
}
49+
50+
public struct PublicSendable: Sendable {
51+
// always okay
52+
nonisolated let b = 0
53+
nonisolated var c: Int { 0 }
54+
55+
// okay
56+
nonisolated var d = 0
57+
58+
// never okay
59+
nonisolated lazy var e = 0 // expected-error {{'nonisolated' is not supported on lazy properties}}
60+
@P nonisolated var f = 0 // expected-error {{'nonisolated' is not supported on properties with property wrappers}}
61+
}
62+
63+
public struct PublicNonSendable {
64+
// always okay
65+
nonisolated let b = 0
66+
nonisolated var c: Int { 0 }
67+
68+
// not okay
69+
nonisolated var d = 0 // expected-error {{'nonisolated' cannot be applied to mutable stored properties}}
70+
// expected-note@-1 {{convert 'd' to a 'let' constant or consider declaring it 'nonisolated(unsafe)' if manually managing concurrency safety}}
71+
72+
// never okay
73+
nonisolated lazy var e = 0 // expected-error {{'nonisolated' is not supported on lazy properties}}
74+
@P nonisolated var f = 0 // expected-error {{'nonisolated' is not supported on properties with property wrappers}}
75+
}
76+
77+
78+
nonisolated struct NonisolatedStruct: GloballyIsolated {
79+
var x: NonSendable
80+
var y: Int = 1
81+
82+
init(x: NonSendable) {
83+
self.x = x // okay
84+
}
85+
86+
struct Nested: GloballyIsolated {
87+
// expected-note@+1 {{mutation of this property is only permitted within the actor}}
88+
var z: NonSendable
89+
nonisolated init(z: NonSendable) {
90+
// expected-error@+1 {{main actor-isolated property 'z' can not be mutated from a nonisolated context}}
91+
self.z = z
92+
}
93+
}
94+
}
95+
96+
@MainActor struct S {
97+
var value: NonSendable // globally-isolated
98+
struct Nested {} // 'Nested' is not @MainActor-isolated
99+
}
100+
101+
// expected-note@+1 {{calls to global function 'requireMain()' from outside of its actor context are implicitly asynchronous}}
102+
@MainActor func requireMain() {}
103+
104+
nonisolated struct S1: GloballyIsolated {
105+
var x: NonSendable
106+
func f() {
107+
// expected-error@+1 {{call to main actor-isolated global function 'requireMain()' in a synchronous nonisolated context}}
108+
requireMain()
109+
}
110+
}
111+
112+
// MARK: - Protocols
113+
114+
nonisolated protocol Refined: GloballyIsolated {}
115+
116+
struct A: Refined {
117+
var x: NonSendable
118+
init(x: NonSendable) {
119+
self.x = x // okay
120+
}
121+
}
122+
123+
// MARK: - Extensions
124+
125+
nonisolated extension GloballyIsolated {
126+
var x: NonSendable { .init () }
127+
func implicitlyNonisolated() {}
128+
}
129+
130+
struct C: GloballyIsolated {
131+
nonisolated func explicitlyNonisolated() {
132+
let _ = x // okay
133+
implicitlyNonisolated() // okay
134+
}
135+
}
136+
137+
// MARK: - Enums
138+
139+
nonisolated enum E: GloballyIsolated {
140+
func implicitlyNonisolated() {}
141+
init() {}
142+
}
143+
144+
struct TestEnum {
145+
nonisolated func call() {
146+
E().implicitlyNonisolated() // okay
147+
}
148+
}
149+
150+
// MARK: - Classes
151+
152+
nonisolated class K: GloballyIsolated {
153+
var x: NonSendable
154+
init(x: NonSendable) {
155+
self.x = x // okay
156+
}
157+
}
158+
159+
// MARK: - Storage of non-Sendable
160+
161+
class KlassA {
162+
nonisolated var test: NonSendable = NonSendable()
163+
}
164+
165+
// MARK: - Restrictions
166+
167+
@MainActor
168+
nonisolated struct Conflict {}
169+
// expected-error@-1 {{struct 'Conflict' has multiple actor-isolation attributes ('nonisolated' and 'MainActor')}}

0 commit comments

Comments
 (0)