about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorManish Goregaokar <manishsmail@gmail.com>2018-01-01 13:01:19 +0530
committerManish Goregaokar <manishsmail@gmail.com>2018-01-22 15:24:29 +0530
commit4f10f676d9e39940bf54ebfc7017f1505837532f (patch)
tree45c482fbc3abe2d2f20fa9f44e57223316eb58bf /src
parent8166b59c74f423fbd9b5f1f21f63b9c1f972c9cc (diff)
downloadrust-4f10f676d9e39940bf54ebfc7017f1505837532f.tar.gz
rust-4f10f676d9e39940bf54ebfc7017f1505837532f.zip
Handle relative paths
Diffstat (limited to 'src')
-rw-r--r--src/librustc_resolve/lib.rs64
-rw-r--r--src/librustdoc/clean/mod.rs36
-rw-r--r--src/librustdoc/core.rs4
3 files changed, 61 insertions, 43 deletions
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index fdbed251799..07c940612b1 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<PathResolution> {
-        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<F>(&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<PathResolution> {
+        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<hir::Path, ()> {
+    pub fn resolve_str_path_error(&mut self, span: Span, path_str: &str, is_value: bool) -> Result<hir::Path, ()> {
+        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 {
@@ -1883,8 +1890,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<F>(&mut self, id: NodeId, f: F)
-        where F: FnOnce(&mut Resolver)
+    pub fn with_scope<F, T>(&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
@@ -1895,13 +1902,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 206de77b00e..7daf8a7ae6d 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -472,6 +472,11 @@ impl Clean<Item> 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<Item> = vec![];
         items.extend(self.extern_crates.iter().map(|x| x.clean(cx)));
         items.extend(self.imports.iter().flat_map(|x| x.clean(cx)));
@@ -488,6 +493,8 @@ impl Clean<Item> for doctree::Module {
         items.extend(self.impls.iter().flat_map(|x| x.clean(cx)));
         items.extend(self.macros.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 = {
@@ -847,21 +854,20 @@ impl Clean<Attributes> 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::<Vec<_>>();
-                    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 6fc21f0541b..5fe4794389f 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -23,6 +23,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;
@@ -47,6 +48,8 @@ pub type ExternalPaths = FxHashMap<DefId, (Vec<String>, clean::TypeKind)>;
 pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a> {
     pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
     pub resolver: &'a RefCell<resolve::Resolver<'rcx>>,
+    /// The stack of module NodeIds up till this point
+    pub mod_ids: RefCell<Vec<NodeId>>,
     pub populated_all_crate_impls: Cell<bool>,
     // 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());