diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 7c476657041..0a01cc91f0e 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -62,6 +62,9 @@ // in the HIR, especially for multiple identifiers. use hir; +use hir::map::Definitions; +use hir::map::definitions::DefPathData; +use hir::def_id::DefIndex; use std::collections::BTreeMap; use std::collections::HashMap; @@ -92,10 +95,20 @@ pub struct LoweringContext<'a> { // A copy of cached_id, but is also set to an id while a node is lowered for // the first time. gensym_key: Cell, + // We must keep the set of definitions up to date as we add nodes that + // weren't in the AST. + definitions: Option<&'a RefCell>, + // As we walk the AST we must keep track of the current 'parent' def id (in + // the form of a DefIndex) so that if we create a new node which introduces + // a definition, then we can properly create the def id. + parent_def: Cell>, } impl<'a, 'hir> LoweringContext<'a> { - pub fn new(id_assigner: &'a NodeIdAssigner, c: Option<&Crate>) -> LoweringContext<'a> { + pub fn new(id_assigner: &'a NodeIdAssigner, + c: Option<&Crate>, + defs: &'a RefCell) + -> LoweringContext<'a> { let crate_root = c.and_then(|c| { if std_inject::no_core(c) { None @@ -113,6 +126,23 @@ impl<'a, 'hir> LoweringContext<'a> { cached_id: Cell::new(0), gensym_cache: RefCell::new(HashMap::new()), gensym_key: Cell::new(0), + definitions: Some(defs), + parent_def: Cell::new(None), + } + } + + // Only use this when you want a LoweringContext for testing and won't look + // up def ids for anything created during lowering. + pub fn testing_context(id_assigner: &'a NodeIdAssigner) -> LoweringContext<'a> { + LoweringContext { + crate_root: None, + id_cache: RefCell::new(HashMap::new()), + id_assigner: id_assigner, + cached_id: Cell::new(0), + gensym_cache: RefCell::new(HashMap::new()), + gensym_key: Cell::new(0), + definitions: None, + parent_def: Cell::new(None), } } @@ -146,6 +176,25 @@ impl<'a, 'hir> LoweringContext<'a> { fn diagnostic(&self) -> &Handler { self.id_assigner.diagnostic() } + + fn with_parent_def T>(&self, parent_id: NodeId, f: F) -> T { + if self.definitions.is_none() { + // This should only be used for testing. + return f(); + } + + let old_def = self.parent_def.get(); + self.parent_def.set(Some(self.get_def(parent_id))); + let result = f(); + self.parent_def.set(old_def); + + result + } + + fn get_def(&self, id: NodeId) -> DefIndex { + let defs = self.definitions.unwrap().borrow(); + defs.opt_def_index(id).unwrap() + } } // Utility fn for setting and unsetting the cached id. @@ -733,47 +782,51 @@ pub fn lower_item_kind(lctx: &LoweringContext, i: &ItemKind) -> hir::Item_ { } pub fn lower_trait_item(lctx: &LoweringContext, i: &TraitItem) -> hir::TraitItem { - hir::TraitItem { - id: i.id, - name: i.ident.name, - attrs: lower_attrs(lctx, &i.attrs), - node: match i.node { - TraitItemKind::Const(ref ty, ref default) => { - hir::ConstTraitItem(lower_ty(lctx, ty), - default.as_ref().map(|x| lower_expr(lctx, x))) - } - TraitItemKind::Method(ref sig, ref body) => { - hir::MethodTraitItem(lower_method_sig(lctx, sig), - body.as_ref().map(|x| lower_block(lctx, x))) - } - TraitItemKind::Type(ref bounds, ref default) => { - hir::TypeTraitItem(lower_bounds(lctx, bounds), - default.as_ref().map(|x| lower_ty(lctx, x))) - } - }, - span: i.span, - } + lctx.with_parent_def(i.id, || { + hir::TraitItem { + id: i.id, + name: i.ident.name, + attrs: lower_attrs(lctx, &i.attrs), + node: match i.node { + TraitItemKind::Const(ref ty, ref default) => { + hir::ConstTraitItem(lower_ty(lctx, ty), + default.as_ref().map(|x| lower_expr(lctx, x))) + } + TraitItemKind::Method(ref sig, ref body) => { + hir::MethodTraitItem(lower_method_sig(lctx, sig), + body.as_ref().map(|x| lower_block(lctx, x))) + } + TraitItemKind::Type(ref bounds, ref default) => { + hir::TypeTraitItem(lower_bounds(lctx, bounds), + default.as_ref().map(|x| lower_ty(lctx, x))) + } + }, + span: i.span, + } + }) } pub fn lower_impl_item(lctx: &LoweringContext, i: &ImplItem) -> hir::ImplItem { - hir::ImplItem { - id: i.id, - name: i.ident.name, - attrs: lower_attrs(lctx, &i.attrs), - vis: lower_visibility(lctx, &i.vis), - defaultness: lower_defaultness(lctx, i.defaultness), - node: match i.node { - ImplItemKind::Const(ref ty, ref expr) => { - hir::ImplItemKind::Const(lower_ty(lctx, ty), lower_expr(lctx, expr)) - } - ImplItemKind::Method(ref sig, ref body) => { - hir::ImplItemKind::Method(lower_method_sig(lctx, sig), lower_block(lctx, body)) - } - ImplItemKind::Type(ref ty) => hir::ImplItemKind::Type(lower_ty(lctx, ty)), - ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"), - }, - span: i.span, - } + lctx.with_parent_def(i.id, || { + hir::ImplItem { + id: i.id, + name: i.ident.name, + attrs: lower_attrs(lctx, &i.attrs), + vis: lower_visibility(lctx, &i.vis), + defaultness: lower_defaultness(lctx, i.defaultness), + node: match i.node { + ImplItemKind::Const(ref ty, ref expr) => { + hir::ImplItemKind::Const(lower_ty(lctx, ty), lower_expr(lctx, expr)) + } + ImplItemKind::Method(ref sig, ref body) => { + hir::ImplItemKind::Method(lower_method_sig(lctx, sig), lower_block(lctx, body)) + } + ImplItemKind::Type(ref ty) => hir::ImplItemKind::Type(lower_ty(lctx, ty)), + ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"), + }, + span: i.span, + } + }) } pub fn lower_mod(lctx: &LoweringContext, m: &Mod) -> hir::Mod { @@ -831,7 +884,9 @@ pub fn lower_item_id(_lctx: &LoweringContext, i: &Item) -> hir::ItemId { } pub fn lower_item(lctx: &LoweringContext, i: &Item) -> hir::Item { - let node = lower_item_kind(lctx, &i.node); + let node = lctx.with_parent_def(i.id, || { + lower_item_kind(lctx, &i.node) + }); hir::Item { id: i.id, @@ -844,21 +899,23 @@ pub fn lower_item(lctx: &LoweringContext, i: &Item) -> hir::Item { } pub fn lower_foreign_item(lctx: &LoweringContext, i: &ForeignItem) -> hir::ForeignItem { - hir::ForeignItem { - id: i.id, - name: i.ident.name, - attrs: lower_attrs(lctx, &i.attrs), - node: match i.node { - ForeignItemKind::Fn(ref fdec, ref generics) => { - hir::ForeignItemFn(lower_fn_decl(lctx, fdec), lower_generics(lctx, generics)) - } - ForeignItemKind::Static(ref t, m) => { - hir::ForeignItemStatic(lower_ty(lctx, t), m) - } - }, - vis: lower_visibility(lctx, &i.vis), - span: i.span, - } + lctx.with_parent_def(i.id, || { + hir::ForeignItem { + id: i.id, + name: i.ident.name, + attrs: lower_attrs(lctx, &i.attrs), + node: match i.node { + ForeignItemKind::Fn(ref fdec, ref generics) => { + hir::ForeignItemFn(lower_fn_decl(lctx, fdec), lower_generics(lctx, generics)) + } + ForeignItemKind::Static(ref t, m) => { + hir::ForeignItemStatic(lower_ty(lctx, t), m) + } + }, + vis: lower_visibility(lctx, &i.vis), + span: i.span, + } + }) } pub fn lower_method_sig(lctx: &LoweringContext, sig: &MethodSig) -> hir::MethodSig { @@ -926,9 +983,11 @@ pub fn lower_pat(lctx: &LoweringContext, p: &Pat) -> P { node: match p.node { PatKind::Wild => hir::PatKind::Wild, PatKind::Ident(ref binding_mode, pth1, ref sub) => { - hir::PatKind::Ident(lower_binding_mode(lctx, binding_mode), - respan(pth1.span, lower_ident(lctx, pth1.node)), - sub.as_ref().map(|x| lower_pat(lctx, x))) + lctx.with_parent_def(p.id, || { + hir::PatKind::Ident(lower_binding_mode(lctx, binding_mode), + respan(pth1.span, lower_ident(lctx, pth1.node)), + sub.as_ref().map(|x| lower_pat(lctx, x))) + }) } PatKind::Lit(ref e) => hir::PatKind::Lit(lower_expr(lctx, e)), PatKind::TupleStruct(ref pth, ref pats) => { @@ -1202,9 +1261,11 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P { hir::MatchSource::Normal) } ExprKind::Closure(capture_clause, ref decl, ref body) => { - hir::ExprClosure(lower_capture_clause(lctx, capture_clause), - lower_fn_decl(lctx, decl), - lower_block(lctx, body)) + lctx.with_parent_def(e.id, || { + hir::ExprClosure(lower_capture_clause(lctx, capture_clause), + lower_fn_decl(lctx, decl), + lower_block(lctx, body)) + }) } ExprKind::Block(ref blk) => hir::ExprBlock(lower_block(lctx, blk)), ExprKind::Assign(ref el, ref er) => { @@ -1602,7 +1663,12 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P { // `{ let _result = ...; _result }` // underscore prevents an unused_variables lint if the head diverges let result_ident = lctx.str_to_ident("_result"); - let let_stmt = stmt_let(lctx, e.span, false, result_ident, match_expr, None); + let let_stmt = stmt_let(lctx, + e.span, + false, + result_ident, + match_expr, + None); let result = expr_ident(lctx, e.span, result_ident, None); let block = block_all(lctx, e.span, hir_vec![let_stmt], Some(result)); // add the attributes to the outer returned expr node @@ -1655,7 +1721,8 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P { let err_ctor = expr_path(lctx, path, None); expr_call(lctx, e.span, err_ctor, hir_vec![from_expr], None) }; - let err_pat = pat_err(lctx, e.span, pat_ident(lctx, e.span, err_ident)); + let err_pat = pat_err(lctx, e.span, + pat_ident(lctx, e.span, err_ident)); let ret_expr = expr(lctx, e.span, hir::Expr_::ExprRet(Some(err_expr)), None); @@ -1938,12 +2005,22 @@ fn pat_ident_binding_mode(lctx: &LoweringContext, bm: hir::BindingMode) -> P { let pat_ident = hir::PatKind::Ident(bm, - Spanned { - span: span, - node: ident, - }, - None); - pat(lctx, span, pat_ident) + Spanned { + span: span, + node: ident, + }, + None); + + let pat = pat(lctx, span, pat_ident); + + if let Some(defs) = lctx.definitions { + let mut defs = defs.borrow_mut(); + defs.create_def_with_parent(lctx.parent_def.get(), + pat.id, + DefPathData::Binding(ident.name)); + } + + pat } fn pat_wild(lctx: &LoweringContext, span: Span) -> P { @@ -2130,7 +2207,8 @@ mod test { let ast_in = quote_expr!(&cx, in HEAP { foo() }); let ast_in = assigner.fold_expr(ast_in); - let lctx = LoweringContext::new(&assigner, None); + let lctx = LoweringContext::testing_context(&assigner); + let hir1 = lower_expr(&lctx, &ast_if_let); let hir2 = lower_expr(&lctx, &ast_if_let); assert!(hir1 == hir2); diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index 95f9e8eaac2..9f55f46541c 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// Copyright 2015-2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -13,18 +13,16 @@ use super::MapEntry::*; use hir::*; use hir::intravisit::Visitor; -use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex}; +use hir::def_id::DefId; use middle::cstore::InlinedItem; use std::iter::repeat; -use syntax::ast::{NodeId, CRATE_NODE_ID, DUMMY_NODE_ID}; +use syntax::ast::{NodeId, CRATE_NODE_ID}; use syntax::codemap::Span; -/// A Visitor that walks over an AST and collects Node's into an AST -/// Map. +/// A Visitor that walks over the HIR and collects Node's into a HIR map. pub struct NodeCollector<'ast> { pub krate: &'ast Crate, pub map: Vec>, - pub definitions: Definitions, pub parent_node: NodeId, } @@ -33,16 +31,10 @@ impl<'ast> NodeCollector<'ast> { let mut collector = NodeCollector { krate: krate, map: vec![], - definitions: Definitions::new(), parent_node: CRATE_NODE_ID, }; collector.insert_entry(CRATE_NODE_ID, RootCrate); - let result = collector.create_def_with_parent(None, CRATE_NODE_ID, DefPathData::CrateRoot); - assert_eq!(result, CRATE_DEF_INDEX); - - collector.create_def_with_parent(Some(CRATE_DEF_INDEX), DUMMY_NODE_ID, DefPathData::Misc); - collector } @@ -51,53 +43,20 @@ impl<'ast> NodeCollector<'ast> { parent_node: NodeId, parent_def_path: DefPath, parent_def_id: DefId, - map: Vec>, - definitions: Definitions) + map: Vec>) -> NodeCollector<'ast> { let mut collector = NodeCollector { krate: krate, map: map, parent_node: parent_node, - definitions: definitions, }; assert_eq!(parent_def_path.krate, parent_def_id.krate); - let root_path = Box::new(InlinedRootPath { - data: parent_def_path.data, - def_id: parent_def_id, - }); - collector.insert_entry(parent_node, RootInlinedParent(parent)); - collector.create_def(parent_node, DefPathData::InlinedRoot(root_path)); collector } - fn parent_def(&self) -> Option { - let mut parent_node = Some(self.parent_node); - while let Some(p) = parent_node { - if let Some(q) = self.definitions.opt_def_index(p) { - return Some(q); - } - parent_node = self.map[p as usize].parent_node(); - } - None - } - - fn create_def(&mut self, node_id: NodeId, data: DefPathData) -> DefIndex { - let parent_def = self.parent_def(); - debug!("create_def(node_id={:?}, data={:?}, parent_def={:?})", node_id, data, parent_def); - self.definitions.create_def_with_parent(parent_def, node_id, data) - } - - fn create_def_with_parent(&mut self, - parent: Option, - node_id: NodeId, - data: DefPathData) - -> DefIndex { - self.definitions.create_def_with_parent(parent, node_id, data) - } - fn insert_entry(&mut self, id: NodeId, entry: MapEntry<'ast>) { debug!("ast_map: {:?} => {:?}", id, entry); let len = self.map.len(); @@ -107,15 +66,17 @@ impl<'ast> NodeCollector<'ast> { self.map[id as usize] = entry; } - fn insert_def(&mut self, id: NodeId, node: Node<'ast>, data: DefPathData) -> DefIndex { - self.insert(id, node); - self.create_def(id, data) - } - fn insert(&mut self, id: NodeId, node: Node<'ast>) { let entry = MapEntry::from_node(self.parent_node, node); self.insert_entry(id, entry); } + + fn with_parent(&mut self, parent_id: NodeId, f: F) { + let parent_node = self.parent_node; + self.parent_node = parent_id; + f(self); + self.parent_node = parent_node; + } } impl<'ast> Visitor<'ast> for NodeCollector<'ast> { @@ -130,188 +91,104 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { fn visit_item(&mut self, i: &'ast 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 { - ItemDefaultImpl(..) | ItemImpl(..) => - DefPathData::Impl, - ItemEnum(..) | ItemStruct(..) | ItemTrait(..) | - ItemExternCrate(..) | ItemForeignMod(..) | ItemTy(..) => - DefPathData::TypeNs(i.name), - ItemMod(..) => - DefPathData::Module(i.name), - ItemStatic(..) | ItemConst(..) | ItemFn(..) => - DefPathData::ValueNs(i.name), - ItemUse(..) => - DefPathData::Misc, - }; + self.insert(i.id, NodeItem(i)); - self.insert_def(i.id, NodeItem(i), def_data); - - let parent_node = self.parent_node; - self.parent_node = i.id; - - match i.node { - ItemImpl(..) => {} - ItemEnum(ref enum_definition, _) => { - for v in &enum_definition.variants { - let variant_def_index = - self.insert_def(v.node.data.id(), - NodeVariant(v), - DefPathData::EnumVariant(v.node.name)); - - for field in v.node.data.fields() { - self.create_def_with_parent( - Some(variant_def_index), - field.id, - DefPathData::Field(field.name)); + self.with_parent(i.id, |this| { + match i.node { + ItemEnum(ref enum_definition, _) => { + for v in &enum_definition.variants { + this.insert(v.node.data.id(), NodeVariant(v)); } } - } - ItemForeignMod(..) => { - } - ItemStruct(ref struct_def, _) => { - // If this is a tuple-like struct, register the constructor. - if !struct_def.is_struct() { - self.insert_def(struct_def.id(), - NodeStructCtor(struct_def), - DefPathData::StructCtor); - } - - for field in struct_def.fields() { - self.create_def(field.id, DefPathData::Field(field.name)); - } - } - ItemTrait(_, _, ref bounds, _) => { - for b in bounds.iter() { - if let TraitTyParamBound(ref t, TraitBoundModifier::None) = *b { - self.insert(t.trait_ref.ref_id, NodeItem(i)); + ItemStruct(ref struct_def, _) => { + // If this is a tuple-like struct, register the constructor. + if !struct_def.is_struct() { + this.insert(struct_def.id(), NodeStructCtor(struct_def)); } } - } - ItemUse(ref view_path) => { - match view_path.node { - ViewPathList(_, ref paths) => { - for path in paths { - self.insert(path.node.id(), NodeItem(i)); + ItemTrait(_, _, ref bounds, _) => { + for b in bounds.iter() { + if let TraitTyParamBound(ref t, TraitBoundModifier::None) = *b { + this.insert(t.trait_ref.ref_id, NodeItem(i)); } } - _ => () } + ItemUse(ref view_path) => { + match view_path.node { + ViewPathList(_, ref paths) => { + for path in paths { + this.insert(path.node.id(), NodeItem(i)); + } + } + _ => () + } + } + _ => {} } - _ => {} - } - intravisit::walk_item(self, i); - self.parent_node = parent_node; + intravisit::walk_item(this, i); + }); } fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) { - self.insert_def(foreign_item.id, - NodeForeignItem(foreign_item), - DefPathData::ValueNs(foreign_item.name)); + self.insert(foreign_item.id, NodeForeignItem(foreign_item)); - let parent_node = self.parent_node; - self.parent_node = foreign_item.id; - intravisit::walk_foreign_item(self, foreign_item); - self.parent_node = parent_node; + self.with_parent(foreign_item.id, |this| { + intravisit::walk_foreign_item(this, foreign_item); + }); } fn visit_generics(&mut self, generics: &'ast Generics) { for ty_param in generics.ty_params.iter() { - self.insert_def(ty_param.id, - NodeTyParam(ty_param), - DefPathData::TypeParam(ty_param.name)); + self.insert(ty_param.id, NodeTyParam(ty_param)); } intravisit::walk_generics(self, generics); } fn visit_trait_item(&mut self, ti: &'ast TraitItem) { - let def_data = match ti.node { - MethodTraitItem(..) | ConstTraitItem(..) => DefPathData::ValueNs(ti.name), - TypeTraitItem(..) => DefPathData::TypeNs(ti.name), - }; - self.insert(ti.id, NodeTraitItem(ti)); - self.create_def(ti.id, def_data); - let parent_node = self.parent_node; - self.parent_node = ti.id; - - match ti.node { - ConstTraitItem(_, Some(ref expr)) => { - self.create_def(expr.id, DefPathData::Initializer); - } - _ => { } - } - - intravisit::walk_trait_item(self, ti); - - self.parent_node = parent_node; + self.with_parent(ti.id, |this| { + intravisit::walk_trait_item(this, ti); + }); } fn visit_impl_item(&mut self, ii: &'ast ImplItem) { - let def_data = match ii.node { - ImplItemKind::Method(..) | ImplItemKind::Const(..) => DefPathData::ValueNs(ii.name), - ImplItemKind::Type(..) => DefPathData::TypeNs(ii.name), - }; + self.insert(ii.id, NodeImplItem(ii)); - self.insert_def(ii.id, NodeImplItem(ii), def_data); - - let parent_node = self.parent_node; - self.parent_node = ii.id; - - match ii.node { - ImplItemKind::Const(_, ref expr) => { - self.create_def(expr.id, DefPathData::Initializer); - } - _ => { } - } - - intravisit::walk_impl_item(self, ii); - - self.parent_node = parent_node; + self.with_parent(ii.id, |this| { + intravisit::walk_impl_item(this, ii); + }); } fn visit_pat(&mut self, pat: &'ast Pat) { - let maybe_binding = match pat.node { - PatKind::Ident(_, id, _) => Some(id.node), - _ => None - }; - - if let Some(id) = maybe_binding { - self.insert_def(pat.id, NodeLocal(pat), DefPathData::Binding(id.name)); + let node = if let PatKind::Ident(..) = pat.node { + NodeLocal(pat) } else { - self.insert(pat.id, NodePat(pat)); - } + NodePat(pat) + }; + self.insert(pat.id, node); - let parent_node = self.parent_node; - self.parent_node = pat.id; - intravisit::walk_pat(self, pat); - self.parent_node = parent_node; + self.with_parent(pat.id, |this| { + intravisit::walk_pat(this, pat); + }); } fn visit_expr(&mut self, expr: &'ast Expr) { self.insert(expr.id, NodeExpr(expr)); - match expr.node { - ExprClosure(..) => { self.create_def(expr.id, DefPathData::ClosureExpr); } - _ => { } - } - - let parent_node = self.parent_node; - self.parent_node = expr.id; - intravisit::walk_expr(self, expr); - self.parent_node = parent_node; + self.with_parent(expr.id, |this| { + intravisit::walk_expr(this, expr); + }); } fn visit_stmt(&mut self, stmt: &'ast Stmt) { let id = stmt.node.id(); self.insert(id, NodeStmt(stmt)); - let parent_node = self.parent_node; - self.parent_node = id; - intravisit::walk_stmt(self, stmt); - self.parent_node = parent_node; + + self.with_parent(id, |this| { + intravisit::walk_stmt(this, stmt); + }); } fn visit_fn(&mut self, fk: intravisit::FnKind<'ast>, fd: &'ast FnDecl, @@ -322,22 +199,12 @@ 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; - intravisit::walk_block(self, block); - self.parent_node = parent_node; + self.with_parent(block.id, |this| { + intravisit::walk_block(this, block); + }); } fn visit_lifetime(&mut self, lifetime: &'ast Lifetime) { self.insert(lifetime.id, NodeLifetime(lifetime)); } - - fn visit_lifetime_def(&mut self, def: &'ast LifetimeDef) { - self.create_def(def.lifetime.id, DefPathData::LifetimeDef(def.lifetime.name)); - self.visit_lifetime(&def.lifetime); - } - - fn visit_macro_def(&mut self, macro_def: &'ast MacroDef) { - self.create_def(macro_def.id, DefPathData::MacroDef(macro_def.name)); - } } diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs new file mode 100644 index 00000000000..053d32305be --- /dev/null +++ b/src/librustc/hir/map/def_collector.rs @@ -0,0 +1,384 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +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; +use syntax::parse::token; + +/// Creates def ids for nodes in the HIR. +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, + parent_def: Option, +} + +impl<'ast> DefCollector<'ast> { + pub fn root() -> DefCollector<'ast> { + let mut collector = DefCollector { + hir_crate: None, + definitions: Definitions::new(), + parent_def: None, + }; + let root = collector.create_def_with_parent(None, CRATE_NODE_ID, DefPathData::CrateRoot); + assert_eq!(root, CRATE_DEF_INDEX); + collector.parent_def = Some(root); + + collector.create_def_with_parent(Some(CRATE_DEF_INDEX), DUMMY_NODE_ID, DefPathData::Misc); + + collector + } + + pub fn extend(parent_node: NodeId, + parent_def_path: DefPath, + parent_def_id: DefId, + definitions: Definitions) + -> DefCollector<'ast> { + let mut collector = DefCollector { + hir_crate: None, + parent_def: None, + definitions: definitions, + }; + + assert_eq!(parent_def_path.krate, parent_def_id.krate); + let root_path = Box::new(InlinedRootPath { + data: parent_def_path.data, + def_id: parent_def_id, + }); + + let def = collector.create_def(parent_node, DefPathData::InlinedRoot(root_path)); + collector.parent_def = Some(def); + + 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 + } + + fn create_def(&mut self, node_id: NodeId, data: DefPathData) -> DefIndex { + let parent_def = self.parent_def(); + debug!("create_def(node_id={:?}, data={:?}, parent_def={:?})", node_id, data, parent_def); + self.definitions.create_def_with_parent(parent_def, node_id, data) + } + + fn create_def_with_parent(&mut self, + parent: Option, + node_id: NodeId, + data: DefPathData) + -> DefIndex { + self.definitions.create_def_with_parent(parent, node_id, data) + } + + fn with_parent(&mut self, parent_def: DefIndex, f: F) { + let parent = self.parent_def; + self.parent_def = Some(parent_def); + f(self); + self.parent_def = parent; + } +} + +impl<'ast> visit::Visitor<'ast> for DefCollector<'ast> { + fn visit_item(&mut self, i: &'ast 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 { + ItemKind::DefaultImpl(..) | ItemKind::Impl(..) => + DefPathData::Impl, + ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Trait(..) | + ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | ItemKind::Ty(..) => + DefPathData::TypeNs(i.ident.name), + ItemKind::Mod(..) => DefPathData::Module(i.ident.name), + ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) => + DefPathData::ValueNs(i.ident.name), + ItemKind::Mac(..) => DefPathData::MacroDef(i.ident.name), + ItemKind::Use(..) => DefPathData::Misc, + }; + let def = self.create_def(i.id, def_data); + + self.with_parent(def, |this| { + match i.node { + ItemKind::Enum(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.name)); + + for (index, field) in v.node.data.fields().iter().enumerate() { + let name = field.ident.map(|ident| ident.name) + .unwrap_or(token::intern(&index.to_string())); + this.create_def_with_parent(Some(variant_def_index), + field.id, + DefPathData::Field(name)); + } + } + } + ItemKind::Struct(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 (index, field) in struct_def.fields().iter().enumerate() { + let name = field.ident.map(|ident| ident.name) + .unwrap_or(token::intern(&index.to_string())); + this.create_def(field.id, DefPathData::Field(name)); + } + } + _ => {} + } + visit::walk_item(this, i); + }); + } + + fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) { + let def = self.create_def(foreign_item.id, DefPathData::ValueNs(foreign_item.ident.name)); + + self.with_parent(def, |this| { + visit::walk_foreign_item(this, foreign_item); + }); + } + + fn visit_generics(&mut self, generics: &'ast Generics) { + for ty_param in generics.ty_params.iter() { + self.create_def(ty_param.id, DefPathData::TypeParam(ty_param.ident.name)); + } + + visit::walk_generics(self, generics); + } + + fn visit_trait_item(&mut self, ti: &'ast TraitItem) { + let def_data = match ti.node { + TraitItemKind::Method(..) | TraitItemKind::Const(..) => + DefPathData::ValueNs(ti.ident.name), + TraitItemKind::Type(..) => DefPathData::TypeNs(ti.ident.name), + }; + + let def = self.create_def(ti.id, def_data); + self.with_parent(def, |this| { + if let TraitItemKind::Const(_, Some(ref expr)) = ti.node { + this.create_def(expr.id, DefPathData::Initializer); + } + + visit::walk_trait_item(this, ti); + }); + } + + fn visit_impl_item(&mut self, ii: &'ast ImplItem) { + let def_data = match ii.node { + ImplItemKind::Method(..) | ImplItemKind::Const(..) => + DefPathData::ValueNs(ii.ident.name), + ImplItemKind::Type(..) => DefPathData::TypeNs(ii.ident.name), + ImplItemKind::Macro(..) => DefPathData::MacroDef(ii.ident.name), + }; + + let def = self.create_def(ii.id, def_data); + self.with_parent(def, |this| { + if let ImplItemKind::Const(_, ref expr) = ii.node { + this.create_def(expr.id, DefPathData::Initializer); + } + + visit::walk_impl_item(this, ii); + }); + } + + fn visit_pat(&mut self, pat: &'ast Pat) { + let parent_def = self.parent_def; + + if let PatKind::Ident(_, id, _) = pat.node { + let def = self.create_def(pat.id, DefPathData::Binding(id.node.name)); + self.parent_def = Some(def); + } + + visit::walk_pat(self, pat); + self.parent_def = parent_def; + } + + fn visit_expr(&mut self, expr: &'ast Expr) { + let parent_def = self.parent_def; + + if let ExprKind::Closure(..) = expr.node { + let def = self.create_def(expr.id, DefPathData::ClosureExpr); + self.parent_def = Some(def); + } + + visit::walk_expr(self, expr); + self.parent_def = parent_def; + } + + fn visit_lifetime_def(&mut self, def: &'ast LifetimeDef) { + self.create_def(def.lifetime.id, DefPathData::LifetimeDef(def.lifetime.name)); + } + + fn visit_macro_def(&mut self, macro_def: &'ast MacroDef) { + 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 parent_def = self.parent_def; + + if let hir::PatKind::Ident(_, id, _) = pat.node { + let def = self.create_def(pat.id, DefPathData::Binding(id.node.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 7b8ddee0e23..92f8c9249c8 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -11,6 +11,7 @@ pub use self::Node::*; use self::MapEntry::*; use self::collector::NodeCollector; +use self::def_collector::DefCollector; pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData, DisambiguatedDefPathData, InlinedRootPath}; @@ -21,9 +22,10 @@ use middle::cstore::InlinedItem as II; use hir::def_id::{CRATE_DEF_INDEX, DefId}; use syntax::abi::Abi; -use syntax::ast::{self, Name, NodeId, DUMMY_NODE_ID}; +use syntax::ast::{self, Name, NodeId, DUMMY_NODE_ID, }; use syntax::attr::ThinAttributesExt; use syntax::codemap::{Span, Spanned}; +use syntax::visit; use hir::*; use hir::fold::Folder; @@ -36,6 +38,7 @@ use std::mem; pub mod blocks; mod collector; +mod def_collector; pub mod definitions; #[derive(Copy, Clone, Debug)] @@ -193,7 +196,7 @@ pub struct Map<'ast> { /// plain old integers. map: RefCell>>, - definitions: RefCell, + definitions: &'ast RefCell, } impl<'ast> Map<'ast> { @@ -780,12 +783,18 @@ impl Folder for IdAndSpanUpdater { } } -pub fn map_crate<'ast>(forest: &'ast mut Forest) -> Map<'ast> { - let (map, definitions) = { - let mut collector = NodeCollector::root(&forest.krate); - intravisit::walk_crate(&mut collector, &forest.krate); - (collector.map, collector.definitions) - }; +pub fn collect_definitions<'ast>(krate: &'ast ast::Crate) -> Definitions { + let mut def_collector = DefCollector::root(); + visit::walk_crate(&mut def_collector, krate); + def_collector.definitions +} + +pub fn map_crate<'ast>(forest: &'ast mut Forest, + definitions: &'ast RefCell) + -> Map<'ast> { + let mut collector = NodeCollector::root(&forest.krate); + intravisit::walk_crate(&mut collector, &forest.krate); + let map = collector.map; if log_enabled!(::log::DEBUG) { // This only makes sense for ordered stores; note the @@ -807,7 +816,7 @@ pub fn map_crate<'ast>(forest: &'ast mut Forest) -> Map<'ast> { forest: forest, dep_graph: forest.dep_graph.clone(), map: RefCell::new(map), - definitions: RefCell::new(definitions), + definitions: definitions, } } @@ -834,21 +843,24 @@ 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); - let mut collector = - NodeCollector::extend( - map.krate(), - ii, - ii_parent_id, - parent_def_path, - parent_def_id, - mem::replace(&mut *map.map.borrow_mut(), vec![]), - mem::replace(&mut *map.definitions.borrow_mut(), Definitions::new())); - ii.visit(&mut collector); + 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, + ii_parent_id, + parent_def_path, + parent_def_id, + mem::replace(&mut *map.map.borrow_mut(), vec![])); + ii.visit(&mut collector); *map.map.borrow_mut() = collector.map; - *map.definitions.borrow_mut() = collector.definitions; ii } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index de1a740e0bb..5fc2a955c06 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -43,6 +43,7 @@ use super::Compilation; use serialize::json; +use std::cell::RefCell; use std::collections::HashMap; use std::env; use std::ffi::{OsString, OsStr}; @@ -120,13 +121,24 @@ pub fn compile_input(sess: &Session, Ok(())); let expanded_crate = assign_node_ids(sess, expanded_crate); - // Lower ast -> hir. - let lcx = LoweringContext::new(sess, Some(&expanded_crate)); let dep_graph = DepGraph::new(sess.opts.build_dep_graph()); - let mut hir_forest = time(sess.time_passes(), - "lowering ast -> hir", - || hir_map::Forest::new(lower_crate(&lcx, &expanded_crate), - dep_graph)); + + // Collect defintions for def ids. + let defs = &RefCell::new(time(sess.time_passes(), + "collecting defs", + || hir_map::collect_definitions(&expanded_crate))); + + time(sess.time_passes(), + "external crate/lib resolution", + || LocalCrateReader::new(sess, &cstore, &defs, &expanded_crate, &id) + .read_crates(&dep_graph)); + + // Lower ast -> hir. + let lcx = LoweringContext::new(sess, Some(&expanded_crate), defs); + let hir_forest = &mut time(sess.time_passes(), + "lowering ast -> hir", + || hir_map::Forest::new(lower_crate(&lcx, &expanded_crate), + dep_graph)); // Discard MTWT tables that aren't required past lowering to HIR. if !sess.opts.debugging_opts.keep_mtwt_tables && @@ -135,7 +147,12 @@ pub fn compile_input(sess: &Session, } let arenas = ty::CtxtArenas::new(); - let hir_map = make_map(sess, &mut hir_forest); + + // Construct the HIR map + let hir_map = time(sess.time_passes(), + "indexing hir", + move || hir_map::map_crate(hir_forest, defs)); + write_out_deps(sess, &outputs, &id); @@ -171,7 +188,6 @@ pub fn compile_input(sess: &Session, }; phase_3_run_analysis_passes(sess, - &cstore, hir_map, &arenas, &id, @@ -726,20 +742,10 @@ pub fn assign_node_ids(sess: &Session, krate: ast::Crate) -> ast::Crate { krate } -pub fn make_map<'ast>(sess: &Session, - forest: &'ast mut hir_map::Forest) - -> hir_map::Map<'ast> { - // Construct the HIR map - time(sess.time_passes(), - "indexing hir", - move || hir_map::map_crate(forest)) -} - /// Run the resolution, typechecking, region checking and other /// miscellaneous analysis passes on the crate. Return various /// structures carrying the results of the analysis. pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, - cstore: &CStore, hir_map: hir_map::Map<'tcx>, arenas: &'tcx ty::CtxtArenas<'tcx>, name: &str, @@ -762,10 +768,6 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, let time_passes = sess.time_passes(); - time(time_passes, - "external crate/lib resolution", - || LocalCrateReader::new(sess, cstore, &hir_map, name).read_crates()); - let lang_items = time(time_passes, "language item collection", || { sess.track_errors(|| { middle::lang_items::collect_language_items(&sess, &hir_map) @@ -778,8 +780,8 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, export_map, trait_map, glob_map, - } = time(time_passes, - "resolution", + } = time(sess.time_passes(), + "name resolution", || resolve::resolve_crate(sess, &hir_map, make_glob_map)); let mut analysis = ty::CrateAnalysis { diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 769449b96d2..0e100f48ac3 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -199,14 +199,9 @@ pub fn run_compiler<'a>(args: &[String], // It is somewhat unfortunate that this is hardwired in - this is forced by // the fact that pretty_print_input requires the session by value. let pretty = callbacks.parse_pretty(&sess, &matches); - match pretty { - Some((ppm, opt_uii)) => { - pretty::pretty_print_input(sess, &cstore, cfg, &input, ppm, opt_uii, ofile); - return (Ok(()), None); - } - None => { - // continue - } + if let Some((ppm, opt_uii)) = pretty { + pretty::pretty_print_input(sess, &cstore, cfg, &input, ppm, opt_uii, ofile); + return (Ok(()), None); } let plugins = sess.opts.debugging_opts.extra_plugins.clone(); diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index cde5ba19859..b1143fd3e84 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -29,6 +29,7 @@ use rustc_borrowck as borrowck; use rustc_borrowck::graphviz as borrowck_dot; use rustc_resolve as resolve; use rustc_metadata::cstore::CStore; +use rustc_metadata::creader::LocalCrateReader; use rustc_mir::pretty::write_mir_pretty; use rustc_mir::graphviz::write_mir_graphviz; @@ -43,6 +44,7 @@ use syntax::util::small_vector::SmallVector; use graphviz as dot; +use std::cell::RefCell; use std::fs::File; use std::io::{self, Write}; use std::iter; @@ -179,7 +181,6 @@ impl PpSourceMode { } fn call_with_pp_support_hir<'tcx, A, B, F>(&self, sess: &'tcx Session, - cstore: &CStore, ast_map: &hir_map::Map<'tcx>, arenas: &'tcx ty::CtxtArenas<'tcx>, id: &str, @@ -206,7 +207,6 @@ impl PpSourceMode { } PpmTyped => { abort_on_err(driver::phase_3_run_analysis_passes(sess, - cstore, ast_map.clone(), arenas, id, @@ -721,7 +721,7 @@ pub fn pretty_print_input(sess: Session, let is_expanded = needs_expansion(&ppm); let compute_ast_map = needs_ast_map(&ppm, &opt_uii); let krate = if compute_ast_map { - match driver::phase_2_configure_and_expand(&sess, &cstore, krate, &id[..], None) { + match driver::phase_2_configure_and_expand(&sess, &cstore, krate, &id, None) { Err(_) => return, Ok(k) => driver::assign_node_ids(&sess, k), } @@ -732,14 +732,18 @@ pub fn pretty_print_input(sess: Session, // There is some twisted, god-forsaken tangle of lifetimes here which makes // the ordering of stuff super-finicky. let mut hir_forest; - let lcx = LoweringContext::new(&sess, Some(&krate)); - let arenas = ty::CtxtArenas::new(); + let mut _defs = None; let dep_graph = DepGraph::new(false); + let arenas = ty::CtxtArenas::new(); let _ignore = dep_graph.in_ignore(); let ast_map = if compute_ast_map { + _defs = Some(RefCell::new(hir_map::collect_definitions(&krate))); + let defs = _defs.as_ref().unwrap(); + LocalCrateReader::new(&sess, &cstore, defs, &krate, &id).read_crates(&dep_graph); + let lcx = LoweringContext::new(&sess, Some(&krate), defs); + hir_forest = hir_map::Forest::new(lower_crate(&lcx, &krate), dep_graph.clone()); - let map = driver::make_map(&sess, &mut hir_forest); - Some(map) + Some(hir_map::map_crate(&mut hir_forest, defs)) } else { None }; @@ -752,7 +756,7 @@ pub fn pretty_print_input(sess: Session, .unwrap() .as_bytes() .to_vec(); - let mut rdr = &src[..]; + let mut rdr = &*src; let mut out = Vec::new(); @@ -777,7 +781,6 @@ pub fn pretty_print_input(sess: Session, (PpmHir(s), None) => { let out: &mut Write = &mut out; s.call_with_pp_support_hir(&sess, - cstore, &ast_map.unwrap(), &arenas, &id, @@ -799,7 +802,6 @@ pub fn pretty_print_input(sess: Session, (PpmHir(s), Some(uii)) => { let out: &mut Write = &mut out; s.call_with_pp_support_hir(&sess, - cstore, &ast_map.unwrap(), &arenas, &id, @@ -840,7 +842,6 @@ pub fn pretty_print_input(sess: Session, None }; abort_on_err(driver::phase_3_run_analysis_passes(&sess, - &cstore, ast_map, &arenas, &id, @@ -887,7 +888,6 @@ pub fn pretty_print_input(sess: Session, Some(code) => { let variants = gather_flowgraph_variants(&sess); abort_on_err(driver::phase_3_run_analysis_passes(&sess, - &cstore, ast_map, &arenas, &id, diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index fc12d546288..ce92dd158c9 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -27,8 +27,10 @@ use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::relate::TypeRelation; use rustc::infer::{self, InferOk, InferResult, TypeOrigin}; use rustc_metadata::cstore::CStore; +use rustc_metadata::creader::LocalCrateReader; use rustc::hir::map as hir_map; use rustc::session::{self, config}; +use std::cell::RefCell; use std::rc::Rc; use syntax::ast; use syntax::abi::Abi; @@ -119,13 +121,15 @@ fn test_env(source_string: &str, let krate = driver::phase_2_configure_and_expand(&sess, &cstore, krate, "test", None) .expect("phase 2 aborted"); - let krate = driver::assign_node_ids(&sess, krate); - let lcx = LoweringContext::new(&sess, Some(&krate)); let dep_graph = DepGraph::new(false); + let krate = driver::assign_node_ids(&sess, krate); + let defs = &RefCell::new(hir_map::collect_definitions(&krate)); + LocalCrateReader::new(&sess, &cstore, defs, &krate, "test_crate").read_crates(&dep_graph); + let lcx = LoweringContext::new(&sess, Some(&krate), defs); let _ignore = dep_graph.in_ignore(); - let mut hir_forest = hir_map::Forest::new(lower_crate(&lcx, &krate), dep_graph.clone()); + let mut hir_forest = &mut hir_map::Forest::new(lower_crate(&lcx, &krate), dep_graph.clone()); let arenas = ty::CtxtArenas::new(); - let ast_map = driver::make_map(&sess, &mut hir_forest); + let ast_map = hir_map::map_crate(hir_forest, defs); // run just enough stuff to build a tcx: let lang_items = lang_items::collect_language_items(&sess, &ast_map); diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index 49512a5018e..2d6a043e34a 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -1339,7 +1339,7 @@ fn roundtrip(in_item: hir::Item) { fn test_basic() { let cx = mk_ctxt(); let fnia = FakeNodeIdAssigner; - let lcx = LoweringContext::new(&fnia, None); + let lcx = LoweringContext::testing_context(&fnia); roundtrip(lower_item(&lcx, "e_item!(&cx, fn foo() {} ).unwrap())); @@ -1349,7 +1349,7 @@ fn test_basic() { fn test_smalltalk() { let cx = mk_ctxt(); let fnia = FakeNodeIdAssigner; - let lcx = LoweringContext::new(&fnia, None); + let lcx = LoweringContext::testing_context(&fnia); roundtrip(lower_item(&lcx, "e_item!(&cx, fn foo() -> isize { 3 + 4 } // first smalltalk program ever executed. ).unwrap())); @@ -1359,7 +1359,7 @@ fn test_smalltalk() { fn test_more() { let cx = mk_ctxt(); let fnia = FakeNodeIdAssigner; - let lcx = LoweringContext::new(&fnia, None); + let lcx = LoweringContext::testing_context(&fnia); roundtrip(lower_item(&lcx, "e_item!(&cx, fn foo(x: usize, y: usize) -> usize { let z = x + y; @@ -1378,7 +1378,7 @@ fn test_simplification() { } ).unwrap(); let fnia = FakeNodeIdAssigner; - let lcx = LoweringContext::new(&fnia, None); + let lcx = LoweringContext::testing_context(&fnia); let hir_item = lower_item(&lcx, &item); let item_in = InlinedItemRef::Item(&hir_item); let item_out = simplify_ast(item_in); diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index df9072835b9..635ef4ab358 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -18,7 +18,7 @@ use decoder; use loader::{self, CratePaths}; use rustc::hir::svh::Svh; -use rustc::dep_graph::DepNode; +use rustc::dep_graph::{DepGraph, DepNode}; use rustc::session::{config, Session}; use rustc::session::search_paths::PathKind; use rustc::middle::cstore::{CrateStore, validate_crate_name, ExternCrate}; @@ -37,15 +37,15 @@ use syntax::parse; use syntax::attr; use syntax::attr::AttrMetaMethods; use syntax::parse::token::InternedString; -use rustc::hir::intravisit::Visitor; -use rustc::hir; +use syntax::visit; use log; -pub struct LocalCrateReader<'a, 'b:'a> { +pub struct LocalCrateReader<'a> { sess: &'a Session, cstore: &'a CStore, creader: CrateReader<'a>, - ast_map: &'a hir_map::Map<'b>, + krate: &'a ast::Crate, + defintions: &'a RefCell, } pub struct CrateReader<'a> { @@ -56,9 +56,10 @@ pub struct CrateReader<'a> { local_crate_name: String, } -impl<'a, 'b, 'hir> Visitor<'hir> for LocalCrateReader<'a, 'b> { - fn visit_item(&mut self, a: &'hir hir::Item) { +impl<'a, 'ast> visit::Visitor<'ast> for LocalCrateReader<'a> { + fn visit_item(&mut self, a: &'ast ast::Item) { self.process_item(a); + visit::walk_item(self, a); } } @@ -80,11 +81,8 @@ fn dump_crates(cstore: &CStore) { fn should_link(i: &ast::Item) -> bool { !attr::contains_name(&i.attrs, "no_link") } -// Dup for the hir -fn should_link_hir(i: &hir::Item) -> bool { - !attr::contains_name(&i.attrs, "no_link") -} +#[derive(Debug)] struct CrateInfo { ident: String, name: String, @@ -181,31 +179,6 @@ impl<'a> CrateReader<'a> { } } - // Dup of the above, but for the hir - fn extract_crate_info_hir(&self, i: &hir::Item) -> Option { - match i.node { - hir::ItemExternCrate(ref path_opt) => { - debug!("resolving extern crate stmt. ident: {} path_opt: {:?}", - i.name, path_opt); - let name = match *path_opt { - Some(name) => { - validate_crate_name(Some(self.sess), &name.as_str(), - Some(i.span)); - name.to_string() - } - None => i.name.to_string(), - }; - Some(CrateInfo { - ident: i.name.to_string(), - name: name, - id: i.id, - should_link: should_link_hir(i), - }) - } - _ => None - } - } - fn existing_match(&self, name: &str, hash: Option<&Svh>, kind: PathKind) -> Option { let mut ret = None; @@ -776,29 +749,30 @@ impl<'a> CrateReader<'a> { } } -impl<'a, 'b> LocalCrateReader<'a, 'b> { +impl<'a> LocalCrateReader<'a> { pub fn new(sess: &'a Session, cstore: &'a CStore, - map: &'a hir_map::Map<'b>, + defs: &'a RefCell, + krate: &'a ast::Crate, local_crate_name: &str) - -> LocalCrateReader<'a, 'b> { + -> LocalCrateReader<'a> { LocalCrateReader { sess: sess, cstore: cstore, creader: CrateReader::new(sess, cstore, local_crate_name), - ast_map: map, + krate: krate, + defintions: defs, } } // Traverses an AST, reading all the information about use'd crates and // extern libraries necessary for later resolving, typechecking, linking, // etc. - pub fn read_crates(&mut self) { - let _task = self.ast_map.dep_graph.in_task(DepNode::CrateReader); - let krate = self.ast_map.krate(); + pub fn read_crates(&mut self, dep_graph: &DepGraph) { + let _task = dep_graph.in_task(DepNode::CrateReader); - self.process_crate(krate); - krate.visit_all_items(self); + self.process_crate(self.krate); + visit::walk_crate(self, self.krate); self.creader.inject_allocator_crate(); if log_enabled!(log::INFO) { @@ -811,34 +785,34 @@ impl<'a, 'b> LocalCrateReader<'a, 'b> { self.creader.register_statically_included_foreign_items(); } - fn process_crate(&self, c: &hir::Crate) { + fn process_crate(&self, c: &ast::Crate) { for a in c.attrs.iter().filter(|m| m.name() == "link_args") { - match a.value_str() { - Some(ref linkarg) => self.cstore.add_used_link_args(&linkarg), - None => { /* fallthrough */ } + if let Some(ref linkarg) = a.value_str() { + self.cstore.add_used_link_args(&linkarg); } } } - fn process_item(&mut self, i: &hir::Item) { + fn process_item(&mut self, i: &ast::Item) { match i.node { - hir::ItemExternCrate(_) => { - if !should_link_hir(i) { + ast::ItemKind::ExternCrate(_) => { + if !should_link(i) { return; } - match self.creader.extract_crate_info_hir(i) { + match self.creader.extract_crate_info(i) { Some(info) => { let (cnum, _, _) = self.creader.resolve_crate(&None, - &info.ident, - &info.name, - None, - i.span, - PathKind::Crate, - true); - let def_id = self.ast_map.local_def_id(i.id); + &info.ident, + &info.name, + None, + i.span, + PathKind::Crate, + true); - let len = self.ast_map.def_path(def_id).data.len(); + let defs = self.defintions.borrow(); + let def_id = defs.opt_local_def_id(i.id).unwrap(); + let len = defs.def_path(def_id.index).data.len(); self.creader.update_extern_crate(cnum, ExternCrate { @@ -852,12 +826,12 @@ impl<'a, 'b> LocalCrateReader<'a, 'b> { None => () } } - hir::ItemForeignMod(ref fm) => self.process_foreign_mod(i, fm), + ast::ItemKind::ForeignMod(ref fm) => self.process_foreign_mod(i, fm), _ => { } } } - fn process_foreign_mod(&mut self, i: &hir::Item, fm: &hir::ForeignMod) { + fn process_foreign_mod(&mut self, i: &ast::Item, fm: &ast::ForeignMod) { if fm.abi == Abi::Rust || fm.abi == Abi::RustIntrinsic || fm.abi == Abi::PlatformIntrinsic { return; } diff --git a/src/librustc_save_analysis/csv_dumper.rs b/src/librustc_save_analysis/csv_dumper.rs index 0e02830db7a..45ec9a97a11 100644 --- a/src/librustc_save_analysis/csv_dumper.rs +++ b/src/librustc_save_analysis/csv_dumper.rs @@ -17,10 +17,10 @@ use super::data::*; use super::dump::Dump; use super::span_utils::SpanUtils; -pub struct CsvDumper<'a, 'b, W: 'b> { +pub struct CsvDumper<'tcx, 'b, W: 'b> { output: &'b mut W, dump_spans: bool, - span: SpanUtils<'a> + span: SpanUtils<'tcx> } impl<'a, 'b, W: Write> CsvDumper<'a, 'b, W> { diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 3784c95fe2b..bf6ad703963 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -42,7 +42,7 @@ use syntax::visit::{self, Visitor}; use syntax::print::pprust::{path_to_string, ty_to_string}; use syntax::ptr::P; -use rustc::hir::lowering::{lower_expr, LoweringContext}; +use rustc::hir::lowering::lower_expr; use super::{escape, generated_code, SaveContext, PathCollector}; use super::data::*; @@ -60,12 +60,12 @@ macro_rules! down_cast_data { }; } -pub struct DumpVisitor<'l, 'tcx: 'l, D: 'l> { +pub struct DumpVisitor<'l, 'tcx: 'l, 'll, D: 'll> { save_ctxt: SaveContext<'l, 'tcx>, sess: &'l Session, tcx: &'l TyCtxt<'tcx>, analysis: &'l ty::CrateAnalysis<'l>, - dumper: &'l mut D, + dumper: &'ll mut D, span: SpanUtils<'l>, @@ -77,22 +77,19 @@ pub struct DumpVisitor<'l, 'tcx: 'l, D: 'l> { // one macro use per unique callsite span. mac_defs: HashSet, mac_uses: HashSet, - } -impl <'l, 'tcx, D> DumpVisitor<'l, 'tcx, D> -where D: Dump -{ +impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { pub fn new(tcx: &'l TyCtxt<'tcx>, - lcx: &'l LoweringContext<'l>, + save_ctxt: SaveContext<'l, 'tcx>, analysis: &'l ty::CrateAnalysis<'l>, - dumper: &'l mut D) - -> DumpVisitor<'l, 'tcx, D> { + dumper: &'ll mut D) + -> DumpVisitor<'l, 'tcx, 'll, D> { let span_utils = SpanUtils::new(&tcx.sess); DumpVisitor { sess: &tcx.sess, tcx: tcx, - save_ctxt: SaveContext::from_span_utils(tcx, lcx, span_utils.clone()), + save_ctxt: save_ctxt, analysis: analysis, dumper: dumper, span: span_utils.clone(), @@ -103,7 +100,7 @@ where D: Dump } fn nest(&mut self, scope_id: NodeId, f: F) - where F: FnOnce(&mut DumpVisitor<'l, 'tcx, D>) + where F: FnOnce(&mut DumpVisitor<'l, 'tcx, 'll, D>) { let parent_scope = self.cur_scope; self.cur_scope = scope_id; @@ -982,7 +979,7 @@ where D: Dump } } -impl<'l, 'tcx, 'v, D: Dump + 'l> Visitor<'v> for DumpVisitor<'l, 'tcx, D> { +impl<'v, 'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'v> for DumpVisitor<'l, 'tcx, 'll, D> { fn visit_item(&mut self, item: &ast::Item) { use syntax::ast::ItemKind::*; self.process_macro_use(item.span, item.id); diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 4596398c315..9148b53322b 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -73,7 +73,7 @@ pub mod recorder { pub struct SaveContext<'l, 'tcx: 'l> { tcx: &'l TyCtxt<'tcx>, lcx: &'l lowering::LoweringContext<'l>, - span_utils: SpanUtils<'l>, + span_utils: SpanUtils<'tcx>, } macro_rules! option_try( @@ -90,7 +90,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { pub fn from_span_utils(tcx: &'l TyCtxt<'tcx>, lcx: &'l lowering::LoweringContext<'l>, - span_utils: SpanUtils<'l>) + span_utils: SpanUtils<'tcx>) -> SaveContext<'l, 'tcx> { SaveContext { tcx: tcx, @@ -680,7 +680,7 @@ impl<'v> Visitor<'v> for PathCollector { pub fn process_crate<'l, 'tcx>(tcx: &'l TyCtxt<'tcx>, lcx: &'l lowering::LoweringContext<'l>, krate: &ast::Crate, - analysis: &ty::CrateAnalysis, + analysis: &'l ty::CrateAnalysis<'l>, cratename: &str, odir: Option<&Path>) { let _ignore = tcx.dep_graph.in_ignore(); @@ -726,9 +726,10 @@ pub fn process_crate<'l, 'tcx>(tcx: &'l TyCtxt<'tcx>, }); root_path.pop(); - let utils = SpanUtils::new(&tcx.sess); + let utils: SpanUtils<'tcx> = SpanUtils::new(&tcx.sess); + let save_ctxt = SaveContext::new(tcx, lcx); let mut dumper = CsvDumper::new(&mut output_file, utils); - let mut visitor = DumpVisitor::new(tcx, lcx, analysis, &mut dumper); + let mut visitor = DumpVisitor::new(tcx, save_ctxt, analysis, &mut dumper); // FIXME: we don't write anything! visitor.dump_crate_info(cratename, krate); diff --git a/src/librustc_save_analysis/span_utils.rs b/src/librustc_save_analysis/span_utils.rs index f410d428177..c64eeb92737 100644 --- a/src/librustc_save_analysis/span_utils.rs +++ b/src/librustc_save_analysis/span_utils.rs @@ -26,6 +26,8 @@ use syntax::parse::token::{keywords, Token}; #[derive(Clone)] pub struct SpanUtils<'a> { pub sess: &'a Session, + // FIXME given that we clone SpanUtils all over the place, this err_count is + // probably useless and any logic relying on it is bogus. pub err_count: Cell, } diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index b7c60b8a524..6d1e91a687e 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -22,6 +22,7 @@ use rustc_trans::back::link; use rustc_resolve as resolve; use rustc::hir::lowering::{lower_crate, LoweringContext}; use rustc_metadata::cstore::CStore; +use rustc_metadata::creader::LocalCrateReader; use syntax::{ast, codemap, errors}; use syntax::errors::emitter::ColorConfig; @@ -151,14 +152,18 @@ pub fn run_core(search_paths: SearchPaths, .expect("phase_2_configure_and_expand aborted in rustdoc!"); let krate = driver::assign_node_ids(&sess, krate); + let dep_graph = DepGraph::new(false); + + let defs = &RefCell::new(hir_map::collect_definitions(&krate)); + LocalCrateReader::new(&sess, &cstore, &defs, &krate, &name).read_crates(&dep_graph); + let lcx = LoweringContext::new(&sess, Some(&krate), defs); + // Lower ast -> hir. - let lcx = LoweringContext::new(&sess, Some(&krate)); - let mut hir_forest = hir_map::Forest::new(lower_crate(&lcx, &krate), DepGraph::new(false)); + let mut hir_forest = hir_map::Forest::new(lower_crate(&lcx, &krate), dep_graph); let arenas = ty::CtxtArenas::new(); - let hir_map = driver::make_map(&sess, &mut hir_forest); + let hir_map = hir_map::map_crate(&mut hir_forest, defs); abort_on_err(driver::phase_3_run_analysis_passes(&sess, - &cstore, hir_map, &arenas, &name, diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 5a7050fb42f..487aac1806e 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -94,15 +94,17 @@ pub fn run(input: &str, "rustdoc-test", None) .expect("phase_2_configure_and_expand aborted in rustdoc!"); let krate = driver::assign_node_ids(&sess, krate); - let lcx = LoweringContext::new(&sess, Some(&krate)); + let dep_graph = DepGraph::new(false); + let defs = &RefCell::new(hir_map::collect_definitions(&krate)); + + let lcx = LoweringContext::new(&sess, Some(&krate), defs); let krate = lower_crate(&lcx, &krate); let opts = scrape_test_config(&krate); - let dep_graph = DepGraph::new(false); let _ignore = dep_graph.in_ignore(); let mut forest = hir_map::Forest::new(krate, dep_graph.clone()); - let map = hir_map::map_crate(&mut forest); + let map = hir_map::map_crate(&mut forest, defs); let ctx = core::DocContext { map: &map, diff --git a/src/test/run-make/execution-engine/test.rs b/src/test/run-make/execution-engine/test.rs index 12cc475f121..b9a45c09626 100644 --- a/src/test/run-make/execution-engine/test.rs +++ b/src/test/run-make/execution-engine/test.rs @@ -20,6 +20,7 @@ extern crate rustc_metadata; extern crate rustc_resolve; #[macro_use] extern crate syntax; +use std::cell::RefCell; use std::ffi::{CStr, CString}; use std::mem::transmute; use std::path::PathBuf; @@ -35,6 +36,7 @@ use rustc::session::build_session; use rustc_driver::{driver, abort_on_err}; use rustc::hir::lowering::{lower_crate, LoweringContext}; use rustc_resolve::MakeGlobMap; +use rustc_metadata::creader::LocalCrateReader; use rustc_metadata::cstore::CStore; use libc::c_void; @@ -237,15 +239,17 @@ fn compile_program(input: &str, sysroot: PathBuf) let krate = driver::phase_2_configure_and_expand(&sess, &cstore, krate, &id, None) .expect("phase_2 returned `None`"); - let krate = driver::assign_node_ids(&sess, krate); - let lcx = LoweringContext::new(&sess, Some(&krate)); let dep_graph = DepGraph::new(sess.opts.build_dep_graph()); + let krate = driver::assign_node_ids(&sess, krate); + let defs = RefCell::new(ast_map::collect_definitions(&krate)); + LocalCrateReader::new(&sess, &cstore, &defs, &krate, &id).read_crates(&dep_graph); + let lcx = LoweringContext::new(&sess, Some(&krate), &defs); let mut hir_forest = ast_map::Forest::new(lower_crate(&lcx, &krate), dep_graph); let arenas = ty::CtxtArenas::new(); - let ast_map = driver::make_map(&sess, &mut hir_forest); + let ast_map = ast_map::map_crate(&mut hir_forest, &defs); abort_on_err(driver::phase_3_run_analysis_passes( - &sess, &cstore, ast_map, &arenas, &id, + &sess, ast_map, &arenas, &id, MakeGlobMap::No, |tcx, mir_map, analysis, _| { let trans = driver::phase_4_translate_to_llvm(tcx, mir_map.unwrap(), analysis);