rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
97.06k stars 12.54k forks source link

Unhelpful error message when using bad receiver type #57994

Closed RalfJung closed 11 months ago

RalfJung commented 5 years ago

Consider the following piece of code:

use std::pin::Pin;

trait Test {
    fn test(self: Pin<&mut Self>);
}

fn foo(t: impl Test) {
    t.test()
}

The error here is that test can only be called on Pin<&mut Self>, so t.test does not work. But the error message is less than helpful:

error[E0599]: no method named `test` found for type `impl Test` in the current scope
 --> src/lib.rs:8:7
  |
8 |     t.test()
  |       ^^^^
  |
  = help: items from traits can only be used if the trait is implemented and in scope
  = note: the following trait defines an item `test`, perhaps you need to implement it:
          candidate #1: `Test`

It suggests I import a trait that is already in scope. This leads down the totally wrong path -- not showing the "help" and "note" at all would be better than this. Ideally it could point out the receiver type mismatch.

memoryruins commented 5 years ago

Re-posting from #63966 since it was closed in favor of this thread.


playground 1.39.0-nightly 2019-08-23 9eae1fc0ea9b00341b8f

mod First {
    trait Foo { fn m(self: Box<Self>); }
    fn foo<T: Foo>(a: T) {
        a.m();
    }
}
mod Second {
    trait Bar { fn m(self: std::sync::Arc<Self>); }
    fn bar(b: impl Bar) {
        b.m();
    }
}
help: the following traits define an item `m`, perhaps you need to restrict type parameter `T` with one of them:
  |
