From 88d96b269c77a0de2c143c797aeb61e928f32e03 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Mon, 14 Jan 2019 17:55:57 +0200 Subject: [PATCH] rustc: support overriding region printing in ty::print::Printer. --- src/librustc/infer/error_reporting/mod.rs | 8 + src/librustc/ty/print.rs | 174 +++++++++++++++++++-- src/librustc/util/ppaux.rs | 129 +-------------- src/librustc_codegen_utils/symbol_names.rs | 17 +- src/librustdoc/clean/mod.rs | 8 + 5 files changed, 199 insertions(+), 137 deletions(-) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 974b9c59ea4..768839bf60f 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -457,6 +457,14 @@ impl Printer for AbsolutePathPrinter { type Error = NonTrivialPath; type Path = Vec; + type Region = !; + + fn print_region( + self: PrintCx<'_, '_, '_, Self>, + _region: ty::Region<'_>, + ) -> Result { + Err(NonTrivialPath) + } fn path_crate( self: PrintCx<'_, '_, '_, Self>, diff --git a/src/librustc/ty/print.rs b/src/librustc/ty/print.rs index 4e1fdf657bd..cf47840b022 100644 --- a/src/librustc/ty/print.rs +++ b/src/librustc/ty/print.rs @@ -1,6 +1,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::middle::region; use crate::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable}; use crate::ty::subst::{Kind, Subst, SubstsRef, UnpackedKind}; use crate::middle::cstore::{ExternCrate, ExternCrateSource}; @@ -67,7 +68,7 @@ pub struct RegionHighlightMode { /// This is used when you have a signature like `fn foo(x: &u32, /// y: &'a u32)` and we want to give a name to the region of the /// reference `x`. - pub(crate) highlight_bound_region: Option<(ty::BoundRegion, usize)>, + highlight_bound_region: Option<(ty::BoundRegion, usize)>, } impl RegionHighlightMode { @@ -114,7 +115,7 @@ pub fn highlighting_region_vid( } /// Returns `Some(n)` with the number to use for the given region, if any. - pub(crate) fn region_highlighted(&self, region: ty::Region<'_>) -> Option { + fn region_highlighted(&self, region: ty::Region<'_>) -> Option { self .highlight_regions .iter() @@ -250,6 +251,7 @@ pub trait Printer: Sized { type Error; type Path; + type Region; fn print_def_path( self: PrintCx<'_, '_, 'tcx, Self>, @@ -271,6 +273,11 @@ fn print_impl_path( self.default_print_impl_path(impl_def_id, substs, ns, self_ty, trait_ref) } + fn print_region( + self: PrintCx<'_, '_, '_, Self>, + region: ty::Region<'_>, + ) -> Result; + fn path_crate( self: PrintCx<'_, '_, '_, Self>, cnum: CrateNum, @@ -310,7 +317,7 @@ fn path_generic_args<'gcx, 'tcx>( } /// Trait for printers that pretty-print using `fmt::Write` to the printer. -pub trait PrettyPrinter: Printer + fmt::Write { +pub trait PrettyPrinter: Printer + fmt::Write { /// Enter a nested print context, for pretty-printing /// nested components in some larger context. fn nest<'a, 'gcx, 'tcx, E>( @@ -329,9 +336,26 @@ fn nest<'a, 'gcx, 'tcx, E>( }) } - fn region_highlight_mode(&self) -> RegionHighlightMode { - RegionHighlightMode::default() + /// Return `true` if the region should be printed in path generic args + /// even when it's `'_`, such as in e.g. `Foo<'_, '_, '_>`. + fn always_print_region_in_paths( + self: &PrintCx<'_, '_, '_, Self>, + _region: ty::Region<'_>, + ) -> bool { + false } + + // HACK(eddyb) Trying to print a lifetime might not print anything, which + // may need special handling in the caller (of `ty::RegionKind::print`). + // To avoid printing to a temporary string (which isn't even supported), + // the `print_region_outputs_anything` method can instead be used to + // determine this, ahead of time. + // + // NB: this must be kept in sync with the implementation of `print_region`. + fn print_region_outputs_anything( + self: &PrintCx<'_, '_, '_, Self>, + region: ty::Region<'_>, + ) -> bool; } macro_rules! nest { @@ -795,10 +819,13 @@ pub fn pretty_path_generic_args( let start = if ns == Namespace::ValueNS { "::<" } else { "<" }; - // Don't print any regions if they're all erased. + // Don't print `'_` if there's no printed region. let print_regions = params.iter().any(|param| { match substs[param.index as usize].unpack() { - UnpackedKind::Lifetime(r) => *r != ty::ReErased, + UnpackedKind::Lifetime(r) => { + self.always_print_region_in_paths(r) || + self.print_region_outputs_anything(r) + } _ => false, } }); @@ -827,7 +854,7 @@ pub fn pretty_path_generic_args( continue; } start_or_continue(&mut self, start, ", ")?; - if !region.display_outputs_anything(&self) { + if !self.print_region_outputs_anything(region) { // 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, @@ -873,6 +900,7 @@ impl Printer for FmtPrinter { type Error = fmt::Error; type Path = Self; + type Region = Self; fn print_def_path( mut self: PrintCx<'_, '_, 'tcx, Self>, @@ -929,6 +957,80 @@ fn print_def_path( self.default_print_def_path(def_id, substs, ns, projections) } + fn print_region( + mut self: PrintCx<'_, '_, '_, Self>, + region: ty::Region<'_>, + ) -> Result { + // Watch out for region highlights. + let highlight = self.printer.region_highlight_mode; + if let Some(n) = highlight.region_highlighted(region) { + write!(self.printer, "'{}", n)?; + return Ok(self.printer); + } + + if self.config.is_verbose { + return region.print_debug(self); + } + + // These printouts are concise. They do not contain all the information + // the user might want to diagnose an error, but there is basically no way + // to fit that into a short string. Hence the recommendation to use + // `explain_region()` or `note_and_explain_region()`. + match *region { + ty::ReEarlyBound(ref data) => { + if data.name != "'_" { + write!(self.printer, "{}", data.name)?; + } + } + ty::ReLateBound(_, br) | + ty::ReFree(ty::FreeRegion { bound_region: br, .. }) | + ty::RePlaceholder(ty::Placeholder { name: br, .. }) => { + if let ty::BrNamed(_, name) = br { + if name != "" && name != "'_" { + write!(self.printer, "{}", name)?; + return Ok(self.printer); + } + } + + if let Some((region, counter)) = highlight.highlight_bound_region { + if br == region { + write!(self.printer, "'{}", counter)?; + } + } + } + ty::ReScope(scope) if self.config.identify_regions => { + match scope.data { + region::ScopeData::Node => + write!(self.printer, "'{}s", scope.item_local_id().as_usize())?, + region::ScopeData::CallSite => + write!(self.printer, "'{}cs", scope.item_local_id().as_usize())?, + region::ScopeData::Arguments => + write!(self.printer, "'{}as", scope.item_local_id().as_usize())?, + region::ScopeData::Destruction => + write!(self.printer, "'{}ds", scope.item_local_id().as_usize())?, + region::ScopeData::Remainder(first_statement_index) => write!(self.printer, + "'{}_{}rs", + scope.item_local_id().as_usize(), + first_statement_index.index() + )?, + } + } + ty::ReVar(region_vid) if self.config.identify_regions => { + write!(self.printer, "{:?}", region_vid)?; + } + ty::ReVar(_) => {} + ty::ReScope(_) | + ty::ReErased => {} + ty::ReStatic => write!(self.printer, "'static")?, + ty::ReEmpty => write!(self.printer, "'")?, + + // The user should never encounter these in unsubstituted form. + ty::ReClosureBound(vid) => write!(self.printer, "{:?}", vid)?, + } + + Ok(self.printer) + } + fn path_crate( mut self: PrintCx<'_, '_, '_, Self>, cnum: CrateNum, @@ -1018,7 +1120,59 @@ fn nest<'a, 'gcx, 'tcx, E>( }) } - fn region_highlight_mode(&self) -> RegionHighlightMode { - self.region_highlight_mode + fn always_print_region_in_paths( + self: &PrintCx<'_, '_, '_, Self>, + region: ty::Region<'_>, + ) -> bool { + *region != ty::ReErased + } + + fn print_region_outputs_anything( + self: &PrintCx<'_, '_, '_, Self>, + region: ty::Region<'_>, + ) -> bool { + let highlight = self.printer.region_highlight_mode; + if highlight.region_highlighted(region).is_some() { + return true; + } + + if self.config.is_verbose { + return true; + } + + match *region { + ty::ReEarlyBound(ref data) => { + data.name != "" && data.name != "'_" + } + + ty::ReLateBound(_, br) | + ty::ReFree(ty::FreeRegion { bound_region: br, .. }) | + ty::RePlaceholder(ty::Placeholder { name: br, .. }) => { + if let ty::BrNamed(_, name) = br { + if name != "" && name != "'_" { + return true; + } + } + + if let Some((region, _)) = highlight.highlight_bound_region { + if br == region { + return true; + } + } + + false + } + + ty::ReScope(_) | + ty::ReVar(_) if self.config.identify_regions => true, + + ty::ReVar(_) | + ty::ReScope(_) | + ty::ReErased => false, + + ty::ReStatic | + ty::ReEmpty | + ty::ReClosureBound(_) => true, + } } } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 1ac6f3fea4c..e14741f55ef 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -1,6 +1,5 @@ use crate::hir::def::Namespace; use crate::hir::def_id::DefId; -use crate::middle::region; use crate::ty::subst::{Kind, Subst, SubstsRef, UnpackedKind}; use crate::ty::{Bool, Char, Adt}; use crate::ty::{Error, Str, Array, Slice, Float, FnDef, FnPtr}; @@ -487,72 +486,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { define_print! { () ty::RegionKind, (self, cx) { display { - // Watch out for region highlights. - let highlight = cx.printer.region_highlight_mode(); - if let Some(n) = highlight.region_highlighted(self) { - p!(write("'{}", n)); - return Ok(cx.printer); - } - - if cx.config.is_verbose { - return self.print_debug(cx); - } - - // These printouts are concise. They do not contain all the information - // the user might want to diagnose an error, but there is basically no way - // to fit that into a short string. Hence the recommendation to use - // `explain_region()` or `note_and_explain_region()`. - match *self { - ty::ReEarlyBound(ref data) => { - if data.name != "'_" { - p!(write("{}", data.name)) - } - } - ty::ReLateBound(_, br) | - ty::ReFree(ty::FreeRegion { bound_region: br, .. }) | - ty::RePlaceholder(ty::Placeholder { name: br, .. }) => { - if let ty::BrNamed(_, name) = br { - if name != "" && name != "'_" { - p!(write("{}", name)); - return Ok(cx.printer); - } - } - - if let Some((region, counter)) = highlight.highlight_bound_region { - if br == region { - p!(write("'{}", counter)); - } - } - } - ty::ReScope(scope) if cx.config.identify_regions => { - match scope.data { - region::ScopeData::Node => - p!(write("'{}s", scope.item_local_id().as_usize())), - region::ScopeData::CallSite => - p!(write("'{}cs", scope.item_local_id().as_usize())), - region::ScopeData::Arguments => - p!(write("'{}as", scope.item_local_id().as_usize())), - region::ScopeData::Destruction => - p!(write("'{}ds", scope.item_local_id().as_usize())), - region::ScopeData::Remainder(first_statement_index) => p!(write( - "'{}_{}rs", - scope.item_local_id().as_usize(), - first_statement_index.index() - )), - } - } - ty::ReVar(region_vid) if cx.config.identify_regions => { - p!(write("{:?}", region_vid)); - } - ty::ReVar(_) => {} - ty::ReScope(_) | - ty::ReErased => {} - ty::ReStatic => p!(write("'static")), - ty::ReEmpty => p!(write("'")), - - // The user should never encounter these in unsubstituted form. - ty::ReClosureBound(vid) => p!(write("{:?}", vid)), - } + return cx.print_region(self); } debug { match *self { @@ -594,63 +528,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } } -// HACK(eddyb) Trying to print a lifetime might not print anything, which -// may need special handling in the caller (of `ty::RegionKind::print`). -// To avoid printing to a temporary string, the `display_outputs_anything` -// method can instead be used to determine this, ahead of time. -// -// NB: this must be kept in sync with the printing logic above. -impl ty::RegionKind { - // HACK(eddyb) `pub(crate)` only for `ty::print`. - pub(crate) fn display_outputs_anything

(&self, cx: &PrintCx<'_, '_, '_, P>) -> bool - where P: PrettyPrinter - { - let highlight = cx.printer.region_highlight_mode(); - if highlight.region_highlighted(self).is_some() { - return true; - } - - if cx.config.is_verbose { - return true; - } - - match *self { - ty::ReEarlyBound(ref data) => { - data.name != "" && data.name != "'_" - } - - ty::ReLateBound(_, br) | - ty::ReFree(ty::FreeRegion { bound_region: br, .. }) | - ty::RePlaceholder(ty::Placeholder { name: br, .. }) => { - if let ty::BrNamed(_, name) = br { - if name != "" && name != "'_" { - return true; - } - } - - if let Some((region, _)) = highlight.highlight_bound_region { - if br == region { - return true; - } - } - - false - } - - ty::ReScope(_) | - ty::ReVar(_) if cx.config.identify_regions => true, - - ty::ReVar(_) | - ty::ReScope(_) | - ty::ReErased => false, - - ty::ReStatic | - ty::ReEmpty | - ty::ReClosureBound(_) => true, - } - } -} - define_print! { () ty::FreeRegion, (self, cx) { debug { @@ -830,7 +707,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } Ref(r, ty, mutbl) => { p!(write("&")); - if r.display_outputs_anything(&cx) { + if cx.print_region_outputs_anything(r) { p!(print_display(r), write(" ")); } p!(print(ty::TypeAndMut { ty, mutbl })) @@ -889,7 +766,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { )); } Dynamic(data, r) => { - let print_r = r.display_outputs_anything(&cx); + let print_r = cx.print_region_outputs_anything(r); if print_r { p!(write("(")); } diff --git a/src/librustc_codegen_utils/symbol_names.rs b/src/librustc_codegen_utils/symbol_names.rs index 2f962733118..912f8149513 100644 --- a/src/librustc_codegen_utils/symbol_names.rs +++ b/src/librustc_codegen_utils/symbol_names.rs @@ -409,6 +409,14 @@ impl Printer for SymbolPath { type Error = fmt::Error; type Path = Self; + type Region = Self; + + fn print_region( + self: PrintCx<'_, '_, '_, Self>, + _region: ty::Region<'_>, + ) -> Result { + Ok(self.printer) + } fn path_crate( mut self: PrintCx<'_, '_, '_, Self>, @@ -511,7 +519,14 @@ fn path_generic_args<'gcx, 'tcx>( } } -impl PrettyPrinter for SymbolPath {} +impl PrettyPrinter for SymbolPath { + fn print_region_outputs_anything( + self: &PrintCx<'_, '_, '_, Self>, + _region: ty::Region<'_>, + ) -> bool { + false + } +} impl fmt::Write for SymbolPath { fn write_str(&mut self, s: &str) -> fmt::Result { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 536ee3d58d6..bceae24b1b4 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -4233,6 +4233,14 @@ impl Printer for AbsolutePathPrinter { type Error = !; type Path = Vec; + type Region = (); + + fn print_region( + self: PrintCx<'_, '_, '_, Self>, + _region: ty::Region<'_>, + ) -> Result { + Ok(()) + } fn path_crate( self: PrintCx<'_, '_, '_, Self>, -- 2.44.0