Skip to content

Commit 52d9644

Browse files
committed
[Concurrency] Infer nonisolated for a mutable storage of a value type accessed from within the module.
1 parent 663865c commit 52d9644

File tree

6 files changed

+39
-38
lines changed

6 files changed

+39
-38
lines changed

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -503,9 +503,23 @@ static bool varIsSafeAcrossActors(const ModuleDecl *fromModule,
503503
VarDecl *var,
504504
const ActorIsolation &varIsolation,
505505
ActorReferenceResult::Options &options) {
506-
// must be immutable
507-
if (!var->isLet())
506+
507+
bool accessWithinModule =
508+
(fromModule == var->getDeclContext()->getParentModule());
509+
510+
if (!var->isLet()) {
511+
// A mutable storage of a value type accessed from within the module is
512+
// okay.
513+
if (dyn_cast_or_null<StructDecl>(var->getDeclContext()->getAsDecl()) &&
514+
!var->isStatic() &&
515+
var->hasStorage() &&
516+
var->getTypeInContext()->isSendableType() &&
517+
accessWithinModule) {
518+
return true;
519+
}
520+
// Otherwise, must be immutable.
508521
return false;
522+
}
509523

510524
switch (varIsolation) {
511525
case ActorIsolation::Nonisolated:
@@ -538,9 +552,6 @@ static bool varIsSafeAcrossActors(const ModuleDecl *fromModule,
538552
return false;
539553
}
540554

541-
bool accessWithinModule =
542-
(fromModule == var->getDeclContext()->getParentModule());
543-
544555
// If the type is not 'Sendable', it's unsafe
545556
if (!var->getTypeInContext()->isSendableType()) {
546557
// Compiler versions <= 5.10 treated this variable as nonisolated,

test/Concurrency/actor_isolation.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ func checkIsolationValueType(_ formance: InferredFromConformance,
156156
_ anno: NoGlobalActorValueType) async {
157157
// these still do need an await in Swift 5
158158
_ = await ext.point // expected-warning {{non-sendable type 'Point' in implicitly asynchronous access to main actor-isolated property 'point' cannot cross actor boundary}}
159-
_ = await formance.counter
159+
_ = formance.counter
160160
_ = await anno.point // expected-warning {{non-sendable type 'Point' in implicitly asynchronous access to global actor 'SomeGlobalActor'-isolated property 'point' cannot cross actor boundary}}
161161
// expected-warning@-1 {{non-sendable type 'NoGlobalActorValueType' passed in implicitly asynchronous call to global actor 'SomeGlobalActor'-isolated property 'point' cannot cross actor boundary}}
162162
_ = anno.counter // expected-warning {{non-sendable type 'NoGlobalActorValueType' passed in call to main actor-isolated property 'counter' cannot cross actor boundary}}

test/Concurrency/actor_isolation_swift6.swift

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,12 @@ func checkIsolationValueType(_ formance: InferredFromConformance,
5555
_ = await ext.point // expected-warning {{no 'async' operations occur within 'await' expression}}
5656
_ = await formance.counter // expected-warning {{no 'async' operations occur within 'await' expression}}
5757
_ = await anno.counter // expected-warning {{no 'async' operations occur within 'await' expression}}
58-
59-
// We could extend the 'nonisolated within the module' rule to vars
60-
// value types types if the property type is 'Sendable'.
58+
59+
// this does not need an await, since the property is 'Sendable' and of a
60+
// value type
6161
_ = anno.point
62-
// expected-error@-1 {{expression is 'async' but is not marked with 'await'}}
63-
// expected-note@-2 {{property access is 'async'}}
6462
_ = await anno.point
63+
// expected-warning@-1 {{no 'async' operations occur within 'await' expression}}
6564

6665
// these do need await, regardless of reference or value type
6766
_ = await (formance as any MainCounter).counter

test/Concurrency/derived_conformances_nonisolated.swift

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,11 @@ struct X1: Equatable, Hashable, Codable {
1010
let y: String
1111
}
1212

13-
// expected-error@+5 3{{main actor-isolated property 'y' can not be referenced from a non-isolated context}}
14-
// expected-note@+4{{in static method '==' for derived conformance to 'Equatable'}}
15-
// expected-error@+3{{main actor-isolated property 'y' can not be referenced from a non-isolated context}}
16-
// expected-note@+2{{in static method '==' for derived conformance to 'Equatable'}}
13+
// okay
1714
@MainActor
1815
struct X2: Equatable, Hashable, Codable {
1916
let x: Int
20-
var y: String // expected-note 4 {{property declared here}}
17+
var y: String
2118
}
2219

2320
@MainActor
@@ -26,12 +23,9 @@ enum X3: Hashable, Comparable, Codable {
2623
case b(Int)
2724
}
2825

29-
// expected-warning@+5{{main actor-isolated property 'y' can not be referenced from a non-isolated context}}
30-
// expected-note@+4{{in static method '==' for derived conformance to 'Equatable'}}
31-
// expected-warning@+3{{main actor-isolated property 'y' can not be referenced from a non-isolated context}}
32-
// expected-note@+2{{in static method '==' for derived conformance to 'Equatable'}}
26+
// okay
3327
@preconcurrency @MainActor
3428
struct X4: Equatable {
3529
let x: Int
36-
var y: String // expected-note 2 {{property declared here}}
30+
var y: String
3731
}

test/Concurrency/global_actor_inference.swift

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -285,14 +285,14 @@ func barSync() {
285285

286286
@OtherGlobalActor
287287
struct Observed {
288-
var thing: Int = 0 { // expected-note {{property declared here}}
288+
var thing: Int = 0 {
289289
didSet {}
290290
willSet {}
291291
}
292292
}
293293

294-
func checkObserved(_ o: Observed) { // expected-note {{add '@OtherGlobalActor' to make global function 'checkObserved' part of global actor 'OtherGlobalActor'}}
295-
_ = o.thing // expected-error {{global actor 'OtherGlobalActor'-isolated property 'thing' can not be referenced from a non-isolated context}}
294+
func checkObserved(_ o: Observed) {
295+
_ = o.thing // okay
296296
}
297297

298298
// ----------------------------------------------------------------------
@@ -376,13 +376,13 @@ actor WrapperActor<Wrapped: Sendable> {
376376

377377
struct HasWrapperOnActor {
378378
@WrapperOnActor var synced: Int = 0
379-
// expected-note@-1 3{{property declared here}}
379+
// expected-note@-1 2{{property declared here}}
380380

381-
// expected-note@+1 3{{to make instance method 'testErrors()'}}
381+
// expected-note@+1 2{{to make instance method 'testErrors()'}}
382382
func testErrors() {
383383
_ = synced // expected-error{{main actor-isolated property 'synced' can not be referenced from a non-isolated context}}
384384
_ = $synced // expected-error{{global actor 'SomeGlobalActor'-isolated property '$synced' can not be referenced from a non-isolated context}}
385-
_ = _synced // expected-error{{global actor 'OtherGlobalActor'-isolated property '_synced' can not be referenced from a non-isolated context}}
385+
_ = _synced // okay
386386
}
387387

388388
@MainActor mutating func testOnMain() {
@@ -566,22 +566,21 @@ struct HasWrapperOnUnsafeActor {
566566
// expected-complete-tns-warning@-2 {{default initializer for 'HasWrapperOnUnsafeActor' cannot be both nonisolated and global actor 'OtherGlobalActor'-isolated; this is an error in the Swift 6 language mode}}
567567

568568
@WrapperOnUnsafeActor var synced: Int = 0 // expected-complete-tns-note 2 {{initializer for property '_synced' is global actor 'OtherGlobalActor'-isolated}}
569-
// expected-note @-1 3{{property declared here}}
570-
// expected-complete-tns-note @-2 3{{property declared here}}
569+
// expected-note @-1 2{{property declared here}}
570+
// expected-complete-tns-note @-2 2{{property declared here}}
571571

572572
func testUnsafeOkay() {
573-
// expected-complete-tns-note @-1 {{add '@OtherGlobalActor' to make instance method 'testUnsafeOkay()' part of global actor 'OtherGlobalActor'}}
574-
// expected-complete-tns-note @-2 {{add '@SomeGlobalActor' to make instance method 'testUnsafeOkay()' part of global actor 'SomeGlobalActor'}}
575-
// expected-complete-tns-note @-3 {{add '@MainActor' to make instance method 'testUnsafeOkay()' part of global actor 'MainActor'}}
573+
// expected-complete-tns-note @-1 {{add '@SomeGlobalActor' to make instance method 'testUnsafeOkay()' part of global actor 'SomeGlobalActor'}}
574+
// expected-complete-tns-note @-2 {{add '@MainActor' to make instance method 'testUnsafeOkay()' part of global actor 'MainActor'}}
576575
_ = synced // expected-complete-tns-warning {{main actor-isolated property 'synced' can not be referenced from a non-isolated context}}
577576
_ = $synced // expected-complete-tns-warning {{global actor 'SomeGlobalActor'-isolated property '$synced' can not be referenced from a non-isolated context}}
578-
_ = _synced // expected-complete-tns-warning {{global actor 'OtherGlobalActor'-isolated property '_synced' can not be referenced from a non-isolated context}}
577+
_ = _synced // okay
579578
}
580579

581580
nonisolated func testErrors() {
582581
_ = synced // expected-warning{{main actor-isolated property 'synced' can not be referenced from a non-isolated context}}
583582
_ = $synced // expected-warning{{global actor 'SomeGlobalActor'-isolated property '$synced' can not be referenced from a non-isolated context}}
584-
_ = _synced // expected-warning{{global actor 'OtherGlobalActor'-isolated property '_synced' can not be referenced from a non-isolated context}}
583+
_ = _synced // okay
585584
}
586585

587586
@MainActor mutating func testOnMain() {

test/Concurrency/sendable_keypaths.swift

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,7 @@ func testGlobalActorIsolatedReferences() {
147147
subscript(v: Int) -> Bool { false }
148148
}
149149

150-
let dataKP = \Isolated.data
151-
// expected-warning@-1 {{cannot form key path to main actor-isolated property 'data'; this is an error in the Swift 6 language mode}}
150+
let dataKP = \Isolated.data // Ok
152151
let subscriptKP = \Isolated.[42]
153152
// expected-warning@-1 {{cannot form key path to main actor-isolated subscript 'subscript(_:)'; this is an error in the Swift 6 language mode}}
154153

@@ -158,8 +157,7 @@ func testGlobalActorIsolatedReferences() {
158157
// expected-warning@-1 {{type 'KeyPath<Isolated, Bool>' does not conform to the 'Sendable' protocol}}
159158

160159
func testNonIsolated() {
161-
_ = \Isolated.data
162-
// expected-warning@-1 {{cannot form key path to main actor-isolated property 'data'; this is an error in the Swift 6 language mode}}
160+
_ = \Isolated.data // Ok
163161
}
164162

165163
@MainActor func testIsolated() {

0 commit comments

Comments
 (0)