rustc: merge PrintCx::parameterized and def_path printing.

This commit is contained in:
Eduard-Mihai Burtescu 2018-12-21 17:10:21 +02:00
parent b0fbca953f
commit a15bfc6f48
8 changed files with 469 additions and 329 deletions

View File

@ -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 {

View File

@ -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 &params[..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> {}

View File

@ -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 &params[..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"))
}
}

View File

@ -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(())
}
}

View File

@ -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,

View File

@ -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)]

View File

@ -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() { }
}

View File

@ -1,4 +1,4 @@
error: symbol-name(_ZN15impl1..foo..Foo3bar17hc487d6ec13fe9124E)
error: symbol-name(_ZN5impl13foo3Foo3bar17hc487d6ec13fe9124E)
--> $DIR/impl1.rs:8:9
|
LL | #[rustc_symbol_name]