3 |     fn foo<T: First::Foo + Foo>(a: T) {
  |            ^^^^^^^^^^^^^^^
3 |     fn foo<T: Second::Bar + Foo>(a: T) {
  |            ^^^^^^^^^^^^^^^^

The above suggests a trait from another module with a different name

help: the following traits define an item `m`, perhaps you need to restrict type parameter `impl Bar` with one of them:
   |
9  |     fn bar(b: impl Bar: First::Foo + {
   |               ^^^^^^^^^^^^^^^^^^^^^^
9  |     fn bar(b: impl Bar: Second::Bar + {
   |               ^^^^^^^^^^^^^^^^^^^^^^^

and the next suggestion isn't syntactically correct.

estebank commented 5 years ago

Current output:

error[E0599]: no method named `m` found for type `T` in the current scope
 --> src/lib.rs:4:11
  |
4 |         a.m();
  |           ^ method not found in `T`
  |
  = help: items from traits can only be used if the type parameter is bounded by the trait
help: the following traits define an item `m`, perhaps you need to restrict type parameter `T` with one of them:
  |
3 |     fn foo<T: First::Foo + Foo>(a: T) {
  |            ^^^^^^^^^^^^^^^
3 |     fn foo<T: Second::Bar + Foo>(a: T) {
  |            ^^^^^^^^^^^^^^^^

error[E0599]: no method named `m` found for type `impl Bar` in the current scope
  --> src/lib.rs:10:11
   |
10 |         b.m();
   |           ^ method not found in `impl Bar`
   |
   = help: items from traits can only be used if the type parameter is bounded by the trait
help: the following traits define an item `m`, perhaps you need to restrict type parameter `impl Bar` with one of them:
   |
9  |     fn bar(b: impl Bar + First::Foo) {
   |               ^^^^^^^^^^^^^^^^^^^^^
9  |     fn bar(b: impl Bar + Second::Bar) {
   |               ^^^^^^^^^^^^^^^^^^^^^^
error[E0599]: no method named `test` found for type `impl Test` in the current scope
 --> src/lib.rs:8:7
  |
8 |     t.test()
  |       ^^^^ method not found in `impl Test`
  |
  = help: items from traits can only be used if the type parameter is bounded by the trait
help: the following trait defines an item `test`, perhaps you need to restrict type parameter `impl Test` with it:
  |
7 | fn foo(t: impl Test + Test) {
  |           ^^^^^^^^^^^^^^^^
Nemo157 commented 4 years ago

@rustbot modify labels to +AsyncAwait-OnDeck

This error message comes up a lot when users attempt to manually implement Future or the associated traits like futures::io::{AsyncRead, AsyncWrite} by delegating to a field without pinning it.

estebank commented 4 years ago

Triage: we no longer emit the incorrect suggestions.

estebank commented 4 years ago

Is the following output acceptable?

error[E0599]: no method named `test` found for type parameter `impl Test` in the current scope
 --> file5.rs:8:7
  |
4 |     fn test(self: Pin<&mut Self>);
  |                   -------------- the method might not be found because of this arbitrary self type
...
8 |     t.test()
  |       ^^^^ method not found in `impl Test`
jebrosen commented 4 years ago

That wording does indicates the actual problem (hooray!), but it also doesn't feel very newcomer-friendly to me because of the phrase "arbitrary self type". IMO something like "test() is called on an X but must be called on a Pin<&mut X>" would be more obvious, but I can see that getting difficult to implement in the error messages.

SNCPlay42 commented 4 years ago

@estebank was a note like you suggested in https://github.com/rust-lang/rust/issues/57994#issuecomment-588534790 implemented? (yes, but only for trait methods?)

Currently this code

use core::pin::Pin;
struct S;

impl S {
    fn x(self: Pin<&mut Self>) {
    }
}

fn main() {
    S.x();
}

Outputs

error[E0599]: no method named `x` found for struct `S` in the current scope
  --> src/main.rs:10:7
   |
2  | struct S;
   | --------- method `x` not found for this
...
10 |     S.x();
   |       ^ method not found in `S`

error: aborting due to previous error

Without any hint about there being a method by that name with an unusual receiver type.

Not sure whether I should file a new issue or ask for this one to be reopened.

SNCPlay42 commented 4 years ago

Also fails to provide a hint on opaque Futures from async fns:

use std::future::Future; //would be necessary to call `poll` if the receiver type was correct

async fn f() {

}

fn foo(cx: &mut std::task::Context) {
    f().poll(cx);
}

Outputs

error[E0599]: no method named `poll` found for opaque type `impl std::future::Future` in the current scope
 --> src/lib.rs:8:9
  |
8 |     f().poll(cx);
  |         ^^^^ method not found in `impl std::future::Future`

warning: unused import: `std::future::Future`
 --> src/lib.rs:1:5
  |
1 | use std::future::Future; //would be necessary to call `poll` if the receiver type was correct
  |     ^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(unused_imports)]` on by default

error: aborting due to previous error; 1 warning emitted
estebank commented 3 years ago

Triage: no change.

Yet another error that needs to be accounted for:

error[E0277]: the trait bound `S: Deref` is not satisfied
  --> src/main.rs:10:14
   |
10 |     Pin::new(S).x();
   |              ^ the trait `Deref` is not implemented for `S`
   |
   = note: required by `Pin::<P>::new`

error[E0599]: no method named `x` found for struct `Pin<S>` in the current scope
  --> src/main.rs:10:17
   |
10 |     Pin::new(S).x();
   |                 ^ method not found in `Pin<S>`
estebank commented 3 years ago

Current output for the first comment:

error[E0599]: no method named `m` found for type parameter `T` in the current scope
 --> src/lib.rs:4:11
  |
2 |     trait Foo { fn m(self: Box<Self>); }
  |                    -       --------- the method might not be found because of this arbitrary self type
  |                    |
  |                    the method is available for `Box<T>` here
3 |     fn foo<T: Foo>(a: T) {
4 |         a.m();
  |           ^ method not found in `T`
...
8 |     trait Bar { fn m(self: std::sync::Arc<Self>); }
  |                            -------------------- the method might not be found because of this arbitrary self type
  |
help: consider wrapping the receiver expression with the appropriate type
  |
4 |         Box::new(a).m();
  |         +++++++++ +

error[E0599]: no method named `m` found for type parameter `impl Bar` in the current scope
  --> src/lib.rs:10:11
   |
2  |     trait Foo { fn m(self: Box<Self>); }
   |                            --------- the method might not be found because of this arbitrary self type
...
8  |     trait Bar { fn m(self: std::sync::Arc<Self>); }
   |                    -       -------------------- the method might not be found because of this arbitrary self type
   |                    |
   |                    the method is available for `Arc<impl Bar>` here
9  |     fn bar(b: impl Bar) {
10 |         b.m();
   |           ^ method not found in `impl Bar`
   |
help: consider wrapping the receiver expression with the appropriate type
   |
10 |         Arc::new(b).m();
   |         +++++++++ +

Current output for my comment above (it should suggest &mut S instead of &S, but it's might be good enough):

error[E0277]: the trait bound `S: Deref` is not satisfied
   --> src/main.rs:10:14
    |
10  |     Pin::new(S).x();
    |              ^
    |              |
    |              expected an implementor of trait `Deref`
    |              help: consider borrowing here: `&S`
    |
note: required by `Pin::<P>::new`

error[E0599]: no method named `x` found for struct `Pin` in the current scope
  --> src/main.rs:10:17
   |
10 |     Pin::new(S).x();
   |                 ^ method not found in `Pin<S>`

Current output for the previous comment (it doesn't fix the issue because f: !Unpin, then suggests Box::pin which gives you another E0599):

error[E0599]: no method named `poll` found for opaque type `impl Future` in the current scope
  --> src/lib.rs:8:9
   |
8  |     f().poll(cx);
   |         ^^^^ method not found in `impl Future`
   |
help: consider wrapping the receiver expression with the appropriate type
   |
8  |     Pin::new(&mut f()).poll(cx);
   |     +++++++++++++    +

Current output for the comment prior to that, which I considered solved:

error[E0599]: no method named `x` found for struct `S` in the current scope
  --> src/main.rs:10:7
   |
2  | struct S;
   | --------- method `x` not found for this
...
5  |     fn x(self: Pin<&mut Self>) {
   |        - the method is available for `Pin<&mut S>` here
...
10 |     S.x();
   |       ^ method not found in `S`
   |
help: consider wrapping the receiver expression with the appropriate type
   |
10 |     Pin::new(&mut S).x();
   |     +++++++++++++  +
estebank commented 1 year ago

Fixed:

error[[E0599]](https://doc.rust-lang.org/nightly/error-index.html#E0599): no method named `m` found for type parameter `T` in the current scope
 --> src/lib.rs:4:11
  |
2 |     trait Foo { fn m(self: Box<Self>); }
  |                    -       --------- the method might not be found because of this arbitrary self type
  |                    |
  |                    the method is available for `Box<T>` here
3 |     fn foo<T: Foo>(a: T) {
  |            - method `m` not found for this type parameter
4 |         a.m();
  |           ^ method not found in `T`
...
8 |     trait Bar { fn m(self: std::sync::Arc<Self>); }
  |                            -------------------- the method might not be found because of this arbitrary self type
  |
help: consider wrapping the receiver expression with the appropriate type
  |
4 |         Box::new(a).m();
  |         +++++++++ +

error[[E0599]](https://doc.rust-lang.org/nightly/error-index.html#E0599): no method named `m` found for type parameter `impl Bar` in the current scope
  --> src/lib.rs:10:11
   |
2  |     trait Foo { fn m(self: Box<Self>); }
   |                            --------- the method might not be found because of this arbitrary self type
...
8  |     trait Bar { fn m(self: std::sync::Arc<Self>); }
   |                    -       -------------------- the method might not be found because of this arbitrary self type
   |                    |
   |                    the method is available for `Arc<impl Bar>` here
9  |     fn bar(b: impl Bar) {
   |               -------- method `m` not found for this type parameter
10 |         b.m();
   |           ^ method not found in `impl Bar`
   |
help: consider wrapping the receiver expression with the appropriate type
   |
10 |         Arc::new(b).m();
   |         +++++++++ +

Needs to further refine mutability suggested, when using Pin::new(&S) the error doesn't mention that the method is available for Pin::new(&mut S), and the E0599 is redundant.

error[[E0277]](https://doc.rust-lang.org/nightly/error-index.html#E0277): the trait bound `S: Deref` is not satisfied
  --> src/main.rs:10:14
   |
10 |     Pin::new(S).x();
   |     -------- ^ the trait `Deref` is not implemented for `S`
   |     |
   |     required by a bound introduced by this call
   |
note: required by a bound in `Pin::<P>::new`
  --> /rustc/659e169d37990b9c730a59a96081f2ef7afbe8f1/library/core/src/pin.rs:501:5
help: consider borrowing here
   |
10 |     Pin::new(&S).x();
   |              +
10 |     Pin::new(&mut S).x();
   |              ++++

error[[E0599]](https://doc.rust-lang.org/nightly/error-index.html#E0599): no method named `x` found for struct `Pin` in the current scope
  --> src/main.rs:10:17
   |
10 |     Pin::new(S).x();
   |                 ^ method not found in `Pin<S>`

Gives a suggestion but it doesn't lead to working code:

error[[E0599]](https://doc.rust-lang.org/nightly/error-index.html#E0599): no method named `poll` found for opaque type `impl Future<Output = ()>` in the current scope
 --> src/lib.rs:8:9
  |
8 |     f().poll(cx);
  |         ^^^^ method not found in `impl Future<Output = ()>`
 --> /rustc/659e169d37990b9c730a59a96081f2ef7afbe8f1/library/core/src/future/future.rs:105:8
  |
  = note: the method is available for `Pin<&mut impl Future<Output = ()>>` here
  |
help: consider wrapping the receiver expression with the appropriate type
  |
8 |     Pin::new(&mut f()).poll(cx);
  |     +++++++++++++    +

Fixed

error[[E0599]](https://doc.rust-lang.org/nightly/error-index.html#E0599): no method named `x` found for struct `S` in the current scope
  --> src/main.rs:10:7
   |
2  | struct S;
   | -------- method `x` not found for this struct
...
5  |     fn x(self: Pin<&mut Self>) {
   |        - the method is available for `Pin<&mut S>` here
...
10 |     S.x();
   |       ^ method not found in `S`
   |
help: consider wrapping the receiver expression with the appropriate type
   |
10 |     Pin::new(&mut S).x();
   |     +++++++++++++  +
estebank commented 1 year ago

Only outstanding issue is for the poll case, and I'm not quite sure how we can help the user there (hell, I don't know how to make that code compile myself). @SNCPlay42, what would have been the right code the user should have written for https://github.com/rust-lang/rust/issues/57994#issuecomment-674435883?

RalfJung commented 1 year ago

The code it currently suggests does not even build, so that should definitely be fixed.

Here's how poll can be called:

fn foo(cx: &mut std::task::Context) {
    let mut f = std::pin::pin!(f());
    f.as_mut().poll(cx);
}
estebank commented 1 year ago

@RalfJung I noticed that we already provide an appropriate note on the E0277 to use the pin! macro, but it isn't as prominent as I'd like:

error[E0277]: `[async fn body@src/lib.rs:3:14: 5:2]` cannot be unpinned
 --> src/lib.rs:8:24
  |
3 | async fn f() {
  |              - within this `impl Future<Output = ()>`
...
8 |     std::pin::Pin::new(&mut f()).poll(cx);
  |     ------------------ ^^^^^^^^ within `impl Future<Output = ()>`, the trait `Unpin` is not implemented for `[async fn body@src/lib.rs:3:14: 5:2]`
  |     |
  |     required by a bound introduced by this call
  |
  = note: consider using the `pin!` macro
          consider using `Box::pin` if you need to access the pinned value outside of the current scope
note: required because it appears within the type `impl Future<Output = ()>`
 --> src/lib.rs:3:14
  |
3 | async fn f() {
  |              ^
note: required by a bound in `Pin::<P>::new`
 --> /rustc/f88a8b71cebb730cbd5058c45ebcae1d4d9be377/library/core/src/pin.rs:503:5

Having said that, between https://github.com/rust-lang/rust/pull/114654:

error[E0599]: no method named `poll` found for opaque type `impl Future<Output = ()>` in the current scope
 --> f63.rs:4:9
  |
4 |     f().poll(cx);
  |         ^^^^ method not found in `impl Future<Output = ()>`
  |
  = help: method `poll` found on `Pin<&mut impl Future<Output = ()>>`, see documentation for `std::pin::Pin`
  = help: self type must be pinned to call `Future::poll`, see https://rust-lang.github.io/async-book/04_pinning/01_chapter.html#pinning-in-practice
help: consider pinning the expression
  |
4 ~     let mut pinned = std::pin::pin!(f());
5 ~     pinned.as_mut().poll(cx);
  |

and https://github.com/rust-lang/rust/pull/114469:

error[E0599]: no method named `x` found for struct `Pin<&S>` in the current scope
  --> $DIR/arbitrary_self_type_mut_difference.rs:11:18
   |
LL |     Pin::new(&S).x();
   |                  ^ help: there is a method with a similar name: `y`
   |
note: method is available for `Pin<&mut S>`
  --> $DIR/arbitrary_self_type_mut_difference.rs:6:5
   |
LL |     fn x(self: Pin<&mut Self>) {}
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^

I think we can consider this ticket addressed.