Eloff
Eloff

Reputation: 21666

Async fn reports "hidden type for `impl Trait` captures lifetime that does not appear in bounds"

If I remove the 'static lifetime of the final argument, the program compiles. If I add it back, it fails. To me, it seems both should be valid. Minimal reproduction:

use std::io;

struct Foo {
    user: String,
    pass: String,
}

impl Foo {
    async fn not_works(
        &mut self,
        user: &str,
        pass: &str,
        app_name: &'static str,
    ) -> io::Result<()> {
        self.user = user.to_string() + app_name;
        self.pass = pass.to_string();

        self.do_stuff().await
    }

    async fn works(&mut self, user: &str, pass: &str, app_name: &str) -> io::Result<()> {
        self.user = user.to_string() + app_name;
        self.pass = pass.to_string();

        self.do_stuff().await
    }

    async fn do_stuff(&self) -> io::Result<()> {
        Ok(())
    }
}

#[tokio::main]
async fn main() {
    let mut foo = Foo {
        user: "".to_string(),
        pass: "".to_string(),
    };

    foo.not_works("test", "password", "foobar").await.unwrap();
}
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
  --> src/main.rs:14:10
   |
14 |     ) -> io::Result<()> {
   |          ^^^^^^^^^^^^^^
   |
note: hidden type `impl Future` captures lifetime smaller than the function body
  --> src/main.rs:14:10
   |
14 |     ) -> io::Result<()> {
   |          ^^^^^^^^^^^^^^

It's much more likely the bug is in my understanding and not the compiler though. What am I missing?

Upvotes: 5

Views: 5666

Answers (1)

Kornel
Kornel

Reputation: 100110

This is a limitation of the async fn implementation. Basically, it tries to unify all lifetimes to be the same, and in this case they can't be all 'static.

This works:

fn workaround<'a>(
    &'a mut self,
    user: &'a str,
    pass: &'a str,
    app_name: &'static str,
) -> impl Future<Output = io::Result<()>> + 'a {
    async move {
        self.user = user.to_string() + app_name;
        self.pass = pass.to_string();

        self.do_stuff().await
    }
}

Upvotes: 7

Related Questions