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
}
}
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`.
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}");
}
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.
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.