Skip to content

Commit 86466a3

Browse files
committed
Auto merge of #58981 - estebank:elseless-if, r=davidtwco
Point at coercion reason for `if` expressions without else clause if caused by return type ``` error[E0317]: if may be missing an else clause --> $DIR/if-without-else-as-fn-expr.rs:2:5 | LL | fn foo(bar: usize) -> usize { | ----- found `usize` because of this return type LL | / if bar % 5 == 0 { LL | | return 3; LL | | } | |_____^ expected (), found usize | = note: expected type `()` found type `usize` = note: `if` expressions without `else` must evaluate to `()` ``` Fix #25228.
2 parents 94fd045 + dcaec88 commit 86466a3

File tree

6 files changed

+135
-3
lines changed

6 files changed

+135
-3
lines changed

src/librustc_typeck/check/mod.rs

+46-1
Original file line numberDiff line numberDiff line change
@@ -3463,8 +3463,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
34633463
// We won't diverge unless both branches do (or the condition does).
34643464
self.diverges.set(cond_diverges | then_diverges & else_diverges);
34653465
} else {
3466+
// If this `if` expr is the parent's function return expr, the cause of the type
3467+
// coercion is the return type, point at it. (#25228)
3468+
let ret_reason = self.maybe_get_coercion_reason(then_expr.hir_id, sp);
3469+
34663470
let else_cause = self.cause(sp, ObligationCauseCode::IfExpressionWithNoElse);
3467-
coerce.coerce_forced_unit(self, &else_cause, &mut |_| (), true);
3471+
coerce.coerce_forced_unit(self, &else_cause, &mut |err| {
3472+
if let Some((sp, msg)) = &ret_reason {
3473+
err.span_label(*sp, msg.as_str());
3474+
} else if let ExprKind::Block(block, _) = &then_expr.node {
3475+
if let Some(expr) = &block.expr {
3476+
err.span_label(expr.span, "found here".to_string());
3477+
}
3478+
}
3479+
err.note("`if` expressions without `else` evaluate to `()`");
3480+
err.help("consider adding an `else` block that evaluates to the expected type");
3481+
}, ret_reason.is_none());
34683482

34693483
// If the condition is false we can't diverge.
34703484
self.diverges.set(cond_diverges);
@@ -3478,6 +3492,37 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
34783492
}
34793493
}
34803494

