diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 38d6d710868..517c99f99ef 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -1102,6 +1102,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { } pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm) { + visitor.visit_id(arm.hir_id); walk_list!(visitor, visit_pat, &arm.pats); if let Some(ref g) = arm.guard { match g { diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 3ec4d4e8cc8..8dba7491bf5 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1313,7 +1313,10 @@ impl<'a> LoweringContext<'a> { } fn lower_arm(&mut self, arm: &Arm) -> hir::Arm { + let LoweredNodeId { node_id: _, hir_id } = self.next_id(); + hir::Arm { + hir_id, attrs: self.lower_attrs(&arm.attrs), pats: arm.pats.iter().map(|x| self.lower_pat(x)).collect(), guard: match arm.guard { @@ -1321,6 +1324,7 @@ impl<'a> LoweringContext<'a> { _ => None, }, body: P(self.lower_expr(&arm.body)), + span: arm.span, } } @@ -5023,10 +5027,14 @@ impl<'a> LoweringContext<'a> { // Helper methods for building HIR. fn arm(&mut self, pats: hir::HirVec>, expr: P) -> hir::Arm { + let LoweredNodeId { node_id: _, hir_id } = self.next_id(); + hir::Arm { + hir_id, attrs: hir_vec![], pats, guard: None, + span: expr.span, body: expr, } } diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index eeba628b3bf..b5203f9ec1f 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -430,6 +430,16 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }); } + fn visit_arm(&mut self, arm: &'hir Arm) { + let node = Node::Arm(arm); + + self.insert(arm.span, arm.hir_id, node); + + self.with_parent(arm.hir_id, |this| { + intravisit::walk_arm(this, arm); + }); + } + fn visit_anon_const(&mut self, constant: &'hir AnonConst) { self.insert(DUMMY_SP, constant.hir_id, Node::AnonConst(constant)); diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 4b94f772554..d8fe90d4048 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -373,6 +373,7 @@ impl<'hir> Map<'hir> { Node::Pat(_) | Node::Binding(_) | Node::Local(_) | + Node::Arm(_) | Node::Lifetime(_) | Node::Visibility(_) | Node::Block(_) | @@ -1000,6 +1001,7 @@ impl<'hir> Map<'hir> { Some(Node::Field(ref f)) => Some(&f.attrs[..]), Some(Node::Expr(ref e)) => Some(&*e.attrs), Some(Node::Stmt(ref s)) => Some(s.node.attrs()), + Some(Node::Arm(ref a)) => Some(&*a.attrs), Some(Node::GenericParam(param)) => Some(¶m.attrs[..]), // Unit/tuple structs/variants take the attributes straight from // the struct/variant definition. @@ -1073,6 +1075,7 @@ impl<'hir> Map<'hir> { Some(Node::TraitRef(tr)) => tr.path.span, Some(Node::Binding(pat)) => pat.span, Some(Node::Pat(pat)) => pat.span, + Some(Node::Arm(arm)) => arm.span, Some(Node::Block(block)) => block.span, Some(Node::Ctor(..)) => match self.find_by_hir_id( self.get_parent_node_by_hir_id(hir_id)) @@ -1288,6 +1291,7 @@ impl<'a> print::State<'a> { Node::TraitRef(a) => self.print_trait_ref(&a), Node::Binding(a) | Node::Pat(a) => self.print_pat(&a), + Node::Arm(a) => self.print_arm(&a), Node::Block(a) => { use syntax::print::pprust::PrintState; @@ -1417,6 +1421,9 @@ fn hir_id_to_string(map: &Map<'_>, id: HirId, include_id: bool) -> String { Some(Node::Pat(_)) => { format!("pat {}{}", map.hir_to_pretty_string(id), id_str) } + Some(Node::Arm(_)) => { + format!("arm {}{}", map.hir_to_pretty_string(id), id_str) + } Some(Node::Block(_)) => { format!("block {}{}", map.hir_to_pretty_string(id), id_str) } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 57304c5ed37..08feea3ccce 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1228,6 +1228,9 @@ pub struct Local { /// ` (if ) => `. #[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)] pub struct Arm { + #[stable_hasher(ignore)] + pub hir_id: HirId, + pub span: Span, pub attrs: HirVec, /// Multiple patterns can be combined with `|` pub pats: HirVec>, @@ -2656,6 +2659,7 @@ pub enum Node<'hir> { TraitRef(&'hir TraitRef), Binding(&'hir Pat), Pat(&'hir Pat), + Arm(&'hir Arm), Block(&'hir Block), Local(&'hir Local), MacroDef(&'hir MacroDef), diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 8a9028e5443..ef9fee5cab6 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -1862,7 +1862,7 @@ impl<'a> State<'a> { self.ann.post(self, AnnNode::Pat(pat)) } - fn print_arm(&mut self, arm: &hir::Arm) -> io::Result<()> { + pub fn print_arm(&mut self, arm: &hir::Arm) -> io::Result<()> { // I have no idea why this check is necessary, but here it // is :( if arm.attrs.is_empty() { diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs index c74314ce0c4..0088c97679c 100644 --- a/src/librustc_passes/hir_stats.rs +++ b/src/librustc_passes/hir_stats.rs @@ -149,7 +149,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { } fn visit_arm(&mut self, a: &'v hir::Arm) { - self.record("Arm", Id::None, a); + self.record("Arm", Id::Node(a.hir_id), a); hir_visit::walk_arm(self, a) } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index a69f639e894..99b350b8332 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -781,14 +781,17 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); fn maybe_get_coercion_reason(&self, hir_id: hir::HirId, span: Span) -> Option<(Span, String)> { use hir::Node::{Block, Item, Local}; - let node = self.tcx.hir().get_by_hir_id(self.tcx.hir().get_parent_node_by_hir_id( - self.tcx.hir().get_parent_node_by_hir_id(hir_id), - )); + let hir = self.tcx.hir(); + let arm_id = hir.get_parent_node_by_hir_id(hir_id); + let match_id = hir.get_parent_node_by_hir_id(arm_id); + let containing_id = hir.get_parent_node_by_hir_id(match_id); + + let node = hir.get_by_hir_id(containing_id); if let Block(block) = node { // check that the body's parent is an fn - let parent = self.tcx.hir().get_by_hir_id( - self.tcx.hir().get_parent_node_by_hir_id( - self.tcx.hir().get_parent_node_by_hir_id(block.hir_id), + let parent = hir.get_by_hir_id( + hir.get_parent_node_by_hir_id( + hir.get_parent_node_by_hir_id(block.hir_id), ), ); if let (Some(expr), Item(hir::Item { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index a6bb47bef87..e2c2c46abf6 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -908,6 +908,7 @@ pub struct Arm { pub pats: Vec>, pub guard: Option, pub body: P, + pub span: Span, } #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index d24106f697e..cb967a76822 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -890,12 +890,13 @@ impl<'a> AstBuilder for ExtCtxt<'a> { self.pat_tuple_struct(span, path, vec![pat]) } - fn arm(&self, _span: Span, pats: Vec>, expr: P) -> ast::Arm { + fn arm(&self, span: Span, pats: Vec>, expr: P) -> ast::Arm { ast::Arm { attrs: vec![], pats, guard: None, body: expr, + span, } } diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index f587e63e12b..cb21014ec76 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -392,11 +392,15 @@ pub fn noop_visit_use_tree(use_tree: &mut UseTree, vis: &mut T) { vis.visit_span(span); } -pub fn noop_visit_arm(Arm { attrs, pats, guard, body }: &mut Arm, vis: &mut T) { +pub fn noop_visit_arm( + Arm { attrs, pats, guard, body, span }: &mut Arm, + vis: &mut T, +) { visit_attrs(attrs, vis); visit_vec(pats, |pat| vis.visit_pat(pat)); visit_opt(guard, |guard| vis.visit_guard(guard)); vis.visit_expr(body); + vis.visit_span(span); } pub fn noop_visit_guard(g: &mut Guard, vis: &mut T) { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 24d120376de..ba36783e11e 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3946,6 +3946,7 @@ impl<'a> Parser<'a> { crate fn parse_arm(&mut self) -> PResult<'a, Arm> { let attrs = self.parse_outer_attributes()?; + let lo = self.span; let pats = self.parse_pats()?; let guard = if self.eat_keyword(keywords::If) { Some(Guard::If(self.parse_expr()?)) @@ -3965,6 +3966,8 @@ impl<'a> Parser<'a> { let require_comma = classify::expr_requires_semi_to_be_stmt(&expr) && self.token != token::CloseDelim(token::Brace); + let hi = self.span; + if require_comma { let cm = self.sess.source_map(); self.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Brace)]) @@ -4008,6 +4011,7 @@ impl<'a> Parser<'a> { pats, guard, body: expr, + span: lo.to(hi), }) }