1

I have the following piece of code (it's a self-contained example I wrote to try to isolate the problem with a slightly bigger piece of code):

trait T<'a> {
    fn insert(&mut self, param: &'a u8) ->();
}

struct Noop {}

impl<'a> T<'a> for Noop {
    fn insert(&mut self, param: &'a u8) { }
}

struct Storage<'a> {
    items: Vec<&'a u8>,
    parent: Box<dyn T<'a>>
}

impl<'a> Storage<'a> {
    fn new(parent: Box<dyn T<'a>>) -> Self { Storage {items: vec![], parent } }
}

impl<'a> T<'a> for Storage<'a> {
    fn insert(&mut self, param: &'a u8)  {
        self.items.push(param);
        self.parent.insert(param);
    }
}

fn foo<'x>(param: &'x u8) {
    let mut one_layer: Storage<'x> = Storage::<'x>::new(Box::new(Noop {}));
    one_layer.insert(param);
    // let mut two_layers: Storage<'x> = Storage::<'x>::new(Box::new(Storage::<'x>::new(Box::new(Noop {}))));
    // two_layers.insert(param);
}

When I uncomment the last two lines, the code starts failing to compile with:

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
  --> src\repro.rs:30:35
   |
30 |     let two_layers: Storage<'x> = Storage::<'x>::new(Box::new(Storage::<'x>::new(Box::new(Noop {}))));
   |                                   ^^^^^^^^^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the lifetime `'x` as defined on the function body at 27:8...
  --> src\repro.rs:27:8
   |
27 | fn foo<'x>(param: &'x u8) {
   |        ^^
note: ...so that the types are compatible
  --> src\repro.rs:30:35
   |
30 |     let two_layers: Storage<'x> = Storage::<'x>::new(Box::new(Storage::<'x>::new(Box::new(Noop {}))));
   |                                   ^^^^^^^^^^^^^^^^^^
   = note: expected  `repro::Storage<'_>`
              found  `repro::Storage<'x>`
   = note: but, the lifetime must be valid for the static lifetime...
note: ...so that the expression is assignable
  --> src\repro.rs:30:54
   |
30 |     let two_layers: Storage<'x> = Storage::<'x>::new(Box::new(Storage::<'x>::new(Box::new(Noop {}))));
   |                                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   = note: expected  `std::boxed::Box<(dyn repro::T<'_> + 'static)>`
              found  `std::boxed::Box<dyn repro::T<'_>>`

It appears that the lifetime inference didn't figure out that Box::new(Noop {})) is supposed to be Box<dyn T<'x>>. How do I get it to work, preferably modifying only the foo function?

I read the error explanation for E0495, but it is very basic and doesn't explain my case.

Karol S
  • 9,028
  • 2
  • 32
  • 45
  • Are you sure that you mean for `insert` to consume `self`, rather than receiving a mutable borrow? – E_net4 Jun 12 '20 at 13:16
  • The [duplicate applied to your question](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=3024362b48144dc3a43cfeb27a857d3c): make the boxed trait object a `Box + 'a>`. With that done you still need to fix other unrelated issues (i.e. you almost certaintly want `&mut self` as the method receiver). – E_net4 Jun 12 '20 at 13:21
  • @E_net4likestodownvote The lack `&mut self` was an oversight when preparing the minimal example, the original code used it as expected. – Karol S Jun 12 '20 at 14:18
  • @E_net4likestodownvote And yes, adding `+ 'a` in all the boxes solved the issue. Thanks. – Karol S Jun 12 '20 at 14:21

0 Answers0