Skip to content

Commit 670293c

Browse files
committed
[CodeCompletion] Determine actor isolation of closures from Solution instead of AST
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 39c9ff1 commit 670293c

File tree

9 files changed

+115
-49
lines changed

9 files changed

+115
-49
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
/// Determines whether this function's body uses flow-sensitive isolation.
197206
bool usesFlowSensitiveIsolation(AbstractFunctionDecl const *fn);

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: 5 additions & 2 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)) {

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) {
@@ -1450,10 +1455,14 @@ static bool checkedByFlowIsolation(DeclContext const *refCxt,
14501455
}
14511456

14521457
/// Get the actor isolation of the innermost relevant context.
1453-
static ActorIsolation getInnermostIsolatedContext(const DeclContext *dc) {
1458+
static ActorIsolation getInnermostIsolatedContext(
1459+
const DeclContext *dc,
1460+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
1461+
getClosureActorIsolation) {
14541462
// Retrieve the actor isolation of the context.
14551463
auto mutableDC = const_cast<DeclContext *>(dc);
1456-
switch (auto isolation = getActorIsolationOfContext(mutableDC)) {
1464+
switch (auto isolation =
1465+
getActorIsolationOfContext(mutableDC, getClosureActorIsolation)) {
14571466
case ActorIsolation::ActorInstance:
14581467
case ActorIsolation::Independent:
14591468
case ActorIsolation::Unspecified:
@@ -1536,6 +1545,9 @@ namespace {
15361545
SmallVector<ApplyExpr*, 4> applyStack;
15371546
SmallVector<std::pair<OpaqueValueExpr *, Expr *>, 4> opaqueValues;
15381547
SmallVector<const PatternBindingDecl *, 2> patternBindingStack;
1548+
llvm::function_ref<Type(Expr *)> getType;
1549+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
1550+
getClosureActorIsolation;
15391551

15401552
/// Keeps track of the capture context of variables that have been
15411553
/// explicitly captured in closures.
@@ -1734,7 +1746,13 @@ namespace {
17341746
}
17351747

17361748
public:
1737-
ActorIsolationChecker(const DeclContext *dc) : ctx(dc->getASTContext()) {
1749+
ActorIsolationChecker(
1750+
const DeclContext *dc,
1751+
llvm::function_ref<Type(Expr *)> getType = __Expr_getType,
1752+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
1753+
getClosureActorIsolation = __AbstractClosureExpr_getActorIsolation)
1754+
: ctx(dc->getASTContext()), getType(getType),
1755+
getClosureActorIsolation(getClosureActorIsolation) {
17381756
contextStack.push_back(dc);
17391757
}
17401758

@@ -2034,7 +2052,7 @@ namespace {
20342052
break;
20352053

20362054
if (auto closure = dyn_cast<AbstractClosureExpr>(dc)) {
2037-
auto isolation = closure->getActorIsolation();
2055+
auto isolation = getClosureActorIsolation(closure);
20382056
switch (isolation) {
20392057
case ClosureActorIsolation::Independent:
20402058
if (isSendableClosure(closure, /*forActorIsolation=*/true)) {
@@ -2089,7 +2107,8 @@ namespace {
20892107
// Check isolation of the context itself. We do this separately
20902108
// from the closure check because closures capture specific variables
20912109
// while general isolation is declaration-based.
2092-
switch (auto isolation = getActorIsolationOfContext(dc)) {
2110+
switch (auto isolation =
2111+
getActorIsolationOfContext(dc, getClosureActorIsolation)) {
20932112
case ActorIsolation::Independent:
20942113
case ActorIsolation::Unspecified:
20952114
// Local functions can capture an isolated parameter.
@@ -2459,7 +2478,7 @@ namespace {
24592478

24602479
/// Check actor isolation for a particular application.
24612480
bool checkApply(ApplyExpr *apply) {
2462-
auto fnExprType = apply->getFn()->getType();
2481+
auto fnExprType = getType(apply->getFn());
24632482
if (!fnExprType)
24642483
return false;
24652484

@@ -2474,7 +2493,8 @@ namespace {
24742493
return *contextIsolation;
24752494

24762495
auto declContext = const_cast<DeclContext *>(getDeclContext());
2477-
contextIsolation = getInnermostIsolatedContext(declContext);
2496+
contextIsolation =
2497+
getInnermostIsolatedContext(declContext, getClosureActorIsolation);
24782498
return *contextIsolation;
24792499
};
24802500

@@ -2511,9 +2531,9 @@ namespace {
25112531
// FIXME: The modeling of unsatisfiedIsolation is not great here.
25122532
// We'd be better off using something more like closure isolation
25132533
// that can talk about specific parameters.
2514-
auto nominal = arg->getType()->getAnyNominal();
2534+
auto nominal = getType(arg)->getAnyNominal();
25152535
if (!nominal) {
2516-
nominal = arg->getType()->getASTContext().getProtocol(
2536+
nominal = getType(arg)->getASTContext().getProtocol(
25172537
KnownProtocolKind::Actor);
25182538
}
25192539

@@ -2751,7 +2771,7 @@ namespace {
27512771
// where k is a captured dictionary key.
27522772
if (auto *args = component.getSubscriptArgs()) {
27532773
for (auto arg : *args) {
2754-
auto type = arg.getExpr()->getType();
2774+
auto type = getType(arg.getExpr());
27552775
if (type &&
27562776
shouldDiagnoseExistingDataRaces(getDeclContext()) &&
27572777
diagnoseNonSendableTypes(
@@ -2784,8 +2804,8 @@ namespace {
27842804
if (base)
27852805
isolatedActor.emplace(getIsolatedActor(base));
27862806
auto result = ActorReferenceResult::forReference(
2787-
declRef, loc, getDeclContext(),
2788-
kindOfUsage(decl, context), isolatedActor);
2807+
declRef, loc, getDeclContext(), kindOfUsage(decl, context),
2808+
isolatedActor, None, None, getClosureActorIsolation);
27892809
switch (result) {
27902810
case ActorReferenceResult::SameConcurrencyDomain:
27912811
if (diagnoseReferenceToUnsafeGlobal(decl, loc))
@@ -2869,7 +2889,8 @@ namespace {
28692889
refKind = isolatedActor->kind;
28702890
refGlobalActor = isolatedActor->globalActor;
28712891
} else {
2872-
auto contextIsolation = getInnermostIsolatedContext(getDeclContext());
2892+
auto contextIsolation = getInnermostIsolatedContext(
2893+
getDeclContext(), getClosureActorIsolation);
28732894
switch (contextIsolation) {
28742895
case ActorIsolation::ActorInstance:
28752896
refKind = ReferencedActor::Isolated;
@@ -2913,7 +2934,7 @@ namespace {
29132934
// Attempt to resolve the global actor type of a closure.
29142935
Type resolveGlobalActorType(ClosureExpr *closure) {
29152936
// Check whether the closure's type has a global actor already.
2916-
if (Type closureType = closure->getType()) {
2937+
if (Type closureType = getType(closure)) {
29172938
if (auto closureFnType = closureType->getAs<FunctionType>()) {
29182939
if (Type globalActor = closureFnType->getGlobalActor())
29192940
return globalActor;
@@ -2955,7 +2976,8 @@ namespace {
29552976
return ClosureActorIsolation::forIndependent(preconcurrency);
29562977

29572978
// A non-Sendable closure gets its isolation from its context.
2958-
auto parentIsolation = getActorIsolationOfContext(closure->getParent());
2979+
auto parentIsolation = getActorIsolationOfContext(
2980+
closure->getParent(), getClosureActorIsolation);
29592981
preconcurrency |= parentIsolation.preconcurrency();
29602982

29612983
// We must have parent isolation determined to get here.
@@ -2993,10 +3015,10 @@ bool ActorIsolationChecker::mayExecuteConcurrentlyWith(
29933015
// If both contexts are isolated to the same actor, then they will not
29943016
// execute concurrently.
29953017
auto useIsolation = getActorIsolationOfContext(
2996-
const_cast<DeclContext *>(useContext));
3018+
const_cast<DeclContext *>(useContext), getClosureActorIsolation);
29973019
if (useIsolation.isActorIsolated()) {
29983020
auto defIsolation = getActorIsolationOfContext(
2999-
const_cast<DeclContext *>(defContext));
3021+
const_cast<DeclContext *>(defContext), getClosureActorIsolation);
30003022
if (useIsolation == defIsolation)
30013023
return false;
30023024
}
@@ -3070,9 +3092,12 @@ void swift::checkPropertyWrapperActorIsolation(
30703092
expr->walk(checker);
30713093
}
30723094

3073-
ClosureActorIsolation
3074-
swift::determineClosureActorIsolation(AbstractClosureExpr *closure) {
3075-
ActorIsolationChecker checker(closure->getParent());
3095+
ClosureActorIsolation swift::determineClosureActorIsolation(
3096+
AbstractClosureExpr *closure, llvm::function_ref<Type(Expr *)> getType,
3097+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
3098+
getClosureActorIsolation) {
3099+
ActorIsolationChecker checker(closure->getParent(), getType,
3100+
getClosureActorIsolation);
30763101
return checker.determineClosureIsolation(closure);
30773102
}
30783103

@@ -3762,14 +3787,15 @@ ActorIsolation ActorIsolationRequest::evaluate(
37623787
// If this is a defer body, inherit unconditionally; we don't
37633788
// care if the enclosing function captures the isolated parameter.
37643789
if (func->isDeferBody()) {
3765-
auto enclosingIsolation =
3766-
getActorIsolationOfContext(func->getDeclContext());
3790+
auto enclosingIsolation = getActorIsolationOfContext(
3791+
func->getDeclContext(), __AbstractClosureExpr_getActorIsolation);
37673792
return inferredIsolation(enclosingIsolation);
37683793
}
37693794

37703795
if (func->isLocalCapture() && !func->isSendable()) {
3771-
switch (auto enclosingIsolation =
3772-
getActorIsolationOfContext(func->getDeclContext())) {
3796+
switch (auto enclosingIsolation = getActorIsolationOfContext(
3797+
func->getDeclContext(),
3798+
__AbstractClosureExpr_getActorIsolation)) {
37733799
case ActorIsolation::Independent:
37743800
case ActorIsolation::Unspecified:
37753801
// Do nothing.
@@ -5020,10 +5046,11 @@ static bool equivalentIsolationContexts(
50205046

50215047
ActorReferenceResult ActorReferenceResult::forReference(
50225048
ConcreteDeclRef declRef, SourceLoc declRefLoc, const DeclContext *fromDC,
5023-
Optional<VarRefUseEnv> useKind,
5024-
Optional<ReferencedActor> actorInstance,
5049+
Optional<VarRefUseEnv> useKind, Optional<ReferencedActor> actorInstance,
50255050
Optional<ActorIsolation> knownDeclIsolation,
5026-
Optional<ActorIsolation> knownContextIsolation) {
5051+
Optional<ActorIsolation> knownContextIsolation,
5052+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
5053+
getClosureActorIsolation) {
50275054
// If not provided, compute the isolation of the declaration, adjusted
50285055
// for references.
50295056
ActorIsolation declIsolation = ActorIsolation::forUnspecified();
@@ -5045,7 +5072,8 @@ ActorReferenceResult ActorReferenceResult::forReference(
50455072
if (knownContextIsolation) {
50465073
contextIsolation = *knownContextIsolation;
50475074
} else {
5048-
contextIsolation = getInnermostIsolatedContext(fromDC);
5075+
contextIsolation =
5076+
getInnermostIsolatedContext(fromDC, getClosureActorIsolation);
50495077
}
50505078

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

lib/Sema/TypeCheckConcurrency.h

Lines changed: 9 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>
@@ -49,6 +50,10 @@ class TypeBase;
4950
class ValueDecl;
5051
class VarDecl;
5152

53+
/// Trampoline for AbstractClosureExpr::getActorIsolation.
54+
ClosureActorIsolation
55+
__AbstractClosureExpr_getActorIsolation(AbstractClosureExpr *CE);
56+
5257
/// Add notes suggesting the addition of 'async', as appropriate,
5358
/// to a diagnostic for a function that isn't an async context.
5459
void addAsyncNotes(AbstractFunctionDecl const* func);
@@ -60,16 +65,6 @@ void checkInitializerActorIsolation(Initializer *init, Expr *expr);
6065
void checkEnumElementActorIsolation(EnumElementDecl *element, Expr *expr);
6166
void checkPropertyWrapperActorIsolation(VarDecl *wrappedVar, Expr *expr);
6267

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-
7368
/// States the reason for checking the Sendability of a given declaration.
7469
enum class SendableCheckReason {
7570
/// A reference to an actor from outside that actor.
@@ -240,13 +235,13 @@ struct ActorReferenceResult {
240235
/// provided when referencing the declaration. This can be either the base
241236
/// of a member access or a parameter passed to a function.
242237
static ActorReferenceResult forReference(
243-
ConcreteDeclRef declRef,
244-
SourceLoc declRefLoc,
245-
const DeclContext *fromDC,
238+
ConcreteDeclRef declRef, SourceLoc declRefLoc, const DeclContext *fromDC,
246239
Optional<VarRefUseEnv> useKind = None,
247240
Optional<ReferencedActor> actorInstance = None,
248241
Optional<ActorIsolation> knownDeclIsolation = None,
249-
Optional<ActorIsolation> knownContextIsolation = None);
242+
Optional<ActorIsolation> knownContextIsolation = None,
243+
llvm::function_ref<ClosureActorIsolation(AbstractClosureExpr *)>
244+
getClosureActorIsolation = __AbstractClosureExpr_getActorIsolation);
250245

251246
operator Kind() const { return kind; }
252247
};

0 commit comments

Comments
 (0)