Type errors (E0308) are a common occurrence in rustc. Whenever I confuse myself about the type of something, I tend to assign it to some x: i32 and let the compiler blame me with a hint about what type x actually is. The note-section attached to the error message contains the fully qualified type name, which is technically as correct as one can get. However, this also produces a lot of clutter, because the type-name that I'm actually interested in is much more concise if types in scope of the offending statement are taken into account. For example:
use std::collections::HashMap;
fn foobar(x: &i32) {
}
fn main() {
let mut foo = HashMap::new();
foo.insert("foo", Ok(Some("bar")));
foo.insert("oof", Err("Oh noes!"));
foobar(&foo);
println!("{:#?}", foo);
}
The note says
found type
std::collections::HashMap<&str, std::result::Result<std::option::Option<&str>, &str>>
Again, while this is as precise as it can get, most of this is just clutter, especially with deeply nested types: I know that HashMap is from std::collections, I also know that Option refers to std::option::Option. If I had some other type shadowing those names, I'd be aware of it. Reading the note, I have to demangle the type-name to
found type
HashMap<&str, Result<Option<&str>, &str>>
which is what the type-name would be if I wanted to write it down, considering all the uses.
Could we at least have an option (or an extra note) for E0308 where the type-names get uncluttered by considering the types that are in scope for the offending statement? This would reduce the intellectual burden and may enable one to just copy&paste the type-name from the note.
cc #21934
As I said in #58088 , I would suggest banning all path names from types in error messages and to include use statements in the error message to avoid ambiguity and to allow the user to verify the path if needed.
It's exponentially useful when the same types are referred to more than once, which is quite common. The problem seems also especially bad with generics, which are common in rust as well.
Sorry, but I'm not the same oppnion as you are. Let's suggest you have to structs called Foo in different paths in your code. You only import/use one at the moment. Now you compile your project and your compiler will complain something related to Foo but because there are no paths you will likely end up digging at the wrong Foo.
I don't think that removing paths from the error is a good solution!
@hellow554 That's why I'm suggesting use statements to be included in the error messages, with full, unambiguous paths. I don't know, but I feel that unfortunately the screenshot I posted speaks louder than a thousand words, and I mean literally speaking... that can't be a desirable UX, no? Maybe we can agree on that to start? I find myself writing post processing scripts to make any sense out of the error messages by removing all the paths.
To make a more concrete proposition, it might look something like:
using the types:
- std::collections::HashMap
- std::result::Result
- std::option::Option
[The erronous code]
error: found type HashMap<&str, Result<Option<&str>, &str>> ...
@najamelan Error messages like that would suggest that it is idiomatic to use std::io::Error;, which is not something I want to see encouraged.
Furthermore there could be cases where multiple identical names show up in the same error message. (e.g. HCons<site::Settings, HCons<ui::Settings, HCons<project::Settings, HNil>>>)
Furthermore there could be cases where multiple identical names show up in the same error message. (e.g.
HCons<site::Settings, HCons<ui::Settings, HCons<project::Settings, HNil>>>)
That's a non-issue, the compiler should just simplify the paths as much as possible without introducing ambiguities. For example:
std::collections::HashMap<serde_json::Result<u32>, std::io::Result<u32>>
Would become:
use std::collections::HashMap;
use std::io;
HashMap<serde_json::Result<u32>, io::Result<u32>>
There's not much difference here, but it would help considerably in cases like this:
error[E0271]: type mismatch resolving `<impl futures_core::stream::TryStream as futures_core::stream::Stream>::Item == std::result::Result<(bytes::bytes::Bytes, std::net::SocketAddr), std::io::Error>`
--> src/main.rs:220:13
|
220 | let _ = task::spawn(foo);
| ^^^^^^^^^^^ expected associated type, found enum `std::result::Result`
|
= note: expected associated type `<impl futures_core::stream::TryStream as futures_core::stream::Stream>::Item`
found enum `std::result::Result<(bytes::bytes::Bytes, std::net::SocketAddr), std::io::Error>`
= note: consider constraining the associated type `<impl futures_core::stream::TryStream as futures_core::stream::Stream>::Item` to `std::result::Result<(bytes::bytes::Bytes, std::net::SocketAddr), std::io::Error>` or calling a method that returns `<impl futures_core::stream::TryStream as futures_core::stream::Stream>::Item`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
= note: required because of the requirements on the impl of `core::future::future::Future` for `futures_util::stream::stream::forward::Forward<impl futures_core::stream::TryStream, futures_util::sink::map_err::SinkMapErr<futures_util::sink::fanout::Fanout<futures_channel::mpsc::UnboundedSender<(bytes::bytes::Bytes, std::net::SocketAddr)>, futures_channel::mpsc::UnboundedSender<(bytes::bytes::Bytes, std::net::SocketAddr)>>, [closure@src/main.rs:218:47: 218:101]>>`
And errors like this are rather common while using futures.
Most helpful comment
@hellow554 That's why I'm suggesting use statements to be included in the error messages, with full, unambiguous paths. I don't know, but I feel that unfortunately the screenshot I posted speaks louder than a thousand words, and I mean literally speaking... that can't be a desirable UX, no? Maybe we can agree on that to start? I find myself writing post processing scripts to make any sense out of the error messages by removing all the paths.
To make a more concrete proposition, it might look something like: