Skip to content

Commit 442cf9b

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 ec73a3a commit 442cf9b

File tree

10 files changed

+122
-45
lines changed

10 files changed

+122
-45
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: 5 additions & 2 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
auto dcToUse = dc;
92169219
// Defer bodies share actor isolation of their enclosing context.
92179220
if (auto FD = dyn_cast<FuncDecl>(dcToUse)) {
@@ -9226,7 +9229,7 @@ ActorIsolation swift::getActorIsolationOfContext(DeclContext *dc) {
92269229
return getActorIsolation(var);
92279230

92289231
if (auto *closure = dyn_cast<AbstractClosureExpr>(dcToUse)) {
9229-
return closure->getActorIsolation().getActorIsolation();
9232+
return getClosureActorIsolation(closure).getActorIsolation();
92309233
}
92319234

92329235
if (auto *tld = dyn_cast<TopLevelCodeDecl>(dcToUse)) {

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: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -755,8 +755,18 @@ 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), getClosureActorIsolation);
760770
if (contextIsolation != isolation) {
761771
implicitlyAsync = true;
762772
}

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: 46 additions & 24 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:
@@ -1564,6 +1568,9 @@ namespace {
15641568
SmallVector<ApplyExpr*, 4> applyStack;
15651569
SmallVector<std::pair<OpaqueValueExpr *, Expr *>, 4> opaqueValues;
15661570
SmallVector<const PatternBindingDecl *, 2> patternBindingStack;
1571+
llvm::function_ref<Type(Expr *)> getType;
1572+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
1573+
getClosureActorIsolation;
15671574

15681575
/// Keeps track of the capture context of variables that have been
15691576
/// explicitly captured in closures.
@@ -1762,7 +1769,13 @@ namespace {
17621769
}
17631770

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

@@ -2062,7 +2075,7 @@ namespace {
20622075
break;
20632076

20642077
if (auto closure = dyn_cast<AbstractClosureExpr>(dc)) {
2065-
auto isolation = closure->getActorIsolation();
2078+
auto isolation = getClosureActorIsolation(closure);
20662079
switch (isolation) {
20672080
case ClosureActorIsolation::Independent:
20682081
if (isSendableClosure(closure, /*forActorIsolation=*/true)) {
@@ -2117,7 +2130,8 @@ namespace {
21172130
// Check isolation of the context itself. We do this separately
21182131
// from the closure check because closures capture specific variables
21192132
// while general isolation is declaration-based.
2120-
switch (auto isolation = getActorIsolationOfContext(dc)) {
2133+
switch (auto isolation =
2134+
getActorIsolationOfContext(dc, getClosureActorIsolation)) {
21212135
case ActorIsolation::Independent:
21222136
case ActorIsolation::Unspecified:
21232137
// Local functions can capture an isolated parameter.
@@ -2491,7 +2505,7 @@ namespace {
24912505

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

@@ -2506,7 +2520,8 @@ namespace {
25062520
return *contextIsolation;
25072521

25082522
auto declContext = const_cast<DeclContext *>(getDeclContext());
2509-
contextIsolation = getInnermostIsolatedContext(declContext);
2523+
contextIsolation =
2524+
getInnermostIsolatedContext(declContext, getClosureActorIsolation);
25102525
return *contextIsolation;
25112526
};
25122527

@@ -2542,9 +2557,9 @@ namespace {
25422557
// FIXME: The modeling of unsatisfiedIsolation is not great here.
25432558
// We'd be better off using something more like closure isolation
25442559
// that can talk about specific parameters.
2545-
auto nominal = arg->getType()->getAnyNominal();
2560+
auto nominal = getType(arg)->getAnyNominal();
25462561
if (!nominal) {
2547-
nominal = arg->getType()->getASTContext().getProtocol(
2562+
nominal = getType(arg)->getASTContext().getProtocol(
25482563
KnownProtocolKind::Actor);
25492564
}
25502565

@@ -2772,7 +2787,7 @@ namespace {
27722787
// where k is a captured dictionary key.
27732788
if (auto *args = component.getSubscriptArgs()) {
27742789
for (auto arg : *args) {
2775-
auto type = arg.getExpr()->getType();
2790+
auto type = getType(arg.getExpr());
27762791
if (type &&
27772792
shouldDiagnoseExistingDataRaces(getDeclContext()) &&
27782793
diagnoseNonSendableTypes(
@@ -2805,8 +2820,8 @@ namespace {
28052820
if (base)
28062821
isolatedActor.emplace(getIsolatedActor(base));
28072822
auto result = ActorReferenceResult::forReference(
2808-
declRef, loc, getDeclContext(),
2809-
kindOfUsage(decl, context), isolatedActor);
2823+
declRef, loc, getDeclContext(), kindOfUsage(decl, context),
2824+
isolatedActor, None, None, getClosureActorIsolation);
28102825
switch (result) {
28112826
case ActorReferenceResult::SameConcurrencyDomain:
28122827
if (diagnoseReferenceToUnsafeGlobal(decl, loc))
@@ -2890,7 +2905,8 @@ namespace {
28902905
refKind = isolatedActor->kind;
28912906
refGlobalActor = isolatedActor->globalActor;
28922907
} else {
2893-
auto contextIsolation = getInnermostIsolatedContext(getDeclContext());
2908+
auto contextIsolation = getInnermostIsolatedContext(
2909+
getDeclContext(), getClosureActorIsolation);
28942910
switch (contextIsolation) {
28952911
case ActorIsolation::ActorInstance:
28962912
refKind = ReferencedActor::Isolated;
@@ -2939,7 +2955,7 @@ namespace {
29392955
// Attempt to resolve the global actor type of a closure.
29402956
Type resolveGlobalActorType(ClosureExpr *closure) {
29412957
// Check whether the closure's type has a global actor already.
2942-
if (Type closureType = closure->getType()) {
2958+
if (Type closureType = getType(closure)) {
29432959
if (auto closureFnType = closureType->getAs<FunctionType>()) {
29442960
if (Type globalActor = closureFnType->getGlobalActor())
29452961
return globalActor;
@@ -2981,7 +2997,8 @@ namespace {
29812997
return ClosureActorIsolation::forIndependent(preconcurrency);
29822998

29832999
// A non-Sendable closure gets its isolation from its context.
2984-
auto parentIsolation = getActorIsolationOfContext(closure->getParent());
3000+
auto parentIsolation = getActorIsolationOfContext(
3001+
closure->getParent(), getClosureActorIsolation);
29853002
preconcurrency |= parentIsolation.preconcurrency();
29863003

29873004
// We must have parent isolation determined to get here.
@@ -3019,10 +3036,10 @@ bool ActorIsolationChecker::mayExecuteConcurrentlyWith(
30193036
// If both contexts are isolated to the same actor, then they will not
30203037
// execute concurrently.
30213038
auto useIsolation = getActorIsolationOfContext(
3022-
const_cast<DeclContext *>(useContext));
3039+
const_cast<DeclContext *>(useContext), getClosureActorIsolation);
30233040
if (useIsolation.isActorIsolated()) {
30243041
auto defIsolation = getActorIsolationOfContext(
3025-
const_cast<DeclContext *>(defContext));
3042+
const_cast<DeclContext *>(defContext), getClosureActorIsolation);
30263043
if (useIsolation == defIsolation)
30273044
return false;
30283045
}
@@ -3096,9 +3113,12 @@ void swift::checkPropertyWrapperActorIsolation(
30963113
expr->walk(checker);
30973114
}
30983115

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

@@ -5120,10 +5140,11 @@ static bool equivalentIsolationContexts(
51205140

51215141
ActorReferenceResult ActorReferenceResult::forReference(
51225142
ConcreteDeclRef declRef, SourceLoc declRefLoc, const DeclContext *fromDC,
5123-
Optional<VarRefUseEnv> useKind,
5124-
Optional<ReferencedActor> actorInstance,
5143+
Optional<VarRefUseEnv> useKind, Optional<ReferencedActor> actorInstance,
51255144
Optional<ActorIsolation> knownDeclIsolation,
5126-
Optional<ActorIsolation> knownContextIsolation) {
5145+
Optional<ActorIsolation> knownContextIsolation,
5146+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
5147+
getClosureActorIsolation) {
51275148
// If not provided, compute the isolation of the declaration, adjusted
51285149
// for references.
51295150
ActorIsolation declIsolation = ActorIsolation::forUnspecified();
@@ -5145,7 +5166,8 @@ ActorReferenceResult ActorReferenceResult::forReference(
51455166
if (knownContextIsolation) {
51465167
contextIsolation = *knownContextIsolation;
51475168
} else {
5148-
contextIsolation = getInnermostIsolatedContext(fromDC);
5169+
contextIsolation =
5170+
getInnermostIsolatedContext(fromDC, getClosureActorIsolation);
51495171
}
51505172

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

lib/Sema/TypeCheckConcurrency.h

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "swift/AST/ASTContext.h"
2121
#include "swift/AST/ConcreteDeclRef.h"
2222
#include "swift/AST/DiagnosticEngine.h"
23+
#include "swift/AST/Expr.h"
2324
#include "swift/AST/Module.h"
2425
#include "swift/AST/Type.h"
2526
#include <cassert>
@@ -60,16 +61,6 @@ void checkInitializerActorIsolation(Initializer *init, Expr *expr);
6061
void checkEnumElementActorIsolation(EnumElementDecl *element, Expr *expr);
6162
void checkPropertyWrapperActorIsolation(VarDecl *wrappedVar, Expr *expr);
6263

63-
/// Determine the isolation of a particular closure.
64-
///
65-
/// This forwards to \c ActorIsolationChecker::determineClosureActorIsolation
66-
/// and thus assumes that enclosing closures have already had their isolation
67-
/// checked.
68-
///
69-
/// This does not set the closure's actor isolation
70-
ClosureActorIsolation
71-
determineClosureActorIsolation(AbstractClosureExpr *closure);
72-
7364
/// States the reason for checking the Sendability of a given declaration.
7465
enum class SendableCheckReason {
7566
/// A reference to an actor from outside that actor.
@@ -244,13 +235,13 @@ struct ActorReferenceResult {
244235
/// provided when referencing the declaration. This can be either the base
245236
/// of a member access or a parameter passed to a function.
246237
static ActorReferenceResult forReference(
247-
ConcreteDeclRef declRef,
248-
SourceLoc declRefLoc,
249-
const DeclContext *fromDC,
238+
ConcreteDeclRef declRef, SourceLoc declRefLoc, const DeclContext *fromDC,
250239
Optional<VarRefUseEnv> useKind = None,
251240
Optional<ReferencedActor> actorInstance = None,
252241
Optional<ActorIsolation> knownDeclIsolation = None,
253-
Optional<ActorIsolation> knownContextIsolation = None);
242+
Optional<ActorIsolation> knownContextIsolation = None,
243+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
244+
getClosureActorIsolation = __AbstractClosureExpr_getActorIsolation);
254245

255246
operator Kind() const { return kind; }
256247
};

lib/Sema/TypeCheckStmt.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1988,7 +1988,8 @@ bool TypeCheckASTNodeAtLocRequest::evaluate(
19881988
// isolation checked before nested ones are being checked by the way
19891989
// TypeCheckASTNodeAtLocRequest is called multiple times, as described
19901990
// above.
1991-
auto ActorIsolation = determineClosureActorIsolation(CE);
1991+
auto ActorIsolation = determineClosureActorIsolation(
1992+
CE, __Expr_getType, __AbstractClosureExpr_getActorIsolation);
19921993
CE->setActorIsolation(ActorIsolation);
19931994
if (CE->getBodyState() != ClosureExpr::BodyState::ReadyForTypeChecking)
19941995
return false;

0 commit comments

Comments
 (0)