Lifetime parameters or bounds on method do not match the trait declaration

How to fix the following lifetime issue:

trait Wrappers {
    type Wrapper<'a>: ?Sized
    where
        Self: 'a;
}

trait Has<W: Wrappers> {
    fn get(&self) -> W::Wrapper<'_>;
}

impl<T> Wrappers for T {
    type Wrapper<'a> = T where Self: 'a;
}

impl<'b, T> Has<&'b T> for T {
    fn get<'a>(&'a self) -> &'b T where 'b: 'a {
        self
    }
}

playground.

It's related with this question.

It results in the following error:

error[E0195]: lifetime parameters or bounds on method `get` do not match the trait declaration
  --> src/lib.rs:16:11
   |
8  |     fn get(&self) -> W::Wrapper<'_>;
   |           - lifetimes in impl do not match this method in trait
...
16 |     fn get<'a>(&'a self) -> &'b T where 'b: 'a {
   |           ^^^^ lifetimes do not match method in trait

For more information about this error, try `rustc --explain E0195`.

You can't extend the lifetime of references, so this signature:

impl<'b, T> Has<&'b T> for T {
    fn get<'a>(&'a self) -> &'b T where 'b: 'a {
        self
    }
}

I.e.

impl<'b, T> Has<&'b T> for T {
    fn get(&self) -> &'b T {
        self
    }
}

Cannot work because the lifetime 'a (or the anonymous &self lifetime in the second snippet) may be shorter than 'b.


You cannot reborrow a &'long T from a &'short T.

A T cannot "Has<&'specifically_long T>".

1 Like

Is there any way to fix it?

impl<'b, T> Has<&'b T> for T {
    fn get(&self) -> &'b T {
        self
    }
}

For this code, it seems that there is no way to specify that 'b is longer than 'self.

Correct.

If there was such a way for that to compile, this would be possible:

fn main() {
    let short_lived = "Hi".to_string();
    // `'b = 'static` is longer than implicit borrow of `short_lived`
    let borrow: &'static String = short_lived.get();
    drop(short_lived);
    // Use after free: instant UB
    println!("{borrow}");
}
1 Like

I find myself wondering why the lifetime system of Rust does not introduce a 'self lifetime to signify the lifetime of Self.:thinking:

You may be conflating the (dynamic) liveness scope of values[1] with the lifetimes of types[2]. Rust borrowing rules are statically enforced (i.e. at compile time), whereas the liveness scope of values are undecidable in the general case.


  1. unfortunately also commonly called a lifetime ↩ī¸Ž

  2. a compile-time property that is erased before runtime ↩ī¸Ž

1 Like

Because there is no such thing as "the lifetime of Self".

Lifetime parameters are just regular generic parameters. If you want to name them, you have to declare them and add them to the signature. &self is not special; it's just syntax sugar for a reference to a value of type Self, which is like any other type. When you take a reference to a value, the lifetime parameter of that reference is for that particular borrow. The (elided) lifetime parameter of self in a method is for that one particular function call. It does not signify the entire duration during which the value exists.

Lifetimes constrain implementations, but they neither keep values alive, nor do they need to be equal to their maximal possible value.

3 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.