]> git.lizzy.rs Git - rust.git/commitdiff
rustc: remove ty::item_path::RootMode by moving local logic into the printer.
authorEduard-Mihai Burtescu <edy.burt@gmail.com>
Mon, 10 Dec 2018 10:59:08 +0000 (12:59 +0200)
committerEduard-Mihai Burtescu <edy.burt@gmail.com>
Fri, 15 Mar 2019 07:26:13 +0000 (09:26 +0200)
src/librustc/ty/item_path.rs
src/librustc/ty/print.rs
src/librustc_codegen_utils/symbol_names.rs
src/librustdoc/clean/mod.rs

index 1eb3952032a6de4044f08fc3a3210ed664d0e614..6f8d0d19103eac598b262e3a2798ec1fcf72a517 100644 (file)
@@ -2,11 +2,11 @@
 use crate::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use crate::ty::{self, DefIdTree, Ty, TyCtxt};
 use crate::middle::cstore::{ExternCrate, ExternCrateSource};
+use ty::print::PrintCx;
 use syntax::ast;
-use syntax::symbol::{keywords, LocalInternedString, Symbol};
+use syntax::symbol::{keywords, Symbol};
 
 use std::cell::Cell;
-use std::fmt::Debug;
 
 thread_local! {
     static FORCE_ABSOLUTE: Cell<bool> = Cell::new(false);
@@ -58,16 +58,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// suitable for user output. It is relative to the current crate
     /// root, unless with_forced_absolute_paths was used.
     pub fn item_path_str(self, def_id: DefId) -> String {
-        let mode = FORCE_ABSOLUTE.with(|force| {
-            if force.get() {
-                RootMode::Absolute
-            } else {
-                RootMode::Local
-            }
-        });
-        let mut printer = LocalPathPrinter::new(mode);
-        debug!("item_path_str: printer={:?} def_id={:?}", printer, def_id);
-        self.print_item_path(&mut printer, def_id)
+        debug!("item_path_str: def_id={:?}", def_id);
+        let mut cx = PrintCx::new(self);
+        if FORCE_ABSOLUTE.with(|force| force.get()) {
+            AbsolutePathPrinter::print_item_path(&mut cx, def_id)
+        } else {
+            LocalPathPrinter::print_item_path(&mut cx, def_id)
+        }
     }
 
     /// Returns a string identifying this local node-id.
@@ -78,246 +75,27 @@ pub fn node_path_str(self, id: ast::NodeId) -> String {
     /// Returns a string identifying this def-id. This string is
     /// suitable for user output. It always begins with a crate identifier.
     pub fn absolute_item_path_str(self, def_id: DefId) -> String {
-        let mut printer = LocalPathPrinter::new(RootMode::Absolute);
-        debug!("absolute_item_path_str: printer={:?} def_id={:?}", printer, def_id);
-        self.print_item_path(&mut printer, def_id)
-    }
-
-    /// Returns the "path" to a particular crate. This can proceed in
-    /// various ways, depending on the `root_mode` of the `printer`.
-    /// (See `RootMode` enum for more details.)
-    fn print_krate_path<P>(
-        self,
-        printer: &mut P,
-        cnum: CrateNum,
-    ) -> P::Path
-        where P: ItemPathPrinter + Debug
-    {
-        debug!(
-            "print_krate_path: printer={:?} cnum={:?} LOCAL_CRATE={:?}",
-            printer, cnum, LOCAL_CRATE
-        );
-        match printer.root_mode() {
-            RootMode::Local => {
-                // In local mode, when we encounter a crate other than
-                // LOCAL_CRATE, execution proceeds in one of two ways:
-                //
-                // 1. for a direct dependency, where user added an
-                //    `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 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 {
-                    match *self.extern_crate(cnum.as_def_id()) {
-                        Some(ExternCrate {
-                            src: ExternCrateSource::Extern(def_id),
-                            direct: true,
-                            span,
-                            ..
-                        }) if !span.is_dummy() => {
-                            debug!("print_krate_path: def_id={:?}", def_id);
-                            self.print_item_path(printer, def_id)
-                        }
-                        _ => {
-                            let name = self.crate_name(cnum).as_str();
-                            debug!("print_krate_path: name={:?}", name);
-                            printer.path_crate(Some(&name))
-                        }
-                    }
-                } else if self.sess.rust_2018() {
-                    // We add the `crate::` keyword on Rust 2018, only when desired.
-                    if SHOULD_PREFIX_WITH_CRATE.with(|flag| flag.get()) {
-                        printer.path_crate(Some(&keywords::Crate.name().as_str()))
-                    } else {
-                        printer.path_crate(None)
-                    }
-                } else {
-                    printer.path_crate(None)
-                }
-            }
-            RootMode::Absolute => {
-                // In absolute mode, just write the crate name
-                // unconditionally.
-                let name = self.original_crate_name(cnum).as_str();
-                debug!("print_krate_path: original_name={:?}", name);
-                printer.path_crate(Some(&name))
-            }
-        }
-    }
-
-    /// If possible, this returns a global path resolving to `external_def_id` that is visible
-    /// from at least one local module and returns true. If the crate defining `external_def_id` is
-    /// declared with an `extern crate`, the path is guaranteed to use the `extern crate`.
-    fn try_print_visible_item_path<P>(
-        self,
-        printer: &mut P,
-        external_def_id: DefId,
-    ) -> Option<P::Path>
-        where P: ItemPathPrinter + Debug
-    {
-        debug!(
-            "try_print_visible_item_path: printer={:?} external_def_id={:?}",
-            printer, external_def_id
-        );
-        let visible_parent_map = self.visible_parent_map(LOCAL_CRATE);
-
-        let (mut cur_def, mut cur_path) = (external_def_id, Vec::<LocalInternedString>::new());
-        loop {
-            debug!(
-                "try_print_visible_item_path: cur_def={:?} cur_path={:?} CRATE_DEF_INDEX={:?}",
-                cur_def, cur_path, CRATE_DEF_INDEX,
-            );
-            // If `cur_def` is a direct or injected extern crate, return the path to the crate
-            // followed by the path to the item within the crate.
-            if cur_def.index == CRATE_DEF_INDEX {
-                match *self.extern_crate(cur_def) {
-                    Some(ExternCrate {
-                        src: ExternCrateSource::Extern(def_id),
-                        direct: true,
-                        span,
-                        ..
-                    }) => {
-                        debug!("try_print_visible_item_path: def_id={:?}", def_id);
-                        let path = if !span.is_dummy() {
-                            self.print_item_path(printer, def_id)
-                        } else {
-                            printer.path_crate(Some(
-                                &self.crate_name(cur_def.krate).as_str(),
-                            ))
-                        };
-                        return Some(cur_path.iter().rev().fold(path, |path, segment| {
-                            printer.path_append(path, &segment)
-                        }));
-                    }
-                    None => {
-                        let path = printer.path_crate(Some(
-                            &self.crate_name(cur_def.krate).as_str(),
-                        ));
-                        return Some(cur_path.iter().rev().fold(path, |path, segment| {
-                            printer.path_append(path, &segment)
-                        }));
-                    }
-                    _ => {},
-                }
-            }
-
-            let mut cur_def_key = self.def_key(cur_def);
-            debug!("try_print_visible_item_path: cur_def_key={:?}", cur_def_key);
-
-            // For a UnitStruct or TupleStruct we want the name of its parent rather than <unnamed>.
-            if let DefPathData::StructCtor = cur_def_key.disambiguated_data.data {
-                let parent = DefId {
-                    krate: cur_def.krate,
-                    index: cur_def_key.parent.expect("DefPathData::StructCtor missing a parent"),
-                };
-
-                cur_def_key = self.def_key(parent);
-            }
-
-            let visible_parent = visible_parent_map.get(&cur_def).cloned();
-            let actual_parent = self.parent(cur_def);
-
-            let data = cur_def_key.disambiguated_data.data;
-            debug!(
-                "try_print_visible_item_path: data={:?} visible_parent={:?} actual_parent={:?}",
-                data, visible_parent, actual_parent,
-            );
-            let symbol = match data {
-                // In order to output a path that could actually be imported (valid and visible),
-                // we need to handle re-exports correctly.
-                //
-                // For example, take `std::os::unix::process::CommandExt`, this trait is actually
-                // defined at `std::sys::unix::ext::process::CommandExt` (at time of writing).
-                //
-                // `std::os::unix` rexports the contents of `std::sys::unix::ext`. `std::sys` is
-                // private so the "true" path to `CommandExt` isn't accessible.
-                //
-                // In this case, the `visible_parent_map` will look something like this:
-                //
-                // (child) -> (parent)
-                // `std::sys::unix::ext::process::CommandExt` -> `std::sys::unix::ext::process`
-                // `std::sys::unix::ext::process` -> `std::sys::unix::ext`
-                // `std::sys::unix::ext` -> `std::os`
-                //
-                // This is correct, as the visible parent of `std::sys::unix::ext` is in fact
-                // `std::os`.
-                //
-                // When printing the path to `CommandExt` and looking at the `cur_def_key` that
-                // corresponds to `std::sys::unix::ext`, we would normally print `ext` and then go
-                // to the parent - resulting in a mangled path like
-                // `std::os::ext::process::CommandExt`.
-                //
-                // Instead, we must detect that there was a re-export and instead print `unix`
-                // (which is the name `std::sys::unix::ext` was re-exported as in `std::os`). To
-                // do this, we compare the parent of `std::sys::unix::ext` (`std::sys::unix`) with
-                // the visible parent (`std::os`). If these do not match, then we iterate over
-                // the children of the visible parent (as was done when computing
-                // `visible_parent_map`), looking for the specific child we currently have and then
-                // have access to the re-exported name.
-                DefPathData::Module(actual_name) |
-                DefPathData::TypeNs(actual_name) if visible_parent != actual_parent => {
-                    visible_parent
-                        .and_then(|parent| {
-                            self.item_children(parent)
-                                .iter()
-                                .find(|child| child.def.def_id() == cur_def)
-                                .map(|child| child.ident.as_str())
-                        })
-                        .unwrap_or_else(|| actual_name.as_str())
-                },
-                _ => {
-                    data.get_opt_name().map(|n| n.as_str()).unwrap_or_else(|| {
-                        // Re-exported `extern crate` (#43189).
-                        if let DefPathData::CrateRoot = data {
-                            self.original_crate_name(cur_def.krate).as_str()
-                        } else {
-                            Symbol::intern("<unnamed>").as_str()
-                        }
-                    })
-                },
-            };
-            debug!("try_print_visible_item_path: symbol={:?}", symbol);
-            cur_path.push(symbol);
-
-            cur_def = visible_parent?;
-        }
+        debug!("absolute_item_path_str: def_id={:?}", def_id);
+        let mut cx = PrintCx::new(self);
+        AbsolutePathPrinter::print_item_path(&mut cx, def_id)
     }
+}
 
