3

I'm trying to implement the following trait, where the <'baz> is required for a later impl<'baz> Baz<'baz> for T where T: OtherTrait.

trait Baz<'baz>: Clone {
    fn baz(&'baz mut self);
    
    fn bazzed(&self) -> Self {
        let mut x = self.clone();
        x.baz();
        x
    }
}

Rustc understandably fails:

Compiling playground v0.0.1 (/playground)
error[E0309]: the parameter type `Self` may not live long enough
 --> src/lib.rs:6:9
  |
6 |         x.baz();
  |         ^
  |
  = help: consider adding an explicit lifetime bound `Self: 'baz`...
  = note: ...so that the type `Self` is not borrowed for too long

error[E0309]: the parameter type `Self` may not live long enough
 --> src/lib.rs:6:11
  |
6 |         x.baz();
  |           ^^^
  |
  = help: consider adding an explicit lifetime bound `Self: 'baz`...
  = note: ...so that the reference type `&'baz mut Self` does not outlive the data it points at

For more information about this error, try `rustc --explain E0309`.
error: could not compile `playground` due to 2 previous errors

So I follow its suggestion:

trait Baz<'baz>: Clone {
    fn baz(&'baz mut self);
    
    fn bazzed(&self) -> Self 
    where
        Self: 'baz
    {
        let mut x = self.clone();
        x.baz();
        x
    }
}

And I don't quite understand what it's not liking now...

Compiling playground v0.0.1 (/playground)
error[E0597]: `x` does not live long enough
  --> src/lib.rs:9:9
   |
1  | trait Baz<'baz>: Clone {
   |           ---- lifetime `'baz` defined here
...
9  |         x.baz();
   |         ^^^^^^^
   |         |
   |         borrowed value does not live long enough
   |         argument requires that `x` is borrowed for `'baz`
10 |         x
11 |     }
   |     - `x` dropped here while still borrowed

error[E0505]: cannot move out of `x` because it is borrowed
  --> src/lib.rs:10:9
   |
1  | trait Baz<'baz>: Clone {
   |           ---- lifetime `'baz` defined here
...
9  |         x.baz();
   |         -------
   |         |
   |         borrow of `x` occurs here
   |         argument requires that `x` is borrowed for `'baz`
10 |         x
   |         ^ move out of `x` occurs here

Some errors have detailed explanations: E0505, E0597.
For more information about an error, try `rustc --explain E0505`.
error: could not compile `playground` due to 2 previous errors

I tried making Self: 'static too but that did not help either. What am I missing here?



The <'baz> I need for another trait, that looks roughly like:

trait ReturnIteratorMut<'item> {
    type IterType: Iterator<Item = &'item mut Thing>;

    fn iterator<'slf: 'item>(&'slf mut self) -> Self::IterType;
}

I want to implement Baz for all of these by applying baz() to every item in the iterator, so I need 'baz: 'item. This works fine with just the baz() method, it's only the bazzed() that it starts to complain at.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
tuydore
  • 33
  • 4
  • 1
    Why does `'baz` exist? When do you use it? "...where the `<'baz>` is required for a later `impl<'baz> Baz<'baz> for T where T: OtherTrait`." Can you explain that in more detail? – John Kugelman Jul 14 '22 at 14:16
  • 1
    The suggestions made by `rustc` are merely suggestions, and are not always right. You might be trying to write something which is not even possible. Consider explaining the real purpose of that lifetime parameter. – E_net4 Jul 14 '22 at 14:18
  • 1
    Updated to include why I need the lifetime parameter. This isn't as much a question of "how can I do this?" as I could work around the `bazzed()` method, but a "why does this happen?". – tuydore Jul 14 '22 at 14:29

1 Answers1

1

Let's first try to understand what's wrong with this code, without the compiler's help.

x.baz() requires x to live for 'baz. Since 'baz can be any lifetime this means x has to live for 'static. It does not - it is a local variable, and this is an error (you might want HRTB, but you said you want to focus on the compiler errors so I don't deal with the solution).

The compiler's second errors are just that - x does not live long enough, or, if we look at the opposite angle, x is borrowed for 'static and so we cannot move it (the compiler shows both errors in order to maximize displayed errors - sometimes it works, sometimes, like in this case, it leads to confusing errors being shown).

The first error(s) is a negligible result of this constraint, but it hides the actual error (for what it's worth, on nightly they're all shown together): x needs to live for 'static, but not just it does not, sometimes it is impossible for any variable of its type to be. Suppose Self is &'some_short_lifetime i32 - it cannot live for 'static, since it contains a shorter lifetime. This is the reason "Self may not live long enough`.

Chayim Friedman
  • 47,971
  • 5
  • 48
  • 77