Skip to content

Commit

Permalink
Rollup merge of #88871 - FabianWolff:issue-88403, r=jackh726
Browse files Browse the repository at this point in the history
Fix suggestion for nested struct patterns

Fixes #88403, and also a similar problem where the unused binding is in a function parameter pattern.
  • Loading branch information
Manishearth authored Oct 5, 2021
2 parents eb86098 + 2bff77d commit 60b9c5d
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 8 deletions.
23 changes: 15 additions & 8 deletions compiler/rustc_passes/src/liveness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,21 +265,24 @@ impl IrMaps<'tcx> {
self.capture_info_map.insert(hir_id, Rc::new(cs));
}

fn add_from_pat(&mut self, pat: &hir::Pat<'tcx>) {
fn collect_shorthand_field_ids(&self, pat: &hir::Pat<'tcx>) -> HirIdSet {
// For struct patterns, take note of which fields used shorthand
// (`x` rather than `x: x`).
let mut shorthand_field_ids = HirIdSet::default();
let mut pats = VecDeque::new();
pats.push_back(pat);

while let Some(pat) = pats.pop_front() {
use rustc_hir::PatKind::*;
match &pat.kind {
Binding(.., inner_pat) => {
pats.extend(inner_pat.iter());
}
Struct(_, fields, _) => {
let ids = fields.iter().filter(|f| f.is_shorthand).map(|f| f.pat.hir_id);
shorthand_field_ids.extend(ids);
let (short, not_short): (Vec<&_>, Vec<&_>) =
fields.iter().partition(|f| f.is_shorthand);
shorthand_field_ids.extend(short.iter().map(|f| f.pat.hir_id));
pats.extend(not_short.iter().map(|f| f.pat));
}
Ref(inner_pat, _) | Box(inner_pat) => {
pats.push_back(inner_pat);
Expand All @@ -296,6 +299,12 @@ impl IrMaps<'tcx> {
}
}

return shorthand_field_ids;
}

fn add_from_pat(&mut self, pat: &hir::Pat<'tcx>) {
let shorthand_field_ids = self.collect_shorthand_field_ids(pat);

pat.each_binding(|_, hir_id, _, ident| {
self.add_live_node_for_node(hir_id, VarDefNode(ident.span, hir_id));
self.add_variable(Local(LocalInfo {
Expand Down Expand Up @@ -373,15 +382,13 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
}

fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
let shorthand_field_ids = self.collect_shorthand_field_ids(param.pat);
param.pat.each_binding(|_bm, hir_id, _x, ident| {
let var = match param.pat.kind {
rustc_hir::PatKind::Struct(_, fields, _) => Local(LocalInfo {
rustc_hir::PatKind::Struct(..) => Local(LocalInfo {
id: hir_id,
name: ident.name,
is_shorthand: fields
.iter()
.find(|f| f.ident == ident)
.map_or(false, |f| f.is_shorthand),
is_shorthand: shorthand_field_ids.contains(&hir_id),
}),
_ => Param(hir_id, ident.name),
};
Expand Down
20 changes: 20 additions & 0 deletions src/test/ui/suggestions/ignore-nested-field-binding.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Regression test for #88403, where prefixing with an underscore was
// erroneously suggested for a nested shorthand struct field binding.

// run-rustfix
#![allow(unused)]
#![forbid(unused_variables)]

struct Inner { i: i32 }
struct Outer { o: Inner }

fn foo(Outer { o: Inner { i: _ } }: Outer) {}
//~^ ERROR: unused variable: `i`
//~| HELP: try ignoring the field

fn main() {
let s = Outer { o: Inner { i: 42 } };
let Outer { o: Inner { i: _ } } = s;
//~^ ERROR: unused variable: `i`
//~| HELP: try ignoring the field
}
20 changes: 20 additions & 0 deletions src/test/ui/suggestions/ignore-nested-field-binding.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Regression test for #88403, where prefixing with an underscore was
// erroneously suggested for a nested shorthand struct field binding.

// run-rustfix
#![allow(unused)]
#![forbid(unused_variables)]

struct Inner { i: i32 }
struct Outer { o: Inner }

fn foo(Outer { o: Inner { i } }: Outer) {}
//~^ ERROR: unused variable: `i`
//~| HELP: try ignoring the field

fn main() {
let s = Outer { o: Inner { i: 42 } };
let Outer { o: Inner { i } } = s;
//~^ ERROR: unused variable: `i`
//~| HELP: try ignoring the field
}
20 changes: 20 additions & 0 deletions src/test/ui/suggestions/ignore-nested-field-binding.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
error: unused variable: `i`
--> $DIR/ignore-nested-field-binding.rs:11:27
|
LL | fn foo(Outer { o: Inner { i } }: Outer) {}
| ^ help: try ignoring the field: `i: _`
|
note: the lint level is defined here
--> $DIR/ignore-nested-field-binding.rs:6:11
|
LL | #![forbid(unused_variables)]
| ^^^^^^^^^^^^^^^^

error: unused variable: `i`
--> $DIR/ignore-nested-field-binding.rs:17:28
|
LL | let Outer { o: Inner { i } } = s;
| ^ help: try ignoring the field: `i: _`

error: aborting due to 2 previous errors

0 comments on commit 60b9c5d

Please sign in to comment.