From bbf0daa19276354d5759d0b0bd7d31bcd3cc301c Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 16 Jun 2015 21:56:33 +1200 Subject: [PATCH 1/4] Add parent_node to ast_map --- src/librustc/ast_map/mod.rs | 200 ++++++++++++++++++++++++------------ 1 file changed, 133 insertions(+), 67 deletions(-) diff --git a/src/librustc/ast_map/mod.rs b/src/librustc/ast_map/mod.rs index 06d87f5333ad..39ad2022183e 100644 --- a/src/librustc/ast_map/mod.rs +++ b/src/librustc/ast_map/mod.rs @@ -121,27 +121,28 @@ pub enum Node<'ast> { NodeLifetime(&'ast Lifetime), } -/// Represents an entry and its parent Node ID +/// Represents an entry and its parent NodeID and parent_node NodeID, see +/// get_parent_node for the distinction. /// The odd layout is to bring down the total size. #[derive(Copy, Debug)] enum MapEntry<'ast> { /// Placeholder for holes in the map. NotPresent, - /// All the node types, with a parent ID. - EntryItem(NodeId, &'ast Item), - EntryForeignItem(NodeId, &'ast ForeignItem), - EntryTraitItem(NodeId, &'ast TraitItem), - EntryImplItem(NodeId, &'ast ImplItem), - EntryVariant(NodeId, &'ast Variant), - EntryExpr(NodeId, &'ast Expr), - EntryStmt(NodeId, &'ast Stmt), - EntryArg(NodeId, &'ast Pat), - EntryLocal(NodeId, &'ast Pat), - EntryPat(NodeId, &'ast Pat), - EntryBlock(NodeId, &'ast Block), - EntryStructCtor(NodeId, &'ast StructDef), - EntryLifetime(NodeId, &'ast Lifetime), + /// All the node types, with a parent and scope ID. + EntryItem(NodeId, NodeId, &'ast Item), + EntryForeignItem(NodeId, NodeId, &'ast ForeignItem), + EntryTraitItem(NodeId, NodeId, &'ast TraitItem), + EntryImplItem(NodeId, NodeId, &'ast ImplItem), + EntryVariant(NodeId, NodeId, &'ast Variant), + EntryExpr(NodeId, NodeId, &'ast Expr), + EntryStmt(NodeId, NodeId, &'ast Stmt), + EntryArg(NodeId, NodeId, &'ast Pat), + EntryLocal(NodeId, NodeId, &'ast Pat), + EntryPat(NodeId, NodeId, &'ast Pat), + EntryBlock(NodeId, NodeId, &'ast Block), + EntryStructCtor(NodeId, NodeId, &'ast StructDef), + EntryLifetime(NodeId, NodeId, &'ast Lifetime), /// Roots for node trees. RootCrate, @@ -161,58 +162,77 @@ struct InlinedParent { } impl<'ast> MapEntry<'ast> { - fn from_node(p: NodeId, node: Node<'ast>) -> MapEntry<'ast> { + fn from_node(p: NodeId, s: NodeId, node: Node<'ast>) -> MapEntry<'ast> { match node { - NodeItem(n) => EntryItem(p, n), - NodeForeignItem(n) => EntryForeignItem(p, n), - NodeTraitItem(n) => EntryTraitItem(p, n), - NodeImplItem(n) => EntryImplItem(p, n), - NodeVariant(n) => EntryVariant(p, n), - NodeExpr(n) => EntryExpr(p, n), - NodeStmt(n) => EntryStmt(p, n), - NodeArg(n) => EntryArg(p, n), - NodeLocal(n) => EntryLocal(p, n), - NodePat(n) => EntryPat(p, n), - NodeBlock(n) => EntryBlock(p, n), - NodeStructCtor(n) => EntryStructCtor(p, n), - NodeLifetime(n) => EntryLifetime(p, n) + NodeItem(n) => EntryItem(p, s, n), + NodeForeignItem(n) => EntryForeignItem(p, s, n), + NodeTraitItem(n) => EntryTraitItem(p, s, n), + NodeImplItem(n) => EntryImplItem(p, s, n), + NodeVariant(n) => EntryVariant(p, s, n), + NodeExpr(n) => EntryExpr(p, s, n), + NodeStmt(n) => EntryStmt(p, s, n), + NodeArg(n) => EntryArg(p, s, n), + NodeLocal(n) => EntryLocal(p, s, n), + NodePat(n) => EntryPat(p, s, n), + NodeBlock(n) => EntryBlock(p, s, n), + NodeStructCtor(n) => EntryStructCtor(p, s, n), + NodeLifetime(n) => EntryLifetime(p, s, n) } } fn parent(self) -> Option { Some(match self { - EntryItem(id, _) => id, - EntryForeignItem(id, _) => id, - EntryTraitItem(id, _) => id, - EntryImplItem(id, _) => id, - EntryVariant(id, _) => id, - EntryExpr(id, _) => id, - EntryStmt(id, _) => id, - EntryArg(id, _) => id, - EntryLocal(id, _) => id, - EntryPat(id, _) => id, - EntryBlock(id, _) => id, - EntryStructCtor(id, _) => id, - EntryLifetime(id, _) => id, + EntryItem(id, _, _) => id, + EntryForeignItem(id, _, _) => id, + EntryTraitItem(id, _, _) => id, + EntryImplItem(id, _, _) => id, + EntryVariant(id, _, _) => id, + EntryExpr(id, _, _) => id, + EntryStmt(id, _, _) => id, + EntryArg(id, _, _) => id, + EntryLocal(id, _, _) => id, + EntryPat(id, _, _) => id, + EntryBlock(id, _, _) => id, + EntryStructCtor(id, _, _) => id, + EntryLifetime(id, _, _) => id, + _ => return None + }) + } + + fn parent_node(self) -> Option { + Some(match self { + EntryItem(_, id, _) => id, + EntryForeignItem(_, id, _) => id, + EntryTraitItem(_, id, _) => id, + EntryImplItem(_, id, _) => id, + EntryVariant(_, id, _) => id, + EntryExpr(_, id, _) => id, + EntryStmt(_, id, _) => id, + EntryArg(_, id, _) => id, + EntryLocal(_, id, _) => id, + EntryPat(_, id, _) => id, + EntryBlock(_, id, _) => id, + EntryStructCtor(_, id, _) => id, + EntryLifetime(_, id, _) => id, _ => return None }) } fn to_node(self) -> Option> { Some(match self { - EntryItem(_, n) => NodeItem(n), - EntryForeignItem(_, n) => NodeForeignItem(n), - EntryTraitItem(_, n) => NodeTraitItem(n), - EntryImplItem(_, n) => NodeImplItem(n), - EntryVariant(_, n) => NodeVariant(n), - EntryExpr(_, n) => NodeExpr(n), - EntryStmt(_, n) => NodeStmt(n), - EntryArg(_, n) => NodeArg(n), - EntryLocal(_, n) => NodeLocal(n), - EntryPat(_, n) => NodePat(n), - EntryBlock(_, n) => NodeBlock(n), - EntryStructCtor(_, n) => NodeStructCtor(n), - EntryLifetime(_, n) => NodeLifetime(n), + EntryItem(_, _, n) => NodeItem(n), + EntryForeignItem(_, _, n) => NodeForeignItem(n), + EntryTraitItem(_, _, n) => NodeTraitItem(n), + EntryImplItem(_, _, n) => NodeImplItem(n), + EntryVariant(_, _, n) => NodeVariant(n), + EntryExpr(_, _, n) => NodeExpr(n), + EntryStmt(_, _, n) => NodeStmt(n), + EntryArg(_, _, n) => NodeArg(n), + EntryLocal(_, _, n) => NodeLocal(n), + EntryPat(_, _, n) => NodePat(n), + EntryBlock(_, _, n) => NodeBlock(n), + EntryStructCtor(_, _, n) => NodeStructCtor(n), + EntryLifetime(_, _, n) => NodeLifetime(n), _ => return None }) } @@ -289,6 +309,18 @@ impl<'ast> Map<'ast> { self.find_entry(id).and_then(|x| x.parent()).unwrap_or(id) } + /// Similar to get_parent, returns the parent node id or id if there is no + /// parent. + /// This function returns the most direct parent in the AST, whereas get_parent + /// returns the enclosing item. Note that this might not be the actual parent + /// node in the AST - some kinds of nodes are not in the map and these will + /// never appear as the parent_node. So you can always walk the parent_nodes + /// from a node to the root of the ast (unless you get the same id back here + /// that can happen if the id is not in the map itself or is just weird). + pub fn get_parent_node(&self, id: NodeId) -> NodeId { + self.find_entry(id).and_then(|x| x.parent_node()).unwrap_or(id) + } + pub fn get_parent_did(&self, id: NodeId) -> DefId { let parent = self.get_parent(id); match self.find_entry(parent) { @@ -301,7 +333,7 @@ impl<'ast> Map<'ast> { pub fn get_foreign_abi(&self, id: NodeId) -> abi::Abi { let parent = self.get_parent(id); let abi = match self.find_entry(parent) { - Some(EntryItem(_, i)) => { + Some(EntryItem(_, _, i)) => { match i.node { ItemForeignMod(ref nm) => Some(nm.abi), _ => None @@ -591,11 +623,11 @@ impl<'a, 'ast> Iterator for NodesMatchingSuffix<'a, 'ast> { } self.idx += 1; let (p, name) = match self.map.find_entry(idx) { - Some(EntryItem(p, n)) => (p, n.name()), - Some(EntryForeignItem(p, n))=> (p, n.name()), - Some(EntryTraitItem(p, n)) => (p, n.name()), - Some(EntryImplItem(p, n)) => (p, n.name()), - Some(EntryVariant(p, n)) => (p, n.name()), + Some(EntryItem(p, _, n)) => (p, n.name()), + Some(EntryForeignItem(p, _, n))=> (p, n.name()), + Some(EntryTraitItem(p, _, n)) => (p, n.name()), + Some(EntryImplItem(p, _, n)) => (p, n.name()), + Some(EntryVariant(p, _, n)) => (p, n.name()), _ => continue, }; if self.matches_names(p, name) { @@ -648,7 +680,8 @@ impl Folder for IdAndSpanUpdater { struct NodeCollector<'ast> { map: Vec>, /// The node in which we are currently mapping (an item or a method). - parent: NodeId + parent: NodeId, + parent_node: NodeId, } impl<'ast> NodeCollector<'ast> { @@ -662,7 +695,7 @@ impl<'ast> NodeCollector<'ast> { } fn insert(&mut self, id: NodeId, node: Node<'ast>) { - let entry = MapEntry::from_node(self.parent, node); + let entry = MapEntry::from_node(self.parent, self.parent_node, node); self.insert_entry(id, entry); } @@ -678,6 +711,8 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { self.insert(i.id, NodeItem(i)); let parent = self.parent; self.parent = i.id; + let parent_node = self.parent_node; + self.parent_node = i.id; match i.node { ItemImpl(_, _, _, _, _, ref impl_items) => { for ii in impl_items { @@ -728,48 +763,70 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { } visit::walk_item(self, i); self.parent = parent; + self.parent_node = parent_node; } fn visit_trait_item(&mut self, ti: &'ast TraitItem) { let parent = self.parent; self.parent = ti.id; + let parent_node = self.parent_node; + self.parent_node = ti.id; visit::walk_trait_item(self, ti); self.parent = parent; + self.parent_node = parent_node; } fn visit_impl_item(&mut self, ii: &'ast ImplItem) { let parent = self.parent; self.parent = ii.id; + let parent_node = self.parent_node; + self.parent_node = ii.id; visit::walk_impl_item(self, ii); self.parent = parent; + self.parent_node = parent_node; } fn visit_pat(&mut self, pat: &'ast Pat) { + let parent_node = self.parent_node; + self.parent_node = pat.id; self.insert(pat.id, match pat.node { // Note: this is at least *potentially* a pattern... PatIdent(..) => NodeLocal(pat), _ => NodePat(pat) }); visit::walk_pat(self, pat); + self.parent_node = parent_node; } fn visit_expr(&mut self, expr: &'ast Expr) { + let parent_node = self.parent_node; + self.parent_node = expr.id; self.insert(expr.id, NodeExpr(expr)); visit::walk_expr(self, expr); + self.parent_node = parent_node; } fn visit_stmt(&mut self, stmt: &'ast Stmt) { - self.insert(ast_util::stmt_id(stmt), NodeStmt(stmt)); + let id = ast_util::stmt_id(stmt); + let parent_node = self.parent_node; + self.parent_node = id; + self.insert(id, NodeStmt(stmt)); visit::walk_stmt(self, stmt); + self.parent_node = parent_node; } fn visit_fn(&mut self, fk: visit::FnKind<'ast>, fd: &'ast FnDecl, - b: &'ast Block, s: Span, _: NodeId) { + b: &'ast Block, s: Span, id: NodeId) { + let parent_node = self.parent_node; + self.parent_node = id; self.visit_fn_decl(fd); visit::walk_fn(self, fk, fd, b, s); + self.parent_node = parent_node; } fn visit_ty(&mut self, ty: &'ast Ty) { + let parent_node = self.parent_node; + self.parent_node = ty.id; match ty.node { TyBareFn(ref fd) => { self.visit_fn_decl(&*fd.decl); @@ -777,15 +834,22 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { _ => {} } visit::walk_ty(self, ty); + self.parent_node = parent_node; } fn visit_block(&mut self, block: &'ast Block) { + let parent_node = self.parent_node; + self.parent_node = block.id; self.insert(block.id, NodeBlock(block)); visit::walk_block(self, block); + self.parent_node = parent_node; } fn visit_lifetime_ref(&mut self, lifetime: &'ast Lifetime) { + let parent_node = self.parent_node; + self.parent_node = lifetime.id; self.insert(lifetime.id, NodeLifetime(lifetime)); + self.parent_node = parent_node; } fn visit_lifetime_def(&mut self, def: &'ast LifetimeDef) { @@ -809,7 +873,8 @@ pub fn map_crate<'ast, F: FoldOps>(forest: &'ast mut Forest, fold_ops: F) -> Map let mut collector = NodeCollector { map: vec![], - parent: CRATE_NODE_ID + parent: CRATE_NODE_ID, + parent_node: CRATE_NODE_ID, }; collector.insert_entry(CRATE_NODE_ID, RootCrate); visit::walk_crate(&mut collector, &forest.krate); @@ -866,7 +931,8 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>, let mut collector = NodeCollector { map: mem::replace(&mut *map.map.borrow_mut(), vec![]), - parent: fld.new_id(DUMMY_NODE_ID) + parent: fld.new_id(DUMMY_NODE_ID), + parent_node: fld.new_id(DUMMY_NODE_ID), }; let ii_parent_id = collector.parent; collector.insert_entry(ii_parent_id, RootInlinedParent(ii_parent)); From b23ddc60e9fcb188421060a83f1af2b815fc60e2 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 16 Jun 2015 22:20:30 +1200 Subject: [PATCH 2/4] Implement get_enclosing_scope and use it in save-analysis --- src/librustc/ast_map/mod.rs | 28 ++++++++++++++++++++++++++++ src/librustc_trans/save/mod.rs | 16 ++++++++-------- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/src/librustc/ast_map/mod.rs b/src/librustc/ast_map/mod.rs index 39ad2022183e..7c80ba376c36 100644 --- a/src/librustc/ast_map/mod.rs +++ b/src/librustc/ast_map/mod.rs @@ -321,6 +321,34 @@ impl<'ast> Map<'ast> { self.find_entry(id).and_then(|x| x.parent_node()).unwrap_or(id) } + /// Returns the nearest enclosing scope. A scope is an item or block. + /// FIXME it is not clear to me that all items qualify as scopes - statics + /// and associated types probably shouldn't, for example. Behaviour in this + /// regard should be expected to be highly unstable. + pub fn get_enclosing_scope(&self, id: NodeId) -> Option { + let mut last_id = id; + // Walk up the chain of parents until we find a 'scope'. + loop { + let cur_id = self.get_parent_node(last_id); + if cur_id == last_id { + return None; + } + + match self.get(cur_id) { + NodeItem(_) | + NodeForeignItem(_) | + NodeTraitItem(_) | + NodeImplItem(_) | + NodeBlock(_) => { + return Some(cur_id); + } + _ => {} + } + + last_id = cur_id; + } + } + pub fn get_parent_did(&self, id: NodeId) -> DefId { let parent = self.get_parent(id); match self.find_entry(parent) { diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index 27805b9d8330..e9c91f4f4c19 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -172,7 +172,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { qualname: qualname, declaration: None, span: sub_span.unwrap(), - scope: self.tcx.map.get_parent(item.id), + scope: self.tcx.map.get_enclosing_scope(item.id).unwrap(), }) } ast::ItemStatic(ref typ, mt, ref expr) => { @@ -191,7 +191,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { name: get_ident(item.ident).to_string(), qualname: qualname, span: sub_span.unwrap(), - scope: self.tcx.map.get_parent(item.id), + scope: self.tcx.map.get_enclosing_scope(item.id).unwrap(), value: value, type_value: ty_to_string(&typ), }) @@ -205,7 +205,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { name: get_ident(item.ident).to_string(), qualname: qualname, span: sub_span.unwrap(), - scope: self.tcx.map.get_parent(item.id), + scope: self.tcx.map.get_enclosing_scope(item.id).unwrap(), value: self.span_utils.snippet(expr.span), type_value: ty_to_string(&typ), }) @@ -223,7 +223,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { name: get_ident(item.ident).to_string(), qualname: qualname, span: sub_span.unwrap(), - scope: self.tcx.map.get_parent(item.id), + scope: self.tcx.map.get_enclosing_scope(item.id).unwrap(), filename: filename, }) }, @@ -237,14 +237,14 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { value: val, span: sub_span.unwrap(), qualname: enum_name, - scope: self.tcx.map.get_parent(item.id), + scope: self.tcx.map.get_enclosing_scope(item.id).unwrap(), }) }, ast::ItemImpl(_, _, _, ref trait_ref, ref typ, _) => { let mut type_data = None; let sub_span; - let parent = self.tcx.map.get_parent(item.id); + let parent = self.tcx.map.get_enclosing_scope(item.id).unwrap(); match typ.node { // Common case impl for a struct or something basic. @@ -337,7 +337,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { return Some(Data::VariableRefData(VariableRefData { name: get_ident(ident.node).to_string(), span: sub_span.unwrap(), - scope: self.tcx.map.get_parent(expr.id), + scope: self.tcx.map.get_enclosing_scope(expr.id).unwrap(), ref_id: f.id, })); } @@ -360,7 +360,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let sub_span = self.span_utils.span_for_last_ident(path.span); Some(Data::TypeRefData(TypeRefData { span: sub_span.unwrap(), - scope: self.tcx.map.get_parent(expr.id), + scope: self.tcx.map.get_enclosing_scope(expr.id).unwrap(), ref_id: def_id, })) } From 15dcb5bfc51753aad5527888ec5a1c9381e8d1e1 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Thu, 25 Jun 2015 15:48:59 -0700 Subject: [PATCH 3/4] Alternate method --- src/librustc/ast_map/mod.rs | 214 +++++++++++++++++---------------- src/librustc_trans/save/mod.rs | 16 +-- 2 files changed, 117 insertions(+), 113 deletions(-) diff --git a/src/librustc/ast_map/mod.rs b/src/librustc/ast_map/mod.rs index 7c80ba376c36..800cd7e8aeea 100644 --- a/src/librustc/ast_map/mod.rs +++ b/src/librustc/ast_map/mod.rs @@ -130,19 +130,19 @@ enum MapEntry<'ast> { NotPresent, /// All the node types, with a parent and scope ID. - EntryItem(NodeId, NodeId, &'ast Item), - EntryForeignItem(NodeId, NodeId, &'ast ForeignItem), - EntryTraitItem(NodeId, NodeId, &'ast TraitItem), - EntryImplItem(NodeId, NodeId, &'ast ImplItem), - EntryVariant(NodeId, NodeId, &'ast Variant), - EntryExpr(NodeId, NodeId, &'ast Expr), - EntryStmt(NodeId, NodeId, &'ast Stmt), - EntryArg(NodeId, NodeId, &'ast Pat), - EntryLocal(NodeId, NodeId, &'ast Pat), - EntryPat(NodeId, NodeId, &'ast Pat), - EntryBlock(NodeId, NodeId, &'ast Block), - EntryStructCtor(NodeId, NodeId, &'ast StructDef), - EntryLifetime(NodeId, NodeId, &'ast Lifetime), + EntryItem(NodeId, &'ast Item), + EntryForeignItem(NodeId, &'ast ForeignItem), + EntryTraitItem(NodeId, &'ast TraitItem), + EntryImplItem(NodeId, &'ast ImplItem), + EntryVariant(NodeId, &'ast Variant), + EntryExpr(NodeId, &'ast Expr), + EntryStmt(NodeId, &'ast Stmt), + EntryArg(NodeId, &'ast Pat), + EntryLocal(NodeId, &'ast Pat), + EntryPat(NodeId, &'ast Pat), + EntryBlock(NodeId, &'ast Block), + EntryStructCtor(NodeId, &'ast StructDef), + EntryLifetime(NodeId, &'ast Lifetime), /// Roots for node trees. RootCrate, @@ -162,77 +162,58 @@ struct InlinedParent { } impl<'ast> MapEntry<'ast> { - fn from_node(p: NodeId, s: NodeId, node: Node<'ast>) -> MapEntry<'ast> { + fn from_node(s: NodeId, node: Node<'ast>) -> MapEntry<'ast> { match node { - NodeItem(n) => EntryItem(p, s, n), - NodeForeignItem(n) => EntryForeignItem(p, s, n), - NodeTraitItem(n) => EntryTraitItem(p, s, n), - NodeImplItem(n) => EntryImplItem(p, s, n), - NodeVariant(n) => EntryVariant(p, s, n), - NodeExpr(n) => EntryExpr(p, s, n), - NodeStmt(n) => EntryStmt(p, s, n), - NodeArg(n) => EntryArg(p, s, n), - NodeLocal(n) => EntryLocal(p, s, n), - NodePat(n) => EntryPat(p, s, n), - NodeBlock(n) => EntryBlock(p, s, n), - NodeStructCtor(n) => EntryStructCtor(p, s, n), - NodeLifetime(n) => EntryLifetime(p, s, n) + NodeItem(n) => EntryItem(s, n), + NodeForeignItem(n) => EntryForeignItem(s, n), + NodeTraitItem(n) => EntryTraitItem(s, n), + NodeImplItem(n) => EntryImplItem(s, n), + NodeVariant(n) => EntryVariant(s, n), + NodeExpr(n) => EntryExpr(s, n), + NodeStmt(n) => EntryStmt(s, n), + NodeArg(n) => EntryArg(s, n), + NodeLocal(n) => EntryLocal(s, n), + NodePat(n) => EntryPat(s, n), + NodeBlock(n) => EntryBlock(s, n), + NodeStructCtor(n) => EntryStructCtor(s, n), + NodeLifetime(n) => EntryLifetime(s, n) } } - fn parent(self) -> Option { - Some(match self { - EntryItem(id, _, _) => id, - EntryForeignItem(id, _, _) => id, - EntryTraitItem(id, _, _) => id, - EntryImplItem(id, _, _) => id, - EntryVariant(id, _, _) => id, - EntryExpr(id, _, _) => id, - EntryStmt(id, _, _) => id, - EntryArg(id, _, _) => id, - EntryLocal(id, _, _) => id, - EntryPat(id, _, _) => id, - EntryBlock(id, _, _) => id, - EntryStructCtor(id, _, _) => id, - EntryLifetime(id, _, _) => id, - _ => return None - }) - } - fn parent_node(self) -> Option { Some(match self { - EntryItem(_, id, _) => id, - EntryForeignItem(_, id, _) => id, - EntryTraitItem(_, id, _) => id, - EntryImplItem(_, id, _) => id, - EntryVariant(_, id, _) => id, - EntryExpr(_, id, _) => id, - EntryStmt(_, id, _) => id, - EntryArg(_, id, _) => id, - EntryLocal(_, id, _) => id, - EntryPat(_, id, _) => id, - EntryBlock(_, id, _) => id, - EntryStructCtor(_, id, _) => id, - EntryLifetime(_, id, _) => id, + EntryItem(id, _) => id, + EntryForeignItem(id, _) => id, + EntryTraitItem(id, _) => id, + EntryImplItem(id, _) => id, + EntryVariant(id, _) => id, + EntryExpr(id, _) => id, + EntryStmt(id, _) => id, + EntryArg(id, _) => id, + EntryLocal(id, _) => id, + EntryPat(id, _) => id, + EntryBlock(id, _) => id, + EntryStructCtor(id, _) => id, + EntryLifetime(id, _) => id, _ => return None }) } fn to_node(self) -> Option> { Some(match self { - EntryItem(_, _, n) => NodeItem(n), - EntryForeignItem(_, _, n) => NodeForeignItem(n), - EntryTraitItem(_, _, n) => NodeTraitItem(n), - EntryImplItem(_, _, n) => NodeImplItem(n), - EntryVariant(_, _, n) => NodeVariant(n), - EntryExpr(_, _, n) => NodeExpr(n), - EntryStmt(_, _, n) => NodeStmt(n), - EntryArg(_, _, n) => NodeArg(n), - EntryLocal(_, _, n) => NodeLocal(n), - EntryPat(_, _, n) => NodePat(n), - EntryBlock(_, _, n) => NodeBlock(n), - EntryStructCtor(_, _, n) => NodeStructCtor(n), - EntryLifetime(_, _, n) => NodeLifetime(n), + EntryItem(_, n) => NodeItem(n), + EntryForeignItem(_, n) => NodeForeignItem(n), + EntryTraitItem(_, n) => NodeTraitItem(n), + EntryImplItem(_, n) => NodeImplItem(n), + EntryVariant(_, n) => NodeVariant(n), + EntryExpr(_, n) => NodeExpr(n), + EntryStmt(_, n) => NodeStmt(n), + EntryArg(_, n) => NodeArg(n), + EntryLocal(_, n) => NodeLocal(n), + EntryPat(_, n) => NodePat(n), + EntryBlock(_, n) => NodeBlock(n), + EntryStructCtor(_, n) => NodeStructCtor(n), + EntryLifetime(_, n) => NodeLifetime(n), _ => return None }) } @@ -306,7 +287,37 @@ impl<'ast> Map<'ast> { /// Retrieve the parent NodeId for `id`, or `id` itself if no /// parent is registered in this map. pub fn get_parent(&self, id: NodeId) -> NodeId { - self.find_entry(id).and_then(|x| x.parent()).unwrap_or(id) + let mut id = id; + loop { + let parent_node = self.get_parent_node(id); + if parent_node == 0 { + return parent_node; + } + if parent_node == id { + return id; + } + + let node = self.find_entry(parent_node); + if node.is_none() { + return id; + } + let node = node.unwrap().to_node(); + match node { + Some(node) => match node { + NodeItem(_) | + NodeForeignItem(_) | + NodeTraitItem(_) | + NodeImplItem(_) => { + return parent_node; + } + _ => {} + }, + None => { + return parent_node; + } + } + id = parent_node; + } } /// Similar to get_parent, returns the parent node id or id if there is no @@ -334,6 +345,10 @@ impl<'ast> Map<'ast> { return None; } + if cur_id == 0 { + return Some(0); + } + match self.get(cur_id) { NodeItem(_) | NodeForeignItem(_) | @@ -361,7 +376,7 @@ impl<'ast> Map<'ast> { pub fn get_foreign_abi(&self, id: NodeId) -> abi::Abi { let parent = self.get_parent(id); let abi = match self.find_entry(parent) { - Some(EntryItem(_, _, i)) => { + Some(EntryItem(_, i)) => { match i.node { ItemForeignMod(ref nm) => Some(nm.abi), _ => None @@ -650,15 +665,15 @@ impl<'a, 'ast> Iterator for NodesMatchingSuffix<'a, 'ast> { return None; } self.idx += 1; - let (p, name) = match self.map.find_entry(idx) { - Some(EntryItem(p, _, n)) => (p, n.name()), - Some(EntryForeignItem(p, _, n))=> (p, n.name()), - Some(EntryTraitItem(p, _, n)) => (p, n.name()), - Some(EntryImplItem(p, _, n)) => (p, n.name()), - Some(EntryVariant(p, _, n)) => (p, n.name()), + let name = match self.map.find_entry(idx) { + Some(EntryItem(_, n)) => n.name(), + Some(EntryForeignItem(_, n))=> n.name(), + Some(EntryTraitItem(_, n)) => n.name(), + Some(EntryImplItem(_, n)) => n.name(), + Some(EntryVariant(_, n)) => n.name(), _ => continue, }; - if self.matches_names(p, name) { + if self.matches_names(self.map.get_parent(idx), name) { return Some(idx) } } @@ -707,8 +722,6 @@ impl Folder for IdAndSpanUpdater { /// A Visitor that walks over an AST and collects Node's into an AST Map. struct NodeCollector<'ast> { map: Vec>, - /// The node in which we are currently mapping (an item or a method). - parent: NodeId, parent_node: NodeId, } @@ -723,7 +736,7 @@ impl<'ast> NodeCollector<'ast> { } fn insert(&mut self, id: NodeId, node: Node<'ast>) { - let entry = MapEntry::from_node(self.parent, self.parent_node, node); + let entry = MapEntry::from_node(self.parent_node, node); self.insert_entry(id, entry); } @@ -737,10 +750,10 @@ impl<'ast> NodeCollector<'ast> { impl<'ast> Visitor<'ast> for NodeCollector<'ast> { fn visit_item(&mut self, i: &'ast Item) { self.insert(i.id, NodeItem(i)); - let parent = self.parent; - self.parent = i.id; + let parent_node = self.parent_node; self.parent_node = i.id; + match i.node { ItemImpl(_, _, _, _, _, ref impl_items) => { for ii in impl_items { @@ -790,55 +803,51 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { _ => {} } visit::walk_item(self, i); - self.parent = parent; self.parent_node = parent_node; } fn visit_trait_item(&mut self, ti: &'ast TraitItem) { - let parent = self.parent; - self.parent = ti.id; let parent_node = self.parent_node; self.parent_node = ti.id; visit::walk_trait_item(self, ti); - self.parent = parent; self.parent_node = parent_node; } fn visit_impl_item(&mut self, ii: &'ast ImplItem) { - let parent = self.parent; - self.parent = ii.id; let parent_node = self.parent_node; self.parent_node = ii.id; + visit::walk_impl_item(self, ii); - self.parent = parent; + self.parent_node = parent_node; } fn visit_pat(&mut self, pat: &'ast Pat) { - let parent_node = self.parent_node; - self.parent_node = pat.id; self.insert(pat.id, match pat.node { // Note: this is at least *potentially* a pattern... PatIdent(..) => NodeLocal(pat), _ => NodePat(pat) }); + + let parent_node = self.parent_node; + self.parent_node = pat.id; visit::walk_pat(self, pat); self.parent_node = parent_node; } fn visit_expr(&mut self, expr: &'ast Expr) { + self.insert(expr.id, NodeExpr(expr)); let parent_node = self.parent_node; self.parent_node = expr.id; - self.insert(expr.id, NodeExpr(expr)); visit::walk_expr(self, expr); self.parent_node = parent_node; } fn visit_stmt(&mut self, stmt: &'ast Stmt) { let id = ast_util::stmt_id(stmt); + self.insert(id, NodeStmt(stmt)); let parent_node = self.parent_node; self.parent_node = id; - self.insert(id, NodeStmt(stmt)); visit::walk_stmt(self, stmt); self.parent_node = parent_node; } @@ -866,18 +875,15 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { } fn visit_block(&mut self, block: &'ast Block) { + self.insert(block.id, NodeBlock(block)); let parent_node = self.parent_node; self.parent_node = block.id; - self.insert(block.id, NodeBlock(block)); visit::walk_block(self, block); self.parent_node = parent_node; } fn visit_lifetime_ref(&mut self, lifetime: &'ast Lifetime) { - let parent_node = self.parent_node; - self.parent_node = lifetime.id; self.insert(lifetime.id, NodeLifetime(lifetime)); - self.parent_node = parent_node; } fn visit_lifetime_def(&mut self, def: &'ast LifetimeDef) { @@ -901,7 +907,6 @@ pub fn map_crate<'ast, F: FoldOps>(forest: &'ast mut Forest, fold_ops: F) -> Map let mut collector = NodeCollector { map: vec![], - parent: CRATE_NODE_ID, parent_node: CRATE_NODE_ID, }; collector.insert_entry(CRATE_NODE_ID, RootCrate); @@ -957,12 +962,11 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>, ii: ii }); + let ii_parent_id = fld.new_id(DUMMY_NODE_ID); let mut collector = NodeCollector { map: mem::replace(&mut *map.map.borrow_mut(), vec![]), - parent: fld.new_id(DUMMY_NODE_ID), - parent_node: fld.new_id(DUMMY_NODE_ID), + parent_node: ii_parent_id, }; - let ii_parent_id = collector.parent; collector.insert_entry(ii_parent_id, RootInlinedParent(ii_parent)); visit::walk_inlined_item(&mut collector, &ii_parent.ii); diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index e9c91f4f4c19..9d66e99df305 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -172,7 +172,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { qualname: qualname, declaration: None, span: sub_span.unwrap(), - scope: self.tcx.map.get_enclosing_scope(item.id).unwrap(), + scope: self.tcx.map.get_enclosing_scope(item.id).unwrap_or(0), }) } ast::ItemStatic(ref typ, mt, ref expr) => { @@ -191,7 +191,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { name: get_ident(item.ident).to_string(), qualname: qualname, span: sub_span.unwrap(), - scope: self.tcx.map.get_enclosing_scope(item.id).unwrap(), + scope: self.tcx.map.get_enclosing_scope(item.id).unwrap_or(0), value: value, type_value: ty_to_string(&typ), }) @@ -205,7 +205,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { name: get_ident(item.ident).to_string(), qualname: qualname, span: sub_span.unwrap(), - scope: self.tcx.map.get_enclosing_scope(item.id).unwrap(), + scope: self.tcx.map.get_enclosing_scope(item.id).unwrap_or(0), value: self.span_utils.snippet(expr.span), type_value: ty_to_string(&typ), }) @@ -223,7 +223,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { name: get_ident(item.ident).to_string(), qualname: qualname, span: sub_span.unwrap(), - scope: self.tcx.map.get_enclosing_scope(item.id).unwrap(), + scope: self.tcx.map.get_enclosing_scope(item.id).unwrap_or(0), filename: filename, }) }, @@ -237,14 +237,14 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { value: val, span: sub_span.unwrap(), qualname: enum_name, - scope: self.tcx.map.get_enclosing_scope(item.id).unwrap(), + scope: self.tcx.map.get_enclosing_scope(item.id).unwrap_or(0), }) }, ast::ItemImpl(_, _, _, ref trait_ref, ref typ, _) => { let mut type_data = None; let sub_span; - let parent = self.tcx.map.get_enclosing_scope(item.id).unwrap(); + let parent = self.tcx.map.get_enclosing_scope(item.id).unwrap_or(0); match typ.node { // Common case impl for a struct or something basic. @@ -337,7 +337,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { return Some(Data::VariableRefData(VariableRefData { name: get_ident(ident.node).to_string(), span: sub_span.unwrap(), - scope: self.tcx.map.get_enclosing_scope(expr.id).unwrap(), + scope: self.tcx.map.get_enclosing_scope(expr.id).unwrap_or(0), ref_id: f.id, })); } @@ -360,7 +360,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let sub_span = self.span_utils.span_for_last_ident(path.span); Some(Data::TypeRefData(TypeRefData { span: sub_span.unwrap(), - scope: self.tcx.map.get_enclosing_scope(expr.id).unwrap(), + scope: self.tcx.map.get_enclosing_scope(expr.id).unwrap_or(0), ref_id: def_id, })) } From 8261599e62a7930cec372e637e5ab58f5a26532c Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 1 Jul 2015 08:58:48 +1200 Subject: [PATCH 4/4] Refactoring --- src/librustc/ast_map/mod.rs | 159 ++++++++++++++++++------------------ 1 file changed, 81 insertions(+), 78 deletions(-) diff --git a/src/librustc/ast_map/mod.rs b/src/librustc/ast_map/mod.rs index 800cd7e8aeea..3205141e604c 100644 --- a/src/librustc/ast_map/mod.rs +++ b/src/librustc/ast_map/mod.rs @@ -121,15 +121,14 @@ pub enum Node<'ast> { NodeLifetime(&'ast Lifetime), } -/// Represents an entry and its parent NodeID and parent_node NodeID, see -/// get_parent_node for the distinction. +/// Represents an entry and its parent NodeID. /// The odd layout is to bring down the total size. #[derive(Copy, Debug)] enum MapEntry<'ast> { /// Placeholder for holes in the map. NotPresent, - /// All the node types, with a parent and scope ID. + /// All the node types, with a parent ID. EntryItem(NodeId, &'ast Item), EntryForeignItem(NodeId, &'ast ForeignItem), EntryTraitItem(NodeId, &'ast TraitItem), @@ -162,21 +161,21 @@ struct InlinedParent { } impl<'ast> MapEntry<'ast> { - fn from_node(s: NodeId, node: Node<'ast>) -> MapEntry<'ast> { + fn from_node(p: NodeId, node: Node<'ast>) -> MapEntry<'ast> { match node { - NodeItem(n) => EntryItem(s, n), - NodeForeignItem(n) => EntryForeignItem(s, n), - NodeTraitItem(n) => EntryTraitItem(s, n), - NodeImplItem(n) => EntryImplItem(s, n), - NodeVariant(n) => EntryVariant(s, n), - NodeExpr(n) => EntryExpr(s, n), - NodeStmt(n) => EntryStmt(s, n), - NodeArg(n) => EntryArg(s, n), - NodeLocal(n) => EntryLocal(s, n), - NodePat(n) => EntryPat(s, n), - NodeBlock(n) => EntryBlock(s, n), - NodeStructCtor(n) => EntryStructCtor(s, n), - NodeLifetime(n) => EntryLifetime(s, n) + NodeItem(n) => EntryItem(p, n), + NodeForeignItem(n) => EntryForeignItem(p, n), + NodeTraitItem(n) => EntryTraitItem(p, n), + NodeImplItem(n) => EntryImplItem(p, n), + NodeVariant(n) => EntryVariant(p, n), + NodeExpr(n) => EntryExpr(p, n), + NodeStmt(n) => EntryStmt(p, n), + NodeArg(n) => EntryArg(p, n), + NodeLocal(n) => EntryLocal(p, n), + NodePat(n) => EntryPat(p, n), + NodeBlock(n) => EntryBlock(p, n), + NodeStructCtor(n) => EntryStructCtor(p, n), + NodeLifetime(n) => EntryLifetime(p, n) } } @@ -284,45 +283,9 @@ impl<'ast> Map<'ast> { self.find_entry(id).and_then(|x| x.to_node()) } - /// Retrieve the parent NodeId for `id`, or `id` itself if no - /// parent is registered in this map. - pub fn get_parent(&self, id: NodeId) -> NodeId { - let mut id = id; - loop { - let parent_node = self.get_parent_node(id); - if parent_node == 0 { - return parent_node; - } - if parent_node == id { - return id; - } - - let node = self.find_entry(parent_node); - if node.is_none() { - return id; - } - let node = node.unwrap().to_node(); - match node { - Some(node) => match node { - NodeItem(_) | - NodeForeignItem(_) | - NodeTraitItem(_) | - NodeImplItem(_) => { - return parent_node; - } - _ => {} - }, - None => { - return parent_node; - } - } - id = parent_node; - } - } - /// Similar to get_parent, returns the parent node id or id if there is no /// parent. - /// This function returns the most direct parent in the AST, whereas get_parent + /// This function returns the immediate parent in the AST, whereas get_parent /// returns the enclosing item. Note that this might not be the actual parent /// node in the AST - some kinds of nodes are not in the map and these will /// never appear as the parent_node. So you can always walk the parent_nodes @@ -332,35 +295,75 @@ impl<'ast> Map<'ast> { self.find_entry(id).and_then(|x| x.parent_node()).unwrap_or(id) } + /// If there is some error when walking the parents (e.g., a node does not + /// have a parent in the map or a node can't be found), then we return the + /// last good node id we found. Note that reaching the crate root (id == 0), + /// is not an error, since items in the crate module have the crate root as + /// parent. + fn walk_parent_nodes(&self, start_id: NodeId, found: F) -> Result + where F: Fn(&Node<'ast>) -> bool + { + let mut id = start_id; + loop { + let parent_node = self.get_parent_node(id); + if parent_node == 0 { + return Ok(0); + } + if parent_node == id { + return Err(id); + } + + let node = self.find_entry(parent_node); + if node.is_none() { + return Err(id); + } + let node = node.unwrap().to_node(); + match node { + Some(ref node) => { + if found(node) { + return Ok(parent_node); + } + } + None => { + return Err(parent_node); + } + } + id = parent_node; + } + } + + /// Retrieve the NodeId for `id`'s parent item, or `id` itself if no + /// parent item is in this map. The "parent item" is the closest parent node + /// in the AST which is recorded by the map and is an item, either an item + /// in a module, trait, or impl. + pub fn get_parent(&self, id: NodeId) -> NodeId { + match self.walk_parent_nodes(id, |node| match *node { + NodeItem(_) | + NodeForeignItem(_) | + NodeTraitItem(_) | + NodeImplItem(_) => true, + _ => false, + }) { + Ok(id) => id, + Err(id) => id, + } + } + /// Returns the nearest enclosing scope. A scope is an item or block. /// FIXME it is not clear to me that all items qualify as scopes - statics /// and associated types probably shouldn't, for example. Behaviour in this /// regard should be expected to be highly unstable. pub fn get_enclosing_scope(&self, id: NodeId) -> Option { - let mut last_id = id; - // Walk up the chain of parents until we find a 'scope'. - loop { - let cur_id = self.get_parent_node(last_id); - if cur_id == last_id { - return None; - } - - if cur_id == 0 { - return Some(0); - } - - match self.get(cur_id) { - NodeItem(_) | - NodeForeignItem(_) | - NodeTraitItem(_) | - NodeImplItem(_) | - NodeBlock(_) => { - return Some(cur_id); - } - _ => {} - } - - last_id = cur_id; + match self.walk_parent_nodes(id, |node| match *node { + NodeItem(_) | + NodeForeignItem(_) | + NodeTraitItem(_) | + NodeImplItem(_) | + NodeBlock(_) => true, + _ => false, + }) { + Ok(id) => Some(id), + Err(_) => None, } }