From a15bfc6f483c552f793932f7ac7fcbb69d187681 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Fri, 21 Dec 2018 17:10:21 +0200 Subject: [PATCH] rustc: merge PrintCx::parameterized and def_path printing. --- src/librustc/infer/error_reporting/mod.rs | 7 +- src/librustc/ty/print.rs | 329 +++++++++++++++------ src/librustc/util/ppaux.rs | 257 ++++++---------- src/librustc_codegen_utils/symbol_names.rs | 182 +++++++----- src/librustdoc/clean/mod.rs | 26 +- src/librustdoc/lib.rs | 1 + src/test/ui/symbol-names/impl1.rs | 2 +- src/test/ui/symbol-names/impl1.stderr | 2 +- 8 files changed, 473 insertions(+), 333 deletions(-) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 2a638853992..c99ab215b35 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -450,8 +450,11 @@ fn check_and_note_conflicting_crates( 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 { diff --git a/src/librustc/ty/print.rs b/src/librustc/ty/print.rs index de0c3ee7fff..45762460f2d 100644 --- a/src/librustc/ty/print.rs +++ b/src/librustc/ty/print.rs @@ -2,7 +2,7 @@ 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 std::cell::Cell; use std::fmt::{self, Write as _}; +use std::iter; use std::ops::Deref; thread_local! { @@ -151,8 +152,9 @@ fn print_def_path( def_id: DefId, substs: Option>, ns: Namespace, + projections: impl Iterator>, ) -> 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 @@ 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>, + ) -> Self::Path; + #[must_use] fn path_impl(self: &mut PrintCx<'_, '_, '_, Self>, text: &str) -> Self::Path; #[must_use] fn path_append( @@ -174,6 +182,15 @@ 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>, + ) -> Self::Path; } #[must_use] @@ -193,6 +210,7 @@ fn guess_def_namespace(self, def_id: DefId) -> Namespace { DefPathData::EnumVariant(..) | DefPathData::Field(..) | DefPathData::AnonConst | + DefPathData::ConstParam(..) | DefPathData::ClosureExpr | DefPathData::StructCtor => Namespace::ValueNS, @@ -212,14 +230,10 @@ pub fn def_path_str_with_substs_and_ns( 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 @@ pub fn def_path_str_with_substs_and_ns( /// 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 @@ pub fn def_path_str(self, def_id: DefId) -> String { 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 PrintCx<'a, 'gcx, 'tcx, P> { @@ -251,10 +261,12 @@ pub fn default_print_def_path( def_id: DefId, substs: Option>, ns: Namespace, + projections: impl Iterator>, ) -> 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 @@ pub fn default_print_def_path( 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 + } } } } @@ -335,7 +357,7 @@ fn default_print_impl_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!("", trait_ref, self_ty)); } else { @@ -348,7 +370,7 @@ fn default_print_impl_path( 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 @@ fn default_print_impl_path( // 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 @@ fn default_print_impl_path( } _ => { - 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 { } } -// 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 { pub fmt: F, } -impl FmtPrinter { +impl 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<::Path> { + fn try_print_visible_def_path(&mut self, def_id: DefId) -> Option { 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 @@ fn try_print_visible_def_path( }) => { 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 @@ fn try_print_visible_def_path( } 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 @@ fn try_print_visible_def_path( 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>, + ) -> 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>, + ) -> 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 fmt::Write for FmtPrinter { @@ -609,9 +706,27 @@ fn print_def_path( def_id: DefId, substs: Option>, ns: Namespace, + projections: impl Iterator>, ) -> 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 @@ fn print_impl_path( ) -> 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 @@ fn print_impl_path( // 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!("", span)); } @@ -641,6 +758,11 @@ fn print_impl_path( } 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 @@ fn path_crate(self: &mut PrintCx<'_, '_, '_, Self>, cnum: CrateNum) -> Self::Pat Ok(PrettyPath { empty: false }) } } + fn path_qualified( + self: &mut PrintCx<'_, '_, 'tcx, Self>, + self_ty: Ty<'tcx>, + trait_ref: Option>, + ) -> 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 @@ fn path_append( 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>, + ) -> Self::Path { + self.pretty_path_generic_args(path, params, substs, ns, projections) + } } impl PrettyPrinter for FmtPrinter {} diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 39e26f13233..2c38c437cf6 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -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::{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 @@ fn fn_sig( Ok(()) } - fn parameterized( - &mut self, - def_id: DefId, - substs: SubstsRef<'tcx>, - ns: Namespace, - projections: impl Iterator>, - ) -> 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(&mut self, value: &ty::Binder) -> fmt::Result where T: Print<'tcx, P, Output = fmt::Result> + TypeFoldable<'tcx> { @@ -490,7 +365,8 @@ pub fn parameterized( ) -> 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 @@ pub fn parameterized( 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 @@ pub fn parameterized( // 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 @@ pub fn parameterized( } // 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 @@ pub fn parameterized( // 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 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 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 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 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 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 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 @@ fn display_outputs_anything

(&self, cx: &mut PrintCx<'_, '_, '_, P>) -> bool { // // NB: this must be kept in sync with the printing logic above. impl ty::RegionKind { - fn display_outputs_anything

(&self, cx: &mut PrintCx<'_, '_, '_, P>) -> bool { + // HACK(eddyb) `pub(crate)` only for `ty::print`. + pub(crate) fn display_outputs_anything

(&self, cx: &mut PrintCx<'_, '_, '_, P>) -> bool { if cx.is_verbose { return true; } @@ -1097,16 +998,17 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 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 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 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 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } } 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 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 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 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 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 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 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 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 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")) } } diff --git a/src/librustc_codegen_utils/symbol_names.rs b/src/librustc_codegen_utils/symbol_names.rs index b417091704d..4c7b00ae078 100644 --- a/src/librustc_codegen_utils/symbol_names.rs +++ b/src/librustc_codegen_utils/symbol_names.rs @@ -93,7 +93,7 @@ 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 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 @@ fn new(tcx: TyCtxt<'_, '_, '_>) -> Self { 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 @@ fn from_interned(symbol: ty::SymbolName, tcx: TyCtxt<'_, '_, '_>) -> Self { 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; 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>, + ) -> 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>, + ) -> 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(()) + } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 6cf8a9896d5..f629447fc64 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -39,7 +39,7 @@ 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 @@ impl Printer for AbsolutePathPrinter { 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>, + ) -> 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 @@ fn path_append( 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>, + ) -> 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, diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 58ba827ee05..2ac44d0109f 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -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)] diff --git a/src/test/ui/symbol-names/impl1.rs b/src/test/ui/symbol-names/impl1.rs index 992527017fb..c712137e828 100644 --- a/src/test/ui/symbol-names/impl1.rs +++ b/src/test/ui/symbol-names/impl1.rs @@ -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() { } } diff --git a/src/test/ui/symbol-names/impl1.stderr b/src/test/ui/symbol-names/impl1.stderr index d225c53e492..eda8646b5b4 100644 --- a/src/test/ui/symbol-names/impl1.stderr +++ b/src/test/ui/symbol-names/impl1.stderr @@ -1,4 +1,4 @@ -error: symbol-name(_ZN15impl1..foo..Foo3bar17hc487d6ec13fe9124E) +error: symbol-name(_ZN5impl13foo3Foo3bar17hc487d6ec13fe9124E) --> $DIR/impl1.rs:8:9 | LL | #[rustc_symbol_name] -- 2.44.0