Skip to content

Can't compile the use of impl AsyncFn within a spawned thread #138207

Open
@jephthia

Description

@jephthia

I'm getting the following errors when attempting to use a closure within a spawned thread, the errors are a bit too cryptic for me to understand how to correct the following code.

#[tokio::main]
async fn main() {
    tokio::spawn(async move {
        let text = String::from("");
        something(&text).await;
    });
}

async fn something(text: &String) {
    let try_something = async || {
        println!("{text}");
    };

    // try_something().await;   // works
    retry(try_something).await; // fails
}

async fn retry(action: impl AsyncFn()) {
    action().await;
}

Error:

error: implementation of `Send` is not general enough
 --> src/main.rs:3:5
  |
3 | /     tokio::spawn(async move {
4 | |         let text = String::from("");
5 | |         something(&text).await;
6 | |     });
  | |______^ implementation of `Send` is not general enough
  |
  = note: `Send` would have to be implemented for the type `&'0 &String`, for any lifetime `'0`...
  = note: ...but `Send` is actually implemented for the type `&'1 &String`, for some specific lifetime `'1`


Using impl Fn() -> impl Future instead of impl AsyncFn then works but for my use case, a mutable closure is needed which blocks me from using impl FnMut because of the following issue:

#[tokio::main]
async fn main() {
    let mut count = 0;

    let try_something = async || {
        count = 1;
    };

    retry(try_something).await;
}

async fn retry<F>(mut action: impl FnMut() -> F) // fails but would work if this was instead `impl AsyncFnMut()`
where
    F: Future<Output = ()>,
{
    action().await;
}

Error:

error: async closure does not implement `FnMut` because it captures state from its environment
  --> src/main.rs:26:25
   |
26 |     let try_something = async || {
   |                         ^^^^^^^^
...
30 |     retry(try_something).await;
   |     ----- required by a bound introduced by this call
   |
note: required by a bound in `retry`
  --> src/main.rs:33:36
   |
33 | async fn retry<F>(mut action: impl FnMut() -> F)
   |                                    ^^^^^^^^^^^^ required by this bound in `retry`


Essentially,

  1. I need to use a mutable reference in a closure which means I'd want to use async || {} instead of || async {},
  2. but using impl AsyncFnMut seems to break as soon as it's within a spawned thread which means I'd want to instead try: impl FnMut -> impl Future,
  3. but using impl FnMut seems to break the use of async || {} which means I'd want to instead try: || async {},
  4. but using || async {} no longer allows me to use a mutable reference which then breaks the required functionality
  5. and so I then repeat back to step 1, and I've been stuck on that loop for the last couple of hours, each time trying a different variation to try and get it to work but with no luck.

  • Is impl AsyncFn* not allowed within spawned threads?
  • Can async || {} not be passed to a function that takes impl FnMut -> impl Future?

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-async-closures`async || {}`A-diagnosticsArea: Messages for errors, warnings, and lintsD-confusingDiagnostics: Confusing error or lint that should be reworked.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions