Skip to content

Commit adabdcb

Browse files
authored
Merge pull request #41639 from xedin/se-0326-special-handling-of-local-funcs
[CSClosure] Delay type-checking of local functions until body is rewr…
2 parents ae02d05 + e9f7a6a commit adabdcb

File tree

2 files changed

+50
-1
lines changed

2 files changed

+50
-1
lines changed

lib/Sema/CSClosure.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1004,6 +1004,9 @@ class ClosureConstraintApplication
10041004
RewriteTargetFn rewriteTarget;
10051005
bool isSingleExpression;
10061006

1007+
/// All `func`s declared in the body of the closure.
1008+
SmallVector<FuncDecl *, 4> LocalFuncs;
1009+
10071010
public:
10081011
/// Whether an error was encountered while generating constraints.
10091012
bool hadError = false;
@@ -1048,6 +1051,14 @@ class ClosureConstraintApplication
10481051
// information e.g. accessors and do access/availability checks.
10491052
}
10501053

1054+
// Local functions cannot be type-checked in-order because they can
1055+
// capture variables declared after them. Let's save them to be
1056+
// processed after the solution has been applied to the body.
1057+
if (auto *func = dyn_cast<FuncDecl>(decl)) {
1058+
LocalFuncs.push_back(func);
1059+
return;
1060+
}
1061+
10511062
TypeChecker::typeCheckDecl(decl);
10521063
}
10531064

@@ -1456,6 +1467,19 @@ class ClosureConstraintApplication
14561467
UNSUPPORTED_STMT(Fail)
14571468
#undef UNSUPPORTED_STMT
14581469

1470+
public:
1471+
/// Apply solution to the closure and return updated body.
1472+
ASTNode apply() {
1473+
auto body = visit(closure->getBody());
1474+
1475+
// Since local functions can capture variables that are declared
1476+
// after them, let's type-check them after all of the pattern
1477+
// bindings have been resolved by applying solution to the body.
1478+
for (auto *func : LocalFuncs)
1479+
TypeChecker::typeCheckDecl(func);
1480+
1481+
return body;
1482+
}
14591483
};
14601484

14611485
}
@@ -1552,7 +1576,7 @@ bool ConstraintSystem::applySolutionToBody(Solution &solution,
15521576
auto closureType = cs.getType(closure)->castTo<FunctionType>();
15531577
ClosureConstraintApplication application(
15541578
solution, closure, closureType->getResult(), rewriteTarget);
1555-
auto body = application.visit(closure->getBody());
1579+
auto body = application.apply();
15561580

15571581
if (!body || application.hadError)
15581582
return true;

test/expr/closure/multi_statement.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,3 +208,28 @@ func test_custom_tilde_equals_operator_matching() {
208208
}
209209
}
210210
}
211+
212+
// Local functions can capture variables before they are declared.
213+
func test_local_function_capturing_vars() {
214+
struct A {
215+
var cond: Bool
216+
}
217+
218+
func test<T>(fn: () -> T) -> T {
219+
fn()
220+
}
221+
222+
func outer(a: A) {
223+
test {
224+
func local() {
225+
if !message.isEmpty { // Ok
226+
print(message)
227+
}
228+
229+
message = "World" // Ok
230+
}
231+
232+
var message = a.cond ? "hello" : ""
233+
}
234+
}
235+
}

0 commit comments

Comments
 (0)