rustc: move the contents of ty::item_path to ty::print.
This commit is contained in:
parent
e0c75ff40d
commit
9f8aaa04e0
10 changed files with 573 additions and 580 deletions
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -95,7 +95,6 @@ mod erase_regions;
|
||||||
pub mod fast_reject;
|
pub mod fast_reject;
|
||||||
pub mod fold;
|
pub mod fold;
|
||||||
pub mod inhabitedness;
|
pub mod inhabitedness;
|
||||||
pub mod item_path;
|
|
||||||
pub mod layout;
|
pub mod layout;
|
||||||
pub mod _match;
|
pub mod _match;
|
||||||
pub mod outlives;
|
pub mod outlives;
|
||||||
|
|
|
@ -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 rustc_data_structures::fx::FxHashSet;
|
||||||
use syntax::symbol::InternedString;
|
use syntax::symbol::InternedString;
|
||||||
|
|
||||||
|
use std::cell::Cell;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops::Deref;
|
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
|
// FIXME(eddyb) this module uses `pub(crate)` for things used only
|
||||||
// from `ppaux` - when that is removed, they can be re-privatized.
|
// 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 struct FmtPrinter<F: fmt::Write> {
|
||||||
pub fmt: F,
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -4,11 +4,10 @@
|
||||||
|
|
||||||
use crate::dep_graph::{DepNodeIndex, DepNode, DepKind, SerializedDepNodeIndex};
|
use crate::dep_graph::{DepNodeIndex, DepNode, DepKind, SerializedDepNodeIndex};
|
||||||
use crate::ty::tls;
|
use crate::ty::tls;
|
||||||
use crate::ty::{TyCtxt};
|
use crate::ty::{self, TyCtxt};
|
||||||
use crate::ty::query::Query;
|
use crate::ty::query::Query;
|
||||||
use crate::ty::query::config::{QueryConfig, QueryDescription};
|
use crate::ty::query::config::{QueryConfig, QueryDescription};
|
||||||
use crate::ty::query::job::{QueryJob, QueryResult, QueryInfo};
|
use crate::ty::query::job::{QueryJob, QueryResult, QueryInfo};
|
||||||
use crate::ty::item_path;
|
|
||||||
|
|
||||||
use crate::util::common::{profq_msg, ProfileQueriesMsg, QueryMsg};
|
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.
|
// sometimes cycles itself, leading to extra cycle errors.
|
||||||
// (And cycle errors around impls tend to occur during the
|
// (And cycle errors around impls tend to occur during the
|
||||||
// collect/coherence phases anyhow.)
|
// 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 span = fix_span(stack[1 % stack.len()].span, &stack[0].query);
|
||||||
let mut err = struct_span_err!(self.sess,
|
let mut err = struct_span_err!(self.sess,
|
||||||
span,
|
span,
|
||||||
|
|
|
@ -93,8 +93,7 @@ use rustc::hir::Node;
|
||||||
use rustc::hir::CodegenFnAttrFlags;
|
use rustc::hir::CodegenFnAttrFlags;
|
||||||
use rustc::hir::map::definitions::DefPathData;
|
use rustc::hir::map::definitions::DefPathData;
|
||||||
use rustc::ich::NodeIdHashingMode;
|
use rustc::ich::NodeIdHashingMode;
|
||||||
use rustc::ty::item_path::{self, ItemPathPrinter};
|
use rustc::ty::print::{PrintCx, Printer};
|
||||||
use rustc::ty::print::PrintCx;
|
|
||||||
use rustc::ty::query::Providers;
|
use rustc::ty::query::Providers;
|
||||||
use rustc::ty::subst::SubstsRef;
|
use rustc::ty::subst::SubstsRef;
|
||||||
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
|
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 {
|
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)
|
PrintCx::new(tcx, SymbolPathPrinter)
|
||||||
.print_def_path(def_id, None, Namespace::ValueNS)
|
.print_def_path(def_id, None, Namespace::ValueNS)
|
||||||
.into_interned()
|
.into_interned()
|
||||||
|
@ -400,7 +399,7 @@ impl SymbolPath {
|
||||||
|
|
||||||
struct SymbolPathPrinter;
|
struct SymbolPathPrinter;
|
||||||
|
|
||||||
impl ItemPathPrinter for SymbolPathPrinter {
|
impl Printer for SymbolPathPrinter {
|
||||||
type Path = SymbolPath;
|
type Path = SymbolPath;
|
||||||
|
|
||||||
fn path_crate(self: &mut PrintCx<'_, '_, '_, Self>, cnum: CrateNum) -> Self::Path {
|
fn path_crate(self: &mut PrintCx<'_, '_, '_, Self>, cnum: CrateNum) -> Self::Path {
|
||||||
|
|
|
@ -104,7 +104,7 @@ use rustc::hir::map::DefPathData;
|
||||||
use rustc::mir::mono::{Linkage, Visibility, CodegenUnitNameBuilder};
|
use rustc::mir::mono::{Linkage, Visibility, CodegenUnitNameBuilder};
|
||||||
use rustc::middle::exported_symbols::SymbolExportLevel;
|
use rustc::middle::exported_symbols::SymbolExportLevel;
|
||||||
use rustc::ty::{self, TyCtxt, InstanceDef};
|
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::ty::query::Providers;
|
||||||
use rustc::util::common::time;
|
use rustc::util::common::time;
|
||||||
use rustc::util::nodemap::{DefIdSet, FxHashMap, FxHashSet};
|
use rustc::util::nodemap::{DefIdSet, FxHashMap, FxHashSet};
|
||||||
|
|
|
@ -29,7 +29,7 @@ use rustc::mir::visit::{
|
||||||
};
|
};
|
||||||
use rustc::mir::Local;
|
use rustc::mir::Local;
|
||||||
use rustc::mir::*;
|
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::bit_set::BitSet;
|
||||||
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
|
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
|
||||||
use rustc_data_structures::work_queue::WorkQueue;
|
use rustc_data_structures::work_queue::WorkQueue;
|
||||||
|
@ -265,7 +265,7 @@ pub fn dump_mir<'a, 'tcx>(
|
||||||
if !dump_enabled(tcx, pass_name, source) {
|
if !dump_enabled(tcx, pass_name, source) {
|
||||||
return;
|
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
|
// see notes on #41697 below
|
||||||
tcx.def_path_str(source.def_id())
|
tcx.def_path_str(source.def_id())
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,7 +2,6 @@ use rustc::hir::def_id::{DefId, LOCAL_CRATE};
|
||||||
use rustc::mir::*;
|
use rustc::mir::*;
|
||||||
use rustc::mir::visit::Visitor;
|
use rustc::mir::visit::Visitor;
|
||||||
use rustc::ty::{self, TyCtxt};
|
use rustc::ty::{self, TyCtxt};
|
||||||
use rustc::ty::item_path;
|
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_data_structures::indexed_vec::Idx;
|
use rustc_data_structures::indexed_vec::Idx;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
@ -78,7 +77,7 @@ pub fn dump_mir<'a, 'gcx, 'tcx, F>(
|
||||||
return;
|
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
|
// see notes on #41697 below
|
||||||
tcx.def_path_str(source.def_id())
|
tcx.def_path_str(source.def_id())
|
||||||
});
|
});
|
||||||
|
@ -103,7 +102,7 @@ pub fn dump_enabled<'a, 'gcx, 'tcx>(
|
||||||
None => return false,
|
None => return false,
|
||||||
Some(ref filters) => filters,
|
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
|
// see notes on #41697 below
|
||||||
tcx.def_path_str(source.def_id())
|
tcx.def_path_str(source.def_id())
|
||||||
});
|
});
|
||||||
|
@ -612,7 +611,7 @@ fn write_mir_sig(
|
||||||
_ => bug!("Unexpected def description {:?}", descr),
|
_ => bug!("Unexpected def description {:?}", descr),
|
||||||
}
|
}
|
||||||
|
|
||||||
item_path::with_forced_impl_filename_line(|| {
|
ty::print::with_forced_impl_filename_line(|| {
|
||||||
// see notes on #41697 elsewhere
|
// see notes on #41697 elsewhere
|
||||||
write!(w, " {}", tcx.def_path_str(src.def_id()))
|
write!(w, " {}", tcx.def_path_str(src.def_id()))
|
||||||
})?;
|
})?;
|
||||||
|
|
|
@ -15,7 +15,7 @@ use rustc::hir::print;
|
||||||
use rustc::infer::type_variable::TypeVariableOrigin;
|
use rustc::infer::type_variable::TypeVariableOrigin;
|
||||||
use rustc::traits::Obligation;
|
use rustc::traits::Obligation;
|
||||||
use rustc::ty::{self, Adt, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TypeFoldable};
|
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_pos::{Span, FileName};
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::util::lev_distance::find_best_match_for_name;
|
use syntax::util::lev_distance::find_best_match_for_name;
|
||||||
|
|
|
@ -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
|
pub fn get_path_for_type<F>(tcx: TyCtxt<'_, '_, '_>, def_id: DefId, def_ctor: F) -> hir::Path
|
||||||
where F: Fn(DefId) -> Def {
|
where F: Fn(DefId) -> Def {
|
||||||
use rustc::ty::item_path::ItemPathPrinter;
|
use rustc::ty::print::{PrintCx, Printer};
|
||||||
use rustc::ty::print::PrintCx;
|
|
||||||
|
|
||||||
struct AbsolutePathPrinter;
|
struct AbsolutePathPrinter;
|
||||||
|
|
||||||
impl ItemPathPrinter for AbsolutePathPrinter {
|
impl Printer for AbsolutePathPrinter {
|
||||||
type Path = Vec<String>;
|
type Path = Vec<String>;
|
||||||
|
|
||||||
fn path_crate(self: &mut PrintCx<'_, '_, '_, Self>, cnum: CrateNum) -> Self::Path {
|
fn path_crate(self: &mut PrintCx<'_, '_, '_, Self>, cnum: CrateNum) -> Self::Path {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue