rust-lang / rust

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

Crate version mismatch suggestion not being shown for trait not implemented error #89143

Closed edmorley closed 1 week ago

edmorley commented 3 years ago

In #66561 the diagnostic for trait not implemented errors was improved to add a hint suggesting there may be multiple crate versions, if there was a trait found with the same name. However that hint is not being shown for the testcase below, when I would have expected it to be.

Note: This is a variation/subset of #22750 - however I'm filing this separately since (a) this part was meant to be fixed by #66561, (b) #22750 covers a mixture of several issues (such as surfacing crate version info from cargo) and so less actionable.


Steps to reproduce:

  1. Clone https://github.com/edmorley/testcase-rustc-crate-version-mismatch
  2. cd a && cargo check

The current output is (using rustc 1.59.0-beta.8):

    Checking c v0.1.0 (/Users/emorley/src/testcase-rustc-crate-version-mismatch/c-v0.1)
    Checking c v0.2.0 (/Users/emorley/src/testcase-rustc-crate-version-mismatch/c-v0.2)
    Checking b v0.1.0 (/Users/emorley/src/testcase-rustc-crate-version-mismatch/b)
    Checking a v0.1.0 (/Users/emorley/src/testcase-rustc-crate-version-mismatch/a)
error[E0277]: the trait bound `CustomErrorHandler: ErrorHandler` is not satisfied
 --> src/main.rs:5:17
  |
5 |     cnb_runtime(CustomErrorHandler {});
  |     ----------- ^^^^^^^^^^^^^^^^^^^^^ the trait `ErrorHandler` is not implemented for `CustomErrorHandler`
  |     |
  |     required by a bound introduced by this call
  |
note: required by a bound in `cnb_runtime`
 --> /Users/emorley/src/testcase-rustc-crate-version-mismatch/c-v0.2/src/lib.rs:3:41
  |
3 | pub fn cnb_runtime(_error_handler: impl ErrorHandler) {}
  |                                         ^^^^^^^^^^^^ required by this bound in `cnb_runtime`

For more information about this error, try `rustc --explain E0277`.
error: could not compile `a` due to previous error

Ideally the output should look like:

$ cargo check
    Checking c v0.1.0 (/Users/emorley/src/testcase-rustc-crate-version-mismatch/c-v0.1)
    Checking c v0.2.0 (/Users/emorley/src/testcase-rustc-crate-version-mismatch/c-v0.2)
    Checking b v0.1.0 (/Users/emorley/src/testcase-rustc-crate-version-mismatch/b)
    Checking a v0.1.0 (/Users/emorley/src/testcase-rustc-crate-version-mismatch/a)
error[E0277]: the trait bound `CustomErrorHandler: ErrorHandler` is not satisfied
 --> src/main.rs:5:17
  |
5 |     cnb_runtime(CustomErrorHandler {});
  |     ----------- ^^^^^^^^^^^^^^^^^^^^^ the trait `ErrorHandler` is not implemented for `CustomErrorHandler`
  |     |
  |     required by a bound introduced by this call
  |
note: required by a bound in `cnb_runtime`
 --> /Users/emorley/src/testcase-rustc-crate-version-mismatch/c-v0.2/src/lib.rs:3:41
  |
3 | pub fn cnb_runtime(_error_handler: impl ErrorHandler) {}
  |                                         ^^^^^^^^^^^^ required by this bound in `cnb_runtime`
help: trait impl with same name found
  --> /Users/emorley/src/testcase-rustc-crate-version-mismatch/b/src/lib.rs:3
   |
LL | impl c::ErrorHandler for CustomErrorHandler {}
   | ^^^^^^^^^^^^^^^^^^^
   = note: Perhaps two different versions of crate `c` are being used?

For more information about this error, try `rustc --explain E0277`.
error: could not compile `a` due to previous error
pmarks commented 3 years ago

We've seen a similar case recently where the note: Perhaps two different versions of cratecare being used? should have been triggered. Not sure if it's the same bug or new one. Message we got is below. I can prepare a minimal test case and/or file a separate issue.

