Skip to content

Detect method chains that call methods that aren't meant to be chained #104204

Closed
@estebank

Description

@estebank

In long method chains we might inadvertently call a method that is not meant to be chained. When this happens, the most likely error to occur is a type error involving (). We should instead look if the rhs expression is a method chain and look at all the chained call's type to find where () is introduced.

Given

let x: Vec<i32> = vec![1, 2, 3].into_iter().collect::<Vec<i32>>().sort_by_key(|i| i);
let x: Vec<i32> = vec![1, 2, 3].into_iter().collect::<Vec<i32>>().sort_by_key(|i| i).sort();

we emit

error[[E0308]](https://doc.rust-lang.org/nightly/error-index.html#E0308): mismatched types
 --> src/main.rs:2:23
  |
2 |     let x: Vec<i32> = vec![1, 2, 3].into_iter().collect::<Vec<i32>>().sort_by_key(|i| i);
  |            --------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `Vec`, found `()`
  |            |
  |            expected due to this
  |
  = note: expected struct `Vec<i32>`
          found unit type `()`

error[[E0599]](https://doc.rust-lang.org/nightly/error-index.html#E0599): no method named `sort` found for unit type `()` in the current scope
 --> src/main.rs:3:90
  |
3 |     let x: Vec<i32> = vec![1, 2, 3].into_iter().collect::<Vec<i32>>().sort_by_key(|i| i).sort();
  |                                                                                          ^^^^ method not found in `()`

Ideally the output would be closer to

error[E0308]: mismatched types
 --> src/main.rs:2:23
  |
2 |     let x: Vec<i32> = vec![1, 2, 3].into_iter().collect::<Vec<i32>>().sort_by_key(|i| i);
  |            --------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `Vec`, found `()`
  |            |
  |            expected due to this
  |
  = note: expected struct `Vec<i32>`
          found unit type `()`
help: `sort_by_key` takes `&mut self` and returns `()`, it isn't meant to be used in method chains
 --> src/main.rs:2:23
  |
2 |     let x: Vec<i32> = vec![1, 2, 3].into_iter().collect::<Vec<i32>>().sort_by_key(|i| i);
  |                                                                       ^^^^^^^^^^^^^^^^^^ takes `&mut self` and returns `()`, it is not meant to be chained 
  |
help: introduce a binding and call `sort_by_key` on it
  |
2 ~     let mut x: Vec<i32> = vec![1, 2, 3].into_iter().collect::<Vec<i32>>();
3 +     x.sort_by_key(|i| i);
  |

error[E0599]: no method named `sort` found for unit type `()` in the current scope
 --> src/main.rs:3:90
  |
3 |     let x: Vec<i32> = vec![1, 2, 3].into_iter().collect::<Vec<i32>>().sort_by_key(|i| i).sort();
  |                                                                                          ^^^^ method not found in `()`
help: an earlier method call is of type `Vec<i32>`, which has method `sort`
 --> src/main.rs:3:90
  |
3 |     let x: Vec<i32> = vec![1, 2, 3].into_iter().collect::<Vec<i32>>().sort_by_key(|i| i).sort();
  |                                                ^^^^^^^^^^^^^^^^^^^^^^ ------------------ takes `&mut self` and returns `()`, it is not meant to be chained
  |                                                |
  |                                                `sort` can be called after this method call

Metadata

Metadata

Assignees

Labels

A-diagnosticsArea: Messages for errors, warnings, and lintsA-suggestion-diagnosticsArea: Suggestions generated by the compiler applied by `cargo fix`D-newcomer-roadblockDiagnostics: Confusing error or lint; hard to understand for new users.D-papercutDiagnostics: An error or lint that needs small tweaks.D-terseDiagnostics: An error or lint that doesn't give enough information about the problem at hand.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions