Repository: rust
Issue: Consolidate unused warnings into one diagnostic
Labels: A-diagnostics,T-compiler

## Proposal

During development there are often dozens of warnings about unused arguments,
unconstructed enum variants and unused struct fields.

- These are good! However they're very verbose, to the point of degrading the developer experience, printing a separate multi-line message for each unused item:

![Current verbose output](https://user-images.githubusercontent.com/2095902/139169289-d0ed61da-969c-4767-a842-30054fb5ea85.png)

- I am imagining a solution which produces output like:

```
warning: unused variables: `im`, `unused` 
 --> src/main.rs:18:25
   |
18 | fn demo(string: String, im: f32, unused: u32) {
   |                         ^^       ^^^^^^ help: if this is intentional, prefix with an underscore: `_im`, `_unused`
   |
```

### In a perfect world this would generalize further:
- unconstructed enum variants (consolidated by enum): 
```
warning: variants are never constructed: `Stable`, `Unsubscribe`
  --> src/other_mod/mod.rs:15:3
   |
15 |     Stable,
   |     ^^^^^^
   |
25 | /   Unstable, {
26 | |     period: usize,
27 | |   }
   | |___^
```

- unused struct fields (consolidated by struct):
```
warning: fields are never read: `im_unused`, `me_too`
  --> src/the_mod.rs:77:3
   |
77 |   im_unused: String,
   |   ^^^^^^^^^^^^^^^^^
79 |   me_too: String
   |   ^^^^^^^^^^^^^^
```

- unused functions (grouped by impl block, or grouped by whatever the implementation is "on"):
```
warning: associated functions are never used: `store`, `list`
  --> src/main.rs:40:25
   |
40 |   pub async fn store(&self) {
   |                ^^^^^
60 |   pub fn list(&self) -> Vec<u8> {
   |          ^^^^^
```

- unused local variables (consolidated by scope):
```
warning: unused variables: `local_creation_time`, `count`
   --> src/my_mod/mod.rs:159:12
    |
159 |       let (local_creation_time, file) = {
    |            ^^^^^^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_local_creation_time`
    |
170 |       let count = 0;
    |           ^^^^^ help: if this is intentional, prefix it with an underscore: `_count`
```

- One can imagine this going even further:
  - unconstructed structs (consolidated by module?)
```
warning: structs are never constructed: `Format`, `Packet`
   --> src/serial_bus.rs:29:8
    |
29  | struct Format {}
    |        ^^^^^^
120 | struct Packet {}
    |        ^^^^^^
```
  - unconstructed enums (consolidated by module?)
```
warning: enums are never used: `LinkType`, `Checksum`
  --> src/serial_bus.rs:50:10
   |
50 | pub enum LinkType {
   |          ^^^^^^^^
95 | pub enum Checksum {
   |          ^^^^^^^^
   |
```

## Supporting Arguments

- Consolidation of these messages would reduce the cognitive complexity of the compiler output
   - Conceptually there are not 15 very distinct warnings, there are 4 warnings, each of them nearly identical and often adjacent in the source. 
   - Lots and lots (and lots) of separate messages is overwhelming, consolidation makes the output easier to grok.
   - The effect of a "wall of yellow" output _that is mostly ignorable_ is to lead humans to _mostly ignore it_, accidentally overlooking warnings which are not benign, e.g. `#[must_use]` warnings and the like.
      - In principle people should remedy all warnings before publishing or moving to production, and in doing so they would eventually read every warning (the important ones), so no issue. I wager this does not always happen. Our tools should guide us towards the outcomes we desire, and so the parent argument stands.
   -  Reducing wall-of-yellow output is good for experienced users, but it is especially valuable for beginners. I posit these changes would contribute to accelerating language adoption and ecosystem growth.

- We already do this for unused imports:
   -  in fact the compiler can consolidate many warnings into 1 warning (I've seen "lots of" unused items consolidated, it may even be unbounded, I don't know)
   - (However, import warnings are only consolidated if they are from the same statement. This should also be improved, I should have a warning about 5 unused imports, not 5 warnings about 5 unused imports)

![Unused imports warnings are consolidated](https://user-images.githubusercontent.com/2095902/139169749-615c8b63-91fe-4f94-8d31-73cc3f29c9af.png)

## Additional Thoughts

- Warnings without consolidation provide a line and column number. For consolidated warnings, there is no longer an inarguably correct location to point to. I think that all consolidations described above only occur inside single files, so I propose we use the first infraction that a warning represents. For example, if we have two unused variables in the same scope, the first unused variable is what is pointed to even though both are listed in the warning. 

- The same arguments I have made above can be applied to _some_ aspects of error reporting:
- However in the case of errors I think they should always remain separate
- When compared to warnings, errors are extremely cognitively demanding to parse, understand the root cause of, and repair. They should probably never be consolidated in the output.
- One similar quality of life change w.r.t. error reporting that I will argue for is guaranteeing that errors are always printed last (closest to the terminal prompt, least likely to be cut off), although it is not directly related to this ticket so I can save that for another day.

I have never contributed to `rustc` or related tooling, so I do not have an intuition for how difficult implementation of my proposal will be, so I apologize if it turns out I am asking for the world 😄 .

I understand that my proposal constitutes a substantial change to the human-facing output behavior of `rustc`, and I appreciate your consideration.

Thank you for reading.