Skip to content

Commit a641192

Browse files
committed
[Concurrency] Handle cases where a property initializer is subsumed by another
property for IsolatedDefaultValues. For property wrappers and init accesors, skip property initializers that are subsumed, e.g. by an init accessor or a backing property wrapper initializer, and always consider the subsuming initializer to determine whether compiler synthesized initializers should have `nonisolated` applied. This change also lessens the source break of SE-0411 by still emitting member initializers in implicit constructors when the initializer violates actor isolation to preserve the behavior of existing code when concurrency diagnostics are downgraded to warnings in Swift 5 mode. (cherry picked from commit 20829fa)
1 parent 99e9db8 commit a641192

File tree

5 files changed

+107
-23
lines changed

5 files changed

+107
-23
lines changed

lib/SILGen/SILGenConstructor.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1544,9 +1544,20 @@ void SILGenFunction::emitMemberInitializer(DeclContext *dc, VarDecl *selfDecl,
15441544

15451545
case ActorIsolation::GlobalActor:
15461546
case ActorIsolation::GlobalActorUnsafe:
1547-
case ActorIsolation::ActorInstance:
1548-
if (requiredIsolation != contextIsolation)
1547+
case ActorIsolation::ActorInstance: {
1548+
if (requiredIsolation != contextIsolation) {
1549+
// Implicit initializers diagnose actor isolation violations
1550+
// for property initializers in Sema. Still emit the invalid
1551+
// member initializer here to avoid duplicate diagnostics and
1552+
// to preserve warn-until-Swift-6 behavior.
1553+
auto *init =
1554+
dyn_cast_or_null<ConstructorDecl>(dc->getAsDecl());
1555+
if (init && init->isImplicit())
1556+
break;
1557+
15491558
continue;
1559+
}
1560+
}
15501561
}
15511562

15521563
auto *varPattern = field->getPattern(i);

