Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 796ce9f

Browse files
committed
Suggest returning tail expressions that match return type
Some newcomers are confused by the behavior of tail expressions, interpreting that "leaving out the `;` makes it the return value". To help them go in the right direction, suggest using `return` instead when applicable.
1 parent 3e826bb commit 796ce9f

File tree

7 files changed

+122
-3
lines changed

7 files changed

+122
-3
lines changed

compiler/rustc_typeck/src/check/coercion.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1458,7 +1458,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
14581458
fcx.get_fn_decl(parent_id)
14591459
};
14601460

1461-
if let (Some((fn_decl, can_suggest)), _) = (fn_decl, pointing_at_return_type) {
1461+
if let Some((fn_decl, can_suggest)) = fn_decl {
14621462
if expression.is_none() {
14631463
pointing_at_return_type |= fcx.suggest_missing_return_type(
14641464
&mut err,
@@ -1472,6 +1472,16 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
14721472
fn_output = Some(&fn_decl.output); // `impl Trait` return type
14731473
}
14741474
}
1475+
1476+
let parent_id = fcx.tcx.hir().get_parent_item(id);
1477+
let parent_item = fcx.tcx.hir().get(parent_id);
1478+
1479+
if let (Some((expr, _)), Some((fn_decl, _, _))) =
1480+
(expression, fcx.get_node_fn_decl(parent_item))
1481+
{
1482+
fcx.suggest_missing_return_expr(&mut err, expr, fn_decl, expected, found);
1483+
}
1484+
14751485
if let (Some(sp), Some(fn_output)) = (fcx.ret_coercion_span.get(), fn_output) {
14761486
self.add_impl_trait_explanation(&mut err, cause, fcx, expected, sp, fn_output);
14771487
}

compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
464464
}
465465
}
466466

467+
pub(in super::super) fn suggest_missing_return_expr(
468+
&self,
469+
err: &mut DiagnosticBuilder<'_>,
470+
expr: &'tcx hir::Expr<'tcx>,
471+
fn_decl: &hir::FnDecl<'_>,
472+
expected: Ty<'tcx>,
473+
found: Ty<'tcx>,
474+
) {
475+
if !expected.is_unit() {
476+
return;
477+
}
478+
let found = self.resolve_vars_with_obligations(found);
479+
if let hir::FnRetTy::Return(ty) = fn_decl.output {
480+
let ty = AstConv::ast_ty_to_ty(self, ty);
481+
let ty = self.normalize_associated_types_in(expr.span, ty);
482+
if self.can_coerce(found, ty) {
483+
err.multipart_suggestion(
484+
"you might have meant to return this value",
485+
vec![
486+
(expr.span.shrink_to_lo(), "return ".to_string()),
487+
(expr.span.shrink_to_hi(), ";".to_string()),
488+
],
489+
Applicability::MaybeIncorrect,
490+
);
491+
}
492+
}
493+
}
494+
467495
pub(in super::super) fn suggest_missing_parentheses(
468496
&self,
469497
err: &mut DiagnosticBuilder<'_>,

src/test/ui/macros/empty-trailing-stmt.stderr

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ error[E0308]: mismatched types
33
|
44
LL | { true }
55
| ^^^^ expected `()`, found `bool`
6+
|
7+
help: you might have meant to return this value
8+
|
9+
LL | { return true; }
10+
| ^^^^^^ ^
611

712
error[E0308]: mismatched types
813
--> $DIR/empty-trailing-stmt.rs:5:13

src/test/ui/parser/expr-as-stmt-2.stderr

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,37 @@ error[E0308]: mismatched types
22
--> $DIR/expr-as-stmt-2.rs:3:26
33
|
44
LL | if let Some(x) = a { true } else { false }
5-
| ---------------------^^^^------------------ help: consider using a semicolon here
5+
| ---------------------^^^^-----------------
66
| | |
77
| | expected `()`, found `bool`
88
| expected this to be `()`
9+
|
10+
help: consider using a semicolon here
11+
|
12+
LL | if let Some(x) = a { true } else { false };
13+
| ^
14+
help: you might have meant to return this value
15+
|
16+
LL | if let Some(x) = a { return true; } else { false }
17+
| ^^^^^^ ^
918

1019
error[E0308]: mismatched types
1120
--> $DIR/expr-as-stmt-2.rs:3:40
1221
|
1322
LL | if let Some(x) = a { true } else { false }
14-
| -----------------------------------^^^^^--- help: consider using a semicolon here
23+
| -----------------------------------^^^^^--
1524
| | |
1625
| | expected `()`, found `bool`
1726
| expected this to be `()`
27+
|
28+
help: consider using a semicolon here
29+
|
30+
LL | if let Some(x) = a { true } else { false };
31+
| ^
32+
help: you might have meant to return this value
33+
|
34+
LL | if let Some(x) = a { true } else { return false; }
35+
| ^^^^^^ ^
1836

1937
error[E0308]: mismatched types
2038
--> $DIR/expr-as-stmt-2.rs:6:5

src/test/ui/parser/expr-as-stmt.stderr

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,24 +40,44 @@ error[E0308]: mismatched types
4040
|
4141
LL | {2} + {2}
4242
| ^ expected `()`, found integer
43+
|
44+
help: you might have meant to return this value
45+
|
46+
LL | {return 2;} + {2}
47+
| ^^^^^^ ^
4348

4449
error[E0308]: mismatched types
4550
--> $DIR/expr-as-stmt.rs:12:6
4651
|
4752
LL | {2} + 2
4853
| ^ expected `()`, found integer
54+
|
55+
help: you might have meant to return this value
56+
|
57+
LL | {return 2;} + 2
58+
| ^^^^^^ ^
4959

5060
error[E0308]: mismatched types
5161
--> $DIR/expr-as-stmt.rs:18:7
5262
|
5363
LL | { 42 } + foo;
5464
| ^^ expected `()`, found integer
65+
|
66+
help: you might have meant to return this value
67+
|
68+
LL | { return 42; } + foo;
69+
| ^^^^^^ ^
5570

5671
error[E0308]: mismatched types
5772
--> $DIR/expr-as-stmt.rs:24:7
5873
|
5974
LL | { 3 } * 3
6075
| ^ expected `()`, found integer
76+
|
77+
help: you might have meant to return this value
78+
|
79+
LL | { return 3; } * 3
80+
| ^^^^^^ ^
6181

6282
error[E0614]: type `{integer}` cannot be dereferenced
6383
--> $DIR/expr-as-stmt.rs:24:11
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
fn main() {
2+
let _ = foo(true);
3+
}
4+
5+
fn foo(x: bool) -> Result<f64, i32> {
6+
if x {
7+
Err(42) //~ ERROR mismatched types
8+
}
9+
Ok(42.0)
10+
}
11+
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/tail-expr-as-potential-return.rs:7:9
3+
|
4+
LL | / if x {
5+
LL | | Err(42)
6+
| | ^^^^^^^ expected `()`, found enum `std::result::Result`
7+
LL | | }
8+
| |_____- expected this to be `()`
9+
|
10+
= note: expected unit type `()`
11+
found enum `std::result::Result<_, {integer}>`
12+
help: try adding a semicolon
13+
|
14+
LL | Err(42);
15+
| ^
16+
help: consider using a semicolon here
17+
|
18+
LL | };
19+
| ^
20+
help: you might have meant to return this value
21+
|
22+
LL | return Err(42);
23+
| ^^^^^^ ^
24+
25+
error: aborting due to previous error
26+
27+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)