Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type-checking a pattern match that panics

Tags:

rust

I'm trying to understand what Rust's rules are around ! and type-checking.

This function does type-check:

fn works<E>(r: Result<i32, E>) -> i32 {
    match r {
        Ok(v) => v,
        Err(_) => {
            panic!("bad");
        }
    }
}

Whereas this one does not:

fn fails<E>(r: Result<i32, E>) -> i32 {
    match r {
        Ok(v) => v,
        Err(_) => {
            panic!("bad");
            ()
        }
    }
}

This seems independent of whether I opt into the unstable ! feature actually. With fails, I get a warning about unreachable code and an error (E0308) about the Err arm returning a () instead of a i32.

Why the distinction? I was under the impression that there's really no difference between { E; } and { E; () } - the former has no final operand, so is implicitly (), whereas the latter has a final operand, so is... explicitly (). But in this case, something about the presence of panic! causes the ; there to not have effect.

Does { panic!("bad"); } actually somehow have type ! or is there some other way the compiler is simply suppressing the error?

like image 286
Barry Avatar asked Aug 05 '26 20:08

Barry


1 Answers

I don't think this is documented somewhere, and I don't know if it is intentional - you can try reporting a bug.

This difference stems from the fact that when there is a tail expression in the block, the compiler firstly expects it to matches the expected return type and emits an error if it does not. Only then it checks if the block diverges (has an expression that returns !) and allow any type if it does, but the error was already emitted.

Here the compiler checks the type of the tail expression, and here it allows any type if the block diverges.

This is somewhat documented in rustc's source code:

// Subtle: if there is no explicit tail expression,
// that is typically equivalent to a tail expression
// of `()` -- except if the block diverges. In that
// case, there is no value supplied from the tail
// expression (assuming there are no other breaks,
// this implies that the type of the block will be
// `!`).
like image 101
Chayim Friedman Avatar answered Aug 08 '26 13:08

Chayim Friedman



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!