]> git.lizzy.rs Git - rust.git/commitdiff
track the extern-crate def-id rather than path
authorNiko Matsakis <niko@alum.mit.edu>
Wed, 16 Mar 2016 09:50:38 +0000 (05:50 -0400)
committerNiko Matsakis <niko@alum.mit.edu>
Fri, 25 Mar 2016 18:07:19 +0000 (14:07 -0400)
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
src/librustc/middle/ty/mod.rs
src/librustc_metadata/creader.rs
src/librustc_metadata/csearch.rs
src/librustc_metadata/cstore.rs
src/librustc_metadata/decoder.rs

index 34af4826c3ea46318d7ed3839e0953a39a0380e7..7cad9b10f85ec2a16d44f1c56646112de8d86707 100644 (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!() }
index d4af14cf40907a2d5dccffc51a4b66956be84984..61e591e2fcea63645f64775805c24e4882b80b6b 100644 (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()))
         }
     }
 
index c1144387553f05c257d4c43e34ca95a9afdcbfe0..4fe10aea2e0fb3bdaa4b950409897731e262a61a 100644 (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 => ()
index fb4dbbba8da49d2e6ba9effc643ee7c930eaf58c..25cc2f91753a3f407af74473ab1f65690c345a8f 100644 (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);
+        decoder::def_key(&cdata, def.index)
+    }
+
+    fn relative_def_path(&self, def: DefId) -> hir_map::DefPath {
         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_path(&cdata, def.index)
     }
 
     fn variant_kind(&self, def_id: DefId) -> Option<VariantKind> {
index 17c485c73497f8c31310e28977f5fb488f1797ca..f092ee3919826a0b79eaf693f946e4304276a85a 100644 (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")
index 562525e956a892f623572357d25fa66c79a94dc6..561248fc703f3fc01b55860ecb38851560efd01b 100644 (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);