From 7effbebb299634e65e2e50cf6d0c52a060be280c Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 1 Jan 2018 13:01:19 +0530 Subject: [PATCH] Handle relative paths --- src/librustc_resolve/lib.rs | 64 +++++++++++++++++++++---------------- src/librustdoc/clean/mod.rs | 36 ++++++++++++--------- src/librustdoc/core.rs | 4 +++ 3 files changed, 61 insertions(+), 43 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 98f428c2527ca..4280942bdb603 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1413,25 +1413,6 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> { fn resolve_str_path(&mut self, span: Span, crate_root: Option<&str>, components: &[&str], is_value: bool) -> hir::Path { - self.resolve_str_path_cb(span, crate_root, components, is_value, - |resolver, span, error| resolve_error(resolver, span, error)) - } - - fn get_resolution(&mut self, id: NodeId) -> Option { - self.def_map.get(&id).cloned() - } - - fn definitions(&mut self) -> &mut Definitions { - &mut self.definitions - } -} - -impl<'a> Resolver<'a> { - /// resolve_str_path, but takes a callback in case there was an error - fn resolve_str_path_cb(&mut self, span: Span, crate_root: Option<&str>, - components: &[&str], is_value: bool, error_callback: F) -> hir::Path - where F: for<'b, 'c> FnOnce(&'c mut Resolver, Span, ResolutionError<'b>) - { use std::iter; let mut path = hir::Path { span, @@ -1441,19 +1422,45 @@ impl<'a> Resolver<'a> { }).map(hir::PathSegment::from_name).collect(), }; - self.resolve_hir_path_cb(&mut path, is_value, error_callback); + self.resolve_hir_path(&mut path, is_value); path } + fn get_resolution(&mut self, id: NodeId) -> Option { + self.def_map.get(&id).cloned() + } + + fn definitions(&mut self) -> &mut Definitions { + &mut self.definitions + } +} + +impl<'a> Resolver<'a> { /// Rustdoc uses this to resolve things in a recoverable way. ResolutionError<'a> /// isn't something that can be returned because it can't be made to live that long, /// and also it's a private type. Fortunately rustdoc doesn't need to know the error, /// just that an error occured. - pub fn resolve_str_path_error(&mut self, span: Span, crate_root: Option<&str>, - components: &[&str], is_value: bool) -> Result { + pub fn resolve_str_path_error(&mut self, span: Span, path_str: &str, is_value: bool) -> Result { + use std::iter; let mut errored = false; - let path = self.resolve_str_path_cb(span, crate_root, components, is_value, - |_, _, _| errored = true); + + let mut path = if path_str.starts_with("::") { + hir::Path { + span, + def: Def::Err, + segments: iter::once(keywords::CrateRoot.name()).chain({ + path_str.split("::").skip(1).map(Symbol::intern) + }).map(hir::PathSegment::from_name).collect(), + } + } else { + hir::Path { + span, + def: Def::Err, + segments: path_str.split("::").map(Symbol::intern) + .map(hir::PathSegment::from_name).collect(), + } + }; + self.resolve_hir_path_cb(&mut path, is_value, |_, _, _| errored = true); if errored || path.def == Def::Err { Err(()) } else { @@ -1874,8 +1881,8 @@ impl<'a> Resolver<'a> { // generate a fake "implementation scope" containing all the // implementations thus found, for compatibility with old resolve pass. - fn with_scope(&mut self, id: NodeId, f: F) - where F: FnOnce(&mut Resolver) + pub fn with_scope(&mut self, id: NodeId, f: F) -> T + where F: FnOnce(&mut Resolver) -> T { let id = self.definitions.local_def_id(id); let module = self.module_map.get(&id).cloned(); // clones a reference @@ -1886,13 +1893,14 @@ impl<'a> Resolver<'a> { self.ribs[TypeNS].push(Rib::new(ModuleRibKind(module))); self.finalize_current_module_macro_resolutions(); - f(self); + let ret = f(self); self.current_module = orig_module; self.ribs[ValueNS].pop(); self.ribs[TypeNS].pop(); + ret } else { - f(self); + f(self) } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index f48940519e0d6..0e025a40c411f 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -473,6 +473,11 @@ impl Clean for doctree::Module { "".to_string() }; + // maintain a stack of mod ids + // we could also pass this down through clean() + // but that might complicate things. + cx.mod_ids.borrow_mut().push(self.id); + let mut items: Vec = vec![]; items.extend(self.extern_crates.iter().map(|x| x.clean(cx))); items.extend(self.imports.iter().flat_map(|x| x.clean(cx))); @@ -490,6 +495,8 @@ impl Clean for doctree::Module { items.extend(self.macros.iter().map(|x| x.clean(cx))); items.extend(self.def_traits.iter().map(|x| x.clean(cx))); + cx.mod_ids.borrow_mut().pop(); + // determine if we should display the inner contents or // the outer `mod` item for the source code. let whence = { @@ -849,21 +856,20 @@ impl Clean for [ast::Attribute] { link.trim() }; - if !path_str.starts_with("::") { - // FIXME (misdreavus): can only support absolute paths because of limitations - // in Resolver. this may, with a lot of effort, figure out how to resolve paths - // within scopes, but the one use of `resolve_hir_path` i found in the HIR - // lowering code itself used an absolute path. we're brushing up against some - // structural limitations in the compiler already, but this may be a design one - // as well >_> - continue; - } - - // This allocation could be avoided if resolve_str_path could take an iterator; - // but it can't because that would break object safety. This can still be - // fixed. - let components = path_str.split("::").skip(1).collect::>(); - let resolve = |is_val| cx.resolver.borrow_mut().resolve_str_path_error(DUMMY_SP, None, &components, is_val); + let resolve = |is_val| { + // In case we're in a module, try to resolve the relative + // path + if let Some(id) = cx.mod_ids.borrow().last() { + cx.resolver.borrow_mut() + .with_scope(*id, |resolver| { + resolver.resolve_str_path_error(DUMMY_SP, &path_str, is_val) + }) + } else { + // FIXME(Manishearth) this branch doesn't seem to ever be hit, really + cx.resolver.borrow_mut() + .resolve_str_path_error(DUMMY_SP, &path_str, is_val) + } + }; if let Some(is_value) = is_value { if let Ok(path) = resolve(is_value) { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 44187725905ea..95c84b936fed7 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -24,6 +24,7 @@ use rustc_resolve as resolve; use rustc_metadata::creader::CrateLoader; use rustc_metadata::cstore::CStore; +use syntax::ast::NodeId; use syntax::codemap; use syntax::feature_gate::UnstableFeatures; use errors; @@ -48,6 +49,8 @@ pub type ExternalPaths = FxHashMap, clean::TypeKind)>; pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a> { pub tcx: TyCtxt<'a, 'tcx, 'tcx>, pub resolver: &'a RefCell>, + /// The stack of module NodeIds up till this point + pub mod_ids: RefCell>, pub populated_all_crate_impls: Cell, // Note that external items for which `doc(hidden)` applies to are shown as // non-reachable while local items aren't. This is because we're reusing @@ -243,6 +246,7 @@ pub fn run_core(search_paths: SearchPaths, render_type, ty_substs: Default::default(), lt_substs: Default::default(), + mod_ids: Default::default(), }; debug!("crate: {:?}", tcx.hir.krate());