Add a function for querying the isolation of an Initializer.

This commit is contained in:
John McCall
2025-09-09 14:15:05 -04:00
parent a6c40c75c8
commit df7cfbfbc1
2 changed files with 65 additions and 26 deletions

View File

@@ -28,6 +28,7 @@ class raw_ostream;
namespace swift {
class DeclContext;
class Initializer;
class ModuleDecl;
class VarDecl;
class NominalTypeDecl;
@@ -434,6 +435,10 @@ InferredActorIsolation getInferredActorIsolation(ValueDecl *value);
ActorIsolation
__AbstractClosureExpr_getActorIsolation(AbstractClosureExpr *CE);
/// Determine how the given initialization context is isolated.
ActorIsolation getActorIsolation(Initializer *init,
bool ignoreDefaultArguments = false);
/// Determine how the given declaration context is isolated.
/// \p getClosureActorIsolation allows the specification of actor isolation for
/// closures that haven't been saved been saved to the AST yet. This is useful

View File

@@ -12008,7 +12008,6 @@ ActorIsolation swift::getActorIsolationOfContext(
DeclContext *dc,
llvm::function_ref<ActorIsolation(AbstractClosureExpr *)>
getClosureActorIsolation) {
auto &ctx = dc->getASTContext();
auto dcToUse = dc;
// Defer bodies share the actor isolation of their enclosing context.
@@ -12023,44 +12022,79 @@ ActorIsolation swift::getActorIsolationOfContext(
if (auto *vd = dyn_cast_or_null<ValueDecl>(dcToUse->getAsDecl()))
return getActorIsolation(vd);
// In the context of the initializing or default-value expression of a
// stored property:
// - For a static stored property, the isolation matches the VarDecl.
// Static properties are initialized upon first use, so the isolation
// of the initializer must match the isolation required to access the
// property.
// - For a field of a nominal type, the expression can require the same
// actor isolation as the field itself. That default expression may only
// be used from inits that meet the required isolation.
if (auto *var = dcToUse->getNonLocalVarDecl()) {
// If IsolatedDefaultValues are enabled, treat this context as having
// unspecified isolation. We'll compute the required isolation for
// the initializer and validate that it matches the isolation of the
// var itself in the DefaultInitializerIsolation request.
if (ctx.LangOpts.hasFeature(Feature::IsolatedDefaultValues))
return ActorIsolation::forUnspecified();
return getActorIsolation(var);
}
if (auto *closure = dyn_cast<AbstractClosureExpr>(dcToUse)) {
return getClosureActorIsolation(closure);
}
if (auto *init = dyn_cast<Initializer>(dcToUse)) {
// FIXME: force default argument initializers to report a meaningless
// isolation in order to break a bunch of cycles with the way that
// isolation is computed for them.
return getActorIsolation(init, /*ignoreDefaultArguments*/ true);
}
if (isa<TopLevelCodeDecl>(dcToUse)) {
auto &ctx = dc->getASTContext();
if (dcToUse->isAsyncContext() ||
dcToUse->getASTContext().LangOpts.StrictConcurrencyLevel >=
StrictConcurrency::Complete) {
if (Type mainActor = dcToUse->getASTContext().getMainActorType())
ctx.LangOpts.StrictConcurrencyLevel >= StrictConcurrency::Complete) {
if (Type mainActor = ctx.getMainActorType())
return ActorIsolation::forGlobalActor(mainActor)
.withPreconcurrency(
!dcToUse->getASTContext().isSwiftVersionAtLeast(6));
.withPreconcurrency(!ctx.isSwiftVersionAtLeast(6));
}
}
return ActorIsolation::forUnspecified();
}
ActorIsolation swift::getActorIsolation(Initializer *init,
bool ignoreDefaultArguments) {
switch (init->getInitializerKind()) {
case InitializerKind::PatternBinding:
// In the context of the initializing or default-value expression of a
// stored property:
// - For a static stored property, the isolation matches the VarDecl.
// Static properties are initialized upon first use, so the isolation
// of the initializer must match the isolation required to access the
// property.
// - For a field of a nominal type, the expression can require the same
// actor isolation as the field itself. That default expression may only
// be used from inits that meet the required isolation.
if (auto *var = init->getNonLocalVarDecl()) {
auto &ctx = var->getASTContext();
// If IsolatedDefaultValues are enabled, treat this context as having
// unspecified isolation. We'll compute the required isolation for
// the initializer and validate that it matches the isolation of the
// var itself in the DefaultInitializerIsolation request.
if (ctx.LangOpts.hasFeature(Feature::IsolatedDefaultValues))
return ActorIsolation::forUnspecified();
return getActorIsolation(var);
}
return ActorIsolation::forUnspecified();
case InitializerKind::DefaultArgument: {
auto defArgInit = cast<DefaultArgumentInitializer>(init);
// A hack when used from getActorIsolationOfContext to maintain the
// current behavior and avoid request cycles.
if (ignoreDefaultArguments)
return ActorIsolation::forUnspecified();
auto fn = cast<ValueDecl>(defArgInit->getParent()->getAsDecl());
auto param = getParameterAt(fn, defArgInit->getIndex());
assert(param);
return param->getInitializerIsolation();
}
case InitializerKind::PropertyWrapper:
case InitializerKind::CustomAttribute:
return ActorIsolation::forUnspecified();
}
llvm_unreachable("bad initializer kind");
}
bool swift::isSameActorIsolated(ValueDecl *value, DeclContext *dc) {
auto valueIsolation = getActorIsolation(value);
auto dcIsolation = getActorIsolationOfContext(dc);