3495+
fn maybe_get_coercion_reason(&self, hir_id: hir::HirId, sp: Span) -> Option<(Span, String)> {
3496+
let node = self.tcx.hir().get_by_hir_id(self.tcx.hir().get_parent_node_by_hir_id(
3497+
self.tcx.hir().get_parent_node_by_hir_id(hir_id),
3498+
));
3499+
if let Node::Block(block) = node {
3500+
// check that the body's parent is an fn
3501+
let parent = self.tcx.hir().get_by_hir_id(
3502+
self.tcx.hir().get_parent_node_by_hir_id(
3503+
self.tcx.hir().get_parent_node_by_hir_id(block.hir_id),
3504+
),
3505+
);
3506+
if let (Some(expr), Node::Item(hir::Item {
3507+
node: hir::ItemKind::Fn(..), ..
3508+
})) = (&block.expr, parent) {
3509+
// check that the `if` expr without `else` is the fn body's expr
3510+
if expr.span == sp {
3511+
return self.get_fn_decl(hir_id).map(|(fn_decl, _)| (
3512+
fn_decl.output.span(),
3513+
format!("expected `{}` because of this return type", fn_decl.output),
3514+
));
3515+
}
3516+
}
3517+
}
3518+
if let Node::Local(hir::Local {
3519+
ty: Some(_), pat, ..
3520+
}) = node {
3521+
return Some((pat.span, "expected because of this assignment".to_string()));
3522+
}
3523+
None
3524+
}
3525+
34813526
// Check field access expressions
34823527
fn check_field(&self,
34833528
expr: &'gcx hir::Expr,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
fn foo(bar: usize) -> usize {
2+
if bar % 5 == 0 {
3+
return 3;
4+
}
5+
//~^^^ ERROR if may be missing an else clause
6+
}
7+
8+
fn foo2(bar: usize) -> usize {
9+
let x: usize = if bar % 5 == 0 {
10+
return 3;
11+
};
12+
//~^^^ ERROR if may be missing an else clause
13+
x
14+
}
15+
16+
fn foo3(bar: usize) -> usize {
17+
if bar % 5 == 0 {
18+
3
19+
}
20+
//~^^^ ERROR if may be missing an else clause
21+
}
22+
23+
fn main() {
24+
let _ = foo(1);
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
error[E0317]: if may be missing an else clause
2+
--> $DIR/if-without-else-as-fn-expr.rs:2:5
3+
|
4+
LL | fn foo(bar: usize) -> usize {
5+
| ----- expected `usize` because of this return type
6+
LL | / if bar % 5 == 0 {
7+
LL | | return 3;
8+
LL | | }
9+
| |_____^ expected usize, found ()
10+
|
11+
= note: expected type `usize`
12+
found type `()`
13+
= note: `if` expressions without `else` evaluate to `()`
14+
= help: consider adding an `else` block that evaluates to the expected type
15+
16+
error[E0317]: if may be missing an else clause
17+
--> $DIR/if-without-else-as-fn-expr.rs:9:20
18+
|
19+
LL | let x: usize = if bar % 5 == 0 {
20+
| _________-__________^
21+
| | |
22+
| | expected because of this assignment
23+
LL | | return 3;
24+
LL | | };
25+
| |_____^ expected usize, found ()
26+
|
27+
= note: expected type `usize`
28+
found type `()`
29+
= note: `if` expressions without `else` evaluate to `()`
30+
= help: consider adding an `else` block that evaluates to the expected type
31+
32+
error[E0317]: if may be missing an else clause
33+
--> $DIR/if-without-else-as-fn-expr.rs:17:5
34+
|
35+
LL | fn foo3(bar: usize) -> usize {
36+
| ----- expected `usize` because of this return type
37+
LL | / if bar % 5 == 0 {
38+
LL | | 3
39+
LL | | }
40+
| |_____^ expected usize, found ()
41+
|
42+
= note: expected type `usize`
43+
found type `()`
44+
= note: `if` expressions without `else` evaluate to `()`
45+
= help: consider adding an `else` block that evaluates to the expected type
46+
47+
error: aborting due to 3 previous errors
48+
49+
For more information about this error, try `rustc --explain E0317`.

src/test/ui/if/if-without-else-result.stderr

+6-1
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,15 @@ error[E0317]: if may be missing an else clause
22
--> $DIR/if-without-else-result.rs:2:13
33
|
44
LL | let a = if true { true };
5-
| ^^^^^^^^^^^^^^^^ expected (), found bool
5+
| ^^^^^^^^^^----^^
6+
| | |
7+
| | found here
8+
| expected (), found bool
69
|
710
= note: expected type `()`
811
found type `bool`
12+
= note: `if` expressions without `else` evaluate to `()`
13+
= help: consider adding an `else` block that evaluates to the expected type
914

1015
error: aborting due to previous error
1116

src/test/ui/issues/issue-4201.stderr

+3
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@ LL | |
88
LL | |
99
LL | |
1010
LL | | 1
11+
| | - found here
1112
LL | | };
1213
| |_____^ expected (), found integer
1314
|
1415
= note: expected type `()`
1516
found type `{integer}`
17+
= note: `if` expressions without `else` evaluate to `()`
18+
= help: consider adding an `else` block that evaluates to the expected type
1619

1720
error: aborting due to previous error
1821

src/test/ui/issues/issue-50577.stderr

+6-1
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,15 @@ error[E0317]: if may be missing an else clause
22
--> $DIR/issue-50577.rs:3:16
33
|
44
LL | Drop = assert_eq!(1, 1)
5-
| ^^^^^^^^^^^^^^^^ expected (), found isize
5+
| ^^^^^^^^^^^^^^^^
6+
| |
7+
| expected (), found isize
8+
| found here
69
|
710
= note: expected type `()`
811
found type `isize`
12+
= note: `if` expressions without `else` evaluate to `()`
13+
= help: consider adding an `else` block that evaluates to the expected type
914
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
1015

1116
error: aborting due to previous error

0 commit comments

Comments
 (0)