From 744be0b5aac8c06c60dabac3a7802a8117c946b2 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Thu, 14 Apr 2016 18:04:55 +1200 Subject: [PATCH] HIR visitor for DefCollector So that we can work with inlined HIR from metadata. --- src/librustc/hir/map/def_collector.rs | 174 +++++++++++++++++++++++++- src/librustc/hir/map/mod.rs | 15 ++- 2 files changed, 175 insertions(+), 14 deletions(-) diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index 9d6027932f6..f8d0243548f 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -10,20 +10,28 @@ use super::*; +use hir; +use hir::intravisit; use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex}; +use middle::cstore::InlinedItem; + use syntax::ast::*; use syntax::visit; /// Creates def ids for nodes in the HIR. -pub struct DefCollector { +pub struct DefCollector<'ast> { + // If we are walking HIR (c.f., AST), we need to keep a reference to the + // crate. + hir_crate: Option<&'ast hir::Crate>, pub definitions: Definitions, - pub parent_def: Option, + parent_def: Option, } -impl DefCollector { - pub fn root() -> DefCollector { +impl<'ast> DefCollector<'ast> { + pub fn root() -> DefCollector<'ast> { let mut collector = DefCollector { + hir_crate: None, definitions: Definitions::new(), parent_def: None, }; @@ -39,8 +47,9 @@ impl DefCollector { parent_def_path: DefPath, parent_def_id: DefId, definitions: Definitions) - -> DefCollector { + -> DefCollector<'ast> { let mut collector = DefCollector { + hir_crate: None, parent_def: None, definitions: definitions, }; @@ -57,6 +66,11 @@ impl DefCollector { collector } + pub fn walk_item(&mut self, ii: &'ast InlinedItem, krate: &'ast hir::Crate) { + self.hir_crate = Some(krate); + ii.visit(self); + } + fn parent_def(&self) -> Option { self.parent_def } @@ -83,7 +97,7 @@ impl DefCollector { } } -impl<'ast> visit::Visitor<'ast> for DefCollector { +impl<'ast> visit::Visitor<'ast> for DefCollector<'ast> { fn visit_item(&mut self, i: &'ast Item) { debug!("visit_item: {:?}", i); @@ -226,3 +240,151 @@ impl<'ast> visit::Visitor<'ast> for DefCollector { self.create_def(macro_def.id, DefPathData::MacroDef(macro_def.ident.name)); } } + +// We walk the HIR rather than the AST when reading items from metadata. +impl<'ast> intravisit::Visitor<'ast> for DefCollector<'ast> { + /// Because we want to track parent items and so forth, enable + /// deep walking so that we walk nested items in the context of + /// their outer items. + fn visit_nested_item(&mut self, item_id: hir::ItemId) { + debug!("visit_nested_item: {:?}", item_id); + let item = self.hir_crate.unwrap().item(item_id.id); + self.visit_item(item) + } + + fn visit_item(&mut self, i: &'ast hir::Item) { + debug!("visit_item: {:?}", i); + + // Pick the def data. This need not be unique, but the more + // information we encapsulate into + let def_data = match i.node { + hir::ItemDefaultImpl(..) | hir::ItemImpl(..) => + DefPathData::Impl, + hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemTrait(..) | + hir::ItemExternCrate(..) | hir::ItemMod(..) | hir::ItemForeignMod(..) | + hir::ItemTy(..) => + DefPathData::TypeNs(i.name), + hir::ItemStatic(..) | hir::ItemConst(..) | hir::ItemFn(..) => + DefPathData::ValueNs(i.name), + hir::ItemUse(..) => DefPathData::Misc, + }; + let def = self.create_def(i.id, def_data); + + self.with_parent(def, |this| { + match i.node { + hir::ItemEnum(ref enum_definition, _) => { + for v in &enum_definition.variants { + let variant_def_index = + this.create_def(v.node.data.id(), + DefPathData::EnumVariant(v.node.name)); + + for field in v.node.data.fields() { + this.create_def_with_parent(Some(variant_def_index), + field.id, + DefPathData::Field(field.name)); + } + } + } + hir::ItemStruct(ref struct_def, _) => { + // If this is a tuple-like struct, register the constructor. + if !struct_def.is_struct() { + this.create_def(struct_def.id(), + DefPathData::StructCtor); + } + + for field in struct_def.fields() { + this.create_def(field.id, DefPathData::Field(field.name)); + } + } + _ => {} + } + intravisit::walk_item(this, i); + }); + } + + fn visit_foreign_item(&mut self, foreign_item: &'ast hir::ForeignItem) { + let def = self.create_def(foreign_item.id, DefPathData::ValueNs(foreign_item.name)); + + self.with_parent(def, |this| { + intravisit::walk_foreign_item(this, foreign_item); + }); + } + + fn visit_generics(&mut self, generics: &'ast hir::Generics) { + for ty_param in generics.ty_params.iter() { + self.create_def(ty_param.id, DefPathData::TypeParam(ty_param.name)); + } + + intravisit::walk_generics(self, generics); + } + + fn visit_trait_item(&mut self, ti: &'ast hir::TraitItem) { + let def_data = match ti.node { + hir::MethodTraitItem(..) | hir::ConstTraitItem(..) => + DefPathData::ValueNs(ti.name), + hir::TypeTraitItem(..) => DefPathData::TypeNs(ti.name), + }; + + let def = self.create_def(ti.id, def_data); + self.with_parent(def, |this| { + if let hir::ConstTraitItem(_, Some(ref expr)) = ti.node { + this.create_def(expr.id, DefPathData::Initializer); + } + + intravisit::walk_trait_item(this, ti); + }); + } + + fn visit_impl_item(&mut self, ii: &'ast hir::ImplItem) { + let def_data = match ii.node { + hir::ImplItemKind::Method(..) | hir::ImplItemKind::Const(..) => + DefPathData::ValueNs(ii.name), + hir::ImplItemKind::Type(..) => DefPathData::TypeNs(ii.name), + }; + + let def = self.create_def(ii.id, def_data); + self.with_parent(def, |this| { + if let hir::ImplItemKind::Const(_, ref expr) = ii.node { + this.create_def(expr.id, DefPathData::Initializer); + } + + intravisit::walk_impl_item(this, ii); + }); + } + + fn visit_pat(&mut self, pat: &'ast hir::Pat) { + let maybe_binding = match pat.node { + hir::PatKind::Ident(_, id, _) => Some(id.node), + _ => None + }; + + let parent_def = self.parent_def; + if let Some(id) = maybe_binding { + let def = self.create_def(pat.id, DefPathData::Binding(id.name)); + self.parent_def = Some(def); + } + + intravisit::walk_pat(self, pat); + self.parent_def = parent_def; + } + + fn visit_expr(&mut self, expr: &'ast hir::Expr) { + let parent_def = self.parent_def; + + if let hir::ExprClosure(..) = expr.node { + let def = self.create_def(expr.id, DefPathData::ClosureExpr); + self.parent_def = Some(def); + } + + intravisit::walk_expr(self, expr); + self.parent_def = parent_def; + } + + fn visit_lifetime_def(&mut self, def: &'ast hir::LifetimeDef) { + self.create_def(def.lifetime.id, DefPathData::LifetimeDef(def.lifetime.name)); + } + + fn visit_macro_def(&mut self, macro_def: &'ast hir::MacroDef) { + self.create_def(macro_def.id, DefPathData::MacroDef(macro_def.name)); + } +} \ No newline at end of file diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index a505ad19889..1d0c40646b5 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -843,14 +843,13 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>, let ii = map.forest.inlined_items.alloc(ii); let ii_parent_id = fld.new_id(DUMMY_NODE_ID); - // TODO need to save defs in metadata :-( - // let defs = mem::replace(&mut *map.definitions.borrow_mut(), Definitions::new()); - // let mut def_collector = DefCollector::extend(ii_parent_id, - // parent_def_path.clone(), - // parent_def_id, - // defs); - // ii.visit(&mut def_collector); - // *map.definitions.borrow_mut() = def_collector.definitions; + let defs = mem::replace(&mut *map.definitions.borrow_mut(), Definitions::new()); + let mut def_collector = DefCollector::extend(ii_parent_id, + parent_def_path.clone(), + parent_def_id, + defs); + def_collector.walk_item(ii, map.krate()); + *map.definitions.borrow_mut() = def_collector.definitions; let mut collector = NodeCollector::extend(map.krate(), ii,