dtolnay/async-trait

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

Offen

#64 geöffnet am 31.01.2020

 (1 Kommentar) (1 Reaktion) (0 zugewiesene Personen)Rust (98 Forks)github user discovery
help wanted

Repository-Metriken

Stars
 (2.153 Sterne)
PR-Merge-Metriken
 (Durchschn. Merge 4m) (2 gemergte PRs in 30 T)

Beschreibung

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.

Contributor Guide