https://github.com/huonw/bad-error-messages-a contains a crate a
. https://github.com/huonw/bad-error-messages-bc contains two crates, b
and c
.
a
contains a trait Foo
and a function test
that requires that trait.b
depends on a specific revision (8b532f5, not the HEAD) of a
and contains a type Bar
that implements a::Foo
.c
depends on a
's HEAD (happens to be 84cfe230) and b
, and tries to use b::Bar
with a::test
.c
fails to compile despite Bar
"clearly" implementing Foo
... it's even displayed in the docs!
Cloning https://github.com/huonw/bad-error-messages-bc and running cargo build
in the root (which is c
) gives
Compiling a v0.0.1 (https://github.com/huonw/bad-error-messages-a#84cfe230)
Compiling a v0.0.1 (https://github.com/huonw/bad-error-messages-a?rev=8b532f5#8b532f51)
Compiling b v0.0.1 (file:///home/huon/projects/test-rust/error-messages/c)
Compiling c v0.0.1 (file:///home/huon/projects/test-rust/error-messages/c)
src/lib.rs:5:5: 5:12 error: the trait `a::Foo` is not implemented for the type `b::Bar` [E0277]
src/lib.rs:5 a::test(b::Bar);
^~~~~~~
error: aborting due to previous error
There's no indication of the fundamental problem from either rustdoc
or rustc
: that there's two different versions of a
being used, meaning a#84cfe230::Foo
and a#8b532f5::Foo
are different. Bar
only implements the latter, but in c
, the name a
refers to a#84cfe230
so a::test(...)
requires the former. (Using name#rev
to represent the crate with that version.)
There _is_ an indication of the difference in the example above, since a
is compiled twice, but that comes from cargo
, not rustc
. This issue is focusing on the fact that rustc
itself does not give helpful errors and/or allow tools like cargo to control those errors.
It would be nice if rustc:
foo#0.2.3
instead of the filepath/name"note: there's multiple versions of crate
...in use"
: along with a listing of the possibilities.(NB. I've used cargo
to construct this example because it is the easiest way I can get two different versions of a crate. This appears in rust-lang/rust's makefiles too, where the std
test runner is called "std" internally, but links against another crate called "std", i.e. the conventional standard library.)
This bit me today with uuid
! It took me a few minutes before I even understood that it wasn't "my" code that was giving this off.
Related, its also annoying if only crate local paths get emitted, like in backtraces.
We need a way for crates to identify themself uniquely, and not just by an identifier. Maybe a scheme like <crate foo #ef12f212>::bar::baz
?
I was bitten by this too.
Kimundi: Agreed for the need to unique identification. But then again, in some cases the local path tells more directly where the problem is. I wonder if there are cases where path is better and cases where a hash is better. Or maybe some kind of hybrid: If version information from cargo is available, use that. If not, if version control information is available, use commit SSH, and if no other information exists, use a path...?
Nominating for high priority. I think this is one of the main pain points people have when using cargo, and one of the major reasons for people complaining about cargo allowing multiple versions of a crate. It's usually easy to identify once you've seen it a few times, but it is a horribly confusing and annoying experience.
(Tagged with both compiler and tools since cargo presumably plays into this, but this is probably most relevant to the compiler subteam.)
@golddranks: the question of connecting semantically relevant info to crates is discussed a little in the issue. I think the best plan would external tools to pass in arbitrary strings connected to each crate, defaulting to the path, meaning rustc doesn't have to actually understand anything, just print strings (the compiler already has an --extern NAME=PATH
argument that tools like cargo use, it could be extended to also allow --extern NAME#"ID"=PATH
or something).
I've also seen an increasing number of IRC questions about this.
On Sep 7, 2015, at 20:58, Huon Wilson [email protected] wrote:
Nominating for high priority. I think this is one of the main pain points people have when using cargo, and one of the major reasons for people complaining about cargo allowing multiple versions of a crate. It's usually easy to identify once you've seen it a few times, but it is a horribly confusing and annoying experience.
(Tagged with both compiler and tools since cargo presumably plays into this, but this is probably most relevant to the compiler subteam.)
@golddranks: the question of connecting semantically relevant info to crates is discussed a little in the issue. I think the best plan would external tools to pass in arbitrary strings connected to each crate, defaulting to the path, meaning rustc doesn't have to actually understand anything, just print strings (the compiler already has an --extern NAME=PATH argument that tools like cargo use, it could be extended to also allow --extern NAME#"ID"=PATH or something).
―
Reply to this email directly or view it on GitHub.
I'll take a crack at this
I think at the very least, for mismatched type and unimplemented trait errors, if we detect a crate mismatch, we should mention it. Any other such errors?
Mismatched type is the big one.
Being able to understand this would also help Rustdoc a lot, I think there are bugs open. (That way, we could know if something is a re-export or not)
No no no github, I said "partial fix"
Anyway, #28300 fixes the error when there's a type mismatch. "Can't find trait" will be a tad trickier
I had a corner-case posted on Reddit that was even more confusing:
src/main.rs:9:45: 9:47 error: mismatched types:
expected `&cookie::jar::CookieJar<'_>`,
found `&cookie::jar::CookieJar<'_>`
I was using Hyper with the latest cookie crate. I did it because even though 'hyper' depends on 'cookie=0.1.21' or somesuch, I couldn't use 'cookie' on my program. I'll suggest a change on cargo if it doesn't yet exist.
Yeah, this should be fixed but the just-landed PR.
triage: P-medium -- we think that the most important cases here have been covered. If this issue continues to arise frequently on IRC, we could bump up the priority to high.
This error message did not show up when I had "identical-type" type mismatches..
Compiling test v0.1.0 (file:///test)
main.rs:17:37: 17:70 error: mismatched types:
expected `&nalgebra::structs::vector::Vector3<f32>`,
found `&nalgebra::structs::vector::Vector3<f32>`
(expected struct `nalgebra::structs::vector::Vector3`,
found a different struct `nalgebra::structs::vector::Vector3`) [E0308]
main.rs:17 c.prepend_to_local_rotation(&Vector3::new(0.0f32, 0.014, 0.0));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.rs:17:37: 17:70 help: run `rustc --explain E0308` to see a detailed explanation
main.rs:17:37: 17:70 note: Perhaps two different versions of crate `nalgebra` are being used?
main.rs:17 c.prepend_to_local_rotation(&Vector3::new(0.0f32, 0.014, 0.0));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error
Could not compile `test`.
my rustc version is rustc 1.9.0-nightly (998a6720b 2016-03-07)
.
@sezna it did?
main.rs:17:37: 17:70 note: Perhaps two different versions of crate
nalgebra
are being used?
:smile: it's fileline_note and sometimes gets lost in the output
@Manishearth I actually do still have something to contribute, although it may not be useful. The reason I thought it didn't output the message is because it didn't the first time, as nalgebra was aliased as "na".
See below.
Compiling test v0.1.0 (file:///Users/alexhansen/Codin/rust/test)
main.rs:17:37: 17:70 error: mismatched types:
expected `&nalgebra::structs::vector::Vector3<f32>`,
found `&na::structs::vector::Vector3<f32>`
(expected struct `nalgebra::structs::vector::Vector3`,
found struct `na::structs::vector::Vector3`) [E0308]
main.rs:17 c.prepend_to_local_rotation(&Vector3::new(0.0f32, 0.014, 0.0));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I'm not as silly as I originally thought!
IIRC this isn't really possible to fix; how do you tell that two crates are the same, conceptually?
Good point. Well, I have nothing more then. Sorry about this little mixup!
IIRC this isn't really possible to fix; how do you tell that two crates are the same, conceptually?
rustc should be able to handle the aliased case in theory, since it knows the true name/path of a crate (e.g. uses of an na::Foo
type can be tracked back to the nalgebra
in extern crate nalgebra as na;
).
Oh, right, we have that crate name.
This is a frequent thing I get asked about in hyper. Users depend on hyper, and a server framework, and then get a very confusing error message when trying to set a header. Consider:
impl Headers {
pub fn set<H: Header>(&mut self, header: H) {}
}
When using a version of hyper that doesn't match what the server framework does, then when they do response.headers.set(ContentLength(10))
, the message says "the trait hyper::header::Header
is not implemented for the type hyper::header::ContentLength
".
Ideally, magic would happen in cargo and this error would never happen. Realistically, this error could notice when the items come from separate crates, but the crates have the same name, and append "possible crate version mismatch" or some such.
Ideally, magic would happen in cargo and this error would never happen.
I'll disagree with this, but probably not disagree with your actual intent. It's very much a good thing that cargo allows pulling in multiple versions of a crate. In _some_ cargo issue that I can't find now, I advocated that what we would actually want is some syntax like
[dependencies]
server = "1.2.3"
hyper = { from: "server" }
Crates also publicly expose hyper (or other building-block libraries) as part of their public API but without properly accounting for everything that entails.
However, there is always the case for better error messages! 😸
I also got bitten by this issue multiple times. Once with hyper
+ iron
, once with r2d2_redis
+ redis
. I found this issue through https://www.reddit.com/r/rust/comments/4sy81y/best_practice_for_exposing_library_dependencies/.
I'd support a syntax like the once mentioned by @shepmaster. It provides a way for the user to differentiate between "I want this version of hyper" and "I simply want the version of hyper that server uses".
Possibly a corner case, but I'm hitting this in a custom build.rs
Compiling pnetlink v0.1.0 (file:///home/robertc/personal/rust/rusty_rail/../pnetlink)
error[E0308]: mismatched types
--> ../pnetlink/build.rs:26:31
|
26 | pnet_macros::register(&mut registry);
| ^^^^^^^^^^^^^ expected struct `syntex::Registry`, found a different struct `syntex::Registry`
|
= note: expected type `&mut syntex::Registry`
= note: found type `&mut syntex::Registry`
note: Perhaps two different versions of crate `syntex` are being used?
--> ../pnetlink/build.rs:26:31
|
26 | pnet_macros::register(&mut registry);
| ^^^^^^^^^^^^^
The warning seems to work?
note: Perhaps two different versions of crate
syntexare being used?
To be clear, this filed issue is about improving the diagnostics of this situation and ensuring people know that a different crate is being used. This already works in your case. The fact that two different versions of the crate are being liked are a problem on your side, and is not a rustc bug.
Right - so this message is missing:
I guess. Though rustc
doesn't have this info; that's purely on the cargo side, so that's much harder to implement.
I suggest using cargo tree
(cargo install cargo-tree
) to debug this; it tells you exactly what your dependency tree looks like and it's easy to look for the mismatch
Though
rustc
doesn't have this info; that's purely on the cargo side
Theoretically, couldn't we pass more info into rustc
? For example, to use the rand
crate, it looks like
rustc src/main.rs --extern rand=/private/tmp/wat/target/debug/deps/librand-49a08859d086fffe.rlib
Would it be possible to extend it to include a version identifier?
rustc src/main.rs --extern rand:0.3.14=/private/tmp/wat/target/debug/deps/librand-49a08859d086fffe.rlib
That identifier wouldn't be used for anything other than informative text.
Yes, we could. Probably needs an rfc though.
@Manishearth Thanks for the pointer..
Perhaps rustc could:
And the cargo docs don't mention cargo-tree at all - I had seen it referenced in a forums post but couldn't find it in the cargo repo - and for whatever reason my google searches kept getting me articles about shipping lumber :).
cargo-tree isn't an official tool, it's a crate (https://crates.io/crates/cargo-tree). cargo install
lets you install any binary crate off crates.io.
Rustc diagnostics shouldn't link to an external tool, really.
Yes, I get that its third party; but it seems odd to _not_ link to the currently best tool for solving a problem - whats the ideological object there?
Rustc doesn't even refer to _cargo_ in its diagnostics.
Prior art:
GHC shows the package name and version when appropriate
npm has a peerDependencies
field which exposes the transitive dependencies of a library -- I think this has been suggested as rust-lang/cargo#2064
Sometimes this can suggest private paths, which makes this even more confusing.
This snippet is taken from an IRC conversation with a (rightly) confused user:
expected struct `gfx_graphics::glyph::GlyphCache`, found struct `gfx_graphics::GlyphCache`
^ --- This path is private ^ --- This is the publicly available path
I suggest we at least temporarily mitigate this by applying @huonw's third suggestion from the list, which shouldn't require interfacing with anything external.
detected errors that may be caused by ambiguous names and noted it explicitly, e.g. when there is a error involving an ambiguous crate print (once) some extra lines like "note: there's multiple versions of crate...in use": along with a listing of the possibilities.
Some of the issues here (around misleading module paths being reported) may be related to #34769
This has started popping up more frequently again on Stack Overflow due to a slow shift towards Serde 1.0 as some crates depend on Serde 0.8, 0.9, or 1.0, all of which are incompatible.
@Manishearth I'm unassigning you since I don't think you are actively working on this and probably don't have it in a todo list or anything like that?
Experienced this again ("doesn't implement trait", due to disagreement about which type we were talking about). Asked about status on IRC and got "Lints are not really a priority", which I think would be too bad.
This isn't a lint.
I'm not sure what we are talking about, but what I meant by "this" is the missed opportunity to explain an error to the user. I agree that this is in no sense a lint, and in the future I'll explain this to people on IRC who try and speak for the project?
What @Manishearth is trying to communicate is that there is a policy level of pushing most lints to Clippy or other tools rather than integrating them into the compiler.
This seems more like an area where the type errors could be improved.
New lints need an RFC, but this isn't a lint; it's an error message that should be improved. They're different things.
Let me try again. I experienced a form of the issue described, though the version where a trait is implemented for one version of a type and not another (which may not be what was partially fixed). When asking about this issue on IRC, it was stated (by a regular, possibly not in a formal capacity) that "Lints are not really a priority".
This is only meant to be another "ping" about how Rust's usually quite good error messages still have some limitations, and wasn't meant to be about who thinks it was a lint, or whether its standing as a lint makes it less interesting, or anything like that. Obviously, feel free to hash that out amongst yourselves, but not on my account. :)
I'm not sure what we are talking about,
I'm meant that this is not a lint, this is diagnostics, so "lints are not a priority" doesn't apply here and whoever gave you that status was wrong about it. Though it's possible that diagnostics are no longer a priority here either (I'd be surprised, given the ergonomics initiative and prior focus on diagnostics by the docs team).
So it appears there should be a note for this, but I don't see it in the case when you try to call a trait method and the trait is implemented for the wrong version of the struct.
error[E0599]: no method named `build_vk_surface` found for type `winit::WindowBuilder` in the current scope
--> src/main.rs:27:46
|
27 | let window = winit::WindowBuilder::new().build_vk_surface(&events_loop, Arc::clone(&instance));
| ^^^^^^^^^^^^^^^^
Here my crate was accidentally depending on winit 0.11 whereas the trait was defined on version 0.7.
No chance at better diagnostics here?
My friend just ran into this and one thing I'd like to see in error messages is explanation where those crates came from.
E.g. the crate depends on a
and b
, a
depends on c 1.0
and b
depends on c 1.1
.
I'd like to see error message like this:
Note: two versions of the crate `c` are present
Note: crate `c` of version 1.0 required by crate `a`
Note: crate `a` required by this crate
Note: crate `c` of version 1.1 required by crate `b`
Note: crate `b` required by this crate
I'd like to see both dependency chains in full to be able to investigate.
@Kixunil Did you mean?
Note: two versions of the crate `c` are present
Note: crate `c` of version 1.0 required by crate `a`
Note: crate `a` required by this crate
Note: crate `c` of version 1.1 required by crate `b`
Note: crate `b` required by this crate
But I thought having multiple versions of the same crate are allowed?
@pickfire yes, thank you, I corrected it.
I'm interested in working on this. I already have a very tentative approach here, but I'm struggling a bit.
I hope the approach is understandable (find all traits with the same name/path as the expected but unsatisfied one, if one of those is implemented by the type, give helpful diagnostics).
I would really like to show crate versions, but apparently they're not present in the compiler at the moment according to Esteban.
So I'm going to first add some help text for E0277
(trait `Trait` is not implemented for `Struct`) and try to create a nice PR for that.
Alright, the next possible steps could be:
Last week I encountered a variant of this bug that does not seem to have been addressed by PR #66561.
Namely this scenario:
Click to see the Cargo.toml and Rust source files involved.
a/Cargo.toml
[package]
name = "a"
version = "0.1.0"
[dependencies]
b = { path = "../b" }
c = { path = "../c-v0.2" }
b/Cargo.toml
[package]
name = "b"
version = "0.1.0"
[dependencies]
c = { path = "../c-v0.1" }
c-v0.1/Cargo.toml
[package]
name = "c"
version = "0.1.0"
c-v0.2/Cargo.toml
[package]
name = "c"
version = "0.2.0"
a/src/lib.rs
pub struct A<C: c::C> { b: b::B<C> }
b/src/lib.rs
pub struct B<C> where C: c::C { pub c: C }
c-v0.1/src/lib.rs
pub trait C { }
c-v0.2/src/lib.rs
pub trait C { }
When I try to build this, I get the following error from rustc
:
error[E0277]: the trait bound `C: c::C` is not satisfied
--> a/src/lib.rs:1:25
|
1 | pub struct A<C: c::C> { b: b::B<C> }
| ^^^^^^^^^^ the trait `c::C` is not implemented for `C`
|
help: consider further restricting this bound with `+ c::C`
--> a/src/lib.rs:1:17
|
1 | pub struct A<C: c::C> { b: b::B<C> }
| ^^^^
= note: required by `b::B`
error: aborting due to previous error
(Which is pretty frustrating suggestion when one doesn't realize that the root issue is a version mismatch.)
I would have loved to get a "Perhaps two different versions of crate crate_a2
are being used?" error message but didn't. In my case I had a derived impl for a different version of the trait. Took me a long while to figure out what was going on. A better error message would be most appreciated.
I was bitten by this today. Since cargo tree
has been added recently in stable, it was really easy to understand which version were used where. Maybe it could be possible to suggest using it in a note
?
@robinmoussu I just noticed cargo tree
has -d
switch. In that case, the switch should be suggested as well.
Most helpful comment
My friend just ran into this and one thing I'd like to see in error messages is explanation where those crates came from.
E.g. the crate depends on
a
andb
,a
depends onc 1.0
andb
depends onc 1.1
.I'd like to see error message like this:
I'd like to see both dependency chains in full to be able to investigate.