Skip to content

Commit e4b1a79

Browse files
committed
concerning well-formed suggestions for unused shorthand field patterns
Previously, unused variables would get a note that the warning could be silenced by prefixing the variable with an underscore, but that doesn't work for field shorthand patterns, which the liveness analysis didn't know about. The "to avoid this warning" verbiage seemed unnecessary. Resolves #47390.
1 parent 8f9d915 commit e4b1a79

File tree

4 files changed

+124
-16
lines changed

4 files changed

+124
-16
lines changed

src/librustc/middle/liveness.rs

+49-14
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ use self::VarKind::*;
109109
use hir::def::*;
110110
use ty::{self, TyCtxt};
111111
use lint;
112-
use util::nodemap::NodeMap;
112+
use util::nodemap::{NodeMap, NodeSet};
113113

114114
use std::{fmt, usize};
115115
use std::io::prelude::*;
@@ -244,7 +244,8 @@ struct CaptureInfo {
244244
#[derive(Copy, Clone, Debug)]
245245
struct LocalInfo {
246246
id: NodeId,
247-
name: ast::Name
247+
name: ast::Name,
248+
is_shorthand: bool,
248249
}
249250

250251
#[derive(Copy, Clone, Debug)]
@@ -333,6 +334,13 @@ impl<'a, 'tcx> IrMaps<'a, 'tcx> {
333334
}
334335
}
335336

337+
fn variable_is_shorthand(&self, var: Variable) -> bool {
338+
match self.var_kinds[var.get()] {
339+
Local(LocalInfo { is_shorthand, .. }) => is_shorthand,
340+
Arg(..) | CleanExit => false
341+
}
342+
}
343+
336344
fn set_captures(&mut self, node_id: NodeId, cs: Vec<CaptureInfo>) {
337345
self.capture_info_map.insert(node_id, Rc::new(cs));
338346
}
@@ -384,23 +392,41 @@ fn visit_local<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, local: &'tcx hir::Local) {
384392
let name = path1.node;
385393
ir.add_live_node_for_node(p_id, VarDefNode(sp));
386394
ir.add_variable(Local(LocalInfo {
387-
id: p_id,
388-
name,
395+
id: p_id,
396+
name,
397+
is_shorthand: false,
389398
}));
390399
});
391400
intravisit::walk_local(ir, local);
392401
}
393402

394403
fn visit_arm<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, arm: &'tcx hir::Arm) {
395404
for pat in &arm.pats {
405+
// for struct patterns, take note of which fields used shorthand (`x`
406+
// rather than `x: x`)
407+
//
408+
// FIXME: according to the rust-lang-nursery/rustc-guide book and
409+
// librustc/README.md, `NodeId`s are to be phased out in favor of
410+
// `HirId`s; however, we need to match the signature of `each_binding`,
411+
// which uses `NodeIds`.
412+
let mut shorthand_field_ids = NodeSet();
413+
if let hir::PatKind::Struct(_, ref fields, _) = pat.node {
414+
for field in fields {
415+
if field.node.is_shorthand {
416+
shorthand_field_ids.insert(field.node.pat.id);
417+
}
418+
}
419+
}
420+
396421
pat.each_binding(|bm, p_id, sp, path1| {
397422
debug!("adding local variable {} from match with bm {:?}",
398423
p_id, bm);
399424
let name = path1.node;
400425
ir.add_live_node_for_node(p_id, VarDefNode(sp));
401426
ir.add_variable(Local(LocalInfo {
402427
id: p_id,
403-
name,
428+
name: name,
429+
is_shorthand: shorthand_field_ids.contains(&p_id)
404430
}));
405431
})
406432
}
@@ -1483,17 +1509,26 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
14831509
self.assigned_on_exit(ln, var).is_some()
14841510
};
14851511

