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

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

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.

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

No branches or pull requests

3 participants