Misleading suggestion for missing trait bounds

c4939e3
Opened by Josh Stone at 2024-10-04 23:33:05

This is a simplified version of https://users.rust-lang.org/t/solved-iterator-filter-and-zip-in-place/9809/4

trait Foo {
    fn foo(self) -> Self;
}

impl<I, T, U> Foo for I
    where I: Iterator<Item = (T, U)>
{
    fn foo(self) -> Self {
        self
    }
}

fn main() {
    let v = vec![(1, 'a'), (2, 'b'), (3, 'c')];
    for x in v.iter().foo() {
        println!("{:?}", x);
    }
}

The error is:

error: no method named `foo` found for type `std::slice::Iter<'_, ({integer}, char)>` in the current scope
  --> <anon>:15:23
   |
15 |     for x in v.iter().foo() {
   |                       ^^^
   |
   = note: the method `foo` exists but the following trait bounds were not satisfied: `&std::slice::Iter<'_, ({integer}, char)> : std::iter::Iterator`
   = help: items from traits can only be used if the trait is implemented and in scope; the following trait defines an item `foo`, perhaps you need to implement it:
   = help: candidate #1: `Foo`

The note: chose to report missing &Iter: Iterator, which is true, but it's not best thing it could have noted. I guess it's looking at &Iter because of some auto-ref in the method call. But if you force it to use Iter directly with UFCS, like Foo::foo(v.iter()), the note is more useful.

error[E0271]: type mismatch resolving `<std::slice::Iter<'_, ({integer}, char)> as std::iter::Iterator>::Item == (_, _)`
  --> <anon>:15:14
   |
15 |     for x in Foo::foo(v.iter()) {
   |              ^^^^^^^^ expected reference, found tuple
   |
   = note: expected type `&({integer}, char)`
              found type `(_, _)`
   = note: required because of the requirements on the impl of `Foo` for `std::slice::Iter<'_, ({integer}, char)>`
   = note: required by `Foo::foo`

So we do have an Iterator, just the wrong Item.

  1. This is a simplified version of https://users.rust-lang.org/t/solved-iterator-filter-and-zip-in-place/9809/4

    trait Foo {
        fn foo(self) -> Self;
    }
    
    impl<I, T, U> Foo for I
        where I: Iterator<Item = (T, U)>
    {
        fn foo(self) -> Self {
            self
        }
    }
    
    fn main() {
        let v = vec![(1, 'a'), (2, 'b'), (3, 'c')];
        for x in v.iter().foo() {
            println!("{:?}", x);
        }
    }
    

    The error is:

    error: no method named `foo` found for type `std::slice::Iter<'_, ({integer}, char)>` in the current scope
      --> <anon>:15:23
       |
    15 |     for x in v.iter().foo() {
       |                       ^^^
       |
       = note: the method `foo` exists but the following trait bounds were not satisfied: `&std::slice::Iter<'_, ({integer}, char)> : std::iter::Iterator`
       = help: items from traits can only be used if the trait is implemented and in scope; the following trait defines an item `foo`, perhaps you need to implement it:
       = help: candidate #1: `Foo`
    

    The note: chose to report missing &Iter: Iterator, which is true, but it's not best thing it could have noted. I guess it's looking at &Iter because of some auto-ref in the method call. But if you force it to use Iter directly with UFCS, like Foo::foo(v.iter()), the note is more useful.

    error[E0271]: type mismatch resolving `<std::slice::Iter<'_, ({integer}, char)> as std::iter::Iterator>::Item == (_, _)`
      --> <anon>:15:14
       |
    15 |     for x in Foo::foo(v.iter()) {
       |              ^^^^^^^^ expected reference, found tuple
       |
       = note: expected type `&({integer}, char)`
                  found type `(_, _)`
       = note: required because of the requirements on the impl of `Foo` for `std::slice::Iter<'_, ({integer}, char)>`
       = note: required by `Foo::foo`
    

    So we do have an Iterator, just the wrong Item.

    Esteban Kuber at 2019-04-29 00:35:10

  2. Current output:

    error[E0599]: no method named `foo` found for type `std::slice::Iter<'_, ({integer}, char)>` in the current scope
      --> src/main.rs:15:23
       |
    15 |     for x in v.iter().foo() {
       |                       ^^^ method not found in `std::slice::Iter<'_, ({integer}, char)>`
       |
       = note: the method `foo` exists but the following trait bounds were not satisfied:
               `&mut std::slice::Iter<'_, ({integer}, char)> : Foo`
               `&std::slice::Iter<'_, ({integer}, char)> : Foo`
               `std::slice::Iter<'_, ({integer}, char)> : Foo`
       = help: items from traits can only be used if the trait is implemented and in scope
       = note: the following trait defines an item `foo`, perhaps you need to implement it:
               candidate #1: `Foo`
    

    Esteban Kuber at 2019-10-15 18:09:54

  3. Triage: no change.

    Esteban Kuber at 2020-02-03 18:49:40

  4. Current output, very little change:

    error[E0599]: no method named `foo` found for struct `std::slice::Iter<'_, ({integer}, char)>` in the current scope
        --> src/main.rs:15:23
         |
    15   |       for x in v.iter().foo() {
         |                         ^^^ method not found in `std::slice::Iter<'_, ({integer}, char)>`
         |
         = note: the method `foo` exists but the following trait bounds were not satisfied:
                 `<std::slice::Iter<'_, ({integer}, char)> as std::iter::Iterator>::Item = (_, _)`
                 which is required by `std::slice::Iter<'_, ({integer}, char)>: Foo`
                 `<&std::slice::Iter<'_, ({integer}, char)> as std::iter::Iterator>::Item = (_, _)`
                 which is required by `&std::slice::Iter<'_, ({integer}, char)>: Foo`
                 `&std::slice::Iter<'_, ({integer}, char)>: std::iter::Iterator`
                 which is required by `&std::slice::Iter<'_, ({integer}, char)>: Foo`
                 `<&mut std::slice::Iter<'_, ({integer}, char)> as std::iter::Iterator>::Item = (_, _)`
                 which is required by `&mut std::slice::Iter<'_, ({integer}, char)>: Foo`
    

    Esteban Kuber at 2020-06-15 19:20:35

  5. Current output:

    error[[E0599]](https://doc.rust-lang.org/nightly/error_codes/E0599.html): the method `foo` exists for struct `Iter<'_, ({integer}, char)>`, but its trait bounds were not satisfied
      --> src/main.rs:15:23
       |
    15 |     for x in v.iter().foo() {
       |                       ^^^ method cannot be called on `Iter<'_, ({integer}, char)>` due to unsatisfied trait bounds
      --> /rustc/8131b9774ebcb6c162fcac71545a13543ec369e7/library/core/src/slice/iter.rs:62:1
       |
       = note: doesn't satisfy `<_ as Iterator>::Item = (_, _)`
       |
       = note: doesn't satisfy `std::slice::Iter<'_, ({integer}, char)>: Foo`
       |
    note: the following trait bounds were not satisfied:
          `&std::slice::Iter<'_, ({integer}, char)>: Iterator`
          `<&mut std::slice::Iter<'_, ({integer}, char)> as Iterator>::Item = (_, _)`
          `<&std::slice::Iter<'_, ({integer}, char)> as Iterator>::Item = (_, _)`
          `<std::slice::Iter<'_, ({integer}, char)> as Iterator>::Item = (_, _)`
      --> src/main.rs:6:14
       |
    5  | impl<I, T, U> Foo for I
       |               ---     -
    6  |     where I: Iterator<Item = (T, U)>
       |              ^^^^^^^^^^^^^^^^^^^^^^^
       |              |        |
       |              |        unsatisfied trait bound introduced here
       |              unsatisfied trait bound introduced here
    

    Esteban Kuber at 2023-08-03 19:18:08

  6. Another case from #36513:

    pub trait JoinWithString { 
      fn join(self, separator: &'static str) -> String; 
    } 
    
    impl<X> JoinWithString for X 
      where X: Iterator<Item = String> 
    { 
      fn join(self, separator: &'static str) -> String { 
        unimplemented!()
      } 
    }
    
    
    fn main() {
        let a: Vec<std::path::PathBuf> = Vec::new();
        a.iter().map(|x| x.to_str().unwrap()).join(":");
    }
    

    Esteban Kuber at 2024-02-15 02:29:24

  7. Current output:

    error[E0599]: no method named `foo` found for struct `std::slice::Iter<'_, ({integer}, char)>` in the current scope
      --> src/main.rs:15:23
       |
    15 |     for x in v.iter().foo() {
       |                       ^^^ `std::slice::Iter<'_, ({integer}, char)>` is not an iterator
       |
    help: call `.into_iter()` first
       |
    15 |     for x in v.iter().into_iter().foo() {
       |                       ++++++++++++
    

    The suggestion is incorrect. It should instead tell the user to replace iter() with into_iter().

    Esteban Kuber at 2024-10-04 23:32:08