error[E0599]: no method named `find_fastqs` found for enum `fastq_set::filenames::FastqDef` in the current scope
   --> turing_pd/src/ligation_qc_process_reads.rs:294:36
    |
294 |             for fastq in fastq_def.find_fastqs().unwrap() {
    |                                    ^^^^^^^^^^^ method not found in `fastq_set::filenames::FastqDef`
    |
   ::: /mnt/bazelbuild/user/joey.arthur/cargo/git/checkouts/fastq_set-9504d5db1bfdb3fb/69af0bc/src/filenames/mod.rs:22:8
    |
22  |     fn find_fastqs(&self) -> Result<Vec<InputFastqs>, Error>;
    |        ----------- the method is available for `fastq_set::filenames::FastqDef` here
    |
    = help: items from traits can only be used if the trait is in scope
    = note: the following trait is implemented but not in scope; perhaps add a `use` for it:
            `use fastq_set::filenames::FindFastqs;`

error: unused import: `fastq_set::filenames::FindFastqs`
 --> turing_pd/src/ligation_qc_process_reads.rs:4:5
  |
4 | use fastq_set::filenames::FindFastqs;
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
konnorandrews commented 2 years ago

I helped @JtotheThree on the Rust Discord server with a related setup. Its not exactly the same so I have create a test case for it here. However, this setup looks to be closely related to this class of help messages so I have included it here instead of making a new issue.

The contradictory seeming help message rustc provides caused confusion on what was happening. In the original code there was a macro involved that was suspected originally as ignoring use statements. After using the fully qualified syntax to invoke the trait function it was realized that the trait used was not the same version as the implementing version and the macro was not at fault.

This setup is also similar to @pmarks case above, but with an associated function instead of a method.

theCapypara commented 2 years ago

I stumbled upon this issue today. In case it helps, here's my particular setup:

Crates involved:

amiquip provides a trait and an impl as such:

use mio::net::TcpStream;
pub trait IoStream: Read + Write + Evented + Send + 'static {}

impl IoStream for TcpStream {}

When trying to use pass a v0.8 TcpStream to a method of amiquip that wants an IoStream I get the following error:

error[E0277]: the trait bound `mio::net::TcpStream: amiquip::IoStream` is not satisfied
   --> x/src/main.rs:68:26
    |
68  |     let mut connection = Connection::open_tls_stream(
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `amiquip::IoStream` is not implemented for `mio::net::TcpStream`
    |
    = help: the following other types implement trait `amiquip::IoStream`:
              amiquip::stream::native_tls::TlsStream<S>
              mio::net::tcp::TcpStream
note: required by a bound in `amiquip::Connection::open_tls_stream`
   --> /home/x/.cargo/registry/src/github.com-1ecc6299db9ec823/amiquip-0.4.2/src/connection.rs:262:66
    |
262 |     pub fn open_tls_stream<Auth: Sasl, C: Into<TlsConnector>, S: IoStream>(
    |                                                                  ^^^^^^^^ required by this bound in `amiquip::Connection::open_tls_stream`

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

This is by far the worst error message the Rust compiler has given me so far. It took me almost an hour until I realized what was going on, I thought I'd gone insane.

The compiler should output a hint about a possible version mismatch in this case.

estebank commented 3 months ago

Interestingly, #124944 doesn't trigger for the case in the repro repository. I'll dig deeper. Edit: I've found the discrepancy: currently the new note will trigger only if the type comes from another version of the same crate, but we need to also check "of all of the traits available, is there one with the same name, same crate name, and different crate DefId?", which is different (and more general). I have a patch to account for this:

error[E0277]: the trait bound `CustomErrorHandler: ErrorHandler` is not satisfied
 --> src/main.rs:5:17
  |
5 |     cnb_runtime(CustomErrorHandler {});
  |     ----------- ^^^^^^^^^^^^^^^^^^^^^ the trait `ErrorHandler` is not implemented for `CustomErrorHandler`
  |     |
  |     required by a bound introduced by this call
  |
help: you have multiple different versions of crate `ErrorHandler` in your dependency graph
 --> src/main.rs:1:5
  |
1 | use b::CustomErrorHandler;
  |     ^ one version of crate `ErrorHandler` is used here, as a dependency of crate `b`
2 | use c::cnb_runtime;
  |     ^ one version of crate `ErrorHandler` is used here, as a direct dependency of the current crate
note: two types coming from two different versions of the same crate are different types even if they look the same
 --> /home/gh-estebank/testcase-rustc-crate-version-mismatch/c-v0.2/src/lib.rs:1:1
  |
1 | pub trait ErrorHandler {}
  | ^^^^^^^^^^^^^^^^^^^^^^ this is the required trait
  |
 ::: /home/gh-estebank/testcase-rustc-crate-version-mismatch/c-v0.1/src/lib.rs:1:1
  |
1 | pub trait ErrorHandler {}
  | ---------------------- this is the found trait
  = help: you can use `cargo tree` to explore your dependency tree
note: required by a bound in `cnb_runtime`
 --> /home/gh-estebank/testcase-rustc-crate-version-mismatch/c-v0.2/src/lib.rs:3:41
  |
3 | pub fn cnb_runtime(_error_handler: impl ErrorHandler) {}
  |                                         ^^^^^^^^^^^^ required by this bound in `cnb_runtime`

Screenshot 2024-08-08 at 1 24 26 PM

estebank commented 3 months ago

Final output:

error[E0277]: the trait bound `CustomErrorHandler: ErrorHandler` is not satisfied
 --> src/main.rs:5:17
  |
5 |     cnb_runtime(CustomErrorHandler {});
  |     ----------- ^^^^^^^^^^^^^^^^^^^^^ the trait `ErrorHandler` is not implemented for `CustomErrorHandler`
  |     |
  |     required by a bound introduced by this call
  |
help: you have multiple different versions of crate `c` in your dependency graph
 --> src/main.rs:1:5
  |
1 | use b::CustomErrorHandler;
  |     ^ one version of crate `ErrorHandler` is used here, as a dependency of crate `b`
2 | use c::cnb_runtime;
  |     ^ one version of crate `ErrorHandler` is used here, as a direct dependency of the current crate
note: two types coming from two different versions of the same crate are different types even if they look the same
 --> /home/gh-estebank/testcase-rustc-crate-version-mismatch/c-v0.2/src/lib.rs:1:1
  |
1 | pub trait ErrorHandler {}
  | ^^^^^^^^^^^^^^^^^^^^^^ this is the required trait
  |
 ::: /home/gh-estebank/testcase-rustc-crate-version-mismatch/b/src/lib.rs:1:1
  |
1 | pub struct CustomErrorHandler {}
  | ----------------------------- this type doesn't implement the required trait
  |
 ::: /home/gh-estebank/testcase-rustc-crate-version-mismatch/c-v0.1/src/lib.rs:1:1
  |
1 | pub trait ErrorHandler {}
  | ---------------------- this is the found trait
  = help: you can use `cargo tree` to explore your dependency tree
note: required by a bound in `cnb_runtime`
 --> /home/gh-estebank/testcase-rustc-crate-version-mismatch/c-v0.2/src/lib.rs:3:41
  |
3 | pub fn cnb_runtime(_error_handler: impl ErrorHandler) {}
  |                                         ^^^^^^^^^^^^ required by this bound in `cnb_runtime`

Screenshot 2024-08-08 at 2 36 34 PM

edmorley commented 3 months ago

| ^ one version of crate ErrorHandler is used here, as a dependency of crate b

In the testcase none of the crates are named ErrorHandler.

It seems this perhaps should be either trait ErrorHandler or crate 'c' ?

edmorley commented 3 months ago

Oh and thank you for looking into fixing/improving this!

estebank commented 3 months ago

Thanks for pointing that out, I fixed it after I took the screenshot (crate_name -> trait_name typo) :)