rust-lang / rust

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

"is not an iterator" diagnostic through blanket implementation, when the type is actually an iterator but is missing a marker #127511

Open progval opened 2 months ago

progval commented 2 months ago

Code

(inspired by rayon's ParallelBridge)

pub trait ParallelBridge: Sized {
    // Required method
    fn par_bridge(self) -> ();
}

impl<T: Iterator + Send> ParallelBridge for T
where
    T::Item: Send,
{
    fn par_bridge(self) -> () {
        unimplemented!("par_bridge");
    }
}

fn f(it: impl Iterator<Item=u64>) {
    it.map(|i| i+1).par_bridge()
}

fn main() -> std::io::Result<()> {
    let (_tx, rx) = std::sync::mpsc::sync_channel(1000);
    f(rx.iter());

    Ok(())
}

playground

Current output

Compiling playground v0.0.1 (/playground)
error[E0599]: no method named `par_bridge` found for struct `Map<impl Iterator<Item = u64>, {closure@src/main.rs:17:12: 17:15}>` in the current scope
  --> src/main.rs:17:21
   |
17 |     it.map(|i| i+1).par_bridge()
   |                     ^^^^^^^^^^ `Map<impl Iterator<Item = u64>, {closure@src/main.rs:17:12: 17:15}>` is not an iterator
   |
help: call `.into_iter()` first
   |
17 |     it.map(|i| i+1).into_iter().par_bridge()
   |                     ++++++++++++

For more information about this error, try `rustc --explain E0599`.
error: could not compile `playground` (bin "playground") due to 1 previous error

Desired output

The same error there is when removing the .map()

   Compiling playground v0.0.1 (/playground)
error[E0599]: no method named `par_bridge` found for type parameter `impl Iterator<Item = u64>` in the current scope
  --> src/main.rs:17:8
   |
16 | fn f(it: impl Iterator<Item=u64>) {
   |          ----------------------- method `par_bridge` not found for this type parameter
17 |     it.map(|i| i+1).par_bridge()
   |        ^^^^^^^^^^ method cannot be called on `impl Iterator<Item = u64>` due to unsatisfied trait bounds
   |
   = help: items from traits can only be used if the type parameter is bounded by the trait
help: the following trait defines an item `par_bridge`, perhaps you need to restrict type parameter `impl Iterator<Item = u64>` with it:
   |
16 | fn f(it: impl Iterator<Item=u64> + ParallelBridge) {
   |                                  ++++++++++++++++

For more information about this error, try `rustc --explain E0599`.
error: could not compile `playground` (bin "playground") due to 1 previous error

Rationale and extra context

The error indicated the type does not implement Iterator, even though it does and Send is the one that is missing.

Other cases

No response

Rust Version

rustc 1.79.0

Anything else?

No response

GrigorenkoPV commented 2 months ago

Similar to #124802?

kpreid commented 2 months ago

Here is a slightly smaller reproduction that only uses core and has a more egregious error message (“impl Iterator is not an iterator”). Reduced from a case found by @zakarumych.

trait Missing {}
trait HasMethod {
    fn foo(self);
}
impl<T: Iterator + Missing> HasMethod for T {
    fn foo(self) {}
}

fn get_iter() -> impl Iterator {
    // any Iterator impl will do
    core::iter::once(())
}

fn main() {
    get_iter().foo();
}
error[E0599]: no method named `foo` found for opaque type `impl Iterator` in the current scope
  --> src/main.rs:15:16
   |
15 |     get_iter().foo();
   |                ^^^ `impl Iterator` is not an iterator
   |
help: call `.into_iter()` first
   |
15 |     get_iter().into_iter().foo();
   |                ++++++++++++