dtolnay / async-trait

Type erasure for async trait methods
Apache License 2.0
1.84k stars 85 forks source link

GAT: lifetime bound not satisfied #186

Closed vorot93 closed 2 years ago

vorot93 commented 2 years ago

https://github.com/rust-lang/rust/issues/91883 slightly expanded fails:

#![feature(generic_associated_types)]

use async_trait::async_trait;
use std::fmt::Debug;
use std::marker::PhantomData;

#[derive(Debug)]
pub struct TransactionImpl<'db> {
    _marker: PhantomData<&'db ()>,
}

#[derive(Debug)]
pub struct CursorImpl<'tx> {
    _marker: PhantomData<&'tx ()>,
}

#[async_trait]
pub trait Cursor<'tx>: Send {
    async fn seek_exact(&mut self, key: String) -> Result<String, ()>;
}

#[async_trait]
pub trait Transaction<'db>: Send + Sync + Debug + Sized {
    type Cursor<'tx>: Cursor<'tx>
    where
        'db: 'tx,
        Self: 'tx;

    async fn cursor<'tx>(&'tx self) -> Result<Self::Cursor<'tx>, ()>
    where
        'db: 'tx;

    async fn read<'tx>(&'tx self, key: String) -> Result<String, ()>
    where
        'db: 'tx,
    {
        Ok(self.cursor().await?.seek_exact(key).await?)
    }
}

#[async_trait]
impl<'tx> Cursor<'tx> for CursorImpl<'tx> {
    async fn seek_exact(&mut self, key: String) -> Result<String, ()> {
        loop {}
    }
}

#[async_trait]
impl<'db> Transaction<'db> for TransactionImpl<'db> {
    type Cursor<'tx>
    where
        'db: 'tx,
    = CursorImpl<'tx>;

    async fn cursor<'tx>(&'tx self) -> Result<Self::Cursor<'tx>, ()>
    where
        'db: 'tx,
    {
        loop {}
    }
}
error[E0478]: lifetime bound not satisfied
  --> src/lib.rs:36:5
   |
36 | /     {
37 | |         Ok(self.cursor().await?.seek_exact(key).await?)
38 | |     }
   | |_____^
dtolnay commented 2 years ago

This seems like a compiler bug. It should be providing more guidance than this on what lifetime constraint it has in mind and what extra bound needs to be added where.

I'll close this issue until the GAT implementation in rustc is in better shape. After that, if something causes the new diagnostic from rustc to be misplaced or otherwise hard to interpret specifically due to async-trait, we can reopen an issue.