Skip to content

Commit 37b1733

Browse files
committed
[SR-11711] Single-expression returns for #if declarations within functions
1 parent b72fb1c commit 37b1733

File tree

10 files changed

+2621
-19
lines changed

10 files changed

+2621
-19
lines changed

lib/AST/Decl.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -684,7 +684,7 @@ Expr *AbstractFunctionDecl::getSingleExpressionBody() const {
684684
assert(hasSingleExpressionBody() && "Not a single-expression body");
685685
auto braceStmt = getBody();
686686
assert(braceStmt != nullptr && "No body currently available.");
687-
auto body = getBody()->getFirstElement();
687+
auto body = getBody()->getElements().back();
688688
if (auto *stmt = body.dyn_cast<Stmt *>()) {
689689
if (auto *returnStmt = dyn_cast<ReturnStmt>(stmt)) {
690690
return returnStmt->getResult();
@@ -701,7 +701,7 @@ Expr *AbstractFunctionDecl::getSingleExpressionBody() const {
701701

702702
void AbstractFunctionDecl::setSingleExpressionBody(Expr *NewBody) {
703703
assert(hasSingleExpressionBody() && "Not a single-expression body");
704-
auto body = getBody()->getFirstElement();
704+
auto body = getBody()->getElements().back();
705705
if (auto *stmt = body.dyn_cast<Stmt *>()) {
706706
if (auto *returnStmt = dyn_cast<ReturnStmt>(stmt)) {
707707
returnStmt->setResult(NewBody);
@@ -717,7 +717,7 @@ void AbstractFunctionDecl::setSingleExpressionBody(Expr *NewBody) {
717717
return;
718718
}
719719
}
720-
getBody()->setFirstElement(NewBody);
720+
getBody()->getElements().back() = NewBody;
721721
}
722722

723723
bool AbstractStorageDecl::isTransparent() const {

lib/AST/Expr.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1974,10 +1974,10 @@ FORWARD_SOURCE_LOCS_TO(ClosureExpr, Body.getPointer())
19741974

19751975
Expr *ClosureExpr::getSingleExpressionBody() const {
19761976
assert(hasSingleExpressionBody() && "Not a single-expression body");
1977-
auto body = getBody()->getFirstElement();
1977+
auto body = getBody()->getElements().back();
19781978
if (auto stmt = body.dyn_cast<Stmt *>()) {
19791979
if (auto braceStmt = dyn_cast<BraceStmt>(stmt))
1980-
return braceStmt->getFirstElement().get<Expr *>();
1980+
return braceStmt->getElements().back().get<Expr *>();
19811981

19821982
return cast<ReturnStmt>(stmt)->getResult();
19831983
}
@@ -2003,7 +2003,7 @@ void AutoClosureExpr::setBody(Expr *E) {
20032003
}
20042004

20052005
Expr *AutoClosureExpr::getSingleExpressionBody() const {
2006-
return cast<ReturnStmt>(Body->getFirstElement().get<Stmt *>())->getResult();
2006+
return cast<ReturnStmt>(Body->getElements().back().get<Stmt *>())->getResult();
20072007
}
20082008

20092009
Expr *AutoClosureExpr::getUnwrappedCurryThunkExpr() const {

lib/IDE/CodeCompletion.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6101,13 +6101,13 @@ bool CodeCompletionCallbacksImpl::trySolverCompletion(bool MaybeFuncBody) {
61016101
// to work via TypeCheckCompletionCallback.
61026102
static void undoSingleExpressionReturn(DeclContext *DC) {
61036103
auto updateBody = [](BraceStmt *BS, ASTContext &Ctx) -> bool {
6104-
ASTNode FirstElem = BS->getFirstElement();
6105-
auto *RS = dyn_cast_or_null<ReturnStmt>(FirstElem.dyn_cast<Stmt*>());
6104+
ASTNode LastElem = BS->getLastElement();
6105+
auto *RS = dyn_cast_or_null<ReturnStmt>(LastElem.dyn_cast<Stmt*>());
61066106

61076107
if (!RS || !RS->isImplicit())
61086108
return false;
61096109

6110-
BS->setFirstElement(RS->getResult());
6110+
BS->getElements().back() = RS->getResult();
61116111
return true;
61126112
};
61136113

lib/IDE/ExprContextAnalysis.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1112,7 +1112,15 @@ class ExprContextAnalyzer {
11121112
/// in order to avoid a base expression affecting the type. However, now that
11131113
/// we've typechecked, we will take the context type into account.
11141114
static bool isSingleExpressionBodyForCodeCompletion(BraceStmt *body) {
1115-
return body->getNumElements() == 1 && body->getFirstElement().is<Expr *>();
1115+
if (body->getNumElements() == 2) {
1116+
if (auto *D = body->getFirstElement().dyn_cast<Decl *>()) {
1117+
if (auto *ICD = dyn_cast<IfConfigDecl>(D)) {
1118+
auto ACE = ICD->getActiveClauseElements();
1119+
return ACE.size() == 1;
1120+
}
1121+
}
1122+
}
1123+
return body->getNumElements() == 1 && body->getElements().back().is<Expr *>();
11161124
}
11171125

11181126
public:

lib/Parse/ParseDecl.cpp

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6656,13 +6656,41 @@ BraceStmt *Parser::parseAbstractFunctionBodyImpl(AbstractFunctionDecl *AFD) {
66566656

66576657
BraceStmt *BS = Body.get();
66586658
AFD->setBodyParsed(BS);
6659+
6660+
if (BS->getNumElements() == 0)
6661+
return BS;
6662+
6663+
auto Element = BS->getFirstElement();
6664+
6665+
// If the body consists of an #if declaration with a single
6666+
// expression active clause, turn it into a return statement.
6667+
bool ReturnsLastElement = false;
6668+
if (BS->getNumElements() == 2) {
6669+
if (auto *D = Element.dyn_cast<Decl *>()) {
6670+
// Step into nested active clause.
6671+
while (auto *ICD = dyn_cast<IfConfigDecl>(D)) {
6672+
auto ACE = ICD->getActiveClauseElements();
6673+
if (ACE.size() == 1) {
6674+
Element = BS->getLastElement();
6675+
ReturnsLastElement = true;
6676+
break;
6677+
} else if (ACE.size() == 2) {
6678+
if (auto *ND = ACE.front().dyn_cast<Decl *>()) {
6679+
D = ND;
6680+
continue;
6681+
}
6682+
}
6683+
break;
6684+
}
6685+
}
6686+
}
66596687

66606688
// If the body consists of a single expression, turn it into a return
66616689
// statement.
6662-
if (BS->getNumElements() != 1)
6690+
if (BS->getNumElements() != 1 &&
6691+
!ReturnsLastElement)
66636692
return BS;
66646693

6665-
auto Element = BS->getFirstElement();
66666694
if (auto *stmt = Element.dyn_cast<Stmt *>()) {
66676695
if (isa<FuncDecl>(AFD)) {
66686696
if (auto *returnStmt = dyn_cast<ReturnStmt>(stmt)) {
@@ -6687,15 +6715,15 @@ BraceStmt *Parser::parseAbstractFunctionBodyImpl(AbstractFunctionDecl *AFD) {
66876715
}
66886716
if (isa<FuncDecl>(AFD)) {
66896717
auto RS = new (Context) ReturnStmt(SourceLoc(), E);
6690-
BS->setFirstElement(RS);
6718+
BS->getElements().back() = RS;
66916719
AFD->setHasSingleExpressionBody();
66926720
AFD->setSingleExpressionBody(E);
66936721
} else if (auto *F = dyn_cast<ConstructorDecl>(AFD)) {
66946722
if (F->isFailable() && isa<NilLiteralExpr>(E)) {
66956723
// If it's a nil literal, just insert return. This is the only
66966724
// legal thing to return.
66976725
auto RS = new (Context) ReturnStmt(E->getStartLoc(), E);
6698-
BS->setFirstElement(RS);
6726+
BS->getElements().back() = RS;
66996727
AFD->setHasSingleExpressionBody();
67006728
AFD->setSingleExpressionBody(E);
67016729
}

lib/Sema/TypeCheckStmt.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1926,7 +1926,7 @@ bool TypeCheckASTNodeAtLocRequest::evaluate(Evaluator &evaluator,
19261926
func->getResultInterfaceType()->isVoid()) {
19271927
// The function returns void. We don't need an explicit return, no matter
19281928
// what the type of the expression is. Take the inserted return back out.
1929-
func->getBody()->setFirstElement(func->getSingleExpressionBody());
1929+
func->getBody()->getElements().back() = func->getSingleExpressionBody();
19301930
}
19311931
}
19321932

@@ -1991,7 +1991,7 @@ TypeCheckFunctionBodyRequest::evaluate(Evaluator &evaluator,
19911991
func->getResultInterfaceType()->isVoid()) {
19921992
// The function returns void. We don't need an explicit return, no matter
19931993
// what the type of the expression is. Take the inserted return back out.
1994-
body->setFirstElement(func->getSingleExpressionBody());
1994+
body->getElements().back() = func->getSingleExpressionBody();
19951995
}
19961996
} else if (isa<ConstructorDecl>(AFD) &&
19971997
(body->empty() ||
@@ -2025,12 +2025,12 @@ TypeCheckFunctionBodyRequest::evaluate(Evaluator &evaluator,
20252025
// that we have eagerly converted something like `{ fatalError() }`
20262026
// into `{ return fatalError() }` that has to be corrected here.
20272027
if (isa<FuncDecl>(AFD) && cast<FuncDecl>(AFD)->hasSingleExpressionBody()) {
2028-
if (auto *stmt = body->getFirstElement().dyn_cast<Stmt *>()) {
2028+
if (auto *stmt = body->getElements().back().dyn_cast<Stmt *>()) {
20292029
if (auto *retStmt = dyn_cast<ReturnStmt>(stmt)) {
20302030
if (retStmt->isImplicit() && retStmt->hasResult()) {
20312031
auto returnType = retStmt->getResult()->getType();
20322032
if (returnType && returnType->isUninhabited())
2033-
body->setFirstElement(retStmt->getResult());
2033+
body->getElements().back() = retStmt->getResult();
20342034
}
20352035
}
20362036
}

test/FixCode/fixits-omit-return.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,16 @@ let cl_fixit_addreturn: () -> String = {
1010
"foo" // expected-warning {{string literal is unused}} expected-error {{missing return in a closure expected to return 'String'; did you mean to return the last expression?}} {{5-5=return }}
1111
}
1212

13+
func ff_fixit_addreturn_ifdecl() -> String {
14+
#if true
15+
print("entering ff_fixit_addreturn()")
16+
"foo" // expected-warning {{string literal is unused}} expected-error {{missing return in a function expected to return 'String'; did you mean to return the last expression?}} {{5-5=return }}
17+
#endif
18+
}
1319

20+
let cl_fixit_addreturn_ifdecl: () -> String = {
21+
#if true
22+
print("entering cl_fixit_addreturn()")
23+
"foo" // expected-warning {{string literal is unused}} expected-error {{missing return in a closure expected to return 'String'; did you mean to return the last expression?}} {{5-5=return }}
24+
#endif
25+
}

test/Parse/omit_return_fail.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,15 @@ func badIs<T>(_ value: Any, anInstanceOf type: T.Type) -> Bool {
77
func foo() -> Int {
88
return // expected-error {{non-void function should return a value}}
99
}
10+
11+
func badIs_ifdecl<T>(_ value: Any, anInstanceOf type: T.Type) -> Bool {
12+
#if true
13+
value is type // expected-error {{cannot find type 'type' in scope}}
14+
#endif
15+
}
16+
17+
func foo_ifdecl() -> Int {
18+
#if true
19+
return // expected-error {{non-void function should return a value}}
20+
#endif
21+
}

0 commit comments

Comments
 (0)