rust-lang / futures-rs

Zero-cost asynchronous programming in Rust
https://rust-lang.github.io/futures-rs/
Apache License 2.0
5.29k stars 607 forks source link

Non-send future produced by chaining `Stream` combinators #2845

Closed George-Miao closed 3 months ago

George-Miao commented 3 months ago

The future produced by chaining filter_map and chunks with a self reference inside filter_map closure is not Send for some reason, and this can be fixed by adding a .boxed() after the chunks call.

fn assert_send<T: Send>(t: T) -> T { t }
async fn test() {
    struct A;
    impl A {
        async fn a(&self) {
            futures::stream::iter([0u8])
                .filter_map(|_| async {
                    self.c();
                    // self.b().await; // Same as calling `c`
                    Some(0)
                })
                .chunks(1)
                // .boxed() // This will fix the problem
                .for_each(|_| async {}) // This can be anything consumes the stream without pinning it, include for_each_concurrent and collect
                .await;
        }

        async fn b(&self) {}

        fn c(&self) {}
    }
    assert_send(A.a()).await; // This will fail to compile
}

Error:

error[E0308]: mismatched types
   --> [:REDACTED:]/test.rs:252:9
    |
231 |                       .filter_map(|_| async {
    |  _____________________________________-
232 | |                         self.c();
233 | |                         // self.b().await; // Same as calling `c`
234 | |                         Some(0)
235 | |                     })
    | |                     -
    | |                     |
    | |_____________________the expected `async` block
    |                       the found `async` block
...
252 |           assert_send(A.a_consume()).await; // This will fail to compile
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
    |
    = note: expected `async` block `{async block@[:REDACTED:]/test.rs:231:37: 235:22}`
               found `async` block `{async block@[:REDACTED:]/test.rs:231:37: 235:22}`
note: the lifetime requirement is introduced here
   --> [:REDACTED:]/test.rs:223:23
    |
223 |     fn assert_send<T: Send>(t: T) -> T {
    |                       ^^^^

For more information about this error, try `rustc --explain E0308`.
taiki-e commented 3 months ago

This is a rustc bug: https://github.com/rust-lang/rust/issues/104382

Closing in favor of the upstream issue.