Skip to content

Commit 3e816f5

Browse files
authored
Merge pull request swiftlang#71034 from hborla/5.10-default-init-isolation
[5.10][Concurrency] Handle cases where a property initializer is subsumed by another property for `IsolatedDefaultValues`.
2 parents 53f2ff7 + 38a9faa commit 3e816f5

File tree

5 files changed

+158
-44
lines changed

5 files changed

+158
-44
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: 70 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -349,45 +349,82 @@ static ConstructorDecl *createImplicitConstructor(NominalTypeDecl *decl,
349349
// initializers apply Sendable checking to arguments at the call-site,
350350
// and actor initializers do not run on the actor, so initial values
351351
// cannot be actor-instance-isolated.
352-
bool shouldAddNonisolated = true;
353-
llvm::Optional<ActorIsolation> existingIsolation = llvm::None;
352+
ActorIsolation existingIsolation = getActorIsolation(decl);
354353
VarDecl *previousVar = nullptr;
354+
bool hasError = false;
355+
356+
// FIXME: Calling `getAllMembers` here causes issues for conformance
357+
// synthesis to RawRepresentable and friends. Instead, iterate over
358+
// both the stored properties and the init accessor properties, as
359+
// those can participate in implicit initializers.
360+
361+
auto stored = decl->getStoredProperties();
362+
auto initAccessor = decl->getInitAccessorProperties();
363+
364+
auto shouldAddNonisolated = [&](ArrayRef<VarDecl *> properties) {
365+
if (hasError)
366+
return false;
367+
368+
bool addNonisolated = true;
369+
for (auto *var : properties) {
370+
auto *pbd = var->getParentPatternBinding();
371+
if (!pbd)
372+
continue;
373+
374+
auto i = pbd->getPatternEntryIndexForVarDecl(var);
375+
if (pbd->isInitializerSubsumed(i))
376+
continue;
377+
378+
ActorIsolation initIsolation;
379+
if (var->hasInitAccessor()) {
380+
// Init accessors share the actor isolation of the property;
381+
// the accessor body can call anything in that isolation domain,
382+
// and we don't attempt to infer when the isolation isn't
383+
// necessary.
384+
initIsolation = getActorIsolation(var);
385+
} else {
386+
initIsolation = var->getInitializerIsolation();
387+
}
355388

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()) {
360-
auto type = var->getTypeInContext();
361-
auto isolation = getActorIsolation(var);
362-
if (isolation.isGlobalActor()) {
363-
if (!isSendableType(decl->getModuleContext(), type) ||
364-
var->getInitializerIsolation().isGlobalActor()) {
365-
// If different isolated stored properties require different
366-
// global actors, it is impossible to initialize this type.
367-
if (existingIsolation &&
368-
*existingIsolation != isolation) {
369-
ctx.Diags.diagnose(decl->getLoc(),
370-
diag::conflicting_stored_property_isolation,
371-
ICK == ImplicitConstructorKind::Memberwise,
372-
decl->getDeclaredType(), *existingIsolation, isolation);
373-
previousVar->diagnose(
374-
diag::property_requires_actor,
375-
previousVar->getDescriptiveKind(),
376-
previousVar->getName(), *existingIsolation);
377-
var->diagnose(
378-
diag::property_requires_actor,
379-
var->getDescriptiveKind(),
380-
var->getName(), isolation);
381-
}
389+
auto type = var->getTypeInContext();
390+
auto isolation = getActorIsolation(var);
391+
if (isolation.isGlobalActor()) {
392+
if (!isSendableType(decl->getModuleContext(), type) ||
393+
initIsolation.isGlobalActor()) {
394+
// If different isolated stored properties require different
395+
// global actors, it is impossible to initialize this type.
396+
if (existingIsolation != isolation) {
397+
ctx.Diags.diagnose(decl->getLoc(),
398+
diag::conflicting_stored_property_isolation,
399+
ICK == ImplicitConstructorKind::Memberwise,
400+
decl->getDeclaredType(), existingIsolation, isolation)
401+
.warnUntilSwiftVersion(6);
402+
if (previousVar) {
403+
previousVar->diagnose(
404+
diag::property_requires_actor,
405+
previousVar->getDescriptiveKind(),
406+
previousVar->getName(), existingIsolation);
407+
}
408+
var->diagnose(
409+
diag::property_requires_actor,
410+
var->getDescriptiveKind(),
411+
var->getName(), isolation);
412+
hasError = true;
413+
return false;
414+
}
382415

383-
existingIsolation = isolation;
384-
previousVar = var;
385-
shouldAddNonisolated = false;
416+
existingIsolation = isolation;
417+
previousVar = var;
418+
addNonisolated = false;
419+
}
386420
}
387421
}
388-
}
389422

390-
if (shouldAddNonisolated) {
423+
return addNonisolated;
424+
};
425+
426+
if (shouldAddNonisolated(stored) &&
427+
shouldAddNonisolated(initAccessor)) {
391428
addNonIsolatedToSynthesized(decl, ctor);
392429
}
393430
}

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: 60 additions & 7 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

@@ -151,7 +149,7 @@ struct S2 {
151149
}
152150

153151
struct S3 {
154-
// expected-error@+1 {{default argument cannot be both main actor-isolated and global actor 'SomeGlobalActor'-isolated}}
152+
// expected-error@+1 3 {{default argument cannot be both main actor-isolated and global actor 'SomeGlobalActor'-isolated}}
155153
var (x, y, z) = (requiresMainActor(), requiresSomeGlobalActor(), 10)
156154
}
157155

@@ -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

@@ -224,8 +220,65 @@ class C3 {
224220
var y = 0
225221
}
226222

223+
@MainActor class MultipleVars {
224+
var (x, y) = (0, 0)
225+
}
226+
227227
func callDefaultInit() async {
228228
_ = C2()
229229
_ = NonIsolatedInit()
230230
_ = NonIsolatedInit(x: 10)
231+
_ = MultipleVars()
232+
}
233+
234+
// expected-warning@+1 {{default initializer for 'MultipleVarsInvalid' cannot be both nonisolated and main actor-isolated; this is an error in Swift 6}}
235+
class MultipleVarsInvalid {
236+
// expected-note@+1 {{initializer for property 'x' is main actor-isolated}}
237+
@MainActor var (x, y) = (requiresMainActor(), requiresMainActor())
238+
}
239+
240+
@propertyWrapper
241+
@preconcurrency @MainActor
242+
struct RequiresMain<Value> {
243+
var wrappedValue: Value
244+
245+
init(wrappedValue: Value) {
246+
self.wrappedValue = wrappedValue
247+
}
248+
}
249+
250+
// This is okay; UseRequiresMain has an inferred 'MainActor'
251+
// attribute.
252+
struct UseRequiresMain {
253+
@RequiresMain private var x = 10
254+
}
255+
256+
nonisolated func test() async {
257+
// expected-error@+2 {{expression is 'async' but is not marked with 'await'}}
258+
// expected-note@+1 {{calls to initializer 'init()' from outside of its actor context are implicitly asynchronous}}
259+
_ = UseRequiresMain()
260+
}
261+
262+
// expected-warning@+2 {{memberwise initializer for 'InitAccessors' cannot be both nonisolated and main actor-isolated; this is an error in Swift 6}}
263+
// expected-warning@+1 {{default initializer for 'InitAccessors' cannot be both nonisolated and main actor-isolated; this is an error in Swift 6}}
264+
struct InitAccessors {
265+
private var _a: Int
266+
267+
// expected-note@+1 2 {{initializer for property 'a' is main actor-isolated}}
268+
@MainActor var a: Int = 5 {
269+
@storageRestrictions(initializes: _a)
270+
init {
271+
_a = requiresMainActor()
272+
}
273+
get {
274+
_a
275+
}
276+
}
277+
}
278+
279+
// Make sure isolation inference for implicit initializers
280+
// doesn't impact conformance synthesis.
281+
282+
struct CError: Error, RawRepresentable {
283+
var rawValue: CInt
231284
}

0 commit comments

Comments
 (0)