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

Unhelpful error message when using bad receiver type #57994

Closed
RalfJung opened this issue Jan 30, 2019 · 14 comments · Fixed by #69255 or #114654
Closed

Unhelpful error message when using bad receiver type #57994

RalfJung opened this issue Jan 30, 2019 · 14 comments · Fixed by #69255 or #114654
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-traits Area: Trait system 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

@RalfJung
Copy link
Member

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
Copy link
Contributor

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
Copy link
Contributor

estebank commented Sep 26, 2019

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) {
  |           ^^^^^^^^^^^^^^^^

@estebank estebank added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Sep 26, 2019
@Nemo157
Copy link
Member

Nemo157 commented Oct 15, 2019

@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 estebank added D-invalid-suggestion Diagnostics: A structured suggestion resulting in incorrect code. D-newcomer-roadblock Diagnostics: Confusing error or lint; hard to understand for new users. labels Oct 15, 2019
@estebank estebank added D-confusing Diagnostics: Confusing error or lint that should be reworked. and removed D-invalid-suggestion Diagnostics: A structured suggestion resulting in incorrect code. D-newcomer-roadblock Diagnostics: Confusing error or lint; hard to understand for new users. labels Feb 2, 2020
@estebank
Copy link
Contributor

Triage: we no longer emit the incorrect suggestions.

@estebank
Copy link
Contributor

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
Copy link
Contributor

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.

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
@SNCPlay42
Copy link
Contributor

SNCPlay42 commented Aug 15, 2020

@estebank was a note like you suggested in #57994 (comment) 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
Copy link
Contributor

SNCPlay42 commented Aug 15, 2020

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
Copy link
Contributor

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
Copy link
Contributor

estebank commented Sep 10, 2021

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
Copy link
Contributor

estebank commented Jan 5, 2023

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 added a commit to estebank/rust that referenced this issue Aug 4, 2023
```
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>) {}
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
```

Related to rust-lang#57994, as one of the presented cases can lead to code like
this.
estebank added a commit to estebank/rust that referenced this issue Aug 4, 2023
@estebank
Copy link
Contributor

estebank commented Aug 4, 2023

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 #57994 (comment)?

@RalfJung
Copy link
Member Author

RalfJung commented Aug 4, 2023

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
Copy link
Contributor

estebank commented Aug 9, 2023

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

matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Aug 9, 2023
…diff, r=davidtwco

Detect method not found on arbitrary self type with different mutability

```
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>) {}
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
```

Related to rust-lang#57994, as one of the presented cases can lead to code like this.
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Oct 3, 2023
…dtwco

Suggest `pin!()` instead of `Pin::new()` when appropriate

When encountering a type that needs to be pinned but that is `!Unpin`, suggest using the `pin!()` macro.

Fix rust-lang#57994.
@bors bors closed this as completed in 2c3fd1a Oct 3, 2023
rust-timer added a commit to rust-lang-ci/rust that referenced this issue Oct 3, 2023
Rollup merge of rust-lang#114654 - estebank:suggest-pin-macro, r=davidtwco

Suggest `pin!()` instead of `Pin::new()` when appropriate

When encountering a type that needs to be pinned but that is `!Unpin`, suggest using the `pin!()` macro.

Fix rust-lang#57994.
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-traits Area: Trait system 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
8 participants