Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spurious E0282 'type annotations needed' when other compile errors exist #88630

Open
kpreid opened this issue Sep 3, 2021 · 3 comments
Open
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-inference Area: Type inference T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@kpreid
Copy link
Contributor

kpreid commented Sep 3, 2021

Given the following code:

fn troublesome() {
    does_not_exist();
}

fn innocent_bystander() {
    // Approximately what assert_eq! does, inlined for the sake of simplicity
    if "x".as_bytes() != &[] {
        panic!();
    }
}

The current output is:

   Compiling playground v0.0.1 (/playground)
error[E0425]: cannot find function `does_not_exist` in this scope
 --> src/lib.rs:2:5
  |
2 |     does_not_exist();
  |     ^^^^^^^^^^^^^^ not found in this scope

error[E0282]: type annotations needed
 --> src/lib.rs:7:23
  |
7 |     if "x".as_bytes() != &[] {
  |                       ^^ cannot infer type

However, if does_not_exist(); is commented out, not only does its error E0425 disappear, the type inference error E0282 also does. This results in a frustrating situation where, whenever you have an error of the first sort, any ==s or assert_eq!()s elsewhere in your crate that are fragile in this way also flood the error output. This makes it unnecessarily difficult to practice the workflow of “change something in a breaking way, then fix all the now-erroneous call sites”. It could also mislead beginners because the compiler is confidently stating a falsehood.

Ideally, these “type annotations needed” errors would not appear unless the annotations were actually needed. An approximation of this would be to not show them when any other errors appear. An even better approximation, I speculate in ignorance of the compiler internals, would be to not show them if whatever inference pass would have resolved the concrete type is known to have been skipped due to previous errors.

Or, perhaps this code is inherently fraught, and it would be wise for the programmer to actually provide a type annotation. In that case, it would be nice if there was a warning about that when the code compiles successfully.


Tested on rustc 1.54.0 stable, also current nightly.

I previously mentioned this problem in #44345, but got no response there, and I also now think that this situation is significantly different. In particular, no trait implementations are being added, and the error is entirely spurious rather than being a newly-ambiguous trait implementation selection.

@kpreid kpreid added A-diagnostics Area: Messages for errors, warnings, and lints T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Sep 3, 2021
@kpreid
Copy link
Contributor Author

kpreid commented May 11, 2022

I've just learned from https://users.rust-lang.org/t/confusing-type-inference-error-with-json-macro/75522 that this same kind of problem, with the same message “type annotations needed”, can also appear with error code E0283. Mentioning that now for searchability.

See also issues #75331, #68507 for other cases of erroneous “type annotations needed”, though in those cases it isn't action-at-a-distance.

@riking
Copy link

riking commented Nov 7, 2022

At the rustc source level, this is likely related to the use of either span_delay_err or stash_err and friends.

@BoxyUwU
Copy link
Member

BoxyUwU commented May 11, 2023

I spoke to @compiler-errors about this a little bit yesterday and we figured out what is up with this. Unfortunately its not a really cool type system issue :(

First thing is that this doesn't reproduce locally if you just make a new crate. It's important to have serde_json as a dependency. play.rust-lang.org has a tonne of dependencies including serde_json which is why it works on playground (you can see serde json in the error output for the inference error.)

As far as I know you don't get to use any impls from your dependencies if you havent actually used any of the crate's API anywhere.

extern crate serde_json;

fn innocent_bystander() {
    // Approximately what assert_eq! does, inlined for the sake of simplicity
    if "x".as_bytes() != &[] {
        panic!();
    }
}

in 2015 edition will unconditionally fail to compile with the inference error, wheras removing the extern crate and using cargo.toml deps it compiles fine.

What's happening is that for "x".as_bytes() != &[] to typeck we attempt to prove [u8]: PartialEq<[_; 0]>. Without serde json we end up inferring that infer var to be u8 because there is only a single PartialEq impl for u8. Serde json introduces a u8: PartialEq<SomeSerdeJsonType> which stops this from being able to be inferred. The following code gives the same inference error:

impl PartialEq<Foo> for u8 {
    fn eq(&self, other: &Foo) -> bool {
        todo!()
    }
}

struct Foo;

fn innocent_bystander() {
    "x".as_bytes() != &[];
}

fn main() {}

The reason that the does_not_exist affects things in the playground example is because when we get a name res error we seem to fully import all crates which means that typeck sees all of their impls. Without does_not_exist the serde_json impl isnt fully present and so the u8: PartialEq<SomeOtherType> doesnt exist when typeck'ing innocent_bystander so it succeeds. With does_not_exist we get a nameres error and serde_json's impls exist when typeck'ing innocent_bystander so it fails.

The minimal repro for this issue would be the following:

// some library crate `foo`
// lib.rs

impl PartialEq<Foo> for u8 {
    fn eq(&self, other: &Foo) -> bool {
        todo!()
    }
}

pub struct Foo;

// our binary crate with a `Cargo.toml` dep on `foo`
// main.rs

fn evil() {
    does_not_exist(); // comment and uncomment this to trigger the inference error
}

fn innocent_bystander() {
    "x".as_bytes() != &[];
}

fn main() {}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-inference Area: Type inference T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

4 participants