Skip to content

Commit f4a6b95

Browse files
committed
Move single-expr return transform from Parse to Sema
Rather than doing the transform in the parser, and then potentially undoing it in Sema, move the entire transform into Sema. This also lets us unify the logic between function decls and closures, and allows ASTGen to benefit from it.
1 parent b1070f2 commit f4a6b95

File tree

9 files changed

+160
-154
lines changed

9 files changed

+160
-154
lines changed

include/swift/AST/TypeCheckRequests.h

+20-3
Original file line numberDiff line numberDiff line change
@@ -4128,9 +4128,9 @@ class PreCheckReturnStmtRequest
41284128
bool isCached() const { return true; }
41294129
};
41304130

4131-
/// Performs some pre-checking of a function body, including inserting and
4132-
/// removing implict returns where needed. This request is currently
4133-
/// side-effectful, as it will mutate the body in-place.
4131+
/// Performs some pre-checking of a function body, including inserting implicit
4132+
/// returns where needed. This request is currently side-effectful, as it will
4133+
/// mutate the body in-place.
41344134
///
41354135
/// Note this request is currently uncached as:
41364136
/// - The result will ultimately be cached by TypeCheckFunctionBodyRequest.
@@ -4152,6 +4152,23 @@ class PreCheckFunctionBodyRequest
41524152
BraceStmt *evaluate(Evaluator &evaluator, AbstractFunctionDecl *AFD) const;
41534153
};
41544154

