trait Get {
type T<'a> where Self: 'a;
fn get(&self);
}
fn test_fun<'b, T>(get_to: T)
where
T: Get<T<'b> = T> + 'b,
{
get_to.get();
}
But these can not:
trait Get {
type T<'a> where Self: 'a;
fn get(&self) -> Self::T<'_>; //this is the only defference from above
}
fn test_fun<'b, T>(get_to: T)
where
T: Get<T<'b> = T> + 'b,
{
get_to.get();
}
The only difference between the two versions comes from return value of method get from trait Get.
What makes the error happened?
Adding the return type restrains the call to Get::get's lifetime as 'b, since <T as Get>::T<'x> is only defined when 'x = 'b. And that 'b' may outlive test_fun's scope, where get_to lives, resulting the borrow outlives get_to.
Reminder: T: 'a does not means for any variable x: T, x outlives 'a. (Think all those short lived Strings, but we have String: 'static.)
I think it's a limitation of GATs and the bounds checks. With the second version, the compiler is assuming that the 'b is relevant -- that you're going to want to call T::get with a &'b self so you get a T back out. (The output of T::get might not be T for other lifetimes.)
The function body as written doesn't technically need that to happen. This program could be accepted.
But if the function did need that to happen, it can't happen because the caller of test_fun chooses 'b, and they can only choose lifetimes that are longer than the function body, and thus you can never borrow a local like get_to for a caller-chosen lifetime like 'b. So the compiler's assumption results in the borrow error.
If you don't need to have T::get return a T, you should just drop the bound: T: Get.
If you do need that, you need it to happen for arbitrarily short lifetimes, and that's what HRTBs (higher-ranked trait bounds) are for: T: for<'x> Get<T<'x> = T>.
// `Limiter` is a defaulted type parameter that takes the place of the
// `where Self: 'a` bound you had on the GAT. `Self: 'x` is implied
// by the presense of the `&'x Self`, as it's required for the reference
// to be well formed.
trait GetGat<'x, Limiter = &'x Self> {
type T;
}
// So here for example it's really `impl<'x, 'y: 'x>`
// Or alternatively `where &'y f32: 'x`, `where Self: 'x`
impl<'x, 'y> GetGat<'x> for &'y f32 {
type T = &'y f32;
}
// And here's it really `for <'any where T: 'any>`
// (which you cannot write directly in Rust!)
fn test_fun<T>(get_to: T)
where
T: Get + for<'any> GetGat<'any, T = T>,