Skip to content

Commit 7ab2cfd

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 92bcd71 commit 7ab2cfd

File tree

9 files changed

+117
-50
lines changed

9 files changed

+117
-50
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
@@ -9209,7 +9209,10 @@ ActorIsolation swift::getActorIsolation(ValueDecl *value) {
92099209
ActorIsolation::forUnspecified());
92109210
}
92119211

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

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

92199222

92209223
if (auto *closure = dyn_cast<AbstractClosureExpr>(dc)) {
9221-
return closure->getActorIsolation().getActorIsolation();
9224+
return getClosureActorIsolation(closure).getActorIsolation();
92229225
}
92239226

92249227
if (auto *tld = dyn_cast<TopLevelCodeDecl>(dc)) {
@@ -9237,7 +9240,8 @@ ActorIsolation swift::getActorIsolationOfContext(DeclContext *dc) {
92379240

92389241
bool swift::isSameActorIsolated(ValueDecl *value, DeclContext *dc) {
92399242
auto valueIsolation = getActorIsolation(value);
9240-
auto dcIsolation = getActorIsolationOfContext(dc);
9243+
auto dcIsolation = getActorIsolationOfContext(
9244+
dc, [](AbstractClosureExpr *ACE) { return ACE->getActorIsolation(); });
92419245
return valueIsolation.isActorIsolated() && dcIsolation.isActorIsolated() &&
92429246
valueIsolation.getActor() == dcIsolation.getActor();
92439247
}

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
@@ -851,7 +851,10 @@ void SILGenFunction::emitHopToActorValue(SILLocation loc, ManagedValue actor) {
851851
if (!F.isAsync()) {
852852
llvm::report_fatal_error("Builtin.hopToActor must be in an async function");
853853
}
854-
auto isolation = getActorIsolationOfContext(FunctionDC);
854+
auto isolation =
855+
getActorIsolationOfContext(FunctionDC, [](AbstractClosureExpr *CE) {
856+
return CE->getActorIsolation();
857+
});
855858
if (isolation != ActorIsolation::Independent
856859
&& isolation != ActorIsolation::Unspecified) {
857860
// TODO: Explicit hop with no hop-back should only be allowed in independent

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 56 additions & 28 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) {
@@ -1462,10 +1467,14 @@ static bool checkedByFlowIsolation(DeclContext const *refCxt,
14621467
}
14631468

14641469
/// Get the actor isolation of the innermost relevant context.
1465-
static ActorIsolation getInnermostIsolatedContext(const DeclContext *dc) {
1470+
static ActorIsolation getInnermostIsolatedContext(
1471+
const DeclContext *dc,
1472+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
1473+
getClosureActorIsolation) {
14661474
// Retrieve the actor isolation of the context.
14671475
auto mutableDC = const_cast<DeclContext *>(dc);
1468-
switch (auto isolation = getActorIsolationOfContext(mutableDC)) {
1476+
switch (auto isolation =
1477+
getActorIsolationOfContext(mutableDC, getClosureActorIsolation)) {
14691478
case ActorIsolation::ActorInstance:
14701479
case ActorIsolation::Independent:
14711480
case ActorIsolation::Unspecified:
@@ -1548,6 +1557,9 @@ namespace {
15481557
SmallVector<ApplyExpr*, 4> applyStack;
15491558
SmallVector<std::pair<OpaqueValueExpr *, Expr *>, 4> opaqueValues;
15501559
SmallVector<const PatternBindingDecl *, 2> patternBindingStack;
1560+
llvm::function_ref<Type(Expr *)> getType;
1561+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
1562+
getClosureActorIsolation;
15511563

15521564
/// Keeps track of the capture context of variables that have been
15531565
/// explicitly captured in closures.
@@ -1746,7 +1758,13 @@ namespace {
17461758
}
17471759

17481760
public:
1749-
ActorIsolationChecker(const DeclContext *dc) : ctx(dc->getASTContext()) {
1761+
ActorIsolationChecker(
1762+
const DeclContext *dc,
1763+
llvm::function_ref<Type(Expr *)> getType = __Expr_getType,
1764+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
1765+
getClosureActorIsolation = __AbstractClosureExpr_getActorIsolation)
1766+
: ctx(dc->getASTContext()), getType(getType),
1767+
getClosureActorIsolation(getClosureActorIsolation) {
17501768
contextStack.push_back(dc);
17511769
}
17521770

@@ -2046,7 +2064,7 @@ namespace {
20462064
break;
20472065

20482066
if (auto closure = dyn_cast<AbstractClosureExpr>(dc)) {
2049-
auto isolation = closure->getActorIsolation();
2067+
auto isolation = getClosureActorIsolation(closure);
20502068
switch (isolation) {
20512069
case ClosureActorIsolation::Independent:
20522070
if (isSendableClosure(closure, /*forActorIsolation=*/true)) {
@@ -2101,7 +2119,8 @@ namespace {
21012119
// Check isolation of the context itself. We do this separately
21022120
// from the closure check because closures capture specific variables
21032121
// while general isolation is declaration-based.
2104-
switch (auto isolation = getActorIsolationOfContext(dc)) {
2122+
switch (auto isolation =
2123+
getActorIsolationOfContext(dc, getClosureActorIsolation)) {
21052124
case ActorIsolation::Independent:
21062125
case ActorIsolation::Unspecified:
21072126
// Local functions can capture an isolated parameter.
@@ -2475,7 +2494,7 @@ namespace {
24752494

24762495
/// Check actor isolation for a particular application.
24772496
bool checkApply(ApplyExpr *apply) {
2478-
auto fnExprType = apply->getFn()->getType();
2497+
auto fnExprType = getType(apply->getFn());
24792498
if (!fnExprType)
24802499
return false;
24812500

@@ -2490,7 +2509,8 @@ namespace {
24902509
return *contextIsolation;
24912510

24922511
auto declContext = const_cast<DeclContext *>(getDeclContext());
2493-
contextIsolation = getInnermostIsolatedContext(declContext);
2512+
contextIsolation =
2513+
getInnermostIsolatedContext(declContext, getClosureActorIsolation);
24942514
return *contextIsolation;
24952515
};
24962516

@@ -2527,9 +2547,9 @@ namespace {
25272547
// FIXME: The modeling of unsatisfiedIsolation is not great here.
25282548
// We'd be better off using something more like closure isolation
25292549
// that can talk about specific parameters.
2530-
auto nominal = arg->getType()->getAnyNominal();
2550+
auto nominal = getType(arg)->getAnyNominal();
25312551
if (!nominal) {
2532-
nominal = arg->getType()->getASTContext().getProtocol(
2552+
nominal = getType(arg)->getASTContext().getProtocol(
25332553
KnownProtocolKind::Actor);
25342554
}
25352555

@@ -2768,7 +2788,7 @@ namespace {
27682788
// where k is a captured dictionary key.
27692789
if (auto *args = component.getSubscriptArgs()) {
27702790
for (auto arg : *args) {
2771-
auto type = arg.getExpr()->getType();
2791+
auto type = getType(arg.getExpr());
27722792
if (type &&
27732793
shouldDiagnoseExistingDataRaces(getDeclContext()) &&
27742794
diagnoseNonSendableTypes(
@@ -2801,8 +2821,8 @@ namespace {
28012821
if (base)
28022822
isolatedActor.emplace(getIsolatedActor(base));
28032823
auto result = ActorReferenceResult::forReference(
2804-
declRef, loc, getDeclContext(),
2805-
kindOfUsage(decl, context), isolatedActor);
2824+
declRef, loc, getDeclContext(), kindOfUsage(decl, context),
2825+
isolatedActor, None, None, getClosureActorIsolation);
28062826
switch (result) {
28072827
case ActorReferenceResult::SameConcurrencyDomain:
28082828
if (diagnoseReferenceToUnsafeGlobal(decl, loc))
@@ -2886,7 +2906,8 @@ namespace {
28862906
refKind = isolatedActor->kind;
28872907
refGlobalActor = isolatedActor->globalActor;
28882908
} else {
2889-
auto contextIsolation = getInnermostIsolatedContext(getDeclContext());
2909+
auto contextIsolation = getInnermostIsolatedContext(
2910+
getDeclContext(), getClosureActorIsolation);
28902911
switch (contextIsolation) {
28912912
case ActorIsolation::ActorInstance:
28922913
refKind = ReferencedActor::Isolated;
@@ -2930,7 +2951,7 @@ namespace {
29302951
// Attempt to resolve the global actor type of a closure.
29312952
Type resolveGlobalActorType(ClosureExpr *closure) {
29322953
// Check whether the closure's type has a global actor already.
2933-
if (Type closureType = closure->getType()) {
2954+
if (Type closureType = getType(closure)) {
29342955
if (auto closureFnType = closureType->getAs<FunctionType>()) {
29352956
if (Type globalActor = closureFnType->getGlobalActor())
29362957
return globalActor;
@@ -2972,7 +2993,8 @@ namespace {
29722993
return ClosureActorIsolation::forIndependent(preconcurrency);
29732994

29742995
// A non-Sendable closure gets its isolation from its context.
2975-
auto parentIsolation = getActorIsolationOfContext(closure->getParent());
2996+
auto parentIsolation = getActorIsolationOfContext(
2997+
closure->getParent(), getClosureActorIsolation);
29762998
preconcurrency |= parentIsolation.preconcurrency();
29772999

29783000
// We must have parent isolation determined to get here.
@@ -3010,10 +3032,10 @@ bool ActorIsolationChecker::mayExecuteConcurrentlyWith(
30103032
// If both contexts are isolated to the same actor, then they will not
30113033
// execute concurrently.
30123034
auto useIsolation = getActorIsolationOfContext(
3013-
const_cast<DeclContext *>(useContext));
3035+
const_cast<DeclContext *>(useContext), getClosureActorIsolation);
30143036
if (useIsolation.isActorIsolated()) {
30153037
auto defIsolation = getActorIsolationOfContext(
3016-
const_cast<DeclContext *>(defContext));
3038+
const_cast<DeclContext *>(defContext), getClosureActorIsolation);
30173039
if (useIsolation == defIsolation)
30183040
return false;
30193041
}
@@ -3087,9 +3109,12 @@ void swift::checkPropertyWrapperActorIsolation(
30873109
expr->walk(checker);
30883110
}
30893111

3090-
ClosureActorIsolation
3091-
swift::determineClosureActorIsolation(AbstractClosureExpr *closure) {
3092-
ActorIsolationChecker checker(closure->getParent());
3112+
ClosureActorIsolation swift::determineClosureActorIsolation(
3113+
AbstractClosureExpr *closure, llvm::function_ref<Type(Expr *)> getType,
3114+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
3115+
getClosureActorIsolation) {
3116+
ActorIsolationChecker checker(closure->getParent(), getType,
3117+
getClosureActorIsolation);
30933118
return checker.determineClosureIsolation(closure);
30943119
}
30953120

@@ -3779,14 +3804,15 @@ ActorIsolation ActorIsolationRequest::evaluate(
37793804
// If this is a defer body, inherit unconditionally; we don't
37803805
// care if the enclosing function captures the isolated parameter.
37813806
if (func->isDeferBody()) {
3782-
auto enclosingIsolation =
3783-
getActorIsolationOfContext(func->getDeclContext());
3807+
auto enclosingIsolation = getActorIsolationOfContext(
3808+
func->getDeclContext(), __AbstractClosureExpr_getActorIsolation);
37843809
return inferredIsolation(enclosingIsolation);
37853810
}
37863811

37873812
if (func->isLocalCapture() && !func->isSendable()) {
3788-
switch (auto enclosingIsolation =
3789-
getActorIsolationOfContext(func->getDeclContext())) {
3813+
switch (auto enclosingIsolation = getActorIsolationOfContext(
3814+
func->getDeclContext(),
3815+
__AbstractClosureExpr_getActorIsolation)) {
37903816
case ActorIsolation::Independent:
37913817
case ActorIsolation::Unspecified:
37923818
// Do nothing.
@@ -5045,10 +5071,11 @@ static bool equivalentIsolationContexts(
50455071

50465072
ActorReferenceResult ActorReferenceResult::forReference(
50475073
ConcreteDeclRef declRef, SourceLoc declRefLoc, const DeclContext *fromDC,
5048-
Optional<VarRefUseEnv> useKind,
5049-
Optional<ReferencedActor> actorInstance,
5074+
Optional<VarRefUseEnv> useKind, Optional<ReferencedActor> actorInstance,
50505075
Optional<ActorIsolation> knownDeclIsolation,
5051-
Optional<ActorIsolation> knownContextIsolation) {
5076+
Optional<ActorIsolation> knownContextIsolation,
5077+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
5078+
getClosureActorIsolation) {
50525079
// If not provided, compute the isolation of the declaration, adjusted
50535080
// for references.
50545081
ActorIsolation declIsolation = ActorIsolation::forUnspecified();
@@ -5070,7 +5097,8 @@ ActorReferenceResult ActorReferenceResult::forReference(
50705097
if (knownContextIsolation) {
50715098
contextIsolation = *knownContextIsolation;
50725099
} else {
5073-
contextIsolation = getInnermostIsolatedContext(fromDC);
5100+
contextIsolation =
5101+
getInnermostIsolatedContext(fromDC, getClosureActorIsolation);
50745102
}
50755103

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

0 commit comments

Comments
 (0)