Skip to content

Using the format!() macro with an async function makes the whole Future non-Send #101650

Open
@Hocuri

Description

@Hocuri

I tried this code: (minimal reproducible example; for the actual code see chatmail/core#3591)

use core::future::Future;
use core::pin::Pin;

fn build_string() -> Pin<Box<dyn Future<Output = String> + Send>> {
    Box::pin(async move {
        let mut string_builder = "<h>".to_string();
        string_builder += &format!("Hello {}", helper().await);
        string_builder += "</h>";
        string_builder
    })
}

async fn helper() -> String {
    "World".to_string()
}

Playground

Note that we are using,

format!("Hello {}", helper().await)

in a context where the Future needs to be Send; only this line without the string_builder seems not to be able to reproduce the issue though.

I expected to see this happen: That the code behaves the same as

let s = helper().await;
format!("Hello {}", s)

Instead, this happened:

There are two error messages (about line 5 and line 7); this issue is about the first one:

error: future cannot be sent between threads safely
 --> src/lib.rs:5:5
  |
5 |     Box::pin(async move {
  |     ^^^^^^^^^^^^^^^^^^^ future created by async block is not `Send`
  |
  = help: the trait `Sync` is not implemented for `core::fmt::Opaque`
note: future is not `Send` as this value is used across an await
 --> src/lib.rs:7:56
  |
7 |         string_builder += &format!("Hello {}", helper().await);
  |                            ----------------------------^^^^^^-
  |                            |                   |       |
  |                            |                   |       await occurs here, with `helper().await` maybe used later
  |                            |                   has type `ArgumentV1<'_>` which is not `Send`
  |                            `helper().await` is later dropped here
  = note: required for the cast to the object type `dyn Future<Output = String> + Send`

The second error message didn't appear in the original issue in chatmail/core#3591, possibly because there the call to Box::pin() and the format!() call are in two different crates:

error: generator cannot be sent between threads safely
  --> deltachat-jsonrpc/src/api/mod.rs:74:1
   |
74 | #[rpc(all_positional, ts_outdir = "typescript/generated")]
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future created by async block is not `Send`
   |
   = help: the trait `Sync` is not implemented for `core::fmt::Opaque`
   = note: required for the cast to the object type `dyn Future<Output = Result<Value, yerpc::Error>> + Send`
   = note: this error originates in the attribute macro `rpc` (in Nightly builds, run with -Z macro-backtrace for more info)

Meta

rustc --version --verbose

Probably doesn't matter, anyway:

rustc 1.61.0 (fe5b13d68 2022-05-18)
binary: rustc
commit-hash: fe5b13d681f25ee6474be29d748c65adcd91f69e
commit-date: 2022-05-18
host: x86_64-unknown-linux-gnu
release: 1.61.0
LLVM version: 14.0.0

@rustbot label +A-fmt

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-fmtArea: `core::fmt`C-bugCategory: This is a bug.E-easyCall for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue.E-needs-testCall for participation: An issue has been fixed and does not reproduce, but no test has been added.T-libsRelevant to the library 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