Why using a GAT in this async recursive function requires a static type lifetime?

I stumbled across a weird case with GATs + async, and I'm not yet sure if it is a bug or not. Consider the following program:

#![feature(generic_associated_types)]
use std::pin::Pin;
use std::future::Future;

fn foo<'a, C>(
  context: &'a C,
) -> Pin<Box<dyn 'a + Send + Future<Output=()>>>
where
  C: 'a + Send + Sync + Foo
{
    Box::pin(async move {
        let context_ref = context.as_ref();
        foo(context).await
    })
}

pub trait Foo {
    type Ref<'a>: Send + Sync where Self: 'a;

    fn as_ref(&self) -> Self::Ref<'_>;
}

This fails to compile because rustc requires C to have a 'static lifetime. Any other lifetime will result in

error: `C` does not live long enough
  --> src/lib.rs:11:5
   |
11 | /     Box::pin(async move {
12 | |         let context_ref = context.as_ref();
13 | |         foo(context).await
14 | |     })
   | |______^

without any explanation as to why it does not live long enough.

I've done a little bit of digging but I still don't understand this requirement. Here is what I've found:

  • This seems related to the Send bound of the future returned by foo. If I remove this bound, the problem disappears.
  • The Ref associated type in Foo is supposed to act like a reference. If I use an actual reference as the return type of Foo::as_ref, the problem disappears.
  • If I rewrite the program without GATs as follows, the problem disappears:
fn foo<'a, C>(
  context: &'a C,
) -> Pin<Box<dyn 'a + Send + Future<Output=()>>>
where
  C: 'a + Send + Sync + Foo<'a>
{
    Box::pin(async move {
        let context_ref = context.as_ref();
        foo(context).await
    })
}

pub trait Foo<'a> {
    type Ref: Send + Sync;

    fn as_ref(&'a self) -> Self::Ref;
}

I don't see a real difference that would cause one to require C to have a 'static lifetime and not the other.

Can anyone could explain to me why this is happening, if it is a compiler bug/limitation or not, and if it is, if there is a related issue already opened on https://github.com/rust-lang/rust.

1 Like