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

Confusing Error Message On Not Specifying Trait Bound In Generic Function Signature #41030

Closed
louy2 opened this issue Apr 3, 2017 · 7 comments · Fixed by #62772
Closed

Confusing Error Message On Not Specifying Trait Bound In Generic Function Signature #41030

louy2 opened this issue Apr 3, 2017 · 7 comments · Fixed by #62772
Labels
A-diagnostics Area: Messages for errors, warnings, and lints C-enhancement Category: An issue proposing an enhancement or a PR with one.

Comments

@louy2
Copy link

louy2 commented Apr 3, 2017

I am working through this Rust-101 tutorial and is faced with such a challenge:

There is a crucial difference to templates in C++: We actually have to declare which traits we want the type to satisfy. If we left away the Minimum, Rust would have complained that we cannot call min. Just try it!

So I tried it. Rust complained, but in a pretty confusing way:

no method named min found for type T in the current scope
note: the method min exists but the following trait bounds were not satisfied: T : std::iter::Iterator
help: items from traits can only be used if the trait is implemented and in scope; the following traits define an item min, perhaps you need to implement one of them:
help: candidate #1: part02::Minimum
help: candidate #2: part07::Minimum
help: candidate #3: std::iter::Iterator

The minimal code that produces the error message is

// main.rs
pub enum SomethingOrNothing<T>  {
    Something(T),
    Nothing,
}
pub use self::SomethingOrNothing::*;

pub trait Minimum : Copy {
    fn min(self, b: Self) -> Self;
}

pub fn vec_min<T/*: Minimum*/>(v: Vec<T>) -> SomethingOrNothing<T> {
    let mut min = Nothing;
    for e in v {
        min = Something(match min {
            Nothing => e,
            // Here, we can now call the `min` function of the trait.
            Something(n) => {
                e.min(n)
            }
        });
    }
    min
}

impl Minimum for i32 {
    fn min(self, b: Self) -> Self {
        if self < b { self } else { b }
    }
}

fn main() {
    let v = vec![18,5,7,3,9,27];
    let min = vec_min(v);
}

The error message tells me that I need to implement a trait. Since I have already implemented it, I would be confused by the error message, and misled by it from the actual reason, failure to declare it in the signature. I think it would be better if the message is changed to

no method named min found for type T in the current scope
note: the method min exists but the following trait bounds were not satisfied: T : std::iter::Iterator
help: items from traits can only be used if the trait is implemented and in scope; the following traits define an item min, perhaps you need to implement declare one of them for T:
help: candidate #1: part02::Minimum
help: candidate #2: part07::Minimum
help: candidate #3: std::iter::Iterator

On the other hand, if I actually drop the block impl Minimum for i32, but declare Minimum in the signature, the error message is

E0277: the trait bound {integer}: Minimum is not satisfied
label: the trait Minimum is not implemented for {integer}
note: required by vec_min

which is straightforward enough.

@sfackler sfackler added the A-diagnostics Area: Messages for errors, warnings, and lints label Apr 3, 2017
@Mark-Simulacrum
Copy link
Member

Today, we suggest that the method exists, but we somehow fail to see that it exists on Minimum in the first note and then latter note it in the second note.

error[E0599]: no method named `min` found for type `T` in the current scope
  --> test.rs:18:19
   |
18 |                 e.min(n)
   |                   ^^^
   |
   = note: the method `min` exists but the following trait bounds were not satisfied:
           `T : std::cmp::Ord`
           `T : std::cmp::Ord`
           `T : std::iter::Iterator`
   = help: items from traits can only be used if the trait is implemented and in scope
   = note: the following traits define an item `min`, perhaps you need to implement one of them:
           candidate #1: `Minimum`
           candidate #2: `core::num::Float`
           candidate #3: `std::cmp::Ord`
           candidate #4: `std::iter::Iterator`

@louy2
Copy link
Author

louy2 commented Jun 21, 2017

It still doesn't help a lot IMO... since the problem is the bound isn't declared in the signature, and nothing regarding declaration is mentioned.

note: the following traits define an item min, perhaps you need to implement one of them:

