Skip to content

Commit 33bff48

Browse files
authored
Merge pull request #78367 from hamishknight/in-context
[Sema] Remove RecontextualizeClosures
2 parents 33f03f7 + 6a1f8c7 commit 33bff48

12 files changed

+133
-154
lines changed

include/swift/AST/DeclContext.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,8 @@ class alignas(1 << DeclContextAlignInBits) DeclContext
261261
friend class Initializer; // uses setParent
262262
friend class AutoClosureExpr; // uses setParent
263263
friend class AbstractClosureExpr; // uses setParent
264-
264+
friend class Decl; // uses setParent
265+
265266
template<class A, class B, class C>
266267
friend struct ::llvm::CastInfo;
267268

lib/AST/Decl.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -768,6 +768,9 @@ void Decl::setInvalid() {
768768

769769
void Decl::setDeclContext(DeclContext *DC) {
770770
Context = DC;
771+
// If this Decl is also a DeclContext, we need to update its parent too.
772+
if (auto *thisDC = dyn_cast<DeclContext>(this))
773+
thisDC->setParent(DC);
771774
}
772775

773776
bool Decl::isUserAccessible() const {

lib/Sema/TypeCheckCaptures.cpp

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -241,10 +241,9 @@ class FindCapturedVars : public ASTWalker {
241241
}
242242

243243
LazyInitializerWalking getLazyInitializerWalkingBehavior() override {
244-
// We don't want to walk into lazy initializers because they're not
245-
// really present at this level. We'll catch them when processing
246-
// the getter.
247-
return LazyInitializerWalking::None;
244+
// Captures for lazy initializers are computed as part of the parent
245+
// accessor.
246+
return LazyInitializerWalking::InAccessor;
248247
}
249248

250249
MacroWalking getMacroWalkingBehavior() const override {
@@ -643,12 +642,6 @@ class FindCapturedVars : public ASTWalker {
643642
if (auto *PEE = dyn_cast<PackElementExpr>(E))
644643
return walkToPackElementExpr(PEE);
645644

646-
// Look into lazy initializers.
647-
if (auto *LIE = dyn_cast<LazyInitializerExpr>(E)) {
648-
LIE->getSubExpr()->walk(*this);
649-
return Action::Continue(E);
650-
}
651-
652645
// When we see a reference to the 'super' expression, capture 'self' decl.
653646
if (auto *superE = dyn_cast<SuperRefExpr>(E)) {
654647
if (auto *selfDecl = superE->getSelf()) {

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2947,6 +2947,13 @@ namespace {
29472947
return MacroWalking::Expansion;
29482948
}
29492949

2950+
LazyInitializerWalking getLazyInitializerWalkingBehavior() override {
2951+
// We want to walk lazy initializers as part of their implicit getters
2952+
// since we're interested in querying capture information, and captures
2953+
// for lazy inits are computed as part of type-checking the accessor.
2954+
return LazyInitializerWalking::InAccessor;
2955+
}
2956+
29502957
PreWalkResult<Pattern *> walkToPatternPre(Pattern *pattern) override {
29512958
// Walking into patterns leads to nothing good because then we
29522959
// end up visiting the AccessorDecls of a top-level

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1340,7 +1340,7 @@ Expr *DefaultArgumentExprRequest::evaluate(Evaluator &evaluator,
13401340

13411341
// Walk the checked initializer and contextualize any closures
13421342
// we saw there.
1343-
TypeChecker::contextualizeInitializer(dc, initExpr);
1343+
TypeChecker::contextualizeExpr(initExpr, dc);
13441344
TypeChecker::checkInitializerEffects(dc, initExpr);
13451345

13461346
return initExpr;

lib/Sema/TypeCheckExpr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -772,7 +772,7 @@ Expr *CallerSideDefaultArgExprRequest::evaluate(
772772
return new (ctx) ErrorExpr(initExpr->getSourceRange(), paramTy);
773773
}
774774
if (param->getDefaultArgumentKind() == DefaultArgumentKind::ExpressionMacro) {
775-
TypeChecker::contextualizeCallSideDefaultArgument(dc, initExpr);
775+
TypeChecker::contextualizeExpr(initExpr, dc);
776776
TypeChecker::checkCallerSideDefaultArgumentEffects(dc, initExpr);
777777
}
778778
return initExpr;

lib/Sema/TypeCheckStmt.cpp

Lines changed: 77 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -62,61 +62,47 @@ using namespace swift;
6262
#define DEBUG_TYPE "TypeCheckStmt"
6363

6464
namespace {
65-
/// After forming autoclosures, we must re-parent any closure expressions
66-
/// nested inside the autoclosure, because the autoclosure introduces a new
67-
/// DeclContext.
68-
class ContextualizeClosuresAndMacros : public ASTWalker {
65+
/// After forming autoclosures and lazy initializer getters, we must update
66+
/// the DeclContexts for any AST nodes that store the DeclContext they're
67+
/// within. This includes e.g closures and decls, as well as some other
68+
/// expressions, statements, and patterns.
69+
class ContextualizationWalker : public ASTWalker {
6970
DeclContext *ParentDC;
71+
72+
ContextualizationWalker(DeclContext *parent) : ParentDC(parent) {}
73+
7074
public:
71-
ContextualizeClosuresAndMacros(DeclContext *parent) : ParentDC(parent) {}
75+
static void contextualize(ASTNode node, DeclContext *DC) {
76+
node.walk(ContextualizationWalker(DC));
77+
}
7278

7379
MacroWalking getMacroWalkingBehavior() const override {
7480
return MacroWalking::ArgumentsAndExpansion;
7581
}
7682

77-
PreWalkResult<Expr *> walkToExprPre(Expr *E) override {
78-
if (auto CE = dyn_cast<AutoClosureExpr>(E)) {
79-
CE->setParent(ParentDC);
80-
81-
// Recurse into the autoclosure body with the new ParentDC.
82-
auto oldParentDC = ParentDC;
83-
ParentDC = CE;
84-
CE->getBody()->walk(*this);
85-
ParentDC = oldParentDC;
86-
87-
TypeChecker::computeCaptures(CE);
88-
return Action::SkipNode(E);
89-
}
90-
91-
if (auto CapE = dyn_cast<CaptureListExpr>(E)) {
92-
// Capture lists need to be reparented to enclosing autoclosures
93-
// and/or initializers of property wrapper backing properties
94-
// (because they subsume initializers associated with wrapped
95-
// properties).
96-
if (isa<AutoClosureExpr>(ParentDC) ||
97-
isPropertyWrapperBackingPropertyInitContext(ParentDC)) {
98-
for (auto &Cap : CapE->getCaptureList()) {
99-
Cap.PBD->setDeclContext(ParentDC);
100-
Cap.getVar()->setDeclContext(ParentDC);
101-
}
102-
}
103-
}
83+
LazyInitializerWalking getLazyInitializerWalkingBehavior() override {
84+
// Don't walk lazy initializers, we contextualize the getter body
85+
// specially when synthesizing.
86+
return LazyInitializerWalking::None;
87+
}
10488

105-
if (auto CE = dyn_cast<ClosureExpr>(E)) {
89+
PreWalkResult<Expr *> walkToExprPre(Expr *E) override {
90+
if (auto *CE = dyn_cast<AbstractClosureExpr>(E)) {
10691
CE->setParent(ParentDC);
107-
CE->getBody()->walk(ContextualizeClosuresAndMacros(CE));
92+
contextualize(CE->getBody(), CE);
10893

10994
TypeChecker::computeCaptures(CE);
11095
return Action::SkipNode(E);
11196
}
11297

11398
// Caller-side default arguments need their @autoclosures checked.
114-
if (auto *DAE = dyn_cast<DefaultArgumentExpr>(E))
99+
if (auto *DAE = dyn_cast<DefaultArgumentExpr>(E)) {
115100
if (DAE->isCallerSide() &&
116101
(DAE->getParamDecl()->isAutoClosure() ||
117102
(DAE->getParamDecl()->getDefaultArgumentKind() ==
118103
DefaultArgumentKind::ExpressionMacro)))
119104
DAE->getCallerSideDefaultExpr()->walk(*this);
105+
}
120106

121107
// Macro expansion expressions require a DeclContext as well.
122108
if (auto macroExpansion = dyn_cast<MacroExpansionExpr>(E)) {
@@ -126,26 +112,62 @@ namespace {
126112
return Action::Continue(E);
127113
}
128114

129-
/// We don't want to recurse into most local declarations.
130-
PreWalkAction walkToDeclPre(Decl *D) override {
131-
// But we do want to walk into the initializers of local
132-
// variables.
133-
return Action::VisitNodeIf(isa<PatternBindingDecl>(D));
115+
PreWalkResult<Pattern *> walkToPatternPre(Pattern *P) override {
116+
// A couple of patterns store DeclContexts.
117+
if (auto *EP = dyn_cast<ExprPattern>(P))
118+
EP->setDeclContext(ParentDC);
119+
if (auto *EP = dyn_cast<EnumElementPattern>(P))
120+
EP->setDeclContext(ParentDC);
121+
122+
return Action::Continue(P);
134123
}
135124

136-
private:
137-
static bool isPropertyWrapperBackingPropertyInitContext(DeclContext *DC) {
138-
auto *init = dyn_cast<PatternBindingInitializer>(DC);
139-
if (!init)
140-
return false;
125+
PreWalkResult<Stmt *> walkToStmtPre(Stmt *S) override {
126+
// The ASTWalker doesn't walk the case body variables, contextualize them
127+
// ourselves.
128+
if (auto *CS = dyn_cast<CaseStmt>(S)) {
129+
for (auto *CaseVar : CS->getCaseBodyVariablesOrEmptyArray())
130+
CaseVar->setDeclContext(ParentDC);
131+
}
132+
// A few statements store DeclContexts, update them.
133+
if (auto *BS = dyn_cast<BreakStmt>(S))
134+
BS->setDeclContext(ParentDC);
135+
if (auto *CS = dyn_cast<ContinueStmt>(S))
136+
CS->setDeclContext(ParentDC);
137+
if (auto *FS = dyn_cast<FallthroughStmt>(S))
138+
FS->setDeclContext(ParentDC);
141139

142-
if (auto *PB = init->getBinding()) {
143-
auto *var = PB->getSingleVar();
144-
return var && var->getOriginalWrappedProperty(
145-
PropertyWrapperSynthesizedPropertyKind::Backing);
140+
return Action::Continue(S);
141+
}
142+
143+
PreWalkAction walkToDeclPre(Decl *D) override {
144+
// We may encounter some decls parented outside of a local context, e.g
145+
// VarDecls in TopLevelCodeDecls are parented to the file. In such cases,
146+
// assume the DeclContext they already have is correct, autoclosures
147+
// and lazy var inits cannot be defined in such contexts anyway.
148+
if (!D->getDeclContext()->isLocalContext())
149+
return Action::SkipNode();
150+
151+
D->setDeclContext(ParentDC);
152+
153+
// Auxiliary decls need to have their contexts adjusted too.
154+
if (auto *VD = dyn_cast<VarDecl>(D)) {
155+
VD->visitAuxiliaryDecls([&](VarDecl *D) {
156+
D->setDeclContext(ParentDC);
157+
});
146158
}
147159

148-
return false;
160+
// We don't currently support peer macro declarations in local contexts,
161+
// however we don't reject them either; so just to be safe, adjust their
162+
// context too.
163+
D->visitAuxiliaryDecls([&](Decl *D) {
164+
D->setDeclContext(ParentDC);
165+
});
166+
167+
// Only recurse into decls that aren't themselves DeclContexts. This
168+
// allows us to visit e.g initializers for PatternBindingDecls and
169+
// accessors for VarDecls.
170+
return Action::SkipNodeIf(isa<DeclContext>(D));
149171
}
150172
};
151173

@@ -197,21 +219,13 @@ namespace {
197219
};
198220
} // end anonymous namespace
199221

200-
void TypeChecker::contextualizeInitializer(Initializer *DC, Expr *E) {
201-
ContextualizeClosuresAndMacros CC(DC);
202-
E->walk(CC);
203-
}
204-
205-
void TypeChecker::contextualizeCallSideDefaultArgument(DeclContext *DC,
206-
Expr *E) {
207-
ContextualizeClosuresAndMacros CC(DC);
208-
E->walk(CC);
222+
void TypeChecker::contextualizeExpr(Expr *E, DeclContext *DC) {
223+
ContextualizationWalker::contextualize(E, DC);
209224
}
210225

211226
void TypeChecker::contextualizeTopLevelCode(TopLevelCodeDecl *TLCD) {
212-
ContextualizeClosuresAndMacros CC(TLCD);
213227
if (auto *body = TLCD->getBody())
214-
body->walk(CC);
228+
ContextualizationWalker::contextualize(body, TLCD);
215229
}
216230

217231
namespace {
@@ -1034,7 +1048,7 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
10341048
/// Type-check an entire function body.
10351049
bool typeCheckBody(BraceStmt *&S) {
10361050
bool HadError = typeCheckStmt(S);
1037-
S->walk(ContextualizeClosuresAndMacros(DC));
1051+
ContextualizationWalker::contextualize(S, DC);
10381052
return HadError;
10391053
}
10401054

@@ -2916,7 +2930,7 @@ TypeCheckFunctionBodyRequest::evaluate(Evaluator &eval,
29162930
body = *optBody;
29172931
alreadyTypeChecked = true;
29182932

2919-
body->walk(ContextualizeClosuresAndMacros(AFD));
2933+
ContextualizationWalker::contextualize(body, AFD);
29202934
}
29212935
}
29222936
}

lib/Sema/TypeCheckStorage.cpp

Lines changed: 6 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -619,7 +619,7 @@ static void checkAndContextualizePatternBindingInit(PatternBindingDecl *binding,
619619

620620
if (auto *initContext = binding->getInitContext(i)) {
621621
auto *init = binding->getInit(i);
622-
TypeChecker::contextualizeInitializer(initContext, init);
622+
TypeChecker::contextualizeExpr(init, initContext);
623623
}
624624
}
625625

@@ -1661,75 +1661,6 @@ synthesizeRead2CoroutineGetterBody(AccessorDecl *getter, ASTContext &ctx) {
16611661
return synthesizeTrivialGetterBody(getter, TargetImpl::Implementation, ctx);
16621662
}
16631663

1664-
namespace {
1665-
/// This ASTWalker explores an expression tree looking for expressions (which
1666-
/// are DeclContext's) and changes their parent DeclContext to NewDC.
1667-
/// TODO: We ought to consider merging this with
1668-
/// ContextualizeClosuresAndMacros, or better yet removing it in favor of
1669-
/// avoiding the recontextualization for lazy vars.
1670-
class RecontextualizeClosures : public ASTWalker {
1671-
DeclContext *NewDC;
1672-
public:
1673-
RecontextualizeClosures(DeclContext *NewDC) : NewDC(NewDC) {}
1674-
1675-
MacroWalking getMacroWalkingBehavior() const override {
1676-
return MacroWalking::ArgumentsAndExpansion;
1677-
}
1678-
1679-
PreWalkResult<Expr *> walkToExprPre(Expr *E) override {
1680-
// If we find a closure, update its declcontext and do *not* walk into it.
1681-
if (auto CE = dyn_cast<AbstractClosureExpr>(E)) {
1682-
CE->setParent(NewDC);
1683-
return Action::SkipNode(E);
1684-
}
1685-
1686-
return Action::Continue(E);
1687-
}
1688-
1689-
PreWalkResult<Pattern *> walkToPatternPre(Pattern *P) override {
1690-
if (auto *EP = dyn_cast<ExprPattern>(P))
1691-
EP->setDeclContext(NewDC);
1692-
if (auto *EP = dyn_cast<EnumElementPattern>(P))
1693-
EP->setDeclContext(NewDC);
1694-
1695-
return Action::Continue(P);
1696-
}
1697-
1698-
PreWalkResult<Stmt *> walkToStmtPre(Stmt *S) override {
1699-
// The ASTWalker doesn't walk the case body variables, contextualize them
1700-
// ourselves.
1701-
if (auto *CS = dyn_cast<CaseStmt>(S)) {
1702-
for (auto *CaseVar : CS->getCaseBodyVariablesOrEmptyArray())
1703-
CaseVar->setDeclContext(NewDC);
1704-
}
1705-
// A few statements store DeclContexts, update them.
1706-
if (auto *BS = dyn_cast<BreakStmt>(S))
1707-
BS->setDeclContext(NewDC);
1708-
if (auto *CS = dyn_cast<ContinueStmt>(S))
1709-
CS->setDeclContext(NewDC);
1710-
if (auto *FS = dyn_cast<FallthroughStmt>(S))
1711-
FS->setDeclContext(NewDC);
1712-
1713-
return Action::Continue(S);
1714-
}
1715-
1716-
PreWalkAction walkToDeclPre(Decl *D) override {
1717-
D->setDeclContext(NewDC);
1718-
1719-
// Auxiliary decls need to have their contexts adjusted too.
1720-
if (auto *VD = dyn_cast<VarDecl>(D)) {
1721-
VD->visitAuxiliaryDecls([&](VarDecl *D) {
1722-
D->setDeclContext(NewDC);
1723-
});
1724-
}
1725-
1726-
// Skip walking the children of any Decls that are also DeclContexts,
1727-
// they will already have the right parent.
1728-
return Action::SkipNodeIf(isa<DeclContext>(D));
1729-
}
1730-
};
1731-
} // end anonymous namespace
1732-
17331664
/// Synthesize the getter for a lazy property with the specified storage
17341665
/// vardecl.
17351666
static std::pair<BraceStmt *, bool>
@@ -1801,12 +1732,13 @@ synthesizeLazyGetterBody(AccessorDecl *Get, VarDecl *VD, VarDecl *Storage,
18011732
InitValue = new (Ctx) ErrorExpr(SourceRange(), Tmp2VD->getTypeInContext());
18021733
}
18031734

1804-
// Recontextualize any closure declcontexts nested in the initializer to
1805-
// realize that they are in the getter function.
1735+
// We may have stolen the self decl from a PatternBindingInitializer,
1736+
// re-parent it here.
18061737
if (Get->hasImplicitSelfDecl())
18071738
Get->getImplicitSelfDecl()->setDeclContext(Get);
18081739

1809-
InitValue->walk(RecontextualizeClosures(Get));
1740+
// Also re-contextualize any nodes nested in the initializer.
1741+
TypeChecker::contextualizeExpr(InitValue, Get);
18101742

18111743
// Wrap the initializer in a LazyInitializerExpr to avoid walking it twice.
18121744
auto initType = InitValue->getType();
@@ -3201,7 +3133,7 @@ static void typeCheckSynthesizedWrapperInitializer(VarDecl *wrappedVar,
32013133
// will be done in visitPatternBindingDecl.
32023134
if (!contextualize)
32033135
return;
3204-
TypeChecker::contextualizeInitializer(initContext, initializer);
3136+
TypeChecker::contextualizeExpr(initializer, initContext);
32053137
checkPropertyWrapperActorIsolation(wrappedVar, initializer);
32063138
TypeChecker::checkInitializerEffects(initContext, initializer);
32073139
}

0 commit comments

Comments
 (0)