Generic associated types broken

I'm having some trouble with some very basic code involving generic associated types. After updating my Rust version, some code that used to work now errored because of this change to require where Self: 'a on GATs. After making the necessary changes I'm stuck with a problem. I've created a minimal reproduction here:

#![feature(generic_associated_types)]
use std::future::{Future, ready, Ready};

pub trait Example {
    type Value<'a>: Future<Output = &'a str> where Self: 'a;
    fn example(&mut self) -> Self::Value<'_>;
}

pub struct ExImpl<'a>(&'a str);

impl Example for ExImpl<'_> {
    type Value<'a> = Ready<&'a str> where Self: 'a;
    fn example(&mut self) -> Self::Value<'_> {
        ready(self.0)
    }
}

async fn callee(mut ex: impl Example) {
    // Note that if you don't use a separate function, no errors appear
    dbg!(ex.example().await);
}

#[tokio::main]
async fn main() {
    tokio::spawn(async move {
        let ex = ExImpl("hello");
        callee(ex).await;
    });
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0477]: the type `ExImpl<'_>` does not fulfill the required lifetime
  --> src/main.rs:24:5
   |
24 |     tokio::spawn(async move {
   |     ^^^^^^^^^^^^

For more information about this error, try `rustc --explain E0477`.
error: could not compile `playground` due to previous error

Now maybe my code is just broken, but it compiled fine without the where Self: 'a bounds a few versions back. Also this error is extremely cryptic - given that it's on tokio::spawn, I'd assume it has something to do with ExImpl<'_> not having a static lifetime, but it actually does since I'm using a string literal, so I don't know what's up with that. I also didn't get any diagnostics beyond that singular statement.

Any ideas on how to work around this issue, and/or if this is a bug in the compiler?

1 Like

I find the error-at-a-distance quite odd. On top of that, they explicitly asks for use-cases that break. So I would definitely report it, and link to the issue you cite.

You can hack around requiring the bound, or use the workaround of a separate supertrait for the GAT alone (with enough refactoring).