Skip to content

Commit

Permalink
Detect if-else chains with a missing final else in type errors
Browse files Browse the repository at this point in the history
```
error[E0308]: `if` and `else` have incompatible types
  --> $DIR/if-else-chain-missing-else.rs:12:12
   |
LL |        let x = if let Ok(x) = res {
   |  ______________-
LL | |          x
   | |          - expected because of this
LL | |      } else if let Err(e) = res {
   | | ____________^
LL | ||         return Err(e);
LL | ||     };
   | ||     ^
   | ||_____|
   |  |_____`if` and `else` have incompatible types
   |        expected `i32`, found `()`
   |
   = note: `if` expressions without `else` evaluate to `()`
   = note: consider adding an `else` block that evaluates to the expected type
```

We probably want a longer explanation and fewer spans on this case.

Partially address #133316.
  • Loading branch information
estebank committed Jan 16, 2025
1 parent 27f3361 commit f78a1bd
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
}) => {
let then_span = self.find_block_span_from_hir_id(then_id);
let else_span = self.find_block_span_from_hir_id(else_id);
if let hir::Node::Expr(e) = self.tcx.hir_node(else_id)
&& let hir::ExprKind::If(_cond, _then, None) = e.kind
&& else_ty.is_unit()
{
// Account for `let x = if a { 1 } else if b { 2 };`
err.note("`if` expressions without `else` evaluate to `()`");
err.note("consider adding an `else` block that evaluates to the expected type");
}
err.span_label(then_span, "expected because of this");
if let Some(sp) = outer_span {
err.span_label(sp, "`if` and `else` have incompatible types");
Expand Down
20 changes: 20 additions & 0 deletions tests/ui/expr/if/if-else-chain-missing-else.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
enum Cause { Cause1, Cause2 }
struct MyErr { x: Cause }

fn main() {
_ = f();
}

fn f() -> Result<i32, MyErr> {
let res = could_fail();
let x = if let Ok(x) = res {
x
} else if let Err(e) = res { //~ ERROR `if` and `else`
return Err(e);
};
Ok(x)
}

fn could_fail() -> Result<i32, MyErr> {
Ok(0)
}
22 changes: 22 additions & 0 deletions tests/ui/expr/if/if-else-chain-missing-else.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
error[E0308]: `if` and `else` have incompatible types
--> $DIR/if-else-chain-missing-else.rs:12:12
|
LL | let x = if let Ok(x) = res {
| ______________-
LL | | x
| | - expected because of this
LL | | } else if let Err(e) = res {
| | ____________^
LL | || return Err(e);
LL | || };
| || ^
| ||_____|
| |_____`if` and `else` have incompatible types
| expected `i32`, found `()`
|
= note: `if` expressions without `else` evaluate to `()`
= note: consider adding an `else` block that evaluates to the expected type

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0308`.

0 comments on commit f78a1bd

Please sign in to comment.