Skip to content

Commit 74b462b

Browse files
committed
WIP: Allow return to be omitted from single expression functions.
1 parent 5f823fb commit 74b462b

File tree

7 files changed

+1437
-6
lines changed

7 files changed

+1437
-6
lines changed

Diff for: include/swift/AST/Decl.h

+17-3
Original file line numberDiff line numberDiff line change
@@ -401,8 +401,7 @@ class alignas(1 << DeclAlignInBits) Decl {
401401
SWIFT_INLINE_BITFIELD(SubscriptDecl, VarDecl, 2,
402402
StaticSpelling : 2
403403
);
404-
405-
SWIFT_INLINE_BITFIELD(AbstractFunctionDecl, ValueDecl, 3+8+1+1+1+1+1+1+1,
404+
SWIFT_INLINE_BITFIELD(AbstractFunctionDecl, ValueDecl, 3+8+1+1+1+1+1+1+1+1,
406405
/// \see AbstractFunctionDecl::BodyKind
407406
BodyKind : 3,
408407

@@ -426,7 +425,10 @@ class alignas(1 << DeclAlignInBits) Decl {
426425

427426
/// Whether this member was synthesized as part of a derived
428427
/// protocol conformance.
429-
Synthesized : 1
428+
Synthesized : 1,
429+
430+
/// Whether this member's body consists of a single expression.
431+
HasSingleExpressionBody : 1
430432
);
431433

432434
SWIFT_INLINE_BITFIELD(FuncDecl, AbstractFunctionDecl, 1+2+1+1+2,
@@ -5433,13 +5435,25 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
54335435
Bits.AbstractFunctionDecl.NeedsNewVTableEntry = false;
54345436
Bits.AbstractFunctionDecl.HasComputedNeedsNewVTableEntry = false;
54355437
Bits.AbstractFunctionDecl.Synthesized = false;
5438+
Bits.AbstractFunctionDecl.HasSingleExpressionBody = false;
54365439
}
54375440

54385441
void setBodyKind(BodyKind K) {
54395442
Bits.AbstractFunctionDecl.BodyKind = unsigned(K);
54405443
}
54415444

54425445
public:
5446+
void setHasSingleExpressionBody(bool Has = true) {
5447+
Bits.AbstractFunctionDecl.HasSingleExpressionBody = Has;
5448+
}
5449+
5450+
bool hasSingleExpressionBody() const {
5451+
return Bits.AbstractFunctionDecl.HasSingleExpressionBody;
5452+
}
5453+
5454+
Expr *getSingleExpressionBody() const;
5455+
void setSingleExpressionBody(Expr *NewBody);
5456+
54435457
/// Returns the string for the base name, or "_" if this is unnamed.
54445458
StringRef getNameStr() const {
54455459
assert(!getFullName().isSpecial() && "Cannot get string for special names");

Diff for: lib/AST/ASTDumper.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -1070,7 +1070,10 @@ namespace {
10701070
Indent -= 2;
10711071
}
10721072
}
1073-
if (auto Body = D->getBody(/*canSynthesize=*/false)) {
1073+
if (D->hasSingleExpressionBody()) {
1074+
OS << '\n';
1075+
printRec(D->getSingleExpressionBody());
1076+
} else if (auto Body = D->getBody(/*canSynthesize=*/false)) {
10741077
OS << '\n';
10751078
printRec(Body, D->getASTContext());
10761079
}

Diff for: lib/AST/ASTWalker.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,15 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
339339
}
340340
}
341341

342+
// FIXME: FIXME_NOW: DETERMINE: Is this or something like it needed? Right
343+
// now it's causing assertion failures during AST verification.
344+
//
345+
// if (AFD->hasSingleExpressionBody()) {
346+
// if (Expr *body = doIt(AFD->getSingleExpressionBody()))
347+
// AFD->setSingleExpressionBody(body);
348+
// else
349+
// return true;
350+
// }
342351
if (AFD->getBody(/*canSynthesize=*/false)) {
343352
AbstractFunctionDecl::BodyKind PreservedKind = AFD->getBodyKind();
344353
if (BraceStmt *S = cast_or_null<BraceStmt>(doIt(AFD->getBody())))

Diff for: lib/AST/Decl.cpp

+20
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,26 @@ case DeclKind::ID: return cast<ID##Decl>(this)->getLoc();
471471
llvm_unreachable("Unknown decl kind");
472472
}
473473

474+
Expr *AbstractFunctionDecl::getSingleExpressionBody() const {
475+
assert(hasSingleExpressionBody() && "Not a single-expression body");
476+
auto braceStmt = getBody();
477+
assert(braceStmt != nullptr && "No body currently available.");
478+
auto body = getBody()->getElement(0);
479+
if (body.is<Stmt *>())
480+
return cast<ReturnStmt>(body.get<Stmt *>())->getResult();
481+
return body.get<Expr *>();
482+
}
483+
484+
void AbstractFunctionDecl::setSingleExpressionBody(Expr *NewBody) {
485+
assert(hasSingleExpressionBody() && "Not a single-expression body");
486+
auto body = getBody()->getElement(0);
487+
if (body.is<Stmt *>()) {
488+
cast<ReturnStmt>(body.get<Stmt *>())->setResult(NewBody);
489+
return;
490+
}
491+
getBody()->setElement(0, NewBody);
492+
}
493+
474494
bool AbstractStorageDecl::isTransparent() const {
475495
return getAttrs().hasAttribute<TransparentAttr>();
476496
}

Diff for: lib/Parse/ParseDecl.cpp

+50-2
Original file line numberDiff line numberDiff line change
@@ -5655,8 +5655,56 @@ void Parser::parseAbstractFunctionBody(AbstractFunctionDecl *AFD) {
56555655
Context.Stats->getFrontendCounters().NumFunctionsParsed++;
56565656

56575657
ParserResult<BraceStmt> Body = parseBraceItemList(diag::invalid_diagnostic);
5658-
if (!Body.isNull())
5659-
AFD->setBody(Body.get());
5658+
if (!Body.isNull()) {
5659+
// If the body consists of a single expression, turn it into a return
5660+
// statement.
5661+
BraceStmt * BS = Body.get();
5662+
AFD->setBody(BS);
5663+
// FIXME: FIXME_NOW: DETERMINE: Do we need to handle the code completion
5664+
// case here? It is being handled for closure
5665+
// (Parser::parseExprClosure).
5666+
if (BS->getNumElements() == 1) {
5667+
auto Element = BS->getElement(0);
5668+
// FIXME: FIXME_NOW: DETERMINE: Do we need to do this? It's being done
5669+
// for closures (Parser::parseExprClosure) but it may not be
5670+
// relevant here.
5671+
//
5672+
// if (Element.is<Stmt *>()) {
5673+
// if (auto returnStmt =
5674+
// dyn_cast_or_null<ReturnStmt>(Element.get<Stmt*>())) {
5675+
//
5676+
// if (!returnStmt->hasResult()) {
5677+
// Expr *returnExpr = TupleExpr::createEmpty(Context,
5678+
// SourceLoc(),
5679+
// SourceLoc(),
5680+
// /*implicit*/true);
5681+
//
5682+
// returnStmt->setResult(returnExpr);
5683+
// AFD->setHasSingleExpressionBody();
5684+
// AFD->setSingleExpressionBody(returnExpr);
5685+
// }
5686+
// }
5687+
// } else
5688+
if (Element.is<Expr *>()) {
5689+
auto E = Element.get<Expr *>();
5690+
if (auto F = dyn_cast_or_null<FuncDecl>(AFD)) {
5691+
auto RS = new (Context) ReturnStmt(SourceLoc(), E);
5692+
BS->setElement(0, RS);
5693+
AFD->setHasSingleExpressionBody();
5694+
AFD->setSingleExpressionBody(E);
5695+
} else if (auto F = dyn_cast_or_null<ConstructorDecl>(AFD)) {
5696+
if (F->getFailability() != OTK_None && isa<NilLiteralExpr>(E)) {
5697+
// If it's a nil literal, just insert return. This is the only
5698+
// legal thing to return.
5699+
auto RS = new (Context) ReturnStmt(E->getStartLoc(), E);
5700+
BS->setElement(0, RS);
5701+
AFD->setHasSingleExpressionBody();
5702+
AFD->setSingleExpressionBody(E);
5703+
}
5704+
}
5705+
}
5706+
}
5707+
}
56605708
}
56615709

56625710
bool Parser::parseAbstractFunctionBodyDelayed(AbstractFunctionDecl *AFD) {

Diff for: lib/Sema/TypeCheckStmt.cpp

+42
Original file line numberDiff line numberDiff line change
@@ -1905,6 +1905,48 @@ bool TypeChecker::typeCheckFunctionBodyUntil(FuncDecl *FD,
19051905
BraceStmt *BS = FD->getBody();
19061906
assert(BS && "Should have a body");
19071907

1908+
// FIXME: FIXME_NOW: DETERMINE: What is the appropriate place for this code to
1909+
// live?
1910+
if (FD->hasSingleExpressionBody()) {
1911+
auto fnType = FD->getBodyResultTypeLoc().getType();
1912+
auto returnStmt = cast<ReturnStmt>(BS->getElement(0).get<Stmt *>());
1913+
auto E = returnStmt->getResult();
1914+
1915+
// FIXME: FIXME_NOW: DETERMINE: Does this actually need to be here? It's
1916+
// being done for closures, but there may be a reason that applies
1917+
// there but not here.
1918+
//
1919+
// if (E != FD->getSingleExpressionBody()) {
1920+
// FD->setSingleExpressionBody(E);
1921+
// }
1922+
1923+
if (FD->getBodyResultTypeLoc().isNull() || fnType->isVoid()) {
1924+
auto voidExpr = TupleExpr::createEmpty(Context,
1925+
E->getStartLoc(),
1926+
E->getEndLoc(),
1927+
/*implicit*/true);
1928+
returnStmt->setResult(voidExpr);
1929+
BS = BraceStmt::create(Context,
1930+
BS->getStartLoc(),
1931+
{ E, returnStmt },
1932+
BS->getEndLoc(),
1933+
/*implicit=*/true);
1934+
} else {
1935+
// FIXME: FIXME_NOW: DETERMINE: Is this the appropriate mechanism to use
1936+
// to divine the type of E?
1937+
auto exprTy = typeCheckExpression(E, FD, TypeLoc(),
1938+
CTP_ReturnStmt);
1939+
if (!exprTy.isNull() && exprTy->isUninhabited() &&
1940+
exprTy->getCanonicalType() != fnType->getCanonicalType()) {
1941+
BS = BraceStmt::create(Context,
1942+
BS->getStartLoc(),
1943+
{ E },
1944+
BS->getEndLoc(),
1945+
/*implicit=*/true);
1946+
}
1947+
}
1948+
}
1949+
19081950
StmtChecker SC(*this, static_cast<AbstractFunctionDecl *>(FD));
19091951
SC.EndTypeCheckLoc = EndTypeCheckLoc;
19101952
bool HadError = SC.typeCheckBody(BS);

0 commit comments

Comments
 (0)