From ab9b8441468aed505f83a2ddf74454f9cdfeab33 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 16 Mar 2016 05:50:38 -0400 Subject: [PATCH] track the extern-crate def-id rather than path We used to track, for each crate, a path that led to the extern-crate that imported it. Instead of that, track the def-id of the extern crate, along with a bit more information, and derive the path on the fly. --- src/librustc/middle/cstore.rs | 33 ++++++++++-- src/librustc/middle/ty/mod.rs | 27 +++++++++- src/librustc_metadata/creader.rs | 86 ++++++++++++++++++++++---------- src/librustc_metadata/csearch.rs | 33 ++++++------ src/librustc_metadata/cstore.rs | 57 +++------------------ src/librustc_metadata/decoder.rs | 4 +- 6 files changed, 141 insertions(+), 99 deletions(-) diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 34af4826c3ea..7cad9b10f85e 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -127,6 +127,27 @@ pub enum FoundAst<'ast> { NotFound, } +#[derive(Copy, Clone, Debug)] +pub struct ExternCrate { + /// def_id of an `extern crate` in the current crate that caused + /// this crate to be loaded; note that there could be multiple + /// such ids + pub def_id: DefId, + + /// span of the extern crate that caused this to be loaded + pub span: Span, + + /// If true, then this crate is the crate named by the extern + /// crate referenced above. If false, then this crate is a dep + /// of the crate. + pub direct: bool, + + /// Number of links to reach the extern crate `def_id` + /// declaration; used to select the extern crate with the shortest + /// path + pub path_len: usize, +} + /// A store of Rust crates, through with their metadata /// can be accessed. /// @@ -147,7 +168,7 @@ pub trait CrateStore<'tcx> : Any { fn repr_attrs(&self, def: DefId) -> Vec; fn item_type(&self, tcx: &TyCtxt<'tcx>, def: DefId) -> ty::TypeScheme<'tcx>; - fn item_path(&self, def: DefId) -> Vec; + fn relative_item_path(&self, def: DefId) -> Vec; fn extern_item_path(&self, def: DefId) -> Vec; fn item_name(&self, def: DefId) -> ast::Name; fn item_predicates(&self, tcx: &TyCtxt<'tcx>, def: DefId) @@ -203,6 +224,7 @@ pub trait CrateStore<'tcx> : Any { fn is_staged_api(&self, cnum: ast::CrateNum) -> bool; fn is_explicitly_linked(&self, cnum: ast::CrateNum) -> bool; fn is_allocator(&self, cnum: ast::CrateNum) -> bool; + fn extern_crate(&self, cnum: ast::CrateNum) -> Option; fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec; /// The name of the crate as it is referred to in source code of the current /// crate. @@ -218,7 +240,8 @@ pub trait CrateStore<'tcx> : Any { fn reachable_ids(&self, cnum: ast::CrateNum) -> Vec; // resolve - fn def_path(&self, def: DefId) -> hir_map::DefPath; + fn def_key(&self, def: DefId) -> hir_map::DefKey; + fn relative_def_path(&self, def: DefId) -> hir_map::DefPath; fn variant_kind(&self, def_id: DefId) -> Option; fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option; fn tuple_struct_definition_if_ctor(&self, did: DefId) -> Option; @@ -323,7 +346,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn repr_attrs(&self, def: DefId) -> Vec { unimplemented!() } fn item_type(&self, tcx: &TyCtxt<'tcx>, def: DefId) -> ty::TypeScheme<'tcx> { unimplemented!() } - fn item_path(&self, def: DefId) -> Vec { unimplemented!() } + fn relative_item_path(&self, def: DefId) -> Vec { unimplemented!() } fn extern_item_path(&self, def: DefId) -> Vec { unimplemented!() } fn item_name(&self, def: DefId) -> ast::Name { unimplemented!() } fn item_predicates(&self, tcx: &TyCtxt<'tcx>, def: DefId) @@ -386,6 +409,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn is_staged_api(&self, cnum: ast::CrateNum) -> bool { unimplemented!() } fn is_explicitly_linked(&self, cnum: ast::CrateNum) -> bool { unimplemented!() } fn is_allocator(&self, cnum: ast::CrateNum) -> bool { unimplemented!() } + fn extern_crate(&self, cnum: ast::CrateNum) -> Option { unimplemented!() } fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec { unimplemented!() } fn crate_name(&self, cnum: ast::CrateNum) -> InternedString { unimplemented!() } @@ -404,7 +428,8 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn reachable_ids(&self, cnum: ast::CrateNum) -> Vec { unimplemented!() } // resolve - fn def_path(&self, def: DefId) -> hir_map::DefPath { unimplemented!() } + fn def_key(&self, def: DefId) -> hir_map::DefKey { unimplemented!() } + fn relative_def_path(&self, def: DefId) -> hir_map::DefPath { unimplemented!() } fn variant_kind(&self, def_id: DefId) -> Option { unimplemented!() } fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option { unimplemented!() } diff --git a/src/librustc/middle/ty/mod.rs b/src/librustc/middle/ty/mod.rs index d4af14cf4090..61e591e2fcea 100644 --- a/src/librustc/middle/ty/mod.rs +++ b/src/librustc/middle/ty/mod.rs @@ -2222,11 +2222,14 @@ impl<'tcx> TyCtxt<'tcx> { self.with_path(id, |path| ast_map::path_to_string(path)) } + /// Returns the `DefPath` of an item. Note that if `id` is not + /// local to this crate -- or is inlined into this crate -- the + /// result will be a non-local `DefPath`. pub fn def_path(&self, id: DefId) -> ast_map::DefPath { if id.is_local() { self.map.def_path(id) } else { - self.sess.cstore.def_path(id) + self.sess.cstore.relative_def_path(id) } } @@ -2236,7 +2239,27 @@ impl<'tcx> TyCtxt<'tcx> { if let Some(id) = self.map.as_local_node_id(id) { self.map.with_path(id, f) } else { - f(self.sess.cstore.item_path(id).iter().cloned().chain(LinkedPath::empty())) + let mut path: Vec<_>; + if let Some(extern_crate) = self.sess.cstore.extern_crate(id.krate) { + if !extern_crate.direct { + // this comes from some crate that we don't have a direct + // path to; we'll settle for just prepending the name of + // the crate. + path = self.sess.cstore.extern_item_path(id) + } else { + // start with the path to the extern crate, then + // add the relative path to the actual item + fn collector(elems: ast_map::PathElems) -> Vec { + elems.collect() + } + path = self.with_path(extern_crate.def_id, collector); + path.extend(self.sess.cstore.relative_item_path(id)); + } + } else { + // if this was injected, just make a path with name of crate + path = self.sess.cstore.extern_item_path(id); + } + f(path.iter().cloned().chain(LinkedPath::empty())) } } diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index c1144387553f..4fe10aea2e0f 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -21,7 +21,7 @@ use rustc::back::svh::Svh; use rustc::dep_graph::DepNode; use rustc::session::{config, Session}; use rustc::session::search_paths::PathKind; -use rustc::middle::cstore::{CrateStore, validate_crate_name}; +use rustc::middle::cstore::{CrateStore, validate_crate_name, ExternCrate}; use rustc::util::nodemap::FnvHashMap; use rustc::front::map as hir_map; @@ -38,7 +38,6 @@ use syntax::attr; use syntax::attr::AttrMetaMethods; use syntax::errors::FatalError; use syntax::parse::token::InternedString; -use syntax::util::small_vector::SmallVector; use rustc_front::intravisit::Visitor; use rustc_front::hir; use log; @@ -344,15 +343,13 @@ impl<'a> CrateReader<'a> { let cmeta = Rc::new(cstore::crate_metadata { name: name.to_string(), - local_path: RefCell::new(SmallVector::zero()), - local_def_path: RefCell::new(vec![]), + extern_crate: Cell::new(None), index: decoder::load_index(metadata.as_slice()), xref_index: decoder::load_xrefs(metadata.as_slice()), data: metadata, cnum_map: RefCell::new(cnum_map), cnum: cnum, codemap_import_info: RefCell::new(vec![]), - span: span, staged_api: staged_api, explicitly_linked: Cell::new(explicitly_linked), }); @@ -386,8 +383,7 @@ impl<'a> CrateReader<'a> { span: Span, kind: PathKind, explicitly_linked: bool) - -> (ast::CrateNum, Rc, - cstore::CrateSource) { + -> (ast::CrateNum, Rc, cstore::CrateSource) { enum LookupResult { Previous(ast::CrateNum), Loaded(loader::Library), @@ -444,23 +440,54 @@ impl<'a> CrateReader<'a> { } } + fn update_extern_crate(&mut self, + cnum: ast::CrateNum, + mut extern_crate: ExternCrate) + { + let cmeta = self.cstore.get_crate_data(cnum); + let old_extern_crate = cmeta.extern_crate.get(); + + // Prefer: + // - something over nothing (tuple.0); + // - direct extern crate to indirect (tuple.1); + // - shorter paths to longer (tuple.2). + let new_rank = (true, extern_crate.direct, !extern_crate.path_len); + let old_rank = match old_extern_crate { + None => (false, false, !0), + Some(ref c) => (true, c.direct, !c.path_len), + }; + + if old_rank >= new_rank { + return; // no change needed + } + + cmeta.extern_crate.set(Some(extern_crate)); + + // Propagate the extern crate info to dependencies. + extern_crate.direct = false; + for &dep_cnum in cmeta.cnum_map.borrow().values() { + self.update_extern_crate(dep_cnum, extern_crate); + } + } + // Go through the crate metadata and load any crates that it references fn resolve_crate_deps(&mut self, root: &Option, - cdata: &[u8], span : Span) - -> cstore::cnum_map { + cdata: &[u8], + span : Span) + -> cstore::cnum_map { debug!("resolving deps of external crate"); // The map from crate numbers in the crate we're resolving to local crate // numbers decoder::get_crate_deps(cdata).iter().map(|dep| { debug!("resolving dep crate {} hash: `{}`", dep.name, dep.hash); let (local_cnum, _, _) = self.resolve_crate(root, - &dep.name, - &dep.name, - Some(&dep.hash), - span, - PathKind::Dependency, - dep.explicitly_linked); + &dep.name, + &dep.name, + Some(&dep.hash), + span, + PathKind::Dependency, + dep.explicitly_linked); (dep.cnum, local_cnum) }).collect() } @@ -802,19 +829,24 @@ impl<'a, 'b> LocalCrateReader<'a, 'b> { match self.creader.extract_crate_info_hir(i) { Some(info) => { - let (cnum, cmeta, _) = self.creader.resolve_crate(&None, - &info.ident, - &info.name, - None, - i.span, - PathKind::Crate, - true); + 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); - let def_path = self.ast_map.def_path(def_id); - cmeta.update_local_def_path(def_path); - self.ast_map.with_path(i.id, |path| { - cmeta.update_local_path(path) - }); + + let len = self.ast_map.def_path(def_id).data.len(); + + self.creader.update_extern_crate(cnum, + ExternCrate { + def_id: def_id, + span: i.span, + direct: true, + path_len: len, + }); self.cstore.add_extern_mod_stmt_cnum(info.id, cnum); } None => () diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index fb4dbbba8da4..25cc2f91753a 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -13,7 +13,7 @@ use decoder; use encoder; use loader; -use middle::cstore::{CrateStore, CrateSource, ChildItem, FoundAst}; +use middle::cstore::{CrateStore, CrateSource, ChildItem, ExternCrate, FoundAst}; use middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference}; use middle::def; use middle::lang_items; @@ -128,16 +128,9 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { decoder::get_method_arg_names(&cdata, did.index) } - fn item_path(&self, def: DefId) -> Vec { + fn relative_item_path(&self, def: DefId) -> Vec { let cdata = self.get_crate_data(def.krate); - let path = decoder::get_item_path(&cdata, def.index); - - cdata.with_local_path(|cpath| { - let mut r = Vec::with_capacity(cpath.len() + path.len()); - r.extend_from_slice(cpath); - r.extend_from_slice(&path); - r - }) + decoder::get_item_path(&cdata, def.index) } fn extern_item_path(&self, def: DefId) -> Vec { @@ -344,6 +337,11 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { token::intern_and_get_ident(&self.get_crate_data(cnum).name()) } + fn extern_crate(&self, cnum: ast::CrateNum) -> Option + { + self.get_crate_data(cnum).extern_crate.get() + } + fn crate_hash(&self, cnum: ast::CrateNum) -> Svh { let cdata = self.get_crate_data(cnum); @@ -383,12 +381,17 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { decoder::get_reachable_ids(&cdata) } - fn def_path(&self, def: DefId) -> hir_map::DefPath - { + /// Returns the `DefKey` for a given `DefId`. This indicates the + /// parent `DefId` as well as some idea of what kind of data the + /// `DefId` refers to. + fn def_key(&self, def: DefId) -> hir_map::DefKey { let cdata = self.get_crate_data(def.krate); - let path = decoder::def_path(&cdata, def.index); - let local_path = cdata.local_def_path(); - local_path.into_iter().chain(path).collect() + decoder::def_key(&cdata, def.index) + } + + fn relative_def_path(&self, def: DefId) -> hir_map::DefPath { + let cdata = self.get_crate_data(def.krate); + decoder::def_path(&cdata, def.index) } fn variant_kind(&self, def_id: DefId) -> Option { diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 17c485c73497..f092ee391982 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -21,7 +21,7 @@ use index; use loader; use rustc::back::svh::Svh; -use rustc::front::map as ast_map; +use rustc::middle::cstore::{ExternCrate}; use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet}; use std::cell::{RefCell, Ref, Cell}; @@ -31,9 +31,7 @@ use flate::Bytes; use syntax::ast; use syntax::attr; use syntax::codemap; -use syntax::parse::token; use syntax::parse::token::IdentInterner; -use syntax::util::small_vector::SmallVector; pub use middle::cstore::{NativeLibraryKind, LinkagePreference}; pub use middle::cstore::{NativeStatic, NativeFramework, NativeUnknown}; @@ -63,13 +61,16 @@ pub struct ImportedFileMap { pub struct crate_metadata { pub name: String, - pub local_path: RefCell>, - pub local_def_path: RefCell, + + /// Information about the extern crate that caused this crate to + /// be loaded. If this is `None`, then the crate was injected + /// (e.g., by the allocator) + pub extern_crate: Cell>, + pub data: MetadataBlob, pub cnum_map: RefCell, pub cnum: ast::CrateNum, pub codemap_import_info: RefCell>, - pub span: codemap::Span, pub staged_api: bool, pub index: index::Index, @@ -268,50 +269,6 @@ impl crate_metadata { } } - pub fn with_local_path(&self, f: F) -> T - where F: Fn(&[ast_map::PathElem]) -> T - { - let cpath = self.local_path.borrow(); - if cpath.is_empty() { - let name = ast_map::PathMod(token::intern(&self.name)); - f(&[name]) - } else { - f(cpath.as_slice()) - } - } - - pub fn update_local_path<'a, 'b>(&self, candidate: ast_map::PathElems<'a, 'b>) { - let mut cpath = self.local_path.borrow_mut(); - let cap = cpath.len(); - match cap { - 0 => *cpath = candidate.collect(), - 1 => (), - _ => { - let candidate: SmallVector<_> = candidate.collect(); - if candidate.len() < cap { - *cpath = candidate; - } - }, - } - } - - pub fn local_def_path(&self) -> ast_map::DefPath { - let local_def_path = self.local_def_path.borrow(); - if local_def_path.is_empty() { - let name = ast_map::DefPathData::DetachedCrate(token::intern(&self.name)); - vec![ast_map::DisambiguatedDefPathData { data: name, disambiguator: 0 }] - } else { - local_def_path.clone() - } - } - - pub fn update_local_def_path(&self, candidate: ast_map::DefPath) { - let mut local_def_path = self.local_def_path.borrow_mut(); - if local_def_path.is_empty() || candidate.len() < local_def_path.len() { - *local_def_path = candidate; - } - } - pub fn is_allocator(&self) -> bool { let attrs = decoder::get_crate_attributes(self.data()); attr::contains_name(&attrs, "allocator") diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 562525e956a8..561248fc703f 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1763,7 +1763,9 @@ pub fn closure_ty<'tcx>(cdata: Cmd, closure_id: DefIndex, tcx: &TyCtxt<'tcx>) .parse_closure_ty() } -fn def_key(item_doc: rbml::Doc) -> hir_map::DefKey { +pub fn def_key(cdata: Cmd, id: DefIndex) -> hir_map::DefKey { + debug!("def_key: id={:?}", id); + let item_doc = cdata.lookup_item(id); match reader::maybe_get_doc(item_doc, tag_def_key) { Some(def_key_doc) => { let mut decoder = reader::Decoder::new(def_key_doc);