Skip to content

Commit 18ba448

Browse files
committed
[Concurrency] When isolated default values are enabled, synthesized initializers
should be nonisolated if all initialized properties are Sendable with nonisolated default values. (cherry picked from commit d6fce01)
1 parent c0696b1 commit 18ba448

File tree

4 files changed

+99
-5
lines changed

4 files changed

+99
-5
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5200,6 +5200,12 @@ ERROR(distributed_actor_isolated_non_self_reference,none,
52005200
"distributed actor-isolated %kind0 can not be accessed from a "
52015201
"non-isolated context",
52025202
(const ValueDecl *))
5203+
ERROR(conflicting_stored_property_isolation,none,
5204+
"%select{default|memberwise}0 initializer for %1 cannot be both %2 and %3",
5205+
(bool, Type, ActorIsolation, ActorIsolation))
5206+
NOTE(property_requires_actor,none,
5207+
"initializer for %0 %1 is %2",
5208+
(DescriptiveDeclKind, Identifier, ActorIsolation))
52035209
ERROR(isolated_default_argument_context,none,
52045210
"%0 default value in a %1 context",
52055211
(ActorIsolation, ActorIsolation))

lib/Sema/CodeSynthesis.cpp

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -336,13 +336,64 @@ static ConstructorDecl *createImplicitConstructor(NominalTypeDecl *decl,
336336
ctor->setSynthesized();
337337
ctor->setAccess(accessLevel);
338338

339+
if (ctx.LangOpts.hasFeature(Feature::IsolatedDefaultValues)) {
340+
// If any of the type's actor-isolated properties:
341+
// 1. Have non-Sendable type, or
342+
// 2. Have an isolated initial value
343+
// then the initializer must also be actor-isolated. If all
344+
// isolated properties have Sendable type and a nonisolated
345+
// default value, then the initializer can be nonisolated.
346+
//
347+
// These rules only apply for global actor isolation, because actor
348+
// initializers apply Sendable checking to arguments at the call-site,
349+
// and actor initializers do not run on the actor, so initial values
350+
// cannot be actor-instance-isolated.
351+
bool shouldAddNonisolated = true;
352+
llvm::Optional<ActorIsolation> existingIsolation = llvm::None;
353+
VarDecl *previousVar = nullptr;
354+
355+
// The memberwise init properties are also effectively what the
356+
// default init uses, e.g. default initializers initialize via
357+
// properties wrapped and init accessors.
358+
for (auto var : decl->getMemberwiseInitProperties()) {
359+
auto type = var->getTypeInContext();
360+
auto isolation = getActorIsolation(var);
361+
if (isolation.isGlobalActor()) {
362+
if (!isSendableType(decl->getModuleContext(), type) ||
363+
var->getInitializerIsolation().isGlobalActor()) {
364+
// If different isolated stored properties require different
365+
// global actors, it is impossible to initialize this type.
366+
if (existingIsolation &&
367+
*existingIsolation != isolation) {
368+
ctx.Diags.diagnose(decl->getLoc(),
369+
diag::conflicting_stored_property_isolation,
370+
ICK == ImplicitConstructorKind::Memberwise,
371+
decl->getDeclaredType(), *existingIsolation, isolation);
372+
previousVar->diagnose(
373+
diag::property_requires_actor,
374+
previousVar->getDescriptiveKind(),
375+
previousVar->getName(), *existingIsolation);
376+
var->diagnose(
377+
diag::property_requires_actor,
378+
var->getDescriptiveKind(),
379+
var->getName(), isolation);
380+
}
381+
382+
existingIsolation = isolation;
383+
previousVar = var;
384+
shouldAddNonisolated = false;
385+
}
386+
}
387+
}
388+
389+
if (shouldAddNonisolated) {
390+
addNonIsolatedToSynthesized(decl, ctor);
391+
}
392+
}
393+
339394
if (ICK == ImplicitConstructorKind::Memberwise) {
340395
ctor->setIsMemberwiseInitializer();
341396

342-
// FIXME: If 'IsolatedDefaultValues' is enabled, the memberwise init
343-
// should be 'nonisolated' if none of the memberwise-initialized properties
344-
// are global actor isolated and have non-Sendable type, and none of the
345-
// initial values require global actor isolation.
346397
if (!ctx.LangOpts.hasFeature(Feature::IsolatedDefaultValues)) {
347398
addNonIsolatedToSynthesized(decl, ctor);
348399
}

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4818,8 +4818,11 @@ DefaultInitializerIsolation::evaluate(Evaluator &evaluator,
48184818
return ActorIsolation::forUnspecified();
48194819

48204820
auto i = pbd->getPatternEntryIndexForVarDecl(var);
4821+
if (!pbd->isInitializerChecked(i))
4822+
TypeChecker::typeCheckPatternBinding(pbd, i);
4823+
48214824
dc = cast<Initializer>(pbd->getInitContext(i));
4822-
initExpr = var->getParentInitializer();
4825+
initExpr = pbd->getInit(i);
48234826
enclosingIsolation = getActorIsolation(var);
48244827
} else if (auto *param = dyn_cast<ParamDecl>(var)) {
48254828
// If this parameter corresponds to a stored property for a

test/Concurrency/isolated_default_arguments.swift

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,3 +195,37 @@ extension A {
195195
_ = S2(required: 10)
196196
}
197197
}
198+
199+
// expected-error@+1 {{default initializer for 'C1' cannot be both main actor-isolated and global actor 'SomeGlobalActor'-isolated}}
200+
class C1 {
201+
// expected-note@+1 {{initializer for property 'x' is main actor-isolated}}
202+
@MainActor var x = requiresMainActor()
203+
// expected-note@+1 {{initializer for property 'y' is global actor 'SomeGlobalActor'-isolated}}
204+
@SomeGlobalActor var y = requiresSomeGlobalActor()
205+
}
206+
207+
class NonSendable {}
208+
209+
// expected-error@+1 {{default initializer for 'C2' cannot be both main actor-isolated and global actor 'SomeGlobalActor'-isolated}}
210+
class C2 {
211+
// expected-note@+1 {{initializer for property 'x' is main actor-isolated}}
212+
@MainActor var x = NonSendable()
213+
// expected-note@+1 {{initializer for property 'y' is global actor 'SomeGlobalActor'-isolated}}
214+
@SomeGlobalActor var y = NonSendable()
215+
}
216+
217+
class C3 {
218+
@MainActor var x = 1
219+
@SomeGlobalActor var y = 2
220+
}
221+
222+
@MainActor struct NonIsolatedInit {
223+
var x = 0
224+
var y = 0
225+
}
226+
227+
func callDefaultInit() async {
228+
_ = C2()
229+
_ = NonIsolatedInit()
230+
_ = NonIsolatedInit(x: 10)
231+
}

0 commit comments

Comments
 (0)