rustc: introduce a ty::print::PrettyPrinter helper for printing "<...>".

This commit is contained in:
Eduard-Mihai Burtescu 2019-01-14 22:07:38 +02:00
parent 35e5123f51
commit ab26b26d34
2 changed files with 133 additions and 118 deletions

View file

@ -336,7 +336,7 @@ pub trait PrettyPrinter:
/// nested components in some larger context.
fn nest<'a, 'gcx, 'tcx, E>(
self: PrintCx<'a, 'gcx, 'tcx, Self>,
f: impl for<'b> FnOnce(PrintCx<'b, 'gcx, 'tcx, Self>) -> Result<Self, E>,
f: impl FnOnce(PrintCx<'_, 'gcx, 'tcx, Self>) -> Result<Self, E>,
) -> Result<PrintCx<'a, 'gcx, 'tcx, Self>, E> {
let printer = f(PrintCx {
tcx: self.tcx,
@ -350,6 +350,17 @@ pub trait PrettyPrinter:
})
}
/// Print `<...>` around what `f` prints.
fn generic_delimiters<'gcx, 'tcx>(
mut self: PrintCx<'_, 'gcx, 'tcx, Self>,
f: impl FnOnce(PrintCx<'_, 'gcx, 'tcx, Self>) -> Result<Self, Self::Error>,
) -> Result<Self, Self::Error> {
write!(self.printer, "<")?;
let mut printer = f(self)?;
write!(printer, ">")?;
Ok(printer)
}
/// 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(
@ -746,7 +757,7 @@ impl<'gcx, 'tcx, P: PrettyPrinter> PrintCx<'_, 'gcx, 'tcx, P> {
}
pub fn pretty_path_qualified(
mut self,
self,
self_ty: Ty<'tcx>,
trait_ref: Option<ty::TraitRef<'tcx>>,
ns: Namespace,
@ -772,20 +783,19 @@ impl<'gcx, 'tcx, P: PrettyPrinter> PrintCx<'_, 'gcx, 'tcx, P> {
}
}
write!(self.printer, "<")?;
nest!(self, |cx| self_ty.print_display(cx));
if let Some(trait_ref) = trait_ref {
write!(self.printer, " as ")?;
nest!(self, |cx| cx.print_def_path(
trait_ref.def_id,
Some(trait_ref.substs),
Namespace::TypeNS,
iter::empty(),
));
}
write!(self.printer, ">")?;
Ok(self.printer)
self.generic_delimiters(|mut cx| {
nest!(cx, |cx| self_ty.print_display(cx));
if let Some(trait_ref) = trait_ref {
write!(cx.printer, " as ")?;
nest!(cx, |cx| cx.print_def_path(
trait_ref.def_id,
Some(trait_ref.substs),
Namespace::TypeNS,
iter::empty(),
));
}
Ok(cx.printer)
})
}
pub fn pretty_path_append_impl(
@ -796,17 +806,18 @@ impl<'gcx, 'tcx, P: PrettyPrinter> PrintCx<'_, 'gcx, 'tcx, P> {
self_ty: Ty<'tcx>,
trait_ref: Option<ty::TraitRef<'tcx>>,
) -> Result<P::Path, P::Error> {
// HACK(eddyb) going through `path_append` means symbol name
// computation gets to handle its equivalent of `::` correctly.
nest!(self, |cx| cx.path_append(print_prefix, "<impl "));
if let Some(trait_ref) = trait_ref {
nest!(self, |cx| trait_ref.print_display(cx));
write!(self.printer, " for ")?;
}
nest!(self, |cx| self_ty.print_display(cx));
write!(self.printer, ">")?;
nest!(self, print_prefix);
Ok(self.printer)
self.generic_delimiters(|mut cx| {
write!(cx.printer, "impl ")?;
if let Some(trait_ref) = trait_ref {
nest!(cx, |cx| trait_ref.print_display(cx));
write!(cx.printer, " for ")?;
}
nest!(cx, |cx| self_ty.print_display(cx));
Ok(cx.printer)
})
}
pub fn pretty_path_generic_args(
@ -821,18 +832,6 @@ impl<'gcx, 'tcx, P: PrettyPrinter> PrintCx<'_, 'gcx, 'tcx, P> {
) -> Result<P::Path, P::Error> {
nest!(self, |cx| print_prefix(cx));
let mut empty = true;
let mut start_or_continue = |cx: &mut Self, start: &str, cont: &str| {
write!(cx.printer, "{}", if empty {
empty = false;
start
} else {
cont
})
};
let start = if ns == Namespace::ValueNS { "::<" } else { "<" };
// Don't print `'_` if there's no printed region.
let print_regions = params.iter().any(|param| {
match substs[param.index as usize].unpack() {
@ -861,45 +860,75 @@ impl<'gcx, 'tcx, P: PrettyPrinter> PrintCx<'_, 'gcx, 'tcx, P> {
}).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(&mut self, start, ", ")?;
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,
// or because it refers to some block in the code,
// etc. I'm not sure how best to serialize this.
write!(self.printer, "'_")?;
} else {
nest!(self, |cx| region.print_display(cx));
}
let params = &params[..params.len() - num_supplied_defaults];
let mut args = params.iter().map(|param| {
substs[param.index as usize].unpack()
}).filter(|arg| {
match arg {
UnpackedKind::Lifetime(_) => print_regions,
_ => true,
}
});
let arg0 = args.next();
let mut projections = projections;
let projection0 = projections.next();
if arg0.is_none() && projection0.is_none() {
return Ok(self.printer);
}
// FIXME(eddyb) move this into `generic_delimiters`.
if ns == Namespace::ValueNS {
write!(self.printer, "::")?;
}
self.generic_delimiters(|mut cx| {
let mut empty = true;
let mut maybe_comma = |cx: &mut Self| {
if empty {
empty = false;
Ok(())
} else {
write!(cx.printer, ", ")
}
UnpackedKind::Type(ty) => {
start_or_continue(&mut self, start, ", ")?;
nest!(self, |cx| ty.print_display(cx));
}
UnpackedKind::Const(ct) => {
start_or_continue(&mut self, start, ", ")?;
nest!(self, |cx| ct.print_display(cx));
};
for arg in arg0.into_iter().chain(args) {
maybe_comma(&mut cx)?;
match arg {
UnpackedKind::Lifetime(region) => {
if !cx.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,
// or because it refers to some block in the code,
// etc. I'm not sure how best to serialize this.
write!(cx.printer, "'_")?;
} else {
nest!(cx, |cx| region.print_display(cx));
}
}
UnpackedKind::Type(ty) => {
nest!(cx, |cx| ty.print_display(cx));
}
UnpackedKind::Const(ct) => {
nest!(cx, |cx| ct.print_display(cx));
}
}
}
}
for projection in projections {
start_or_continue(&mut self, start, ", ")?;
write!(self.printer, "{}=",
self.tcx.associated_item(projection.item_def_id).ident)?;
nest!(self, |cx| projection.ty.print_display(cx));
}
for projection in projection0.into_iter().chain(projections) {
maybe_comma(&mut cx)?;
start_or_continue(&mut self, "", ">")?;
write!(cx.printer, "{}=",
cx.tcx.associated_item(projection.item_def_id).ident)?;
nest!(cx, |cx| projection.ty.print_display(cx));
}
Ok(self.printer)
Ok(cx.printer)
})
}
}
@ -1087,7 +1116,15 @@ impl<F: fmt::Write> Printer for FmtPrinter<F> {
self_ty: Ty<'tcx>,
trait_ref: Option<ty::TraitRef<'tcx>>,
) -> Result<Self::Path, Self::Error> {
self.pretty_path_append_impl(print_prefix, self_ty, trait_ref)
self.pretty_path_append_impl(|cx| {
let mut printer = print_prefix(cx)?;
if !printer.empty {
write!(printer, "::")?;
}
Ok(printer)
}, self_ty, trait_ref)
}
fn path_append<'gcx, 'tcx>(
self: PrintCx<'_, 'gcx, 'tcx, Self>,
@ -1126,7 +1163,7 @@ impl<F: fmt::Write> Printer for FmtPrinter<F> {
impl<F: fmt::Write> PrettyPrinter for FmtPrinter<F> {
fn nest<'a, 'gcx, 'tcx, E>(
mut self: PrintCx<'a, 'gcx, 'tcx, Self>,
f: impl for<'b> FnOnce(PrintCx<'b, 'gcx, 'tcx, Self>) -> Result<Self, E>,
f: impl FnOnce(PrintCx<'_, 'gcx, 'tcx, Self>) -> Result<Self, E>,
) -> Result<PrintCx<'a, 'gcx, 'tcx, Self>, E> {
let was_empty = std::mem::replace(&mut self.printer.empty, true);
let mut printer = f(PrintCx {

View file

@ -434,28 +434,12 @@ impl Printer for SymbolPath {
Ok(self.printer)
}
fn path_qualified(
mut self: PrintCx<'_, '_, 'tcx, Self>,
self: PrintCx<'_, '_, 'tcx, Self>,
self_ty: Ty<'tcx>,
trait_ref: Option<ty::TraitRef<'tcx>>,
ns: Namespace,
) -> Result<Self::Path, Self::Error> {
// HACK(eddyb) avoid `keep_within_component` for the cases
// that print without `<...>` around `self_ty`.
match self_ty.sty {
ty::Adt(..) | ty::Foreign(_) |
ty::Bool | ty::Char | ty::Str |
ty::Int(_) | ty::Uint(_) | ty::Float(_)
if trait_ref.is_none() =>
{
return self.pretty_path_qualified(self_ty, trait_ref, ns);
}
_ => {}
}
let kept_within_component = mem::replace(&mut self.printer.keep_within_component, true);
let mut path = self.pretty_path_qualified(self_ty, trait_ref, ns)?;
path.keep_within_component = kept_within_component;
Ok(path)
self.pretty_path_qualified(self_ty, trait_ref, ns)
}
fn path_append_impl<'gcx, 'tcx>(
@ -466,18 +450,11 @@ impl Printer for SymbolPath {
self_ty: Ty<'tcx>,
trait_ref: Option<ty::TraitRef<'tcx>>,
) -> Result<Self::Path, Self::Error> {
let kept_within_component = self.printer.keep_within_component;
let mut path = self.pretty_path_append_impl(
|cx| {
let mut path = print_prefix(cx)?;
path.keep_within_component = true;
Ok(path)
},
self.pretty_path_append_impl(
|cx| cx.path_append(print_prefix, ""),
self_ty,
trait_ref,
)?;
path.keep_within_component = kept_within_component;
Ok(path)
)
}
fn path_append<'gcx, 'tcx>(
self: PrintCx<'_, 'gcx, 'tcx, Self>,
@ -486,11 +463,9 @@ impl Printer for SymbolPath {
) -> Result<Self::Path, Self::Error>,
text: &str,
) -> Result<Self::Path, Self::Error> {
let keep_within_component = self.printer.keep_within_component;
let mut path = print_prefix(self)?;
if keep_within_component {
if path.keep_within_component {
// HACK(eddyb) print the path similarly to how `FmtPrinter` prints it.
path.write_str("::")?;
} else {
@ -510,20 +485,7 @@ impl Printer for SymbolPath {
ns: Namespace,
projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
) -> Result<Self::Path, Self::Error> {
let kept_within_component = self.printer.keep_within_component;
let mut path = self.pretty_path_generic_args(
|cx| {
let mut path = print_prefix(cx)?;
path.keep_within_component = true;
Ok(path)
},
params,
substs,
ns,
projections,
)?;
path.keep_within_component = kept_within_component;
Ok(path)
self.pretty_path_generic_args(print_prefix, params, substs, ns, projections)
}
}
@ -534,6 +496,22 @@ impl PrettyPrinter for SymbolPath {
) -> bool {
false
}
fn generic_delimiters<'gcx, 'tcx>(
mut self: PrintCx<'_, 'gcx, 'tcx, Self>,
f: impl FnOnce(PrintCx<'_, 'gcx, 'tcx, Self>) -> Result<Self, Self::Error>,
) -> Result<Self, Self::Error> {
write!(self.printer, "<")?;
let kept_within_component =
mem::replace(&mut self.printer.keep_within_component, true);
let mut path = f(self)?;
path.keep_within_component = kept_within_component;
write!(path, ">")?;
Ok(path)
}
}
impl fmt::Write for SymbolPath {