Skip to content

Commit f366263

Browse files
authored
Merge pull request #59943 from ahoppen/pr/actorisolation-with-gettype
[Sema] Add custom functions to ActorIsolationChecker to determine expr type and closure actor isolation
2 parents 38a528c + 442cf9b commit f366263

File tree

11 files changed

+147
-65
lines changed

11 files changed

+147
-65
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/AST/Expr.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3658,6 +3658,8 @@ class ClosureActorIsolation {
36583658
bool preconcurrency() const {
36593659
return storage.getInt();
36603660
}
3661+
3662+
ActorIsolation getActorIsolation() const;
36613663
};
36623664

36633665
/// A base class for closure expressions.

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 & 22 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,27 +9229,7 @@ ActorIsolation swift::getActorIsolationOfContext(DeclContext *dc) {
92269229
return getActorIsolation(var);
92279230

92289231
if (auto *closure = dyn_cast<AbstractClosureExpr>(dcToUse)) {
9229-
switch (auto isolation = closure->getActorIsolation()) {
9230-
case ClosureActorIsolation::Independent:
9231-
return ActorIsolation::forIndependent()
9232-
.withPreconcurrency(isolation.preconcurrency());
9233-
9234-
case ClosureActorIsolation::GlobalActor: {
9235-
return ActorIsolation::forGlobalActor(
9236-
isolation.getGlobalActor(), /*unsafe=*/false)
9237-
.withPreconcurrency(isolation.preconcurrency());
9238-
}
9239-
9240-
case ClosureActorIsolation::ActorInstance: {
9241-
auto selfDecl = isolation.getActorInstance();
9242-
auto actor = selfDecl->getType()->getReferenceStorageReferent()
9243-
->getAnyActor();
9244-
assert(actor && "Bad closure actor isolation?");
9245-
// FIXME: This could be a parameter... or a capture... hmmm.
9246-
return ActorIsolation::forActorInstanceSelf(actor)
9247-
.withPreconcurrency(isolation.preconcurrency());
9248-
}
9249-
}
9232+
return getClosureActorIsolation(closure).getActorIsolation();
92509233
}
92519234

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

lib/AST/Expr.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1779,6 +1779,29 @@ RebindSelfInConstructorExpr::getCalledConstructor(bool &isChainToSuper) const {
17791779
return otherCtorRef;
17801780
}
17811781

1782+
ActorIsolation ClosureActorIsolation::getActorIsolation() const {
1783+
switch (getKind()) {
1784+
case ClosureActorIsolation::Independent:
1785+
return ActorIsolation::forIndependent().withPreconcurrency(
1786+
preconcurrency());
1787+
1788+
case ClosureActorIsolation::GlobalActor: {
1789+
return ActorIsolation::forGlobalActor(getGlobalActor(), /*unsafe=*/false)
1790+
.withPreconcurrency(preconcurrency());
1791+
}
1792+
1793+
case ClosureActorIsolation::ActorInstance: {
1794+
auto selfDecl = getActorInstance();
1795+
auto actor =
1796+
selfDecl->getType()->getReferenceStorageReferent()->getAnyActor();
1797+
assert(actor && "Bad closure actor isolation?");
1798+
// FIXME: This could be a parameter... or a capture... hmmm.
1799+
return ActorIsolation::forActorInstanceSelf(actor).withPreconcurrency(
1800+
preconcurrency());
1801+
}
1802+
}
1803+
}
1804+
17821805
void AbstractClosureExpr::setParameterList(ParameterList *P) {
17831806
parameterList = P;
17841807
// Change the DeclContext of any parameters to be this closure.
@@ -1880,6 +1903,16 @@ Expr *AbstractClosureExpr::getSingleExpressionBody() const {
18801903
return nullptr;
18811904
}
18821905

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+
18831916
#define FORWARD_SOURCE_LOCS_TO(CLASS, NODE) \
18841917
SourceRange CLASS::getSourceRange() const { \
18851918
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
@@ -933,7 +933,10 @@ void SILGenFunction::emitHopToActorValue(SILLocation loc, ManagedValue actor) {
933933
if (!F.isAsync()) {
934934
llvm::report_fatal_error("Builtin.hopToActor must be in an async function");
935935
}
936-
auto isolation = getActorIsolationOfContext(FunctionDC);
936+
auto isolation =
937+
getActorIsolationOfContext(FunctionDC, [](AbstractClosureExpr *CE) {
938+
return CE->getActorIsolation();
939+
});
937940
if (isolation != ActorIsolation::Independent
938941
&& isolation != ActorIsolation::Unspecified) {
939942
// 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

0 commit comments

Comments
 (0)