maybe change to

note: the following traits define an item min, perhaps you need to declare or implement one of them:

@Mark-Simulacrum Mark-Simulacrum added the C-enhancement Category: An issue proposing an enhancement or a PR with one. label Jul 26, 2017
@kornelski
Copy link
Contributor

kornelski commented Oct 3, 2017

I think that can be easily fixed by checking if unsatisfied_predicates is not empty and using a different message in that case https://github.com/rust-lang/rust/blob/master/src/librustc_typeck/check/method/suggest.rs#L175

Do you have suggestion how the error should look like? Does that sound ok?

The method {} cannot be used in the current scope, because the following trait bounds were not satisfied: {}

@louy2
Copy link
Author

louy2 commented Oct 4, 2017

@pornel
I don't think your error message communicates much more than the current one. I also think the error message is already straightforward enough.

From my perspective, I think the problem is one of asymmetry in the help section. It mentioned "items from traits can only be used if the trait is implemented and in scope", but then went on to only suggest "perhaps you need to implement one of them". Excuse me for being insistent on this, but I believe the best way is to remind that to bring function into scope the trait bound needs to be declared as well as implemented.

@louy2
Copy link
Author

louy2 commented Oct 4, 2017

LOL this is actually a duplicate of #21673 . There's even a FIXME note in the source.

@kornelski
Copy link
Contributor

kornelski commented Oct 4, 2017

@louy2 I think we're talking about different cases (which may be another reason to split or reword the message). For methods the message says "method not found", but adds a note saying "the method exists", which I really don't like, because it's very easy to miss the nuance and interpret the message as nonsense "the method does not exist" "but it exists".

I've explained more here:

https://internals.rust-lang.org/t/multiple-variants-of-the-same-erorr-message/6002

@estebank
Copy link
Contributor

With #62772 the output will be:

error[E0599]: no method named `min` found for type `T` in the current scope
  --> file7.rs:18:19
   |
18 |                 e.min(n)
   |                   ^^^
   |
   = note: the method `min` exists but the following trait bounds were not satisfied:
           `&T : std::cmp::Ord`
           `&mut T : std::cmp::Ord`
           `&mut T : std::iter::Iterator`
   = help: items from traits can only be used if the type parameter is bounded by the trait
help: the following traits define an item `min`, perhaps you need to restrict type argument `T` with one of them:
   |
11 | pub fn vec_min<T: Minimum/*: Minimum*/>(v: Vec<T>) -> SomethingOrNothing<T> {
   |                ^^^^^^^^^^
11 | pub fn vec_min<T: std::cmp::Ord/*: Minimum*/>(v: Vec<T>) -> SomethingOrNothing<T> {
   |                ^^^^^^^^^^^^^^^^
11 | pub fn vec_min<T: std::iter::Iterator/*: Minimum*/>(v: Vec<T>) -> SomethingOrNothing<T> {
   |                ^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

Centril added a commit to Centril/rust that referenced this issue Jul 21, 2019
Suggest trait bound on type parameter when it is unconstrained

Given

```
trait Foo { fn method(&self) {} }

fn call_method<T>(x: &T) {
    x.method()
}
```

suggest constraining `T` with `Foo`.

Fix rust-lang#21673, fix rust-lang#41030.
Centril added a commit to Centril/rust that referenced this issue Jul 23, 2019
Suggest trait bound on type parameter when it is unconstrained

Given

```
trait Foo { fn method(&self) {} }

fn call_method<T>(x: &T) {
    x.method()
}
```

suggest constraining `T` with `Foo`.

Fix rust-lang#21673, fix rust-lang#41030.
Centril added a commit to Centril/rust that referenced this issue Jul 24, 2019
Suggest trait bound on type parameter when it is unconstrained

Given

```
trait Foo { fn method(&self) {} }

fn call_method<T>(x: &T) {
    x.method()
}
```

suggest constraining `T` with `Foo`.

Fix rust-lang#21673, fix rust-lang#41030.
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-enhancement Category: An issue proposing an enhancement or a PR with one.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants