Consider the following Rust code:
fn f() -> i32 {
loop {
println!("Infinite loop!");
}
println!("Unreachable");
}
This compiles (with a warning) and runs, despite the fact that the return type is wrong.
It would seem that the compiler is OK with the return type of ()
in the last line because it detects that this code is unreachable.
However, if we remove the last semicolon:
fn f() -> i32 {
loop {
println!("Infinite loop!");
}
println!("Unreachable")
}
Then the code no longer compiles, giving a type error:
error[E0308]: mismatched types
--> src/main.rs:14:5
|
14 | println!("Unreachable")
| ^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `()`
|
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
Why is this? Isn't the return type the same, ()
, in both of these code snipets?
Note: I'm interested in understanding why the Rust compiler behaves differently on these two examples, i.e. how the Rust compiler is implemented. I did not mean to ask a philosophical question about how it "should" behave, from the perspective of language design (I understand that such a question would probably be off-topic).
The return type in the first code block is actually !
(called never) because you have a loop that never exits (so rust gives you a warning saying it's unreachable). The full type would be:
fn f() -> !
I suspect !
is more like the 'bottom' type in Rust than anything else. In the second case, your function likely errors out in an earlier stage during type checking because of the mismatch between i32 and () before the compiler gets to the 'unreachability' analysis, like it does in the first example.
edit: as suggested, here is the relevant part of the rust book https://doc.rust-lang.org/book/ch19-04-advanced-types.html#the-never-type-that-never-returns
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With