Skip to content
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

Open
nikomatsakis opened this issue Apr 2, 2015 · 9 comments
Open

Coherence error messages can be inscrutable #23980

nikomatsakis opened this issue Apr 2, 2015 · 9 comments
Labels
A-diagnostics Area: Messages for errors, warnings, and lints C-bug Category: This is a bug. E-hard Call for participation: Hard difficulty. Experience needed to fix: A lot. P-medium Medium priority T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@nikomatsakis
Copy link
Contributor

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:

  1. Precisely what type overlaps
  2. For each case of negative reasoning it was not able to make, why it was not able to make it.
    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.
@nikomatsakis nikomatsakis added the A-diagnostics Area: Messages for errors, warnings, and lints label Apr 2, 2015
@nikomatsakis
Copy link
Contributor Author

triage: P-high (1.0)

@rust-highfive rust-highfive added the P-medium Medium priority label Apr 2, 2015
@rust-highfive rust-highfive added this to the 1.0 milestone Apr 2, 2015
@nikomatsakis nikomatsakis self-assigned this Apr 2, 2015
@nikomatsakis
Copy link
Contributor Author

@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:

  • Multiple impls can be applied to &MyType
    • First candidate is impl X, on line 123
    • Second candidate is in crate A: impl<T> Foo for &T

However, the last part is a bit tricky since the impl must be reconstructed from metadata, but we can start with even just printing &MyType. It's "obvious" from the impl decl (sort of...) once you know what's going on, but helpful to see it printed when you don't.

@flaper87 flaper87 assigned flaper87 and unassigned nikomatsakis Apr 3, 2015
@steveklabnik steveklabnik removed this from the 1.0 milestone May 21, 2015
@nikomatsakis
Copy link
Contributor Author

I'm encouraging @aturon to take this on :)

aturon added a commit to aturon/rust that referenced this issue Dec 16, 2015
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
bors added a commit that referenced this issue Dec 16, 2015
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
@nikomatsakis nikomatsakis reopened this Dec 22, 2015
@nikomatsakis
Copy link
Contributor Author

I still consider the error messages fairly inscrutable, even with @aturon's commit.

@nikomatsakis
Copy link
Contributor Author

In particular, I think we should tell you where we failed to use negative reasoning because of orphan rules.

@aturon
Copy link
Member

aturon commented Dec 22, 2015

@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.

@nikomatsakis
Copy link
Contributor Author

@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:

conflicting implementations of trait FromSqlRow<(_, _), _> for type (_, _)

which is definitely a good start. But I think it'd be great if it could add:

the danger is that another crate might write an impl like:

impl FromSql<(i32, i32), MyLocalType> for (i32, i32)

which would induce overlap.

@huonw
Copy link
Member

huonw commented May 20, 2016

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.

@Mark-Simulacrum Mark-Simulacrum added the C-bug Category: This is a bug. label Jul 22, 2017
@Mark-Simulacrum Mark-Simulacrum marked this as a duplicate of #36162 Jul 26, 2017
frewsxcv added a commit to frewsxcv/rust that referenced this issue Aug 29, 2017
…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
```
frewsxcv added a commit to frewsxcv/rust that referenced this issue Aug 29, 2017
…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
```
frewsxcv added a commit to frewsxcv/rust that referenced this issue Aug 29, 2017
…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
```
bors added a commit that referenced this issue Sep 6, 2017
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
```
bors added a commit that referenced this issue Oct 25, 2017
…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
```
@oli-obk oli-obk added the E-hard Call for participation: Hard difficulty. Experience needed to fix: A lot. label May 24, 2019
@jonas-schievink jonas-schievink added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Feb 6, 2020
@estebank
Copy link
Contributor

estebank commented Aug 3, 2023

Current output:

error[E0119]: conflicting implementations of trait `FromSqlRow<(_, _), _>` for type `(_, _)`
 --> src/main.rs:9:1
  |
5 | impl<T, ST, DB> FromSqlRow<ST, DB> for T where
  | ---------------------------------------- first implementation here
...
9 | impl<A, B, TA, TB, DB> FromSqlRow<(TA, TB), DB> for (A, B) where
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(_, _)`
  |
  = note: downstream crates may implement trait `FromSql<(_, _), _>` for type `(_, _)`
error[E0119]: conflicting implementations of trait `From<MyError<_>>` for type `MyError<_>`
 --> src/main.rs:9:1
  |
9 | impl<S: Storage> From<S::Error> for MyError<S> {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: conflicting implementation in crate `core`:
          - impl<T> From<T> for T;
          - ```

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints C-bug Category: This is a bug. E-hard Call for participation: Hard difficulty. Experience needed to fix: A lot. P-medium Medium priority T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

10 participants