-
Notifications
You must be signed in to change notification settings - Fork 13.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Coherence error messages can be inscrutable #23980
Comments
triage: P-high (1.0) |
@flaper87 is going to look into this as well. As a concrete first step, we want to print out the overlapping types, and not just cite impls. For example: // crate A
trait Foo { }
impl<T> Foo for &T { }
// crate B
struct MyType;
impl Foo for &MyType { } // X This would ideally print something like:
However, the last part is a bit tricky since the impl must be reconstructed from metadata, but we can start with even just printing |
I'm encouraging @aturon to take this on :) |
Currently, a coherence error based on overlapping impls simply mentions the trait, and points to the two conflicting impls: ``` error: conflicting implementations for trait `Foo` ``` With this commit, the error will include all input types to the trait (including the `Self` type) after unification between the overlapping impls. In other words, the error message will provide feedback with full type details, like: ``` error: conflicting implementations of trait `Foo<u32>` for type `u8`: ``` When the `Self` type for the two impls unify to an inference variable, it is elided in the output, since "for type `_`" is just noise in that case. Closes rust-lang#23980
Currently, a coherence error based on overlapping impls simply mentions the trait, and points to the two conflicting impls: ``` error: conflicting implementations for trait `Foo` ``` With this commit, the error will include all input types to the trait (including the `Self` type) after unification between the overlapping impls. In other words, the error message will provide feedback with full type details, like: ``` error: conflicting implementations of trait `Foo<u32>` for type `u8`: ``` When the `Self` type for the two impls unify to an inference variable, it is elided in the output, since "for type `_`" is just noise in that case. Closes #23980 r? @nikomatsakis
I still consider the error messages fairly inscrutable, even with @aturon's commit. |
In particular, I think we should tell you where we failed to use negative reasoning because of orphan rules. |
@nikomatsakis Whoops, sorry for the premature closure. I'd be interested in continuing to work in this space, but we should talk about the end goal. |
@aturon basically I think we should report each piece of negative reasoning that we were not able to use because of orphan rules. Bonus points if we limit it to negative reasoning that would have helped. I think the "motivating example" form this thread is interesting -- the thread opens with an explanation of the error, it seems like coherence could probably have produced something much like that. Right now the example gives you a counter-example like:
which is definitely a good start. But I think it'd be great if it could add:
|
http://stackoverflow.com/q/37347311/1256624 is a "real world" example where confusion was caused by being overly definite in the error message rather than explaining that it was a possibility/what the actual risk is. |
…r=nikomatsakis Add hints when intercrate ambiguity causes overlap. I'm going to tackle rust-lang#23980. # Examples ## Trait impl overlap caused by possible downstream impl ```rust trait Foo<X> {} trait Bar<X> {} impl<X, T> Foo<X> for T where T: Bar<X> {} impl<X> Foo<X> for i32 {} fn main() {} ``` ``` error[E0119]: conflicting implementations of trait `Foo<_>` for type `i32`: --> test1.rs:4:1 | 3 | impl<X, T> Foo<X> for T where T: Bar<X> {} | ------------------------------------------ first implementation here 4 | impl<X> Foo<X> for i32 {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `i32` | = note: downstream crates may implement Bar error: aborting due to previous error ``` ## Trait impl overlap caused by possible upstream update ```rust trait Foo {} impl<T> Foo for T where T: ::std::fmt::Octal {} impl Foo for () {} fn main() {} ``` ``` error[E0119]: conflicting implementations of trait `Foo` for type `()`: --> test2.rs:3:1 | 2 | impl<T> Foo for T where T: ::std::fmt::Octal {} | ----------------------------------------------- first implementation here 3 | impl Foo for () {} | ^^^^^^^^^^^^^^^^^^ conflicting implementation for `()` | = note: upstream crates may add new impl for std::fmt::Octal in future versions error: aborting due to previous error ``` ## Inherent impl overlap caused by possible downstream impl ```rust trait Bar<X> {} struct A<T, X>(T, X); impl<X, T> A<T, X> where T: Bar<X> { fn f(&self) {} } impl<X> A<i32, X> { fn f(&self) {} } fn main() {} ``` ``` error[E0592]: duplicate definitions with name `f` --> test3.rs:4:38 | 4 | impl<X, T> A<T, X> where T: Bar<X> { fn f(&self) {} } | ^^^^^^^^^^^^^^ duplicate definitions for `f` 5 | impl<X> A<i32, X> { fn f(&self) {} } | -------------- other definition for `f` | = note: downstream crates may implement Bar error: aborting due to previous error ``` ## Inherent impl overlap caused by possible upstream update ```rust struct A<T>(T); impl<T> A<T> where T: ::std::fmt::Octal { fn f(&self) {} } impl A<()> { fn f(&self) {} } fn main() {} ``` ``` error[E0592]: duplicate definitions with name `f` --> test4.rs:3:43 | 3 | impl<T> A<T> where T: ::std::fmt::Octal { fn f(&self) {} } | ^^^^^^^^^^^^^^ duplicate definitions for `f` 4 | impl A<()> { fn f(&self) {} } | -------------- other definition for `f` | = note: upstream crates may add new impl for std::fmt::Octal in future versions error: aborting due to previous error ```
…r=nikomatsakis Add hints when intercrate ambiguity causes overlap. I'm going to tackle rust-lang#23980. # Examples ## Trait impl overlap caused by possible downstream impl ```rust trait Foo<X> {} trait Bar<X> {} impl<X, T> Foo<X> for T where T: Bar<X> {} impl<X> Foo<X> for i32 {} fn main() {} ``` ``` error[E0119]: conflicting implementations of trait `Foo<_>` for type `i32`: --> test1.rs:4:1 | 3 | impl<X, T> Foo<X> for T where T: Bar<X> {} | ------------------------------------------ first implementation here 4 | impl<X> Foo<X> for i32 {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `i32` | = note: downstream crates may implement Bar error: aborting due to previous error ``` ## Trait impl overlap caused by possible upstream update ```rust trait Foo {} impl<T> Foo for T where T: ::std::fmt::Octal {} impl Foo for () {} fn main() {} ``` ``` error[E0119]: conflicting implementations of trait `Foo` for type `()`: --> test2.rs:3:1 | 2 | impl<T> Foo for T where T: ::std::fmt::Octal {} | ----------------------------------------------- first implementation here 3 | impl Foo for () {} | ^^^^^^^^^^^^^^^^^^ conflicting implementation for `()` | = note: upstream crates may add new impl for std::fmt::Octal in future versions error: aborting due to previous error ``` ## Inherent impl overlap caused by possible downstream impl ```rust trait Bar<X> {} struct A<T, X>(T, X); impl<X, T> A<T, X> where T: Bar<X> { fn f(&self) {} } impl<X> A<i32, X> { fn f(&self) {} } fn main() {} ``` ``` error[E0592]: duplicate definitions with name `f` --> test3.rs:4:38 | 4 | impl<X, T> A<T, X> where T: Bar<X> { fn f(&self) {} } | ^^^^^^^^^^^^^^ duplicate definitions for `f` 5 | impl<X> A<i32, X> { fn f(&self) {} } | -------------- other definition for `f` | = note: downstream crates may implement Bar error: aborting due to previous error ``` ## Inherent impl overlap caused by possible upstream update ```rust struct A<T>(T); impl<T> A<T> where T: ::std::fmt::Octal { fn f(&self) {} } impl A<()> { fn f(&self) {} } fn main() {} ``` ``` error[E0592]: duplicate definitions with name `f` --> test4.rs:3:43 | 3 | impl<T> A<T> where T: ::std::fmt::Octal { fn f(&self) {} } | ^^^^^^^^^^^^^^ duplicate definitions for `f` 4 | impl A<()> { fn f(&self) {} } | -------------- other definition for `f` | = note: upstream crates may add new impl for std::fmt::Octal in future versions error: aborting due to previous error ```
…r=nikomatsakis Add hints when intercrate ambiguity causes overlap. I'm going to tackle rust-lang#23980. # Examples ## Trait impl overlap caused by possible downstream impl ```rust trait Foo<X> {} trait Bar<X> {} impl<X, T> Foo<X> for T where T: Bar<X> {} impl<X> Foo<X> for i32 {} fn main() {} ``` ``` error[E0119]: conflicting implementations of trait `Foo<_>` for type `i32`: --> test1.rs:4:1 | 3 | impl<X, T> Foo<X> for T where T: Bar<X> {} | ------------------------------------------ first implementation here 4 | impl<X> Foo<X> for i32 {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `i32` | = note: downstream crates may implement Bar error: aborting due to previous error ``` ## Trait impl overlap caused by possible upstream update ```rust trait Foo {} impl<T> Foo for T where T: ::std::fmt::Octal {} impl Foo for () {} fn main() {} ``` ``` error[E0119]: conflicting implementations of trait `Foo` for type `()`: --> test2.rs:3:1 | 2 | impl<T> Foo for T where T: ::std::fmt::Octal {} | ----------------------------------------------- first implementation here 3 | impl Foo for () {} | ^^^^^^^^^^^^^^^^^^ conflicting implementation for `()` | = note: upstream crates may add new impl for std::fmt::Octal in future versions error: aborting due to previous error ``` ## Inherent impl overlap caused by possible downstream impl ```rust trait Bar<X> {} struct A<T, X>(T, X); impl<X, T> A<T, X> where T: Bar<X> { fn f(&self) {} } impl<X> A<i32, X> { fn f(&self) {} } fn main() {} ``` ``` error[E0592]: duplicate definitions with name `f` --> test3.rs:4:38 | 4 | impl<X, T> A<T, X> where T: Bar<X> { fn f(&self) {} } | ^^^^^^^^^^^^^^ duplicate definitions for `f` 5 | impl<X> A<i32, X> { fn f(&self) {} } | -------------- other definition for `f` | = note: downstream crates may implement Bar error: aborting due to previous error ``` ## Inherent impl overlap caused by possible upstream update ```rust struct A<T>(T); impl<T> A<T> where T: ::std::fmt::Octal { fn f(&self) {} } impl A<()> { fn f(&self) {} } fn main() {} ``` ``` error[E0592]: duplicate definitions with name `f` --> test4.rs:3:43 | 3 | impl<T> A<T> where T: ::std::fmt::Octal { fn f(&self) {} } | ^^^^^^^^^^^^^^ duplicate definitions for `f` 4 | impl A<()> { fn f(&self) {} } | -------------- other definition for `f` | = note: upstream crates may add new impl for std::fmt::Octal in future versions error: aborting due to previous error ```
Add hints when intercrate ambiguity causes overlap. I'm going to tackle #23980. # Examples ## Trait impl overlap caused by possible downstream impl ```rust trait Foo<X> {} trait Bar<X> {} impl<X, T> Foo<X> for T where T: Bar<X> {} impl<X> Foo<X> for i32 {} fn main() {} ``` ``` error[E0119]: conflicting implementations of trait `Foo<_>` for type `i32`: --> test1.rs:4:1 | 3 | impl<X, T> Foo<X> for T where T: Bar<X> {} | ------------------------------------------ first implementation here 4 | impl<X> Foo<X> for i32 {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `i32` | = note: downstream crates may implement Bar error: aborting due to previous error ``` ## Trait impl overlap caused by possible upstream update ```rust trait Foo {} impl<T> Foo for T where T: ::std::fmt::Octal {} impl Foo for () {} fn main() {} ``` ``` error[E0119]: conflicting implementations of trait `Foo` for type `()`: --> test2.rs:3:1 | 2 | impl<T> Foo for T where T: ::std::fmt::Octal {} | ----------------------------------------------- first implementation here 3 | impl Foo for () {} | ^^^^^^^^^^^^^^^^^^ conflicting implementation for `()` | = note: upstream crates may add new impl for std::fmt::Octal in future versions error: aborting due to previous error ``` ## Inherent impl overlap caused by possible downstream impl ```rust trait Bar<X> {} struct A<T, X>(T, X); impl<X, T> A<T, X> where T: Bar<X> { fn f(&self) {} } impl<X> A<i32, X> { fn f(&self) {} } fn main() {} ``` ``` error[E0592]: duplicate definitions with name `f` --> test3.rs:4:38 | 4 | impl<X, T> A<T, X> where T: Bar<X> { fn f(&self) {} } | ^^^^^^^^^^^^^^ duplicate definitions for `f` 5 | impl<X> A<i32, X> { fn f(&self) {} } | -------------- other definition for `f` | = note: downstream crates may implement Bar error: aborting due to previous error ``` ## Inherent impl overlap caused by possible upstream update ```rust struct A<T>(T); impl<T> A<T> where T: ::std::fmt::Octal { fn f(&self) {} } impl A<()> { fn f(&self) {} } fn main() {} ``` ``` error[E0592]: duplicate definitions with name `f` --> test4.rs:3:43 | 3 | impl<T> A<T> where T: ::std::fmt::Octal { fn f(&self) {} } | ^^^^^^^^^^^^^^ duplicate definitions for `f` 4 | impl A<()> { fn f(&self) {} } | -------------- other definition for `f` | = note: upstream crates may add new impl for std::fmt::Octal in future versions error: aborting due to previous error ```
…sakis Improve diagnostic of E0119 with extern crate, try to print the conflicting impl. Closes #27403. Closes #23563. Should improve #23980. The diagnostic now looks like: ``` error[E0119]: conflicting implementations of trait `std::convert::Into<_>` for type `GenX<_>`: --> $DIR/issue-27403.rs:15:1 | 15 | / impl<S> Into<S> for GenX<S> { 16 | | fn into(self) -> S { 17 | | self.inner 18 | | } 19 | | } | |_^ | = note: conflicting implementation in crate `core`: - impl<T, U> std::convert::Into<U> for T where U: std::convert::From<T>; error: aborting due to previous error ```
Current output:
|
In particular, when the overlap check fails, it doesn't give much clarity, particularly when the overlap is between impls in different crates. It should tell you:
bind's glue function should tail-call its target #2 might be a bit tricky to do, not sure, but we can certainly improve on current state of affairs.
The text was updated successfully, but these errors were encountered: