Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Confusing error when summing iterator of () #105184

Closed
jvns opened this issue Dec 2, 2022 · 9 comments
Closed

Confusing error when summing iterator of () #105184

jvns opened this issue Dec 2, 2022 · 9 comments
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-traits Area: Trait system D-papercut Diagnostics: An error or lint that needs small tweaks. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@jvns
Copy link
Contributor

jvns commented Dec 2, 2022

Here's some code (playground):

fn main() {
    vec![(), ()].iter().sum::<i32>();
}

This has an obvious bug: You can't sum a bunch of () and get an i32 as a result. Here's the error message, though:

2 |     vec![(), ()].iter().sum::<i32>();
  |     ^^^^^^^^^^^^^^^^^^^ --- required by a bound introduced by this call
  |     |
  |     the trait `Sum<&()>` is not implemented for `i32`

This was very confusing to me -- I'd expect to see an error saying something like Sum not implemented for Iter<()>. But instead it says that Sum is not implemented for i32 But I'm not trying to sum i32s!

(my actual bug was actually that I'd accidentally added an extra ; in my code, so that I was trying to sum ()s instead of i32, and the confusing error message made it harder to figure out that out)

What's actually going on here is:

  • i32 has a static method called sum(iter: Iter<i32>), that comes from the Sum trait.
  • Iter has a sum() method that calls this static method on i32
  • when I run my_iter.sum(), it tries to call i32::sum(my_iter)
  • i32::sum isn't defined for Iter<()>
  • as a result, we get the error message the trait Sum<&()>is not implemented fori32``

I might not have gotten all the types/terms exactly right, but I think that's the gist of it.

This all makes sense, but it's was pretty confusing for me to unwind. Maybe the compiler could have helped me unwind it?

reporting as requested by @estebank

@jvns jvns added A-diagnostics Area: Messages for errors, warnings, and lints T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Dec 2, 2022
@estebank estebank added A-traits Area: Trait system D-confusing Diagnostics: Confusing error or lint that should be reworked. D-newcomer-roadblock Diagnostics: Confusing error or lint; hard to understand for new users. D-terse Diagnostics: An error or lint that doesn't give enough information about the problem at hand. labels Dec 2, 2022
@estebank
Copy link
Contributor

estebank commented Dec 2, 2022

@jvns out of curiosity, what dev environment were you using? Was it the playground, VSCode, IntelliJ or running rustc/cargo in the terminal?

The output from the terminal gives a little extra context that helps to piece together some of the bullet points (the last note), but of course I'd like to add a bit more context than we have today:

error[E0277]: the trait bound `i32: Sum<()>` is not satisfied
    --> f52.rs:6:20
     |
6    |     println!("{}", scores.sum::<i32>());
     |                    ^^^^^^ --- required by a bound introduced by this call
     |                    |
     |                    the trait `Sum<()>` is not implemented for `i32`
     |
     = help: the following other types implement trait `Sum<A>`:
               <f32 as Sum<&'a f32>>
               <f32 as Sum>
               <f64 as Sum<&'a f64>>
               <f64 as Sum>
               <i128 as Sum<&'a i128>>
               <i128 as Sum>
               <i16 as Sum<&'a i16>>
               <i16 as Sum>
             and 20 others
note: required by a bound in `std::iter::Iterator::sum`
    --> /Users/ekuber/workspace/rust/library/core/src/iter/traits/iterator.rs:3379:12
     |
3379 |         S: Sum<Self::Item>,
     |            ^^^^^^^^^^^^^^^ required by this bound in `std::iter::Iterator::sum`

@drewtato
Copy link

drewtato commented Dec 4, 2022

Could this look like collect's error? It has a similar trait-on-return-type structure. Example of collect's current error:

a value of type `Vec<i32>` cannot be built from an iterator over elements of type `&()`

sum's error could say:

a sum of type `i32` cannot be built from an iterator over elements of type `&()`

or

a value of type `i32` cannot be created by summing an iterator over elements of type `&()`

Ideally this would say "...cannot be summarized from...", but "summarized" has been too far separated from "sum" in English.1

I don't really like having "an iterator over" in either of these but I'd either include it for consistency, or remove it from both.

Also don't forget Iterator::product.

Footnotes

  1. Likewise, collect could say "cannot be collected from" which does work in English, but that's for a different issue.

@jruderman
Copy link
Contributor

I'd use "summed" rather than "summarized" in this context

@drewtato
Copy link

drewtato commented Dec 4, 2022

The problem with "summed" is that it is a thing you do to the individual items and not a thing you do to the result. You can say "I summed two numbers" but you can't say "I summed the answer". The latter suggests you added the answer to something else, not that you added things to get the answer.

@jvns
Copy link
Contributor Author

jvns commented Dec 4, 2022

I was using rustc in the terminal (version (897e37553 2022-11-02)). I do see the note: required by a bound in std::iter::Iterator::sum message now, but I probably ignored it when I originally saw it, because I didn't really know what "a bound" is.

I don't see this part of the error message though:

     |
3379 |         S: Sum<Self::Item>,
     |            ^^^^^^^^^^^^^^^ required by this bound in `std::iter::Iterator::sum`

this seems much clearer to me:

a value of type `i32` cannot be created by summing an iterator over elements of type `&()`

@fee1-dead
Copy link
Member

I think we can make this a rustc_on_unimplemented note.

@fee1-dead fee1-dead added E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue. E-mentor Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion. labels Dec 4, 2022
@estebank
Copy link
Contributor

estebank commented Dec 5, 2022

I have the following output:

error[E0277]: the trait bound `i32: Sum<()>` is not satisfied
    --> src/test/ui/iterators/invalid-iterator-chain.rs:7:20
     |
7    |     println!("{}", scores.sum::<i32>());
     |                    ^^^^^^ --- required by a bound introduced by this call
     |                    |
     |                    the trait `Sum<()>` is not implemented for `i32`
     |
     = help: the following other types implement trait `Sum<A>`:
               <i32 as Sum<&'a i32>>
               <i32 as Sum>
note: the expression is of type `Map<std::slice::Iter<'_, ({integer}, {integer})>, [closure@src/test/ui/iterators/invalid-iterator-chain.rs:4:14: 4:22]>`
    --> src/test/ui/iterators/invalid-iterator-chain.rs:7:20
     |
2    |       let scores = vec![(0, 0)]
     |                    ------------ this expression has type `Vec<({integer}, {integer})>`
3    |           .iter()
     |            ------ associated type `std::iter::Iterator::Item` is `&({integer}, {integer})` here
4    |           .map(|(a, b)| {
     |  __________-
5    | |             a + b;
6    | |         });
     | |__________- associated type `std::iter::Iterator::Item` is `()` here
7    |       println!("{}", scores.sum::<i32>());
     |                      ^^^^^^
note: required by a bound in `std::iter::Iterator::sum`
    --> /Users/ekuber/workspace/rust/library/core/src/iter/traits/iterator.rs:3379:12
     |
3379 |         S: Sum<Self::Item>,
     |            ^^^^^^^^^^^^^^^ required by this bound in `std::iter::Iterator::sum`

Along with @aDotInTheVoid's change the output would be:

error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `()`
    --> src/test/ui/iterators/invalid-iterator-chain.rs:7:20
     |
7    |     println!("{}", scores.sum::<i32>());
     |                    ^^^^^^ --- required by a bound introduced by this call
     |                    |
     |                    value of type `i32` cannot be made by summing a `std::iter::Iterator<Item=()>`
     |
     = note: the trait bound `i32: Sum<()>` is not satisfied
     = help: the following other types implement trait `Sum<A>`:
               <i32 as Sum<&'a i32>>
               <i32 as Sum>
note: the expression is of type `Map<std::slice::Iter<'_, ({integer}, {integer})>, [closure@src/test/ui/iterators/invalid-iterator-chain.rs:4:14: 4:22]>`
    --> src/test/ui/iterators/invalid-iterator-chain.rs:7:20
     |
2    |       let scores = vec![(0, 0)]
     |                    ------------ this expression has type `Vec<({integer}, {integer})>`
3    |           .iter()
     |            ------ associated type `std::iter::Iterator::Item` is `&({integer}, {integer})` here
4    |           .map(|(a, b)| {
     |  __________-
5    | |             a + b;
6    | |         });
     | |__________- associated type `std::iter::Iterator::Item` is `()` here
7    |       println!("{}", scores.sum::<i32>());
     |                      ^^^^^^
note: required by a bound in `std::iter::Iterator::sum`
    --> /Users/ekuber/workspace/rust/library/core/src/iter/traits/iterator.rs:3379:12
     |
3379 |         S: Sum<Self::Item>,
     |            ^^^^^^^^^^^^^^^ required by this bound in `std::iter::Iterator::sum`

I'm exploring how I can make the "the following impls" note less verbose.

Dylan-DPC added a commit to Dylan-DPC/rust that referenced this issue Dec 9, 2022
…lemented, r=estebank

Add `rustc_on_unimplemented` to `Sum` and `Product` trait.

Helps with rust-lang#105184, but I don't think it fully fixes it.
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Dec 9, 2022
…lemented, r=estebank

Add `rustc_on_unimplemented` to `Sum` and `Product` trait.

Helps with rust-lang#105184, but I don't think it fully fixes it.
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Dec 13, 2022
Point out the type of associated types in every method call of iterator chains

Partially address rust-lang#105184 by pointing out the type of associated types in every method call of iterator chains:

```
note: the expression is of type `Map<std::slice::Iter<'_, {integer}>, [closure@src/test/ui/iterators/invalid-iterator-chain.rs:12:18: 12:21]>`
    --> src/test/ui/iterators/invalid-iterator-chain.rs:12:14
     |
10   |         vec![0, 1]
     |         ---------- this expression has type `Vec<{integer}>`
11   |             .iter()
     |              ------ associated type `std::iter::Iterator::Item` is `&{integer}` here
12   |             .map(|x| { x; })
     |              ^^^^^^^^^^^^^^^ associated type `std::iter::Iterator::Item` is `()` here
```

We also reduce the number of impls we mention when any of the candidates is an "exact match". This benefits the output of cases with numerics greatly.

Outstanding work would be to provide a structured suggestion for appropriate changes, like in this case detecting the spurious `;` in the closure.
@fee1-dead fee1-dead removed E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue. E-mentor Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion. labels Dec 13, 2022
@estebank estebank added D-papercut Diagnostics: An error or lint that needs small tweaks. and removed D-confusing Diagnostics: Confusing error or lint that should be reworked. D-newcomer-roadblock Diagnostics: Confusing error or lint; hard to understand for new users. D-terse Diagnostics: An error or lint that doesn't give enough information about the problem at hand. labels Dec 13, 2022
@estebank
Copy link
Contributor

estebank commented Dec 13, 2022

Given the current output, I believe the only outstanding work is to look at the involved closures and point at stray ;s.

error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `()`
  --> $DIR/invalid-iterator-chain.rs:7:27
   |
LL |     println!("{}", scores.sum::<i32>());
   |                           ^^^ value of type `i32` cannot be made by summing a `std::iter::Iterator<Item=()>`
   |
   = help: the trait `Sum<()>` is not implemented for `i32`
   = help: the following other types implement trait `Sum<A>`:
             <i32 as Sum<&'a i32>>
             <i32 as Sum>
note: the method call chain might not have had the expected associated types
  --> $DIR/invalid-iterator-chain.rs:4:10
   |
LL |       let scores = vec![(0, 0)]
   |                    ------------ this expression has type `Vec<({integer}, {integer})>`
LL |           .iter()
   |            ------ `Iterator::Item` is `&({integer}, {integer})` here
LL |           .map(|(a, b)| {
   |  __________^
LL | |             a + b;
LL | |         });
   | |__________^ `Iterator::Item` changed to `()` here
note: required by a bound in `std::iter::Iterator::sum`
  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
   |
LL |         S: Sum<Self::Item>,
   |            ^^^^^^^^^^^^^^^ required by this bound in `Iterator::sum`

@estebank
Copy link
Contributor

Current output:

error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `&()`
 --> src/main.rs:2:31
  |
2 |     vec![(), ()].iter().sum::<i32>();
  |                         ---   ^^^ value of type `i32` cannot be made by summing a `std::iter::Iterator<Item=&()>`
  |                         |
  |                         required by a bound introduced by this call
  |
  = help: the trait `Sum<&()>` is not implemented for `i32`
  = help: the following other types implement trait `Sum<A>`:
            <i32 as Sum>
            <i32 as Sum<&'a i32>>
note: the method call chain might not have had the expected associated types
 --> src/main.rs:2:18
  |
2 |     vec![(), ()].iter().sum::<i32>();
  |     ------------ ^^^^^^ `Iterator::Item` is `&()` here
  |     |
  |     this expression has type `Vec<()>`
note: required by a bound in `std::iter::Iterator::sum`
 --> /rustc/6b771f6b5a6c8b03b6322a9c77ac77cb346148f0/library/core/src/iter/traits/iterator.rs:3630:5
error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `()`
 --> src/main.rs:2:47
  |
2 |     vec![1, 2].iter().map(|x| {x + 1;}).sum::<i32>();
  |                                         ---   ^^^ value of type `i32` cannot be made by summing a `std::iter::Iterator<Item=()>`
  |                                         |
  |                                         required by a bound introduced by this call
  |
  = help: the trait `Sum<()>` is not implemented for `i32`
  = help: the following other types implement trait `Sum<A>`:
            <i32 as Sum>
            <i32 as Sum<&'a i32>>
note: the method call chain might not have had the expected associated types
 --> src/main.rs:2:23
  |
2 |     vec![1, 2].iter().map(|x| {x + 1;}).sum::<i32>();
  |     ---------- ------ ^^^^^^^^^^^^^^^^^ `Iterator::Item` changed to `()` here
  |     |          |
  |     |          `Iterator::Item` is `&{integer}` here
  |     this expression has type `Vec<{integer}>`
note: required by a bound in `std::iter::Iterator::sum`
 --> /rustc/6b771f6b5a6c8b03b6322a9c77ac77cb346148f0/library/core/src/iter/traits/iterator.rs:3630:5
help: consider removing this semicolon
  |
2 -     vec![1, 2].iter().map(|x| {x + 1;}).sum::<i32>();
2 +     vec![1, 2].iter().map(|x| {x + 1}).sum::<i32>();
  |

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-traits Area: Trait system D-papercut Diagnostics: An error or lint that needs small tweaks. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

5 participants