Skip to content

Commit 7b4c9fe

Browse files
committed
Allow implicit last expressions for functions and closures
Gated behind the experimental feature `ImplicitLastExprResults`.
1 parent 33cdd33 commit 7b4c9fe

14 files changed

+1015
-475
lines changed

include/swift/AST/Stmt.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -269,8 +269,8 @@ class ReturnStmt : public Stmt {
269269
return createImplicit(ctx, SourceLoc(), result);
270270
}
271271

272-
/// Create an implicit implied ReturnStmt for a single expression body.
273-
static ReturnStmt *forSingleExprBody(ASTContext &ctx, Expr *result) {
272+
/// Create an implicit implied ReturnStmt for e.g a single expression body.
273+
static ReturnStmt *createImplied(ASTContext &ctx, Expr *result) {
274274
assert(result && "Result must be present to be implied");
275275
auto *RS = createImplicit(ctx, result);
276276
RS->Bits.ReturnStmt.IsImplied = true;

include/swift/Basic/Features.def

+2-2
Original file line numberDiff line numberDiff line change
@@ -231,8 +231,8 @@ EXPERIMENTAL_FEATURE(ThenStatements, false)
231231
/// Enable 'do' expressions.
232232
EXPERIMENTAL_FEATURE(DoExpressions, false)
233233

234-
/// Enable implicitly treating the last expression in an 'if'/'switch'
235-
/// expression as the result
234+
/// Enable implicitly treating the last expression in a function, closure,
235+
/// and 'if'/'switch' expression as the result.
236236
EXPERIMENTAL_FEATURE(ImplicitLastExprResults, false)
237237

238238
/// Enable the `@_rawLayout` attribute.

lib/Parse/ParseDecl.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -8862,7 +8862,7 @@ Parser::parseAbstractFunctionBodyImpl(AbstractFunctionDecl *AFD) {
88628862
SourceLoc LBraceLoc, RBraceLoc;
88638863
LBraceLoc = consumeToken(tok::l_brace);
88648864
auto *CCE = new (Context) CodeCompletionExpr(Tok.getLoc());
8865-
auto *Return = ReturnStmt::forSingleExprBody(Context, CCE);
8865+
auto *Return = ReturnStmt::createImplied(Context, CCE);
88668866
CodeCompletionCallbacks->setParsedDecl(accessor);
88678867
CodeCompletionCallbacks->completeAccessorBeginning(CCE);
88688868
RBraceLoc = Tok.getLoc();

lib/Sema/TypeCheckStmt.cpp

+17-9
Original file line numberDiff line numberDiff line change
@@ -2662,15 +2662,23 @@ bool TypeCheckASTNodeAtLocRequest::evaluate(
26622662
}
26632663

26642664
/// Insert an implicit return for a single expression body function if needed.
2665-
static void addSingleExprReturnIfNeeded(BraceStmt *body, DeclContext *dc) {
2666-
// Must have a single active element.
2667-
auto node = body->getSingleActiveElement();
2668-
if (!node)
2665+
static void addImplicitReturnIfNeeded(BraceStmt *body, DeclContext *dc) {
2666+
if (body->empty())
26692667
return;
26702668

2669+
// Must have a single active element (which is guarenteed to be the last
2670+
// element), or we must be allowing implicit last expression results.
26712671
auto &ctx = dc->getASTContext();
2672+
if (!body->getSingleActiveElement() &&
2673+
!ctx.LangOpts.hasFeature(Feature::ImplicitLastExprResults)) {
2674+
return;
2675+
}
2676+
auto node = body->getLastElement();
2677+
if (!node)
2678+
return;
2679+
26722680
auto makeResult = [&](Expr *E) {
2673-
body->setLastElement(ReturnStmt::forSingleExprBody(ctx, E));
2681+
body->setLastElement(ReturnStmt::createImplied(ctx, E));
26742682
};
26752683

26762684
// For a constructor, we only support nil literals as the implicit result.
@@ -2730,8 +2738,8 @@ PreCheckFunctionBodyRequest::evaluate(Evaluator &evaluator,
27302738
assert(body && "Expected body");
27312739
assert(!AFD->isBodyTypeChecked() && "Body already type-checked?");
27322740

2733-
// Insert an implicit return for a single expression body.
2734-
addSingleExprReturnIfNeeded(body, AFD);
2741+
// Insert an implicit return if needed.
2742+
addImplicitReturnIfNeeded(body, AFD);
27352743

27362744
// For constructors, we make sure that the body ends with a "return"
27372745
// stmt, which we either implicitly synthesize, or the user can write.
@@ -2765,8 +2773,8 @@ BraceStmt *PreCheckClosureBodyRequest::evaluate(Evaluator &evaluator,
27652773
}
27662774
}
27672775
}
2768-
// Insert an implicit return for a single expression body.
2769-
addSingleExprReturnIfNeeded(body, closure);
2776+
// Insert an implicit return if needed.
2777+
addImplicitReturnIfNeeded(body, closure);
27702778
return body;
27712779
}
27722780

test/Constraints/if_switch_implicit_last_expr.swift

-168
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// RUN: %target-typecheck-verify-swift -enable-experimental-feature ImplicitLastExprResults %clang-importer-sdk
2+
3+
// REQUIRES: objc_interop
4+
5+
// Experimental feature requires asserts
6+
// REQUIRES: asserts
7+
8+
import Foundation
9+
10+
func testReturn1(_ d: Double) -> CGFloat {
11+
print("hello")
12+
d
13+
}
14+
15+
func testReturn2(_ d: Double) -> CGFloat {
16+
()
17+
if .random() { d } else { 0 }
18+
}
19+
20+
func testReturn3(_ d: CGFloat) -> Double {
21+
print("hello")
22+
switch Bool.random() { case true: d case false: 0 }
23+
}
24+
25+
func testReturn4(_ d: Double) -> CGFloat {
26+
print("hello")
27+
if .random() {
28+
print("hello")
29+
d
30+
} else {
31+
if .random() {
32+
print("hello")
33+
d
34+
} else {
35+
0
36+
}
37+
}
38+
}
39+
40+
func testClosure(_ d: CGFloat) {
41+
func fn(_: () -> Double) {}
42+
fn {
43+
print("hello")
44+
d
45+
}
46+
fn {
47+
print("hello")
48+
if .random() { 0.0 } else { d }
49+
}
50+
fn {
51+
print("hello")
52+
if .random() {
53+
print("hello")
54+
d
55+
} else {
56+
if .random() {
57+
print("hello")
58+
d
59+
} else {
60+
0
61+
}
62+
}
63+
}
64+
}

test/IDE/complete_if_switch_implicit_last_expr.swift

-70
This file was deleted.

0 commit comments

Comments
 (0)