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 byfoo
. If I remove this bound, the problem disappears. - The
Ref
associated type inFoo
is supposed to act like a reference. If I use an actual reference as the return type ofFoo::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
.