Skip to content

E0599 message misleads by framing inapplicable methods as "not found" in the "current scope" #138476

Open
@kornelski

Description

@kornelski

Code

struct Bork<T = ()>(T);

impl Bork {
    fn this_method_exists(&self) {}
}

fn main() {
    let bork = Bork(0u8);

    bork.this_method_exists();
}

playground

Current output

error[E0599]: no method named `this_method_exists` found for struct `Bork<u8>` in the current scope
  --> src/main.rs:10:10
   |
1  | pub struct Bork<T = ()>(T);
   | ----------------------- method `this_method_exists` not found for this struct
...
10 |     bork.this_method_exists();
   |          ^^^^^^^^^^^^^^^^^^ method not found in `Bork<u8>`
   |
   = note: the method was found for
           - `Bork`

Desired output

Ideally:

error[E0599]: the method `this_method_exists` can't be called on struct `Bork<u8>`
  --> src/main.rs:12:10
   |
12 |     bork.this_method_exists();
   |     ^^^^ expected `Bork<()>`, found `Bork<u8>`
...
1  | impl Bork {
   |     fn this_method_exists(&self) {}
   |        ------------------ method found for `Bork<()>`
...
11 |     let bork = Bork(0u8);
   |                     ---   
   |                     |
   |                     type inferred due to this

but primarily I'd just like to avoid the misleading "no method named found … in the current scope".

Rationale and extra context

E0599 (NoAssociatedItem) handles a lot of different error cases, some with different messages. My issue is specifically with the phrasing of the method case:

no method named found for … in the current scope

The first half, "no method named found" may be technically true from compiler's internal perspective — it searched a fully-qualified type and found nothing applicable. However, to an average user it sounds like "file not found". It can easily be interpreted as "you've made a typo in the method name".

This ends up being very confusing when the method actually exists. The user may be able to easily find the method they mean to call — people don't stop searching for a method when trait bounds aren't satisfied! This makes it puzzling when the compiler "can't" find the method. The error message makes it sound like there was no method found with this name, and the search simply failed due to lack of any methods named like this. It doesn't explain the subtlety that it was a more complex kind of search for a fully qualified path that has all the required type arguments (some span notes do a good job of clarifying specific cases, but the initial error message remains puzzling).

The last part "in the current scope" has issues too:

In the current scope implies there may be other scopes where the method can be found, but that's not always true. When a method is called on a wrong type (typically the right struct with wrong generic parameters), it's not a scope problem, it's a type mismatch: there is no scope at all in which it could be "found". In this case the message misleads user to think "have I got the right scope?" instead of "have I got the right type?". A concrete type may be technically a kind of scope in the name resolver, but to users scopes are modules and blocks of code.

Even in cases when it is really a scope issue (such as importing a trait), it makes the message a sort of a garden-path sentence. The message starts off like it's trying to say "method not found", but the correct interpretation is "the method can be found, but you need to import a trait into this scope".

My suggestion for fixing this:

  • If an inherent method with that name exists (ignoring mismatch in generic args), then don't phrase the error as "method named not found", but as something like "method can't be called"
  • Don't add "in the current scope" unless there's a trait with such method, and the trait isn't in scope.
  • This diagnostic already has lots of good suggestions. Many of them could replace the error message with the specific case.
  • Maybe split out cases out of E0599? Failure of resolve_fully_qualified_call may be a single cause from the compiler's perspective, but from user perspective importing traits into scope is a different case than correcting receiver's generic type arguments, and different from adding Sized bounds, and different from adding a forgotten .await.

Other cases

Axum has Router::with_state that uses generic type in a counter-intuitive way. Axum's Router relies heavily on type inference to work, so the generic type mismatch is impossible to spot in the source code.

Rust ends up suggesting to use wrong method instead of suggesting correcting the generic type:

error[E0599]: no method named `into_make_service` found for struct `Router<State>` in the current scope
   |
help: there is a method `into_service` with a similar name
   |
34 -     router.into_make_service();
34 +     router.into_service();

Rust Version

rustc 1.87.0-nightly (9fb94b32d 2025-03-10)

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-diagnosticsArea: Messages for errors, warnings, and lintsT-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