Skip to content

Multiple applicable items in scope suggests wrong code for references to trait objects #58988

Open
@hcpl

Description

@hcpl

Suggestions from E0034 prepend & to expressions as a string regardless of whether the result type-checks.

Example:

trait Foo { fn baz(&self) -> u8; }
trait Bar { fn baz(&self) -> u64; }
trait Quux: Foo + Bar {}

struct Spam;

impl Foo for Spam { fn baz(&self) -> u8 { 10 } }
impl Bar for Spam { fn baz(&self) -> u64 { 10000 } }
impl Quux for Spam {}

fn main() {
    let quux = &Spam as &dyn Quux;
    quux.baz();
    //Foo::baz(&quux); // what compiler suggests
    //Foo::baz(quux); // correct suggestion
    
    (&Spam as &dyn Quux).baz();
    //Foo::baz(&&Spam as &dyn Quux); // what compiler suggests
    //Foo::baz(&Spam as &dyn Quux); // correct suggestion
}

Playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=97c044b74af4a3798f01b223ca868bd8.

Errors
error[E0034]: multiple applicable items in scope
  --> src/main.rs:13:10
   |
13 |     quux.baz();
   |          ^^^ multiple `baz` found
   |
note: candidate #1 is defined in the trait `Foo`
  --> src/main.rs:1:13
   |
1  | trait Foo { fn baz(&self) -> u8; }
   |             ^^^^^^^^^^^^^^^^^^^^
   = help: to disambiguate the method call, write `Foo::baz(&quux)` instead
note: candidate #2 is defined in the trait `Bar`
  --> src/main.rs:2:13
   |
2  | trait Bar { fn baz(&self) -> u64; }
   |             ^^^^^^^^^^^^^^^^^^^^^
   = help: to disambiguate the method call, write `Bar::baz(&quux)` instead

error[E0034]: multiple applicable items in scope
  --> src/main.rs:17:26
   |
17 |     (&Spam as &dyn Quux).baz();
   |                          ^^^ multiple `baz` found
   |
note: candidate #1 is defined in the trait `Foo`
  --> src/main.rs:1:13
   |
1  | trait Foo { fn baz(&self) -> u8; }
   |             ^^^^^^^^^^^^^^^^^^^^
   = help: to disambiguate the method call, write `Foo::baz(&&Spam as &Quux)` instead
note: candidate #2 is defined in the trait `Bar`
  --> src/main.rs:2:13
   |
2  | trait Bar { fn baz(&self) -> u64; }
   |             ^^^^^^^^^^^^^^^^^^^^^
   = help: to disambiguate the method call, write `Bar::baz(&&Spam as &Quux)` instead

Notice how in the second case, the suggested code has &&Spam as &Quux instead of &(&Spam as &Quux) which is equivalent to the first case.

Applying suggestions from these errors will produce new errors:

Errors
error[E0277]: the trait bound `&dyn Quux: Foo` is not satisfied
  --> src/main.rs:14:5
   |
14 |     Foo::baz(&quux); // what compiler suggests
   |     ^^^^^^^^ the trait `Foo` is not implemented for `&dyn Quux`
   |
note: required by `Foo::baz`
  --> src/main.rs:1:13
   |
1  | trait Foo { fn baz(&self) -> u8; }
   |             ^^^^^^^^^^^^^^^^^^^^

error[E0277]: the trait bound `&Spam: Quux` is not satisfied
  --> src/main.rs:18:14
   |
18 |     Foo::baz(&&Spam as &dyn Quux); // what compiler suggests
   |              --^^^^
   |              |
   |              the trait `Quux` is not implemented for `&Spam`
   |              help: consider removing 1 leading `&`-references
   |
   = help: the following implementations were found:
             <Spam as Quux>
   = note: required for the cast to the object type `dyn Quux`

The same thing happens for mutable references where &mut is prepended instead.

Reproducible on all stable Rust versions back to 1.16.0, beta and nightly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-dyn-traitArea: trait objects, vtable layoutA-suggestion-diagnosticsArea: Suggestions generated by the compiler applied by `cargo fix`D-incorrectDiagnostics: A diagnostic that is giving misleading or incorrect information.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