1
Fork 0

rustc: move the contents of ty::item_path to ty::print.

This commit is contained in:
Eduard-Mihai Burtescu 2018-12-19 13:25:31 +02:00
parent e0c75ff40d
commit 9f8aaa04e0
10 changed files with 573 additions and 580 deletions

View file

@ -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<bool> = Cell::new(false);
static FORCE_IMPL_FILENAME_LINE: Cell<bool> = Cell::new(false);
static SHOULD_PREFIX_WITH_CRATE: Cell<bool> = 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<F: FnOnce() -> 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<F: FnOnce() -> 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<F: FnOnce() -> 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<SubstsRef<'tcx>>,
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<P: ItemPathPrinter> PrintCx<'a, 'gcx, 'tcx, P> {
pub fn default_print_def_path(
&mut self,
def_id: DefId,
substs: Option<SubstsRef<'tcx>>,
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<SubstsRef<'tcx>>,
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!("<impl {} for {}>", trait_ref, self_ty));
} else {
return self.path_append(path, &format!("<impl {}>", 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 `<Foo>::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<DefId> {
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<SubstsRef<'tcx>>,
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<SubstsRef<'tcx>>,
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<<Self as ItemPathPrinter>::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 <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 = 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("<unnamed>").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<SubstsRef<'tcx>>,
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<SubstsRef<'tcx>>,
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!("<impl at {:?}>", 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
}
}

View file

@ -95,7 +95,6 @@ mod erase_regions;
pub mod fast_reject;
pub mod fold;
pub mod inhabitedness;
pub mod item_path;
pub mod layout;
pub mod _match;
pub mod outlives;

View file

@ -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<bool> = Cell::new(false);
static FORCE_IMPL_FILENAME_LINE: Cell<bool> = Cell::new(false);
static SHOULD_PREFIX_WITH_CRATE: Cell<bool> = 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<F: FnOnce() -> 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<F: FnOnce() -> 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<F: FnOnce() -> 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 @@ pub trait Print<'tcx, P> {
}
}
pub trait Printer: Sized {
type Path;
fn print_def_path(
self: &mut PrintCx<'_, '_, 'tcx, Self>,
def_id: DefId,
substs: Option<SubstsRef<'tcx>>,
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<SubstsRef<'tcx>>,
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<SubstsRef<'tcx>>,
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<P: Printer> PrintCx<'a, 'gcx, 'tcx, P> {
pub fn default_print_def_path(
&mut self,
def_id: DefId,
substs: Option<SubstsRef<'tcx>>,
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<SubstsRef<'tcx>>,
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!("<impl {} for {}>", trait_ref, self_ty));
} else {
return self.path_append(path, &format!("<impl {}>", 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 `<Foo>::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<DefId> {
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<F: fmt::Write> {
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<<Self as Printer>::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 <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 = 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("<unnamed>").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<SubstsRef<'tcx>>,
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<SubstsRef<'tcx>>,
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!("<impl at {:?}>", 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
}
}

View file

@ -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 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
// 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,

View file

@ -93,8 +93,7 @@ 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};
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 @@ impl SymbolPath {
struct SymbolPathPrinter;
impl ItemPathPrinter for SymbolPathPrinter {
impl Printer for SymbolPathPrinter {
type Path = SymbolPath;
fn path_crate(self: &mut PrintCx<'_, '_, '_, Self>, cnum: CrateNum) -> Self::Path {

View file

@ -104,7 +104,7 @@ use rustc::hir::map::DefPathData;
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};

View file

@ -29,7 +29,7 @@ use rustc::mir::visit::{
};
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())
});

View file

@ -2,7 +2,6 @@ use rustc::hir::def_id::{DefId, LOCAL_CRATE};
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()))
})?;

View file

@ -15,7 +15,7 @@ use rustc::hir::print;
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;

View file

@ -4225,12 +4225,11 @@ 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 {
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<String>;
fn path_crate(self: &mut PrintCx<'_, '_, '_, Self>, cnum: CrateNum) -> Self::Path {