Skip to content

Commit 7bd762e

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 4b564f2 commit 7bd762e

File tree

9 files changed

+120
-51
lines changed

9 files changed

+120
-51
lines changed

include/swift/AST/ActorIsolation.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ class VarDecl;
3030
class NominalTypeDecl;
3131
class SubstitutionMap;
3232
class AbstractFunctionDecl;
33+
class AbstractClosureExpr;
34+
class ClosureActorIsolation;
3335

3436
/// Determine whether the given types are (canonically) equal, declared here
3537
/// to avoid having to include Types.h.
@@ -191,7 +193,14 @@ class ActorIsolation {
191193
ActorIsolation getActorIsolation(ValueDecl *value);
192194

193195
/// Determine how the given declaration context is isolated.
194-
ActorIsolation getActorIsolationOfContext(DeclContext *dc);
196+
/// \p getClosureActorIsolation allows the specification of actor isolation for
197+
/// closures that haven't been saved been saved to the AST yet. This is useful
198+
/// for solver-based code completion which doesn't modify the AST but stores the
199+
/// actor isolation of closures in the constraint system solution.
200+
ActorIsolation getActorIsolationOfContext(
201+
DeclContext *dc,
202+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
203+
getClosureActorIsolation);
195204

196205
/// Check if both the value, and context are isolated to the same actor.
197206
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: 7 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,8 @@ 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(
9241+
dc, [](AbstractClosureExpr *ACE) { return ACE->getActorIsolation(); });
92389242
return valueIsolation.isActorIsolated() && dcIsolation.isActorIsolated() &&
92399243
valueIsolation.getActor() == dcIsolation.getActor();
92409244
}

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
@@ -873,7 +873,10 @@ void SILGenFunction::emitHopToActorValue(SILLocation loc, ManagedValue actor) {
873873
if (!F.isAsync()) {
874874
llvm::report_fatal_error("Builtin.hopToActor must be in an async function");
875875
}
876-
auto isolation = getActorIsolationOfContext(FunctionDC);
876+
auto isolation =
877+
getActorIsolationOfContext(FunctionDC, [](AbstractClosureExpr *CE) {
878+
return CE->getActorIsolation();
879+
});
877880
if (isolation != ActorIsolation::Independent
878881
&& isolation != ActorIsolation::Unspecified) {
879882
// TODO: Explicit hop with no hop-back should only be allowed in independent

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 59 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@
3131

3232
using namespace swift;
3333

34+
ClosureActorIsolation
35+
swift::__AbstractClosureExpr_getActorIsolation(AbstractClosureExpr *CE) {
36+
return CE->getActorIsolation();
37+
}
38+
3439
/// Determine whether it makes sense to infer an attribute in the given
3540
/// context.
3641
static bool shouldInferAttributeInContext(const DeclContext *dc) {
@@ -1474,10 +1479,14 @@ static bool checkedByFlowIsolation(DeclContext const *refCxt,
14741479
}
14751480

14761481
/// Get the actor isolation of the innermost relevant context.
1477-
static ActorIsolation getInnermostIsolatedContext(const DeclContext *dc) {
1482+
static ActorIsolation getInnermostIsolatedContext(
1483+
const DeclContext *dc,
1484+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
1485+
getClosureActorIsolation) {
14781486
// Retrieve the actor isolation of the context.
14791487
auto mutableDC = const_cast<DeclContext *>(dc);
1480-
switch (auto isolation = getActorIsolationOfContext(mutableDC)) {
1488+
switch (auto isolation =
1489+
getActorIsolationOfContext(mutableDC, getClosureActorIsolation)) {
14811490
case ActorIsolation::ActorInstance:
14821491
case ActorIsolation::Independent:
14831492
case ActorIsolation::Unspecified:
@@ -1560,6 +1569,9 @@ namespace {
15601569
SmallVector<ApplyExpr*, 4> applyStack;
15611570
SmallVector<std::pair<OpaqueValueExpr *, Expr *>, 4> opaqueValues;
15621571
SmallVector<const PatternBindingDecl *, 2> patternBindingStack;
1572+
llvm::function_ref<Type(Expr *)> getType;
1573+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
1574+
getClosureActorIsolation;
15631575

15641576
/// Keeps track of the capture context of variables that have been
15651577
/// explicitly captured in closures.
@@ -1758,7 +1770,13 @@ namespace {
17581770
}
17591771

17601772
public:
1761-
ActorIsolationChecker(const DeclContext *dc) : ctx(dc->getASTContext()) {
1773+
ActorIsolationChecker(
1774+
const DeclContext *dc,
1775+
llvm::function_ref<Type(Expr *)> getType = __Expr_getType,
1776+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
1777+
getClosureActorIsolation = __AbstractClosureExpr_getActorIsolation)
1778+
: ctx(dc->getASTContext()), getType(getType),
1779+
getClosureActorIsolation(getClosureActorIsolation) {
17621780
contextStack.push_back(dc);
17631781
}
17641782

@@ -2058,7 +2076,7 @@ namespace {
20582076
break;
20592077

20602078
if (auto closure = dyn_cast<AbstractClosureExpr>(dc)) {
2061-
auto isolation = closure->getActorIsolation();
2079+
auto isolation = getClosureActorIsolation(closure);
20622080
switch (isolation) {
20632081
case ClosureActorIsolation::Independent:
20642082
if (isSendableClosure(closure, /*forActorIsolation=*/true)) {
@@ -2113,7 +2131,8 @@ namespace {
21132131
// Check isolation of the context itself. We do this separately
21142132
// from the closure check because closures capture specific variables
21152133
// while general isolation is declaration-based.
2116-
switch (auto isolation = getActorIsolationOfContext(dc)) {
2134+
switch (auto isolation =
2135+
getActorIsolationOfContext(dc, getClosureActorIsolation)) {
21172136
case ActorIsolation::Independent:
21182137
case ActorIsolation::Unspecified:
21192138
// Local functions can capture an isolated parameter.
@@ -2487,7 +2506,7 @@ namespace {
24872506

24882507
/// Check actor isolation for a particular application.
24892508
bool checkApply(ApplyExpr *apply) {
2490-
auto fnExprType = apply->getFn()->getType();
2509+
auto fnExprType = getType(apply->getFn());
24912510
if (!fnExprType)
24922511
return false;
24932512

@@ -2502,7 +2521,8 @@ namespace {
25022521
return *contextIsolation;
25032522

25042523
auto declContext = const_cast<DeclContext *>(getDeclContext());
2505-
contextIsolation = getInnermostIsolatedContext(declContext);
2524+
contextIsolation =
2525+
getInnermostIsolatedContext(declContext, getClosureActorIsolation);
25062526
return *contextIsolation;
25072527
};
25082528

@@ -2539,9 +2559,9 @@ namespace {
25392559
// FIXME: The modeling of unsatisfiedIsolation is not great here.
25402560
// We'd be better off using something more like closure isolation
25412561
// that can talk about specific parameters.
2542-
auto nominal = arg->getType()->getAnyNominal();
2562+
auto nominal = getType(arg)->getAnyNominal();
25432563
if (!nominal) {
2544-
nominal = arg->getType()->getASTContext().getProtocol(
2564+
nominal = getType(arg)->getASTContext().getProtocol(
25452565
KnownProtocolKind::Actor);
25462566
}
25472567

@@ -2694,7 +2714,9 @@ namespace {
26942714
// Otherwise, we have concurrent access. Complain.
26952715
bool preconcurrencyContext =
26962716
getActorIsolationOfContext(
2697-
const_cast<DeclContext *>(getDeclContext())).preconcurrency();
2717+
const_cast<DeclContext *>(getDeclContext()),
2718+
__AbstractClosureExpr_getActorIsolation)
2719+
.preconcurrency();
26982720

26992721
ctx.Diags.diagnose(
27002722
loc, diag::concurrent_access_of_local_capture,
@@ -2785,7 +2807,7 @@ namespace {
27852807
// where k is a captured dictionary key.
27862808
if (auto *args = component.getSubscriptArgs()) {
27872809
for (auto arg : *args) {
2788-
auto type = arg.getExpr()->getType();
2810+
auto type = getType(arg.getExpr());
27892811
if (type &&
27902812
shouldDiagnoseExistingDataRaces(getDeclContext()) &&
27912813
diagnoseNonSendableTypes(
@@ -2818,8 +2840,8 @@ namespace {
28182840
if (base)
28192841
isolatedActor.emplace(getIsolatedActor(base));
28202842
auto result = ActorReferenceResult::forReference(
2821-
declRef, loc, getDeclContext(),
2822-
kindOfUsage(decl, context), isolatedActor);
2843+
declRef, loc, getDeclContext(), kindOfUsage(decl, context),
2844+
isolatedActor, None, None, getClosureActorIsolation);
28232845
switch (result) {
28242846
case ActorReferenceResult::SameConcurrencyDomain:
28252847
if (diagnoseReferenceToUnsafeGlobal(decl, loc))
@@ -2903,7 +2925,8 @@ namespace {
29032925
refKind = isolatedActor->kind;
29042926
refGlobalActor = isolatedActor->globalActor;
29052927
} else {
2906-
auto contextIsolation = getInnermostIsolatedContext(getDeclContext());
2928+
auto contextIsolation = getInnermostIsolatedContext(
2929+
getDeclContext(), getClosureActorIsolation);
29072930
switch (contextIsolation) {
29082931
case ActorIsolation::ActorInstance:
29092932
refKind = ReferencedActor::Isolated;
@@ -2952,7 +2975,7 @@ namespace {
29522975
// Attempt to resolve the global actor type of a closure.
29532976
Type resolveGlobalActorType(ClosureExpr *closure) {
29542977
// Check whether the closure's type has a global actor already.
2955-
if (Type closureType = closure->getType()) {
2978+
if (Type closureType = getType(closure)) {
29562979
if (auto closureFnType = closureType->getAs<FunctionType>()) {
29572980
if (Type globalActor = closureFnType->getGlobalActor())
29582981
return globalActor;
@@ -2994,7 +3017,8 @@ namespace {
29943017
return ClosureActorIsolation::forIndependent(preconcurrency);
29953018

29963019
// A non-Sendable closure gets its isolation from its context.
2997-
auto parentIsolation = getActorIsolationOfContext(closure->getParent());
3020+
auto parentIsolation = getActorIsolationOfContext(
3021+
closure->getParent(), getClosureActorIsolation);
29983022
preconcurrency |= parentIsolation.preconcurrency();
29993023

30003024
// We must have parent isolation determined to get here.
@@ -3032,10 +3056,10 @@ bool ActorIsolationChecker::mayExecuteConcurrentlyWith(
30323056
// If both contexts are isolated to the same actor, then they will not
30333057
// execute concurrently.
30343058
auto useIsolation = getActorIsolationOfContext(
3035-
const_cast<DeclContext *>(useContext));
3059+
const_cast<DeclContext *>(useContext), getClosureActorIsolation);
30363060
if (useIsolation.isActorIsolated()) {
30373061
auto defIsolation = getActorIsolationOfContext(
3038-
const_cast<DeclContext *>(defContext));
3062+
const_cast<DeclContext *>(defContext), getClosureActorIsolation);
30393063
if (useIsolation == defIsolation)
30403064
return false;
30413065
}
@@ -3109,9 +3133,12 @@ void swift::checkPropertyWrapperActorIsolation(
31093133
expr->walk(checker);
31103134
}
31113135

3112-
ClosureActorIsolation
3113-
swift::determineClosureActorIsolation(AbstractClosureExpr *closure) {
3114-
ActorIsolationChecker checker(closure->getParent());
3136+
ClosureActorIsolation swift::determineClosureActorIsolation(
3137+
AbstractClosureExpr *closure, llvm::function_ref<Type(Expr *)> getType,
3138+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
3139+
getClosureActorIsolation) {
3140+
ActorIsolationChecker checker(closure->getParent(), getType,
3141+
getClosureActorIsolation);
31153142
return checker.determineClosureIsolation(closure);
31163143
}
31173144

@@ -3801,14 +3828,15 @@ ActorIsolation ActorIsolationRequest::evaluate(
38013828
// If this is a defer body, inherit unconditionally; we don't
38023829
// care if the enclosing function captures the isolated parameter.
38033830
if (func->isDeferBody()) {
3804-
auto enclosingIsolation =
3805-
getActorIsolationOfContext(func->getDeclContext());
3831+
auto enclosingIsolation = getActorIsolationOfContext(
3832+
func->getDeclContext(), __AbstractClosureExpr_getActorIsolation);
38063833
return inferredIsolation(enclosingIsolation);
38073834
}
38083835

38093836
if (func->isLocalCapture() && !func->isSendable()) {
3810-
switch (auto enclosingIsolation =
3811-
getActorIsolationOfContext(func->getDeclContext())) {
3837+
switch (auto enclosingIsolation = getActorIsolationOfContext(
3838+
func->getDeclContext(),
3839+
__AbstractClosureExpr_getActorIsolation)) {
38123840
case ActorIsolation::Independent:
38133841
case ActorIsolation::Unspecified:
38143842
// Do nothing.
@@ -5092,10 +5120,11 @@ static bool equivalentIsolationContexts(
50925120

50935121
ActorReferenceResult ActorReferenceResult::forReference(
50945122
ConcreteDeclRef declRef, SourceLoc declRefLoc, const DeclContext *fromDC,
5095-
Optional<VarRefUseEnv> useKind,
5096-
Optional<ReferencedActor> actorInstance,
5123+
Optional<VarRefUseEnv> useKind, Optional<ReferencedActor> actorInstance,
50975124
Optional<ActorIsolation> knownDeclIsolation,
5098-
Optional<ActorIsolation> knownContextIsolation) {
5125+
Optional<ActorIsolation> knownContextIsolation,
5126+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
5127+
getClosureActorIsolation) {
50995128
// If not provided, compute the isolation of the declaration, adjusted
51005129
// for references.
51015130
ActorIsolation declIsolation = ActorIsolation::forUnspecified();
@@ -5117,7 +5146,8 @@ ActorReferenceResult ActorReferenceResult::forReference(
51175146
if (knownContextIsolation) {
51185147
contextIsolation = *knownContextIsolation;
51195148
} else {
5120-
contextIsolation = getInnermostIsolatedContext(fromDC);
5149+
contextIsolation =
5150+
getInnermostIsolatedContext(fromDC, getClosureActorIsolation);
51215151
}
51225152

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

0 commit comments

Comments
 (0)