rust icon indicating copy to clipboard operation
rust copied to clipboard

Detect type mismatch due to loop that might never iterate

Open estebank opened this issue 3 years ago • 8 comments

Given

fn foo() -> i32 {
    for i in 0..0 {
        return i;
    }
}

the current output is

error[E0308]: mismatched types
 --> src/lib.rs:2:5
  |
1 |   fn foo() -> i32 {
  |               --- expected `i32` because of return type
2 | /     for i in 0..0 {
3 | |         return i;
4 | |     }
  | |_____^ expected `i32`, found `()`

If a return statement is present in the tail expression, and that tail expression is a loop, it should provide more information for newcomers:

error[E0308]: mismatched types
 --> src/lib.rs:2:5
  |
1 |   fn foo() -> i32 {
  |               --- expected `i32` because of return type
2 | /     for i in 0..0 {
3 | |         return i;
4 | |     }
  | |_____^ expected `i32`, found `()`
note: the function expects a value to always be returned, but loops might run zero times
 --> src/lib.rs:2:5
  |
2 |     for i in 0..0 {
  |              ^^^^ this might have zero elements to iterate on
3 |         return i;
  |                - if the loop doesn't execute, this value would never get returned
help: return a value for the case when the loop has zero elements to iterate on, and consider changing the return type to account for that possibility
  |
1 ~ fn foo() -> Option<i32> {
...
5 +     None
  |

estebank avatar Jul 06 '22 17:07 estebank

@rustbot claim

lyming2007 avatar Jul 19 '22 03:07 lyming2007

do we need to duplicate the statement of loop to emit more information? How about the output like this?

error[E0308]: mismatched types
 --> src/lib.rs:2:5
  |
1 |   fn foo() -> i32 {
  |               --- expected `i32` because of return type
2 | /     for i in 0..0 {
   |           ^^^^ this might have zero elements to iterate on
3 | |         return i;
   |                - if the loop doesn't execute, this value would never get returned
help: return a value for the case when the loop has zero elements to iterate on, and consider changing the return type to account for that possibility
4 | |     }
  | |_____^ expected `i32`, found `()`
note: the function expects a value to always be returned, but loops might run zero times

lyming2007 avatar Jul 20 '22 14:07 lyming2007

@lyming2007 that might work as well, but I'd like to see what it looks like in the terminal, as too much text density can affect readability. The note for example is redundant with the label in line 2, so that could be removed when we show the label.

estebank avatar Jul 20 '22 19:07 estebank

now the output looks like:

error[E0308]: mismatched types
 --> main.rs:2:5
  |
1 |   fn foo() -> i32 {
  |               --- expected `i32` because of return type
2 | /     for i in 0..0 {
3 | |         return i;
4 | |     }
  | |_____^ expected `i32`, found `()`

note: the function expects a value to always be returned, but loops might run zero times
 --> main.rs:2:5
  |
2 |       for i in 0..0 {
  |       ^------------
  |       |
  |  _____this might have zero elements to iterate on
  | |
3 | |         return i;
  | |         -------- if the loop doesn't execute, this value would never get returned
4 | |     }
  | |_____^
  |
  = help: return a value for the case when the loop has zero elements to iterate on, and consider changing the return type to account for that possibility

error: aborting due to previous error

Is that good enough? @estebank

lyming2007 avatar Jul 28 '22 16:07 lyming2007

https://github.com/rust-lang/rust/pull/100094

lyming2007 avatar Aug 03 '22 05:08 lyming2007

@lyming2007 that seems very close! I'll add comments in the PR.

estebank avatar Aug 03 '22 12:08 estebank

@lyming2007 that seems very close! I'll add comments in the PR.

committed the changes as you suggested which is very helpful. Please check if I missed anything. @estebank

lyming2007 avatar Aug 04 '22 21:08 lyming2007

@estebank thanks for the review and suggestions. Can you take a look at https://github.com/rust-lang/rust/pull/99064 by the way? It's been a while since I fixed it

lyming2007 avatar Aug 05 '22 23:08 lyming2007

Removing D-newcomer-roadblock as the current output is

error[E0308]: mismatched types
 --> src/lib.rs:2:5
  |
1 |   fn foo() -> i32 {
  |               --- expected `i32` because of return type
2 | /     for i in 0..0 {
3 | |         return i;
4 | |     }
  | |_____^ expected `i32`, found `()`
  |
note: the function expects a value to always be returned, but loops might run zero times
 --> src/lib.rs:2:5
  |
2 |     for i in 0..0 {
  |     ^^^^^^^^^^^^^ this might have zero elements to iterate on
3 |         return i;
  |         -------- if the loop doesn't execute, this value would never get returned
  = help: return a value for the case when the loop has zero elements to iterate on, or consider changing the return type to account for that possibility

and that's already great. Only thing left to do might be to add a structured suggestion.

estebank avatar Jan 05 '23 19:01 estebank