Skip to content

Commit 972a878

Browse files
committed
Sema: Fix capture analysis with pack iteration for loop inside of a closure
The generic environment introduced by a `for .. in` statement remains in scope until the end of the statement. Copy and paste (ugh) the book-keeping from ASTVerifier for this.
1 parent 093f255 commit 972a878

File tree

1 file changed

+44
-1
lines changed

1 file changed

+44
-1
lines changed

lib/Sema/TypeCheckCaptures.cpp

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ class FindCapturedVars : public ASTWalker {
3939
SmallVector<CapturedValue, 4> Captures;
4040
llvm::SmallDenseMap<ValueDecl*, unsigned, 4> captureEntryNumber;
4141

42+
/// We track the pack expansion expressions in ForEachStmts, because
43+
/// their local generics remain in scope until the end of the statement.
44+
llvm::DenseSet<PackExpansionExpr *> ForEachPatternSequences;
45+
4246
/// A stack of pack element environments we're currently walking into.
4347
/// A reference to an element archetype defined by one of these is not
4448
/// a capture.
@@ -652,13 +656,52 @@ class FindCapturedVars : public ASTWalker {
652656
if (auto expansion = dyn_cast<PackExpansionExpr>(E)) {
653657
if (auto *env = expansion->getGenericEnvironment()) {
654658
assert(env == VisitingEnvironments.back());
655-
VisitingEnvironments.pop_back();
656659
(void) env;
660+
661+
// If this is the pack expansion of a for .. in loop, the generic
662+
// environment remains in scope until the end of the loop.
663+
if (ForEachPatternSequences.count(expansion) == 0)
664+
VisitingEnvironments.pop_back();
657665
}
658666
}
659667

660668
return Action::Continue(E);
661669
}
670+
671+
PreWalkResult<Stmt *> walkToStmtPre(Stmt *S) override {
672+
if (auto *forEachStmt = dyn_cast<ForEachStmt>(S)) {
673+
if (auto *expansion =
674+
dyn_cast<PackExpansionExpr>(forEachStmt->getParsedSequence())) {
675+
if (auto *env = expansion->getGenericEnvironment()) {
676+
// Remember this generic environment, so that it remains on the
677+
// visited stack until the end of the for .. in loop.
678+
assert(ForEachPatternSequences.count(expansion) == 0);
679+
ForEachPatternSequences.insert(expansion);
680+
}
681+
}
682+
}
683+
684+
return Action::Continue(S);
685+
}
686+
687+
PostWalkResult<Stmt *> walkToStmtPost(Stmt *S) override {
688+
if (auto *forEachStmt = dyn_cast<ForEachStmt>(S)) {
689+
if (auto *expansion =
690+
dyn_cast<PackExpansionExpr>(forEachStmt->getParsedSequence())) {
691+
if (auto *env = expansion->getGenericEnvironment()) {
692+
assert(ForEachPatternSequences.count(expansion) != 0);
693+
ForEachPatternSequences.erase(expansion);
694+
695+
// Clean up the generic environment bound by the for loop.
696+
assert(env == VisitingEnvironments.back());
697+
VisitingEnvironments.pop_back();
698+
(void) env;
699+
}
700+
}
701+
}
702+
703+
return Action::Continue(S);
704+
}
662705
};
663706

664707
} // end anonymous namespace

0 commit comments

Comments
 (0)