dtolnay / async-trait

Type erasure for async trait methods
Apache License 2.0
1.81k stars 84 forks source link

Cannot infer an appropriate lifetime #108

Closed delbato closed 1 year ago

delbato commented 4 years ago

Hi! First off - excuse myself. Im not even sure if this qualifies as a bug. However, here is what i am trying to do:

/// The System trait
#[async_trait]
pub trait System<'s>: Send + Sync {
    /// The associated system data
    type Data<'s>: SystemData<'s>;

    /// Sets up the system data
    fn setup(world: &mut World) -> Result<(), Box<dyn Error>> {
        Self::Data::setup(world)
    }

    /// Initializes the system
    async fn init(&mut self);

    /// Updates the system
    async fn update(&mut self, data: Self::Data);
}

#[async_trait]
pub trait DynSystem {
    async fn d_init(&mut self);
    async fn d_update(&mut self, world: &mut World);
}

#[async_trait]
impl<'s, T: System<'s>> DynSystem for T {
    async fn d_init(&mut self) {
        self.init().await;
    }

    async fn d_update(&mut self, world: &mut World) {
        let data = Self::Data::fetch(world).await;
    }
}

The above code fails with Cannot infer an appropriate lifetime for 's due to conflicting requirements. Any help would be much appreciated!

dtolnay commented 4 years ago

Please provide a minimal compilable repro. Compiling the code you gave produces a different error message from the one you are asking about, and it looks like much of the code may not be directly involved so could be simplified while still reproducing the same error.

taiki-e commented 4 years ago

I could reproduce this error by modified the code you gave. Reproduction: playground (Removed dependency on GAT and replaced traits/types that do not exist in scope with empty trait/type definitions) Disclaimer: The comments below assume that this reproduction is correct.

Cause: This is a compiler bug: https://github.com/rust-lang/rust/issues/60658 (duplicate of #34)

Workaround: Replace the T: System<'s> bounds in the DynSystem impl with HRTB and add Send bounds. (https://github.com/rust-lang/rust/issues/60658#issuecomment-493043548)

- impl<'s, T: System<'s>> DynSystem for T {
+ impl<T> DynSystem for T
+     where
+         for<'a> T: System<'a> + Send,
+     {

playground

delbato commented 4 years ago

Please provide a minimal compilable repro. Compiling the code you gave produces a different error message from the one you are asking about, and it looks like much of the code may not be directly involved so could be simplified while still reproducing the same error.

Yes, excuse that. I forgot my proper issue reporting etiquette. I will keep this in mind for next time :)

taiki-e, thanks for the heads up. Good to know this was an actual bug that i just reported badly, and not an error with what i was trying to do :) I suppose this can be closed then?

delbato commented 4 years ago

Hi again! I believe i ran into a similar issue again. Heres a reproducible example.

Is there a way to circumvent this in this case or am i simply approaching this wrong? Thanks a lot for your help so far!

taiki-e commented 4 years ago

@wrckn Seems 's and type parameters need to outlive 'async_trait, so it needs to add 's: 'async_trait bounds to methods and $ty: 's bounds to impls: playground

(async-trait automatically adds 'async_trait bounds to lifetimes and type parameters contained in arguments of methods, but not to lifetimes and type parameters only used anywhere else. See also https://github.com/dtolnay/async-trait/issues/8#issuecomment-514812245)

dtolnay commented 1 year ago

Fixed by async-trait 0.1.43.