operate on HirId
in hir::Pat::each_binding
, and consequences of that
Changing the `each_binding` utility method to take the `HirId` of a binding pattern rather than its `NodeId` seems like a modest first step in support of the `HirId`ification initiative #50928. (The inspiration for choosing this in particular came from the present author's previous work on diagnostics issued during liveness analysis, which is the most greatly affected module in this change.)
This commit is contained in:
parent
2b1d69d6b5
commit
1329605a3d
@ -10,7 +10,7 @@
|
||||
|
||||
use hir::def::Def;
|
||||
use hir::def_id::DefId;
|
||||
use hir::{self, PatKind};
|
||||
use hir::{self, HirId, PatKind};
|
||||
use syntax::ast;
|
||||
use syntax::codemap::Spanned;
|
||||
use syntax_pos::Span;
|
||||
@ -91,11 +91,11 @@ impl hir::Pat {
|
||||
/// Call `f` on every "binding" in a pattern, e.g., on `a` in
|
||||
/// `match foo() { Some(a) => (), None => () }`
|
||||
pub fn each_binding<F>(&self, mut f: F)
|
||||
where F: FnMut(hir::BindingAnnotation, ast::NodeId, Span, &Spanned<ast::Name>),
|
||||
where F: FnMut(hir::BindingAnnotation, HirId, Span, &Spanned<ast::Name>),
|
||||
{
|
||||
self.walk(|p| {
|
||||
if let PatKind::Binding(binding_mode, _, ref pth, _) = p.node {
|
||||
f(binding_mode, p.id, p.span, pth);
|
||||
f(binding_mode, p.hir_id, p.span, pth);
|
||||
}
|
||||
true
|
||||
});
|
||||
|
@ -608,9 +608,10 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
||||
fn walk_local(&mut self, local: &hir::Local) {
|
||||
match local.init {
|
||||
None => {
|
||||
let delegate = &mut self.delegate;
|
||||
local.pat.each_binding(|_, id, span, _| {
|
||||
delegate.decl_without_init(id, span);
|
||||
local.pat.each_binding(|_, hir_id, span, _| {
|
||||
// FIXME: converting HirId → NodeId is said to be relatively expensive
|
||||
let node_id = self.mc.tcx.hir.definitions().find_node_for_hir_id(hir_id);
|
||||
self.delegate.decl_without_init(node_id, span);
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -110,7 +110,7 @@ use hir::def::*;
|
||||
use ty::{self, TyCtxt};
|
||||
use lint;
|
||||
use errors::Applicability;
|
||||
use util::nodemap::{NodeMap, NodeSet};
|
||||
use util::nodemap::{NodeMap, HirIdMap, HirIdSet};
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::{fmt, u32};
|
||||
@ -122,7 +122,7 @@ use syntax::ptr::P;
|
||||
use syntax::symbol::keywords;
|
||||
use syntax_pos::Span;
|
||||
|
||||
use hir::Expr;
|
||||
use hir::{Expr, HirId};
|
||||
use hir;
|
||||
use hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
|
||||
|
||||
@ -236,19 +236,19 @@ fn invalid_node() -> LiveNode { LiveNode(u32::MAX) }
|
||||
|
||||
struct CaptureInfo {
|
||||
ln: LiveNode,
|
||||
var_nid: NodeId
|
||||
var_hid: HirId
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
struct LocalInfo {
|
||||
id: NodeId,
|
||||
id: HirId,
|
||||
name: ast::Name,
|
||||
is_shorthand: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
enum VarKind {
|
||||
Arg(NodeId, ast::Name),
|
||||
Arg(HirId, ast::Name),
|
||||
Local(LocalInfo),
|
||||
CleanExit
|
||||
}
|
||||
@ -258,8 +258,8 @@ struct IrMaps<'a, 'tcx: 'a> {
|
||||
|
||||
num_live_nodes: usize,
|
||||
num_vars: usize,
|
||||
live_node_map: NodeMap<LiveNode>,
|
||||
variable_map: NodeMap<Variable>,
|
||||
live_node_map: HirIdMap<LiveNode>,
|
||||
variable_map: HirIdMap<Variable>,
|
||||
capture_info_map: NodeMap<Rc<Vec<CaptureInfo>>>,
|
||||
var_kinds: Vec<VarKind>,
|
||||
lnks: Vec<LiveNodeKind>,
|
||||
@ -271,8 +271,8 @@ impl<'a, 'tcx> IrMaps<'a, 'tcx> {
|
||||
tcx,
|
||||
num_live_nodes: 0,
|
||||
num_vars: 0,
|
||||
live_node_map: NodeMap(),
|
||||
variable_map: NodeMap(),
|
||||
live_node_map: HirIdMap(),
|
||||
variable_map: HirIdMap(),
|
||||
capture_info_map: NodeMap(),
|
||||
var_kinds: Vec::new(),
|
||||
lnks: Vec::new(),
|
||||
@ -290,11 +290,11 @@ impl<'a, 'tcx> IrMaps<'a, 'tcx> {
|
||||
ln
|
||||
}
|
||||
|
||||
fn add_live_node_for_node(&mut self, node_id: NodeId, lnk: LiveNodeKind) {
|
||||
fn add_live_node_for_node(&mut self, hir_id: HirId, lnk: LiveNodeKind) {
|
||||
let ln = self.add_live_node(lnk);
|
||||
self.live_node_map.insert(node_id, ln);
|
||||
self.live_node_map.insert(hir_id, ln);
|
||||
|
||||
debug!("{:?} is node {}", ln, node_id);
|
||||
debug!("{:?} is node {:?}", ln, hir_id);
|
||||
}
|
||||
|
||||
fn add_variable(&mut self, vk: VarKind) -> Variable {
|
||||
@ -314,11 +314,11 @@ impl<'a, 'tcx> IrMaps<'a, 'tcx> {
|
||||
v
|
||||
}
|
||||
|
||||
fn variable(&self, node_id: NodeId, span: Span) -> Variable {
|
||||
match self.variable_map.get(&node_id) {
|
||||
fn variable(&self, hir_id: HirId, span: Span) -> Variable {
|
||||
match self.variable_map.get(&hir_id) {
|
||||
Some(&var) => var,
|
||||
None => {
|
||||
span_bug!(span, "no variable registered for id {}", node_id);
|
||||
span_bug!(span, "no variable registered for id {:?}", hir_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -374,10 +374,10 @@ fn visit_fn<'a, 'tcx: 'a>(ir: &mut IrMaps<'a, 'tcx>,
|
||||
let body = ir.tcx.hir.body(body_id);
|
||||
|
||||
for arg in &body.arguments {
|
||||
arg.pat.each_binding(|_bm, arg_id, _x, path1| {
|
||||
debug!("adding argument {}", arg_id);
|
||||
arg.pat.each_binding(|_bm, hir_id, _x, path1| {
|
||||
debug!("adding argument {:?}", hir_id);
|
||||
let name = path1.node;
|
||||
fn_maps.add_variable(Arg(arg_id, name));
|
||||
fn_maps.add_variable(Arg(hir_id, name));
|
||||
})
|
||||
};
|
||||
|
||||
@ -397,11 +397,7 @@ fn visit_fn<'a, 'tcx: 'a>(ir: &mut IrMaps<'a, 'tcx>,
|
||||
fn add_from_pat<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, pat: &P<hir::Pat>) {
|
||||
// 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`.
|
||||
let mut shorthand_field_ids = NodeSet();
|
||||
let mut shorthand_field_ids = HirIdSet();
|
||||
let mut pats = VecDeque::new();
|
||||
pats.push_back(pat);
|
||||
while let Some(pat) = pats.pop_front() {
|
||||
@ -413,7 +409,7 @@ fn add_from_pat<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, pat: &P<hir::Pat>) {
|
||||
Struct(_, ref fields, _) => {
|
||||
for field in fields {
|
||||
if field.node.is_shorthand {
|
||||
shorthand_field_ids.insert(field.node.pat.id);
|
||||
shorthand_field_ids.insert(field.node.pat.hir_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -434,13 +430,13 @@ fn add_from_pat<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, pat: &P<hir::Pat>) {
|
||||
}
|
||||
}
|
||||
|
||||
pat.each_binding(|_bm, p_id, _sp, path1| {
|
||||
pat.each_binding(|_bm, hir_id, _sp, path1| {
|
||||
let name = path1.node;
|
||||
ir.add_live_node_for_node(p_id, VarDefNode(path1.span));
|
||||
ir.add_live_node_for_node(hir_id, VarDefNode(path1.span));
|
||||
ir.add_variable(Local(LocalInfo {
|
||||
id: p_id,
|
||||
id: hir_id,
|
||||
name,
|
||||
is_shorthand: shorthand_field_ids.contains(&p_id)
|
||||
is_shorthand: shorthand_field_ids.contains(&hir_id)
|
||||
}));
|
||||
});
|
||||
}
|
||||
@ -463,14 +459,14 @@ fn visit_expr<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, expr: &'tcx Expr) {
|
||||
hir::ExprPath(hir::QPath::Resolved(_, ref path)) => {
|
||||
debug!("expr {}: path that leads to {:?}", expr.id, path.def);
|
||||
if let Def::Local(..) = path.def {
|
||||
ir.add_live_node_for_node(expr.id, ExprNode(expr.span));
|
||||
ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span));
|
||||
}
|
||||
intravisit::walk_expr(ir, expr);
|
||||
}
|
||||
hir::ExprClosure(..) => {
|
||||
// Interesting control flow (for loops can contain labeled
|
||||
// breaks or continues)
|
||||
ir.add_live_node_for_node(expr.id, ExprNode(expr.span));
|
||||
ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span));
|
||||
|
||||
// Make a live_node for each captured variable, with the span
|
||||
// being the location that the variable is used. This results
|
||||
@ -481,8 +477,8 @@ fn visit_expr<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, expr: &'tcx Expr) {
|
||||
for fv in freevars {
|
||||
if let Def::Local(rv) = fv.def {
|
||||
let fv_ln = ir.add_live_node(FreeVarNode(fv.span));
|
||||
call_caps.push(CaptureInfo {ln: fv_ln,
|
||||
var_nid: rv});
|
||||
let var_hid = ir.tcx.hir.node_to_hir_id(rv);
|
||||
call_caps.push(CaptureInfo { ln: fv_ln, var_hid });
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -493,11 +489,11 @@ fn visit_expr<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, expr: &'tcx Expr) {
|
||||
|
||||
// live nodes required for interesting control flow:
|
||||
hir::ExprIf(..) | hir::ExprMatch(..) | hir::ExprWhile(..) | hir::ExprLoop(..) => {
|
||||
ir.add_live_node_for_node(expr.id, ExprNode(expr.span));
|
||||
ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span));
|
||||
intravisit::walk_expr(ir, expr);
|
||||
}
|
||||
hir::ExprBinary(op, ..) if op.node.is_lazy() => {
|
||||
ir.add_live_node_for_node(expr.id, ExprNode(expr.span));
|
||||
ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span));
|
||||
intravisit::walk_expr(ir, expr);
|
||||
}
|
||||
|
||||
@ -590,8 +586,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn live_node(&self, node_id: NodeId, span: Span) -> LiveNode {
|
||||
match self.ir.live_node_map.get(&node_id) {
|
||||
fn live_node(&self, hir_id: HirId, span: Span) -> LiveNode {
|
||||
match self.ir.live_node_map.get(&hir_id) {
|
||||
Some(&ln) => ln,
|
||||
None => {
|
||||
// This must be a mismatch between the ir_map construction
|
||||
@ -600,28 +596,28 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||
// creating liveness nodes for.
|
||||
span_bug!(
|
||||
span,
|
||||
"no live node registered for node {}",
|
||||
node_id);
|
||||
"no live node registered for node {:?}",
|
||||
hir_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn variable(&self, node_id: NodeId, span: Span) -> Variable {
|
||||
self.ir.variable(node_id, span)
|
||||
fn variable(&self, hir_id: HirId, span: Span) -> Variable {
|
||||
self.ir.variable(hir_id, span)
|
||||
}
|
||||
|
||||
fn pat_bindings<F>(&mut self, pat: &hir::Pat, mut f: F) where
|
||||
F: FnMut(&mut Liveness<'a, 'tcx>, LiveNode, Variable, Span, NodeId),
|
||||
F: FnMut(&mut Liveness<'a, 'tcx>, LiveNode, Variable, Span, HirId),
|
||||
{
|
||||
pat.each_binding(|_bm, p_id, sp, n| {
|
||||
let ln = self.live_node(p_id, sp);
|
||||
let var = self.variable(p_id, n.span);
|
||||
f(self, ln, var, n.span, p_id);
|
||||
pat.each_binding(|_bm, hir_id, sp, n| {
|
||||
let ln = self.live_node(hir_id, sp);
|
||||
let var = self.variable(hir_id, n.span);
|
||||
f(self, ln, var, n.span, hir_id);
|
||||
})
|
||||
}
|
||||
|
||||
fn arm_pats_bindings<F>(&mut self, pat: Option<&hir::Pat>, f: F) where
|
||||
F: FnMut(&mut Liveness<'a, 'tcx>, LiveNode, Variable, Span, NodeId),
|
||||
F: FnMut(&mut Liveness<'a, 'tcx>, LiveNode, Variable, Span, HirId),
|
||||
{
|
||||
if let Some(pat) = pat {
|
||||
self.pat_bindings(pat, f);
|
||||
@ -927,7 +923,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||
match expr.node {
|
||||
// Interesting cases with control flow or which gen/kill
|
||||
hir::ExprPath(hir::QPath::Resolved(_, ref path)) => {
|
||||
self.access_path(expr.id, path, succ, ACC_READ | ACC_USE)
|
||||
self.access_path(expr.hir_id, path, succ, ACC_READ | ACC_USE)
|
||||
}
|
||||
|
||||
hir::ExprField(ref e, _) => {
|
||||
@ -937,11 +933,9 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||
hir::ExprClosure(.., blk_id, _, _) => {
|
||||
debug!("{} is an ExprClosure", self.ir.tcx.hir.node_to_pretty_string(expr.id));
|
||||
|
||||
/*
|
||||
The next-node for a break is the successor of the entire
|
||||
loop. The next-node for a continue is the top of this loop.
|
||||
*/
|
||||
let node = self.live_node(expr.id, expr.span);
|
||||
// The next-node for a break is the successor of the entire
|
||||
// loop. The next-node for a continue is the top of this loop.
|
||||
let node = self.live_node(expr.hir_id, expr.span);
|
||||
|
||||
let break_ln = succ;
|
||||
let cont_ln = node;
|
||||
@ -958,7 +952,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||
};
|
||||
caps.iter().rev().fold(succ, |succ, cap| {
|
||||
self.init_from_succ(cap.ln, succ);
|
||||
let var = self.variable(cap.var_nid, expr.span);
|
||||
let var = self.variable(cap.var_hid, expr.span);
|
||||
self.acc(cap.ln, var, ACC_READ | ACC_USE);
|
||||
cap.ln
|
||||
})
|
||||
@ -980,7 +974,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||
//
|
||||
let else_ln = self.propagate_through_opt_expr(els.as_ref().map(|e| &**e), succ);
|
||||
let then_ln = self.propagate_through_expr(&then, succ);
|
||||
let ln = self.live_node(expr.id, expr.span);
|
||||
let ln = self.live_node(expr.hir_id, expr.span);
|
||||
self.init_from_succ(ln, else_ln);
|
||||
self.merge_from_succ(ln, then_ln, false);
|
||||
self.propagate_through_expr(&cond, ln)
|
||||
@ -1011,7 +1005,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||
// ( succ )
|
||||
//
|
||||
//
|
||||
let ln = self.live_node(expr.id, expr.span);
|
||||
let ln = self.live_node(expr.hir_id, expr.span);
|
||||
self.init_empty(ln, succ);
|
||||
let mut first_merge = true;
|
||||
for arm in arms {
|
||||
@ -1132,7 +1126,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||
hir::ExprBinary(op, ref l, ref r) if op.node.is_lazy() => {
|
||||
let r_succ = self.propagate_through_expr(&r, succ);
|
||||
|
||||
let ln = self.live_node(expr.id, expr.span);
|
||||
let ln = self.live_node(expr.hir_id, expr.span);
|
||||
self.init_from_succ(ln, succ);
|
||||
self.merge_from_succ(ln, r_succ, false);
|
||||
|
||||
@ -1249,7 +1243,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||
-> LiveNode {
|
||||
match expr.node {
|
||||
hir::ExprPath(hir::QPath::Resolved(_, ref path)) => {
|
||||
self.access_path(expr.id, path, succ, acc)
|
||||
self.access_path(expr.hir_id, path, succ, acc)
|
||||
}
|
||||
|
||||
// We do not track other places, so just propagate through
|
||||
@ -1260,22 +1254,23 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn access_var(&mut self, id: NodeId, nid: NodeId, succ: LiveNode, acc: u32, span: Span)
|
||||
fn access_var(&mut self, hir_id: HirId, nid: NodeId, succ: LiveNode, acc: u32, span: Span)
|
||||
-> LiveNode {
|
||||
let ln = self.live_node(id, span);
|
||||
let ln = self.live_node(hir_id, span);
|
||||
if acc != 0 {
|
||||
self.init_from_succ(ln, succ);
|
||||
let var = self.variable(nid, span);
|
||||
let var_hid = self.ir.tcx.hir.node_to_hir_id(nid);
|
||||
let var = self.variable(var_hid, span);
|
||||
self.acc(ln, var, acc);
|
||||
}
|
||||
ln
|
||||
}
|
||||
|
||||
fn access_path(&mut self, id: NodeId, path: &hir::Path, succ: LiveNode, acc: u32)
|
||||
fn access_path(&mut self, hir_id: HirId, path: &hir::Path, succ: LiveNode, acc: u32)
|
||||
-> LiveNode {
|
||||
match path.def {
|
||||
Def::Local(nid) => {
|
||||
self.access_var(id, nid, succ, acc, path.span)
|
||||
self.access_var(hir_id, nid, succ, acc, path.span)
|
||||
}
|
||||
_ => succ
|
||||
}
|
||||
@ -1309,7 +1304,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||
|
||||
// first iteration:
|
||||
let mut first_merge = true;
|
||||
let ln = self.live_node(expr.id, expr.span);
|
||||
let ln = self.live_node(expr.hir_id, expr.span);
|
||||
self.init_empty(ln, succ);
|
||||
match kind {
|
||||
LoopLoop => {}
|
||||
@ -1455,9 +1450,10 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||
// if there is no later assignment. If this local is actually
|
||||
// mutable, then check for a reassignment to flag the mutability
|
||||
// as being used.
|
||||
let ln = self.live_node(expr.id, expr.span);
|
||||
let var = self.variable(nid, expr.span);
|
||||
self.warn_about_dead_assign(expr.span, expr.id, ln, var);
|
||||
let ln = self.live_node(expr.hir_id, expr.span);
|
||||
let var_hid = self.ir.tcx.hir.node_to_hir_id(nid);
|
||||
let var = self.variable(var_hid, expr.span);
|
||||
self.warn_about_dead_assign(expr.span, expr.hir_id, ln, var);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
@ -1479,15 +1475,15 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||
|
||||
fn warn_about_unused_args(&self, body: &hir::Body, entry_ln: LiveNode) {
|
||||
for arg in &body.arguments {
|
||||
arg.pat.each_binding(|_bm, p_id, _, path1| {
|
||||
arg.pat.each_binding(|_bm, hir_id, _, path1| {
|
||||
let sp = path1.span;
|
||||
let var = self.variable(p_id, sp);
|
||||
let var = self.variable(hir_id, sp);
|
||||
// Ignore unused self.
|
||||
let name = path1.node;
|
||||
if name != keywords::SelfValue.name() {
|
||||
if !self.warn_about_unused(sp, p_id, entry_ln, var) {
|
||||
if !self.warn_about_unused(sp, hir_id, entry_ln, var) {
|
||||
if self.live_on_entry(entry_ln, var).is_none() {
|
||||
self.report_dead_assign(p_id, sp, var, true);
|
||||
self.report_dead_assign(hir_id, sp, var, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1505,7 +1501,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||
|
||||
fn warn_about_unused(&self,
|
||||
sp: Span,
|
||||
id: NodeId,
|
||||
hir_id: HirId,
|
||||
ln: LiveNode,
|
||||
var: Variable)
|
||||
-> bool {
|
||||
@ -1527,14 +1523,14 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||
|
||||
if is_assigned {
|
||||
self.ir.tcx
|
||||
.lint_node_note(lint::builtin::UNUSED_VARIABLES, id, sp,
|
||||
&format!("variable `{}` is assigned to, but never used",
|
||||
name),
|
||||
&suggest_underscore_msg);
|
||||
.lint_hir_note(lint::builtin::UNUSED_VARIABLES, hir_id, sp,
|
||||
&format!("variable `{}` is assigned to, but never used",
|
||||
name),
|
||||
&suggest_underscore_msg);
|
||||
} else if name != "self" {
|
||||
let msg = format!("unused variable: `{}`", name);
|
||||
let mut err = self.ir.tcx
|
||||
.struct_span_lint_node(lint::builtin::UNUSED_VARIABLES, id, sp, &msg);
|
||||
.struct_span_lint_hir(lint::builtin::UNUSED_VARIABLES, hir_id, sp, &msg);
|
||||
if self.ir.variable_is_shorthand(var) {
|
||||
err.span_suggestion_with_applicability(sp, "try ignoring the field",
|
||||
format!("{}: _", name),
|
||||
@ -1557,21 +1553,21 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||
|
||||
fn warn_about_dead_assign(&self,
|
||||
sp: Span,
|
||||
id: NodeId,
|
||||
hir_id: HirId,
|
||||
ln: LiveNode,
|
||||
var: Variable) {
|
||||
if self.live_on_exit(ln, var).is_none() {
|
||||
self.report_dead_assign(id, sp, var, false);
|
||||
self.report_dead_assign(hir_id, sp, var, false);
|
||||
}
|
||||
}
|
||||
|
||||
fn report_dead_assign(&self, id: NodeId, sp: Span, var: Variable, is_argument: bool) {
|
||||
fn report_dead_assign(&self, hir_id: HirId, sp: Span, var: Variable, is_argument: bool) {
|
||||
if let Some(name) = self.should_warn(var) {
|
||||
if is_argument {
|
||||
self.ir.tcx.lint_node(lint::builtin::UNUSED_ASSIGNMENTS, id, sp,
|
||||
self.ir.tcx.lint_hir(lint::builtin::UNUSED_ASSIGNMENTS, hir_id, sp,
|
||||
&format!("value passed to `{}` is never read", name));
|
||||
} else {
|
||||
self.ir.tcx.lint_node(lint::builtin::UNUSED_ASSIGNMENTS, id, sp,
|
||||
self.ir.tcx.lint_hir(lint::builtin::UNUSED_ASSIGNMENTS, hir_id, sp,
|
||||
&format!("value assigned to `{}` is never read", name));
|
||||
}
|
||||
}
|
||||
|
@ -2544,6 +2544,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
&self.intern_goals(&[goal])[0]
|
||||
}
|
||||
|
||||
pub fn lint_hir<S: Into<MultiSpan>>(self,
|
||||
lint: &'static Lint,
|
||||
hir_id: HirId,
|
||||
span: S,
|
||||
msg: &str) {
|
||||
self.struct_span_lint_hir(lint, hir_id, span.into(), msg).emit()
|
||||
}
|
||||
|
||||
pub fn lint_node<S: Into<MultiSpan>>(self,
|
||||
lint: &'static Lint,
|
||||
id: NodeId,
|
||||
@ -2552,6 +2560,17 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
self.struct_span_lint_node(lint, id, span.into(), msg).emit()
|
||||
}
|
||||
|
||||
pub fn lint_hir_note<S: Into<MultiSpan>>(self,
|
||||
lint: &'static Lint,
|
||||
hir_id: HirId,
|
||||
span: S,
|
||||
msg: &str,
|
||||
note: &str) {
|
||||
let mut err = self.struct_span_lint_hir(lint, hir_id, span.into(), msg);
|
||||
err.note(note);
|
||||
err.emit()
|
||||
}
|
||||
|
||||
pub fn lint_node_note<S: Into<MultiSpan>>(self,
|
||||
lint: &'static Lint,
|
||||
id: NodeId,
|
||||
@ -2590,6 +2609,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn struct_span_lint_hir<S: Into<MultiSpan>>(self,
|
||||
lint: &'static Lint,
|
||||
hir_id: HirId,
|
||||
span: S,
|
||||
msg: &str)
|
||||
-> DiagnosticBuilder<'tcx>
|
||||
{
|
||||
// FIXME: converting HirId → NodeId is said to be relatively expensive
|
||||
let node_id = self.hir.definitions().find_node_for_hir_id(hir_id);
|
||||
let (level, src) = self.lint_level_at_node(lint, node_id);
|
||||
lint::struct_lint_level(self.sess, lint, level, src, Some(span.into()), msg)
|
||||
}
|
||||
|
||||
pub fn struct_span_lint_node<S: Into<MultiSpan>>(self,
|
||||
lint: &'static Lint,
|
||||
id: NodeId,
|
||||
|
@ -31,8 +31,9 @@ pub type ItemLocalSet = FxHashSet<ItemLocalId>;
|
||||
|
||||
pub fn NodeMap<T>() -> NodeMap<T> { FxHashMap() }
|
||||
pub fn DefIdMap<T>() -> DefIdMap<T> { FxHashMap() }
|
||||
pub fn HirIdMap<T>() -> HirIdMap<T> { FxHashMap() }
|
||||
pub fn ItemLocalMap<T>() -> ItemLocalMap<T> { FxHashMap() }
|
||||
pub fn NodeSet() -> NodeSet { FxHashSet() }
|
||||
pub fn DefIdSet() -> DefIdSet { FxHashSet() }
|
||||
pub fn HirIdSet() -> HirIdSet { FxHashSet() }
|
||||
pub fn ItemLocalSet() -> ItemLocalSet { FxHashSet() }
|
||||
|
||||
|
@ -46,17 +46,16 @@ impl<'a, 'tcx> UnusedMutCx<'a, 'tcx> {
|
||||
let tcx = self.bccx.tcx;
|
||||
let mut mutables = FxHashMap();
|
||||
for p in pats {
|
||||
p.each_binding(|_, id, span, path1| {
|
||||
p.each_binding(|_, hir_id, span, path1| {
|
||||
let name = path1.node;
|
||||
|
||||
// Skip anything that looks like `_foo`
|
||||
if name.as_str().starts_with("_") {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip anything that looks like `&foo` or `&mut foo`, only look
|
||||
// for by-value bindings
|
||||
let hir_id = tcx.hir.node_to_hir_id(id);
|
||||
let bm = match self.bccx.tables.pat_binding_modes().get(hir_id) {
|
||||
Some(&bm) => bm,
|
||||
None => span_bug!(span, "missing binding mode"),
|
||||
@ -66,25 +65,26 @@ impl<'a, 'tcx> UnusedMutCx<'a, 'tcx> {
|
||||
_ => return,
|
||||
}
|
||||
|
||||
mutables.entry(name).or_insert(Vec::new()).push((id, hir_id, span));
|
||||
mutables.entry(name).or_insert(Vec::new()).push((hir_id, span));
|
||||
});
|
||||
}
|
||||
|
||||
for (_name, ids) in mutables {
|
||||
// If any id for this name was used mutably then consider them all
|
||||
// ok, so move on to the next
|
||||
if ids.iter().any(|&(_, ref id, _)| self.used_mut.contains(id)) {
|
||||
continue
|
||||
if ids.iter().any(|&(ref hir_id, _)| self.used_mut.contains(hir_id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut_span = tcx.sess.codemap().span_until_non_whitespace(ids[0].2);
|
||||
let (hir_id, span) = ids[0];
|
||||
let mut_span = tcx.sess.codemap().span_until_non_whitespace(span);
|
||||
|
||||
// Ok, every name wasn't used mutably, so issue a warning that this
|
||||
// didn't need to be mutable.
|
||||
tcx.struct_span_lint_node(UNUSED_MUT,
|
||||
ids[0].0,
|
||||
ids[0].2,
|
||||
"variable does not need to be mutable")
|
||||
tcx.struct_span_lint_hir(UNUSED_MUT,
|
||||
hir_id,
|
||||
span,
|
||||
"variable does not need to be mutable")
|
||||
.span_suggestion_short(mut_span, "remove this `mut`", "".to_owned())
|
||||
.emit();
|
||||
}
|
||||
|
@ -499,8 +499,7 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor,
|
||||
pats: &[P<Pat>]) {
|
||||
let mut by_ref_span = None;
|
||||
for pat in pats {
|
||||
pat.each_binding(|_, id, span, _path| {
|
||||
let hir_id = cx.tcx.hir.node_to_hir_id(id);
|
||||
pat.each_binding(|_, hir_id, span, _path| {
|
||||
let bm = *cx.tables
|
||||
.pat_binding_modes()
|
||||
.get(hir_id)
|
||||
|
@ -380,7 +380,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
|
||||
|
||||
fn constrain_bindings_in_pat(&mut self, pat: &hir::Pat) {
|
||||
debug!("regionck::visit_pat(pat={:?})", pat);
|
||||
pat.each_binding(|_, id, span, _| {
|
||||
pat.each_binding(|_, hir_id, span, _| {
|
||||
// If we have a variable that contains region'd data, that
|
||||
// data will be accessible from anywhere that the variable is
|
||||
// accessed. We must be wary of loops like this:
|
||||
@ -403,8 +403,6 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
|
||||
// iteration. The easiest way to guarantee this is to require
|
||||
// that the lifetime of any regions that appear in a
|
||||
// variable's type enclose at least the variable's scope.
|
||||
|
||||
let hir_id = self.tcx.hir.node_to_hir_id(id);
|
||||
let var_scope = self.region_scope_tree.var_scope(hir_id.local_id);
|
||||
let var_region = self.tcx.mk_region(ty::ReScope(var_scope));
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user