Source code errors and subsequent type inference errors - why?

The following code snippet is known broken, but triggers an additional error diagnostic where I do not understand how this can be:

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");
}

My error is on the last line; {yaks} for non-existing yaks will not work - that is something the compiler will rightfully complain about.

But in the presence of that error, the compiler also emits an additional mystifying error message "type annotations needed for type integer":

error[E0425]: cannot find value `yaks` in this scope
  --> src/tracing_error.rs:13:32
   |
13 |     print!("we have run out of {yaks} to shave");
   |                                ^^^^^^ not found in this scope

error[E0283]: type annotations needed for `{integer}`
  --> src/tracing_error.rs:12:14
   |
10 |     let number_of_yaks = 3;
   |         -------------- consider giving `number_of_yaks` a type
11 | 
12 |     bleep_it(Box::new(number_of_yaks));
   |              ^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type `{integer}`
   |
note: multiple `impl`s satisfying `{integer}: SomeInteger` found
  --> src/tracing_error.rs:2:1
   |
2  | impl  SomeInteger for i8  { fn bleep(&self) {} }
   | ^^^^^^^^^^^^^^^^^^^^^^^^
3  | impl  SomeInteger for i32 { fn bleep(&self) {} }
   | ^^^^^^^^^^^^^^^^^^^^^^^^^
   = note: required for the cast to the object type `dyn SomeInteger

It would seem as if the error on the {yaks} results in a full abort on type inference, and with type inference, no types get resolved, hence the subsequent error flagging the need for type annotations.

Questions:

a) is my speculation on that rustc implementation detail correct - i.e. no type inference stage in the above scenario?

b) I suspect the ordering of the errors is due to accumulation of errors over multiple stages, hence the format string problem is detected first, (then no type inference taking place), then complaints about being unable to get resolved types?

I realize that these are probably rustc implementation details, but then we are working with an implementation of a real compiler.

The reason for this posting: I am trying to learn how to efficiently read rust compiler error messages, so any explanation for the above or general approaches how to "work out the true problems" would be much appreciated.

You don't have any variables called yaks. The variable is called number_of_yaks.

1 Like

To anyone reading this, the author has posted another question about the same code:

Many thanks, @alice for your response.

I am aware that the source code is faulty, and said as much in my first sentence. I am asking here why rustc emits the additional type inference errors.

In the posting in editors/IDE I use, admittedly, the exact same known broken source snippet to ask how the diagnostics in Visual Studio Code + Rust Analyzer can possibly be tuned to allow for better error comprehension in the IDE.

Just FWIW and perhaps to sharpen the focus of my posts.

You can simplify the example a bit

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

fn main() {
    1.bleep();
    a
}

You can also try the following

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

fn main() {
    1.bleep();
}

An integer literal is assumed to be an i32 if the compiler has no reason to assume otherwise. I can't say I'm familiar with rustc internals, but maybe making this assumption for code that has other errors sometimes confounds things further, and so the assumption isn't made.

1 Like

It's definitely not no inference. The error goes away if there's only one {integer} implementation or for this:

impl  SomeInteger for Vec<&'static str> { fn bleep(&self) {} }
fn main() {
    let number_of_yaks = [""].into_iter().collect();
    // ...
}

There may not be any less inference at all; maybe there's just no literal-fallback in the face of inference failures during this error mode, today. (That's speculation.)

Probably something like that. Compilers often try to limp along after an error in an attempt to find what the programmer would consider the root error / to let the programmer avoid a "fix one little thing, check, fix another little thing, check, ..." loop.

That said, this appears to be a diagnostic regression. Emitting this error in this situation is new as of the most recent compiler version (1.58); it doesn't do so in 1.57. So, certainly not something to rely on.

Here's the issue about the diagnostic regression.

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.