dtolnay/async-trait

Elided or placeholdered generic lifetimes are not properly respected in trait implementation

Aperta

#64 aperta il 31 gen 2020

 (1 commento) (1 reazione) (0 assegnatari)Rust (98 fork)github user discovery
help wanted

Metriche repository

Star
 (2153 stelle)
Metriche merge PR
 (Merge medio 4m) (2 PR mergiate in 30 g)

Descrizione

Consider the following, where the lifetime for & is elided in the trait implementation and a placeholder is used for the generic in the trait:

#[async_trait::async_trait]
trait Foo<'a>: Sized {
    async fn f(bar: &'a usize) -> Self;
}

#[async_trait::async_trait]
impl Foo<'_> for usize {
    async fn f(bar: &usize) -> Self {
        10
    }
}

This generates the following implementation:

impl Foo<'_> for usize {
    fn f<'y, 'life0>(bar: &'life0 usize) -> BoxFuture<'y, Self>
        where 'life0: 'y, Self: 'y
    {
        async fn __f(bar: &usize) -> usize { 10 }
        Box::pin(__f::<>(bar))
    }
}

This, of course, does not match the generated trait definition which has only a single lifetime generic in f. The "correct" implementation would look like:

impl<'f> Foo<'f> for usize {
    fn f<'y>(bar: &'f usize) -> BoxFuture<'y, Self>
        where 'f: 'y, Self: 'y
    {
        async fn __f(bar: &usize) -> usize { 10 }
        Box::pin(__f::<>(bar))
    }
}

This, of course, would require async-trait to know that the placeholdered generic lifetime in the trait corresponds to the elided lifetime in the implementation. In general, it's clear that async-trait can't do this as it doesn't have type information nor access to the AST of the definition.

I believe that async-trait should likely error when trait generics are placeholdered. At least then the user gets a nice error message as opposed to incorrect code being generated.

Guida contributor