Skip to content

Commit 38a9325

Browse files
committed
[Sema] Add custom functions to ActorIsolationChecker to determine expr type and closure actor isolation
When we get rid of `LeaveClosureBodiesUnchecked` we no longer save closure types to the AST and thus also don’t save their actor isolation to the AST. Hence, we need to extract types and actor isolations of parent closures from the constraint system solution instead of the AST. This prepares `ActorIsolationChecker` to take custom functions to determine the type of an expression or the actor isolation of a closure.
1 parent b93997a commit 38a9325

File tree

10 files changed

+128
-50
lines changed

10 files changed

+128
-50
lines changed

include/swift/AST/ActorIsolation.h

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,19 @@ class VarDecl;
3030
class NominalTypeDecl;
3131
class SubstitutionMap;
3232
class AbstractFunctionDecl;
33+
class AbstractClosureExpr;
34+
class ClosureActorIsolation;
35+
36+
/// Trampoline for AbstractClosureExpr::getActorIsolation.
37+
ClosureActorIsolation
38+
__AbstractClosureExpr_getActorIsolation(AbstractClosureExpr *CE);
39+
40+
/// Returns a function reference to \c __AbstractClosureExpr_getActorIsolation.
41+
/// This is needed so we can use it as a default argument for
42+
/// \c getActorIsolationOfContext without knowing the layout of
43+
/// \c ClosureActorIsolation.
44+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
45+
_getRef__AbstractClosureExpr_getActorIsolation();
3346

3447
/// Determine whether the given types are (canonically) equal, declared here
3548
/// to avoid having to include Types.h.
@@ -191,7 +204,15 @@ class ActorIsolation {
191204
ActorIsolation getActorIsolation(ValueDecl *value);
192205

193206
/// Determine how the given declaration context is isolated.
194-
ActorIsolation getActorIsolationOfContext(DeclContext *dc);
207+
/// \p getClosureActorIsolation allows the specification of actor isolation for
208+
/// closures that haven't been saved been saved to the AST yet. This is useful
209+
/// for solver-based code completion which doesn't modify the AST but stores the
210+
/// actor isolation of closures in the constraint system solution.
211+
ActorIsolation getActorIsolationOfContext(
212+
DeclContext *dc,
213+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
214+
getClosureActorIsolation =
215+
_getRef__AbstractClosureExpr_getActorIsolation());
195216

196217
/// Check if both the value, and context are isolated to the same actor.
197218
bool isSameActorIsolated(ValueDecl *value, DeclContext *dc);

include/swift/IDE/CompletionLookup.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,10 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
126126
llvm::SmallDenseMap<const VarDecl *, Type> SolutionSpecificVarTypes;
127127

128128
bool CanCurrDeclContextHandleAsync = false;
129+
/// Actor isolations that were determined during constraint solving but that
130+
/// haven't been saved to the AST.
131+
llvm::DenseMap<AbstractClosureExpr *, ClosureActorIsolation>
132+
ClosureActorIsolations;
129133
bool HaveDot = false;
130134
bool IsUnwrappedOptional = false;
131135
SourceLoc DotLoc;
@@ -258,6 +262,12 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
258262
this->CanCurrDeclContextHandleAsync = CanCurrDeclContextHandleAsync;
259263
}
260264

265+
void setClosureActorIsolations(
266+
llvm::DenseMap<AbstractClosureExpr *, ClosureActorIsolation>
267+
ClosureActorIsolations) {
268+
this->ClosureActorIsolations = ClosureActorIsolations;
269+
}
270+
261271
const ExpectedTypeContext *getExpectedTypeContext() const {
262272
return &expectedTypeContext;
263273
}

