Skip to content

Wrongly typing a collect with async streams causes confusing error messages alongside a cascade of unhelpful error messages #85132

Open
@Frederik-Baetens

Description

@Frederik-Baetens

Given the following code:

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=05ab45beb0f9d4f2f7cdd9fc89f17a03

use futures::stream::{self, StreamExt};

#[tokio::main]
async fn main() {
    let key1: String = "/helloa".to_string();

    dbg!(&key1);

    let futlist = stream::iter(0..10);
    let _stringvec: Vec<String> = futlist.map(move |_| {
        async {
            key1.clone();
        }
    }).buffer_unordered(10).collect::<Vec<String>>().await;
}

The current output is:

   Compiling playground v0.0.1 (/playground)
error[E0277]: the trait bound `Vec<String>: Extend<()>` is not satisfied
  --> src/main.rs:14:29
   |
14 |     }).buffer_unordered(10).collect::<Vec<String>>().await;
   |                             ^^^^^^^ the trait `Extend<()>` is not implemented for `Vec<String>`
   |
   = help: the following implementations were found:
             <Vec<T, A> as Extend<&'a T>>
             <Vec<T, A> as Extend<T>>

error[E0277]: the trait bound `Vec<String>: Extend<()>` is not satisfied
  --> src/main.rs:10:35
   |
10 |       let _stringvec: Vec<String> = futlist.map(move |_| {
   |  ___________________________________^
11 | |         async {
12 | |             key1.clone();
13 | |         }
14 | |     }).buffer_unordered(10).collect::<Vec<String>>().await;
   | |__________________________________________________________^ the trait `Extend<()>` is not implemented for `Vec<String>`
   |
   = help: the following implementations were found:
             <Vec<T, A> as Extend<&'a T>>
             <Vec<T, A> as Extend<T>>
   = note: required because of the requirements on the impl of `futures::Future` for `Collect<BufferUnordered<futures::stream::Map<futures::stream::Iter<std::ops::Range<{integer}>>, [closure@src/main.rs:10:47: 14:6]>>, Vec<String>>`
   = note: required by `futures::Future::poll`

error[E0698]: type inside `async` block must be known in this context
  --> src/main.rs:9:9
   |
9  |     let futlist = stream::iter(0..10);
   |         ^^^^^^^ cannot infer type for type `{integer}`
   |
note: the type is part of the `async` block because of this `await`
  --> src/main.rs:10:35
   |
10 |       let _stringvec: Vec<String> = futlist.map(move |_| {
   |  ___________________________________^
11 | |         async {
12 | |             key1.clone();
13 | |         }
14 | |     }).buffer_unordered(10).collect::<Vec<String>>().await;
   | |__________________________________________________________^

error[E0698]: type inside `async` block must be known in this context
  --> src/main.rs:10:35
   |
