Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue with reference lifetimes in closures #257

Open
tezlm opened this issue Jan 24, 2024 · 1 comment
Open

Issue with reference lifetimes in closures #257

tezlm opened this issue Jan 24, 2024 · 1 comment
Labels
bug Something isn't working

Comments

@tezlm
Copy link

tezlm commented Jan 24, 2024

On latest async-trait (0.1.77) this code doesn't compile:

struct Foo;

#[async_trait::async_trait]
trait Bar {
    async fn foo(&self, call: &(dyn (Fn(&String) -> bool) + Sync));
}

#[async_trait::async_trait]
impl Bar for Foo {
    async fn foo(&self, call: &(dyn (Fn(&String) -> bool) + Sync)) {
        let thing = "a".to_string();
        call(&thing);
    }
}

fn main() {
    Foo::foo(&Foo, &|a| a == "a");
}

This expands to:

    fn foo<'life0, 'life1, 'life2, 'async_trait>(
        &'life0 self,
        call: &'life1 (dyn (Fn(&'life2 String) -> bool) + Sync),
    ) -> ::core::pin::Pin<
        Box<
            dyn ::core::future::Future<Output = ()> + ::core::marker::Send + 'async_trait,
        >,
    >
    where
        'life0: 'async_trait,
        'life1: 'async_trait,
        'life2: 'async_trait,
        Self: 'async_trait;

And gives the compiler error:

error[E0597]: `thing` does not live long enough
  --> src/main.rs:12:14
   |
10 |     async fn foo(&self, call: &(dyn (Fn(&String) -> bool) + Sync)) {
   |                         ---- lifetime `'1` appears in the type of `call`
11 |         let thing = "a".to_string();
   |             ----- binding `thing` declared here
12 |         call(&thing);
   |         -----^^^^^^-
   |         |    |
   |         |    borrowed value does not live long enough
   |         argument requires that `thing` is borrowed for `'1`
13 |     }
   |     - `thing` dropped here while still borrowed

Manually removing 'life2 makes the code compile.

@dtolnay dtolnay added the bug Something isn't working label Mar 23, 2024
@dtolnay
Copy link
Owner

dtolnay commented Mar 23, 2024

This can be worked around by writing the higher-rank trait bound for the function type, rather than relying on lifetime elision.

#[async_trait::async_trait]
trait Bar {
    async fn foo(&self, call: &(dyn (for<'a> Fn(&'a String) -> bool) + Sync));
                                     ^^^^^^^     ^^
}

#[async_trait::async_trait]
impl Bar for Foo {
    async fn foo(&self, call: &(dyn (for<'a> Fn(&'a String) -> bool) + Sync)) {
                                     ^^^^^^^     ^^
        let thing = "a".to_string();
        call(&thing);
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants