From bbed61d3d2489eb974d52e327b4fe63e361426ce Mon Sep 17 00:00:00 2001 From: Shotaro Yamada Date: Tue, 10 Apr 2018 23:01:24 +0900 Subject: [PATCH] Extend `ExternCrate` to cover externs inferred from `use` or paths --- src/librustc/ich/impls_cstore.rs | 27 +++++- src/librustc/middle/cstore.rs | 48 ++++++++--- src/librustc/ty/item_path.rs | 34 ++++---- src/librustc_metadata/creader.rs | 92 ++++++++++++++++++--- src/librustc_resolve/build_reduced_graph.rs | 8 +- src/librustc_resolve/lib.rs | 2 +- src/librustc_resolve/resolve_imports.rs | 7 +- src/librustc_save_analysis/lib.rs | 6 +- 8 files changed, 173 insertions(+), 51 deletions(-) diff --git a/src/librustc/ich/impls_cstore.rs b/src/librustc/ich/impls_cstore.rs index 0071850e1052..0e33c64333da 100644 --- a/src/librustc/ich/impls_cstore.rs +++ b/src/librustc/ich/impls_cstore.rs @@ -12,6 +12,7 @@ //! from rustc::middle::cstore in no particular order. use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult}; +use ich::StableHashingContext; use middle; @@ -47,12 +48,32 @@ impl_stable_hash_for!(enum middle::cstore::LinkagePreference { }); impl_stable_hash_for!(struct middle::cstore::ExternCrate { - def_id, + src, span, - direct, - path_len + direct }); +impl<'a> HashStable> for middle::cstore::ExternCrateSource { + fn hash_stable( + &self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher, + ) { + use middle::cstore::ExternCrateSource::*; + + ::std::mem::discriminant(self).hash_stable(hcx, hasher); + + match *self { + Extern { def_id, path_len } => { + def_id.hash_stable(hcx, hasher); + path_len.hash_stable(hcx, hasher); + } + Use { path_len } => path_len.hash_stable(hcx, hasher), + Path => {} + } + } +} + impl_stable_hash_for!(struct middle::cstore::CrateSource { dylib, rlib, diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index add9b621596b..6208a8a767c1 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -148,10 +148,7 @@ pub enum LoadedMacro { #[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, + pub src: ExternCrateSource, /// span of the extern crate that caused this to be loaded pub span: Span, @@ -160,11 +157,28 @@ pub struct ExternCrate { /// 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, +#[derive(Copy, Clone, Debug)] +pub enum ExternCrateSource { + /// Crate is loaded by `extern crate`. + Extern { + /// def_id of the item in the current crate that caused + /// this crate to be loaded; note that there could be multiple + /// such ids + def_id: DefId, + + /// Number of links to reach the extern crate `def_id` + /// declaration; used to select the extern crate with the shortest + /// path + path_len: usize, + }, + // Crate is loaded by `use`. + Use { + path_len: usize, + }, + /// Crate is implicitly loaded by an absolute or an `extern::` path. + Path, } pub struct EncodedMetadata { @@ -357,9 +371,23 @@ impl CrateStore for DummyCrateStore { } pub trait CrateLoader { - fn process_item(&mut self, item: &ast::Item, defs: &Definitions); + fn process_extern_crate(&mut self, item: &ast::Item, defs: &Definitions) -> CrateNum; + + fn process_path_extern( + &mut self, + name: Symbol, + span: Span, + ) -> CrateNum; + + fn process_use_extern( + &mut self, + name: Symbol, + span: Span, + id: ast::NodeId, + defs: &Definitions, + ) -> CrateNum; + fn postprocess(&mut self, krate: &ast::Crate); - fn resolve_crate_from_path(&mut self, name: Symbol, span: Span) -> CrateNum; } // This method is used when generating the command line to pass through to diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index 1f23b0a27e33..771bdcc55e39 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -11,6 +11,7 @@ use hir::map::DefPathData; use hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use ty::{self, Ty, TyCtxt}; +use middle::cstore::{ExternCrate, ExternCrateSource}; use syntax::ast; use syntax::symbol::Symbol; use syntax::symbol::InternedString; @@ -95,21 +96,20 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // `extern crate` manually, we put the `extern // crate` as the parent. So you wind up with // something relative to the current crate. - // 2. for an indirect crate, where there is no extern - // crate, we just prepend the crate name. + // 2. for an extern inferred from a path or an indirect crate, + // where there is no explicit `extern crate`, we just prepend + // the crate name. // // Returns `None` for the local crate. if cnum != LOCAL_CRATE { let opt_extern_crate = self.extern_crate(cnum.as_def_id()); - let opt_extern_crate = opt_extern_crate.and_then(|extern_crate| { - if extern_crate.direct { - Some(extern_crate.def_id) - } else { - None - } - }); - if let Some(extern_crate_def_id) = opt_extern_crate { - self.push_item_path(buffer, extern_crate_def_id); + if let Some(ExternCrate { + src: ExternCrateSource::Extern { def_id, .. }, + direct: true, + .. + }) = *opt_extern_crate + { + self.push_item_path(buffer, def_id); } else { buffer.push(&self.crate_name(cnum).as_str()); } @@ -137,14 +137,18 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // followed by the path to the item within the crate and return. if cur_def.index == CRATE_DEF_INDEX { match *self.extern_crate(cur_def) { - Some(ref extern_crate) if extern_crate.direct => { - self.push_item_path(buffer, extern_crate.def_id); - cur_path.iter().rev().map(|segment| buffer.push(&segment)).count(); + Some(ExternCrate { + src: ExternCrateSource::Extern { def_id, .. }, + direct: true, + .. + }) => { + self.push_item_path(buffer, def_id); + cur_path.iter().rev().for_each(|segment| buffer.push(&segment)); return true; } None => { buffer.push(&self.crate_name(cur_def.krate).as_str()); - cur_path.iter().rev().map(|segment| buffer.push(&segment)).count(); + cur_path.iter().rev().for_each(|segment| buffer.push(&segment)); return true; } _ => {}, diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 86f495c5fac3..268624cf4309 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -25,7 +25,7 @@ use rustc_back::PanicStrategy; use rustc_back::target::TargetTriple; use rustc::session::search_paths::PathKind; use rustc::middle; -use rustc::middle::cstore::{validate_crate_name, ExternCrate}; +use rustc::middle::cstore::{validate_crate_name, ExternCrate, ExternCrateSource}; use rustc::util::common::record_time; use rustc::util::nodemap::FxHashSet; use rustc::hir::map::Definitions; @@ -367,16 +367,31 @@ impl<'a> CrateLoader<'a> { let cmeta = self.cstore.get_crate_data(cnum); let mut old_extern_crate = cmeta.extern_crate.borrow_mut(); + fn path_len_reverse(src: ExternCrateSource) -> cmp::Reverse { + cmp::Reverse(match src { + ExternCrateSource::Extern { path_len, .. } | + ExternCrateSource::Use { path_len } => path_len, + _ => usize::max_value(), + }) + } + // 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 new_rank = ( + true, + extern_crate.direct, + path_len_reverse(extern_crate.src), + ); let old_rank = match *old_extern_crate { - None => (false, false, !0), - Some(ref c) => (true, c.direct, !c.path_len), + None => (false, false, cmp::Reverse(usize::max_value())), + Some(ref c) => ( + true, + c.direct, + path_len_reverse(c.src), + ), }; - if old_rank >= new_rank { return; // no change needed } @@ -1045,7 +1060,7 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> { } } - fn process_item(&mut self, item: &ast::Item, definitions: &Definitions) { + fn process_extern_crate(&mut self, item: &ast::Item, definitions: &Definitions) -> CrateNum { match item.node { ast::ItemKind::ExternCrate(orig_name) => { debug!("resolving extern crate stmt. ident: {} orig_name: {:?}", @@ -1071,17 +1086,68 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> { let def_id = definitions.opt_local_def_id(item.id).unwrap(); let path_len = definitions.def_path(def_id.index).data.len(); - - let extern_crate = ExternCrate { def_id, span: item.span, direct: true, path_len }; - self.update_extern_crate(cnum, extern_crate, &mut FxHashSet()); + self.update_extern_crate( + cnum, + ExternCrate { + src: ExternCrateSource::Extern { def_id, path_len }, + span: item.span, + direct: true, + }, + &mut FxHashSet(), + ); self.cstore.add_extern_mod_stmt_cnum(item.id, cnum); + cnum } - _ => {} + _ => bug!(), } } - fn resolve_crate_from_path(&mut self, name: Symbol, span: Span) -> CrateNum { - self.resolve_crate(&None, name, name, None, None, span, PathKind::Crate, - DepKind::Explicit).0 + fn process_path_extern( + &mut self, + name: Symbol, + span: Span, + ) -> CrateNum { + let cnum = self.resolve_crate( + &None, name, name, None, None, span, PathKind::Crate, DepKind::Explicit + ).0; + + self.update_extern_crate( + cnum, + ExternCrate { + src: ExternCrateSource::Path, + span, + direct: true, + }, + &mut FxHashSet(), + ); + + cnum + } + + fn process_use_extern( + &mut self, + name: Symbol, + span: Span, + id: ast::NodeId, + definitions: &Definitions, + ) -> CrateNum { + let cnum = self.resolve_crate( + &None, name, name, None, None, span, PathKind::Crate, DepKind::Explicit + ).0; + + let def_id = definitions.opt_local_def_id(id).unwrap(); + let path_len = definitions.def_path(def_id.index).data.len(); + + self.update_extern_crate( + cnum, + ExternCrate { + src: ExternCrateSource::Use { path_len }, + span, + direct: true, + }, + &mut FxHashSet(), + ); + + cnum } } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 0542ca6fb24c..f4e2136a5a11 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -252,10 +252,7 @@ impl<'a> Resolver<'a> { } ItemKind::ExternCrate(orig_name) => { - self.crate_loader.process_item(item, &self.definitions); - - // n.b. we don't need to look at the path option here, because cstore already did - let crate_id = self.cstore.extern_mod_stmt_cnum_untracked(item.id).unwrap(); + let crate_id = self.crate_loader.process_extern_crate(item, &self.definitions); let module = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX }); self.populate_module_if_necessary(module); @@ -302,7 +299,8 @@ impl<'a> Resolver<'a> { self.current_module = module; } - ItemKind::ForeignMod(..) => self.crate_loader.process_item(item, &self.definitions), + // Handled in `rustc_metadata::{native_libs,link_args}` + ItemKind::ForeignMod(..) => {} // These items live in the value namespace. ItemKind::Static(_, m, _) => { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 2bf17cd1317d..aeb31460416c 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3258,7 +3258,7 @@ impl<'a> Resolver<'a> { prev_name == keywords::CrateRoot.name() && self.session.features_untracked().extern_absolute_paths { // `::extern_crate::a::b` - let crate_id = self.crate_loader.resolve_crate_from_path(name, ident.span); + let crate_id = self.crate_loader.process_path_extern(name, ident.span); let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX }); self.populate_module_if_necessary(crate_root); diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 87738f7b79be..37c62a7b0b45 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -627,7 +627,12 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { } } else if is_extern && !token::is_path_segment_keyword(source) { let crate_id = - self.crate_loader.resolve_crate_from_path(source.name, directive.span); + self.resolver.crate_loader.process_use_extern( + source.name, + directive.span, + directive.id, + &self.resolver.definitions, + ); let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX }); self.populate_module_if_necessary(crate_root); diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 4f46fb3545b1..34a9b57c9dc3 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -42,6 +42,7 @@ use rustc::hir; use rustc::hir::def::Def as HirDef; use rustc::hir::map::{Node, NodeItem}; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; +use rustc::middle::cstore::ExternCrate; use rustc::session::config::CrateType::CrateTypeExecutable; use rustc::ty::{self, TyCtxt}; use rustc_typeck::hir_ty_to_ty; @@ -112,10 +113,9 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { for &n in self.tcx.crates().iter() { let span = match *self.tcx.extern_crate(n.as_def_id()) { - Some(ref c) => c.span, + Some(ExternCrate { span, .. }) => span, None => { - debug!("Skipping crate {}, no data", n); - continue; + bug!("no data for crate {}", n); } }; let lo_loc = self.span_utils.sess.codemap().lookup_char_pos(span.lo());