Skip to content

trait object: specific use case of variance and/or coercion #108999

Open
@plafer

Description

Filing this as a bug report because that's my best guess for what I believe is an inconsistency. Or perhaps simply the reference would need to be updated to explain the following.

Note that I will use <: to denote a "subtype" relationship.

I tried this code:

trait Module {}

struct Foo {
    module_box: Box<dyn Module + 'static>,
    module_rc: Rc<dyn Module + 'static>,
}

impl Foo {
    fn mut_box<'s>(&'s mut self) -> &'s mut (dyn Module + 's) {
        // this works
        self.module_box.as_mut() // : &'s mut (dyn Module + 'static)
    }

    fn mut_rc<'s>(&'s mut self) -> Option<&'s mut (dyn Module + 's)> {
        // this doesn't work
        Rc::get_mut(&mut self.module_rc) // : Option<&'s mut (dyn Module + 'static)>
        
        // but this does
//      match Rc::get_mut(&mut self.module_rc) {
//        Some(m) => Some(m),
//        None => None,
//      }
    }
}

I have 2 related questions:

  1. why does the mut_box() implementation work?
  2. why doesn't the mut_rc() implement work?

For (1), I first assumed that subtyping/variance was the reason, since (dyn Module + 'static) <: (dyn Module + 's) (although I wasn't able to 100% confirm). However, according to the reference, &'a mut T is invariant over T; so if I'm reading this correctly, &'s mut (dyn Module + 'static) is NOT a subtype of &'s mut (dyn Module + 's). I then thought maybe an implicit coercion could then explain why it compiled, but was not able to find one in the list of coercion types. Is this a bug?

Question (2) is very similar, except that the whole thing is wrapped in an Option, which seems to be the reason why it fails; the commented-out code unwraps the Option, which I believe sends us back to (1). Do we expect Rc::get_mut(&mut self.module_rc) to work, given that (1) works?

Meta

rustc --version --verbose:

rustc 1.68.0 (2c8cc3432 2023-03-06)
binary: rustc
commit-hash: 2c8cc343237b8f7d5a3c3703e3a87f2eb2c54a74
commit-date: 2023-03-06
host: aarch64-apple-darwin
release: 1.68.0
LLVM version: 15.0.6
Backtrace

error: lifetime may not live long enough
  --> fool/src/main.rs:21:9
   |
19 |     fn mut_rc<'s>(&'s mut self) -> Option<&'s mut (dyn Module + 's)> {
   |               -- lifetime `'s` defined here
20 |         // this doesn't work
21 |         Rc::get_mut(&mut self.module_rc) // : Option<&'s mut (dyn Module + 'static)>
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'s` must outlive `'static`
   |
   = note: requirement occurs because of a mutable reference to `dyn Module`
   = note: mutable references are invariant over their type parameter
   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance

error: could not compile `rust` due to previous error

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    A-DSTsArea: Dynamically-sized types (DSTs)A-trait-objectsArea: trait objects, vtable layoutA-trait-systemArea: Trait systemC-bugCategory: This is a bug.D-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