1
Fork 0

Rollup merge of #135558 - estebank:issue-133316, r=chenyukang

Detect if-else chains with a missing final else in type errors

```
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.
This commit is contained in:
Matthias Krüger 2025-01-17 09:11:18 +01:00 committed by GitHub
commit c43893005e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 50 additions and 0 deletions

View file

@ -620,6 +620,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
}) => { }) => {
let then_span = self.find_block_span_from_hir_id(then_id); let then_span = self.find_block_span_from_hir_id(then_id);
let else_span = self.find_block_span_from_hir_id(else_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"); err.span_label(then_span, "expected because of this");
if let Some(sp) = outer_span { if let Some(sp) = outer_span {
err.span_label(sp, "`if` and `else` have incompatible types"); err.span_label(sp, "`if` and `else` have incompatible types");

View file

@ -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)
}

View file

@ -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`.