Lifetime bounds with async functions

I was playing with lifetimes and async functions, and encountered a compile error with the following code:

struct Invariant<'t, T>(PhantomData<fn(&'t T) -> &'t T>);

trait Rebind<'b> {
    type Output;
}

async fn test<'b, 't, T>() -> Invariant<'t, T::Output>
where
    T: Rebind<'b>,
{
    Invariant(PhantomData)
}

The compiler urges me to add T: 't and 'b: 't, but I cannot figure out why this is needed, since removing async makes the code compile.

I suppose it is due to the 2024 edition RPIT capture rules, which capture all generics by default. How do I capture the needed generics precisely?

A Invariant<'t, T::Output> struct is invariant over both 't and T::Output and comes with an implicit T::Output: 't bound (due to using the type &'t T::Output). It looks like the compiler is trying to prove T::Output: 't, sees that <T as Rebind<'b>>::Output can only be guaranteed to outlive 't if T: 't and 'b: 't, sees that those conditions fail, and reports those failing conditions instead of the root error.

However, for the non-async version of test, the fact that Invariant<'t, T::Output> is mentioned results in an implied bound of T::Output: 't. I suppose that adding async causes that bound to no longer be implied.

Explicitly requiring the usually-implied bound makes it compile:

struct Invariant<'t, T>(PhantomData<fn(&'t T) -> &'t T>);

trait Rebind<'b> {
    type Output;
}

async fn test<'b, 't, T>() -> Invariant<'t, T::Output>
where
    T: Rebind<'b>,
    T::Output: 't,
{
    Invariant(PhantomData)
}
1 Like
1 Like