Skip to content

Commit e0e5814

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 6ab50c8 commit e0e5814

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.
@@ -209,7 +222,15 @@ class ActorIsolation {
209222
ActorIsolation getActorIsolation(ValueDecl *value);
210223

211224
/// Determine how the given declaration context is isolated.
212-
ActorIsolation getActorIsolationOfContext(DeclContext *dc);
225+
/// \p getClosureActorIsolation allows the specification of actor isolation for
226+
/// closures that haven't been saved been saved to the AST yet. This is useful
227+
/// for solver-based code completion which doesn't modify the AST but stores the
228+
/// actor isolation of closures in the constraint system solution.
229+
ActorIsolation getActorIsolationOfContext(
230+
DeclContext *dc,
231+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
232+
getClosureActorIsolation =
233+
_getRef__AbstractClosureExpr_getActorIsolation());
213234

214235
/// Check if both the value, and context are isolated to the same actor.
215236
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;
@@ -262,6 +266,12 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
262266
this->CanCurrDeclContextHandleAsync = CanCurrDeclContextHandleAsync;
263267
}
264268

269+
void setClosureActorIsolations(
270+
llvm::DenseMap<AbstractClosureExpr *, ClosureActorIsolation>
271+
ClosureActorIsolations) {
272+
this->ClosureActorIsolations = ClosureActorIsolations;
273+
}
274+
265275
const ExpectedTypeContext *getExpectedTypeContext() const {
266276
return &expectedTypeContext;
267277
}

include/swift/Sema/IDETypeChecking.h

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

330+
/// Determine the isolation of a particular closure.
331+
ClosureActorIsolation determineClosureActorIsolation(
332+
AbstractClosureExpr *closure, llvm::function_ref<Type(Expr *)> getType,
333+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
334+
getClosureActorIsolation);
335+
330336
/// If the capture list shadows any declarations using shorthand syntax, i.e.
331337
/// syntax that names both the newly declared variable and the referenced
332338
/// 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
@@ -9211,7 +9211,10 @@ ActorIsolation swift::getActorIsolation(ValueDecl *value) {
92119211
ActorIsolation::forUnspecified());
92129212
}
92139213

