Skip to content

Commit 0e8ece6

Browse files
authored
Merge pull request #58834 from xedin/var-finder-return-handling
[CSClosure] Fix per-element variable finder to correctly handle retur…
2 parents 06fd9be + ddd7e49 commit 0e8ece6

File tree

2 files changed

+50
-2
lines changed

2 files changed

+50
-2
lines changed

lib/Sema/CSClosure.cpp

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ Expr *getVoidExpr(ASTContext &ctx) {
3737

3838
/// Find any type variable references inside of an AST node.
3939
class TypeVariableRefFinder : public ASTWalker {
40+
/// A stack of all closures the walker encountered so far.
41+
SmallVector<DeclContext *> ClosureDCs;
42+
4043
ConstraintSystem &CS;
4144
ASTNode Parent;
4245

@@ -46,9 +49,16 @@ class TypeVariableRefFinder : public ASTWalker {
4649
TypeVariableRefFinder(
4750
ConstraintSystem &cs, ASTNode parent,
4851
llvm::SmallPtrSetImpl<TypeVariableType *> &referencedVars)
49-
: CS(cs), Parent(parent), ReferencedVars(referencedVars) {}
52+
: CS(cs), Parent(parent), ReferencedVars(referencedVars) {
53+
if (auto *closure = getAsExpr<ClosureExpr>(Parent))
54+
ClosureDCs.push_back(closure);
55+
}
5056

5157
std::pair<bool, Expr *> walkToExprPre(Expr *expr) override {
58+
if (auto *closure = dyn_cast<ClosureExpr>(expr)) {
59+
ClosureDCs.push_back(closure);
60+
}
61+
5262
if (auto *DRE = dyn_cast<DeclRefExpr>(expr)) {
5363
auto *decl = DRE->getDecl();
5464

@@ -81,20 +91,33 @@ class TypeVariableRefFinder : public ASTWalker {
8191
return {true, expr};
8292
}
8393

94+
Expr *walkToExprPost(Expr *expr) override {
95+
if (auto *closure = dyn_cast<ClosureExpr>(expr)) {
96+
ClosureDCs.pop_back();
97+
}
98+
return expr;
99+
}
100+
84101
std::pair<bool, Stmt *> walkToStmtPre(Stmt *stmt) override {
85102
// Return statements have to reference outside result type
86103
// since all of them are joined by it if it's not specified
87104
// explicitly.
88105
if (isa<ReturnStmt>(stmt)) {
89106
if (auto *closure = getAsExpr<ClosureExpr>(Parent)) {
90-
inferVariables(CS.getClosureType(closure)->getResult());
107+
// Return is only viable if it belongs to a parent closure.
108+
if (currentClosureDC() == closure)
109+
inferVariables(CS.getClosureType(closure)->getResult());
91110
}
92111
}
93112

94113
return {true, stmt};
95114
}
96115

97116
private:
117+
DeclContext *currentClosureDC() const {
118+
return ClosureDCs.empty() ? nullptr : ClosureDCs.back();
119+
}
120+
98121
void inferVariables(Type type) {
99122
type = type->getWithoutSpecifierType();
100123
// Record the type variable itself because it has to

test/expr/closure/multi_statement.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,3 +379,28 @@ func test_diagnosing_on_missing_member_in_case() {
379379
}
380380
}
381381
}
382+
383+
// Type finder shouldn't bring external closure result type
384+
// into the scope of an inner closure e.g. while solving
385+
// init of pattern binding `x`.
386+
func test_type_finder_doesnt_walk_into_inner_closures() {
387+
func test<T>(fn: () -> T) -> T { fn() }
388+
389+
_ = test { // Ok
390+
let x = test {
391+
42
392+
}
393+
394+
let _ = test {
395+
test { "" }
396+
}
397+
398+
// multi-statement
399+
let _ = test {
400+
_ = 42
401+
return test { "" }
402+
}
403+
404+
return x
405+
}
406+
}

0 commit comments

Comments
 (0)