Skip to content

if and else have incompatible types in a let statement, where else block's evaluation will never be assigned #133316

Open
@shanebishop

Description

@shanebishop

I apologize if this was already reported in a separate issue, or if this is a known issue - I wasn't sure how to best search for previous issues like this.

I also realize this might not be a "bug" per se, but the other issue templates didn't seem to quite fit either.

I tried this code:

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 {
        cleanup();
        return Err(e);
    };
    Ok(x)
}

fn could_fail() -> Result<i32, MyErr> {
    // ... code that could fail and return an Err ...
    Ok(0)
}

fn cleanup() {
    // ... cleanup code ...
}

Playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=60acf4e59e3c6403104e01aa409aa395

I expected the code to compile successfully, since the else if branch unconditionally returns. Because the else if branch always returns, x will always be an i32.

Instead, I get this compiler error:

error[E0308]: `if` and `else` have incompatible types
  --> src/main.rs:12:12
   |
10 |        let x = if let Ok(x) = res {
   |  ______________-
11 | |          x
   | |          - expected because of this
12 | |      } else if let Err(e) = res {
   | | ____________^
13 | ||         cleanup();
14 | ||         return Err(e);
15 | ||     };
   | ||     ^
   | ||_____|
   |  |_____`if` and `else` have incompatible types
   |        expected `i32`, found `()`

Meta

rustc --version --verbose:

rustc 1.82.0 (f6e511eec 2024-10-15)
binary: rustc
commit-hash: f6e511eec7342f59a25f7c0534f1dbea00d01b14
commit-date: 2024-10-15
host: x86_64-unknown-linux-gnu
release: 1.82.0
LLVM version: 19.1.1

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-control-flowArea: Control flowA-diagnosticsArea: Messages for errors, warnings, and lintsD-confusingDiagnostics: Confusing error or lint that should be reworked.D-terseDiagnostics: An error or lint that doesn't give enough information about the problem at hand.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions