dtolnay/async-trait

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

Ouverte

#64 ouverte le 31 janv. 2020

 (1 commentaire) (1 réaction) (0 personne assignée)Rust (98 forks)github user discovery
help wanted

Métriques du dépôt

Stars
 (2 153 étoiles)
Métriques de merge PR
 (Merge moyen 4m) (2 PRs mergées en 30 j)

Description

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.

Guide contributeur