mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
rustc: merge PrintCx::parameterized and def_path printing.
This commit is contained in:
parent
b0fbca953f
commit
a15bfc6f48
@ -450,8 +450,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
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 {
|
||||
|
@ -2,7 +2,7 @@ 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::ty::subst::{Kind, Subst, SubstsRef, UnpackedKind};
|
||||
use crate::middle::cstore::{ExternCrate, ExternCrateSource};
|
||||
use syntax::ast;
|
||||
use syntax::symbol::{keywords, Symbol};
|
||||
@ -12,6 +12,7 @@ use syntax::symbol::InternedString;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::fmt::{self, Write as _};
|
||||
use std::iter;
|
||||
use std::ops::Deref;
|
||||
|
||||
thread_local! {
|
||||
@ -151,8 +152,9 @@ pub trait Printer: Sized {
|
||||
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(
|
||||
@ -167,6 +169,12 @@ pub trait Printer: Sized {
|
||||
#[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(
|
||||
@ -174,6 +182,15 @@ pub trait Printer: Sized {
|
||||
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]
|
||||
@ -193,6 +210,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
DefPathData::EnumVariant(..) |
|
||||
DefPathData::Field(..) |
|
||||
DefPathData::AnonConst |
|
||||
DefPathData::ConstParam(..) |
|
||||
DefPathData::ClosureExpr |
|
||||
DefPathData::StructCtor => Namespace::ValueNS,
|
||||
|
||||
@ -212,14 +230,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, '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 {
|
||||
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
|
||||
@ -227,7 +241,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
/// 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.
|
||||
@ -235,14 +253,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
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> {
|
||||
@ -251,10 +261,12 @@ 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());
|
||||
@ -265,36 +277,46 @@ impl<P: Printer> PrintCx<'a, 'gcx, 'tcx, P> {
|
||||
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())
|
||||
},
|
||||
_ => {
|
||||
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);
|
||||
|
||||
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)
|
||||
// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -335,7 +357,7 @@ impl<P: Printer> PrintCx<'a, 'gcx, 'tcx, P> {
|
||||
// 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 {
|
||||
@ -348,7 +370,7 @@ impl<P: Printer> PrintCx<'a, 'gcx, 'tcx, P> {
|
||||
|
||||
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
|
||||
@ -356,14 +378,10 @@ impl<P: Printer> PrintCx<'a, 'gcx, 'tcx, P> {
|
||||
// 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 |
|
||||
@ -375,7 +393,7 @@ impl<P: Printer> PrintCx<'a, 'gcx, 'tcx, P> {
|
||||
}
|
||||
|
||||
_ => {
|
||||
self.path_impl(&format!("<{}>", self_ty))
|
||||
self.path_qualified(self_ty, None)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -429,44 +447,15 @@ pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> {
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
@ -497,7 +486,7 @@ impl<F: fmt::Write> FmtPrinter<F> {
|
||||
}) => {
|
||||
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)
|
||||
};
|
||||
@ -530,7 +519,7 @@ impl<F: fmt::Write> FmtPrinter<F> {
|
||||
}
|
||||
|
||||
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;
|
||||
@ -593,6 +582,114 @@ impl<F: fmt::Write> FmtPrinter<F> {
|
||||
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> {
|
||||
@ -609,9 +706,27 @@ impl<F: fmt::Write> Printer 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>,
|
||||
@ -621,7 +736,9 @@ impl<F: fmt::Write> Printer for FmtPrinter<F> {
|
||||
) -> 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
|
||||
@ -632,7 +749,7 @@ impl<F: fmt::Write> Printer for FmtPrinter<F> {
|
||||
// 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));
|
||||
}
|
||||
@ -641,6 +758,11 @@ impl<F: fmt::Write> Printer for FmtPrinter<F> {
|
||||
}
|
||||
|
||||
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.
|
||||
@ -655,6 +777,13 @@ impl<F: fmt::Write> Printer for FmtPrinter<F> {
|
||||
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 })
|
||||
@ -678,6 +807,16 @@ impl<F: fmt::Write> Printer for FmtPrinter<F> {
|
||||
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> {}
|
||||
|
@ -1,8 +1,7 @@
|
||||
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};
|
||||
@ -10,7 +9,7 @@ use crate::ty::{Param, Bound, RawPtr, Ref, Never, Tuple};
|
||||
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;
|
||||
@ -284,130 +283,6 @@ impl<P: PrettyPrinter> PrintCx<'a, 'gcx, 'tcx, P> {
|
||||
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>
|
||||
{
|
||||
@ -490,7 +365,8 @@ pub fn parameterized<F: fmt::Write>(
|
||||
) -> 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(())
|
||||
})
|
||||
}
|
||||
|
||||
@ -508,7 +384,12 @@ define_print! {
|
||||
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;
|
||||
}
|
||||
@ -519,9 +400,9 @@ define_print! {
|
||||
// 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(),
|
||||
)?;
|
||||
@ -530,8 +411,10 @@ define_print! {
|
||||
}
|
||||
|
||||
// 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
|
||||
@ -543,13 +426,18 @@ define_print! {
|
||||
// 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(())
|
||||
@ -575,7 +463,13 @@ impl fmt::Debug for ty::GenericParamDef {
|
||||
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(())
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -583,7 +477,13 @@ impl fmt::Debug for ty::TraitDef {
|
||||
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(())
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -645,10 +545,10 @@ define_print! {
|
||||
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)
|
||||
@ -874,7 +774,8 @@ define_print! {
|
||||
//
|
||||
// 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;
|
||||
}
|
||||
@ -1097,16 +998,17 @@ define_print_multi! {
|
||||
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(())
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1152,7 +1054,12 @@ define_print! {
|
||||
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) => {
|
||||
@ -1175,7 +1082,13 @@ define_print! {
|
||||
}
|
||||
}
|
||||
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);
|
||||
@ -1190,12 +1103,13 @@ define_print! {
|
||||
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) => {
|
||||
@ -1215,7 +1129,7 @@ define_print! {
|
||||
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))?;
|
||||
@ -1477,7 +1391,13 @@ define_print! {
|
||||
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(())
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1505,16 +1425,33 @@ define_print! {
|
||||
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"))
|
||||
}
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ use rustc::hir::Node;
|
||||
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};
|
||||
@ -106,8 +106,9 @@ use syntax_pos::symbol::Symbol;
|
||||
|
||||
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 {
|
||||
@ -225,9 +226,9 @@ fn get_symbol_hash<'a, 'tcx>(
|
||||
|
||||
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()
|
||||
})
|
||||
}
|
||||
|
||||
@ -323,7 +324,7 @@ fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance
|
||||
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)
|
||||
@ -347,6 +348,12 @@ struct SymbolPath {
|
||||
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 {
|
||||
@ -355,6 +362,7 @@ 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
|
||||
@ -365,109 +373,139 @@ 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(&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$"),
|
||||
impl PrettyPrinter for SymbolPath {}
|
||||
|
||||
'-' | ':' | '.' if strict_naming => {
|
||||
// NVPTX doesn't support these characters in symbol names.
|
||||
result.push('$')
|
||||
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$"),
|
||||
|
||||
// '.' doesn't occur in types and functions, so reuse it
|
||||
// for ':' and '-'
|
||||
'-' | ':' => result.push('.'),
|
||||
'-' | ':' | '.' if self.strict_naming => {
|
||||
// NVPTX doesn't support these characters in symbol names.
|
||||
self.temp_buf.push('$')
|
||||
}
|
||||
|
||||
// These are legal symbols
|
||||
'a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '.' | '$' => result.push(c),
|
||||
// '.' doesn't occur in types and functions, so reuse it
|
||||
// for ':' and '-'
|
||||
'-' | ':' => self.temp_buf.push('.'),
|
||||
|
||||
_ => {
|
||||
result.push('$');
|
||||
for c in c.escape_unicode().skip(1) {
|
||||
match c {
|
||||
'{' => {}
|
||||
'}' => result.push('$'),
|
||||
c => result.push(c),
|
||||
// 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(())
|
||||
}
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ use std::fmt;
|
||||
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;
|
||||
@ -4235,6 +4235,18 @@ where F: Fn(DefId) -> Def {
|
||||
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()]
|
||||
}
|
||||
@ -4246,10 +4258,20 @@ where F: Fn(DefId) -> Def {
|
||||
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,
|
||||
|
@ -8,6 +8,7 @@
|
||||
#![feature(arbitrary_self_types)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(nll)]
|
||||
#![feature(set_stdio)]
|
||||
#![feature(test)]
|
||||
|
@ -5,7 +5,7 @@ mod foo {
|
||||
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() { }
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
error: symbol-name(_ZN15impl1..foo..Foo3bar17hc487d6ec13fe9124E)
|
||||
error: symbol-name(_ZN5impl13foo3Foo3bar17hc487d6ec13fe9124E)
|
||||
--> $DIR/impl1.rs:8:9
|
||||
|
|
||||
LL | #[rustc_symbol_name]
|
||||
|
Loading…
Reference in New Issue
Block a user