Skip to content

Commit acb3517

Browse files
Diagnose missing expr in non-void single-expr func. [52025782] (#25936)
After SE-0255, compiling ``` func foo() -> Int { return } ``` would result in a diagnostic without source location: ``` <unknown>:0: error: cannot convert return expression of type '()' to ``` Now, it results in ``` filename.swift:8:5: error: non-void function should return a value return ^ ``` as it did prior to SE-0255. To achieve that, during type checking for statements, when the StmtChecker visits return statements, check whether we are within a non-void-returning, single-expression function and that that single expression is an implicit empty tuple. (An empty implicit tuple is added as the result of a resultless return statement that appears as the only element in a single-expression function.) To facilitate that, `hasSingleExpressionBody` and `getSingleExpressionBody` was added to `AnyFunctionRef` and added `getSingleExpressionBody` to `AbstractClosureExpr` (which already had `hasSingleExpressionBody`). rdar://problem/52025782
1 parent 0b6a0ce commit acb3517

File tree

5 files changed

+54
-0
lines changed

5 files changed

+54
-0
lines changed

include/swift/AST/AnyFunctionRef.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,18 @@ class AnyFunctionRef {
7676
return !TheFunction.get<AbstractClosureExpr *>()->getType().isNull();
7777
}
7878

79+
bool hasSingleExpressionBody() const {
80+
if (auto *AFD = TheFunction.dyn_cast<AbstractFunctionDecl *>())
81+
return AFD->hasSingleExpressionBody();
82+
return TheFunction.get<AbstractClosureExpr *>()->hasSingleExpressionBody();
83+
}
84+
85+
Expr *getSingleExpressionBody() const {
86+
if (auto *AFD = TheFunction.dyn_cast<AbstractFunctionDecl *>())
87+
return AFD->getSingleExpressionBody();
88+
return TheFunction.get<AbstractClosureExpr *>()->getSingleExpressionBody();
89+
}
90+
7991
Type getType() const {
8092
if (auto *AFD = TheFunction.dyn_cast<AbstractFunctionDecl *>())
8193
return AFD->getInterfaceType();

include/swift/AST/Expr.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3606,6 +3606,12 @@ class AbstractClosureExpr : public DeclContext, public Expr {
36063606
/// Whether this closure consists of a single expression.
36073607
bool hasSingleExpressionBody() const;
36083608

3609+
/// Retrieve the body for closure that has a single expression for
3610+
/// its body.
3611+
///
3612+
/// Only valid when \c hasSingleExpressionBody() is true.
3613+
Expr *getSingleExpressionBody() const;
3614+
36093615
static bool classof(const Expr *E) {
36103616
return E->getKind() >= ExprKind::First_AbstractClosureExpr &&
36113617
E->getKind() <= ExprKind::Last_AbstractClosureExpr;

lib/AST/Expr.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1906,6 +1906,15 @@ bool AbstractClosureExpr::hasSingleExpressionBody() const {
19061906
return true;
19071907
}
19081908

1909+
Expr *AbstractClosureExpr::getSingleExpressionBody() const {
1910+
if (auto closure = dyn_cast<ClosureExpr>(this))
1911+
return closure->getSingleExpressionBody();
1912+
else if (auto autoclosure = dyn_cast<AutoClosureExpr>(this))
1913+
return autoclosure->getSingleExpressionBody();
1914+
1915+
return nullptr;
1916+
}
1917+
19091918
#define FORWARD_SOURCE_LOCS_TO(CLASS, NODE) \
19101919
SourceRange CLASS::getSourceRange() const { \
19111920
return (NODE)->getSourceRange(); \

lib/Sema/TypeCheckStmt.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,29 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
455455
return RS;
456456
}
457457

458+
// If the body consisted of a single return without a result
459+
//
460+
// func foo() -> Int {
461+
// return
462+
// }
463+
//
464+
// in parseAbstractFunctionBody the return is given an empty, implicit tuple
465+
// as its result
466+
//
467+
// func foo() -> Int {
468+
// return ()
469+
// }
470+
//
471+
// Look for that case and diagnose it as missing return expression.
472+
if (!ResultTy->isVoid() && TheFunc->hasSingleExpressionBody()) {
473+
auto expr = TheFunc->getSingleExpressionBody();
474+
if (expr->isImplicit() && isa<TupleExpr>(expr) &&
475+
cast<TupleExpr>(expr)->getNumElements() == 0) {
476+
TC.diagnose(RS->getReturnLoc(), diag::return_expr_missing);
477+
return RS;
478+
}
479+
}
480+
458481
Expr *E = RS->getResult();
459482

460483
// In an initializer, the only expression allowed is "nil", which indicates

test/Parse/omit_return_fail.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,7 @@
33
func badIs<T>(_ value: Any, anInstanceOf type: T.Type) -> Bool {
44
value is type // expected-error {{use of undeclared type 'type'}}
55
}
6+
7+
func foo() -> Int {
8+
return // expected-error {{non-void function should return a value}}
9+
}

0 commit comments

Comments
 (0)