rust-lang / rust-analyzer

A Rust compiler front-end for IDEs
https://rust-analyzer.github.io/
Apache License 2.0
14.16k stars 1.58k forks source link

r-a does not implement never type fallback #16186

Open WaffleLapkin opened 9 months ago

WaffleLapkin commented 9 months ago

rust-analyzer version: 0.3.1774-standalone rustc version: rustc 1.76.0-nightly (503e12932 2023-12-07) (but irrelevant)

fn main() {
    let x /* : ! */ = if false { todo!() } else { <_>::default() };

    dbg!(type_name_of_val(&x));
}

pub fn type_name_of_val<T: ?Sized>(_val: &T) -> &'static str {
    core::any::type_name::<T>()
}

The comment here represents inlay hint produced by rust analyzer. It is however wrong. The code both compiles and outputs the following:

[src/main.rs:4] type_name_of_val(&x) = "()"

The reason why x is () and not ! is due to the infamous "never type fallback logic" in rustc, which states that if you are coercing ! and inference does not suggest a type, then you default to () (this is indeed the problem with stabilizing never — we want this fallback gone, but it can break code (as in this example (without the fallback default does not type check))) (don't quote me on this, I'm not an expert (there is some docs on the rustc function that deals with falling back)).

WaffleLapkin commented 9 months ago

Another example could be core::convert::identity(todo!() /* r-a does *not* show ! -> () coercion here, even though I believe it should be here */);

ShoyuVanilla commented 8 months ago

Related: #15916

ShoyuVanilla commented 7 months ago

I've tried this for a while, but it's not simple to implement one for RA, mostly because it doesn't have something like CoercePredicate, which is needed for making something like diverging coercion graph 🤔 Maybe we should record some relations whenever we try to coerce an inference var into an inference var like rustc does

Veykril commented 7 months ago

Probably better to wait for the trait solver switch here (and maybe by then rustc has finally switched the fallback behavior)