10 |     let _stringvec: Vec<String> = futlist.map(move |_| {
   |                                   ^^^^^^^ cannot infer type for type `{integer}`
   |
note: the type is part of the `async` block because of this `await`
  --> src/main.rs:10:35
   |
10 |       let _stringvec: Vec<String> = futlist.map(move |_| {
   |  ___________________________________^
11 | |         async {
12 | |             key1.clone();
13 | |         }
14 | |     }).buffer_unordered(10).collect::<Vec<String>>().await;
   | |__________________________________________________________^

error[E0698]: type inside `async` block must be known in this context
  --> src/main.rs:10:47
   |
10 |       let _stringvec: Vec<String> = futlist.map(move |_| {
   |  _______________________________________________^
11 | |         async {
12 | |             key1.clone();
13 | |         }
14 | |     }).buffer_unordered(10).collect::<Vec<String>>().await;
   | |_____^ cannot infer type for type `{integer}`
   |
note: the type is part of the `async` block because of this `await`
  --> src/main.rs:10:35
   |
10 |       let _stringvec: Vec<String> = futlist.map(move |_| {
   |  ___________________________________^
11 | |         async {
12 | |             key1.clone();
13 | |         }
14 | |     }).buffer_unordered(10).collect::<Vec<String>>().await;
   | |__________________________________________________________^

error[E0698]: type inside `async` block must be known in this context
  --> src/main.rs:10:35
   |
10 |       let _stringvec: Vec<String> = futlist.map(move |_| {
   |  ___________________________________^
11 | |         async {
12 | |             key1.clone();
13 | |         }
14 | |     }).buffer_unordered(10).collect::<Vec<String>>().await;
   | |______^ cannot infer type for type `{integer}`
   |
note: the type is part of the `async` block because of this `await`
  --> src/main.rs:10:35
   |
10 |       let _stringvec: Vec<String> = futlist.map(move |_| {
   |  ___________________________________^
11 | |         async {
12 | |             key1.clone();
13 | |         }
14 | |     }).buffer_unordered(10).collect::<Vec<String>>().await;
   | |__________________________________________________________^

error[E0698]: type inside `async` block must be known in this context
  --> src/main.rs:10:35
   |
10 |       let _stringvec: Vec<String> = futlist.map(move |_| {
   |  ___________________________________^
11 | |         async {
12 | |             key1.clone();
13 | |         }
14 | |     }).buffer_unordered(10).collect::<Vec<String>>().await;
   | |___________________________^ cannot infer type for type `{integer}`
   |
note: the type is part of the `async` block because of this `await`
  --> src/main.rs:10:35
   |
10 |       let _stringvec: Vec<String> = futlist.map(move |_| {
   |  ___________________________________^
11 | |         async {
12 | |             key1.clone();
13 | |         }
14 | |     }).buffer_unordered(10).collect::<Vec<String>>().await;
   | |__________________________________________________________^

error[E0698]: type inside `async` block must be known in this context
  --> src/main.rs:10:35
   |
10 |       let _stringvec: Vec<String> = futlist.map(move |_| {
   |  ___________________________________^
11 | |         async {
12 | |             key1.clone();
13 | |         }
14 | |     }).buffer_unordered(10).collect::<Vec<String>>().await;
   | |____________________________________________________^ cannot infer type for type `{integer}`
   |
note: the type is part of the `async` block because of this `await`
  --> src/main.rs:10:35
   |
10 |       let _stringvec: Vec<String> = futlist.map(move |_| {
   |  ___________________________________^
11 | |         async {
12 | |             key1.clone();
13 | |         }
14 | |     }).buffer_unordered(10).collect::<Vec<String>>().await;
   | |__________________________________________________________^

error[E0698]: type inside `async` block must be known in this context
  --> src/main.rs:10:35
   |
10 |       let _stringvec: Vec<String> = futlist.map(move |_| {
   |  ___________________________________^
11 | |         async {
12 | |             key1.clone();
13 | |         }
14 | |     }).buffer_unordered(10).collect::<Vec<String>>().await;
   | |__________________________________________________________^ cannot infer type for type `{integer}`
   |
note: the type is part of the `async` block because of this `await`
  --> src/main.rs:10:35
   |
10 |       let _stringvec: Vec<String> = futlist.map(move |_| {
   |  ___________________________________^
11 | |         async {
12 | |             key1.clone();
13 | |         }
14 | |     }).buffer_unordered(10).collect::<Vec<String>>().await;
   | |__________________________________________________________^

error: aborting due to 9 previous errors

Some errors have detailed explanations: E0277, E0698.
For more information about an error, try `rustc --explain E0277`.
error: could not compile `playground`

To learn more, run the command again with --verbose.

Ideally the output should look like:

   Compiling playground v0.0.1 (/playground)
error[E0277]: the trait bound `Vec<String>: Extend<()>` is not satisfied
  --> src/main.rs:14:29
   |
14 |     }).buffer_unordered(10).collect::<Vec<String>>().await;
   |                             ^^^^^^^ the trait `Extend<()>` is not implemented for `Vec<String>`
   |
   = help: the following implementations were found:
             <Vec<T, A> as Extend<&'a T>>
             <Vec<T, A> as Extend<T>>

I guess just the first error shows what the problem is, but it's still a bit scary for a newcomer. Perhaps a nice sentence like "Collect expected a stream of strings, but got a stream of unity types ()"

Even better would be a suggestion to remove the semicolon so that strings are returned, but I can understand that that analysis may be very complex, and it may be hard to avoid making suggestions that are not what the user intended.

The cascade is somewhat similar to #85131 but unlike with #85131, where the main error message is already decent, I think the main error could also be made a bit better here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-async-awaitArea: Async & AwaitA-diagnosticsArea: Messages for errors, warnings, and lintsAsyncAwait-TriagedAsync-await issues that have been triaged during a working group meeting.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