rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
98.15k stars 12.69k forks source link

Error output regression: spurious integer inference error that only occurs if another error occurs #93450

Closed chris-morgan closed 2 years ago

chris-morgan commented 2 years ago

I was just going through my FizzBuzz article as I do every year or so to update compiler error messages and make any related changes necessary, and came across a regression in error output for Figure 3.

Given the following code:

fn main() {
for i in 1..101 {
    let result = if i % 15 == 0 {
        "FizzBuzz"
    } else if i % 5 == 0 {
        "Buzz"
    } else if i % 3 == 0 {
        "Fizz"
    } else {
        i.to_string()
    };
    println!("{}", result);
}
}

This is the output in 1.57.0 (and it’s been just the one error that we now call E0308 right from the outset):

$ rustc +1.57.0 x.rs
error[E0308]: `if` and `else` have incompatible types
  --> x.rs:10:9
   |
7  |       } else if i % 3 == 0 {
   |  ____________-
8  | |         "Fizz"
   | |         ------ expected because of this
9  | |     } else {
10 | |         i.to_string()
   | |         ^^^^^^^^^^^^^ expected `&str`, found struct `String`
11 | |     };
   | |_____- `if` and `else` have incompatible types

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.

But the output in 1.58.0 and in currently nightly adds another error, E0283:

$ rustc +1.58.0 x.rs
error[E0308]: `if` and `else` have incompatible types
  --> x.rs:10:9
   |
7  |       } else if i % 3 == 0 {
   |  ____________-
8  | |         "Fizz"
   | |         ------ expected because of this
9  | |     } else {
10 | |         i.to_string()
   | |         ^^^^^^^^^^^^^ expected `&str`, found struct `String`
11 | |     };
   | |_____- `if` and `else` have incompatible types

error[E0283]: type annotations needed for `{integer}`
  --> x.rs:10:11
   |
2  | for i in 1..101 {
   |          ------ the element type for this iterator is not specified
...
10 |         i.to_string()
   |           ^^^^^^^^^ cannot infer type for type `{integer}`
   |
   = note: multiple `impl`s satisfying `{integer}: ToString` found in the `alloc` crate:
           - impl ToString for i8;
           - impl ToString for u8;

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0283, E0308.
For more information about an error, try `rustc --explain E0283`.

The integer type inference error is spurious, because if you resolve the if/else type mismatch (e.g. tack on .to_string() on the other branches), it also vanishes (resolved to the default of i32, I presume).

SNCPlay42 commented 2 years ago

searched nightlies: from nightly-2021-10-17 to nightly-2021-11-28 regressed nightly: nightly-2021-10-26 searched commit range: https://github.com/rust-lang/rust/compare/00d5e42e776da900049fe19087bc9b0057ec70cd...29b1248025b19bd132c8047fc710ea9314b9b76b regressed commit: https://github.com/rust-lang/rust/commit/41d8c94d454f23239715a6433df79e46df8bce04

bisected with cargo-bisect-rustc v0.6.1 Host triple: x86_64-unknown-linux-gnu Reproduce with: ```bash cargo bisect-rustc --preserve --start=2021-10-17 --end=2021-11-28 --script=./test.sh --regress=success ```

Bisection points to #89427. There were some changes to when the compiler avoids emitting an ambiguity error when there are previous errors, but I'm not sure what the intent was. The appearance of ambiguity errors similar to this one was noted in PR review.

@rustbot label regression-from-stable-to-stable

compiler-errors commented 2 years ago

@rustbot claim

camelid commented 2 years ago

cc @estebank

shoffmeister commented 2 years ago

FWIW, using 1.58.1 I accidentally ran into the same regression (undesirable / surplus E0283) with the following defective code:

trait SomeInteger         { fn bleep(&self);   }
impl  SomeInteger for i8  { fn bleep(&self) {} }
impl  SomeInteger for i32 { fn bleep(&self) {} }

fn bleep_it(a: Box<dyn SomeInteger>) {
    a.bleep();
}

fn main() {
    let number_of_yaks = 3;

    bleep_it(Box::new(number_of_yaks));
    print!("we have run out of {yaks} to shave");
}
apiraino commented 2 years ago

Assigning priority as discussed in the Zulip thread of the Prioritization Working Group.

@rustbot label -I-prioritize +P-medium

estebank commented 2 years ago

@compiler-errors I'm pretty sure this is caused by this removal:

https://github.com/rust-lang/rust/pull/89427/files#diff-8406bbc0d0b43d84c91b1933305df896ecdba0d1f9269e6744f13d87a2ab268aL1552-L1556

I would rather us not add it in the same place because IIRC I moved it (duplicated) deeper into the logic because otherwise with my other changes we had regressions.