rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
97.22k stars 12.56k forks source link

Cascading errors from unsatisfied trait bounds #117515

Open jyn514 opened 11 months ago

jyn514 commented 11 months ago

Code

use futures_util::StreamExt;
use azure_storage_blobs::prelude::BlobClient;

async fn fetch_object(blob_client: BlobClient) -> Result<hyper::Body, Box<dyn std::error::Error>> {
    let azure_stream = blob_client.get().into_stream().flat_map(|chunk| {
        chunk.map(|blob| blob.data)
    });
    Ok(hyper::Body::wrap_stream(azure_stream))
}

Current output

error[E0277]: the trait bound `Result<azure_core::response::ResponseBody, azure_core::error::Error>: Stream` is not satisfied
   --> src/main.rs:5:56
    |
5   |     let azure_stream = blob_client.get().into_stream().flat_map(|chunk| {
    |                                                        ^^^^^^^^ the trait `Stream` is not implemented for `Result<azure_core::response::ResponseBody, azure_core::error::Error>`
    |
    = help: the following other types implement trait `Stream`:
              async_channel::Receiver<T>
              futures_channel::mpsc::Receiver<T>
              futures_channel::mpsc::UnboundedReceiver<T>
              tokio_util::sync::poll_semaphore::PollSemaphore
              Body
              Box<S>
              tokio_util::either::Either<L, R>
              tokio_util::io::sink_writer::SinkWriter<S>
            and 127 others
note: required by a bound in `futures_util::StreamExt::flat_map`
   --> /Users/jyn/.local/lib/cargo/registry/src/index.crates.io-6f17d22bba15001f/futures-util-0.3.29/src/stream/stream/mod.rs:861:12
    |
858 |     fn flat_map<U, F>(self, f: F) -> FlatMap<Self, U, F>
    |        -------- required by a bound in this associated function
...
861 |         U: Stream,
    |            ^^^^^^ required by this bound in `StreamExt::flat_map`

error[E0277]: the trait bound `Result<azure_core::response::ResponseBody, azure_core::error::Error>: Stream` is not satisfied
   --> src/main.rs:8:33
    |
8   |     Ok(hyper::Body::wrap_stream(azure_stream))
    |        ------------------------ ^^^^^^^^^^^^ the trait `Stream` is not implemented for `Result<azure_core::response::ResponseBody, azure_core::error::Error>`
    |        |
    |        required by a bound introduced by this call
    |
    = help: the following other types implement trait `Stream`:
              async_channel::Receiver<T>
              futures_channel::mpsc::Receiver<T>
              futures_channel::mpsc::UnboundedReceiver<T>
              tokio_util::sync::poll_semaphore::PollSemaphore
              Body
              Box<S>
              tokio_util::either::Either<L, R>
              tokio_util::io::sink_writer::SinkWriter<S>
            and 127 others
    = note: required for `Flatten<Map<Pageable<..., ...>, ...>, ...>` to implement `Stream`
    = note: the full type name has been written to '/Users/jyn/.local/lib/cargo/target/debug/deps/example-12c218bf13b78b0c.long-type-15395125195545820898.txt'
note: required by a bound in `Body::wrap_stream`
   --> /Users/jyn/.local/lib/cargo/registry/src/index.crates.io-6f17d22bba15001f/hyper-0.14.27/src/body/body.rs:192:19
    |
190 |     pub fn wrap_stream<S, O, E>(stream: S) -> Body
    |            ----------- required by a bound in this associated function
191 |     where
192 |         S: Stream<Item = Result<O, E>> + Send + 'static,
    |                   ^^^^^^^^^^^^^^^^^^^ required by this bound in `Body::wrap_stream`

For more information about this error, try `rustc --explain E0277`.

Desired output

No response

Rationale and extra context

There are a few things that could be improved from this output.

  1. Listing all possible types that implement Stream is unhelpful (there might already be an issue open for this); they are unrelated to the data I need to get out of azure_stream. Maybe it would be good to only suggest types which can be created from any of the intermediate types? e.g. into_stream returns a Pageable<GetBlobResponse> that implements stream, so suggest that type and things like Map<Pageable>?
  2. The first error points at flat_map, which is good, but it would be even better if it pointed at the place where it infers the return type of the closure (line 6). The signature of flat_map is
    fn flat_map<U, F>(self, f: F) -> FlatMap<Self, U, F>
    where
        F: FnMut(Self::Item) -> U,
        U: Stream,

    and the error complains about U, so it should point to U.

  3. The error on wrap_stream is quite confusing. Here is the signature of wrap_stream:
    pub fn wrap_stream<S, O, E>(stream: S) -> Body
    where
        S: Stream<Item = Result<O, E>> + Send + 'static,
        O: Into<Bytes> + 'static,
        E: Into<Box<dyn StdError + Send + Sync>> + 'static

    As far as I can tell, the problem here is actually the same as before: flat_map requires U to implement Stream. But the error has somehow lost the context of flat_map, and doesn't know how to name U, and so it settles for "required for Flatten<Map<Pageable<..., ...>, ...>, ...> to implement Stream". I think this error should just be hidden altogether, it doesn't add any info.

Other cases

No response

Anything else?

The full type name written to disk is stream::stream::flatten::Flatten<futures_util::stream::Map<azure_core::pageable::pageable::Pageable<GetBlobResponse, azure_core::error::Error>, {closure@src/main.rs:5:65: 5:72}>, Result<azure_core::response::ResponseBody, azure_core::error::Error>>.

jyn514 commented 11 months ago

also, stream::stream::flatten::Flatten in the type name looks wrong, that should start with futures or futures_util. https://docs.rs/futures/latest/futures/prelude/future/struct.Flatten.html

jyn514 commented 11 months ago

(for posterity, this code does compile)

    let azure_stream = blob_client.get().into_stream().map_ok(|chunk| {
        chunk.data
    }).try_flatten();