Expected associated type, found enum `std::result::Result`

Hi, I have an error with associated types that I do not understand:

My code looks roughly like this:

use bytes;
use std::io;
use futures::channel::mpsc;
use async_std::task;

pub fn my_rx() -> impl futures::TryStream<Ok=(bytes::Bytes, std::net::SocketAddr), Error=std::io::Error> {
        unimplemented!()
}

fn main() {
    let inet_rx = my_rx();
    let (tx1, inet_rx1) = mpsc::unbounded();
    let (tx2, inet_rx2) = mpsc::unbounded();
    let mut tx = tx1.fanout(tx2).sink_map_err(|_| io::Error::new(io::ErrorKind::Other, "Send Error"));
    let foo = inet_rx.forward(tx);
    let _ = task::spawn(foo);
}

And the error message I'm getting is:

error[E0271]: type mismatch resolving `<impl futures_core::stream::TryStream as futures_core::stream::Stream>::Item == std::result::Result<(bytes::bytes::Bytes, std::net::SocketAddr), std::io::Error>`
   --> src/main.rs:220:13
    |
220 |     let _ = task::spawn(foo);
    |             ^^^^^^^^^^^ expected associated type, found enum `std::result::Result`
    |
    = note: expected associated type `<impl futures_core::stream::TryStream as futures_core::stream::Stream>::Item`
                          found enum `std::result::Result<(bytes::bytes::Bytes, std::net::SocketAddr), std::io::Error>`
    = note: consider constraining the associated type `<impl futures_core::stream::TryStream as futures_core::stream::Stream>::Item` to `std::result::Result<(bytes::bytes::Bytes, std::net::SocketAddr), std::io::Error>` or calling a method that returns `<impl futures_core::stream::TryStream as futures_core::stream::Stream>::Item`
    = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
    = note: required because of the requirements on the impl of `core::future::future::Future` for `futures_util::stream::stream::forward::Forward<impl futures_core::stream::TryStream, futures_util::sink::map_err::SinkMapErr<futures_util::sink::fanout::Fanout<futures_channel::mpsc::UnboundedSender<(bytes::bytes::Bytes, std::net::SocketAddr)>, futures_channel::mpsc::UnboundedSender<(bytes::bytes::Bytes, std::net::SocketAddr)>>, [closure@src/main.rs:218:47: 218:101]>>`

So rust tells me that <TryStream as Stream>::Item is not eqal to Result<(Bytes, SocketAddr), io::Error>.
I really do not understand what the issue is here, because Stream::Item should be Result<TryStream::Ok, TryStream::Error> and that should be equal to Result<(Bytes, SocketAddr), io::Error>.

Can somebody tell me why the compiler is complaining?

You should not use TryStream as a return type, because while Streams always implement TryStream when the item is a result, the opposite is not true. It's an imperfect type alias that only goes one way.

fn my_rx() -> impl Stream<Item=Result<(Bytes, SocketAddr), io::Error>>

Interesting, this fixes the error. Thanks!
So the reason is that impl Stream<Item=Result<(Bytes, SocketAddr), io::Error>> is not necessarily equal to impl TryStream<Ok=(Bytes, SocketAddr), Error=io::Error>>.
Is that because impl Stream<Item=Result<T,E>> does not implement TryStream<Ok=T, Error=E>?

Yeah. It's the same situation with the From and Into traits. If you implement From, you get Into for free, but the opposite is not true. When you return Stream<Item = Result<...>>, that is definitely also a TryStream, but a TryStream might not be a Stream, so you can't use methods from Stream on something that is just a TryStream.

Okay, that's not quite right. A TryStream<T, E> is always a Stream, but there's no guarantee that it is a Stream<Item = Result<T, E>>. It might be a Stream<Item = SomeOtherType>.

You can't actually create such a stream, but that's because the trait is sealed. In the compiler's eyes, it would be backwards compatible for the futures crate to add such a stream with mismatching item types.

1 Like

I see, thank you for your explanation.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.