Skip to content

Unhelpful error message when using bad receiver type #57994

Description

@RalfJung

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.

Activity

  1. memoryruins commented on Aug 29, 2019

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

  2. estebank commented on Sep 26, 2019

    @estebank
    Contributor

    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) {
      |           ^^^^^^^^^^^^^^^^
    
  3. added
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    on Sep 26, 2019
  4. Nemo157 commented on Oct 15, 2019

    @Nemo157
    Contributor

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

  5. added
    D-invalid-suggestionDiagnostics: A structured suggestion resulting in incorrect code.
    D-newcomer-roadblockDiagnostics: Confusing error or lint; hard to understand for new users.
    on Oct 15, 2019
  6. added
    D-confusingDiagnostics: Confusing error or lint that should be reworked.
    and removed
    D-invalid-suggestionDiagnostics: A structured suggestion resulting in incorrect code.
    D-newcomer-roadblockDiagnostics: Confusing error or lint; hard to understand for new users.
    on Feb 2, 2020
  7. estebank commented on Feb 19, 2020

    @estebank
    Contributor

    Triage: we no longer emit the incorrect suggestions.

  8. estebank commented on Feb 19, 2020

    @estebank
    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`
    
  9. jebrosen commented on Feb 20, 2020

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

  10. 13 remaining items

  11. estebank commented on Aug 4, 2023

    @estebank
    Contributor

    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)?

  12. RalfJung commented on Aug 4, 2023

    @RalfJung
    MemberAuthor

    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);
    }
  13. estebank commented on Aug 9, 2023

    @estebank
    Contributor

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

  14. added a commit that references this issue on Aug 9, 2023
  15. added a commit that references this issue on Aug 14, 2023
    2c3fd1a
  16. added a commit that references this issue on Oct 3, 2023
    535cd8d
  17. added a commit that references this issue on Oct 3, 2023
    d4867d7
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-diagnosticsArea: Messages for errors, warnings, and lintsA-trait-systemArea: Trait systemD-confusingDiagnostics: Confusing error or lint that should be reworked.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions