Skip to content

Improve compiler error on associated types #71035

Closed
@manuels

Description

@manuels

If you have a variable with type impl TryStream<Ok=T, Error=E> and want to use it as a impl Stream<Item=Result<T,E>>, the compiler complains.
The compiler does not take you by the hand and helps you with helpful hints.

I tried (roughly) this code: (EDIT: find a self-contained example here)

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

//pub fn my_rx(sock: std::sync::Arc<UdpSocket>) -> impl futures::Stream<Item=Result<(bytes::Bytes, std::net::SocketAddr), std::io::Error>> { // WORKS
pub fn my_rx(sock: std::sync::Arc<UdpSocket>) -> impl futures::TryStream<Ok=(bytes::Bytes, std::net::SocketAddr), Error=std::io::Error> { // ERROR
    ...
}

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);
}

I expected to see this happen:
I would like the compiler to tell me that that that while there exists an implementation of TryStream<Ok=T, Error=E> as Stream<Result<T,E>>, there might exist other implementations and therefore this code is not accepted. Using Stream<Result<T,E>> instead of TryStream<Ok=T, Error=E> would solve the error.

Instead, this happened:
There are no hints by the compiler.

Meta

rustc --version --verbose:

rustc 1.41.0-nightly (6d77e45f0 2019-12-04)
binary: rustc
commit-hash: 6d77e45f01079fe3d40180b3e256e414ab379f63
commit-date: 2019-12-04
host: x86_64-unknown-linux-gnu
release: 1.41.0-nightly
LLVM version: 9.0

Activity

jonas-schievink

jonas-schievink commented on Apr 11, 2020

@jonas-schievink
Contributor

Please provide a self-contained example that shows the bad diagnostic

added
A-associated-itemsArea: Associated items (types, constants & functions)
A-diagnosticsArea: Messages for errors, warnings, and lints
C-enhancementCategory: An issue proposing an enhancement or a PR with one.
T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
and removed
C-bugCategory: This is a bug.
on Apr 11, 2020
manuels

manuels commented on Apr 12, 2020

@manuels
Author

I tried to break it down to this code:

use futures::channel::mpsc;
use futures::stream::StreamExt;

//fn create_stream() -> impl futures::Stream<Item=Result<(), mpsc::SendError>> { // WORKS
fn create_stream() -> impl futures::TryStream<Ok=(), Error=mpsc::SendError> { // ERROR
    let (_, rx) = mpsc::unbounded();
    rx
}

fn main() {
    let rx = create_stream();
    let (tx, _) = mpsc::unbounded();
    let foo = rx.forward(tx);
    let _ = futures::executor::block_on(foo);
}
error[E0271]: type mismatch resolving `<impl futures_core::stream::TryStream as futures_core::stream::Stream>::Item == std::result::Result<(), futures_channel::mpsc::SendError>`
   --> src/main.rs:14:13
    |
5   | pub fn create_stream() -> impl futures::TryStream<Ok=(), Error=mpsc::SendError> { // ERROR
    |                           ----------------------------------------------------- the expected opaque type
...
14  |     let _ = futures::executor::block_on(foo);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected associated type, found enum `std::result::Result`
    | 
   ::: /playground/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-executor-0.3.4/src/local_pool.rs:315:20
    |
315 | pub fn block_on<F: Future>(f: F) -> F::Output {
    |                    ------ required by this bound in `futures_executor::local_pool::block_on`
    |
    = note: expected associated type `<impl futures_core::stream::TryStream as futures_core::stream::Stream>::Item`
                          found enum `std::result::Result<(), futures_channel::mpsc::SendError>`
    = note: consider constraining the associated type `<impl futures_core::stream::TryStream as futures_core::stream::Stream>::Item` to `std::result::Result<(), futures_channel::mpsc::SendError>` 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_channel::mpsc::UnboundedSender<()>>`

error[E0271]: type mismatch resolving `<impl futures_core::stream::TryStream as futures_core::stream::Stream>::Item == std::result::Result<(), futures_channel::mpsc::SendError>`
  --> src/main.rs:14:13
   |
5  | pub fn create_stream() -> impl futures::TryStream<Ok=(), Error=mpsc::SendError> { // ERROR
   |                           ----------------------------------------------------- the expected opaque type
...
14 |     let _ = futures::executor::block_on(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<(), futures_channel::mpsc::SendError>`
   = note: consider constraining the associated type `<impl futures_core::stream::TryStream as futures_core::stream::Stream>::Item` to `std::result::Result<(), futures_channel::mpsc::SendError>` 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_channel::mpsc::UnboundedSender<()>>`

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0271`.
error: could not compile `playground`.

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

manuels commented on Apr 12, 2020

@manuels
Author

I just found out that defining Stream::Item by hand also works:

fn create_stream() -> impl futures::TryStream<Ok=(), Error=mpsc::SendError,
Item=Result<(), mpsc::SendError>> {
    let (_, rx) = mpsc::unbounded();
    rx
}

Why is that? Is the compiler not able to deduce Stream::Item by itself?
Maybe the compiler should give a hint that declaring Stream::Item yourself would solve the problem.
You might argue that the error message

   = note: consider constraining the associated type `<impl futures_core::stream::TryStream as futures_core::stream::Stream>::Item` to `std::result::Result<(), futures_channel::mpsc::SendError>` or calling a method that returns `<impl futures_core::stream::TryStream as futures_core::stream::Stream>::Item`

does exactly this but it's not directly clear how to do this. Maybe giving an example like

   = note: consider constraining the associated type `<impl futures_core::stream::TryStream as futures_core::stream::Stream>::Item` to `std::result::Result<(), futures_channel::mpsc::SendError>` like this:
  --> src/main.rs:14:13
   |
5  | pub fn create_stream() -> impl futures::TryStream<Ok=(), Error=mpsc::SendError, Item=std::result::Result<(), futures_channel::mpsc::SendError>> {
   |
   = note: or calling a method that returns `<impl futures_core::stream::TryStream as futures_core::stream::Stream>::Item`

would be helpful here.

estebank

estebank commented on Apr 14, 2020

@estebank
Contributor

I think that #71108 might fulfill the last comment's request.

Edit: I just checked and the code doesn't account for impl Trait in return position (which behaves differently to impl Trait in argument position, which is handled). I'll see what I can do to also handle this case.

Edit 2: This will not be handled in the linked PR, it is a second order projection that will need further work for me to be able to supply a structured suggestion.

Edit 3: Managed to get it to work 🎉

error[E0271]: type mismatch resolving `<impl futures_core::stream::TryStream as futures_core::stream::Stream>::Item == std::result::Result<(), futures_channel::mpsc::SendError>`
   --> src/main.rs:14:13
    |
5   | fn create_stream() -> impl futures::TryStream<Ok=(), Error=mpsc::SendError> { // ERROR
    |                       ----------------------------------------------------- the expected opaque type
...
14  |     let _ = futures::executor::block_on(foo);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected associated type, found enum `std::result::Result`
    |
   ::: /Users/ekuber/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-executor-0.3.4/src/local_pool.rs:315:20
    |
315 | pub fn block_on<F: Future>(f: F) -> F::Output {
    |                    ------ required by this bound in `futures_executor::local_pool::block_on`
    |
    = note: expected associated type `<impl futures_core::stream::TryStream as futures_core::stream::Stream>::Item`
                          found enum `std::result::Result<(), futures_channel::mpsc::SendError>`
    = 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_channel::mpsc::UnboundedSender<()>>`
help: consider constraining the associated type `<impl futures_core::stream::TryStream as futures_core::stream::Stream>::Item` to `std::result::Result<(), futures_channel::mpsc::SendError>`
    |
5   | fn create_stream() -> impl futures::TryStream<Ok=(), Error=mpsc::SendError, Item = std::result::Result<(), futures_channel::mpsc::SendError>> { // ERROR
    |                                                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

It's a bit more verbose than I'd like, but we can tackle on a different PR.

added 2 commits that reference this issue on May 4, 2020
b0085c8

Auto merge of rust-lang#71108 - estebank:suggest-proj-type-mismatch-c…

d6823ba
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-associated-itemsArea: Associated items (types, constants & functions)A-diagnosticsArea: Messages for errors, warnings, and lintsA-type-systemArea: Type systemC-enhancementCategory: An issue proposing an enhancement or a PR with one.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

      Participants

      @manuels@Centril@estebank@jonas-schievink

      Issue actions

        Improve compiler error on associated types · Issue #71035 · rust-lang/rust