-    pub fn print_item_path<P>(
-        self,
-        printer: &mut P,
-        def_id: DefId,
-    ) -> P::Path
-        where P: ItemPathPrinter + Debug
+impl PrintCx<'a, 'gcx, 'tcx> {
+    pub fn default_print_item_path<P>(&mut self, def_id: DefId) -> P::Path
+        where P: ItemPathPrinter
     {
-        debug!(
-            "print_item_path: printer={:?} def_id={:?}",
-            printer, def_id
-        );
-        match printer.root_mode() {
-            RootMode::Local if !def_id.is_local() => {
-                match self.try_print_visible_item_path(printer, def_id) {
-                    Some(path) => return path,
-                    None => {}
-                }
-            }
-            _ => {}
-        }
-
-        let key = self.def_key(def_id);
-        debug!("print_item_path: key={:?}", key);
+        debug!("default_print_item_path: def_id={:?}", def_id);
+        let key = self.tcx.def_key(def_id);
+        debug!("default_print_item_path: key={:?}", key);
         match key.disambiguated_data.data {
             DefPathData::CrateRoot => {
                 assert!(key.parent.is_none());
-                self.print_krate_path(printer, def_id.krate)
+                P::path_crate(self, def_id.krate)
             }
 
             DefPathData::Impl => {
-                self.print_impl_path(printer, def_id)
+                self.default_print_impl_path::<P>(def_id)
             }
 
             // Unclear if there is any value in distinguishing these.
@@ -342,27 +120,23 @@ pub fn print_item_path<P>(
             data @ DefPathData::ClosureExpr |
             data @ DefPathData::ImplTrait |
             data @ DefPathData::GlobalMetaData(..) => {
-                let parent_did = self.parent_def_id(def_id).unwrap();
-                let path = self.print_item_path(printer, parent_did);
-                printer.path_append(path, &data.as_interned_str().as_symbol().as_str())
+                let parent_did = self.tcx.parent_def_id(def_id).unwrap();
+                let path = P::print_item_path(self, parent_did);
+                P::path_append(path, &data.as_interned_str().as_symbol().as_str())
             },
 
             DefPathData::StructCtor => { // present `X` instead of `X::{{constructor}}`
-                let parent_def_id = self.parent_def_id(def_id).unwrap();
-                self.print_item_path(printer, parent_def_id)
+                let parent_def_id = self.tcx.parent_def_id(def_id).unwrap();
+                P::print_item_path(self, parent_def_id)
             }
         }
     }
 
-    fn print_impl_path<P>(
-        self,
-        printer: &mut P,
-        impl_def_id: DefId,
-    ) -> P::Path
-        where P: ItemPathPrinter + Debug
+    fn default_print_impl_path<P>(&mut self, impl_def_id: DefId) -> P::Path
+        where P: ItemPathPrinter
     {
-        debug!("print_impl_path: printer={:?} impl_def_id={:?}", printer, impl_def_id);
-        let parent_def_id = self.parent_def_id(impl_def_id).unwrap();
+        debug!("default_print_impl_path: impl_def_id={:?}", impl_def_id);
+        let parent_def_id = self.tcx.parent_def_id(impl_def_id).unwrap();
 
         // Always use types for non-local impls, where types are always
         // available, and filename/line-number is mostly uninteresting.
@@ -373,7 +147,7 @@ fn print_impl_path<P>(
         };
 
         if !use_types {
-            return self.print_impl_path_fallback(printer, impl_def_id);
+            return self.default_print_impl_path_fallback::<P>(impl_def_id);
         }
 
         // Decide whether to print the parent path for the impl.
@@ -381,27 +155,27 @@ fn print_impl_path<P>(
         // users may find it useful. Currently, we omit the parent if
         // the impl is either in the same module as the self-type or
         // as the trait.
-        let self_ty = self.type_of(impl_def_id);
+        let self_ty = self.tcx.type_of(impl_def_id);
         let in_self_mod = match characteristic_def_id_of_type(self_ty) {
             None => false,
-            Some(ty_def_id) => self.parent_def_id(ty_def_id) == Some(parent_def_id),
+            Some(ty_def_id) => self.tcx.parent_def_id(ty_def_id) == Some(parent_def_id),
         };
 
-        let impl_trait_ref = self.impl_trait_ref(impl_def_id);
+        let impl_trait_ref = self.tcx.impl_trait_ref(impl_def_id);
         let in_trait_mod = match impl_trait_ref {
             None => false,
-            Some(trait_ref) => self.parent_def_id(trait_ref.def_id) == Some(parent_def_id),
+            Some(trait_ref) => self.tcx.parent_def_id(trait_ref.def_id) == Some(parent_def_id),
         };
 
         if !in_self_mod && !in_trait_mod {
             // If the impl is not co-located with either self-type or
             // trait-type, then fallback to a format that identifies
             // the module more clearly.
-            let path = self.print_item_path(printer, parent_def_id);
+            let path = P::print_item_path(self, parent_def_id);
             if let Some(trait_ref) = impl_trait_ref {
-                return printer.path_append(path, &format!("<impl {} for {}>", trait_ref, self_ty));
+                return P::path_append(path, &format!("<impl {} for {}>", trait_ref, self_ty));
             } else {
-                return printer.path_append(path, &format!("<impl {}>", self_ty));
+                return P::path_append(path, &format!("<impl {}>", self_ty));
             }
         }
 
@@ -410,7 +184,7 @@ fn print_impl_path<P>(
 
         if let Some(trait_ref) = impl_trait_ref {
             // Trait impls.
-            return printer.path_impl(&format!("<{} as {}>", self_ty, trait_ref));
+            return P::path_impl(self, &format!("<{} as {}>", self_ty, trait_ref));
         }
 
         // Inherent impls. Try to print `Foo::bar` for an inherent
@@ -420,13 +194,13 @@ fn print_impl_path<P>(
             ty::Adt(adt_def, substs) => {
                 // FIXME(eddyb) always print without <> here.
                 if substs.types().next().is_none() { // ignore regions
-                    self.print_item_path(printer, adt_def.did)
+                    P::print_item_path(self, adt_def.did)
                 } else {
-                    printer.path_impl(&format!("<{}>", self_ty))
+                    P::path_impl(self, &format!("<{}>", self_ty))
                 }
             }
 
-            ty::Foreign(did) => self.print_item_path(printer, did),
+            ty::Foreign(did) => P::print_item_path(self, did),
 
             ty::Bool |
             ty::Char |
@@ -434,33 +208,32 @@ fn print_impl_path<P>(
             ty::Uint(_) |
             ty::Float(_) |
             ty::Str => {
-                printer.path_impl(&self_ty.to_string())
+                P::path_impl(self, &self_ty.to_string())
             }
 
             _ => {
-                printer.path_impl(&format!("<{}>", self_ty))
+                P::path_impl(self, &format!("<{}>", self_ty))
             }
         }
     }
 
-    fn print_impl_path_fallback<P>(
-        self,
-        printer: &mut P,
-        impl_def_id: DefId,
-    ) -> P::Path
-        where P: ItemPathPrinter + Debug
+    fn default_print_impl_path_fallback<P>(&mut self, impl_def_id: DefId) -> P::Path
+        where P: ItemPathPrinter
     {
         // If no type info is available, fall back to
         // pretty printing some span information. This should
         // only occur very early in the compiler pipeline.
-        let parent_def_id = self.parent_def_id(impl_def_id).unwrap();
-        let path = self.print_item_path(printer, parent_def_id);
-        let hir_id = self.hir().as_local_hir_id(impl_def_id).unwrap();
-        let item = self.hir().expect_item_by_hir_id(hir_id);
-        let span_str = self.sess.source_map().span_to_string(item.span);
-        printer.path_append(path, &format!("<impl at {}>", span_str))
+        // FIXME(eddyb) this should just be using `tcx.def_span(impl_def_id)`
+        let parent_def_id = self.tcx.parent_def_id(impl_def_id).unwrap();
+        let path = P::print_item_path(self, parent_def_id);
+        let hir_id = self.tcx.hir().as_local_hir_id(impl_def_id).unwrap();
+        let item = self.tcx.hir().expect_item_by_hir_id(hir_id);
+        let span_str = self.tcx.sess.source_map().span_to_string(item.span);
+        P::path_append(path, &format!("<impl at {}>", span_str))
     }
+}
 
+impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// Returns the `DefId` of `def_id`'s parent in the def tree. If
     /// this returns `None`, then `def_id` represents a crate root or
     /// inlined root.
@@ -519,58 +292,202 @@ pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> {
 }
 
 /// Unifying Trait for different kinds of item paths we might
-/// construct. The basic interface is that components get pushed: the
-/// instance can also customize how we handle the root of a crate.
-pub trait ItemPathPrinter {
+/// construct. The basic interface is that components get appended.
+pub trait ItemPathPrinter: Sized {
     type Path;
 
-    fn root_mode(&self) -> RootMode;
+    fn print_item_path(cx: &mut PrintCx<'_, '_, '_>, def_id: DefId) -> Self::Path {
+        cx.default_print_item_path::<Self>(def_id)
+    }
 
-    fn path_crate(&self, name: Option<&str>) -> Self::Path;
-    fn path_impl(&self, text: &str) -> Self::Path;
-    fn path_append(&self, path: Self::Path, text: &str) -> Self::Path;
+    fn path_crate(cx: &mut PrintCx<'_, '_, '_>, cnum: CrateNum) -> Self::Path;
+    fn path_impl(cx: &mut PrintCx<'_, '_, '_>, text: &str) -> Self::Path;
+    fn path_append(path: Self::Path, text: &str) -> Self::Path;
 }
 
-#[derive(Copy, Clone, Debug)]
-pub enum RootMode {
-    /// Try to make a path relative to the local crate. In
-    /// particular, local paths have no prefix, and if the path comes
-    /// from an extern crate, start with the path to the `extern
-    /// crate` declaration.
-    Local,
-
-    /// Always prepend the crate name to the path, forming an absolute
-    /// path from within a given set of crates.
-    Absolute,
-}
+struct AbsolutePathPrinter;
+
+impl ItemPathPrinter for AbsolutePathPrinter {
+    type Path = String;
 
-#[derive(Debug)]
-struct LocalPathPrinter {
-    root_mode: RootMode,
+    fn path_crate(cx: &mut PrintCx<'_, '_, '_>, cnum: CrateNum) -> Self::Path {
+        cx.tcx.original_crate_name(cnum).to_string()
+    }
+    fn path_impl(_cx: &mut PrintCx<'_, '_, '_>, text: &str) -> Self::Path {
+        text.to_string()
+    }
+    fn path_append(mut path: Self::Path, text: &str) -> Self::Path {
+        if !path.is_empty() {
+            path.push_str("::");
+        }
+        path.push_str(text);
+        path
+    }
 }
 
+struct LocalPathPrinter;
+
 impl LocalPathPrinter {
-    fn new(root_mode: RootMode) -> LocalPathPrinter {
-        LocalPathPrinter {
-            root_mode,
+    /// If possible, this returns a global path resolving to `def_id` that is visible
+    /// from at least one local module and returns true. If the crate defining `def_id` is
+    /// declared with an `extern crate`, the path is guaranteed to use the `extern crate`.
+    fn try_print_visible_item_path(
+        cx: &mut PrintCx<'_, '_, '_>,
+        def_id: DefId,
+    ) -> Option<<Self as ItemPathPrinter>::Path> {
+        debug!("try_print_visible_item_path: def_id={:?}", def_id);
+
+        // If `def_id` is a direct or injected extern crate, return the
+        // path to the crate followed by the path to the item within the crate.
+        if def_id.index == CRATE_DEF_INDEX {
+            let cnum = def_id.krate;
+
+            if cnum == LOCAL_CRATE {
+                return Some(Self::path_crate(cx, cnum));
+            }
+
+            // In local mode, when we encounter a crate other than
+            // LOCAL_CRATE, execution proceeds in one of two ways:
+            //
+            // 1. for a direct dependency, where user added an
+            //    `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 extern inferred from a path or an indirect crate,
+            //    where there is no explicit `extern crate`, we just prepend
+            //    the crate name.
+            match *cx.tcx.extern_crate(def_id) {
+                Some(ExternCrate {
+                    src: ExternCrateSource::Extern(def_id),
+                    direct: true,
+                    span,
+                    ..
+                }) => {
+                    debug!("try_print_visible_item_path: def_id={:?}", def_id);
+                    let path = if !span.is_dummy() {
+                        Self::print_item_path(cx, def_id)
+                    } else {
+                        Self::path_crate(cx, cnum)
+                    };
+                    return Some(path);
+                }
+                None => {
+                    return Some(Self::path_crate(cx, cnum));
+                }
+                _ => {},
+            }
         }
+
+        if def_id.is_local() {
+            return None;
+        }
+
+        let visible_parent_map = cx.tcx.visible_parent_map(LOCAL_CRATE);
+
+        let mut cur_def_key = cx.tcx.def_key(def_id);
+        debug!("try_print_visible_item_path: cur_def_key={:?}", cur_def_key);
+
+        // For a UnitStruct or TupleStruct we want the name of its parent rather than <unnamed>.
+        if let DefPathData::StructCtor = cur_def_key.disambiguated_data.data {
+            let parent = DefId {
+                krate: def_id.krate,
+                index: cur_def_key.parent.expect("DefPathData::StructCtor missing a parent"),
+            };
+
+            cur_def_key = cx.tcx.def_key(parent);
+        }
+
+        let visible_parent = visible_parent_map.get(&def_id).cloned()?;
+        let path = Self::try_print_visible_item_path(cx, visible_parent)?;
+        let actual_parent = cx.tcx.parent(def_id);
+
+        let data = cur_def_key.disambiguated_data.data;
+        debug!(
+            "try_print_visible_item_path: data={:?} visible_parent={:?} actual_parent={:?}",
+            data, visible_parent, actual_parent,
+        );
+
+        let symbol = match data {
+            // In order to output a path that could actually be imported (valid and visible),
+            // we need to handle re-exports correctly.
+            //
+            // For example, take `std::os::unix::process::CommandExt`, this trait is actually
+            // defined at `std::sys::unix::ext::process::CommandExt` (at time of writing).
+            //
+            // `std::os::unix` rexports the contents of `std::sys::unix::ext`. `std::sys` is
+            // private so the "true" path to `CommandExt` isn't accessible.
+            //
+            // In this case, the `visible_parent_map` will look something like this:
+            //
+            // (child) -> (parent)
+            // `std::sys::unix::ext::process::CommandExt` -> `std::sys::unix::ext::process`
+            // `std::sys::unix::ext::process` -> `std::sys::unix::ext`
+            // `std::sys::unix::ext` -> `std::os`
+            //
+            // This is correct, as the visible parent of `std::sys::unix::ext` is in fact
+            // `std::os`.
+            //
+            // When printing the path to `CommandExt` and looking at the `cur_def_key` that
+            // corresponds to `std::sys::unix::ext`, we would normally print `ext` and then go
+            // to the parent - resulting in a mangled path like
+            // `std::os::ext::process::CommandExt`.
+            //
+            // Instead, we must detect that there was a re-export and instead print `unix`
+            // (which is the name `std::sys::unix::ext` was re-exported as in `std::os`). To
+            // do this, we compare the parent of `std::sys::unix::ext` (`std::sys::unix`) with
+            // the visible parent (`std::os`). If these do not match, then we iterate over
+            // the children of the visible parent (as was done when computing
+            // `visible_parent_map`), looking for the specific child we currently have and then
+            // have access to the re-exported name.
+            DefPathData::Module(actual_name) |
+            DefPathData::TypeNs(actual_name) if Some(visible_parent) != actual_parent => {
+                cx.tcx.item_children(visible_parent)
+                    .iter()
+                    .find(|child| child.def.def_id() == def_id)
+                    .map(|child| child.ident.as_str())
+                    .unwrap_or_else(|| actual_name.as_str())
+            }
+            _ => {
+                data.get_opt_name().map(|n| n.as_str()).unwrap_or_else(|| {
+                    // Re-exported `extern crate` (#43189).
+                    if let DefPathData::CrateRoot = data {
+                        cx.tcx.original_crate_name(def_id.krate).as_str()
+                    } else {
+                        Symbol::intern("<unnamed>").as_str()
+                    }
+                })
+            },
+        };
+        debug!("try_print_visible_item_path: symbol={:?}", symbol);
+        Some(Self::path_append(path, &symbol))
     }
 }
 
 impl ItemPathPrinter for LocalPathPrinter {
     type Path = String;
 
-    fn root_mode(&self) -> RootMode {
-        self.root_mode
+    fn print_item_path(cx: &mut PrintCx<'_, '_, '_>, def_id: DefId) -> Self::Path {
+        Self::try_print_visible_item_path(cx, def_id)
+            .unwrap_or_else(|| cx.default_print_item_path::<Self>(def_id))
     }
 
-    fn path_crate(&self, name: Option<&str>) -> Self::Path {
-        name.unwrap_or("").to_string()
+    fn path_crate(cx: &mut PrintCx<'_, '_, '_>, cnum: CrateNum) -> Self::Path {
+        if cnum == LOCAL_CRATE {
+            if cx.tcx.sess.rust_2018() {
+                // We add the `crate::` keyword on Rust 2018, only when desired.
+                if SHOULD_PREFIX_WITH_CRATE.with(|flag| flag.get()) {
+                    return keywords::Crate.name().to_string();
+                }
+            }
+            String::new()
+        } else {
+            cx.tcx.crate_name(cnum).to_string()
+        }
     }
-    fn path_impl(&self, text: &str) -> Self::Path {
+    fn path_impl(_cx: &mut PrintCx<'_, '_, '_>, text: &str) -> Self::Path {
         text.to_string()
     }
-    fn path_append(&self, mut path: Self::Path, text: &str) -> Self::Path {
+    fn path_append(mut path: Self::Path, text: &str) -> Self::Path {
         if !path.is_empty() {
             path.push_str("::");
         }
index a9fffa2ee87b1ca08a77e6fada06412d5971b7a3..81101740a4cc962d508590f91bbeed51b338eadd 100644 (file)
@@ -22,7 +22,7 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
 }
 
 pub struct PrintCx<'a, 'gcx, 'tcx> {
-    pub(crate) tcx: TyCtxt<'a, 'gcx, 'tcx>,
+    pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
     pub(crate) is_debug: bool,
     pub(crate) is_verbose: bool,
     pub(crate) identify_regions: bool,
@@ -32,18 +32,20 @@ pub struct PrintCx<'a, 'gcx, 'tcx> {
 }
 
 impl PrintCx<'a, 'gcx, 'tcx> {
+    pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Self {
+        PrintCx {
+            tcx,
+            is_debug: false,
+            is_verbose: tcx.sess.verbose(),
+            identify_regions: tcx.sess.opts.debugging_opts.identify_regions,
+            used_region_names: None,
+            region_index: 0,
+            binder_depth: 0,
+        }
+    }
+
     pub(crate) fn with<R>(f: impl FnOnce(PrintCx<'_, '_, '_>) -> R) -> R {
-        ty::tls::with(|tcx| {
-            f(PrintCx {
-                tcx,
-                is_debug: false,
-                is_verbose: tcx.sess.verbose(),
-                identify_regions: tcx.sess.opts.debugging_opts.identify_regions,
-                used_region_names: None,
-                region_index: 0,
-                binder_depth: 0,
-            })
-        })
+        ty::tls::with(|tcx| f(PrintCx::new(tcx)))
     }
     pub(crate) fn prepare_late_bound_region_info<T>(&mut self, value: &ty::Binder<T>)
     where T: TypeFoldable<'tcx>
index 13f8e13c3288d163a1d6a605cf53ef69da0c57be..56ef15b12a0a9585bd7076a58854f65cffb03f3a 100644 (file)
 //! virtually impossible. Thus, symbol hash generation exclusively relies on
 //! DefPaths which are much more robust in the face of changes to the code base.
 
-use rustc::hir::def_id::{DefId, LOCAL_CRATE};
+use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc::hir::Node;
 use rustc::hir::CodegenFnAttrFlags;
 use rustc::hir::map::definitions::DefPathData;
 use rustc::ich::NodeIdHashingMode;
-use rustc::ty::item_path::{self, ItemPathPrinter, RootMode};
+use rustc::ty::item_path::{self, ItemPathPrinter};
+use rustc::ty::print::PrintCx;
 use rustc::ty::query::Providers;
 use rustc::ty::subst::SubstsRef;
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
@@ -224,7 +225,8 @@ fn get_symbol_hash<'a, 'tcx>(
 
 fn def_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::SymbolName {
     item_path::with_forced_absolute_paths(|| {
-        tcx.push_item_path(&mut SymbolPath::new(tcx), def_id).into_interned()
+        let mut cx = PrintCx::new(tcx);
+        SymbolPathPrinter::print_item_path(&mut cx, def_id).into_interned()
     })
 }
 
@@ -394,29 +396,22 @@ fn finish(mut self, hash: u64) -> String {
     }
 }
 
-#[derive(Debug)]
 struct SymbolPathPrinter;
 
 impl ItemPathPrinter for SymbolPathPrinter {
     type Path = SymbolPath;
 
-    fn root_mode(&self) ->RootMode {
-        RootMode::Absolute
-    }
-
-    fn path_crate(&self, name: Option<&str>) -> Self::Path {
-        let mut path = SymbolPath::new();
-        if let Some(name) = name {
-            path.push(name);
-        }
+    fn path_crate(cx: &mut PrintCx<'_, '_, '_>, cnum: CrateNum) -> Self::Path {
+        let mut path = SymbolPath::new(cx.tcx);
+        path.push(&cx.tcx.original_crate_name(cnum).as_str());
         path
     }
-    fn path_impl(&self, text: &str) -> Self::Path {
-        let mut path = SymbolPath::new();
+    fn path_impl(cx: &mut PrintCx<'_, '_, '_>, text: &str) -> Self::Path {
+        let mut path = SymbolPath::new(cx.tcx);
         path.push(text);
         path
     }
-    fn path_append(&self, mut path: Self::Path, text: &str) -> Self::Path {
+    fn path_append(mut path: Self::Path, text: &str) -> Self::Path {
         path.push(text);
         path
     }
index af40e417d6108fb1872e6975d1d1f83ff9ecad74..ed7f1bbe7e6ac7f74bccc12fcaceda61dd580434 100644 (file)
@@ -4225,30 +4225,33 @@ pub fn path_to_def(tcx: &TyCtxt<'_, '_, '_>, path: &[&str]) -> Option<DefId> {
 
 pub fn get_path_for_type<F>(tcx: TyCtxt<'_, '_, '_>, def_id: DefId, def_ctor: F) -> hir::Path
 where F: Fn(DefId) -> Def {
-    #[derive(Debug)]
-    struct AbsolutePathBuffer {
-        names: Vec<String>,
-    }
+    use rustc::ty::item_path::ItemPathPrinter;
+    use rustc::ty::print::PrintCx;
 
-    impl ty::item_path::ItemPathBuffer for AbsolutePathBuffer {
-        fn root_mode(&self) -> &ty::item_path::RootMode {
-            const ABSOLUTE: &'static ty::item_path::RootMode = &ty::item_path::RootMode::Absolute;
-            ABSOLUTE
-        }
+    struct AbsolutePathPrinter;
+
+    impl ItemPathPrinter for AbsolutePathPrinter {
+        type Path = Vec<String>;
 
-        fn push(&mut self, text: &str) {
-            self.names.push(text.to_owned());
+        fn path_crate(cx: &mut PrintCx<'_, '_, '_>, cnum: CrateNum) -> Self::Path {
+            vec![cx.tcx.original_crate_name(cnum).to_string()]
+        }
+        fn path_impl(_: &mut PrintCx<'_, '_, '_>, text: &str) -> Self::Path {
+            vec![text.to_string()]
+        }
+        fn path_append(mut path: Self::Path, text: &str) -> Self::Path {
+            path.push(text.to_string());
+            path
         }
     }
 
-    let mut apb = AbsolutePathBuffer { names: vec![] };
-
-    tcx.push_item_path(&mut apb, def_id);
+    let mut cx = PrintCx::new(tcx);
+    let names = AbsolutePathPrinter::print_item_path(&mut cx, def_id);
 
     hir::Path {
         span: DUMMY_SP,
         def: def_ctor(def_id),
-        segments: hir::HirVec::from_vec(apb.names.iter().map(|s| hir::PathSegment {
+        segments: hir::HirVec::from_vec(names.iter().map(|s| hir::PathSegment {
             ident: ast::Ident::from_str(&s),
             hir_id: None,
             def: None,