Why does the compiler infer the type here to be the unit type?

Something's definitely wrong here. Even this compiles!

fn parse<T: Default>() -> Option<T> {
    Some(T::default())
}

fn main() {
    let msg = match parse() {
        Some(ok) => ok,
        None => return,
    };
    println!("{:?}", msg);
}

This still compiles with msg: i32, so I have no idea why it thinks that msg should be inferred as (). If I use println!("{}", msg); then it complains about () not implementing Display.

An even further simplified example also compiles:

fn parse()<T>() -> Option<T> {
    println!("type used: {}", std::any::type_name::<T>());
    None
}

fn main() {
    let _v = match parse() {
        Some(v) => v,
        None => return,
    };
}

If I remove the match statement, it stops working. This can work with _v being any type, and we can observe that it chooses ().

Maybe this has something to do with how return expressions have their type inferred?

If you enable #![feature(never_type)], then it will infer that type instead (and complain about ! not implementing the traits required, if any):

#![feature(never_type)]

fn parse<T: Default>() -> Option<T> {
    Some(T::default())
}

fn main() {
    let _v = match parse() {
        Some(v) => v,
        None => return,
    };
}
error[E0277]: the trait bound `!: std::default::Default` is not satisfied
 --> src/main.rs:7:20
  |
2 | fn parse<T: Default>() -> Option<T> {
  |    -----    ------- required by this bound in `parse`
...
7 |     let _v = match parse() {
  |                    ^^^^^ the trait `std::default::Default` is not implemented for `!`
  |
  = note: the trait is implemented for `()`. Possibly this error has been caused by changes to Rust's type-inference algorithm (see: https://github.com/rust-lang/rust/issues/48950 for more info). Consider whether you meant to use the type `()` here instead.
4 Likes