From 9f8aaa04e02c74209e3ea355d8888cbc59a8fb64 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 19 Dec 2018 13:25:31 +0200 Subject: [PATCH] rustc: move the contents of ty::item_path to ty::print. --- src/librustc/ty/item_path.rs | 560 ------------------ src/librustc/ty/mod.rs | 1 - src/librustc/ty/print.rs | 560 +++++++++++++++++- src/librustc/ty/query/plumbing.rs | 5 +- src/librustc_codegen_utils/symbol_names.rs | 7 +- src/librustc_mir/monomorphize/partitioning.rs | 2 +- src/librustc_mir/util/liveness.rs | 4 +- src/librustc_mir/util/pretty.rs | 7 +- src/librustc_typeck/check/method/suggest.rs | 2 +- src/librustdoc/clean/mod.rs | 5 +- 10 files changed, 573 insertions(+), 580 deletions(-) delete mode 100644 src/librustc/ty/item_path.rs diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs deleted file mode 100644 index 9f34f475eff..00000000000 --- a/src/librustc/ty/item_path.rs +++ /dev/null @@ -1,560 +0,0 @@ -use crate::hir::def::Namespace; -use crate::hir::map::DefPathData; -use crate::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; -use crate::ty::{self, DefIdTree, Ty, TyCtxt}; -use crate::ty::print::PrintCx; -use crate::ty::subst::{Subst, SubstsRef}; -use crate::middle::cstore::{ExternCrate, ExternCrateSource}; -use syntax::ast; -use syntax::symbol::{keywords, Symbol}; - -use std::cell::Cell; - -thread_local! { - static FORCE_ABSOLUTE: Cell = Cell::new(false); - static FORCE_IMPL_FILENAME_LINE: Cell = Cell::new(false); - static SHOULD_PREFIX_WITH_CRATE: Cell = Cell::new(false); -} - -/// Enforces that def_path_str always returns an absolute path and -/// also enables "type-based" impl paths. This is used when building -/// symbols that contain types, where we want the crate name to be -/// part of the symbol. -pub fn with_forced_absolute_paths R, R>(f: F) -> R { - FORCE_ABSOLUTE.with(|force| { - let old = force.get(); - force.set(true); - let result = f(); - force.set(old); - result - }) -} - -/// Force us to name impls with just the filename/line number. We -/// normally try to use types. But at some points, notably while printing -/// cycle errors, this can result in extra or suboptimal error output, -/// so this variable disables that check. -pub fn with_forced_impl_filename_line R, R>(f: F) -> R { - FORCE_IMPL_FILENAME_LINE.with(|force| { - let old = force.get(); - force.set(true); - let result = f(); - force.set(old); - result - }) -} - -/// Adds the `crate::` prefix to paths where appropriate. -pub fn with_crate_prefix R, R>(f: F) -> R { - SHOULD_PREFIX_WITH_CRATE.with(|flag| { - let old = flag.get(); - flag.set(true); - let result = f(); - flag.set(old); - result - }) -} - -impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { - // HACK(eddyb) get rid of `def_path_str` and/or pass `Namespace` explicitly always - // (but also some things just print a `DefId` generally so maybe we need this?) - fn guess_def_namespace(self, def_id: DefId) -> Namespace { - match self.def_key(def_id).disambiguated_data.data { - DefPathData::ValueNs(..) | - DefPathData::EnumVariant(..) | - DefPathData::Field(..) | - DefPathData::AnonConst | - DefPathData::ClosureExpr | - DefPathData::StructCtor => Namespace::ValueNS, - - DefPathData::MacroDef(..) => Namespace::MacroNS, - - _ => Namespace::TypeNS, - } - } - - /// Returns a string identifying this `DefId`. This string is - /// suitable for user output. It is relative to the current crate - /// root, unless with_forced_absolute_paths was used. - pub fn def_path_str_with_substs_and_ns( - self, - def_id: DefId, - substs: Option>, - ns: Namespace, - ) -> String { - debug!("def_path_str: def_id={:?}, substs={:?}, ns={:?}", def_id, substs, ns); - if FORCE_ABSOLUTE.with(|force| force.get()) { - PrintCx::new(self, AbsolutePathPrinter).print_def_path(def_id, substs, ns) - } else { - PrintCx::new(self, LocalPathPrinter).print_def_path(def_id, substs, ns) - } - } - - /// Returns a string identifying this def-id. This string is - /// suitable for user output. It is relative to the current crate - /// root, unless with_forced_absolute_paths was used. - pub fn def_path_str(self, def_id: DefId) -> String { - let ns = self.guess_def_namespace(def_id); - self.def_path_str_with_substs_and_ns(def_id, None, ns) - } - - /// Returns a string identifying this local node-id. - pub fn node_path_str(self, id: ast::NodeId) -> String { - self.def_path_str(self.hir().local_def_id(id)) - } - - /// Returns a string identifying this def-id. This string is - /// suitable for user output. It always begins with a crate identifier. - pub fn absolute_def_path_str(self, def_id: DefId) -> String { - debug!("absolute_def_path_str: def_id={:?}", def_id); - let ns = self.guess_def_namespace(def_id); - PrintCx::new(self, AbsolutePathPrinter).print_def_path(def_id, None, ns) - } -} - -impl PrintCx<'a, 'gcx, 'tcx, P> { - pub fn default_print_def_path( - &mut self, - def_id: DefId, - substs: Option>, - ns: Namespace, - ) -> P::Path { - debug!("default_print_def_path: def_id={:?}, substs={:?}, ns={:?}", def_id, substs, ns); - let key = self.tcx.def_key(def_id); - debug!("default_print_def_path: key={:?}", key); - match key.disambiguated_data.data { - DefPathData::CrateRoot => { - assert!(key.parent.is_none()); - self.path_crate(def_id.krate) - } - - DefPathData::Impl => { - self.print_impl_path(def_id, substs, ns) - } - - // Unclear if there is any value in distinguishing these. - // Probably eventually (and maybe we would even want - // finer-grained distinctions, e.g., between enum/struct). - data @ DefPathData::Misc | - data @ DefPathData::TypeNs(..) | - data @ DefPathData::Trait(..) | - data @ DefPathData::TraitAlias(..) | - data @ DefPathData::AssocTypeInTrait(..) | - data @ DefPathData::AssocTypeInImpl(..) | - data @ DefPathData::AssocExistentialInImpl(..) | - data @ DefPathData::ValueNs(..) | - data @ DefPathData::Module(..) | - data @ DefPathData::TypeParam(..) | - data @ DefPathData::LifetimeParam(..) | - data @ DefPathData::ConstParam(..) | - data @ DefPathData::EnumVariant(..) | - data @ DefPathData::Field(..) | - data @ DefPathData::AnonConst | - data @ DefPathData::MacroDef(..) | - data @ DefPathData::ClosureExpr | - data @ DefPathData::ImplTrait | - data @ DefPathData::GlobalMetaData(..) => { - let parent_did = self.tcx.parent(def_id).unwrap(); - let path = self.print_def_path(parent_did, None, ns); - self.path_append(path, &data.as_interned_str().as_symbol().as_str()) - }, - - DefPathData::StructCtor => { // present `X` instead of `X::{{constructor}}` - let parent_def_id = self.tcx.parent(def_id).unwrap(); - self.print_def_path(parent_def_id, substs, ns) - } - } - } - - fn default_print_impl_path( - &mut self, - impl_def_id: DefId, - substs: Option>, - ns: Namespace, - ) -> P::Path { - debug!("default_print_impl_path: impl_def_id={:?}", impl_def_id); - let parent_def_id = self.tcx.parent(impl_def_id).unwrap(); - - // Decide whether to print the parent path for the impl. - // Logically, since impls are global, it's never needed, but - // 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 mut self_ty = self.tcx.type_of(impl_def_id); - if let Some(substs) = substs { - self_ty = self_ty.subst(self.tcx, substs); - } - let in_self_mod = match characteristic_def_id_of_type(self_ty) { - None => false, - Some(ty_def_id) => self.tcx.parent(ty_def_id) == Some(parent_def_id), - }; - - let mut impl_trait_ref = self.tcx.impl_trait_ref(impl_def_id); - if let Some(substs) = substs { - impl_trait_ref = impl_trait_ref.subst(self.tcx, substs); - } - let in_trait_mod = match impl_trait_ref { - None => false, - Some(trait_ref) => self.tcx.parent(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_def_path(parent_def_id, None, ns); - if let Some(trait_ref) = impl_trait_ref { - return self.path_append(path, &format!("", trait_ref, self_ty)); - } else { - return self.path_append(path, &format!("", self_ty)); - } - } - - // Otherwise, try to give a good form that would be valid language - // syntax. Preferably using associated item notation. - - if let Some(trait_ref) = impl_trait_ref { - // Trait impls. - return self.path_impl(&format!("<{} as {}>", self_ty, trait_ref)); - } - - // Inherent impls. Try to print `Foo::bar` for an inherent - // impl on `Foo`, but fallback to `::bar` if self-type is - // anything other than a simple path. - match self_ty.sty { - ty::Adt(adt_def, substs) => { - // FIXME(eddyb) this should recurse to build the path piecewise. - // self.print_def_path(adt_def.did, Some(substs), ns) - let mut s = String::new(); - crate::util::ppaux::parameterized(&mut s, adt_def.did, substs, ns).unwrap(); - self.path_impl(&s) - } - - ty::Foreign(did) => self.print_def_path(did, None, ns), - - ty::Bool | - ty::Char | - ty::Int(_) | - ty::Uint(_) | - ty::Float(_) | - ty::Str => { - self.path_impl(&self_ty.to_string()) - } - - _ => { - self.path_impl(&format!("<{}>", self_ty)) - } - } - } -} - -/// As a heuristic, when we see an impl, if we see that the -/// 'self type' is a type defined in the same module as the impl, -/// we can omit including the path to the impl itself. This -/// function tries to find a "characteristic `DefId`" for a -/// type. It's just a heuristic so it makes some questionable -/// decisions and we may want to adjust it later. -pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option { - match ty.sty { - ty::Adt(adt_def, _) => Some(adt_def.did), - - ty::Dynamic(data, ..) => data.principal_def_id(), - - ty::Array(subty, _) | - ty::Slice(subty) => characteristic_def_id_of_type(subty), - - ty::RawPtr(mt) => characteristic_def_id_of_type(mt.ty), - - ty::Ref(_, ty, _) => characteristic_def_id_of_type(ty), - - ty::Tuple(ref tys) => tys.iter() - .filter_map(|ty| characteristic_def_id_of_type(ty)) - .next(), - - ty::FnDef(def_id, _) | - ty::Closure(def_id, _) | - ty::Generator(def_id, _, _) | - ty::Foreign(def_id) => Some(def_id), - - ty::Bool | - ty::Char | - ty::Int(_) | - ty::Uint(_) | - ty::Str | - ty::FnPtr(_) | - ty::Projection(_) | - ty::Placeholder(..) | - ty::UnnormalizedProjection(..) | - ty::Param(_) | - ty::Opaque(..) | - ty::Infer(_) | - ty::Bound(..) | - ty::Error | - ty::GeneratorWitness(..) | - ty::Never | - ty::Float(_) => None, - } -} - -/// Unifying Trait for different kinds of item paths we might -/// construct. The basic interface is that components get appended. -pub trait ItemPathPrinter: Sized { - type Path; - - fn print_def_path( - self: &mut PrintCx<'_, '_, 'tcx, Self>, - def_id: DefId, - substs: Option>, - ns: Namespace, - ) -> Self::Path { - self.default_print_def_path(def_id, substs, ns) - } - fn print_impl_path( - self: &mut PrintCx<'_, '_, 'tcx, Self>, - impl_def_id: DefId, - substs: Option>, - ns: Namespace, - ) -> Self::Path { - self.default_print_impl_path(impl_def_id, substs, ns) - } - - fn path_crate(self: &mut PrintCx<'_, '_, '_, Self>, cnum: CrateNum) -> Self::Path; - fn path_impl(self: &mut PrintCx<'_, '_, '_, Self>, text: &str) -> Self::Path; - fn path_append( - self: &mut PrintCx<'_, '_, '_, Self>, - path: Self::Path, - text: &str, - ) -> Self::Path; -} - -struct AbsolutePathPrinter; - -impl ItemPathPrinter for AbsolutePathPrinter { - type Path = String; - - fn path_crate(self: &mut PrintCx<'_, '_, '_, Self>, cnum: CrateNum) -> Self::Path { - self.tcx.original_crate_name(cnum).to_string() - } - fn path_impl(self: &mut PrintCx<'_, '_, '_, Self>, text: &str) -> Self::Path { - text.to_string() - } - fn path_append( - self: &mut PrintCx<'_, '_, '_, Self>, - mut path: Self::Path, - text: &str, - ) -> Self::Path { - if !path.is_empty() { - path.push_str("::"); - } - path.push_str(text); - path - } -} - -struct LocalPathPrinter; - -impl LocalPathPrinter { - /// 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_def_path( - self: &mut PrintCx<'_, '_, '_, Self>, - def_id: DefId, - ns: Namespace, - ) -> Option<::Path> { - debug!("try_print_visible_def_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(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 *self.tcx.extern_crate(def_id) { - Some(ExternCrate { - src: ExternCrateSource::Extern(def_id), - direct: true, - span, - .. - }) => { - debug!("try_print_visible_def_path: def_id={:?}", def_id); - let path = if !span.is_dummy() { - self.print_def_path(def_id, None, ns) - } else { - self.path_crate(cnum) - }; - return Some(path); - } - None => { - return Some(self.path_crate(cnum)); - } - _ => {}, - } - } - - if def_id.is_local() { - return None; - } - - let visible_parent_map = self.tcx.visible_parent_map(LOCAL_CRATE); - - let mut cur_def_key = self.tcx.def_key(def_id); - debug!("try_print_visible_def_path: cur_def_key={:?}", cur_def_key); - - // For a UnitStruct or TupleStruct we want the name of its parent rather than . - 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 = self.tcx.def_key(parent); - } - - let visible_parent = visible_parent_map.get(&def_id).cloned()?; - let path = self.try_print_visible_def_path(visible_parent, ns)?; - let actual_parent = self.tcx.parent(def_id); - - let data = cur_def_key.disambiguated_data.data; - debug!( - "try_print_visible_def_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 => { - self.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 { - self.tcx.original_crate_name(def_id.krate).as_str() - } else { - Symbol::intern("").as_str() - } - }) - }, - }; - debug!("try_print_visible_def_path: symbol={:?}", symbol); - Some(self.path_append(path, &symbol)) - } -} - -impl ItemPathPrinter for LocalPathPrinter { - type Path = String; - - fn print_def_path( - self: &mut PrintCx<'_, '_, 'tcx, Self>, - def_id: DefId, - substs: Option>, - ns: Namespace, - ) -> Self::Path { - self.try_print_visible_def_path(def_id, ns) - .unwrap_or_else(|| self.default_print_def_path(def_id, substs, ns)) - } - fn print_impl_path( - self: &mut PrintCx<'_, '_, 'tcx, Self>, - impl_def_id: DefId, - substs: Option>, - ns: Namespace, - ) -> Self::Path { - // Always use types for non-local impls, where types are always - // available, and filename/line-number is mostly uninteresting. - let use_types = !impl_def_id.is_local() || { - // Otherwise, use filename/line-number if forced. - let force_no_types = FORCE_IMPL_FILENAME_LINE.with(|f| f.get()); - !force_no_types - }; - - if !use_types { - // If no type info is available, fall back to - // pretty printing some span information. This should - // only occur very early in the compiler pipeline. - // FIXME(eddyb) this should just be using `tcx.def_span(impl_def_id)` - let parent_def_id = self.tcx.parent(impl_def_id).unwrap(); - let path = self.print_def_path(parent_def_id, None, ns); - let span = self.tcx.def_span(impl_def_id); - return self.path_append(path, &format!("", span)); - } - - self.default_print_impl_path(impl_def_id, substs, ns) - } - - fn path_crate(self: &mut PrintCx<'_, '_, '_, Self>, cnum: CrateNum) -> Self::Path { - if cnum == LOCAL_CRATE { - if self.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 { - self.tcx.crate_name(cnum).to_string() - } - } - fn path_impl(self: &mut PrintCx<'_, '_, '_, Self>, text: &str) -> Self::Path { - text.to_string() - } - fn path_append( - self: &mut PrintCx<'_, '_, '_, Self>, - mut path: Self::Path, - text: &str, - ) -> Self::Path { - if !path.is_empty() { - path.push_str("::"); - } - path.push_str(text); - path - } -} diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 4f933bf0d53..882e2dc62b1 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -95,7 +95,6 @@ pub mod fast_reject; pub mod fold; pub mod inhabitedness; -pub mod item_path; pub mod layout; pub mod _match; pub mod outlives; diff --git a/src/librustc/ty/print.rs b/src/librustc/ty/print.rs index a1d93bc4140..053a7531cad 100644 --- a/src/librustc/ty/print.rs +++ b/src/librustc/ty/print.rs @@ -1,11 +1,64 @@ -use crate::ty::{self, TyCtxt, TypeFoldable}; +use crate::hir::def::Namespace; +use crate::hir::map::DefPathData; +use crate::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; +use crate::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable}; +use crate::ty::subst::{Subst, SubstsRef}; +use crate::middle::cstore::{ExternCrate, ExternCrateSource}; +use syntax::ast; +use syntax::symbol::{keywords, Symbol}; use rustc_data_structures::fx::FxHashSet; use syntax::symbol::InternedString; +use std::cell::Cell; use std::fmt; use std::ops::Deref; +thread_local! { + static FORCE_ABSOLUTE: Cell = Cell::new(false); + static FORCE_IMPL_FILENAME_LINE: Cell = Cell::new(false); + static SHOULD_PREFIX_WITH_CRATE: Cell = Cell::new(false); +} + +/// Enforces that def_path_str always returns an absolute path and +/// also enables "type-based" impl paths. This is used when building +/// symbols that contain types, where we want the crate name to be +/// part of the symbol. +pub fn with_forced_absolute_paths R, R>(f: F) -> R { + FORCE_ABSOLUTE.with(|force| { + let old = force.get(); + force.set(true); + let result = f(); + force.set(old); + result + }) +} + +/// Force us to name impls with just the filename/line number. We +/// normally try to use types. But at some points, notably while printing +/// cycle errors, this can result in extra or suboptimal error output, +/// so this variable disables that check. +pub fn with_forced_impl_filename_line R, R>(f: F) -> R { + FORCE_IMPL_FILENAME_LINE.with(|force| { + let old = force.get(); + force.set(true); + let result = f(); + force.set(old); + result + }) +} + +/// Adds the `crate::` prefix to paths where appropriate. +pub fn with_crate_prefix R, R>(f: F) -> R { + SHOULD_PREFIX_WITH_CRATE.with(|flag| { + let old = flag.get(); + flag.set(true); + let result = f(); + flag.set(old); + result + }) +} + // FIXME(eddyb) this module uses `pub(crate)` for things used only // from `ppaux` - when that is removed, they can be re-privatized. @@ -89,6 +142,511 @@ fn print_debug(&self, cx: &mut PrintCx<'_, '_, 'tcx, P>) -> Self::Output { } } +pub trait Printer: Sized { + type Path; + + fn print_def_path( + self: &mut PrintCx<'_, '_, 'tcx, Self>, + def_id: DefId, + substs: Option>, + ns: Namespace, + ) -> Self::Path { + self.default_print_def_path(def_id, substs, ns) + } + fn print_impl_path( + self: &mut PrintCx<'_, '_, 'tcx, Self>, + impl_def_id: DefId, + substs: Option>, + ns: Namespace, + ) -> Self::Path { + self.default_print_impl_path(impl_def_id, substs, ns) + } + + fn path_crate(self: &mut PrintCx<'_, '_, '_, Self>, cnum: CrateNum) -> Self::Path; + fn path_impl(self: &mut PrintCx<'_, '_, '_, Self>, text: &str) -> Self::Path; + fn path_append( + self: &mut PrintCx<'_, '_, '_, Self>, + path: Self::Path, + text: &str, + ) -> Self::Path; +} + +impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { + // HACK(eddyb) get rid of `def_path_str` and/or pass `Namespace` explicitly always + // (but also some things just print a `DefId` generally so maybe we need this?) + fn guess_def_namespace(self, def_id: DefId) -> Namespace { + match self.def_key(def_id).disambiguated_data.data { + DefPathData::ValueNs(..) | + DefPathData::EnumVariant(..) | + DefPathData::Field(..) | + DefPathData::AnonConst | + DefPathData::ClosureExpr | + DefPathData::StructCtor => Namespace::ValueNS, + + DefPathData::MacroDef(..) => Namespace::MacroNS, + + _ => Namespace::TypeNS, + } + } + + /// Returns a string identifying this `DefId`. This string is + /// suitable for user output. It is relative to the current crate + /// root, unless with_forced_absolute_paths was used. + pub fn def_path_str_with_substs_and_ns( + self, + def_id: DefId, + substs: Option>, + ns: Namespace, + ) -> String { + debug!("def_path_str: def_id={:?}, substs={:?}, ns={:?}", def_id, substs, ns); + if FORCE_ABSOLUTE.with(|force| force.get()) { + PrintCx::new(self, AbsolutePathPrinter).print_def_path(def_id, substs, ns) + } else { + PrintCx::new(self, LocalPathPrinter).print_def_path(def_id, substs, ns) + } + } + + /// Returns a string identifying this `DefId`. This string is + /// suitable for user output. It is relative to the current crate + /// root, unless with_forced_absolute_paths was used. + pub fn def_path_str(self, def_id: DefId) -> String { + let ns = self.guess_def_namespace(def_id); + self.def_path_str_with_substs_and_ns(def_id, None, ns) + } + + /// Returns a string identifying this local node-id. + // FIXME(eddyb) remove in favor of calling `def_path_str` directly. + pub fn node_path_str(self, id: ast::NodeId) -> String { + self.def_path_str(self.hir().local_def_id(id)) + } + + /// Returns a string identifying this `DefId`. This string is + /// suitable for user output. It always begins with a crate identifier. + pub fn absolute_def_path_str(self, def_id: DefId) -> String { + debug!("absolute_def_path_str: def_id={:?}", def_id); + let ns = self.guess_def_namespace(def_id); + PrintCx::new(self, AbsolutePathPrinter).print_def_path(def_id, None, ns) + } +} + +impl PrintCx<'a, 'gcx, 'tcx, P> { + pub fn default_print_def_path( + &mut self, + def_id: DefId, + substs: Option>, + ns: Namespace, + ) -> P::Path { + debug!("default_print_def_path: def_id={:?}, substs={:?}, ns={:?}", def_id, substs, ns); + let key = self.tcx.def_key(def_id); + debug!("default_print_def_path: key={:?}", key); + match key.disambiguated_data.data { + DefPathData::CrateRoot => { + assert!(key.parent.is_none()); + self.path_crate(def_id.krate) + } + + DefPathData::Impl => { + self.print_impl_path(def_id, substs, ns) + } + + // Unclear if there is any value in distinguishing these. + // Probably eventually (and maybe we would even want + // finer-grained distinctions, e.g., between enum/struct). + data @ DefPathData::Misc | + data @ DefPathData::TypeNs(..) | + data @ DefPathData::Trait(..) | + data @ DefPathData::TraitAlias(..) | + data @ DefPathData::AssocTypeInTrait(..) | + data @ DefPathData::AssocTypeInImpl(..) | + data @ DefPathData::AssocExistentialInImpl(..) | + data @ DefPathData::ValueNs(..) | + data @ DefPathData::Module(..) | + data @ DefPathData::TypeParam(..) | + data @ DefPathData::LifetimeParam(..) | + data @ DefPathData::ConstParam(..) | + data @ DefPathData::EnumVariant(..) | + data @ DefPathData::Field(..) | + data @ DefPathData::AnonConst | + data @ DefPathData::MacroDef(..) | + data @ DefPathData::ClosureExpr | + data @ DefPathData::ImplTrait | + data @ DefPathData::GlobalMetaData(..) => { + let parent_did = self.tcx.parent(def_id).unwrap(); + let path = self.print_def_path(parent_did, None, ns); + self.path_append(path, &data.as_interned_str().as_symbol().as_str()) + }, + + DefPathData::StructCtor => { // present `X` instead of `X::{{constructor}}` + let parent_def_id = self.tcx.parent(def_id).unwrap(); + self.print_def_path(parent_def_id, substs, ns) + } + } + } + + fn default_print_impl_path( + &mut self, + impl_def_id: DefId, + substs: Option>, + ns: Namespace, + ) -> P::Path { + debug!("default_print_impl_path: impl_def_id={:?}", impl_def_id); + let parent_def_id = self.tcx.parent(impl_def_id).unwrap(); + + // Decide whether to print the parent path for the impl. + // Logically, since impls are global, it's never needed, but + // 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 mut self_ty = self.tcx.type_of(impl_def_id); + if let Some(substs) = substs { + self_ty = self_ty.subst(self.tcx, substs); + } + let in_self_mod = match characteristic_def_id_of_type(self_ty) { + None => false, + Some(ty_def_id) => self.tcx.parent(ty_def_id) == Some(parent_def_id), + }; + + let mut impl_trait_ref = self.tcx.impl_trait_ref(impl_def_id); + if let Some(substs) = substs { + impl_trait_ref = impl_trait_ref.subst(self.tcx, substs); + } + let in_trait_mod = match impl_trait_ref { + None => false, + Some(trait_ref) => self.tcx.parent(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_def_path(parent_def_id, None, ns); + if let Some(trait_ref) = impl_trait_ref { + return self.path_append(path, &format!("", trait_ref, self_ty)); + } else { + return self.path_append(path, &format!("", self_ty)); + } + } + + // Otherwise, try to give a good form that would be valid language + // syntax. Preferably using associated item notation. + + if let Some(trait_ref) = impl_trait_ref { + // Trait impls. + return self.path_impl(&format!("<{} as {}>", self_ty, trait_ref)); + } + + // Inherent impls. Try to print `Foo::bar` for an inherent + // impl on `Foo`, but fallback to `::bar` if self-type is + // anything other than a simple path. + match self_ty.sty { + ty::Adt(adt_def, substs) => { + // FIXME(eddyb) this should recurse to build the path piecewise. + // self.print_def_path(adt_def.did, Some(substs), ns) + let mut s = String::new(); + crate::util::ppaux::parameterized(&mut s, adt_def.did, substs, ns).unwrap(); + self.path_impl(&s) + } + + ty::Foreign(did) => self.print_def_path(did, None, ns), + + ty::Bool | + ty::Char | + ty::Int(_) | + ty::Uint(_) | + ty::Float(_) | + ty::Str => { + self.path_impl(&self_ty.to_string()) + } + + _ => { + self.path_impl(&format!("<{}>", self_ty)) + } + } + } +} + +/// As a heuristic, when we see an impl, if we see that the +/// 'self type' is a type defined in the same module as the impl, +/// we can omit including the path to the impl itself. This +/// function tries to find a "characteristic `DefId`" for a +/// type. It's just a heuristic so it makes some questionable +/// decisions and we may want to adjust it later. +pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option { + match ty.sty { + ty::Adt(adt_def, _) => Some(adt_def.did), + + ty::Dynamic(data, ..) => data.principal_def_id(), + + ty::Array(subty, _) | + ty::Slice(subty) => characteristic_def_id_of_type(subty), + + ty::RawPtr(mt) => characteristic_def_id_of_type(mt.ty), + + ty::Ref(_, ty, _) => characteristic_def_id_of_type(ty), + + ty::Tuple(ref tys) => tys.iter() + .filter_map(|ty| characteristic_def_id_of_type(ty)) + .next(), + + ty::FnDef(def_id, _) | + ty::Closure(def_id, _) | + ty::Generator(def_id, _, _) | + ty::Foreign(def_id) => Some(def_id), + + ty::Bool | + ty::Char | + ty::Int(_) | + ty::Uint(_) | + ty::Str | + ty::FnPtr(_) | + ty::Projection(_) | + ty::Placeholder(..) | + ty::UnnormalizedProjection(..) | + ty::Param(_) | + ty::Opaque(..) | + ty::Infer(_) | + ty::Bound(..) | + ty::Error | + ty::GeneratorWitness(..) | + ty::Never | + ty::Float(_) => None, + } +} + +// FIXME(eddyb) remove, alongside `FORCE_ABSOLUTE` and `absolute_def_path_str`. +struct AbsolutePathPrinter; + +impl Printer for AbsolutePathPrinter { + type Path = String; + + fn path_crate(self: &mut PrintCx<'_, '_, '_, Self>, cnum: CrateNum) -> Self::Path { + self.tcx.original_crate_name(cnum).to_string() + } + fn path_impl(self: &mut PrintCx<'_, '_, '_, Self>, text: &str) -> Self::Path { + text.to_string() + } + fn path_append( + self: &mut PrintCx<'_, '_, '_, Self>, + mut path: Self::Path, + text: &str, + ) -> Self::Path { + if !path.is_empty() { + path.push_str("::"); + } + path.push_str(text); + path + } +} + pub struct FmtPrinter { pub fmt: F, } + +// FIXME(eddyb) integrate into `FmtPrinter`. +struct LocalPathPrinter; + +impl LocalPathPrinter { + /// 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_def_path( + self: &mut PrintCx<'_, '_, '_, Self>, + def_id: DefId, + ns: Namespace, + ) -> Option<::Path> { + debug!("try_print_visible_def_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(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 *self.tcx.extern_crate(def_id) { + Some(ExternCrate { + src: ExternCrateSource::Extern(def_id), + direct: true, + span, + .. + }) => { + debug!("try_print_visible_def_path: def_id={:?}", def_id); + let path = if !span.is_dummy() { + self.print_def_path(def_id, None, ns) + } else { + self.path_crate(cnum) + }; + return Some(path); + } + None => { + return Some(self.path_crate(cnum)); + } + _ => {}, + } + } + + if def_id.is_local() { + return None; + } + + let visible_parent_map = self.tcx.visible_parent_map(LOCAL_CRATE); + + let mut cur_def_key = self.tcx.def_key(def_id); + debug!("try_print_visible_def_path: cur_def_key={:?}", cur_def_key); + + // For a UnitStruct or TupleStruct we want the name of its parent rather than . + 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 = self.tcx.def_key(parent); + } + + let visible_parent = visible_parent_map.get(&def_id).cloned()?; + let path = self.try_print_visible_def_path(visible_parent, ns)?; + let actual_parent = self.tcx.parent(def_id); + + let data = cur_def_key.disambiguated_data.data; + debug!( + "try_print_visible_def_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 => { + self.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 { + self.tcx.original_crate_name(def_id.krate).as_str() + } else { + Symbol::intern("").as_str() + } + }) + }, + }; + debug!("try_print_visible_def_path: symbol={:?}", symbol); + Some(self.path_append(path, &symbol)) + } +} + +impl Printer for LocalPathPrinter { + type Path = String; + + fn print_def_path( + self: &mut PrintCx<'_, '_, 'tcx, Self>, + def_id: DefId, + substs: Option>, + ns: Namespace, + ) -> Self::Path { + self.try_print_visible_def_path(def_id, ns) + .unwrap_or_else(|| self.default_print_def_path(def_id, substs, ns)) + } + fn print_impl_path( + self: &mut PrintCx<'_, '_, 'tcx, Self>, + impl_def_id: DefId, + substs: Option>, + ns: Namespace, + ) -> Self::Path { + // Always use types for non-local impls, where types are always + // available, and filename/line-number is mostly uninteresting. + let use_types = !impl_def_id.is_local() || { + // Otherwise, use filename/line-number if forced. + let force_no_types = FORCE_IMPL_FILENAME_LINE.with(|f| f.get()); + !force_no_types + }; + + if !use_types { + // If no type info is available, fall back to + // pretty printing some span information. This should + // only occur very early in the compiler pipeline. + // FIXME(eddyb) this should just be using `tcx.def_span(impl_def_id)` + let parent_def_id = self.tcx.parent(impl_def_id).unwrap(); + let path = self.print_def_path(parent_def_id, None, ns); + let span = self.tcx.def_span(impl_def_id); + return self.path_append(path, &format!("", span)); + } + + self.default_print_impl_path(impl_def_id, substs, ns) + } + + fn path_crate(self: &mut PrintCx<'_, '_, '_, Self>, cnum: CrateNum) -> Self::Path { + if cnum == LOCAL_CRATE { + if self.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 { + self.tcx.crate_name(cnum).to_string() + } + } + fn path_impl(self: &mut PrintCx<'_, '_, '_, Self>, text: &str) -> Self::Path { + text.to_string() + } + fn path_append( + self: &mut PrintCx<'_, '_, '_, Self>, + mut path: Self::Path, + text: &str, + ) -> Self::Path { + if !path.is_empty() { + path.push_str("::"); + } + path.push_str(text); + path + } +} diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index e3276ba0bea..cff99f23d0e 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -4,11 +4,10 @@ use crate::dep_graph::{DepNodeIndex, DepNode, DepKind, SerializedDepNodeIndex}; use crate::ty::tls; -use crate::ty::{TyCtxt}; +use crate::ty::{self, TyCtxt}; use crate::ty::query::Query; use crate::ty::query::config::{QueryConfig, QueryDescription}; use crate::ty::query::job::{QueryJob, QueryResult, QueryInfo}; -use crate::ty::item_path; use crate::util::common::{profq_msg, ProfileQueriesMsg, QueryMsg}; @@ -299,7 +298,7 @@ pub(super) fn report_cycle( // sometimes cycles itself, leading to extra cycle errors. // (And cycle errors around impls tend to occur during the // collect/coherence phases anyhow.) - item_path::with_forced_impl_filename_line(|| { + ty::print::with_forced_impl_filename_line(|| { let span = fix_span(stack[1 % stack.len()].span, &stack[0].query); let mut err = struct_span_err!(self.sess, span, diff --git a/src/librustc_codegen_utils/symbol_names.rs b/src/librustc_codegen_utils/symbol_names.rs index 1417cbf1265..b417091704d 100644 --- a/src/librustc_codegen_utils/symbol_names.rs +++ b/src/librustc_codegen_utils/symbol_names.rs @@ -93,8 +93,7 @@ use rustc::hir::CodegenFnAttrFlags; use rustc::hir::map::definitions::DefPathData; use rustc::ich::NodeIdHashingMode; -use rustc::ty::item_path::{self, ItemPathPrinter}; -use rustc::ty::print::PrintCx; +use rustc::ty::print::{PrintCx, Printer}; use rustc::ty::query::Providers; use rustc::ty::subst::SubstsRef; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; @@ -225,7 +224,7 @@ 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(|| { + ty::print::with_forced_absolute_paths(|| { PrintCx::new(tcx, SymbolPathPrinter) .print_def_path(def_id, None, Namespace::ValueNS) .into_interned() @@ -400,7 +399,7 @@ fn finish(mut self, hash: u64) -> String { struct SymbolPathPrinter; -impl ItemPathPrinter for SymbolPathPrinter { +impl Printer for SymbolPathPrinter { type Path = SymbolPath; fn path_crate(self: &mut PrintCx<'_, '_, '_, Self>, cnum: CrateNum) -> Self::Path { diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs index c0e2186d9f3..4a2c05b2013 100644 --- a/src/librustc_mir/monomorphize/partitioning.rs +++ b/src/librustc_mir/monomorphize/partitioning.rs @@ -104,7 +104,7 @@ use rustc::mir::mono::{Linkage, Visibility, CodegenUnitNameBuilder}; use rustc::middle::exported_symbols::SymbolExportLevel; use rustc::ty::{self, TyCtxt, InstanceDef}; -use rustc::ty::item_path::characteristic_def_id_of_type; +use rustc::ty::print::characteristic_def_id_of_type; use rustc::ty::query::Providers; use rustc::util::common::time; use rustc::util::nodemap::{DefIdSet, FxHashMap, FxHashSet}; diff --git a/src/librustc_mir/util/liveness.rs b/src/librustc_mir/util/liveness.rs index 200089530c1..cbdd50cf405 100644 --- a/src/librustc_mir/util/liveness.rs +++ b/src/librustc_mir/util/liveness.rs @@ -29,7 +29,7 @@ }; use rustc::mir::Local; use rustc::mir::*; -use rustc::ty::{item_path, TyCtxt}; +use rustc::ty::{self, TyCtxt}; use rustc_data_structures::bit_set::BitSet; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc_data_structures::work_queue::WorkQueue; @@ -265,7 +265,7 @@ pub fn dump_mir<'a, 'tcx>( if !dump_enabled(tcx, pass_name, source) { return; } - let node_path = item_path::with_forced_impl_filename_line(|| { + let node_path = ty::print::with_forced_impl_filename_line(|| { // see notes on #41697 below tcx.def_path_str(source.def_id()) }); diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index 12d4e90c7c0..a76d26a6831 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -2,7 +2,6 @@ use rustc::mir::*; use rustc::mir::visit::Visitor; use rustc::ty::{self, TyCtxt}; -use rustc::ty::item_path; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::Idx; use std::fmt::Display; @@ -78,7 +77,7 @@ pub fn dump_mir<'a, 'gcx, 'tcx, F>( return; } - let node_path = item_path::with_forced_impl_filename_line(|| { + let node_path = ty::print::with_forced_impl_filename_line(|| { // see notes on #41697 below tcx.def_path_str(source.def_id()) }); @@ -103,7 +102,7 @@ pub fn dump_enabled<'a, 'gcx, 'tcx>( None => return false, Some(ref filters) => filters, }; - let node_path = item_path::with_forced_impl_filename_line(|| { + let node_path = ty::print::with_forced_impl_filename_line(|| { // see notes on #41697 below tcx.def_path_str(source.def_id()) }); @@ -612,7 +611,7 @@ fn write_mir_sig( _ => bug!("Unexpected def description {:?}", descr), } - item_path::with_forced_impl_filename_line(|| { + ty::print::with_forced_impl_filename_line(|| { // see notes on #41697 elsewhere write!(w, " {}", tcx.def_path_str(src.def_id())) })?; diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index f784a720b19..b4a1a2d76c2 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -15,7 +15,7 @@ use rustc::infer::type_variable::TypeVariableOrigin; use rustc::traits::Obligation; use rustc::ty::{self, Adt, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TypeFoldable}; -use rustc::ty::item_path::with_crate_prefix; +use rustc::ty::print::with_crate_prefix; use syntax_pos::{Span, FileName}; use syntax::ast; use syntax::util::lev_distance::find_best_match_for_name; diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 08d165b82b1..6cf8a9896d5 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -4225,12 +4225,11 @@ pub fn path_to_def(tcx: &TyCtxt<'_, '_, '_>, path: &[&str]) -> Option { pub fn get_path_for_type(tcx: TyCtxt<'_, '_, '_>, def_id: DefId, def_ctor: F) -> hir::Path where F: Fn(DefId) -> Def { - use rustc::ty::item_path::ItemPathPrinter; - use rustc::ty::print::PrintCx; + use rustc::ty::print::{PrintCx, Printer}; struct AbsolutePathPrinter; - impl ItemPathPrinter for AbsolutePathPrinter { + impl Printer for AbsolutePathPrinter { type Path = Vec; fn path_crate(self: &mut PrintCx<'_, '_, '_, Self>, cnum: CrateNum) -> Self::Path { -- 2.44.0