Skip to content

Commit 88d96b2

Browse files
committed
rustc: support overriding region printing in ty::print::Printer.
1 parent fc914aa commit 88d96b2

File tree

5 files changed

+199
-137
lines changed

5 files changed

+199
-137
lines changed

src/librustc/infer/error_reporting/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
457457
type Error = NonTrivialPath;
458458

459459
type Path = Vec<String>;
460+
type Region = !;
461+
462+
fn print_region(
463+
self: PrintCx<'_, '_, '_, Self>,
464+
_region: ty::Region<'_>,
465+
) -> Result<Self::Region, Self::Error> {
466+
Err(NonTrivialPath)
467+
}
460468

461469
fn path_crate(
462470
self: PrintCx<'_, '_, '_, Self>,

src/librustc/ty/print.rs

Lines changed: 164 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::hir::def::Namespace;
22
use crate::hir::map::DefPathData;
33
use crate::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
4+
use crate::middle::region;
45
use crate::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable};
56
use crate::ty::subst::{Kind, Subst, SubstsRef, UnpackedKind};
67
use crate::middle::cstore::{ExternCrate, ExternCrateSource};
@@ -67,7 +68,7 @@ pub struct RegionHighlightMode {
6768
/// This is used when you have a signature like `fn foo(x: &u32,
6869
/// y: &'a u32)` and we want to give a name to the region of the
6970
/// reference `x`.
70-
pub(crate) highlight_bound_region: Option<(ty::BoundRegion, usize)>,
71+
highlight_bound_region: Option<(ty::BoundRegion, usize)>,
7172
}
7273