include/swift/Sema/IDETypeChecking.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,12 @@ namespace swift {
325325
/// Just a proxy to swift::contextUsesConcurrencyFeatures() from lib/IDE code.
326326
bool completionContextUsesConcurrencyFeatures(const DeclContext *dc);
327327

328+
/// Determine the isolation of a particular closure.
329+
ClosureActorIsolation determineClosureActorIsolation(
330+
AbstractClosureExpr *closure, llvm::function_ref<Type(Expr *)> getType,
331+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
332+
getClosureActorIsolation);
333+
328334
/// If the capture list shadows any declarations using shorthand syntax, i.e.
329335
/// syntax that names both the newly declared variable and the referenced
330336
/// variable by the same identifier in the source text, i.e. `[foo]`, return

lib/AST/Decl.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9206,7 +9206,10 @@ ActorIsolation swift::getActorIsolation(ValueDecl *value) {
92069206
ActorIsolation::forUnspecified());
92079207
}
92089208

9209-
ActorIsolation swift::getActorIsolationOfContext(DeclContext *dc) {
9209+
ActorIsolation swift::getActorIsolationOfContext(
9210+
DeclContext *dc,
9211+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
9212+
getClosureActorIsolation) {
92109213
if (auto *vd = dyn_cast_or_null<ValueDecl>(dc->getAsDecl()))
92119214
return getActorIsolation(vd);
92129215

@@ -9215,7 +9218,7 @@ ActorIsolation swift::getActorIsolationOfContext(DeclContext *dc) {
92159218

92169219

92179220
if (auto *closure = dyn_cast<AbstractClosureExpr>(dc)) {
9218-
return closure->getActorIsolation().getActorIsolation();
9221+
return getClosureActorIsolation(closure).getActorIsolation();
92199222
}
92209223

92219224
if (auto *tld = dyn_cast<TopLevelCodeDecl>(dc)) {
@@ -9234,7 +9237,7 @@ ActorIsolation swift::getActorIsolationOfContext(DeclContext *dc) {
92349237

92359238
bool swift::isSameActorIsolated(ValueDecl *value, DeclContext *dc) {
92369239
auto valueIsolation = getActorIsolation(value);
9237-
auto dcIsolation = getActorIsolationOfContext(dc);
9240+
auto dcIsolation = getActorIsolationOfContext(dc);
92389241
return valueIsolation.isActorIsolated() && dcIsolation.isActorIsolated() &&
92399242
valueIsolation.getActor() == dcIsolation.getActor();
92409243
}

lib/AST/Expr.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1860,6 +1860,16 @@ Expr *AbstractClosureExpr::getSingleExpressionBody() const {
18601860
return nullptr;
18611861
}
18621862

1863+
ClosureActorIsolation
1864+
swift::__AbstractClosureExpr_getActorIsolation(AbstractClosureExpr *CE) {
1865+
return CE->getActorIsolation();
1866+
}
1867+
1868+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
1869+
swift::_getRef__AbstractClosureExpr_getActorIsolation() {
1870+
return __AbstractClosureExpr_getActorIsolation;
1871+
}
1872+
18631873
#define FORWARD_SOURCE_LOCS_TO(CLASS, NODE) \
18641874
SourceRange CLASS::getSourceRange() const { \
18651875
return (NODE)->getSourceRange(); \

lib/IDE/CompletionLookup.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -755,8 +755,19 @@ void CompletionLookup::analyzeActorIsolation(
755755
}
756756
LLVM_FALLTHROUGH;
757757
case ActorIsolation::GlobalActor: {
758-
auto contextIsolation =
759-
getActorIsolationOfContext(const_cast<DeclContext *>(CurrDeclContext));
758+
auto getClosureActorIsolation = [this](AbstractClosureExpr *CE) {
759+
// Prefer solution-specific actor-isolations and fall back to the one
760+
// recorded in the AST.
761+
auto isolation = ClosureActorIsolations.find(CE);
762+
if (isolation != ClosureActorIsolations.end()) {
763+
return isolation->second;
764+
} else {
765+
return CE->getActorIsolation();
766+
}
767+
};
768+
auto contextIsolation = getActorIsolationOfContext(
769+
const_cast<DeclContext *>(CurrDeclContext),
770+
getClosureActorIsolation);
760771
if (contextIsolation != isolation) {
761772
implicitlyAsync = true;
762773
}

lib/SILGen/SILGenProlog.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -895,7 +895,10 @@ void SILGenFunction::emitHopToActorValue(SILLocation loc, ManagedValue actor) {
895895
if (!F.isAsync()) {
896896
llvm::report_fatal_error("Builtin.hopToActor must be in an async function");
897897
}
898-
auto isolation = getActorIsolationOfContext(FunctionDC);
898+
auto isolation =
899+
getActorIsolationOfContext(FunctionDC, [](AbstractClosureExpr *CE) {
900+
return CE->getActorIsolation();
901+
});
899902
if (isolation != ActorIsolation::Independent
900903
&& isolation != ActorIsolation::Unspecified) {
901904
// TODO: Explicit hop with no hop-back should only be allowed in independent

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 50 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1474,10 +1474,14 @@ static bool checkedByFlowIsolation(DeclContext const *refCxt,
14741474
}
14751475

14761476
/// Get the actor isolation of the innermost relevant context.
1477-
static ActorIsolation getInnermostIsolatedContext(const DeclContext *dc) {
1477+
static ActorIsolation getInnermostIsolatedContext(
1478+
const DeclContext *dc,
1479+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
1480+
getClosureActorIsolation) {
14781481
// Retrieve the actor isolation of the context.
14791482
auto mutableDC = const_cast<DeclContext *>(dc);
1480-
switch (auto isolation = getActorIsolationOfContext(mutableDC)) {
1483+
switch (auto isolation =
1484+
getActorIsolationOfContext(mutableDC, getClosureActorIsolation)) {
14811485
case ActorIsolation::ActorInstance:
14821486
case ActorIsolation::Independent:
14831487
case ActorIsolation::Unspecified:
@@ -1560,6 +1564,9 @@ namespace {
15601564
SmallVector<ApplyExpr*, 4> applyStack;
15611565
SmallVector<std::pair<OpaqueValueExpr *, Expr *>, 4> opaqueValues;
15621566
SmallVector<const PatternBindingDecl *, 2> patternBindingStack;
1567+
llvm::function_ref<Type(Expr *)> getType;
1568+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
1569+
getClosureActorIsolation;
15631570

15641571
/// Keeps track of the capture context of variables that have been
15651572
/// explicitly captured in closures.
@@ -1758,7 +1765,13 @@ namespace {
17581765
}
17591766

17601767
public:
1761-
ActorIsolationChecker(const DeclContext *dc) : ctx(dc->getASTContext()) {
1768+
ActorIsolationChecker(
1769+
const DeclContext *dc,
1770+
llvm::function_ref<Type(Expr *)> getType = __Expr_getType,
1771+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
1772+
getClosureActorIsolation = __AbstractClosureExpr_getActorIsolation)
1773+
: ctx(dc->getASTContext()), getType(getType),
1774+
getClosureActorIsolation(getClosureActorIsolation) {
17621775
contextStack.push_back(dc);
17631776
}
17641777

@@ -2058,7 +2071,7 @@ namespace {
20582071
break;
20592072

20602073
if (auto closure = dyn_cast<AbstractClosureExpr>(dc)) {
2061-
auto isolation = closure->getActorIsolation();
2074+
auto isolation = getClosureActorIsolation(closure);
20622075
switch (isolation) {
20632076
case ClosureActorIsolation::Independent:
20642077
if (isSendableClosure(closure, /*forActorIsolation=*/true)) {
@@ -2113,7 +2126,8 @@ namespace {
21132126
// Check isolation of the context itself. We do this separately
21142127
// from the closure check because closures capture specific variables
21152128
// while general isolation is declaration-based.
2116-
switch (auto isolation = getActorIsolationOfContext(dc)) {
2129+
switch (auto isolation =
2130+
getActorIsolationOfContext(dc, getClosureActorIsolation)) {
21172131
case ActorIsolation::Independent:
21182132
case ActorIsolation::Unspecified:
21192133
// Local functions can capture an isolated parameter.
@@ -2487,7 +2501,7 @@ namespace {
24872501

24882502
/// Check actor isolation for a particular application.
24892503
bool checkApply(ApplyExpr *apply) {
2490-
auto fnExprType = apply->getFn()->getType();
2504+
auto fnExprType = getType(apply->getFn());
24912505
if (!fnExprType)
24922506
return false;
24932507

@@ -2502,7 +2516,8 @@ namespace {
25022516
return *contextIsolation;
25032517

25042518
auto declContext = const_cast<DeclContext *>(getDeclContext());
2505-
contextIsolation = getInnermostIsolatedContext(declContext);
2519+
contextIsolation =
2520+
getInnermostIsolatedContext(declContext, getClosureActorIsolation);
25062521
return *contextIsolation;
25072522
};
25082523

@@ -2539,9 +2554,9 @@ namespace {
25392554
// FIXME: The modeling of unsatisfiedIsolation is not great here.
25402555
// We'd be better off using something more like closure isolation
25412556
// that can talk about specific parameters.
2542-
auto nominal = arg->getType()->getAnyNominal();
2557+
auto nominal = getType(arg)->getAnyNominal();
25432558
if (!nominal) {
2544-
nominal = arg->getType()->getASTContext().getProtocol(
2559+
nominal = getType(arg)->getASTContext().getProtocol(
25452560
KnownProtocolKind::Actor);
25462561
}
25472562

@@ -2785,7 +2800,7 @@ namespace {
27852800
// where k is a captured dictionary key.
27862801
if (auto *args = component.getSubscriptArgs()) {
27872802
for (auto arg : *args) {
2788-
auto type = arg.getExpr()->getType();
2803+
auto type = getType(arg.getExpr());
27892804
if (type &&
27902805
shouldDiagnoseExistingDataRaces(getDeclContext()) &&
27912806
diagnoseNonSendableTypes(
@@ -2818,8 +2833,8 @@ namespace {
28182833
if (base)
28192834
isolatedActor.emplace(getIsolatedActor(base));
28202835
auto result = ActorReferenceResult::forReference(
2821-
declRef, loc, getDeclContext(),
2822-
kindOfUsage(decl, context), isolatedActor);
2836+
declRef, loc, getDeclContext(), kindOfUsage(decl, context),
2837+
isolatedActor, None, None, getClosureActorIsolation);
28232838
switch (result) {
28242839
case ActorReferenceResult::SameConcurrencyDomain:
28252840
if (diagnoseReferenceToUnsafeGlobal(decl, loc))
@@ -2903,7 +2918,8 @@ namespace {
29032918
refKind = isolatedActor->kind;
29042919
refGlobalActor = isolatedActor->globalActor;
29052920
} else {
2906-
auto contextIsolation = getInnermostIsolatedContext(getDeclContext());
2921+
auto contextIsolation = getInnermostIsolatedContext(
2922+
getDeclContext(), getClosureActorIsolation);
29072923
switch (contextIsolation) {
29082924
case ActorIsolation::ActorInstance:
29092925
refKind = ReferencedActor::Isolated;
@@ -2952,7 +2968,7 @@ namespace {
29522968
// Attempt to resolve the global actor type of a closure.
29532969
Type resolveGlobalActorType(ClosureExpr *closure) {
29542970
// Check whether the closure's type has a global actor already.
2955-
if (Type closureType = closure->getType()) {
2971+
if (Type closureType = getType(closure)) {
29562972
if (auto closureFnType = closureType->getAs<FunctionType>()) {
29572973
if (Type globalActor = closureFnType->getGlobalActor())
29582974
return globalActor;
@@ -2994,7 +3010,8 @@ namespace {
29943010
return ClosureActorIsolation::forIndependent(preconcurrency);
29953011

29963012
// A non-Sendable closure gets its isolation from its context.
2997-
auto parentIsolation = getActorIsolationOfContext(closure->getParent());
3013+
auto parentIsolation = getActorIsolationOfContext(
3014+
closure->getParent(), getClosureActorIsolation);
29983015
preconcurrency |= parentIsolation.preconcurrency();
29993016

30003017
// We must have parent isolation determined to get here.
@@ -3032,10 +3049,10 @@ bool ActorIsolationChecker::mayExecuteConcurrentlyWith(
30323049
// If both contexts are isolated to the same actor, then they will not
30333050
// execute concurrently.
30343051
auto useIsolation = getActorIsolationOfContext(
3035-
const_cast<DeclContext *>(useContext));
3052+
const_cast<DeclContext *>(useContext), getClosureActorIsolation);
30363053
if (useIsolation.isActorIsolated()) {
30373054
auto defIsolation = getActorIsolationOfContext(
3038-
const_cast<DeclContext *>(defContext));
3055+
const_cast<DeclContext *>(defContext), getClosureActorIsolation);
30393056
if (useIsolation == defIsolation)
30403057
return false;
30413058
}
@@ -3109,9 +3126,12 @@ void swift::checkPropertyWrapperActorIsolation(
31093126
expr->walk(checker);
31103127
}
31113128

3112-
ClosureActorIsolation
3113-
swift::determineClosureActorIsolation(AbstractClosureExpr *closure) {
3114-
ActorIsolationChecker checker(closure->getParent());
3129+
ClosureActorIsolation swift::determineClosureActorIsolation(
3130+
AbstractClosureExpr *closure, llvm::function_ref<Type(Expr *)> getType,
3131+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
3132+
getClosureActorIsolation) {
3133+
ActorIsolationChecker checker(closure->getParent(), getType,
3134+
getClosureActorIsolation);
31153135
return checker.determineClosureIsolation(closure);
31163136
}
31173137

@@ -3801,14 +3821,14 @@ ActorIsolation ActorIsolationRequest::evaluate(
38013821
// If this is a defer body, inherit unconditionally; we don't
38023822
// care if the enclosing function captures the isolated parameter.
38033823
if (func->isDeferBody()) {
3804-
auto enclosingIsolation =
3805-
getActorIsolationOfContext(func->getDeclContext());
3824+
auto enclosingIsolation = getActorIsolationOfContext(
3825+
func->getDeclContext());
38063826
return inferredIsolation(enclosingIsolation);
38073827
}
38083828

38093829
if (func->isLocalCapture() && !func->isSendable()) {
3810-
switch (auto enclosingIsolation =
3811-
getActorIsolationOfContext(func->getDeclContext())) {
3830+
switch (auto enclosingIsolation = getActorIsolationOfContext(
3831+
func->getDeclContext())) {
38123832
case ActorIsolation::Independent:
38133833
case ActorIsolation::Unspecified:
38143834
// Do nothing.
@@ -5092,10 +5112,11 @@ static bool equivalentIsolationContexts(
50925112

50935113
ActorReferenceResult ActorReferenceResult::forReference(
50945114
ConcreteDeclRef declRef, SourceLoc declRefLoc, const DeclContext *fromDC,
5095-
Optional<VarRefUseEnv> useKind,
5096-
Optional<ReferencedActor> actorInstance,
5115+
Optional<VarRefUseEnv> useKind, Optional<ReferencedActor> actorInstance,
50975116
Optional<ActorIsolation> knownDeclIsolation,
5098-
Optional<ActorIsolation> knownContextIsolation) {
5117+
Optional<ActorIsolation> knownContextIsolation,
5118+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
5119+
getClosureActorIsolation) {
50995120
// If not provided, compute the isolation of the declaration, adjusted
51005121
// for references.
51015122
ActorIsolation declIsolation = ActorIsolation::forUnspecified();
@@ -5117,7 +5138,8 @@ ActorReferenceResult ActorReferenceResult::forReference(
51175138
if (knownContextIsolation) {
51185139
contextIsolation = *knownContextIsolation;
51195140
} else {
5120-
contextIsolation = getInnermostIsolatedContext(fromDC);
5141+
contextIsolation =
5142+
getInnermostIsolatedContext(fromDC, getClosureActorIsolation);
51215143
}
51225144

51235145
// When the declaration is not actor-isolated, it can always be accessed

0 commit comments

Comments
 (0)