if !(did1.is_local() || did2.is_local()) && did1.krate != did2.krate {
let exp_path = self.tcx.def_path_str(did1);
let found_path = self.tcx.def_path_str(did2);
- let exp_abs_path = self.tcx.absolute_def_path_str(did1);
- let found_abs_path = self.tcx.absolute_def_path_str(did2);
+ // HACK(eddyb) switch form `with_forced_absolute_paths`
+ // to a custom implementation of `ty::print::Printer`.
+ let (exp_abs_path, found_abs_path) = ty::print::with_forced_absolute_paths(|| {
+ (self.tcx.def_path_str(did1), self.tcx.def_path_str(did2))
+ });
// We compare strings because DefPath can be different
// for imported and non-imported crates
if exp_path == found_path || exp_abs_path == found_abs_path {
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::ty::subst::{Kind, Subst, SubstsRef, UnpackedKind};
use crate::middle::cstore::{ExternCrate, ExternCrateSource};
use syntax::ast;
use syntax::symbol::{keywords, Symbol};
use std::cell::Cell;
use std::fmt::{self, Write as _};
+use std::iter;
use std::ops::Deref;
thread_local! {
def_id: DefId,
substs: Option<SubstsRef<'tcx>>,
ns: Namespace,
+ projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
) -> Self::Path {
- self.default_print_def_path(def_id, substs, ns)
+ self.default_print_def_path(def_id, substs, ns, projections)
}
#[must_use]
fn print_impl_path(
#[must_use]
fn path_crate(self: &mut PrintCx<'_, '_, '_, Self>, cnum: CrateNum) -> Self::Path;
#[must_use]
+ fn path_qualified(
+ self: &mut PrintCx<'_, '_, 'tcx, Self>,
+ self_ty: Ty<'tcx>,
+ trait_ref: Option<ty::TraitRef<'tcx>>,
+ ) -> Self::Path;
+ #[must_use]
fn path_impl(self: &mut PrintCx<'_, '_, '_, Self>, text: &str) -> Self::Path;
#[must_use]
fn path_append(
path: Self::Path,
text: &str,
) -> Self::Path;
+ #[must_use]
+ fn path_generic_args(
+ self: &mut PrintCx<'_, '_, 'tcx, Self>,
+ path: Self::Path,
+ params: &[ty::GenericParamDef],
+ substs: SubstsRef<'tcx>,
+ ns: Namespace,
+ projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
+ ) -> Self::Path;
}
#[must_use]
DefPathData::EnumVariant(..) |
DefPathData::Field(..) |
DefPathData::AnonConst |
+ DefPathData::ConstParam(..) |
DefPathData::ClosureExpr |
DefPathData::StructCtor => Namespace::ValueNS,
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 {
- let mut s = String::new();
- let _ = PrintCx::new(self, FmtPrinter { fmt: &mut s })
- .print_def_path(def_id, substs, ns);
- s
- }
+ let mut s = String::new();
+ let _ = PrintCx::new(self, FmtPrinter { fmt: &mut s })
+ .print_def_path(def_id, substs, ns, iter::empty());
+ s
}
/// Returns a string identifying this `DefId`. This string is
/// 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)
+ debug!("def_path_str: def_id={:?}, ns={:?}", def_id, ns);
+ let mut s = String::new();
+ let _ = PrintCx::new(self, FmtPrinter { fmt: &mut s })
+ .print_def_path(def_id, None, ns, iter::empty());
+ s
}
/// 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 `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> {
def_id: DefId,
substs: Option<SubstsRef<'tcx>>,
ns: Namespace,
+ projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
) -> 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.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)
+ _ => {
+ let generics = substs.map(|_| self.tcx.generics_of(def_id));
+ let generics_parent = generics.as_ref().and_then(|g| g.parent);
+ let parent_def_id = DefId { index: key.parent.unwrap(), ..def_id };
+ let path = if let Some(generics_parent_def_id) = generics_parent {
+ assert_eq!(parent_def_id, generics_parent_def_id);
+
+ // FIXME(eddyb) try to move this into the parent's printing
+ // logic, instead of doing it when printing the child.
+ let parent_generics = self.tcx.generics_of(parent_def_id);
+ let parent_has_own_self =
+ parent_generics.has_self && parent_generics.parent_count == 0;
+ if let (Some(substs), true) = (substs, parent_has_own_self) {
+ let trait_ref = ty::TraitRef::new(parent_def_id, substs);
+ self.path_qualified(trait_ref.self_ty(), Some(trait_ref))
+ } else {
+ self.print_def_path(parent_def_id, substs, ns, iter::empty())
+ }
+ } else {
+ self.print_def_path(parent_def_id, None, ns, iter::empty())
+ };
+ let path = match key.disambiguated_data.data {
+ // Skip `::{{constructor}}` on tuple/unit structs.
+ DefPathData::StructCtor => path,
+
+ _ => {
+ self.path_append(
+ path,
+ &key.disambiguated_data.data.as_interned_str().as_str(),
+ )
+ }
+ };
+
+ if let (Some(generics), Some(substs)) = (generics, substs) {
+ let has_own_self = generics.has_self && generics.parent_count == 0;
+ let params = &generics.params[has_own_self as usize..];
+ self.path_generic_args(path, params, substs, ns, projections)
+ } else {
+ path
+ }
}
}
}
// 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);
+ let path = self.print_def_path(parent_def_id, None, ns, iter::empty());
if let Some(trait_ref) = impl_trait_ref {
return self.path_append(path, &format!("<impl {} for {}>", trait_ref, self_ty));
} else {
if let Some(trait_ref) = impl_trait_ref {
// Trait impls.
- return self.path_impl(&format!("<{} as {}>", self_ty, trait_ref));
+ return self.path_qualified(self_ty, Some(trait_ref));
}
// Inherent impls. Try to print `Foo::bar` for an inherent
// 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)
+ self.print_def_path(adt_def.did, Some(substs), ns, iter::empty())
}
- ty::Foreign(did) => self.print_def_path(did, None, ns),
+ ty::Foreign(did) => self.print_def_path(did, None, ns, iter::empty()),
ty::Bool |
ty::Char |
}
_ => {
- self.path_impl(&format!("<{}>", self_ty))
+ self.path_qualified(self_ty, 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,
}
-impl<F: fmt::Write> FmtPrinter<F> {
+impl<P: PrettyPrinter> PrintCx<'a, 'gcx, 'tcx, P> {
/// 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> {
+ fn try_print_visible_def_path(&mut self, def_id: DefId) -> Option<P::Path> {
debug!("try_print_visible_def_path: def_id={:?}", def_id);
// If `def_id` is a direct or injected extern crate, return the
}) => {
debug!("try_print_visible_def_path: def_id={:?}", def_id);
let path = if !span.is_dummy() {
- self.print_def_path(def_id, None, ns)
+ self.print_def_path(def_id, None, Namespace::TypeNS, iter::empty())
} else {
self.path_crate(cnum)
};
}
let visible_parent = visible_parent_map.get(&def_id).cloned()?;
- let path = self.try_print_visible_def_path(visible_parent, ns)?;
+ let path = self.try_print_visible_def_path(visible_parent)?;
let actual_parent = self.tcx.parent(def_id);
let data = cur_def_key.disambiguated_data.data;
debug!("try_print_visible_def_path: symbol={:?}", symbol);
Some(self.path_append(path, &symbol))
}
+
+ pub fn pretty_path_qualified(
+ &mut self,
+ self_ty: Ty<'tcx>,
+ trait_ref: Option<ty::TraitRef<'tcx>>,
+ ) -> P::Path {
+ write!(self.printer, "<")?;
+ self_ty.print_display(self)?;
+ if let Some(trait_ref) = trait_ref {
+ write!(self.printer, " as ")?;
+ let _ = self.print_def_path(
+ trait_ref.def_id,
+ Some(trait_ref.substs),
+ Namespace::TypeNS,
+ iter::empty(),
+ )?;
+ }
+ write!(self.printer, ">")?;
+ Ok(PrettyPath { empty: false })
+ }
+
+ pub fn pretty_path_generic_args(
+ &mut self,
+ path: P::Path,
+ params: &[ty::GenericParamDef],
+ substs: SubstsRef<'tcx>,
+ ns: Namespace,
+ projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
+ ) -> P::Path {
+ let path = path?;
+
+ let mut empty = true;
+ let mut start_or_continue = |cx: &mut Self, start: &str, cont: &str| {
+ if empty {
+ empty = false;
+ write!(cx.printer, "{}", start)
+ } else {
+ write!(cx.printer, "{}", cont)
+ }
+ };
+
+ let start = if ns == Namespace::ValueNS { "::<" } else { "<" };
+
+ // Don't print any regions if they're all erased.
+ let print_regions = params.iter().any(|param| {
+ match substs[param.index as usize].unpack() {
+ UnpackedKind::Lifetime(r) => *r != ty::ReErased,
+ _ => false,
+ }
+ });
+
+ // Don't print args that are the defaults of their respective parameters.
+ let num_supplied_defaults = if self.is_verbose {
+ 0
+ } else {
+ params.iter().rev().take_while(|param| {
+ match param.kind {
+ ty::GenericParamDefKind::Lifetime => false,
+ ty::GenericParamDefKind::Type { has_default, .. } => {
+ has_default && substs[param.index as usize] == Kind::from(
+ self.tcx.type_of(param.def_id).subst(self.tcx, substs)
+ )
+ }
+ ty::GenericParamDefKind::Const => false, // FIXME(const_generics:defaults)
+ }
+ }).count()
+ };
+
+ for param in ¶ms[..params.len() - num_supplied_defaults] {
+ match substs[param.index as usize].unpack() {
+ UnpackedKind::Lifetime(region) => {
+ if !print_regions {
+ continue;
+ }
+ start_or_continue(self, start, ", ")?;
+ if !region.display_outputs_anything(self) {
+ // This happens when the value of the region
+ // parameter is not easily serialized. This may be
+ // because the user omitted it in the first place,
+ // or because it refers to some block in the code,
+ // etc. I'm not sure how best to serialize this.
+ write!(self.printer, "'_")?;
+ } else {
+ region.print_display(self)?;
+ }
+ }
+ UnpackedKind::Type(ty) => {
+ start_or_continue(self, start, ", ")?;
+ ty.print_display(self)?;
+ }
+ UnpackedKind::Const(ct) => {
+ start_or_continue(self, start, ", ")?;
+ ct.print_display(self)?;
+ }
+ }
+ }
+
+ for projection in projections {
+ start_or_continue(self, start, ", ")?;
+ write!(self.printer, "{}=",
+ self.tcx.associated_item(projection.item_def_id).ident)?;
+ projection.ty.print_display(self)?;
+ }
+
+ start_or_continue(self, "", ">")?;
+
+ Ok(path)
+ }
}
impl<F: fmt::Write> fmt::Write for FmtPrinter<F> {
def_id: DefId,
substs: Option<SubstsRef<'tcx>>,
ns: Namespace,
+ projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
) -> Self::Path {
- self.try_print_visible_def_path(def_id, ns)
- .unwrap_or_else(|| self.default_print_def_path(def_id, substs, ns))
+ // FIXME(eddyb) avoid querying `tcx.generics_of`
+ // both here and in `default_print_def_path`.
+ let generics = substs.map(|_| self.tcx.generics_of(def_id));
+ if // HACK(eddyb) remove the `FORCE_ABSOLUTE` hack by bypassing `FmtPrinter`
+ !FORCE_ABSOLUTE.with(|force| force.get()) &&
+ generics.as_ref().and_then(|g| g.parent).is_none() {
+ if let Some(path) = self.try_print_visible_def_path(def_id) {
+ let path = if let (Some(generics), Some(substs)) = (generics, substs) {
+ let has_own_self = generics.has_self && generics.parent_count == 0;
+ let params = &generics.params[has_own_self as usize..];
+ self.path_generic_args(path, params, substs, ns, projections)
+ } else {
+ path
+ };
+ return path;
+ }
+ }
+
+ self.default_print_def_path(def_id, substs, ns, projections)
}
fn print_impl_path(
self: &mut PrintCx<'_, '_, 'tcx, Self>,
) -> 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() || {
+ let use_types = // HACK(eddyb) remove the `FORCE_ABSOLUTE` hack by bypassing `FmtPrinter`
+ FORCE_ABSOLUTE.with(|force| force.get()) ||
+ !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
// pretty printing some span information. This should
// only occur very early in the compiler pipeline.
let parent_def_id = self.tcx.parent(impl_def_id).unwrap();
- let path = self.print_def_path(parent_def_id, None, ns);
+ let path = self.print_def_path(parent_def_id, None, ns, iter::empty());
let span = self.tcx.def_span(impl_def_id);
return self.path_append(path, &format!("<impl at {:?}>", span));
}
}
fn path_crate(self: &mut PrintCx<'_, '_, '_, Self>, cnum: CrateNum) -> Self::Path {
+ // HACK(eddyb) remove the `FORCE_ABSOLUTE` hack by bypassing `FmtPrinter`
+ if FORCE_ABSOLUTE.with(|force| force.get()) {
+ write!(self.printer, "{}", self.tcx.original_crate_name(cnum))?;
+ return Ok(PrettyPath { empty: false });
+ }
if cnum == LOCAL_CRATE {
if self.tcx.sess.rust_2018() {
// We add the `crate::` keyword on Rust 2018, only when desired.
Ok(PrettyPath { empty: false })
}
}
+ fn path_qualified(
+ self: &mut PrintCx<'_, '_, 'tcx, Self>,
+ self_ty: Ty<'tcx>,
+ trait_ref: Option<ty::TraitRef<'tcx>>,
+ ) -> Self::Path {
+ self.pretty_path_qualified(self_ty, trait_ref)
+ }
fn path_impl(self: &mut PrintCx<'_, '_, '_, Self>, text: &str) -> Self::Path {
write!(self.printer, "{}", text)?;
Ok(PrettyPath { empty: false })
write!(self.printer, "{}", text)?;
Ok(PrettyPath { empty: false })
}
+ fn path_generic_args(
+ self: &mut PrintCx<'_, '_, 'tcx, Self>,
+ path: Self::Path,
+ params: &[ty::GenericParamDef],
+ substs: SubstsRef<'tcx>,
+ ns: Namespace,
+ projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
+ ) -> Self::Path {
+ self.pretty_path_generic_args(path, params, substs, ns, projections)
+ }
}
impl<F: fmt::Write> PrettyPrinter for FmtPrinter<F> {}
use crate::hir::def::Namespace;
use crate::hir::def_id::DefId;
-use crate::hir::map::definitions::DefPathData;
use crate::middle::region;
-use crate::ty::subst::{self, Kind, Subst, SubstsRef, UnpackedKind};
+use crate::ty::subst::{Kind, Subst, SubstsRef, UnpackedKind};
use crate::ty::{BrAnon, BrEnv, BrFresh, BrNamed};
use crate::ty::{Bool, Char, Adt};
use crate::ty::{Error, Str, Array, Slice, Float, FnDef, FnPtr};
use crate::ty::{Closure, Generator, GeneratorWitness, Foreign, Projection, Opaque};
use crate::ty::{Placeholder, UnnormalizedProjection, Dynamic, Int, Uint, Infer};
use crate::ty::{self, ParamConst, Ty, TypeFoldable};
-use crate::ty::print::{FmtPrinter, PrettyPrinter, PrintCx, Print};
+use crate::ty::print::{FmtPrinter, PrettyPrinter, PrintCx, Print, Printer};
use crate::mir::interpret::ConstValue;
use std::cell::Cell;
Ok(())
}
- fn parameterized(
- &mut self,
- def_id: DefId,
- substs: SubstsRef<'tcx>,
- ns: Namespace,
- projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
- ) -> fmt::Result {
- let key = self.tcx.def_key(def_id);
- let generics = self.tcx.generics_of(def_id);
-
- if let Some(parent_def_id) = generics.parent {
- assert_eq!(parent_def_id, DefId { index: key.parent.unwrap(), ..def_id });
-
- let parent_generics = self.tcx.generics_of(parent_def_id);
- let parent_has_own_self =
- parent_generics.has_self && parent_generics.parent_count == 0;
- if parent_has_own_self {
- print!(self, write("<"), print_display(substs.type_at(0)), write(" as "))?;
- self.parameterized(parent_def_id, substs, Namespace::TypeNS, iter::empty())?;
- print!(self, write(">"))?;
- } else {
- self.parameterized(parent_def_id, substs, ns, iter::empty())?;
- }
-
- // Skip `::{{constructor}}` on tuple/unit structs.
- match key.disambiguated_data.data {
- DefPathData::StructCtor => {}
-
- _ => {
- print!(self, write("::{}", key.disambiguated_data.data.as_interned_str()))?;
- }
- }
- } else {
- // FIXME(eddyb) recurse through printing a path via `self`, instead
- // instead of using the `tcx` method that produces a `String`.
- print!(self, write("{}",
- self.tcx.def_path_str_with_substs_and_ns(def_id, Some(substs), ns)))?;
-
- // For impls, the above call already prints relevant generics args.
- if let DefPathData::Impl = key.disambiguated_data.data {
- return Ok(());
- }
- }
-
- let mut empty = true;
- let mut start_or_continue = |cx: &mut Self, start: &str, cont: &str| {
- if empty {
- empty = false;
- print!(cx, write("{}", start))
- } else {
- print!(cx, write("{}", cont))
- }
- };
-
- let start = if ns == Namespace::ValueNS { "::<" } else { "<" };
-
- let has_own_self = generics.has_self && generics.parent_count == 0;
- let params = &generics.params[has_own_self as usize..];
-
- // Don't print any regions if they're all erased.
- let print_regions = params.iter().any(|param| {
- match substs[param.index as usize].unpack() {
- UnpackedKind::Lifetime(r) => *r != ty::ReErased,
- _ => false,
- }
- });
-
- // Don't print args that are the defaults of their respective parameters.
- let num_supplied_defaults = if self.is_verbose {
- 0
- } else {
- params.iter().rev().take_while(|param| {
- match param.kind {
- ty::GenericParamDefKind::Lifetime => false,
- ty::GenericParamDefKind::Type { has_default, .. } => {
- has_default && substs[param.index as usize] == Kind::from(
- self.tcx.type_of(param.def_id).subst(self.tcx, substs)
- )
- }
- ty::GenericParamDefKind::Const => false, // FIXME(const_generics:defaults)
- }
- }).count()
- };
-
- for param in ¶ms[..params.len() - num_supplied_defaults] {
- match substs[param.index as usize].unpack() {
- UnpackedKind::Lifetime(region) => {
- if !print_regions {
- continue;
- }
- start_or_continue(self, start, ", ")?;
- if !region.display_outputs_anything(self) {
- // This happens when the value of the region
- // parameter is not easily serialized. This may be
- // because the user omitted it in the first place,
- // or because it refers to some block in the code,
- // etc. I'm not sure how best to serialize this.
- print!(self, write("'_"))?;
- } else {
- region.print_display(self)?;
- }
- }
- UnpackedKind::Type(ty) => {
- start_or_continue(self, start, ", ")?;
- ty.print_display(self)?;
- }
- UnpackedKind::Const(ct) => {
- start_or_continue(self, start, ", ")?;
- ct.print_display(self)?;
- }
- }
- }
-
- for projection in projections {
- start_or_continue(self, start, ", ")?;
- print!(self,
- write("{}=",
- self.tcx.associated_item(projection.item_def_id).ident),
- print_display(projection.ty))?;
- }
-
- start_or_continue(self, "", ">")
- }
-
fn in_binder<T>(&mut self, value: &ty::Binder<T>) -> fmt::Result
where T: Print<'tcx, P, Output = fmt::Result> + TypeFoldable<'tcx>
{
) -> fmt::Result {
PrintCx::with(FmtPrinter { fmt: f }, |mut cx| {
let substs = cx.tcx.lift(&substs).expect("could not lift for printing");
- cx.parameterized(did, substs, ns, iter::empty())
+ let _ = cx.print_def_path(did, Some(substs), ns, iter::empty())?;
+ Ok(())
})
}
if let Tuple(ref args) = principal.substs.type_at(0).sty {
let mut projections = self.projection_bounds();
if let (Some(proj), None) = (projections.next(), projections.next()) {
- print!(cx, write("{}", cx.tcx.def_path_str(principal.def_id)))?;
+ let _ = cx.print_def_path(
+ principal.def_id,
+ None,
+ Namespace::TypeNS,
+ iter::empty(),
+ )?;
cx.fn_sig(args, false, proj.ty)?;
resugared_principal = true;
}
// Use a type that can't appear in defaults of type parameters.
let dummy_self = cx.tcx.mk_infer(ty::FreshTy(0));
let principal = principal.with_self_ty(cx.tcx, dummy_self);
- cx.parameterized(
+ let _ = cx.print_def_path(
principal.def_id,
- principal.substs,
+ Some(principal.substs),
Namespace::TypeNS,
self.projection_bounds(),
)?;
}
// Builtin bounds.
+ // FIXME(eddyb) avoid printing twice (needed to ensure
+ // that the auto traits are sorted *and* printed via cx).
let mut auto_traits: Vec<_> = self.auto_traits().map(|did| {
- cx.tcx.def_path_str(did)
+ (cx.tcx.def_path_str(did), did)
}).collect();
// The auto traits come ordered by `DefPathHash`. While
// output, sort the auto-traits alphabetically.
auto_traits.sort();
- for auto_trait in auto_traits {
+ for (_, def_id) in auto_traits {
if !first {
print!(cx, write(" + "))?;
}
first = false;
- print!(cx, write("{}", auto_trait))?;
+ let _ = cx.print_def_path(
+ def_id,
+ None,
+ Namespace::TypeNS,
+ iter::empty(),
+ )?;
}
Ok(())
impl fmt::Debug for ty::TraitDef {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
PrintCx::with(FmtPrinter { fmt: f }, |mut cx| {
- print!(cx, write("{}", cx.tcx.def_path_str(self.def_id)))
+ let _ = cx.print_def_path(
+ self.def_id,
+ None,
+ Namespace::TypeNS,
+ iter::empty(),
+ )?;
+ Ok(())
})
}
}
impl fmt::Debug for ty::AdtDef {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
PrintCx::with(FmtPrinter { fmt: f }, |mut cx| {
- print!(cx, write("{}", cx.tcx.def_path_str(self.did)))
+ let _ = cx.print_def_path(
+ self.did,
+ None,
+ Namespace::TypeNS,
+ iter::empty(),
+ )?;
+ Ok(())
})
}
}
display {
let dummy_self = cx.tcx.mk_infer(ty::FreshTy(0));
- let trait_ref = *ty::Binder::bind(*self)
+ ty::Binder::bind(*self)
.with_self_ty(cx.tcx, dummy_self)
- .skip_binder();
- cx.parameterized(trait_ref.def_id, trait_ref.substs, Namespace::TypeNS, iter::empty())
+ .skip_binder()
+ .print_display(cx)
}
debug {
self.print_display(cx)
//
// NB: this must be kept in sync with the printing logic above.
impl ty::RegionKind {
- fn display_outputs_anything<P>(&self, cx: &mut PrintCx<'_, '_, '_, P>) -> bool {
+ // HACK(eddyb) `pub(crate)` only for `ty::print`.
+ pub(crate) fn display_outputs_anything<P>(&self, cx: &mut PrintCx<'_, '_, '_, P>) -> bool {
if cx.is_verbose {
return true;
}
define_print! {
('tcx) ty::TraitRef<'tcx>, (self, cx) {
display {
- cx.parameterized(self.def_id, self.substs, Namespace::TypeNS, iter::empty())
+ let _ = cx.print_def_path(
+ self.def_id,
+ Some(self.substs),
+ Namespace::TypeNS,
+ iter::empty(),
+ )?;
+ Ok(())
}
debug {
- print!(cx,
- write("<"),
- print(self.self_ty()),
- write(" as "),
- print_display(self),
- write(">")
- )
+ let _ = cx.path_qualified(self.self_ty(), Some(*self))?;
+ Ok(())
}
}
}
FnDef(def_id, substs) => {
let sig = cx.tcx.fn_sig(def_id).subst(cx.tcx, substs);
print!(cx, print(sig), write(" {{"))?;
- cx.parameterized(def_id, substs, Namespace::ValueNS, iter::empty())?;
+ let _ = cx.print_def_path(
+ def_id,
+ Some(substs),
+ Namespace::ValueNS,
+ iter::empty(),
+ )?;
print!(cx, write("}}"))
}
FnPtr(ref bare_fn) => {
}
}
Adt(def, substs) => {
- cx.parameterized(def.did, substs, Namespace::TypeNS, iter::empty())
+ let _ = cx.print_def_path(
+ def.did,
+ Some(substs),
+ Namespace::TypeNS,
+ iter::empty(),
+ )?;
+ Ok(())
}
Dynamic(data, r) => {
let print_r = r.display_outputs_anything(cx);
Ok(())
}
Foreign(def_id) => {
- cx.parameterized(
+ let _ = cx.print_def_path(
def_id,
- subst::InternalSubsts::empty(),
+ None,
Namespace::TypeNS,
iter::empty(),
- )
+ )?;
+ Ok(())
}
Projection(ref data) => data.print(cx),
UnnormalizedProjection(ref data) => {
if let Some(name) = def_key.disambiguated_data.data.get_opt_name() {
print!(cx, write("{}", name))?;
let mut substs = substs.iter();
- // FIXME(eddyb) print this with `parameterized`.
+ // FIXME(eddyb) print this with `print_def_path`.
if let Some(first) = substs.next() {
print!(cx, write("::<"))?;
print!(cx, write("{}", first))?;
define_print! {
('tcx) ty::ProjectionTy<'tcx>, (self, cx) {
display {
- cx.parameterized(self.item_def_id, self.substs, Namespace::TypeNS, iter::empty())
+ let _ = cx.print_def_path(
+ self.item_def_id,
+ Some(self.substs),
+ Namespace::TypeNS,
+ iter::empty(),
+ )?;
+ Ok(())
}
}
}
ty::Predicate::Projection(ref predicate) => predicate.print(cx),
ty::Predicate::WellFormed(ty) => print!(cx, print(ty), write(" well-formed")),
ty::Predicate::ObjectSafe(trait_def_id) => {
- print!(cx, write("the trait `{}` is object-safe",
- cx.tcx.def_path_str(trait_def_id)))
+ print!(cx, write("the trait `"))?;
+ let _ = cx.print_def_path(
+ trait_def_id,
+ None,
+ Namespace::TypeNS,
+ iter::empty(),
+ )?;
+ print!(cx, write("` is object-safe"))
}
ty::Predicate::ClosureKind(closure_def_id, _closure_substs, kind) => {
- print!(cx, write("the closure `{}` implements the trait `{}`",
- cx.tcx.def_path_str(closure_def_id), kind))
+ print!(cx, write("the closure `"))?;
+ let _ = cx.print_def_path(
+ closure_def_id,
+ None,
+ Namespace::ValueNS,
+ iter::empty(),
+ )?;
+ print!(cx, write("` implements the trait `{}`", kind))
}
ty::Predicate::ConstEvaluatable(def_id, substs) => {
print!(cx, write("the constant `"))?;
- cx.parameterized(def_id, substs, Namespace::ValueNS, iter::empty())?;
+ let _ = cx.print_def_path(
+ def_id,
+ Some(substs),
+ Namespace::ValueNS,
+ iter::empty(),
+ )?;
print!(cx, write("` can be evaluated"))
}
}
use rustc::hir::CodegenFnAttrFlags;
use rustc::hir::map::definitions::DefPathData;
use rustc::ich::NodeIdHashingMode;
-use rustc::ty::print::{PrintCx, Printer};
+use rustc::ty::print::{PrettyPath, PrettyPrinter, PrintCx, Printer};
use rustc::ty::query::Providers;
use rustc::ty::subst::SubstsRef;
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use log::debug;
-use std::fmt::Write;
-use std::mem::discriminant;
+use std::fmt::{self, Write};
+use std::iter;
+use std::mem::{self, discriminant};
pub fn provide(providers: &mut Providers<'_>) {
*providers = Providers {
fn def_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::SymbolName {
ty::print::with_forced_absolute_paths(|| {
- PrintCx::new(tcx, SymbolPathPrinter)
- .print_def_path(def_id, None, Namespace::ValueNS)
- .into_interned()
+ let mut cx = PrintCx::new(tcx, SymbolPath::new(tcx));
+ let _ = cx.print_def_path(def_id, None, Namespace::ValueNS, iter::empty());
+ cx.printer.into_interned()
})
}
let mut buf = SymbolPath::from_interned(tcx.def_symbol_name(def_id), tcx);
if instance.is_vtable_shim() {
- buf.push("{{vtable-shim}}");
+ let _ = buf.write_str("{{vtable-shim}}");
}
buf.finish(hash)
result: String,
temp_buf: String,
strict_naming: bool,
+
+ // When `true`, `finalize_pending_component` is a noop.
+ // This is needed when recursing into `path_qualified`,
+ // or `path_generic_args`, as any nested paths are
+ // logically within one component.
+ keep_within_component: bool,
}
impl SymbolPath {
result: String::with_capacity(64),
temp_buf: String::with_capacity(16),
strict_naming: tcx.has_strict_asm_symbol_naming(),
+ keep_within_component: false,
};
result.result.push_str("_ZN"); // _Z == Begin name-sequence, N == nested
result
result: String::with_capacity(64),
temp_buf: String::with_capacity(16),
strict_naming: tcx.has_strict_asm_symbol_naming(),
+ keep_within_component: false,
};
result.result.push_str(&symbol.as_str());
result
}
- fn into_interned(self) -> ty::SymbolName {
+ fn into_interned(mut self) -> ty::SymbolName {
+ self.finalize_pending_component();
ty::SymbolName {
name: Symbol::intern(&self.result).as_interned_str(),
}
}
- fn push(&mut self, text: &str) {
- self.temp_buf.clear();
- let need_underscore = sanitize(&mut self.temp_buf, text, self.strict_naming);
- let _ = write!(
- self.result,
- "{}",
- self.temp_buf.len() + (need_underscore as usize)
- );
- if need_underscore {
- self.result.push('_');
+ fn finalize_pending_component(&mut self) {
+ if !self.keep_within_component && !self.temp_buf.is_empty() {
+ let _ = write!(self.result, "{}{}", self.temp_buf.len(), self.temp_buf);
+ self.temp_buf.clear();
}
- self.result.push_str(&self.temp_buf);
}
fn finish(mut self, hash: u64) -> String {
+ self.finalize_pending_component();
// E = end name-sequence
let _ = write!(self.result, "17h{:016x}E", hash);
self.result
}
}
-struct SymbolPathPrinter;
+// HACK(eddyb) this relies on using the `fmt` interface to get
+// `PrettyPrinter` aka pretty printing of e.g. types in paths,
+// symbol names should have their own printing machinery.
-impl Printer for SymbolPathPrinter {
- type Path = SymbolPath;
+impl Printer for SymbolPath {
+ type Path = Result<PrettyPath, fmt::Error>;
fn path_crate(self: &mut PrintCx<'_, '_, '_, Self>, cnum: CrateNum) -> Self::Path {
- let mut path = SymbolPath::new(self.tcx);
- path.push(&self.tcx.original_crate_name(cnum).as_str());
- path
+ self.printer.write_str(&self.tcx.original_crate_name(cnum).as_str())?;
+ Ok(PrettyPath { empty: false })
+ }
+ fn path_qualified(
+ self: &mut PrintCx<'_, '_, 'tcx, Self>,
+ self_ty: Ty<'tcx>,
+ trait_ref: Option<ty::TraitRef<'tcx>>,
+ ) -> Self::Path {
+ let kept_within_component = mem::replace(&mut self.printer.keep_within_component, true);
+ let r = self.pretty_path_qualified(self_ty, trait_ref);
+ self.printer.keep_within_component = kept_within_component;
+ r
}
fn path_impl(self: &mut PrintCx<'_, '_, '_, Self>, text: &str) -> Self::Path {
- let mut path = SymbolPath::new(self.tcx);
- path.push(text);
- path
+ self.printer.write_str(text)?;
+ Ok(PrettyPath { empty: false })
}
fn path_append(
self: &mut PrintCx<'_, '_, '_, Self>,
- mut path: Self::Path,
+ _: Self::Path,
text: &str,
) -> Self::Path {
- path.push(text);
- path
+ self.printer.finalize_pending_component();
+ self.printer.write_str(text)?;
+ Ok(PrettyPath { empty: false })
+ }
+ fn path_generic_args(
+ self: &mut PrintCx<'_, '_, 'tcx, Self>,
+ path: Self::Path,
+ params: &[ty::GenericParamDef],
+ substs: SubstsRef<'tcx>,
+ ns: Namespace,
+ projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
+ ) -> Self::Path {
+ let kept_within_component = mem::replace(&mut self.printer.keep_within_component, true);
+ let r = self.pretty_path_generic_args(path, params, substs, ns, projections);
+ self.printer.keep_within_component = kept_within_component;
+ r
}
}
-// Name sanitation. LLVM will happily accept identifiers with weird names, but
-// gas doesn't!
-// gas accepts the following characters in symbols: a-z, A-Z, 0-9, ., _, $
-// NVPTX assembly has more strict naming rules than gas, so additionally, dots
-// are replaced with '$' there.
-//
-// returns true if an underscore must be added at the start
-fn sanitize(result: &mut String, s: &str, strict_naming: bool) -> bool {
- for c in s.chars() {
- match c {
- // Escape these with $ sequences
- '@' => result.push_str("$SP$"),
- '*' => result.push_str("$BP$"),
- '&' => result.push_str("$RF$"),
- '<' => result.push_str("$LT$"),
- '>' => result.push_str("$GT$"),
- '(' => result.push_str("$LP$"),
- ')' => result.push_str("$RP$"),
- ',' => result.push_str("$C$"),
-
- '-' | ':' | '.' if strict_naming => {
- // NVPTX doesn't support these characters in symbol names.
- result.push('$')
+impl PrettyPrinter for SymbolPath {}
+
+impl fmt::Write for SymbolPath {
+ fn write_str(&mut self, s: &str) -> fmt::Result {
+ // Name sanitation. LLVM will happily accept identifiers with weird names, but
+ // gas doesn't!
+ // gas accepts the following characters in symbols: a-z, A-Z, 0-9, ., _, $
+ // NVPTX assembly has more strict naming rules than gas, so additionally, dots
+ // are replaced with '$' there.
+
+ for c in s.chars() {
+ if self.temp_buf.is_empty() {
+ match c {
+ 'a'..='z' | 'A'..='Z' | '_' => {}
+ _ => {
+ // Underscore-qualify anything that didn't start as an ident.
+ self.temp_buf.push('_');
+ }
+ }
}
+ match c {
+ // Escape these with $ sequences
+ '@' => self.temp_buf.push_str("$SP$"),
+ '*' => self.temp_buf.push_str("$BP$"),
+ '&' => self.temp_buf.push_str("$RF$"),
+ '<' => self.temp_buf.push_str("$LT$"),
+ '>' => self.temp_buf.push_str("$GT$"),
+ '(' => self.temp_buf.push_str("$LP$"),
+ ')' => self.temp_buf.push_str("$RP$"),
+ ',' => self.temp_buf.push_str("$C$"),
+
+ '-' | ':' | '.' if self.strict_naming => {
+ // NVPTX doesn't support these characters in symbol names.
+ self.temp_buf.push('$')
+ }
- // '.' doesn't occur in types and functions, so reuse it
- // for ':' and '-'
- '-' | ':' => result.push('.'),
-
- // These are legal symbols
- 'a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '.' | '$' => result.push(c),
-
- _ => {
- result.push('$');
- for c in c.escape_unicode().skip(1) {
- match c {
- '{' => {}
- '}' => result.push('$'),
- c => result.push(c),
+ // '.' doesn't occur in types and functions, so reuse it
+ // for ':' and '-'
+ '-' | ':' => self.temp_buf.push('.'),
+
+ // These are legal symbols
+ 'a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '.' | '$' => self.temp_buf.push(c),
+
+ _ => {
+ self.temp_buf.push('$');
+ for c in c.escape_unicode().skip(1) {
+ match c {
+ '{' => {}
+ '}' => self.temp_buf.push('$'),
+ c => self.temp_buf.push(c),
+ }
}
}
}
}
- }
- // Underscore-qualify anything that didn't start as an ident.
- !result.is_empty() && result.as_bytes()[0] != '_' as u8
- && !(result.as_bytes()[0] as char).is_xid_start()
+ Ok(())
+ }
}
use std::hash::{Hash, Hasher};
use std::default::Default;
use std::{mem, slice, vec};
-use std::iter::{FromIterator, once};
+use std::iter::{self, FromIterator, once};
use std::rc::Rc;
use std::str::FromStr;
use std::cell::RefCell;
fn path_crate(self: &mut PrintCx<'_, '_, '_, Self>, cnum: CrateNum) -> Self::Path {
vec![self.tcx.original_crate_name(cnum).to_string()]
}
+ fn path_qualified(
+ self: &mut PrintCx<'_, '_, 'tcx, Self>,
+ self_ty: Ty<'tcx>,
+ trait_ref: Option<ty::TraitRef<'tcx>>,
+ ) -> Self::Path {
+ // This shouldn't ever be needed, but just in case:
+ if let Some(trait_ref) = trait_ref {
+ vec![format!("{:?}", trait_ref)]
+ } else {
+ vec![format!("<{}>", self_ty)]
+ }
+ }
fn path_impl(self: &mut PrintCx<'_, '_, '_, Self>, text: &str) -> Self::Path {
vec![text.to_string()]
}
path.push(text.to_string());
path
}
+ fn path_generic_args(
+ self: &mut PrintCx<'_, '_, 'tcx, Self>,
+ path: Self::Path,
+ _params: &[ty::GenericParamDef],
+ _substs: SubstsRef<'tcx>,
+ _ns: Namespace,
+ _projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
+ ) -> Self::Path {
+ path
+ }
}
let names = PrintCx::new(tcx, AbsolutePathPrinter)
- .print_def_path(def_id, None, Namespace::TypeNS);
+ .print_def_path(def_id, None, Namespace::TypeNS, iter::empty());
hir::Path {
span: DUMMY_SP,
#![feature(arbitrary_self_types)]
#![feature(box_patterns)]
#![feature(box_syntax)]
+#![feature(in_band_lifetimes)]
#![feature(nll)]
#![feature(set_stdio)]
#![feature(test)]
pub struct Foo { x: u32 }
impl Foo {
- #[rustc_symbol_name] //~ ERROR _ZN15impl1..foo..Foo3bar
+ #[rustc_symbol_name] //~ ERROR _ZN5impl13foo3Foo3bar
#[rustc_def_path] //~ ERROR def-path(foo::Foo::bar)
fn bar() { }
}
-error: symbol-name(_ZN15impl1..foo..Foo3bar17hc487d6ec13fe9124E)
+error: symbol-name(_ZN5impl13foo3Foo3bar17hc487d6ec13fe9124E)
--> $DIR/impl1.rs:8:9
|
LL | #[rustc_symbol_name]