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.
This commit is contained in:
Niko Matsakis 2016-03-16 05:50:38 -04:00
parent 6056c5fbed
commit ab9b844146
6 changed files with 141 additions and 99 deletions

View File

@ -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 @@ fn closure_ty(&self, tcx: &TyCtxt<'tcx>, def_id: DefId)
fn repr_attrs(&self, def: DefId) -> Vec<attr::ReprAttr>;
fn item_type(&self, tcx: &TyCtxt<'tcx>, def: DefId)
-> ty::TypeScheme<'tcx>;
fn item_path(&self, def: DefId) -> Vec<hir_map::PathElem>;
fn relative_item_path(&self, def: DefId) -> Vec<hir_map::PathElem>;
fn extern_item_path(&self, def: DefId) -> Vec<hir_map::PathElem>;
fn item_name(&self, def: DefId) -> ast::Name;
fn item_predicates(&self, tcx: &TyCtxt<'tcx>, def: DefId)
@ -203,6 +224,7 @@ fn dylib_dependency_formats(&self, cnum: ast::CrateNum)
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<ExternCrate>;
fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec<ast::Attribute>;
/// The name of the crate as it is referred to in source code of the current
/// crate.
@ -218,7 +240,8 @@ fn crate_struct_field_attrs(&self, cnum: ast::CrateNum)
fn reachable_ids(&self, cnum: ast::CrateNum) -> Vec<DefId>;
// 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<VariantKind>;
fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option<DefId>;
fn tuple_struct_definition_if_ctor(&self, did: DefId) -> Option<DefId>;
@ -323,7 +346,7 @@ fn item_variances(&self, def: DefId) -> ty::ItemVariances { unimplemented!() }
fn repr_attrs(&self, def: DefId) -> Vec<attr::ReprAttr> { unimplemented!() }
fn item_type(&self, tcx: &TyCtxt<'tcx>, def: DefId)
-> ty::TypeScheme<'tcx> { unimplemented!() }
fn item_path(&self, def: DefId) -> Vec<hir_map::PathElem> { unimplemented!() }
fn relative_item_path(&self, def: DefId) -> Vec<hir_map::PathElem> { unimplemented!() }
fn extern_item_path(&self, def: DefId) -> Vec<hir_map::PathElem> { unimplemented!() }
fn item_name(&self, def: DefId) -> ast::Name { unimplemented!() }
fn item_predicates(&self, tcx: &TyCtxt<'tcx>, def: DefId)
@ -386,6 +409,7 @@ fn missing_lang_items(&self, cnum: ast::CrateNum) -> Vec<lang_items::LangItem>
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<ExternCrate> { unimplemented!() }
fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec<ast::Attribute>
{ unimplemented!() }
fn crate_name(&self, cnum: ast::CrateNum) -> InternedString { unimplemented!() }
@ -404,7 +428,8 @@ fn native_libraries(&self, cnum: ast::CrateNum) -> Vec<(NativeLibraryKind, Strin
fn reachable_ids(&self, cnum: ast::CrateNum) -> Vec<DefId> { 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<VariantKind> { unimplemented!() }
fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option<DefId>
{ unimplemented!() }

View File

@ -2222,11 +2222,14 @@ pub fn item_path_str(&self, id: DefId) -> String {
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 @@ pub fn with_path<T, F>(&self, id: DefId, f: F) -> T where
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<ast_map::PathElem> {
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()))
}
}

View File

@ -21,7 +21,7 @@
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::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 @@ fn register_crate(&mut self,
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 @@ fn resolve_crate(&mut self,
span: Span,
kind: PathKind,
explicitly_linked: bool)
-> (ast::CrateNum, Rc<cstore::crate_metadata>,
cstore::CrateSource) {
-> (ast::CrateNum, Rc<cstore::crate_metadata>, cstore::CrateSource) {
enum LookupResult {
Previous(ast::CrateNum),
Loaded(loader::Library),
@ -444,23 +440,54 @@ enum LookupResult {
}
}
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<CratePaths>,
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 @@ fn process_item(&mut self, i: &hir::Item) {
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 => ()

View File

@ -13,7 +13,7 @@
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 @@ fn method_arg_names(&self, did: DefId) -> Vec<String>
decoder::get_method_arg_names(&cdata, did.index)
}
fn item_path(&self, def: DefId) -> Vec<hir_map::PathElem> {
fn relative_item_path(&self, def: DefId) -> Vec<hir_map::PathElem> {
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<hir_map::PathElem> {
@ -344,6 +337,11 @@ fn original_crate_name(&self, cnum: ast::CrateNum) -> token::InternedString
token::intern_and_get_ident(&self.get_crate_data(cnum).name())
}
fn extern_crate(&self, cnum: ast::CrateNum) -> Option<ExternCrate>
{
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 @@ fn reachable_ids(&self, cnum: ast::CrateNum) -> Vec<DefId>
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<VariantKind> {

View File

@ -21,7 +21,7 @@
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 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<SmallVector<ast_map::PathElem>>,
pub local_def_path: RefCell<ast_map::DefPath>,
/// 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<Option<ExternCrate>>,
pub data: MetadataBlob,
pub cnum_map: RefCell<cnum_map>,
pub cnum: ast::CrateNum,
pub codemap_import_info: RefCell<Vec<ImportedFileMap>>,
pub span: codemap::Span,
pub staged_api: bool,
pub index: index::Index,
@ -268,50 +269,6 @@ pub fn imported_filemaps<'a>(&'a self, codemap: &codemap::CodeMap)
}
}
pub fn with_local_path<T, F>(&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")

View File

@ -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);