lib/Sema/CodeSynthesis.cpp

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -350,34 +350,59 @@ static ConstructorDecl *createImplicitConstructor(NominalTypeDecl *decl,
350350
// and actor initializers do not run on the actor, so initial values
351351
// cannot be actor-instance-isolated.
352352
bool shouldAddNonisolated = true;
353-
llvm::Optional<ActorIsolation> existingIsolation = llvm::None;
353+
ActorIsolation existingIsolation = getActorIsolation(decl);
354354
VarDecl *previousVar = nullptr;
355355

356-
// The memberwise init properties are also effectively what the
357-
// default init uses, e.g. default initializers initialize via
358-
// properties wrapped and init accessors.
359-
for (auto var : decl->getMemberwiseInitProperties()) {
356+
for (auto member : decl->getImplementationContext()->getAllMembers()) {
357+
auto pbd = dyn_cast<PatternBindingDecl>(member);
358+
if (!pbd || pbd->isStatic())
359+
continue;
360+
361+
auto *var = pbd->getSingleVar();
362+
if (!var) {
363+
shouldAddNonisolated = false;
364+
break;
365+
}
366+
367+
auto i = pbd->getPatternEntryIndexForVarDecl(var);
368+
if (pbd->isInitializerSubsumed(i))
369+
continue;
370+
371+
ActorIsolation initIsolation;
372+
if (var->hasInitAccessor()) {
373+
// Init accessors share the actor isolation of the property;
374+
// the accessor body can call anything in that isolation domain,
375+
// and we don't attempt to infer when the isolation isn't
376+
// necessary.
377+
initIsolation = getActorIsolation(var);
378+
} else {
379+
initIsolation = var->getInitializerIsolation();
380+
}
381+
360382
auto type = var->getTypeInContext();
361383
auto isolation = getActorIsolation(var);
362384
if (isolation.isGlobalActor()) {
363385
if (!isSendableType(decl->getModuleContext(), type) ||
364-
var->getInitializerIsolation().isGlobalActor()) {
386+
initIsolation.isGlobalActor()) {
365387
// If different isolated stored properties require different
366388
// global actors, it is impossible to initialize this type.
367-
if (existingIsolation &&
368-
*existingIsolation != isolation) {
389+
if (existingIsolation != isolation) {
369390
ctx.Diags.diagnose(decl->getLoc(),
370391
diag::conflicting_stored_property_isolation,
371392
ICK == ImplicitConstructorKind::Memberwise,
372-
decl->getDeclaredType(), *existingIsolation, isolation);
373-
previousVar->diagnose(
374-
diag::property_requires_actor,
375-
previousVar->getDescriptiveKind(),
376-
previousVar->getName(), *existingIsolation);
393+
decl->getDeclaredType(), existingIsolation, isolation)
394+
.warnUntilSwiftVersion(6);
395+
if (previousVar) {
396+
previousVar->diagnose(
397+
diag::property_requires_actor,
398+
previousVar->getDescriptiveKind(),
399+
previousVar->getName(), existingIsolation);
400+
}
377401
var->diagnose(
378402
diag::property_requires_actor,
379403
var->getDescriptiveKind(),
380404
var->getName(), isolation);
405+
break;
381406
}
382407

383408
existingIsolation = isolation;

test/Concurrency/actor_isolation.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,9 +168,12 @@ func checkIsolationValueType(_ formance: InferredFromConformance,
168168
}
169169

170170
// check for instance members that do not need global-actor protection
171+
172+
// expected-warning@+2 {{memberwise initializer for 'NoGlobalActorValueType' cannot be both nonisolated and global actor 'SomeGlobalActor'-isolated; this is an error in Swift 6}}
171173
// expected-note@+1 2 {{consider making struct 'NoGlobalActorValueType' conform to the 'Sendable' protocol}}
172174
struct NoGlobalActorValueType {
173175
@SomeGlobalActor var point: Point // expected-warning {{stored property 'point' within struct cannot have a global actor; this is an error in Swift 6}}
176+
// expected-note@-1 {{initializer for property 'point' is global actor 'SomeGlobalActor'-isolated}}
174177

175178
@MainActor let counter: Int // expected-warning {{stored property 'counter' within struct cannot have a global actor; this is an error in Swift 6}}
176179

test/Concurrency/global_actor_inference.swift

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -558,9 +558,13 @@ struct WrapperOnUnsafeActor<Wrapped> {
558558
}
559559
}
560560

561-
// HasWrapperOnUnsafeActor gets an inferred @MainActor attribute.
561+
// HasWrapperOnUnsafeActor does not have an inferred global actor attribute,
562+
// because synced and $synced have different global actors.
562563
struct HasWrapperOnUnsafeActor {
563-
@WrapperOnUnsafeActor var synced: Int = 0 // expected-complete-sns-warning {{global actor 'OtherGlobalActor'-isolated default value in a main actor-isolated context; this is an error in Swift 6}}
564+
// expected-complete-sns-warning@-1 {{memberwise initializer for 'HasWrapperOnUnsafeActor' cannot be both nonisolated and global actor 'OtherGlobalActor'-isolated; this is an error in Swift 6}}
565+
// expected-complete-sns-warning@-2 {{default initializer for 'HasWrapperOnUnsafeActor' cannot be both nonisolated and global actor 'OtherGlobalActor'-isolated; this is an error in Swift 6}}
566+
567+
@WrapperOnUnsafeActor var synced: Int = 0 // expected-complete-sns-note 2 {{initializer for property '_synced' is global actor 'OtherGlobalActor'-isolated}}
564568
// expected-note @-1 3{{property declared here}}
565569
// expected-complete-sns-note @-2 3{{property declared here}}
566570

@@ -585,6 +589,10 @@ struct HasWrapperOnUnsafeActor {
585589
}
586590
}
587591

592+
nonisolated func createHasWrapperOnUnsafeActor() {
593+
_ = HasWrapperOnUnsafeActor()
594+
}
595+
588596
// ----------------------------------------------------------------------
589597
// Nonisolated closures
590598
// ----------------------------------------------------------------------
@@ -669,7 +677,9 @@ func replacesDynamicOnMainActor() {
669677
// Global-actor isolation of stored property initializer expressions
670678
// ----------------------------------------------------------------------
671679

680+
// expected-complete-sns-warning@+1 {{default initializer for 'Cutter' cannot be both nonisolated and main actor-isolated; this is an error in Swift 6}}
672681
class Cutter {
682+
// expected-complete-sns-note@+1 {{initializer for property 'x' is main actor-isolated}}
673683
@MainActor var x = useFooInADefer()
674684
@MainActor var y = { () -> Bool in
675685
var z = statefulThingy

test/Concurrency/isolated_default_arguments.swift

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
// RUN: %empty-directory(%t)
22

3-
// RUN: %target-swift-frontend -emit-module -emit-module-path %t/OtherActors.swiftmodule -module-name OtherActors %S/Inputs/OtherActors.swift -disable-availability-checking
4-
53
// RUN: %target-swift-frontend -I %t -disable-availability-checking -strict-concurrency=complete -enable-upcoming-feature IsolatedDefaultValues -parse-as-library -emit-sil -o /dev/null -verify %s
64
// RUN: %target-swift-frontend -I %t -disable-availability-checking -strict-concurrency=complete -parse-as-library -emit-sil -o /dev/null -verify -enable-upcoming-feature IsolatedDefaultValues -enable-experimental-feature SendNonSendable %s
75

@@ -196,21 +194,19 @@ extension A {
196194
}
197195
}
198196

199-
// expected-error@+1 {{default initializer for 'C1' cannot be both main actor-isolated and global actor 'SomeGlobalActor'-isolated}}
197+
// expected-warning@+1 {{default initializer for 'C1' cannot be both nonisolated and main actor-isolated; this is an error in Swift 6}}
200198
class C1 {
201199
// expected-note@+1 {{initializer for property 'x' is main actor-isolated}}
202200
@MainActor var x = requiresMainActor()
203-
// expected-note@+1 {{initializer for property 'y' is global actor 'SomeGlobalActor'-isolated}}
204201
@SomeGlobalActor var y = requiresSomeGlobalActor()
205202
}
206203

207204
class NonSendable {}
208205

209-
// expected-error@+1 {{default initializer for 'C2' cannot be both main actor-isolated and global actor 'SomeGlobalActor'-isolated}}
206+
// expected-warning@+1 {{default initializer for 'C2' cannot be both nonisolated and main actor-isolated; this is an error in Swift 6}}
210207
class C2 {
211208
// expected-note@+1 {{initializer for property 'x' is main actor-isolated}}
212209
@MainActor var x = NonSendable()
213-
// expected-note@+1 {{initializer for property 'y' is global actor 'SomeGlobalActor'-isolated}}
214210
@SomeGlobalActor var y = NonSendable()
215211
}
216212

@@ -229,3 +225,42 @@ func callDefaultInit() async {
229225
_ = NonIsolatedInit()
230226
_ = NonIsolatedInit(x: 10)
231227
}
228+
229+
@propertyWrapper
230+
@preconcurrency @MainActor
231+
struct RequiresMain<Value> {
232+
var wrappedValue: Value
233+
234+
init(wrappedValue: Value) {
235+
self.wrappedValue = wrappedValue
236+
}
237+
}
238+
239+
// This is okay; UseRequiresMain has an inferred 'MainActor'
240+
// attribute.
241+
struct UseRequiresMain {
242+
@RequiresMain private var x = 10
243+
}
244+
245+
nonisolated func test() async {
246+
// expected-error@+2 {{expression is 'async' but is not marked with 'await'}}
247+
// expected-note@+1 {{calls to initializer 'init()' from outside of its actor context are implicitly asynchronous}}
248+
_ = UseRequiresMain()
249+
}
250+
251+
// expected-warning@+2 {{memberwise initializer for 'InitAccessors' cannot be both nonisolated and main actor-isolated; this is an error in Swift 6}}
252+
// expected-warning@+1 {{default initializer for 'InitAccessors' cannot be both nonisolated and main actor-isolated; this is an error in Swift 6}}
253+
struct InitAccessors {
254+
private var _a: Int
255+
256+
// expected-note@+1 2 {{initializer for property 'a' is main actor-isolated}}
257+
@MainActor var a: Int = 5 {
258+
@storageRestrictions(initializes: _a)
259+
init {
260+
_a = requiresMainActor()
261+
}
262+
get {
263+
_a
264+
}
265+
}
266+
}

0 commit comments

Comments
 (0)