7374
impl RegionHighlightMode {
@@ -114,7 +115,7 @@ impl RegionHighlightMode {
114115
}
115116

116117
/// Returns `Some(n)` with the number to use for the given region, if any.
117-
pub(crate) fn region_highlighted(&self, region: ty::Region<'_>) -> Option<usize> {
118+
fn region_highlighted(&self, region: ty::Region<'_>) -> Option<usize> {
118119
self
119120
.highlight_regions
120121
.iter()
@@ -250,6 +251,7 @@ pub trait Printer: Sized {
250251
type Error;
251252

252253
type Path;
254+
type Region;
253255

254256
fn print_def_path(
255257
self: PrintCx<'_, '_, 'tcx, Self>,
@@ -271,6 +273,11 @@ pub trait Printer: Sized {
271273
self.default_print_impl_path(impl_def_id, substs, ns, self_ty, trait_ref)
272274
}
273275

276+
fn print_region(
277+
self: PrintCx<'_, '_, '_, Self>,
278+
region: ty::Region<'_>,
279+
) -> Result<Self::Region, Self::Error>;
280+
274281
fn path_crate(
275282
self: PrintCx<'_, '_, '_, Self>,
276283
cnum: CrateNum,
@@ -310,7 +317,7 @@ pub trait Printer: Sized {
310317
}
311318

312319
/// Trait for printers that pretty-print using `fmt::Write` to the printer.
313-
pub trait PrettyPrinter: Printer<Error = fmt::Error, Path = Self> + fmt::Write {
320+
pub trait PrettyPrinter: Printer<Error = fmt::Error, Path = Self, Region = Self> + fmt::Write {
314321
/// Enter a nested print context, for pretty-printing
315322
/// nested components in some larger context.
316323
fn nest<'a, 'gcx, 'tcx, E>(
@@ -329,9 +336,26 @@ pub trait PrettyPrinter: Printer<Error = fmt::Error, Path = Self> + fmt::Write {
329336
})
330337
}
331338

332-
fn region_highlight_mode(&self) -> RegionHighlightMode {
333-
RegionHighlightMode::default()
339+
/// Return `true` if the region should be printed in path generic args
340+
/// even when it's `'_`, such as in e.g. `Foo<'_, '_, '_>`.
341+
fn always_print_region_in_paths(
342+
self: &PrintCx<'_, '_, '_, Self>,
343+
_region: ty::Region<'_>,
344+
) -> bool {
345+
false
334346
}
347+
348+
// HACK(eddyb) Trying to print a lifetime might not print anything, which
349+
// may need special handling in the caller (of `ty::RegionKind::print`).
350+
// To avoid printing to a temporary string (which isn't even supported),
351+
// the `print_region_outputs_anything` method can instead be used to
352+
// determine this, ahead of time.
353+
//
354+
// NB: this must be kept in sync with the implementation of `print_region`.
355+
fn print_region_outputs_anything(
356+
self: &PrintCx<'_, '_, '_, Self>,
357+
region: ty::Region<'_>,
358+
) -> bool;
335359
}
336360

337361
macro_rules! nest {
@@ -795,10 +819,13 @@ impl<'gcx, 'tcx, P: PrettyPrinter> PrintCx<'_, 'gcx, 'tcx, P> {
795819

796820
let start = if ns == Namespace::ValueNS { "::<" } else { "<" };
797821

798-
// Don't print any regions if they're all erased.
822+
// Don't print `'_` if there's no printed region.
799823
let print_regions = params.iter().any(|param| {
800824
match substs[param.index as usize].unpack() {
801-
UnpackedKind::Lifetime(r) => *r != ty::ReErased,
825+
UnpackedKind::Lifetime(r) => {
826+
self.always_print_region_in_paths(r) ||
827+
self.print_region_outputs_anything(r)
828+
}
802829
_ => false,
803830
}
804831
});
@@ -827,7 +854,7 @@ impl<'gcx, 'tcx, P: PrettyPrinter> PrintCx<'_, 'gcx, 'tcx, P> {
827854
continue;
828855
}
829856
start_or_continue(&mut self, start, ", ")?;
830-
if !region.display_outputs_anything(&self) {
857+
if !self.print_region_outputs_anything(region) {
831858
// This happens when the value of the region
832859
// parameter is not easily serialized. This may be
833860
// because the user omitted it in the first place,
@@ -873,6 +900,7 @@ impl<F: fmt::Write> Printer for FmtPrinter<F> {
873900
type Error = fmt::Error;
874901

875902
type Path = Self;
903+
type Region = Self;
876904

877905
fn print_def_path(
878906
mut self: PrintCx<'_, '_, 'tcx, Self>,
@@ -929,6 +957,80 @@ impl<F: fmt::Write> Printer for FmtPrinter<F> {
929957
self.default_print_def_path(def_id, substs, ns, projections)
930958
}
931959

960+
fn print_region(
961+
mut self: PrintCx<'_, '_, '_, Self>,
962+
region: ty::Region<'_>,
963+
) -> Result<Self::Region, Self::Error> {
964+
// Watch out for region highlights.
965+
let highlight = self.printer.region_highlight_mode;
966+
if let Some(n) = highlight.region_highlighted(region) {
967+
write!(self.printer, "'{}", n)?;
968+
return Ok(self.printer);
969+
}
970+
971+
if self.config.is_verbose {
972+
return region.print_debug(self);
973+
}
974+
975+
// These printouts are concise. They do not contain all the information
976+
// the user might want to diagnose an error, but there is basically no way
977+
// to fit that into a short string. Hence the recommendation to use
978+
// `explain_region()` or `note_and_explain_region()`.
979+
match *region {
980+
ty::ReEarlyBound(ref data) => {
981+
if data.name != "'_" {
982+
write!(self.printer, "{}", data.name)?;
983+
}
984+
}
985+
ty::ReLateBound(_, br) |
986+
ty::ReFree(ty::FreeRegion { bound_region: br, .. }) |
987+
ty::RePlaceholder(ty::Placeholder { name: br, .. }) => {
988+
if let ty::BrNamed(_, name) = br {
989+
if name != "" && name != "'_" {
990+
write!(self.printer, "{}", name)?;
991+
return Ok(self.printer);
992+
}
993+
}
994+
995+
if let Some((region, counter)) = highlight.highlight_bound_region {
996+
if br == region {
997+
write!(self.printer, "'{}", counter)?;
998+
}
999+
}
1000+
}
1001+
ty::ReScope(scope) if self.config.identify_regions => {
1002+
match scope.data {
1003+
region::ScopeData::Node =>
1004+
write!(self.printer, "'{}s", scope.item_local_id().as_usize())?,
1005+
region::ScopeData::CallSite =>
1006+
write!(self.printer, "'{}cs", scope.item_local_id().as_usize())?,
1007+
region::ScopeData::Arguments =>
1008+
write!(self.printer, "'{}as", scope.item_local_id().as_usize())?,
1009+
region::ScopeData::Destruction =>
1010+
write!(self.printer, "'{}ds", scope.item_local_id().as_usize())?,
1011+
region::ScopeData::Remainder(first_statement_index) => write!(self.printer,
1012+
"'{}_{}rs",
1013+
scope.item_local_id().as_usize(),
1014+
first_statement_index.index()
1015+
)?,
1016+
}
1017+
}
1018+
ty::ReVar(region_vid) if self.config.identify_regions => {
1019+
write!(self.printer, "{:?}", region_vid)?;
1020+
}
1021+
ty::ReVar(_) => {}
1022+
ty::ReScope(_) |
1023+
ty::ReErased => {}
1024+
ty::ReStatic => write!(self.printer, "'static")?,
1025+
ty::ReEmpty => write!(self.printer, "'<empty>")?,
1026+
1027+
// The user should never encounter these in unsubstituted form.
1028+
ty::ReClosureBound(vid) => write!(self.printer, "{:?}", vid)?,
1029+
}
1030+
1031+
Ok(self.printer)
1032+
}
1033+
9321034
fn path_crate(
9331035
mut self: PrintCx<'_, '_, '_, Self>,
9341036
cnum: CrateNum,
@@ -1018,7 +1120,59 @@ impl<F: fmt::Write> PrettyPrinter for FmtPrinter<F> {
10181120
})
10191121
}
10201122

1021-
fn region_highlight_mode(&self) -> RegionHighlightMode {
1022-
self.region_highlight_mode
1123+
fn always_print_region_in_paths(
1124+
self: &PrintCx<'_, '_, '_, Self>,
1125+
region: ty::Region<'_>,
1126+
) -> bool {
1127+
*region != ty::ReErased
1128+
}
1129+
1130+
fn print_region_outputs_anything(
1131+
self: &PrintCx<'_, '_, '_, Self>,
1132+
region: ty::Region<'_>,
1133+
) -> bool {
1134+
let highlight = self.printer.region_highlight_mode;
1135+
if highlight.region_highlighted(region).is_some() {
1136+
return true;
1137+
}
1138+
1139+
if self.config.is_verbose {
1140+
return true;
1141+
}
1142+
1143+
match *region {
1144+
ty::ReEarlyBound(ref data) => {
1145+
data.name != "" && data.name != "'_"
1146+
}
1147+
1148+
ty::ReLateBound(_, br) |
1149+
ty::ReFree(ty::FreeRegion { bound_region: br, .. }) |
1150+
ty::RePlaceholder(ty::Placeholder { name: br, .. }) => {
1151+
if let ty::BrNamed(_, name) = br {
1152+
if name != "" && name != "'_" {
1153+
return true;
1154+
}
1155+
}
1156+
1157+
if let Some((region, _)) = highlight.highlight_bound_region {
1158+
if br == region {
1159+
return true;
1160+
}
1161+
}
1162+
1163+
false
1164+
}
1165+
1166+
ty::ReScope(_) |
1167+
ty::ReVar(_) if self.config.identify_regions => true,
1168+
1169+
ty::ReVar(_) |
1170+
ty::ReScope(_) |
1171+
ty::ReErased => false,
1172+
1173+
ty::ReStatic |
1174+
ty::ReEmpty |
1175+
ty::ReClosureBound(_) => true,
1176+
}
10231177
}
10241178
}

0 commit comments

Comments
 (0)