Skip to content

Commit 8e6840d

Browse files
authored
Merge pull request #32178 from DougGregor/single-expression-closure-cleanup
[AST] Clean up handling of single-expression closures
2 parents e5e34fa + ad42d47 commit 8e6840d

13 files changed

+65
-36
lines changed

include/swift/AST/Expr.h

+19-5
Original file line numberDiff line numberDiff line change
@@ -3774,7 +3774,7 @@ class ClosureExpr : public AbstractClosureExpr {
37743774
/// The bit indicates whether this closure has had a function builder
37753775
/// applied to it.
37763776
llvm::PointerIntPair<VarDecl *, 1, bool> CapturedSelfDeclAndAppliedBuilder;
3777-
3777+
37783778
/// The location of the "throws", if present.
37793779
SourceLoc ThrowsLoc;
37803780

@@ -3786,7 +3786,8 @@ class ClosureExpr : public AbstractClosureExpr {
37863786
SourceLoc InLoc;
37873787

37883788
/// The explicitly-specified result type.
3789-
TypeExpr *ExplicitResultType;
3789+
llvm::PointerIntPair<TypeExpr *, 1, bool>
3790+
ExplicitResultTypeAndEnclosingChecked;
37903791

37913792
/// The body of the closure, along with a bit indicating whether it
37923793
/// was originally just a single expression.
@@ -3801,7 +3802,8 @@ class ClosureExpr : public AbstractClosureExpr {
38013802
BracketRange(bracketRange),
38023803
CapturedSelfDeclAndAppliedBuilder(capturedSelfDecl, false),
38033804
ThrowsLoc(throwsLoc), ArrowLoc(arrowLoc), InLoc(inLoc),
3804-
ExplicitResultType(explicitResultType), Body(nullptr) {
3805+
ExplicitResultTypeAndEnclosingChecked(explicitResultType, false),
3806+
Body(nullptr) {
38053807
setParameterList(params);
38063808
Bits.ClosureExpr.HasAnonymousClosureVars = false;
38073809
}
@@ -3855,13 +3857,15 @@ class ClosureExpr : public AbstractClosureExpr {
38553857

38563858
Type getExplicitResultType() const {
38573859
assert(hasExplicitResultType() && "No explicit result type");
3858-
return ExplicitResultType->getInstanceType();
3860+
return ExplicitResultTypeAndEnclosingChecked.getPointer()
3861+
->getInstanceType();
38593862
}
38603863
void setExplicitResultType(Type ty);
38613864

38623865
TypeRepr *getExplicitResultTypeRepr() const {
38633866
assert(hasExplicitResultType() && "No explicit result type");
3864-
return ExplicitResultType->getTypeRepr();
3867+
return ExplicitResultTypeAndEnclosingChecked.getPointer()
3868+
->getTypeRepr();
38653869
}
38663870

38673871
/// Determine whether the closure has a single expression for its
@@ -3918,6 +3922,16 @@ class ClosureExpr : public AbstractClosureExpr {
39183922
CapturedSelfDeclAndAppliedBuilder.setInt(flag);
39193923
}
39203924

3925+
/// Whether this closure's body was type checked within the enclosing
3926+
/// context.
3927+
bool wasTypeCheckedInEnclosingContext() const {
3928+
return ExplicitResultTypeAndEnclosingChecked.getInt();
3929+
}
3930+
3931+
void setTypeCheckedInEnclosingContext(bool flag = true) {
3932+
ExplicitResultTypeAndEnclosingChecked.setInt(flag);
3933+
}
3934+
39213935
static bool classof(const Expr *E) {
39223936
return E->getKind() == ExprKind::Closure;
39233937
}

lib/AST/ASTDumper.cpp

+1-5
Original file line numberDiff line numberDiff line change
@@ -2496,11 +2496,7 @@ class PrintExpr : public ExprVisitor<PrintExpr> {
24962496
}
24972497

24982498
OS << '\n';
2499-
if (E->hasSingleExpressionBody()) {
2500-
printRec(E->getSingleExpressionBody());
2501-
} else {
2502-
printRec(E->getBody(), E->getASTContext());
2503-
}
2499+
printRec(E->getBody(), E->getASTContext());
25042500
PrintWithColorRAII(OS, ParenthesisColor) << ')';
25052501
}
25062502
void visitAutoClosureExpr(AutoClosureExpr *E) {

lib/AST/Expr.cpp

+3-6
Original file line numberDiff line numberDiff line change
@@ -1923,7 +1923,8 @@ bool ClosureExpr::capturesSelfEnablingImplictSelf() const {
19231923

19241924
void ClosureExpr::setExplicitResultType(Type ty) {
19251925
assert(ty && !ty->hasTypeVariable());
1926-
ExplicitResultType->setType(MetatypeType::get(ty));
1926+
ExplicitResultTypeAndEnclosingChecked.getPointer()
1927+
->setType(MetatypeType::get(ty));
19271928
}
19281929

19291930
FORWARD_SOURCE_LOCS_TO(AutoClosureExpr, Body)
@@ -2364,11 +2365,7 @@ void swift::simple_display(llvm::raw_ostream &out, const ClosureExpr *CE) {
23642365
return;
23652366
}
23662367

2367-
if (CE->hasSingleExpressionBody()) {
2368-
out << "single expression closure";
2369-
} else {
2370-
out << "closure";
2371-
}
2368+
out << "closure";
23722369
}
23732370

23742371
void swift::simple_display(llvm::raw_ostream &out,

lib/Sema/BuilderTransform.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -1701,6 +1701,13 @@ class PreCheckFunctionBuilderApplication : public ASTWalker {
17011701
FunctionBuilderBodyPreCheck
17021702
PreCheckFunctionBuilderRequest::evaluate(Evaluator &eval,
17031703
AnyFunctionRef fn) const {
1704+
// We don't want to do the precheck if it will already have happened in
1705+
// the enclosing expression.
1706+
bool skipPrecheck = false;
1707+
if (auto closure = dyn_cast_or_null<ClosureExpr>(
1708+
fn.getAbstractClosureExpr()))
1709+
skipPrecheck = shouldTypeCheckInEnclosingExpression(closure);
1710+
17041711
return PreCheckFunctionBuilderApplication(fn, false).run();
17051712
}
17061713

lib/Sema/CSApply.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -5787,9 +5787,9 @@ static bool applyTypeToClosureExpr(ConstraintSystem &cs,
57875787
if (auto CE = dyn_cast<ClosureExpr>(expr)) {
57885788
cs.setType(CE, toType);
57895789

5790-
// If this is not a single-expression closure, write the type into the
5791-
// ClosureExpr directly here, since the visitor won't.
5792-
if (!CE->hasSingleExpressionBody())
5790+
// 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+
if (!shouldTypeCheckInEnclosingExpression(CE))
57935793
CE->setType(toType);
57945794

57955795
return true;

lib/Sema/CSClosure.cpp

+7-2
Original file line numberDiff line numberDiff line change
@@ -331,18 +331,23 @@ SolutionApplicationToFunctionResult ConstraintSystem::applySolution(
331331
fn.setBody(newBody, /*isSingleExpression=*/false);
332332
if (closure) {
333333
closure->setAppliedFunctionBuilder();
334+
closure->setTypeCheckedInEnclosingContext();
334335
solution.setExprTypes(closure);
335336
}
336337

337338
return SolutionApplicationToFunctionResult::Success;
339+
338340
}
341+
assert(closure && "Can only get here with a closure at the moment");
339342

340-
// If there is a single-expression body, transform that body now.
341-
if (fn.hasSingleExpressionBody()) {
343+
// If this closure is checked as part of the enclosing expression, handle
344+
// that now.
345+
if (shouldTypeCheckInEnclosingExpression(closure)) {
342346
ClosureConstraintApplication application(
343347
solution, closure, closureFnType->getResult(), rewriteTarget);
344348
application.visit(fn.getBody());
345349

350+
closure->setTypeCheckedInEnclosingContext();
346351
return SolutionApplicationToFunctionResult::Success;
347352
}
348353

lib/Sema/CSGen.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -2248,7 +2248,8 @@ namespace {
22482248
// as potential hole right away.
22492249
resultTy = CS.createTypeVariable(
22502250
resultLoc,
2251-
closure->hasSingleExpressionBody() ? 0 : TVO_CanBindToHole);
2251+
shouldTypeCheckInEnclosingExpression(closure)
2252+
? 0 : TVO_CanBindToHole);
22522253
}
22532254
}
22542255

lib/Sema/CSSimplify.cpp

+4-5
Original file line numberDiff line numberDiff line change
@@ -7220,14 +7220,13 @@ bool ConstraintSystem::resolveClosure(TypeVariableType *typeVar,
72207220
}
72217221
}
72227222

7223-
bool hasReturn = hasExplicitResult(closure);
7223+
// If this closure should be type-checked as part of this expression,
7224+
// generate constraints for it now.
72247225
auto &ctx = getASTContext();
7225-
// If this is a multi-statement closure its body doesn't participate
7226-
// in type-checking.
7227-
if (closure->hasSingleExpressionBody()) {
7226+
if (shouldTypeCheckInEnclosingExpression(closure)) {
72287227
if (generateConstraints(closure, closureType->getResult()))
72297228
return false;
7230-
} else if (!hasReturn) {
7229+
} else if (!hasExplicitResult(closure)) {
72317230
// If this closure has an empty body and no explicit result type
72327231
// let's bind result type to `Void` since that's the only type empty body
72337232
// can produce. Otherwise, if (multi-statement) closure doesn't have

lib/Sema/ConstraintSystem.h

+6
Original file line numberDiff line numberDiff line change
@@ -5487,6 +5487,12 @@ BraceStmt *applyFunctionBuilderTransform(
54875487
constraints::SolutionApplicationTarget)>
54885488
rewriteTarget);
54895489

5490+
/// Determine whether the given closure expression should be type-checked
5491+
/// within the context of its enclosing expression. Otherwise, it will be
5492+
/// separately type-checked once its enclosing expression has determined all
5493+
/// of the parameter and result types without looking at the body.
5494+
bool shouldTypeCheckInEnclosingExpression(ClosureExpr *expr);
5495+
54905496
} // end namespace swift
54915497

54925498
#endif // LLVM_SWIFT_SEMA_CONSTRAINT_SYSTEM_H

lib/Sema/MiscDiagnostics.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
8686

8787
bool walkToDeclPre(Decl *D) override {
8888
if (auto *closure = dyn_cast<ClosureExpr>(D->getDeclContext()))
89-
return closure->hasAppliedFunctionBuilder();
89+
return closure->wasTypeCheckedInEnclosingContext();
9090
return false;
9191
}
9292

@@ -1459,7 +1459,7 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
14591459
// Don't walk into nested decls.
14601460
bool walkToDeclPre(Decl *D) override {
14611461
if (auto *closure = dyn_cast<ClosureExpr>(D->getDeclContext()))
1462-
return closure->hasAppliedFunctionBuilder();
1462+
return closure->wasTypeCheckedInEnclosingContext();
14631463
return false;
14641464
}
14651465

lib/Sema/TypeCheckAvailability.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -1128,7 +1128,8 @@ static void findAvailabilityFixItNodes(SourceRange ReferenceRange,
11281128
[](ASTNode Node, ASTWalker::ParentTy Parent) {
11291129
if (Expr *ParentExpr = Parent.getAsExpr()) {
11301130
auto *ParentClosure = dyn_cast<ClosureExpr>(ParentExpr);
1131-
if (!ParentClosure || !ParentClosure->hasSingleExpressionBody()) {
1131+
if (!ParentClosure ||
1132+
!ParentClosure->wasTypeCheckedInEnclosingContext()) {
11321133
return false;
11331134
}
11341135
} else if (auto *ParentStmt = Parent.getAsStmt()) {

lib/Sema/TypeCheckConstraints.cpp

+6-3
Original file line numberDiff line numberDiff line change
@@ -1320,9 +1320,8 @@ bool PreCheckExpression::walkToClosureExprPre(ClosureExpr *closure) {
13201320
if (hadParameterError)
13211321
return false;
13221322

1323-
// If the closure has a multi-statement body, we don't walk into it
1324-
// here.
1325-
if (!closure->hasSingleExpressionBody())
1323+
// If we won't be checking the body of the closure, don't walk into it here.
1324+
if (!shouldTypeCheckInEnclosingExpression(closure))
13261325
return false;
13271326

13281327
// Update the current DeclContext to be the closure we're about to
@@ -4058,3 +4057,7 @@ HasDynamicCallableAttributeRequest::evaluate(Evaluator &evaluator,
40584057
return type->hasDynamicCallableAttribute();
40594058
});
40604059
}
4060+
4061+
bool swift::shouldTypeCheckInEnclosingExpression(ClosureExpr *expr) {
4062+
return expr->hasSingleExpressionBody();
4063+
}

lib/Sema/TypeCheckStmt.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -140,10 +140,10 @@ namespace {
140140
}
141141
}
142142

143-
// If the closure has a single expression body or has had a function
144-
// builder applied to it, we need to walk into it with a new sequence.
143+
// If the closure was type checked within its enclosing context,
144+
// we need to walk into it with a new sequence.
145145
// Otherwise, it'll have been separately type-checked.
146-
if (CE->hasSingleExpressionBody() || CE->hasAppliedFunctionBuilder())
146+
if (CE->wasTypeCheckedInEnclosingContext())
147147
CE->getBody()->walk(ContextualizeClosures(CE));
148148

149149
TypeChecker::computeCaptures(CE);

0 commit comments

Comments
 (0)