9214-
ActorIsolation swift::getActorIsolationOfContext(DeclContext *dc) {
9214+
ActorIsolation swift::getActorIsolationOfContext(
9215+
DeclContext *dc,
9216+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
9217+
getClosureActorIsolation) {
92159218
if (auto *vd = dyn_cast_or_null<ValueDecl>(dc->getAsDecl()))
92169219
return getActorIsolation(vd);
92179220

@@ -9220,7 +9223,7 @@ ActorIsolation swift::getActorIsolationOfContext(DeclContext *dc) {
92209223

92219224

92229225
if (auto *closure = dyn_cast<AbstractClosureExpr>(dc)) {
9223-
return closure->getActorIsolation().getActorIsolation();
9226+
return getClosureActorIsolation(closure).getActorIsolation();
92249227
}
92259228

92269229
if (auto *tld = dyn_cast<TopLevelCodeDecl>(dc)) {
@@ -9239,7 +9242,7 @@ ActorIsolation swift::getActorIsolationOfContext(DeclContext *dc) {
92399242

92409243
bool swift::isSameActorIsolated(ValueDecl *value, DeclContext *dc) {
92419244
auto valueIsolation = getActorIsolation(value);
9242-
auto dcIsolation = getActorIsolationOfContext(dc);
9245+
auto dcIsolation = getActorIsolationOfContext(dc);
92439246
return valueIsolation.isActorIsolated() && dcIsolation.isActorIsolated() &&
92449247
valueIsolation.getActor() == dcIsolation.getActor();
92459248
}

lib/AST/Expr.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1903,6 +1903,16 @@ Expr *AbstractClosureExpr::getSingleExpressionBody() const {
19031903
return nullptr;
19041904
}
19051905

1906+
ClosureActorIsolation
1907+
swift::__AbstractClosureExpr_getActorIsolation(AbstractClosureExpr *CE) {
1908+
return CE->getActorIsolation();
1909+
}
1910+
1911+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
1912+
swift::_getRef__AbstractClosureExpr_getActorIsolation() {
1913+
return __AbstractClosureExpr_getActorIsolation;
1914+
}
1915+
19061916
#define FORWARD_SOURCE_LOCS_TO(CLASS, NODE) \
19071917
SourceRange CLASS::getSourceRange() const { \
19081918
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
@@ -921,7 +921,10 @@ void SILGenFunction::emitHopToActorValue(SILLocation loc, ManagedValue actor) {
921921
if (!F.isAsync()) {
922922
llvm::report_fatal_error("Builtin.hopToActor must be in an async function");
923923
}
924-
auto isolation = getActorIsolationOfContext(FunctionDC);
924+
auto isolation =
925+
getActorIsolationOfContext(FunctionDC, [](AbstractClosureExpr *CE) {
926+
return CE->getActorIsolation();
927+
});
925928
if (isolation != ActorIsolation::Independent
926929
&& isolation != ActorIsolation::Unspecified) {
927930
// 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
@@ -1477,10 +1477,14 @@ static bool checkedByFlowIsolation(DeclContext const *refCxt,
14771477
}
14781478

14791479
/// Get the actor isolation of the innermost relevant context.
1480-
static ActorIsolation getInnermostIsolatedContext(const DeclContext *dc) {
1480+
static ActorIsolation getInnermostIsolatedContext(
1481+
const DeclContext *dc,
1482+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
1483+
getClosureActorIsolation) {
14811484
// Retrieve the actor isolation of the context.
14821485
auto mutableDC = const_cast<DeclContext *>(dc);
1483-
switch (auto isolation = getActorIsolationOfContext(mutableDC)) {
1486+
switch (auto isolation =
1487+
getActorIsolationOfContext(mutableDC, getClosureActorIsolation)) {
14841488
case ActorIsolation::ActorInstance:
14851489
case ActorIsolation::Independent:
14861490
case ActorIsolation::Unspecified:
@@ -1563,6 +1567,9 @@ namespace {
15631567
SmallVector<ApplyExpr*, 4> applyStack;
15641568
SmallVector<std::pair<OpaqueValueExpr *, Expr *>, 4> opaqueValues;
15651569
SmallVector<const PatternBindingDecl *, 2> patternBindingStack;
1570+
llvm::function_ref<Type(Expr *)> getType;
1571+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
1572+
getClosureActorIsolation;
15661573

15671574
/// Keeps track of the capture context of variables that have been
15681575
/// explicitly captured in closures.
@@ -1761,7 +1768,13 @@ namespace {
17611768
}
17621769

17631770
public:
1764-
ActorIsolationChecker(const DeclContext *dc) : ctx(dc->getASTContext()) {
1771+
ActorIsolationChecker(
1772+
const DeclContext *dc,
1773+
llvm::function_ref<Type(Expr *)> getType = __Expr_getType,
1774+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
1775+
getClosureActorIsolation = __AbstractClosureExpr_getActorIsolation)
1776+
: ctx(dc->getASTContext()), getType(getType),
1777+
getClosureActorIsolation(getClosureActorIsolation) {
17651778
contextStack.push_back(dc);
17661779
}
17671780

@@ -2061,7 +2074,7 @@ namespace {
20612074
break;
20622075

20632076
if (auto closure = dyn_cast<AbstractClosureExpr>(dc)) {
2064-
auto isolation = closure->getActorIsolation();
2077+
auto isolation = getClosureActorIsolation(closure);
20652078
switch (isolation) {
20662079
case ClosureActorIsolation::Independent:
20672080
if (isSendableClosure(closure, /*forActorIsolation=*/true)) {
@@ -2116,7 +2129,8 @@ namespace {
21162129
// Check isolation of the context itself. We do this separately
21172130
// from the closure check because closures capture specific variables
21182131
// while general isolation is declaration-based.
2119-
switch (auto isolation = getActorIsolationOfContext(dc)) {
2132+
switch (auto isolation =
2133+
getActorIsolationOfContext(dc, getClosureActorIsolation)) {
21202134
case ActorIsolation::Independent:
21212135
case ActorIsolation::Unspecified:
21222136
// Local functions can capture an isolated parameter.
@@ -2490,7 +2504,7 @@ namespace {
24902504

24912505
/// Check actor isolation for a particular application.
24922506
bool checkApply(ApplyExpr *apply) {
2493-
auto fnExprType = apply->getFn()->getType();
2507+
auto fnExprType = getType(apply->getFn());
24942508
if (!fnExprType)
24952509
return false;
24962510

@@ -2505,7 +2519,8 @@ namespace {
25052519
return *contextIsolation;
25062520

25072521
auto declContext = const_cast<DeclContext *>(getDeclContext());
2508-
contextIsolation = getInnermostIsolatedContext(declContext);
2522+
contextIsolation =
2523+
getInnermostIsolatedContext(declContext, getClosureActorIsolation);
25092524
return *contextIsolation;
25102525
};
25112526

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

@@ -2771,7 +2786,7 @@ namespace {
27712786
// where k is a captured dictionary key.
27722787
if (auto *args = component.getSubscriptArgs()) {
27732788
for (auto arg : *args) {
2774-
auto type = arg.getExpr()->getType();
2789+
auto type = getType(arg.getExpr());
27752790
if (type &&
27762791
shouldDiagnoseExistingDataRaces(getDeclContext()) &&
27772792
diagnoseNonSendableTypes(
@@ -2804,8 +2819,8 @@ namespace {
28042819
if (base)
28052820
isolatedActor.emplace(getIsolatedActor(base));
28062821
auto result = ActorReferenceResult::forReference(
2807-
declRef, loc, getDeclContext(),
2808-
kindOfUsage(decl, context), isolatedActor);
2822+
declRef, loc, getDeclContext(), kindOfUsage(decl, context),
2823+
isolatedActor, None, None, getClosureActorIsolation);
28092824
switch (result) {
28102825
case ActorReferenceResult::SameConcurrencyDomain:
28112826
if (diagnoseReferenceToUnsafeGlobal(decl, loc))
@@ -2889,7 +2904,8 @@ namespace {
28892904
refKind = isolatedActor->kind;
28902905
refGlobalActor = isolatedActor->globalActor;
28912906
} else {
2892-
auto contextIsolation = getInnermostIsolatedContext(getDeclContext());
2907+
auto contextIsolation = getInnermostIsolatedContext(
2908+
getDeclContext(), getClosureActorIsolation);
28932909
switch (contextIsolation) {
28942910
case ActorIsolation::ActorInstance:
28952911
refKind = ReferencedActor::Isolated;
@@ -2938,7 +2954,7 @@ namespace {
29382954
// Attempt to resolve the global actor type of a closure.
29392955
Type resolveGlobalActorType(ClosureExpr *closure) {
29402956
// Check whether the closure's type has a global actor already.
2941-
if (Type closureType = closure->getType()) {
2957+
if (Type closureType = getType(closure)) {
29422958
if (auto closureFnType = closureType->getAs<FunctionType>()) {
29432959
if (Type globalActor = closureFnType->getGlobalActor())
29442960
return globalActor;
@@ -2980,7 +2996,8 @@ namespace {
29802996
return ClosureActorIsolation::forIndependent(preconcurrency);
29812997

29822998
// A non-Sendable closure gets its isolation from its context.
2983-
auto parentIsolation = getActorIsolationOfContext(closure->getParent());
2999+
auto parentIsolation = getActorIsolationOfContext(
3000+
closure->getParent(), getClosureActorIsolation);
29843001
preconcurrency |= parentIsolation.preconcurrency();
29853002

29863003
// We must have parent isolation determined to get here.
@@ -3018,10 +3035,10 @@ bool ActorIsolationChecker::mayExecuteConcurrentlyWith(
30183035
// If both contexts are isolated to the same actor, then they will not
30193036
// execute concurrently.
30203037
auto useIsolation = getActorIsolationOfContext(
3021-
const_cast<DeclContext *>(useContext));
3038+
const_cast<DeclContext *>(useContext), getClosureActorIsolation);
30223039
if (useIsolation.isActorIsolated()) {
30233040
auto defIsolation = getActorIsolationOfContext(
3024-
const_cast<DeclContext *>(defContext));
3041+
const_cast<DeclContext *>(defContext), getClosureActorIsolation);
30253042
if (useIsolation == defIsolation)
30263043
return false;
30273044
}
@@ -3095,9 +3112,12 @@ void swift::checkPropertyWrapperActorIsolation(
30953112
expr->walk(checker);
30963113
}
30973114

3098-
ClosureActorIsolation
3099-
swift::determineClosureActorIsolation(AbstractClosureExpr *closure) {
3100-
ActorIsolationChecker checker(closure->getParent());
3115+
ClosureActorIsolation swift::determineClosureActorIsolation(
3116+
AbstractClosureExpr *closure, llvm::function_ref<Type(Expr *)> getType,
3117+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
3118+
getClosureActorIsolation) {
3119+
ActorIsolationChecker checker(closure->getParent(), getType,
3120+
getClosureActorIsolation);
31013121
return checker.determineClosureIsolation(closure);
31023122
}
31033123

@@ -3835,14 +3855,14 @@ ActorIsolation ActorIsolationRequest::evaluate(
38353855
// If this is a defer body, inherit unconditionally; we don't
38363856
// care if the enclosing function captures the isolated parameter.
38373857
if (func->isDeferBody()) {
3838-
auto enclosingIsolation =
3839-
getActorIsolationOfContext(func->getDeclContext());
3858+
auto enclosingIsolation = getActorIsolationOfContext(
3859+
func->getDeclContext());
38403860
return inferredIsolation(enclosingIsolation);
38413861
}
38423862

38433863
if (func->isLocalCapture() && !func->isSendable()) {
3844-
switch (auto enclosingIsolation =
3845-
getActorIsolationOfContext(func->getDeclContext())) {
3864+
switch (auto enclosingIsolation = getActorIsolationOfContext(
3865+
func->getDeclContext())) {
38463866
case ActorIsolation::Independent:
38473867
case ActorIsolation::Unspecified:
38483868
// Do nothing.
@@ -5127,10 +5147,11 @@ static bool equivalentIsolationContexts(
51275147

51285148
ActorReferenceResult ActorReferenceResult::forReference(
51295149
ConcreteDeclRef declRef, SourceLoc declRefLoc, const DeclContext *fromDC,
5130-
Optional<VarRefUseEnv> useKind,
5131-
Optional<ReferencedActor> actorInstance,
5150+
Optional<VarRefUseEnv> useKind, Optional<ReferencedActor> actorInstance,
51325151
Optional<ActorIsolation> knownDeclIsolation,
5133-
Optional<ActorIsolation> knownContextIsolation) {
5152+
Optional<ActorIsolation> knownContextIsolation,
5153+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
5154+
getClosureActorIsolation) {
51345155
// If not provided, compute the isolation of the declaration, adjusted
51355156
// for references.
51365157
ActorIsolation declIsolation = ActorIsolation::forUnspecified();
@@ -5152,7 +5173,8 @@ ActorReferenceResult ActorReferenceResult::forReference(
51525173
if (knownContextIsolation) {
51535174
contextIsolation = *knownContextIsolation;
51545175
} else {
5155-
contextIsolation = getInnermostIsolatedContext(fromDC);
5176+
contextIsolation =
5177+
getInnermostIsolatedContext(fromDC, getClosureActorIsolation);
51565178
}
51575179

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

0 commit comments

Comments
 (0)