Rollup merge of #50327 - varkor:match-unused-struct-field, r=estebank
Display correct unused field suggestion for nested struct patterns Extends https://github.com/rust-lang/rust/pull/47922 by checking more sophisticated patterns (e.g. references, slices, etc.). Before: ``` warning: unused variable: `bar` --> src/main.rs:37:21 | 37 | &Foo::Bar { bar } => true, | ^^^ help: consider using `_bar` instead | = note: #[warn(unused_variables)] on by default ``` After: ``` warning: unused variable: `bar` --> src/main.rs:37:21 | 37 | &Foo::Bar { bar } => true, | ^^^ help: try ignoring the field: `bar: _` | = note: #[warn(unused_variables)] on by default ``` Fixes #50303. r? @estebank
This commit is contained in:
commit
cbbdf998ed
@ -111,6 +111,7 @@ use ty::{self, TyCtxt};
|
||||
use lint;
|
||||
use util::nodemap::{NodeMap, NodeSet};
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::{fmt, usize};
|
||||
use std::io::prelude::*;
|
||||
use std::io;
|
||||
@ -412,18 +413,43 @@ fn visit_local<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, local: &'tcx hir::Local) {
|
||||
}
|
||||
|
||||
fn visit_arm<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, arm: &'tcx hir::Arm) {
|
||||
for pat in &arm.pats {
|
||||
// for struct patterns, take note of which fields used shorthand (`x` rather than `x: x`)
|
||||
for mut pat in &arm.pats {
|
||||
// For struct patterns, take note of which fields used shorthand
|
||||
// (`x` rather than `x: x`).
|
||||
//
|
||||
// FIXME: according to the rust-lang-nursery/rustc-guide book, `NodeId`s are to be phased
|
||||
// out in favor of `HirId`s; however, we need to match the signature of `each_binding`,
|
||||
// which uses `NodeIds`.
|
||||
// FIXME: according to the rust-lang-nursery/rustc-guide book, `NodeId`s are to be
|
||||
// phased out in favor of `HirId`s; however, we need to match the signature of
|
||||
// `each_binding`, which uses `NodeIds`.
|
||||
let mut shorthand_field_ids = NodeSet();
|
||||
if let hir::PatKind::Struct(_, ref fields, _) = pat.node {
|
||||
for field in fields {
|
||||
if field.node.is_shorthand {
|
||||
shorthand_field_ids.insert(field.node.pat.id);
|
||||
let mut pats = VecDeque::new();
|
||||
pats.push_back(pat);
|
||||
while let Some(pat) = pats.pop_front() {
|
||||
use hir::PatKind::*;
|
||||
match pat.node {
|
||||
Binding(_, _, _, ref inner_pat) => {
|
||||
pats.extend(inner_pat.iter());
|
||||
}
|
||||
Struct(_, ref fields, _) => {
|
||||
for field in fields {
|
||||
if field.node.is_shorthand {
|
||||
shorthand_field_ids.insert(field.node.pat.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ref(ref inner_pat, _) |
|
||||
Box(ref inner_pat) => {
|
||||
pats.push_back(inner_pat);
|
||||
}
|
||||
TupleStruct(_, ref inner_pats, _) |
|
||||
Tuple(ref inner_pats, _) => {
|
||||
pats.extend(inner_pats.iter());
|
||||
}
|
||||
Slice(ref pre_pats, ref inner_pat, ref post_pats) => {
|
||||
pats.extend(pre_pats.iter());
|
||||
pats.extend(inner_pat.iter());
|
||||
pats.extend(post_pats.iter());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,8 @@
|
||||
|
||||
// compile-pass
|
||||
|
||||
#![feature(box_syntax)]
|
||||
#![feature(box_patterns)]
|
||||
#![warn(unused)] // UI tests pass `-A unused` (#43896)
|
||||
|
||||
struct SoulHistory {
|
||||
@ -18,6 +20,13 @@ struct SoulHistory {
|
||||
endless_and_singing: bool
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum Large {
|
||||
Suit { case: () }
|
||||
}
|
||||
|
||||
struct Tuple(Large, ());
|
||||
|
||||
fn main() {
|
||||
let i_think_continually = 2;
|
||||
let who_from_the_womb_remembered = SoulHistory {
|
||||
@ -31,4 +40,38 @@ fn main() {
|
||||
endless_and_singing: true } = who_from_the_womb_remembered {
|
||||
hours_are_suns = false;
|
||||
}
|
||||
|
||||
let bag = Large::Suit {
|
||||
case: ()
|
||||
};
|
||||
|
||||
// Plain struct
|
||||
match bag {
|
||||
Large::Suit { case } => {}
|
||||
};
|
||||
|
||||
// Referenced struct
|
||||
match &bag {
|
||||
&Large::Suit { case } => {}
|
||||
};
|
||||
|
||||
// Boxed struct
|
||||
match box bag {
|
||||
box Large::Suit { case } => {}
|
||||
};
|
||||
|
||||
// Tuple with struct
|
||||
match (bag,) {
|
||||
(Large::Suit { case },) => {}
|
||||
};
|
||||
|
||||
// Slice with struct
|
||||
match [bag] {
|
||||
[Large::Suit { case }] => {}
|
||||
};
|
||||
|
||||
// Tuple struct with struct
|
||||
match Tuple(bag, ()) {
|
||||
Tuple(Large::Suit { case }, ()) => {}
|
||||
};
|
||||
}
|
||||
|
@ -1,24 +1,24 @@
|
||||
warning: unused variable: `i_think_continually`
|
||||
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:22:9
|
||||
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:31:9
|
||||
|
|
||||
LL | let i_think_continually = 2;
|
||||
| ^^^^^^^^^^^^^^^^^^^ help: consider using `_i_think_continually` instead
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:13:9
|
||||
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:15:9
|
||||
|
|
||||
LL | #![warn(unused)] // UI tests pass `-A unused` (#43896)
|
||||
| ^^^^^^
|
||||
= note: #[warn(unused_variables)] implied by #[warn(unused)]
|
||||
|
||||
warning: unused variable: `corridors_of_light`
|
||||
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:29:26
|
||||
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:38:26
|
||||
|
|
||||
LL | if let SoulHistory { corridors_of_light,
|
||||
| ^^^^^^^^^^^^^^^^^^ help: try ignoring the field: `corridors_of_light: _`
|
||||
|
||||
warning: variable `hours_are_suns` is assigned to, but never used
|
||||
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:30:26
|
||||
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:39:26
|
||||
|
|
||||
LL | mut hours_are_suns,
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
@ -26,15 +26,51 @@ LL | mut hours_are_suns,
|
||||
= note: consider using `_hours_are_suns` instead
|
||||
|
||||
warning: value assigned to `hours_are_suns` is never read
|
||||
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:32:9
|
||||
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:41:9
|
||||
|
|
||||
LL | hours_are_suns = false;
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:13:9
|
||||
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:15:9
|
||||
|
|
||||
LL | #![warn(unused)] // UI tests pass `-A unused` (#43896)
|
||||
| ^^^^^^
|
||||
= note: #[warn(unused_assignments)] implied by #[warn(unused)]
|
||||
|
||||
warning: unused variable: `case`
|
||||
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:50:23
|
||||
|
|
||||
LL | Large::Suit { case } => {}
|
||||
| ^^^^ help: try ignoring the field: `case: _`
|
||||
|
||||
warning: unused variable: `case`
|
||||
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:55:24
|
||||
|
|
||||
LL | &Large::Suit { case } => {}
|
||||
| ^^^^ help: try ignoring the field: `case: _`
|
||||
|
||||
warning: unused variable: `case`
|
||||
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:60:27
|
||||
|
|
||||
LL | box Large::Suit { case } => {}
|
||||
| ^^^^ help: try ignoring the field: `case: _`
|
||||
|
||||
warning: unused variable: `case`
|
||||
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:65:24
|
||||
|
|
||||
LL | (Large::Suit { case },) => {}
|
||||
| ^^^^ help: try ignoring the field: `case: _`
|
||||
|
||||
warning: unused variable: `case`
|
||||
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:70:24
|
||||
|
|
||||
LL | [Large::Suit { case }] => {}
|
||||
| ^^^^ help: try ignoring the field: `case: _`
|
||||
|
||||
warning: unused variable: `case`
|
||||
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:75:29
|
||||
|
|
||||
LL | Tuple(Large::Suit { case }, ()) => {}
|
||||
| ^^^^ help: try ignoring the field: `case: _`
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user