Skip to content

Incorrect warning about trait object use when accessing trait method via subtrait #83395

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Closed
hudson-ayers opened this issue Mar 22, 2021 · 5 comments
Labels
C-bug Category: This is a bug.

Comments

@hudson-ayers
Copy link
Contributor

I have found that constructing a struct which implements a Supertrait, and then calling one of the trait methods of that Supertrait via the subtrait leads to a warning about trait objects without an explicit dyn being deprecated. See the following minimal example

pub trait Pin: Configure {}
pub trait Configure {
    fn make_output(&self);
}

pub struct MyPin {}

impl Configure for MyPin {
    fn make_output(&self) {}
}
impl Pin for MyPin {}

fn main() {
    let pin = &mut MyPin {};
    //Configure::make_output(pin); //no warning
    Pin::make_output(pin); //prints a warning
}

I expected this to compile without warning

Instead, I get the following output:

warning: trait objects without an explicit `dyn` are deprecated
  --> src/main.rs:20:5
   |
20 |     hil::Pin::make_output(pin); //prints a warning
   |     ^^^^^^^^ help: use `dyn`: `<dyn hil::Pin>`
   |
   = note: `#[warn(bare_trait_objects)]` on by default

It is very surprising to me that whether I get a warning is dependent on whether or not I call the method directly via the Supertrait rather than via the subtrait. I would have expected those to compile equivalent code.

(This minimal reproduction is based off of encountering this error in a number of places in Tock when upgrading to the latest nightly.)

Meta

This happens on current nightly (2021-03-21) but not on a 2 month old nightly (2021-01-07), or on current stable (1.50.0).

Playground link with the warning: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=c4bb2774141c86d7af6971e1876a203c

@hudson-ayers hudson-ayers added the C-bug Category: This is a bug. label Mar 22, 2021
@memoryruins
Copy link
Contributor

memoryruins commented Mar 23, 2021

The warning was added in #82868

To confirm if the warning and codegen matched, I emitted MIR, which included the following:

_4 = move _5 as &dyn Pin (Pointer(Unsize)); // scope 1 at src/main.rs:16:22: 16:25
StorageDead(_5);                 // scope 1 at src/main.rs:16:24: 16:25
_3 = <dyn Pin as Configure>::make_output(move _4) -> bb1; // scope 1 at src/main.rs:16:5: 16:26

showing that Pin::make_output leads to it coercing into a trait object and calling the supertrait's method.

If we try Configure::make_ouput(pin) / pin.make_output(), no trait objects are involved.

_3 = <MyPin as Configure>::make_output(move _4) -> bb1; // scope 1 at src/main.rs:16:5: 16:22

If we try <MyPin as Pin>::make_output, it errors about make_output not being a method of Pin.

It appears it is correctly warning, though understandably surprising.

@hudson-ayers
Copy link
Contributor Author

Thanks for looking at the MIR. I was worried it would be something like that. Is it a bug that using a supertrait leads to different MIR than using the subtrait? I find that behavior..really unintuitive, though I suppose that this warning does actually help nudge people in the direction of the more performant option.

Should I update the title and issue description? Or just close this?

@memoryruins
Copy link
Contributor

memoryruins commented Mar 23, 2021

Based on rust-lang/lang-team#65 (comment), it seems expected for Subtrait::supertrait_function(x) to be treated as <dyn Subtrait as Supertrait>::supertrait_function(x). Let's see if anyone else would like to add input before editing or closing.
cc @scottmcm @petrochenkov

@petrochenkov
Copy link
Contributor

I confirm that the change is intentional.
make_output is not a trait Pin's method, but rather a type dyn Pin's method, so Pin::make_output doesn't work in the world where Pin is not a type (but dyn Pin is) aka edition 2021, with which bare_trait_objects aims to be compatible.

@hudson-ayers
Copy link
Contributor Author

Thanks for the explanation! I'll close this, though I do still feel that the observed behavior is pretty unintuitive to someone not intimately familiar with how supertraits work in Rust.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
C-bug Category: This is a bug.
Projects
None yet
Development

No branches or pull requests

3 participants