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

Detect type mismatch due to loop that might never iterate #98982

Closed
estebank opened this issue Jul 6, 2022 · 9 comments · Fixed by #118072
Closed

Detect type mismatch due to loop that might never iterate #98982

estebank opened this issue Jul 6, 2022 · 9 comments · Fixed by #118072
Assignees
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix`. D-papercut Diagnostics: An error or lint that needs small tweaks. D-terse Diagnostics: An error or lint that doesn't give enough information about the problem at hand. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@estebank
Copy link
Contributor

estebank commented Jul 6, 2022

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 estebank 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. A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix`. D-papercut Diagnostics: An error or lint that needs small tweaks. 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 Jul 6, 2022
@lyming2007
Copy link

@rustbot claim

@lyming2007
Copy link

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

@estebank
Copy link
Contributor Author

@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.

@lyming2007
Copy link

lyming2007 commented Jul 28, 2022

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
Copy link

lyming2007 commented Aug 3, 2022

#100094

@estebank
Copy link
Contributor Author

estebank commented Aug 3, 2022

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

@lyming2007
Copy link

@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 pushed a commit to lyming2007/rust that referenced this issue Aug 5, 2022
when loop as tail expression for miss match type E0308 error, recursively get
the return statement and add diagnostic information on it
use rustc_hir::intravisit to collect the return expression
	modified:   compiler/rustc_typeck/src/check/coercion.rs
	new file:   src/test/ui/typeck/issue-98982.rs
	new file:   src/test/ui/typeck/issue-98982.stderr
@lyming2007
Copy link

@estebank thanks for the review and suggestions.
Can you take a look at #99064 by the way? It's been a while since I fixed it

@estebank
Copy link
Contributor Author

estebank commented Jan 5, 2023

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 estebank removed the D-newcomer-roadblock Diagnostics: Confusing error or lint; hard to understand for new users. label Jan 5, 2023
estebank added a commit to estebank/rust that referenced this issue Nov 19, 2023
We currently provide only a `help` message, this PR introduces the last
two structured suggestions instead:

```
error[E0308]: mismatched types
  --> $DIR/issue-98982.rs:2:5
   |
LL |   fn foo() -> i32 {
   |               --- expected `i32` because of return type
LL | /     for i in 0..0 {
LL | |         return i;
LL | |     }
   | |_____^ expected `i32`, found `()`
   |
note: the function expects a value to always be returned, but loops might run zero times
  --> $DIR/issue-98982.rs:2:5
   |
LL |     for i in 0..0 {
   |     ^^^^^^^^^^^^^ this might have zero elements to iterate on
LL |         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
   |
LL ~     }
LL ~     /* `i32` value */
   |
help: otherwhise consider changing the return type to account for that possibility
   |
LL ~ fn foo() -> Option<i32> {
LL |     for i in 0..0 {
LL ~         return Some(i);
LL ~     }
LL ~     None
   |
```

Fix rust-lang#98982.
estebank added a commit to estebank/rust that referenced this issue Nov 19, 2023
We currently provide only a `help` message, this PR introduces the last
two structured suggestions instead:

```
error[E0308]: mismatched types
  --> $DIR/issue-98982.rs:2:5
   |
LL |   fn foo() -> i32 {
   |               --- expected `i32` because of return type
LL | /     for i in 0..0 {
LL | |         return i;
LL | |     }
   | |_____^ expected `i32`, found `()`
   |
note: the function expects a value to always be returned, but loops might run zero times
  --> $DIR/issue-98982.rs:2:5
   |
LL |     for i in 0..0 {
   |     ^^^^^^^^^^^^^ this might have zero elements to iterate on
LL |         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
   |
LL ~     }
LL ~     /* `i32` value */
   |
help: otherwhise consider changing the return type to account for that possibility
   |
LL ~ fn foo() -> Option<i32> {
LL |     for i in 0..0 {
LL ~         return Some(i);
LL ~     }
LL ~     None
   |
```

Fix rust-lang#98982.
estebank added a commit to estebank/rust that referenced this issue Nov 19, 2023
We currently provide only a `help` message, this PR introduces the last
two structured suggestions instead:

```
error[E0308]: mismatched types
  --> $DIR/issue-98982.rs:2:5
   |
LL |   fn foo() -> i32 {
   |               --- expected `i32` because of return type
LL | /     for i in 0..0 {
LL | |         return i;
LL | |     }
   | |_____^ expected `i32`, found `()`
   |
note: the function expects a value to always be returned, but loops might run zero times
  --> $DIR/issue-98982.rs:2:5
   |
LL |     for i in 0..0 {
   |     ^^^^^^^^^^^^^ this might have zero elements to iterate on
LL |         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
   |
LL ~     }
LL ~     /* `i32` value */
   |
help: otherwise consider changing the return type to account for that possibility
   |
LL ~ fn foo() -> Option<i32> {
LL |     for i in 0..0 {
LL ~         return Some(i);
LL ~     }
LL ~     None
   |
```

Fix rust-lang#98982.
bors added a commit to rust-lang-ci/rust that referenced this issue Dec 3, 2023
Provide structured suggestion for type mismatch in loop

We currently provide only a `help` message, this PR introduces the last two structured suggestions instead:

```
error[E0308]: mismatched types
  --> $DIR/issue-98982.rs:2:5
   |
LL |   fn foo() -> i32 {
   |               --- expected `i32` because of return type
LL | /     for i in 0..0 {
LL | |         return i;
LL | |     }
   | |_____^ expected `i32`, found `()`
   |
note: the function expects a value to always be returned, but loops might run zero times
  --> $DIR/issue-98982.rs:2:5
   |
LL |     for i in 0..0 {
   |     ^^^^^^^^^^^^^ this might have zero elements to iterate on
LL |         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
   |
LL ~     }
LL ~     /* `i32` value */
   |
help: otherwise consider changing the return type to account for that possibility
   |
LL ~ fn foo() -> Option<i32> {
LL |     for i in 0..0 {
LL ~         return Some(i);
LL ~     }
LL ~     None
   |
```

Fix rust-lang#98982.
@bors bors closed this as completed in 45efb8e Dec 3, 2023
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-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix`. D-papercut Diagnostics: An error or lint that needs small tweaks. D-terse Diagnostics: An error or lint that doesn't give enough information about the problem at hand. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants