Skip to content

Commit 556d2b3

Browse files
committed
rustc: support overriding region printing in ty::print::Printer.
1 parent 39359c7 commit 556d2b3

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
@@ -458,6 +458,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
458458
type Error = NonTrivialPath;
459459

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

462470
fn path_crate(
463471
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 hir::def::Namespace;
22
use hir::map::DefPathData;
33
use hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
4+
use middle::region;
45
use ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable};
56
use ty::subst::{Kind, Subst, Substs, UnpackedKind};
67
use 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 {
@@ -115,7 +116,7 @@ impl RegionHighlightMode {
115116

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

253254
type Path;
255+
type Region;
254256

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

277+
fn print_region(
278+
self: PrintCx<'_, '_, '_, Self>,
279+
region: ty::Region<'_>,
280+
) -> Result<Self::Region, Self::Error>;
281+
275282
fn path_crate(
276283
self: PrintCx<'_, '_, '_, Self>,
277284
cnum: CrateNum,
@@ -311,7 +318,7 @@ pub trait Printer: Sized {
311318
}
312319

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

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

338362
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
});
@@ -826,7 +853,7 @@ impl<'gcx, 'tcx, P: PrettyPrinter> PrintCx<'_, 'gcx, 'tcx, P> {
826853
continue;
827854
}
828855
start_or_continue(&mut self, start, ", ")?;
829-
if !region.display_outputs_anything(&self) {
856+
if !self.print_region_outputs_anything(region) {
830857
// This happens when the value of the region
831858
// parameter is not easily serialized. This may be
832859
// because the user omitted it in the first place,
@@ -868,6 +895,7 @@ impl<F: fmt::Write> Printer for FmtPrinter<F> {
868895
type Error = fmt::Error;
869896

870897
type Path = Self;
898+
type Region = Self;
871899

872900
fn print_def_path(
873901
mut self: PrintCx<'_, '_, 'tcx, Self>,
@@ -924,6 +952,80 @@ impl<F: fmt::Write> Printer for FmtPrinter<F> {
924952
self.default_print_def_path(def_id, substs, ns, projections)
925953
}
926954

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

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

0 commit comments

Comments
 (0)