Skip to content

Commit d6fce01

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.
1 parent e9750bc commit d6fce01

File tree

4 files changed

+99
-5
lines changed

4 files changed

+99
-5
lines changed

include/swift/AST/DiagnosticsSema.def

+6
Original file line numberDiff line numberDiff line change
@@ -5345,6 +5345,12 @@ ERROR(distributed_actor_isolated_non_self_reference,none,
53455345
"distributed actor-isolated %kind0 can not be accessed from a "
53465346
"non-isolated context",
53475347
(const ValueDecl *))
5348+
ERROR(conflicting_stored_property_isolation,none,
5349+
"%select{default|memberwise}0 initializer for %1 cannot be both %2 and %3",
5350+
(bool, Type, ActorIsolation, ActorIsolation))
5351+
NOTE(property_requires_actor,none,
5352+
"initializer for %0 %1 is %2",
5353+
(DescriptiveDeclKind, Identifier, ActorIsolation))
53485354
ERROR(isolated_default_argument_context,none,
53495355
"%0 default value in a %1 context",
53505356
(ActorIsolation, ActorIsolation))

lib/Sema/CodeSynthesis.cpp

+55-4
Original file line numberDiff line numberDiff line change
@@ -337,13 +337,64 @@ static ConstructorDecl *createImplicitConstructor(NominalTypeDecl *decl,
337337
ctor->setSynthesized();
338338
ctor->setAccess(accessLevel);
339339

340+
if (ctx.LangOpts.hasFeature(Feature::IsolatedDefaultValues)) {
341+
// If any of the type's actor-isolated properties:
342+
// 1. Have non-Sendable type, or
343+
// 2. Have an isolated initial value
344+
// then the initializer must also be actor-isolated. If all
345+
// isolated properties have Sendable type and a nonisolated
346+
// default value, then the initializer can be nonisolated.
347+
//
348+
// These rules only apply for global actor isolation, because actor
349+
// initializers apply Sendable checking to arguments at the call-site,
350+
// and actor initializers do not run on the actor, so initial values
351+
// cannot be actor-instance-isolated.
352+
bool shouldAddNonisolated = true;
353+
llvm::Optional<ActorIsolation> existingIsolation = llvm::None;
354+
VarDecl *previousVar = nullptr;
355+
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+
}
382+
383+
existingIsolation = isolation;
384+
previousVar = var;
385+
shouldAddNonisolated = false;
386+
}
387+
}
388+
}
389+
390+
if (shouldAddNonisolated) {
391+
addNonIsolatedToSynthesized(decl, ctor);
392+
}
393+
}
394+
340395
if (ICK == ImplicitConstructorKind::Memberwise) {
341396
ctor->setIsMemberwiseInitializer();
342397

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

lib/Sema/TypeCheckConcurrency.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -4767,8 +4767,11 @@ DefaultInitializerIsolation::evaluate(Evaluator &evaluator,
47674767
return ActorIsolation::forUnspecified();
47684768

47694769
auto i = pbd->getPatternEntryIndexForVarDecl(var);
4770+
if (!pbd->isInitializerChecked(i))
4771+
TypeChecker::typeCheckPatternBinding(pbd, i);
4772+
47704773
dc = cast<Initializer>(pbd->getInitContext(i));
4771-
initExpr = var->getParentInitializer();
4774+
initExpr = pbd->getInit(i);
47724775
enclosingIsolation = getActorIsolation(var);
47734776
} else if (auto *param = dyn_cast<ParamDecl>(var)) {
47744777
// If this parameter corresponds to a stored property for a

test/Concurrency/isolated_default_arguments.swift

+34
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)