Skip to content

Commit 1b111f4

Browse files
xedinhborla
authored andcommitted
[PreCheckTarget] Move closure body expansion into PreCheckTarget::walkToClosureExprPre
If closure body is expanded in expression context we need to do some special handling to make sure that source ranges are not completely broken.
1 parent 95b6799 commit 1b111f4

File tree

2 files changed

+23
-9
lines changed

2 files changed

+23
-9
lines changed

lib/Sema/PreCheckTarget.cpp

+23-3
Original file line numberDiff line numberDiff line change
@@ -1149,7 +1149,7 @@ class PreCheckTarget final : public ASTWalker {
11491149

11501150
ASTContext &getASTContext() const { return Ctx; }
11511151

1152-
bool walkToClosureExprPre(ClosureExpr *expr);
1152+
bool walkToClosureExprPre(ClosureExpr *expr, ParentTy &parent);
11531153

11541154
MacroWalking getMacroWalkingBehavior() const override {
11551155
return MacroWalking::Arguments;
@@ -1251,7 +1251,7 @@ class PreCheckTarget final : public ASTWalker {
12511251
// but do not walk into the body. That will be type-checked after
12521252
// we've determine the complete function type.
12531253
if (auto closure = dyn_cast<ClosureExpr>(expr))
1254-
return finish(walkToClosureExprPre(closure), expr);
1254+
return finish(walkToClosureExprPre(closure, Parent), expr);
12551255

12561256
if (auto *unresolved = dyn_cast<UnresolvedDeclRefExpr>(expr))
12571257
return finish(true, TypeChecker::resolveDeclRefExpr(unresolved, DC));
@@ -1533,7 +1533,27 @@ class PreCheckTarget final : public ASTWalker {
15331533

15341534
/// Perform prechecking of a ClosureExpr before we dive into it. This returns
15351535
/// true when we want the body to be considered part of this larger expression.
1536-
bool PreCheckTarget::walkToClosureExprPre(ClosureExpr *closure) {
1536+
bool PreCheckTarget::walkToClosureExprPre(ClosureExpr *closure,
1537+
ParentTy &parent) {
1538+
if (auto *expandedBody = closure->getExpandedBody()) {
1539+
if (Parent.getAsExpr()) {
1540+
// We cannot simply replace the body when closure i.e. is passed
1541+
// as an argument to a call or is a source of an assignment
1542+
// because the source range of the argument list would cross
1543+
// buffer boundaries. One way to avoid that is to inject
1544+
// elements into a new implicit brace statement with the original
1545+
// source locations. Brace statement has to be implicit because its
1546+
// elements are in a different buffer.
1547+
auto sourceRange = closure->getSourceRange();
1548+
closure->setBody(BraceStmt::create(getASTContext(), sourceRange.Start,
1549+
expandedBody->getElements(),
1550+
sourceRange.End,
1551+
/*implicit=*/true));
1552+
} else {
1553+
closure->setBody(expandedBody);
1554+
}
1555+
}
1556+
15371557
// Pre-check the closure body.
15381558
(void)evaluateOrDefault(Ctx.evaluator, PreCheckClosureBodyRequest{closure},
15391559
nullptr);

lib/Sema/TypeCheckStmt.cpp

-6
Original file line numberDiff line numberDiff line change
@@ -2764,12 +2764,6 @@ PreCheckFunctionBodyRequest::evaluate(Evaluator &evaluator,
27642764

27652765
BraceStmt *PreCheckClosureBodyRequest::evaluate(Evaluator &evaluator,
27662766
ClosureExpr *closure) const {
2767-
// If this closure has an attached body macro, expand it now before
2768-
// type checking the body.
2769-
if (auto *expandedBody = closure->getExpandedBody()) {
2770-
closure->setBody(expandedBody);
2771-
}
2772-
27732767
auto *body = closure->getBody();
27742768

27752769
// If we have a single statement 'return', synthesize 'return ()' to ensure

0 commit comments

Comments
 (0)