1512+
let suggest_underscore_msg = format!("consider using `_{}` instead",
1513+
name);
14861514
if is_assigned {
1487-
self.ir.tcx.lint_node_note(lint::builtin::UNUSED_VARIABLES, id, sp,
1488-
&format!("variable `{}` is assigned to, but never used",
1489-
name),
1490-
&format!("to avoid this warning, consider using `_{}` instead",
1491-
name));
1515+
self.ir.tcx
1516+
.lint_node_note(lint::builtin::UNUSED_VARIABLES, id, sp,
1517+
&format!("variable `{}` is assigned to, but never used",
1518+
name),
1519+
&suggest_underscore_msg);
14921520
} else if name != "self" {
1493-
self.ir.tcx.lint_node_note(lint::builtin::UNUSED_VARIABLES, id, sp,
1494-
&format!("unused variable: `{}`", name),
1495-
&format!("to avoid this warning, consider using `_{}` instead",
1496-
name));
1521+
let msg = format!("unused variable: `{}`", name);
1522+
let mut err = self.ir.tcx
1523+
.struct_span_lint_node(lint::builtin::UNUSED_VARIABLES, id, sp, &msg);
1524+
if self.ir.variable_is_shorthand(var) {
1525+
err.span_suggestion(sp, "try ignoring the field",
1526+
format!("{}: _", name));
1527+
} else {
1528+
err.span_suggestion_short(sp, &suggest_underscore_msg,
1529+
format!("_{}", name));
1530+
}
1531+
err.emit()
14971532
}
14981533
}
14991534
true
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// must-compile-successfully
12+
13+
#![warn(unused)] // UI tests pass `-A unused` (#43896)
14+
15+
struct SoulHistory {
16+
corridors_of_light: usize,
17+
hours_are_suns: bool,
18+
endless_and_singing: bool
19+
}
20+
21+
fn main() {
22+
let i_think_continually = 2;
23+
let who_from_the_womb_remembered = SoulHistory {
24+
corridors_of_light: 5,
25+
hours_are_suns: true,
26+
endless_and_singing: true
27+
};
28+
29+
if let SoulHistory { corridors_of_light,
30+
mut hours_are_suns,
31+
endless_and_singing: true } = who_from_the_womb_remembered {
32+
hours_are_suns = false;
33+
}
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
warning: unused variable: `i_think_continually`
2+
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:22:9
3+
|
4+
22 | let i_think_continually = 2;
5+
| ^^^^^^^^^^^^^^^^^^^ help: consider using `_i_think_continually` instead
6+
|
7+
note: lint level defined here
8+
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:13:9
9+
|
10+
13 | #![warn(unused)] // UI tests pass `-A unused` (#43896)
11+
| ^^^^^^
12+
= note: #[warn(unused_variables)] implied by #[warn(unused)]
13+
14+
warning: unused variable: `corridors_of_light`
15+
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:29:26
16+
|
17+
29 | if let SoulHistory { corridors_of_light,
18+
| ^^^^^^^^^^^^^^^^^^ help: try ignoring the field: `corridors_of_light: _`
19+
20+
warning: variable `hours_are_suns` is assigned to, but never used
21+
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:30:26
22+
|
23+
30 | mut hours_are_suns,
24+
| ^^^^^^^^^^^^^^^^^^
25+
|
26+
= note: consider using `_hours_are_suns` instead
27+
28+
warning: value assigned to `hours_are_suns` is never read
29+
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:32:9
30+
|
31+
32 | hours_are_suns = false;
32+
| ^^^^^^^^^^^^^^
33+
|
34+
note: lint level defined here
35+
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:13:9
36+
|
37+
13 | #![warn(unused)] // UI tests pass `-A unused` (#43896)
38+
| ^^^^^^
39+
= note: #[warn(unused_assignments)] implied by #[warn(unused)]
40+

src/test/ui/span/issue-24690.stderr

+1-2
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,14 @@ warning: unused variable: `theOtherTwo`
22
--> $DIR/issue-24690.rs:23:9
33
|
44
23 | let theOtherTwo = 2; //~ WARN should have a snake case name
5-
| ^^^^^^^^^^^
5+
| ^^^^^^^^^^^ help: consider using `_theOtherTwo` instead
66
|
77
note: lint level defined here
88
--> $DIR/issue-24690.rs:18:9
99
|
1010
18 | #![warn(unused)]
1111
| ^^^^^^
1212
= note: #[warn(unused_variables)] implied by #[warn(unused)]
13-
= note: to avoid this warning, consider using `_theOtherTwo` instead
1413

1514
warning: variable `theTwo` should have a snake case name such as `the_two`
1615
--> $DIR/issue-24690.rs:22:9

0 commit comments

Comments
 (0)