Skip to content

Commit 7d4da10

Browse files
authored
Merge pull request #32200 from DougGregor/single-expression-closure-cleanup
[AST] Clean up handling of single-expression closures
2 parents aef3464 + b844035 commit 7d4da10

22 files changed

+165
-148
lines changed

include/swift/AST/ASTWalker.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,12 +216,12 @@ class ASTWalker {
216216
virtual bool shouldWalkIntoLazyInitializers() { return true; }
217217

218218
/// This method configures whether the walker should visit the body of a
219-
/// non-single expression closure.
219+
/// closure that was checked separately from its enclosing expression.
220220
///
221221
/// For work that is performed for every top-level expression, this should
222222
/// be overridden to return false, to avoid duplicating work or visiting
223223
/// bodies of closures that have not yet been type checked.
224-
virtual bool shouldWalkIntoNonSingleExpressionClosure(ClosureExpr *) {
224+
virtual bool shouldWalkIntoSeparatelyCheckedClosure(ClosureExpr *) {
225225
return true;
226226
}
227227

include/swift/AST/AnyFunctionRef.h

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -89,20 +89,6 @@ class AnyFunctionRef {
8989
return TheFunction.get<AbstractClosureExpr *>()->getSingleExpressionBody();
9090
}
9191

92-
void setSingleExpressionBody(Expr *expr) {
93-
if (auto *AFD = TheFunction.dyn_cast<AbstractFunctionDecl *>()) {
94-
AFD->setSingleExpressionBody(expr);
95-
return;
96-
}
97-
98-
auto ACE = TheFunction.get<AbstractClosureExpr *>();
99-
if (auto CE = dyn_cast<ClosureExpr>(ACE)) {
100-
CE->setSingleExpressionBody(expr);
101-
} else {
102-
cast<AutoClosureExpr>(ACE)->setBody(expr);
103-
}
104-
}
105-
10692
Type getType() const {
10793
if (auto *AFD = TheFunction.dyn_cast<AbstractFunctionDecl *>())
10894
return AFD->getInterfaceType();

include/swift/AST/Expr.h

Lines changed: 13 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3770,10 +3770,7 @@ class ClosureExpr : public AbstractClosureExpr {
37703770
/// the CaptureListExpr which would normally maintain this sort of
37713771
/// information about captured variables), we need to have some way to access
37723772
/// this information directly on the ClosureExpr.
3773-
///
3774-
/// The bit indicates whether this closure has had a function builder
3775-
/// applied to it.
3776-
llvm::PointerIntPair<VarDecl *, 1, bool> CapturedSelfDeclAndAppliedBuilder;
3773+
VarDecl * CapturedSelfDecl;
37773774

37783775
/// The location of the "throws", if present.
37793776
SourceLoc ThrowsLoc;
@@ -3787,7 +3784,7 @@ class ClosureExpr : public AbstractClosureExpr {
37873784

37883785
/// The explicitly-specified result type.
37893786
llvm::PointerIntPair<TypeExpr *, 1, bool>
3790-
ExplicitResultTypeAndEnclosingChecked;
3787+
ExplicitResultTypeAndSeparatelyChecked;
37913788

37923789
/// The body of the closure, along with a bit indicating whether it
37933790
/// was originally just a single expression.
@@ -3800,9 +3797,9 @@ class ClosureExpr : public AbstractClosureExpr {
38003797
: AbstractClosureExpr(ExprKind::Closure, Type(), /*Implicit=*/false,
38013798
discriminator, parent),
38023799
BracketRange(bracketRange),
3803-
CapturedSelfDeclAndAppliedBuilder(capturedSelfDecl, false),
3800+
CapturedSelfDecl(capturedSelfDecl),
38043801
ThrowsLoc(throwsLoc), ArrowLoc(arrowLoc), InLoc(inLoc),
3805-
ExplicitResultTypeAndEnclosingChecked(explicitResultType, false),
3802+
ExplicitResultTypeAndSeparatelyChecked(explicitResultType, false),
38063803
Body(nullptr) {
38073804
setParameterList(params);
38083805
Bits.ClosureExpr.HasAnonymousClosureVars = false;
@@ -3857,14 +3854,14 @@ class ClosureExpr : public AbstractClosureExpr {
38573854

38583855
Type getExplicitResultType() const {
38593856
assert(hasExplicitResultType() && "No explicit result type");
3860-
return ExplicitResultTypeAndEnclosingChecked.getPointer()
3857+
return ExplicitResultTypeAndSeparatelyChecked.getPointer()
38613858
->getInstanceType();
38623859
}
38633860
void setExplicitResultType(Type ty);
38643861

38653862
TypeRepr *getExplicitResultTypeRepr() const {
38663863
assert(hasExplicitResultType() && "No explicit result type");
3867-
return ExplicitResultTypeAndEnclosingChecked.getPointer()
3864+
return ExplicitResultTypeAndSeparatelyChecked.getPointer()
38683865
->getTypeRepr();
38693866
}
38703867

@@ -3894,42 +3891,27 @@ class ClosureExpr : public AbstractClosureExpr {
38943891
/// Only valid when \c hasSingleExpressionBody() is true.
38953892
Expr *getSingleExpressionBody() const;
38963893

3897-
/// Set the body for a closure that has a single expression as its
3898-
/// body.
3899-
///
3900-
/// This routine cannot change whether a closure has a single expression as
3901-
/// its body; it can only update that expression.
3902-
void setSingleExpressionBody(Expr *NewBody);
3903-
39043894
/// Is this a completely empty closure?
39053895
bool hasEmptyBody() const;
39063896

39073897
/// VarDecl captured by this closure under the literal name \c self , if any.
39083898
VarDecl *getCapturedSelfDecl() const {
3909-
return CapturedSelfDeclAndAppliedBuilder.getPointer();
3899+
return CapturedSelfDecl;
39103900
}
39113901

39123902
/// Whether this closure captures the \c self param in its body in such a
39133903
/// way that implicit \c self is enabled within its body (i.e. \c self is
39143904
/// captured non-weakly).
39153905
bool capturesSelfEnablingImplictSelf() const;
39163906

3917-
bool hasAppliedFunctionBuilder() const {
3918-
return CapturedSelfDeclAndAppliedBuilder.getInt();
3919-
}
3920-
3921-
void setAppliedFunctionBuilder(bool flag = true) {
3922-
CapturedSelfDeclAndAppliedBuilder.setInt(flag);
3923-
}
3924-
3925-
/// Whether this closure's body was type checked within the enclosing
3926-
/// context.
3927-
bool wasTypeCheckedInEnclosingContext() const {
3928-
return ExplicitResultTypeAndEnclosingChecked.getInt();
3907+
/// Whether this closure's body was type checked separately from its
3908+
/// enclosing expression.
3909+
bool wasSeparatelyTypeChecked() const {
3910+
return ExplicitResultTypeAndSeparatelyChecked.getInt();
39293911
}
39303912

3931-
void setTypeCheckedInEnclosingContext(bool flag = true) {
3932-
ExplicitResultTypeAndEnclosingChecked.setInt(flag);
3913+
void setSeparatelyTypeChecked(bool flag = true) {
3914+
ExplicitResultTypeAndSeparatelyChecked.setInt(flag);
39333915
}
39343916

39353917
static bool classof(const Expr *E) {

lib/AST/ASTWalker.cpp

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -815,21 +815,15 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
815815
return nullptr;
816816
}
817817

818-
// Handle single-expression closures.
819-
if (expr->hasSingleExpressionBody()) {
820-
if (Expr *body = doIt(expr->getSingleExpressionBody())) {
821-
expr->setSingleExpressionBody(body);
822-
return expr;
823-
}
824-
return nullptr;
825-
}
826-
827-
if (!Walker.shouldWalkIntoNonSingleExpressionClosure(expr))
818+
// If the closure was separately type checked and we don't want to
819+
// visit separately-checked closure bodies, bail out now.
820+
if (expr->wasSeparatelyTypeChecked() &&
821+
!Walker.shouldWalkIntoSeparatelyCheckedClosure(expr))
828822
return expr;
829823

830824
// Handle other closures.
831825
if (BraceStmt *body = cast_or_null<BraceStmt>(doIt(expr->getBody()))) {
832-
expr->setBody(body, false);
826+
expr->setBody(body, expr->hasSingleExpressionBody());
833827
return expr;
834828
}
835829
return nullptr;

lib/AST/Expr.cpp

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1898,19 +1898,6 @@ Expr *ClosureExpr::getSingleExpressionBody() const {
18981898
return body.get<Expr *>();
18991899
}
19001900

1901-
void ClosureExpr::setSingleExpressionBody(Expr *NewBody) {
1902-
assert(hasSingleExpressionBody() && "Not a single-expression body");
1903-
auto body = getBody()->getFirstElement();
1904-
if (auto stmt = body.dyn_cast<Stmt *>()) {
1905-
if (auto braceStmt = dyn_cast<BraceStmt>(stmt))
1906-
braceStmt->getFirstElement() = NewBody;
1907-
else
1908-
cast<ReturnStmt>(stmt)->setResult(NewBody);
1909-
return;
1910-
}
1911-
getBody()->setFirstElement(NewBody);
1912-
}
1913-
19141901
bool ClosureExpr::hasEmptyBody() const {
19151902
return getBody()->empty();
19161903
}
@@ -1923,7 +1910,7 @@ bool ClosureExpr::capturesSelfEnablingImplictSelf() const {
19231910

19241911
void ClosureExpr::setExplicitResultType(Type ty) {
19251912
assert(ty && !ty->hasTypeVariable());
1926-
ExplicitResultTypeAndEnclosingChecked.getPointer()
1913+
ExplicitResultTypeAndSeparatelyChecked.getPointer()
19271914
->setType(MetatypeType::get(ty));
19281915
}
19291916

lib/IDE/Refactoring.cpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3659,16 +3659,25 @@ static CallExpr *findTrailingClosureTarget(SourceManager &SM,
36593659
return N.isStmt(StmtKind::Brace) || N.isExpr(ExprKind::Call);
36603660
});
36613661
Finder.resolve();
3662-
if (Finder.getContexts().empty()
3663-
|| !Finder.getContexts().back().is<Expr*>())
3662+
auto contexts = Finder.getContexts();
3663+
if (contexts.empty())
36643664
return nullptr;
3665-
CallExpr *CE = cast<CallExpr>(Finder.getContexts().back().get<Expr*>());
3665+
3666+
// If the innermost context is a statement (which will be a BraceStmt per
3667+
// the filtering condition above), drop it.
3668+
if (contexts.back().is<Stmt *>()) {
3669+
contexts = contexts.drop_back();
3670+
}
3671+
3672+
if (contexts.empty() || !contexts.back().is<Expr*>())
3673+
return nullptr;
3674+
CallExpr *CE = cast<CallExpr>(contexts.back().get<Expr*>());
36663675

36673676
if (CE->hasTrailingClosure())
36683677
// Call expression already has a trailing closure.
36693678
return nullptr;
36703679

3671-
// The last arugment is a closure?
3680+
// The last argument is a closure?
36723681
Expr *Args = CE->getArg();
36733682
if (!Args)
36743683
return nullptr;

lib/Sema/CSApply.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3859,7 +3859,8 @@ namespace {
38593859
if (expr->isLiteralInit()) {
38603860
auto *literalInit = expr->getSubExpr();
38613861
if (auto *call = dyn_cast<CallExpr>(literalInit)) {
3862-
call->getFn()->forEachChildExpr([&](Expr *subExpr) -> Expr * {
3862+
forEachExprInConstraintSystem(call->getFn(),
3863+
[&](Expr *subExpr) -> Expr * {
38633864
auto *TE = dyn_cast<TypeExpr>(subExpr);
38643865
if (!TE)
38653866
return subExpr;
@@ -5788,7 +5789,7 @@ static bool applyTypeToClosureExpr(ConstraintSystem &cs,
57885789
cs.setType(CE, toType);
57895790

57905791
// If this closure isn't type-checked in its enclosing expression, write
5791-
// theg type into the ClosureExpr directly here, since the visitor won't.
5792+
// the type into the ClosureExpr directly here, since the visitor won't.
57925793
if (!shouldTypeCheckInEnclosingExpression(CE))
57935794
CE->setType(toType);
57945795

lib/Sema/CSClosure.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ class ClosureConstraintGenerator
8484
if (!expr)
8585
return;
8686

87+
// FIXME: Use SolutionApplicationTarget?
8788
expr = cs.generateConstraints(expr, closure, /*isInputExpression=*/false);
8889
if (!expr) {
8990
hadError = true;
@@ -330,8 +331,6 @@ SolutionApplicationToFunctionResult ConstraintSystem::applySolution(
330331

331332
fn.setBody(newBody, /*isSingleExpression=*/false);
332333
if (closure) {
333-
closure->setAppliedFunctionBuilder();
334-
closure->setTypeCheckedInEnclosingContext();
335334
solution.setExprTypes(closure);
336335
}
337336

@@ -347,7 +346,6 @@ SolutionApplicationToFunctionResult ConstraintSystem::applySolution(
347346
solution, closure, closureFnType->getResult(), rewriteTarget);
348347
application.visit(fn.getBody());
349348

350-
closure->setTypeCheckedInEnclosingContext();
351349
return SolutionApplicationToFunctionResult::Success;
352350
}
353351

lib/Sema/CSDiagnostics.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,7 @@ bool MissingConformanceFailure::diagnoseAsError() {
436436
}
437437

438438
bool hasFix = false;
439-
caseExpr->forEachChildExpr([&](Expr *expr) -> Expr * {
439+
forEachExprInConstraintSystem(caseExpr, [&](Expr *expr) -> Expr * {
440440
hasFix |= anchors.count(expr);
441441
return hasFix ? nullptr : expr;
442442
});
@@ -3141,7 +3141,7 @@ bool MissingMemberFailure::diagnoseAsError() {
31413141

31423142
bool hasUnresolvedPattern = false;
31433143
if (auto *E = getAsExpr(anchor)) {
3144-
const_cast<Expr *>(E)->forEachChildExpr([&](Expr *expr) {
3144+
forEachExprInConstraintSystem(const_cast<Expr *>(E), [&](Expr *expr) {
31453145
hasUnresolvedPattern |= isa<UnresolvedPatternExpr>(expr);
31463146
return hasUnresolvedPattern ? nullptr : expr;
31473147
});

lib/Sema/CSGen.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3892,6 +3892,13 @@ namespace {
38923892
}
38933893
}
38943894

3895+
// If this is a closure, only walk into its children if they
3896+
// are type-checked in the context of the enclosing expression.
3897+
if (auto closure = dyn_cast<ClosureExpr>(expr)) {
3898+
if (!shouldTypeCheckInEnclosingExpression(closure))
3899+
return { false, expr };
3900+
}
3901+
38953902
// Now, we're ready to walk into sub expressions.
38963903
return {true, expr};
38973904
}
@@ -4031,12 +4038,6 @@ namespace {
40314038

40324039
/// Ignore declarations.
40334040
bool walkToDeclPre(Decl *decl) override { return false; }
4034-
4035-
// Don't walk into statements. This handles the BraceStmt in
4036-
// non-single-expr closures, so we don't walk into their body.
4037-
std::pair<bool, Stmt *> walkToStmtPre(Stmt *S) override {
4038-
return { false, S };
4039-
}
40404041
};
40414042

40424043
class ConstraintWalker : public ASTWalker {

lib/Sema/CSSimplify.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1548,7 +1548,7 @@ static bool fixMissingArguments(ConstraintSystem &cs, ASTNode anchor,
15481548

15491549
// Something like `foo { x in }` or `foo { $0 }`
15501550
if (auto *closure = getAsExpr<ClosureExpr>(anchor)) {
1551-
closure->forEachChildExpr([&](Expr *expr) -> Expr * {
1551+
forEachExprInConstraintSystem(closure, [&](Expr *expr) -> Expr * {
15521552
if (auto *UDE = dyn_cast<UnresolvedDotExpr>(expr)) {
15531553
if (!isParam(UDE->getBase()))
15541554
return expr;
@@ -9397,7 +9397,7 @@ bool ConstraintSystem::recordFix(ConstraintFix *fix, unsigned impact) {
93979397

93989398
bool found = false;
93999399
if (auto *expr = getAsExpr(anchor)) {
9400-
expr->forEachChildExpr([&](Expr *subExpr) -> Expr * {
9400+
forEachExprInConstraintSystem(expr, [&](Expr *subExpr) -> Expr * {
94019401
found |= anchors.count(subExpr);
94029402
return subExpr;
94039403
});

lib/Sema/ConstraintSystem.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,8 @@ static void extendDepthMap(
590590
Expr *expr,
591591
llvm::DenseMap<Expr *, std::pair<unsigned, Expr *>> &depthMap) {
592592
class RecordingTraversal : public ASTWalker {
593+
SmallVector<ClosureExpr *, 4> Closures;
594+
593595
public:
594596
llvm::DenseMap<Expr *, std::pair<unsigned, Expr *>> &DepthMap;
595597
unsigned Depth = 0;
@@ -601,13 +603,37 @@ static void extendDepthMap(
601603
std::pair<bool, Expr *> walkToExprPre(Expr *E) override {
602604
DepthMap[E] = {Depth, Parent.getAsExpr()};
603605
++Depth;
606+
607+
if (auto CE = dyn_cast<ClosureExpr>(E))
608+
Closures.push_back(CE);
609+
604610
return { true, E };
605611
}
606612

607613
Expr *walkToExprPost(Expr *E) override {
614+
if (auto CE = dyn_cast<ClosureExpr>(E)) {
615+
assert(Closures.back() == CE);
616+
Closures.pop_back();
617+
}
618+
608619
--Depth;
609620
return E;
610621
}
622+
623+
std::pair<bool, Stmt *> walkToStmtPre(Stmt *S) override {
624+
if (auto RS = dyn_cast<ReturnStmt>(S)) {
625+
// For return statements, treat the parent of the return expression
626+
// as the closure itself.
627+
if (RS->hasResult() && !Closures.empty()) {
628+
llvm::SaveAndRestore<ParentTy> SavedParent(Parent, Closures.back());
629+
auto E = RS->getResult();
630+
E->walk(*this);
631+
return { false, S };
632+
}
633+
}
634+
635+
return { true, S };
636+
}
611637
};
612638

613639
RecordingTraversal traversal(depthMap);

lib/Sema/ConstraintSystem.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5493,6 +5493,12 @@ BraceStmt *applyFunctionBuilderTransform(
54935493
/// of the parameter and result types without looking at the body.
54945494
bool shouldTypeCheckInEnclosingExpression(ClosureExpr *expr);
54955495

5496+
/// Visit each subexpression that will be part of the constraint system
5497+
/// of the given expression, including those in closure bodies that will be
5498+
/// part of the constraint system.
5499+
void forEachExprInConstraintSystem(
5500+
Expr *expr, llvm::function_ref<Expr *(Expr *)> callback);
5501+
54965502
} // end namespace swift
54975503

54985504
#endif // LLVM_SWIFT_SEMA_CONSTRAINT_SYSTEM_H

0 commit comments

Comments
 (0)