Try to fix warning for unused variables in or patterns, issue #67691

This commit is contained in:
sapir 2020-01-01 01:20:34 +02:00
parent 0c156af20d
commit e22e443208
8 changed files with 139 additions and 56 deletions

View File

@ -1492,28 +1492,33 @@ impl<'tcx> Liveness<'_, 'tcx> {
) { ) {
// In an or-pattern, only consider the variable; any later patterns must have the same // In an or-pattern, only consider the variable; any later patterns must have the same
// bindings, and we also consider the first pattern to be the "authoritative" set of ids. // bindings, and we also consider the first pattern to be the "authoritative" set of ids.
// However, we should take the spans of variables with the same name from the later // However, we should take the ids and spans of variables with the same name from the later
// patterns so the suggestions to prefix with underscores will apply to those too. // patterns so the suggestions to prefix with underscores will apply to those too.
let mut vars: FxIndexMap<String, (LiveNode, Variable, HirId, Vec<Span>)> = <_>::default(); let mut vars: FxIndexMap<String, (LiveNode, Variable, Vec<(HirId, Span)>)> = <_>::default();
pat.each_binding(|_, hir_id, pat_sp, ident| { pat.each_binding(|_, hir_id, pat_sp, ident| {
let ln = entry_ln.unwrap_or_else(|| self.live_node(hir_id, pat_sp)); let ln = entry_ln.unwrap_or_else(|| self.live_node(hir_id, pat_sp));
let var = self.variable(hir_id, ident.span); let var = self.variable(hir_id, ident.span);
let id_and_sp = (hir_id, pat_sp);
vars.entry(self.ir.variable_name(var)) vars.entry(self.ir.variable_name(var))
.and_modify(|(.., spans)| spans.push(ident.span)) .and_modify(|(.., hir_ids_and_spans)| hir_ids_and_spans.push(id_and_sp))
.or_insert_with(|| (ln, var, hir_id, vec![ident.span])); .or_insert_with(|| (ln, var, vec![id_and_sp]));
}); });
for (_, (ln, var, id, spans)) in vars { for (_, (ln, var, hir_ids_and_spans)) in vars {
if self.used_on_entry(ln, var) { if self.used_on_entry(ln, var) {
let id = hir_ids_and_spans[0].0;
let spans = hir_ids_and_spans.into_iter().map(|(_, sp)| sp).collect();
on_used_on_entry(spans, id, ln, var); on_used_on_entry(spans, id, ln, var);
} else { } else {
self.report_unused(spans, id, ln, var); self.report_unused(hir_ids_and_spans, ln, var);
} }
} }
} }
fn report_unused(&self, spans: Vec<Span>, hir_id: HirId, ln: LiveNode, var: Variable) { fn report_unused(&self, hir_ids_and_spans: Vec<(HirId, Span)>, ln: LiveNode, var: Variable) {
let first_hir_id = hir_ids_and_spans[0].0;
if let Some(name) = self.should_warn(var).filter(|name| name != "self") { if let Some(name) = self.should_warn(var).filter(|name| name != "self") {
// annoying: for parameters in funcs like `fn(x: i32) // annoying: for parameters in funcs like `fn(x: i32)
// {ret}`, there is only one node, so asking about // {ret}`, there is only one node, so asking about
@ -1524,8 +1529,8 @@ impl<'tcx> Liveness<'_, 'tcx> {
if is_assigned { if is_assigned {
self.ir.tcx.struct_span_lint_hir( self.ir.tcx.struct_span_lint_hir(
lint::builtin::UNUSED_VARIABLES, lint::builtin::UNUSED_VARIABLES,
hir_id, first_hir_id,
spans, hir_ids_and_spans.into_iter().map(|(_, sp)| sp).collect::<Vec<_>>(),
|lint| { |lint| {
lint.build(&format!("variable `{}` is assigned to, but never used", name)) lint.build(&format!("variable `{}` is assigned to, but never used", name))
.note(&format!("consider using `_{}` instead", name)) .note(&format!("consider using `_{}` instead", name))
@ -1535,31 +1540,45 @@ impl<'tcx> Liveness<'_, 'tcx> {
} else { } else {
self.ir.tcx.struct_span_lint_hir( self.ir.tcx.struct_span_lint_hir(
lint::builtin::UNUSED_VARIABLES, lint::builtin::UNUSED_VARIABLES,
hir_id, first_hir_id,
spans.clone(), hir_ids_and_spans.iter().map(|(_, sp)| *sp).collect::<Vec<_>>(),
|lint| { |lint| {
let mut err = lint.build(&format!("unused variable: `{}`", name)); let mut err = lint.build(&format!("unused variable: `{}`", name));
if self.ir.variable_is_shorthand(var) {
if let Node::Binding(pat) = self.ir.tcx.hir().get(hir_id) {
// Handle `ref` and `ref mut`.
let spans = spans
.iter()
.map(|_span| (pat.span, format!("{}: _", name)))
.collect();
err.multipart_suggestion( let (shorthands, non_shorthands): (Vec<_>, Vec<_>) =
"try ignoring the field", hir_ids_and_spans.into_iter().partition(|(hir_id, span)| {
spans, let var = self.variable(*hir_id, *span);
Applicability::MachineApplicable, self.ir.variable_is_shorthand(var)
); });
}
let mut shorthands = shorthands
.into_iter()
.map(|(_, span)| (span, format!("{}: _", name)))
.collect::<Vec<_>>();
let non_shorthands = non_shorthands
.into_iter()
.map(|(_, span)| (span, format!("_{}", name)))
.collect::<Vec<_>>();
// If we have both shorthand and non-shorthand, prefer the "try ignoring
// the field" message.
if !shorthands.is_empty() {
shorthands.extend(non_shorthands);
err.multipart_suggestion(
"try ignoring the field",
shorthands,
Applicability::MachineApplicable,
);
} else { } else {
err.multipart_suggestion( err.multipart_suggestion(
"if this is intentional, prefix it with an underscore", "if this is intentional, prefix it with an underscore",
spans.iter().map(|span| (*span, format!("_{}", name))).collect(), non_shorthands,
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
} }
err.emit() err.emit()
}, },
); );

View File

@ -12,16 +12,16 @@ LL | #![warn(unused)] // UI tests pass `-A unused` (#43896)
= note: `#[warn(unused_variables)]` implied by `#[warn(unused)]` = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]`
warning: unused variable: `mut_unused_var` warning: unused variable: `mut_unused_var`
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:33:13 --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:33:9
| |
LL | let mut mut_unused_var = 1; LL | let mut mut_unused_var = 1;
| ^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_mut_unused_var` | ^^^^^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_mut_unused_var`
warning: unused variable: `var` warning: unused variable: `var`
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:37:14 --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:37:10
| |
LL | let (mut var, unused_var) = (1, 2); LL | let (mut var, unused_var) = (1, 2);
| ^^^ help: if this is intentional, prefix it with an underscore: `_var` | ^^^^^^^ help: if this is intentional, prefix it with an underscore: `_var`
warning: unused variable: `unused_var` warning: unused variable: `unused_var`
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:37:19 --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:37:19
@ -36,10 +36,10 @@ LL | if let SoulHistory { corridors_of_light,
| ^^^^^^^^^^^^^^^^^^ help: try ignoring the field: `corridors_of_light: _` | ^^^^^^^^^^^^^^^^^^ help: try ignoring the field: `corridors_of_light: _`
warning: variable `hours_are_suns` is assigned to, but never used warning: variable `hours_are_suns` is assigned to, but never used
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:46:30 --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:46:26
| |
LL | mut hours_are_suns, LL | mut hours_are_suns,
| ^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^
| |
= note: consider using `_hours_are_suns` instead = note: consider using `_hours_are_suns` instead

View File

@ -1,10 +1,8 @@
error: unused variable: `field` error: unused variable: `field`
--> $DIR/issue-54180-unused-ref-field.rs:20:26 --> $DIR/issue-54180-unused-ref-field.rs:20:22
| |
LL | E::Variant { ref field } => (), LL | E::Variant { ref field } => (),
| ----^^^^^ | ^^^^^^^^^ help: try ignoring the field: `field: _`
| |
| help: try ignoring the field: `field: _`
| |
note: the lint level is defined here note: the lint level is defined here
--> $DIR/issue-54180-unused-ref-field.rs:3:9 --> $DIR/issue-54180-unused-ref-field.rs:3:9
@ -20,20 +18,16 @@ LL | let _: i32 = points.iter().map(|Point { x, y }| y).sum();
| ^ help: try ignoring the field: `x: _` | ^ help: try ignoring the field: `x: _`
error: unused variable: `f1` error: unused variable: `f1`
--> $DIR/issue-54180-unused-ref-field.rs:26:17 --> $DIR/issue-54180-unused-ref-field.rs:26:13
| |
LL | let S { ref f1 } = s; LL | let S { ref f1 } = s;
| ----^^ | ^^^^^^ help: try ignoring the field: `f1: _`
| |
| help: try ignoring the field: `f1: _`
error: unused variable: `x` error: unused variable: `x`
--> $DIR/issue-54180-unused-ref-field.rs:32:28 --> $DIR/issue-54180-unused-ref-field.rs:32:20
| |
LL | Point { y, ref mut x } => y, LL | Point { y, ref mut x } => y,
| --------^ | ^^^^^^^^^ help: try ignoring the field: `x: _`
| |
| help: try ignoring the field: `x: _`
error: aborting due to 4 previous errors error: aborting due to 4 previous errors

View File

@ -8,6 +8,11 @@ pub enum MyEnum {
B { i: i32, j: i32 }, B { i: i32, j: i32 },
} }
pub enum MixedEnum {
A { i: i32 },
B(i32),
}
pub fn no_ref(x: MyEnum) { pub fn no_ref(x: MyEnum) {
use MyEnum::*; use MyEnum::*;
@ -52,10 +57,29 @@ pub fn inner_with_ref(x: Option<MyEnum>) {
} }
} }
pub fn mixed_no_ref(x: MixedEnum) {
match x {
MixedEnum::A { i: _ } | MixedEnum::B(_i) => {
println!("match");
}
}
}
pub fn mixed_with_ref(x: MixedEnum) {
match x {
MixedEnum::A { i: _ } | MixedEnum::B(_i) => {
println!("match");
}
}
}
pub fn main() { pub fn main() {
no_ref(MyEnum::A { i: 1, j: 2 }); no_ref(MyEnum::A { i: 1, j: 2 });
with_ref(MyEnum::A { i: 1, j: 2 }); with_ref(MyEnum::A { i: 1, j: 2 });
inner_no_ref(Some(MyEnum::A { i: 1, j: 2 })); inner_no_ref(Some(MyEnum::A { i: 1, j: 2 }));
inner_with_ref(Some(MyEnum::A { i: 1, j: 2 })); inner_with_ref(Some(MyEnum::A { i: 1, j: 2 }));
mixed_no_ref(MixedEnum::B(5));
mixed_with_ref(MixedEnum::B(5));
} }

View File

@ -8,6 +8,11 @@ pub enum MyEnum {
B { i: i32, j: i32 }, B { i: i32, j: i32 },
} }
pub enum MixedEnum {
A { i: i32 },
B(i32),
}
pub fn no_ref(x: MyEnum) { pub fn no_ref(x: MyEnum) {
use MyEnum::*; use MyEnum::*;
@ -52,10 +57,29 @@ pub fn inner_with_ref(x: Option<MyEnum>) {
} }
} }
pub fn mixed_no_ref(x: MixedEnum) {
match x {
MixedEnum::A { i } | MixedEnum::B(i) => { //~ ERROR unused variable
println!("match");
}
}
}
pub fn mixed_with_ref(x: MixedEnum) {
match x {
MixedEnum::A { ref i } | MixedEnum::B(ref i) => { //~ ERROR unused variable
println!("match");
}
}
}
pub fn main() { pub fn main() {
no_ref(MyEnum::A { i: 1, j: 2 }); no_ref(MyEnum::A { i: 1, j: 2 });
with_ref(MyEnum::A { i: 1, j: 2 }); with_ref(MyEnum::A { i: 1, j: 2 });
inner_no_ref(Some(MyEnum::A { i: 1, j: 2 })); inner_no_ref(Some(MyEnum::A { i: 1, j: 2 }));
inner_with_ref(Some(MyEnum::A { i: 1, j: 2 })); inner_with_ref(Some(MyEnum::A { i: 1, j: 2 }));
mixed_no_ref(MixedEnum::B(5));
mixed_with_ref(MixedEnum::B(5));
} }

View File

@ -1,5 +1,5 @@
error: unused variable: `j` error: unused variable: `j`
--> $DIR/issue-67691-unused-field-in-or-pattern.rs:15:16 --> $DIR/issue-67691-unused-field-in-or-pattern.rs:20:16
| |
LL | A { i, j } | B { i, j } => { LL | A { i, j } | B { i, j } => {
| ^ ^ | ^ ^
@ -16,7 +16,7 @@ LL | A { i, j: _ } | B { i, j: _ } => {
| ^^^^ ^^^^ | ^^^^ ^^^^
error: unused variable: `j` error: unused variable: `j`
--> $DIR/issue-67691-unused-field-in-or-pattern.rs:25:16 --> $DIR/issue-67691-unused-field-in-or-pattern.rs:30:16
| |
LL | A { i, ref j } | B { i, ref j } => { LL | A { i, ref j } | B { i, ref j } => {
| ^^^^^ ^^^^^ | ^^^^^ ^^^^^
@ -27,7 +27,7 @@ LL | A { i, j: _ } | B { i, j: _ } => {
| ^^^^ ^^^^ | ^^^^ ^^^^
error: unused variable: `j` error: unused variable: `j`
--> $DIR/issue-67691-unused-field-in-or-pattern.rs:35:21 --> $DIR/issue-67691-unused-field-in-or-pattern.rs:40:21
| |
LL | Some(A { i, j } | B { i, j }) => { LL | Some(A { i, j } | B { i, j }) => {
| ^ ^ | ^ ^
@ -38,7 +38,7 @@ LL | Some(A { i, j: _ } | B { i, j: _ }) => {
| ^^^^ ^^^^ | ^^^^ ^^^^
error: unused variable: `j` error: unused variable: `j`
--> $DIR/issue-67691-unused-field-in-or-pattern.rs:47:21 --> $DIR/issue-67691-unused-field-in-or-pattern.rs:52:21
| |
LL | Some(A { i, ref j } | B { i, ref j }) => { LL | Some(A { i, ref j } | B { i, ref j }) => {
| ^^^^^ ^^^^^ | ^^^^^ ^^^^^
@ -48,5 +48,27 @@ help: try ignoring the field
LL | Some(A { i, j: _ } | B { i, j: _ }) => { LL | Some(A { i, j: _ } | B { i, j: _ }) => {
| ^^^^ ^^^^ | ^^^^ ^^^^
error: aborting due to 5 previous errors error: unused variable: `i`
--> $DIR/issue-67691-unused-field-in-or-pattern.rs:62:24
|
LL | MixedEnum::A { i } | MixedEnum::B(i) => {
| ^ ^
|
help: try ignoring the field
|
LL | MixedEnum::A { i: _ } | MixedEnum::B(_i) => {
| ^^^^ ^^
error: unused variable: `i`
--> $DIR/issue-67691-unused-field-in-or-pattern.rs:70:24
|
LL | MixedEnum::A { ref i } | MixedEnum::B(ref i) => {
| ^^^^^ ^^^^^
|
help: try ignoring the field
|
LL | MixedEnum::A { i: _ } | MixedEnum::B(_i) => {
| ^^^^ ^^
error: aborting due to 6 previous errors

View File

@ -1,8 +1,8 @@
error: value assigned to `x` is never read error: value assigned to `x` is never read
--> $DIR/liveness-dead.rs:9:13 --> $DIR/liveness-dead.rs:9:9
| |
LL | let mut x: isize = 3; LL | let mut x: isize = 3;
| ^ | ^^^^^
| |
note: the lint level is defined here note: the lint level is defined here
--> $DIR/liveness-dead.rs:2:9 --> $DIR/liveness-dead.rs:2:9
@ -20,10 +20,10 @@ LL | x = 4;
= help: maybe it is overwritten before being read? = help: maybe it is overwritten before being read?
error: value passed to `x` is never read error: value passed to `x` is never read
--> $DIR/liveness-dead.rs:20:11 --> $DIR/liveness-dead.rs:20:7
| |
LL | fn f4(mut x: i32) { LL | fn f4(mut x: i32) {
| ^ | ^^^^^
| |
= help: maybe it is overwritten before being read? = help: maybe it is overwritten before being read?

View File

@ -44,10 +44,10 @@ LL | let x = 3;
| ^ help: if this is intentional, prefix it with an underscore: `_x` | ^ help: if this is intentional, prefix it with an underscore: `_x`
error: variable `x` is assigned to, but never used error: variable `x` is assigned to, but never used
--> $DIR/liveness-unused.rs:30:13 --> $DIR/liveness-unused.rs:30:9
| |
LL | let mut x = 3; LL | let mut x = 3;
| ^ | ^^^^^
| |
= note: consider using `_x` instead = note: consider using `_x` instead
@ -65,10 +65,10 @@ LL | #![deny(unused_assignments)]
= help: maybe it is overwritten before being read? = help: maybe it is overwritten before being read?
error: variable `z` is assigned to, but never used error: variable `z` is assigned to, but never used
--> $DIR/liveness-unused.rs:37:13 --> $DIR/liveness-unused.rs:37:9
| |
LL | let mut z = 3; LL | let mut z = 3;
| ^ | ^^^^^
| |
= note: consider using `_z` instead = note: consider using `_z` instead