4155+
/// Performs some pre-checking of a closure's body, including inserting implicit
4156+
/// returns where needed. This request is currently side-effectful, as it will
4157+
/// mutate the body in-place. Like PreCheckFunctionBodyRequest, it is currently
4158+
/// uncached.
4159+
class PreCheckClosureBodyRequest
4160+
: public SimpleRequest<PreCheckClosureBodyRequest,
4161+
BraceStmt *(ClosureExpr *),
4162+
RequestFlags::Uncached> {
4163+
public:
4164+
using SimpleRequest::SimpleRequest;
4165+
4166+
private:
4167+
friend SimpleRequest;
4168+
4169+
BraceStmt *evaluate(Evaluator &evaluator, ClosureExpr *closure) const;
4170+
};
4171+
41554172
/// The result of the query for whether a statement can produce a single value.
41564173
class IsSingleValueStmtResult {
41574174
public:

include/swift/AST/TypeCheckerTypeIDZone.def

+3
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,9 @@ SWIFT_REQUEST(TypeChecker, TangentStoredPropertyRequest,
350350
SWIFT_REQUEST(TypeChecker, PreCheckFunctionBodyRequest,
351351
BraceStmt *(AbstractFunctionDecl *),
352352
Uncached, NoLocationInfo)
353+
SWIFT_REQUEST(TypeChecker, PreCheckClosureBodyRequest,
354+
BraceStmt *(ClosureExpr *),
355+
Uncached, NoLocationInfo)
353356
SWIFT_REQUEST(TypeChecker, TypeCheckFunctionBodyRequest,
354357
BraceStmt *(AbstractFunctionDecl *), SeparatelyCached,
355358
NoLocationInfo)

lib/AST/ASTBridging.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1019,7 +1019,7 @@ BridgedClosureExpr_createParsed(BridgedASTContext cContext,
10191019
auto *out = new (context) ClosureExpr(
10201020
attributes, bracketRange, nullptr, nullptr, asyncLoc, throwsLoc,
10211021
/*FIXME:thrownType=*/nullptr, arrowLoc, inLoc, nullptr, declContext);
1022-
out->setBody(body.unbridged(), true);
1022+
out->setBody(body.unbridged(), /*isSingleExpression*/ false);
10231023
out->setParameterList(params);
10241024
return out;
10251025
}

lib/Parse/ParseDecl.cpp

-44
Original file line numberDiff line numberDiff line change
@@ -8840,51 +8840,7 @@ Parser::parseAbstractFunctionBodyImpl(AbstractFunctionDecl *AFD) {
88408840
Fingerprint fp(std::move(currentHash));
88418841

88428842
BraceStmt *BS = Body.get();
8843-
// Reset the single expression body status.
8844-
AFD->setHasSingleExpressionBody(false);
88458843
AFD->setBodyParsed(BS, fp);
8846-
8847-
if (auto Element = BS->getSingleActiveElement()) {
8848-
if (auto *stmt = Element.dyn_cast<Stmt *>()) {
8849-
if (isa<FuncDecl>(AFD)) {
8850-
if (auto *returnStmt = dyn_cast<ReturnStmt>(stmt)) {
8851-
if (!returnStmt->hasResult()) {
8852-
auto returnExpr = TupleExpr::createEmpty(Context,
8853-
SourceLoc(),
8854-
SourceLoc(),
8855-
/*implicit*/true);
8856-
returnStmt->setResult(returnExpr);
8857-
AFD->setHasSingleExpressionBody();
8858-
AFD->setSingleExpressionBody(returnExpr);
8859-
}
8860-
}
8861-
}
8862-
} else if (auto *E = Element.dyn_cast<Expr *>()) {
8863-
if (auto SE = dyn_cast<SequenceExpr>(E->getSemanticsProvidingExpr())) {
8864-
if (SE->getNumElements() > 1 && isa<AssignExpr>(SE->getElement(1))) {
8865-
// This is an assignment. We don't want to implicitly return
8866-
// it.
8867-
return {BS, fp};
8868-
}
8869-
}
8870-
if (isa<FuncDecl>(AFD)) {
8871-
auto RS = ReturnStmt::createImplicit(Context, E);
8872-
BS->setLastElement(RS);
8873-
AFD->setHasSingleExpressionBody();
8874-
AFD->setSingleExpressionBody(E);
8875-
} else if (auto *F = dyn_cast<ConstructorDecl>(AFD)) {
8876-
if (F->isFailable() && isa<NilLiteralExpr>(E)) {
8877-
// If it's a nil literal, just insert return. This is the only
8878-
// legal thing to return.
8879-
auto RS = ReturnStmt::createImplicit(Context, E);
8880-
BS->setLastElement(RS);
8881-
AFD->setHasSingleExpressionBody();
8882-
AFD->setSingleExpressionBody(E);
8883-
}
8884-
}
8885-
}
8886-
}
8887-
88888844
return {BS, fp};
88898845
}
88908846

lib/Parse/ParseExpr.cpp

+3-28
Original file line numberDiff line numberDiff line change
@@ -3050,35 +3050,10 @@ ParserResult<Expr> Parser::parseExprClosure() {
30503050
closure->setHasAnonymousClosureVars();
30513051
}
30523052

3053+
// Set the body of the closure. The computation of the single expression body
3054+
// is left up to the type-checker.
30533055
auto *BS = BraceStmt::create(Context, leftBrace, bodyElements, rightBrace);
3054-
3055-
// If the body consists of a single expression, turn it into a return
3056-
// statement.
3057-
bool hasSingleExpressionBody = false;
3058-
if (!missingRBrace) {
3059-
if (auto Element = BS->getSingleActiveElement()) {
3060-
if (Element.is<Stmt *>()) {
3061-
if (auto returnStmt = dyn_cast<ReturnStmt>(Element.get<Stmt *>())) {
3062-
hasSingleExpressionBody = true;
3063-
if (!returnStmt->hasResult()) {
3064-
auto returnExpr = TupleExpr::createEmpty(Context,
3065-
SourceLoc(),
3066-
SourceLoc(),
3067-
/*implicit*/true);
3068-
returnStmt->setResult(returnExpr);
3069-
}
3070-
}
3071-
} else if (Element.is<Expr *>()) {
3072-
// Create the wrapping return.
3073-
hasSingleExpressionBody = true;
3074-
auto returnExpr = Element.get<Expr*>();
3075-
BS->setLastElement(ReturnStmt::createImplicit(Context, returnExpr));
3076-
}
3077-
}
3078-
}
3079-
3080-
// Set the body of the closure.
3081-
closure->setBody(BS, hasSingleExpressionBody);
3056+
closure->setBody(BS, /*hasSingleExpressionBody*/ false);
30823057

30833058
// If the closure includes a capture list, create an AST node for it as well.
30843059
Expr *result = closure;

lib/Sema/PreCheckExpr.cpp

+3-11
Original file line numberDiff line numberDiff line change
@@ -1462,17 +1462,9 @@ namespace {
14621462
/// Perform prechecking of a ClosureExpr before we dive into it. This returns
14631463
/// true when we want the body to be considered part of this larger expression.
14641464
bool PreCheckExpression::walkToClosureExprPre(ClosureExpr *closure) {
1465-
// If we have a single statement that can become an expression, turn it
1466-
// into an expression now.
1467-
auto *body = closure->getBody();
1468-
if (auto *S = body->getSingleActiveStatement()) {
1469-
if (S->mayProduceSingleValue(Ctx)) {
1470-
auto *SVE = SingleValueStmtExpr::createWithWrappedBranches(
1471-
Ctx, S, /*DC*/ closure, /*mustBeExpr*/ false);
1472-
body->setLastElement(ReturnStmt::createImplicit(Ctx, SVE));
1473-
closure->setBody(body, /*isSingleExpression*/ true);
1474-
}
1475-
}
1465+
// Pre-check the closure body.
1466+
(void)evaluateOrDefault(Ctx.evaluator, PreCheckClosureBodyRequest{closure},
1467+
nullptr);
14761468

14771469
// Update the current DeclContext to be the closure we're about to
14781470
// recurse into.

lib/Sema/TypeCheckStmt.cpp

+94-53
Original file line numberDiff line numberDiff line change
@@ -1065,30 +1065,6 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
10651065
return RS;
10661066
}
10671067

1068-
// If the body consisted of a single return without a result
1069-
//
1070-
// func foo() -> Int {
1071-
// return
1072-
// }
1073-
//
1074-
// in parseAbstractFunctionBody the return is given an empty, implicit tuple
1075-
// as its result
1076-
//
1077-
// func foo() -> Int {
1078-
// return ()
1079-
// }
1080-
//
1081-
// Look for that case and diagnose it as missing return expression.
1082-
if (!ResultTy->isVoid() && TheFunc->hasSingleExpressionBody()) {
1083-
auto expr = TheFunc->getSingleExpressionBody();
1084-
if (expr->isImplicit() && isa<TupleExpr>(expr) &&
1085-
cast<TupleExpr>(expr)->getNumElements() == 0) {
1086-
getASTContext().Diags.diagnose(RS->getReturnLoc(),
1087-
diag::return_expr_missing);
1088-
return RS;
1089-
}
1090-
}
1091-
10921068
Expr *E = RS->getResult();
10931069
TypeCheckExprOptions options = {};
10941070

@@ -2677,6 +2653,83 @@ bool TypeCheckASTNodeAtLocRequest::evaluate(
26772653
return false;
26782654
}
26792655

2656+
/// Insert an implicit return for a single expression body function if needed,
2657+
/// returning \c true if the implicit return was added, \c false otherwise.
2658+
static bool addSingleExprReturnIfNeeded(BraceStmt *body, DeclContext *dc) {
2659+
// Must have a single active element.
2660+
auto node = body->getSingleActiveElement();
2661+
if (!node)
2662+
return false;
2663+
2664+
auto &ctx = dc->getASTContext();
2665+
auto makeResult = [&](Expr *E) -> bool {
2666+
body->setLastElement(ReturnStmt::createImplicit(ctx, E));
2667+
return true;
2668+
};
2669+
2670+
// For a constructor, we only support nil literals as the implicit result.
2671+
if (auto *ctor = dyn_cast<ConstructorDecl>(dc)) {
2672+
if (auto *E = node.dyn_cast<Expr *>()) {
2673+
if (ctor->isFailable() && isa<NilLiteralExpr>(E))
2674+
return makeResult(E);
2675+
}
2676+
return false;
2677+
}
2678+
2679+
// Otherwise, we only support implicit results for FuncDecls and ClosureExprs.
2680+
if (!isa<FuncDecl>(dc) && !isa<ClosureExpr>(dc))
2681+
return false;
2682+
2683+
if (auto *fd = dyn_cast<FuncDecl>(dc)) {
2684+
// Don't apply if we have a result builder, or a Void return type.
2685+
if (getResultBuilderType(fd) || fd->getResultInterfaceType()->isVoid())
2686+
return false;
2687+
}
2688+
2689+
// A statement can potentially become an expression.
2690+
if (auto *S = node.dyn_cast<Stmt *>()) {
2691+
if (S->mayProduceSingleValue(ctx)) {
2692+
auto *SVE = SingleValueStmtExpr::createWithWrappedBranches(
2693+
ctx, S, dc, /*mustBeExpr*/ false);
2694+
return makeResult(SVE);
2695+
}
2696+
// If we have a single statement 'return' in a closure, treat it as a
2697+
// single expression body. If we don't have a return value, synthesize
2698+
// 'return ()'. Don't do this in a FuncDecl since we know we have a
2699+
// non-Void return.
2700+
if (isa<ClosureExpr>(dc)) {
2701+
if (auto *returnStmt = dyn_cast<ReturnStmt>(S)) {
2702+
// Treat the existing result as a single expression return.
2703+
if (returnStmt->hasResult())
2704+
return true;
2705+
2706+
auto *returnExpr = TupleExpr::createEmpty(ctx, SourceLoc(), SourceLoc(),
2707+
/*implicit*/ true);
2708+
returnStmt->setResult(returnExpr);
2709+
return true;
2710+
}
2711+
}
2712+
}
2713+
2714+
if (auto *E = node.dyn_cast<Expr *>()) {
2715+
// Take any expression, except for assignments. This helps improves
2716+
// diagnostics.
2717+
// TODO: We probably ought to apply this to closures too, but that currently
2718+
// regresses a couple of diagnostics.
2719+
if (!isa<ClosureExpr>(dc)) {
2720+
auto *SemanticExpr = E->getSemanticsProvidingExpr();
2721+
if (auto *SE = dyn_cast<SequenceExpr>(SemanticExpr)) {
2722+
if (SE->getNumElements() > 1 && isa<AssignExpr>(SE->getElement(1)))
2723+
return false;
2724+
}
2725+
if (isa<AssignExpr>(SemanticExpr))
2726+
return false;
2727+
}
2728+
return makeResult(E);
2729+
}
2730+
return false;
2731+
}
2732+
26802733
BraceStmt *
26812734
PreCheckFunctionBodyRequest::evaluate(Evaluator &evaluator,
26822735
AbstractFunctionDecl *AFD) const {
@@ -2687,38 +2740,15 @@ PreCheckFunctionBodyRequest::evaluate(Evaluator &evaluator,
26872740
assert(body && "Expected body");
26882741
assert(!AFD->isBodyTypeChecked() && "Body already type-checked?");
26892742

2690-
if (auto *func = dyn_cast<FuncDecl>(AFD)) {
2691-
// Don't apply this pre-checking to functions with result builders.
2692-
if (getResultBuilderType(func))
2693-
return body;
2694-
2695-
if (func->hasSingleExpressionBody() &&
2696-
func->getResultInterfaceType()->isVoid()) {
2697-
// The function returns void. We don't need an explicit return, no
2698-
// matter what the type of the expression is. Take the inserted return
2699-
// back out.
2700-
body->setLastElement(func->getSingleExpressionBody());
2701-
}
2702-
// If there is a single statement in the body that can be turned into a
2703-
// single expression return, do so now.
2704-
if (!func->getResultInterfaceType()->isVoid()) {
2705-
if (auto *S = body->getSingleActiveStatement()) {
2706-
if (S->mayProduceSingleValue(ctx)) {
2707-
auto *SVE = SingleValueStmtExpr::createWithWrappedBranches(
2708-
ctx, S, /*DC*/ func, /*mustBeExpr*/ false);
2709-
body->setLastElement(ReturnStmt::createImplicit(ctx, SVE));
2710-
func->setHasSingleExpressionBody();
2711-
func->setSingleExpressionBody(SVE);
2712-
}
2713-
}
2714-
}
2715-
}
2743+
// Insert an implicit return for a single expression body.
2744+
if (addSingleExprReturnIfNeeded(body, AFD))
2745+
AFD->setHasSingleExpressionBody();
27162746

2747+
// For constructors, we make sure that the body ends with a "return"
2748+
// stmt, which we either implicitly synthesize, or the user can write.
2749+
// This simplifies SILGen.
27172750
if (auto *ctor = dyn_cast<ConstructorDecl>(AFD)) {
27182751
if (body->empty() || !isKnownEndOfConstructor(body->getLastElement())) {
2719-
// For constructors, we make sure that the body ends with a "return"
2720-
// stmt, which we either implicitly synthesize, or the user can write.
2721-
// This simplifies SILGen.
27222752
SmallVector<ASTNode, 8> Elts(body->getElements().begin(),
27232753
body->getElements().end());
27242754
Elts.push_back(ReturnStmt::createImplicit(ctx, body->getRBraceLoc(),
@@ -2730,6 +2760,17 @@ PreCheckFunctionBodyRequest::evaluate(Evaluator &evaluator,
27302760
return body;
27312761
}
27322762

2763+
BraceStmt *PreCheckClosureBodyRequest::evaluate(Evaluator &evaluator,
2764+
ClosureExpr *closure) const {
2765+
auto *body = closure->getBody();
2766+
2767+
// Insert an implicit return for a single expression body.
2768+
if (addSingleExprReturnIfNeeded(body, closure))
2769+
closure->setBody(body, /*isSingleExpression*/ true);
2770+
2771+
return body;
2772+
}
2773+
27332774
/// Determine whether the given declaration requires a definition.
27342775
///
27352776
/// Only valid for declarations that can have definitions, i.e.,

test/SourceKit/CodeExpand/code-expand.swift

+13
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,19 @@ braced2(x: {<#T##() -> Void#>}, y: Int)
146146
// CHECK-NEXT: <#code#>
147147
// CHECK-NEXT: }, y: Int)
148148

149+
braced3({
150+
#if true
151+
<#T##() -> Int#>
152+
#endif
153+
})
154+
// CHECK: braced3({
155+
// CHECK-NEXT: #if true
156+
// CHECK-NEXT: {
157+
// CHECK-NEXT: <#code#>
158+
// CHECK-NEXT: }
159+
// CHECK-NEXT: #endif
160+
// CHECK-NEXT: })
161+
149162
func returnTrailing() -> Int {
150163
return withtrail(<#T##() -> ()#>)
151164
// CHECK: return withtrail {

0 commit comments

Comments
 (0)