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

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

Open
jephthia opened this issue Mar 8, 2025 · 0 comments
Open

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

jephthia opened this issue Mar 8, 2025 · 0 comments
Labels
A-async-closures `async || {}` A-diagnostics Area: Messages for errors, warnings, and lints D-confusing Diagnostics: Confusing error or lint that should be reworked. needs-triage This issue may need triage. Remove it if it has been sufficiently triaged.

Comments

@jephthia
Copy link

jephthia commented Mar 8, 2025

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?
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Mar 8, 2025
@lolbinarycat lolbinarycat added the A-async-closures `async || {}` label Mar 8, 2025
@lolbinarycat lolbinarycat added D-confusing Diagnostics: Confusing error or lint that should be reworked. A-diagnostics Area: Messages for errors, warnings, and lints labels Mar 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-async-closures `async || {}` A-diagnostics Area: Messages for errors, warnings, and lints D-confusing Diagnostics: Confusing error or lint that should be reworked. needs-triage This issue may need triage. Remove it if it has been sufficiently triaged.
Projects
None yet
Development

No branches or pull requests

3 participants