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

Improve E0599 for missing trait bounds (where clauses) #61661

Closed
djc opened this issue Jun 8, 2019 · 8 comments · Fixed by #69255
Closed

Improve E0599 for missing trait bounds (where clauses) #61661

djc opened this issue Jun 8, 2019 · 8 comments · Fixed by #69255
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix` D-confusing Diagnostics: Confusing error or lint that should be reworked. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@djc
Copy link
Contributor

djc commented Jun 8, 2019

For the following example:

struct Foo<T> {
    t: T,
}

struct Inner {
    i: u8,
}

trait Bar {
    fn bar(&self);
}

impl<T> Bar for Foo<T> where T: Clone {
    fn bar(&self) {
        println!("x");
    }
}

fn main() {
    let foo = Foo { t: Inner { i: b'i' } };
    foo.bar();
}

The error message is:

error[E0599]: no method named `bar` found for type `Foo<Inner>` in the current scope
  --> src/main.rs:21:9
   |
1  | struct Foo<T> {
   | ------------- method `bar` not found for this
...
21 |     foo.bar();
   |         ^^^
   |
   = note: the method `bar` exists but the following trait bounds were not satisfied:
           `Foo<Inner> : Bar`
   = help: items from traits can only be used if the trait is implemented and in scope
   = note: the following trait defines an item `bar`, perhaps you need to implement it:
           candidate #1: `Bar`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0599`.
error: Could not compile `playground`.

To learn more, run the command again with --verbose.

Foo<T> does actually implement Bar, and this makes the suggestions from the compiler misleading in this case: there is already an implementation for Foo<T> : Bar, and Bar is already in scope. It would be much more helpful if the compiler could suggest the trait bounds necessary to satisfy the requirement.

This seems very similar to what @estebank suggested in #9082 (comment).

@djc djc changed the title E0599 Improve E0599 for missing trait bounds (where clauses) Jun 8, 2019
@estebank estebank added A-diagnostics Area: Messages for errors, warnings, and lints T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jun 8, 2019
@estebank estebank added A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix` D-confusing Diagnostics: Confusing error or lint that should be reworked. labels Nov 15, 2019
@estebank
Copy link
Contributor

estebank commented Feb 18, 2020

Would the following be enough of an improvement?

error[E0599]: no method named `bar` found for struct `Foo<Inner>` in the current scope
   --> file5.rs:21:9
    |
1   |   struct Foo<T> {
    |   ------------- method `bar` not found for this
...
21  |       foo.bar();
    |           ^^^ method not found in `Foo<Inner>`
    |
    = note: the method `bar` exists but the following trait bounds were not satisfied:
            `Inner: std::clone::Clone` which is required by `Foo<Inner>: Bar`
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `bar`, perhaps you need to implement it:
            candidate #1: `Bar`

@djc
Copy link
Contributor Author

djc commented Feb 18, 2020

This is a great improvement! In this context, the latter three lines are somewhat confusing:

    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `bar`, perhaps you need to implement it:
            candidate #1: `Bar`

Since they actually don't apply for this case.

Also, it might help to elaborate the lines before that, maybe an explicit mention of <Foo<Inner> as Bar>::bar() can be thrown in?

@estebank
Copy link
Contributor

What do you think of the following output?

error[E0599]: no method named `bar` found for struct `Foo<Inner>` in the current scope
  --> file5.rs:21:9
   |
1  | struct Foo<T> {
   | ------------- method `bar` not found for this
...
5  | struct Inner {
   | ------------ this type doesn't satisfy the bound `std::clone::Clone`
...
21 |     foo.bar();
   |         ^^^ method not found in `Foo<Inner>`
   |
   = note: the method `bar` exists but the following trait bounds were not satisfied:
           `Inner: std::clone::Clone`
   = help: items from traits can only be used if the trait is implemented and in scope
   = note: the following trait defines an item `bar`, perhaps you need to implement it:
           candidate #1: `Bar`

Screen Shot 2020-02-18 at 12 05 00 AM

I'll look into removing the last few lines as I agree that they are somewhat misleading here and obscure the solution, but we have to make sure we don't actually hide information useful for other cases with different underlying problems.

@djc
Copy link
Contributor Author

djc commented Feb 18, 2020

Yeah, this would be even better. I still think it would be nice to specifically call out Bar somewhere/somehow as the provider of bar() and the implementer specifying the trait bound (though it doesn't need the full location treatment).

@estebank
Copy link
Contributor

What about this?

error[E0599]: no method named `bar` found for struct `Foo<Inner>` in the current scope
  --> file5.rs:24:9
   |
1  | struct Foo<T> {
   | ------------- method `bar` not found for this
...
5  | struct Inner {
   | ------------ the method `bar` but this type doesn't satisfy the bound `Inner: std::clone::Clone`
...
9  | trait Bar {
   | --------- this trait defines an item `bar`
...
24 |     foo.bar();
   |         ^^^ method not found in `Foo<Inner>`
   |
   = help: items from traits can only be used if the trait is implemented and in scope

@djc
Copy link
Contributor Author

djc commented Feb 18, 2020

I find the four separate span blocks a bit distracting. I would opt for something like this:

error[E0599]: no method named `bar` found for struct `Foo<Inner>` in the current scope
  --> file5.rs:24:9
   |
1  | struct Foo<T> {
   | ------------- method `bar` not found for this
...
5  | struct Inner {
   | ------------ this type doesn't satisfy the bound `Inner: std::clone::Clone`
   |
   = note: the method `bar` exists but the following trait bounds were not satisfied:
           `Inner: std::clone::Clone` which is required by `Foo<Inner>: Bar`
   = help: items from traits can only be used if the trait is implemented and in scope

On the other hand, a span block pointing to the impl Bar for Foo<Inner> might be useful.

@estebank
Copy link
Contributor

The current output in the PR looks like this

error[E0599]: no method named `bar` found for struct `Foo<Inner>` in the current scope
  --> file5.rs:21:9
   |
1  | struct Foo<T> {
   | -------------
   | |
   | method `bar` not found for this
   | doesn't satisfy `Foo<Inner>: Bar`
...
5  | struct Inner {
   | ------------ doesn't satisfy `Inner: std::clone::Clone`
...
9  | trait Bar {
   | --------- `Bar` defines an item `bar`, perhaps you need to implement it
...
21 |     foo.bar();
   |         ^^^ method not found in `Foo<Inner>`
   |
   = note: the method `bar` exists but the following trait bounds were not satisfied:
           `Inner: std::clone::Clone` which is required by `Foo<Inner>: Bar`
   = help: items from traits can only be used if the trait is implemented and in scope

I'm a bit hesitant about removing spans at this point. It might be true that changing it to the following could be a good idea, but I'm not sure:

error[E0599]: no method named `bar` found for struct `Foo<Inner>` in the current scope
  --> file5.rs:21:9
   |
1  | struct Foo<T> {
   | ------------- method `bar` not found for this
...
5  | struct Inner {
   | ------------ doesn't satisfy `Inner: std::clone::Clone`
...
21 |     foo.bar();
   |         ^^^ method not found in `Foo<Inner>`
   |
   = note: the method `bar` exists but the following trait bounds were not satisfied:
           `Inner: std::clone::Clone` which is required by `Foo<Inner>: Bar`
   = help: items from traits can only be used if the trait is implemented and in scope
   = note: the following trait defines an item `bar`, perhaps you need to implement it:
           candidate #1: `Bar`

@djc
Copy link
Contributor Author

djc commented Feb 20, 2020

Let's see if we can get some wisdom from the crowd.

Dylan-DPC-zz pushed a commit to Dylan-DPC-zz/rust that referenced this issue Feb 27, 2020
Dylan-DPC-zz pushed a commit to Dylan-DPC-zz/rust that referenced this issue Feb 28, 2020
@bors bors closed this as completed in 55aee8d Feb 29, 2020
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 A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix` D-confusing Diagnostics: Confusing error or lint that should be reworked. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants