Skip to content

Commit 245e287

Browse files
committed
[AST] Eagerly wire up VarDecl parents when creating CaseStmt
Rather than waiting until type-checking, we can set the parents immediately when we create the CaseStmt. This requires fixing up NamingPatternRequest to look at the recursive parent statement as now the VarDecl may have a variable parent.
1 parent 84befd4 commit 245e287

File tree

2 files changed

+52
-22
lines changed

2 files changed

+52
-22
lines changed

lib/AST/Stmt.cpp

Lines changed: 51 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -773,33 +773,63 @@ CaseStmt::CaseStmt(CaseParentKind parentKind, SourceLoc itemIntroducerLoc,
773773
MutableArrayRef<CaseLabelItem> items{getTrailingObjects<CaseLabelItem>(),
774774
static_cast<size_t>(Bits.CaseStmt.NumPatterns)};
775775

776-
// At the beginning mark all of our var decls as being owned by this
777-
// statement. In the typechecker we wireup the case stmt var decl list since
778-
// we know everything is lined up/typechecked then.
779776
for (unsigned i : range(Bits.CaseStmt.NumPatterns)) {
780777
new (&items[i]) CaseLabelItem(caseLabelItems[i]);
781-
items[i].getPattern()->markOwnedByStatement(this);
782-
}
783-
for (auto *vd : getCaseBodyVariables()) {
784-
vd->setParentPatternStmt(this);
778+
// Mark the CaseStmt as the parent for any canonical VarDecls in the
779+
// pattern.
780+
items[i].getPattern()->forEachVariable([&](VarDecl *VD) {
781+
if (!VD->getParentVarDecl())
782+
VD->setParentPatternStmt(this);
783+
});
785784
}
786785
}
787786

788787
namespace {
789-
static ArrayRef<VarDecl *>
790-
getCaseVarDecls(ASTContext &ctx, ArrayRef<CaseLabelItem> labelItems) {
791-
// Grab the first case label item pattern and use it to initialize the case
792-
// body var decls.
793-
SmallVector<VarDecl *, 4> tmp;
794-
labelItems.front().getPattern()->collectVariables(tmp);
795-
return ctx.AllocateTransform<VarDecl *>(
796-
llvm::ArrayRef(tmp), [&](VarDecl *vOld) -> VarDecl * {
797-
auto *vNew = new (ctx) VarDecl(
798-
/*IsStatic*/ false, vOld->getIntroducer(), vOld->getNameLoc(),
799-
vOld->getName(), vOld->getDeclContext());
800-
vNew->setImplicit();
801-
return vNew;
802-
});
788+
/// Produces an array of internal case body variables, and binds all of the
789+
/// pattern variables that occur within the case to their "parent" pattern
790+
/// variables, forming chains of variables with the same name.
791+
///
792+
/// Given a case such as:
793+
/// \code
794+
/// case .a(let x), .b(let x), .c(let x):
795+
/// \endcode
796+
///
797+
/// Each case item contains a (different) pattern variable named `x`. This
798+
/// function will set the "parent" variable of the second and third `x`
799+
/// variables to the `x` variable immediately to its left. A fourth `x` will be
800+
/// the body case variable, whose parent will be set to the `x` within the final
801+
/// case item.
802+
static ArrayRef<VarDecl *> getCaseVarDecls(ASTContext &ctx,
803+
ArrayRef<CaseLabelItem> labelItems) {
804+
SmallVector<VarDecl *, 4> caseVars;
805+
llvm::SmallDenseMap<Identifier, VarDecl *, 4> allVars;
806+
807+
auto foundVar = [&](VarDecl *VD) {
808+
if (!VD->hasName())
809+
return;
810+
811+
auto &entry = allVars[VD->getName()];
812+
if (entry) {
813+
VD->setParentVarDecl(entry);
814+
} else {
815+
auto *caseVar = new (ctx) VarDecl(
816+
/*IsStatic*/ false, VD->getIntroducer(), VD->getNameLoc(),
817+
VD->getName(), VD->getDeclContext());
818+
caseVar->setImplicit();
819+
caseVars.push_back(caseVar);
820+
}
821+
entry = VD;
822+
};
823+
824+
for (auto &caseItem : labelItems)
825+
caseItem.getPattern()->forEachVariable(foundVar);
826+
827+
// Now that we've collected the case variables, ensure they're parented to
828+
// the last pattern variables we saw.
829+
for (auto caseVar : caseVars)
830+
foundVar(caseVar);
831+
832+
return ctx.AllocateCopy(caseVars);
803833
}
804834

805835
struct FallthroughFinder : ASTWalker {

lib/Sema/TypeCheckDecl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2715,7 +2715,7 @@ NamingPatternRequest::evaluate(Evaluator &evaluator, VarDecl *VD) const {
27152715
}
27162716

27172717
if (!namingPattern) {
2718-
if (auto parentStmt = VD->getParentPatternStmt()) {
2718+
if (auto parentStmt = VD->getRecursiveParentPatternStmt()) {
27192719
// Try type checking parent control statement.
27202720
if (auto condStmt = dyn_cast<LabeledConditionalStmt>(parentStmt)) {
27212721
// The VarDecl is defined inside a condition of a `if` or `while` stmt.

0 commit comments

Comments
 (0)