2 use crate::hir::def::Namespace;
3 use crate::hir::map::DefPathData;
4 use crate::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
5 use crate::middle::cstore::{ExternCrate, ExternCrateSource};
6 use crate::middle::region;
7 use crate::ty::{self, DefIdTree, ParamConst, Ty, TyCtxt, TypeFoldable};
8 use crate::ty::subst::{Kind, Subst, SubstsRef, UnpackedKind};
9 use crate::mir::interpret::ConstValue;
10 use syntax::symbol::{keywords, Symbol};
12 use syntax::symbol::InternedString;
15 use std::fmt::{self, Write as _};
18 // `pretty` is a separate module only for organization.
23 scoped_cx!() = scoped_cx!().nest($closure)?
26 macro_rules! print_inner {
27 (write ($($data:expr),+)) => {
28 write!(scoped_cx!().printer, $($data),+)?
30 ($kind:ident ($data:expr)) => {
31 nest!(|cx| $data.$kind(cx))
35 ($($kind:ident $data:tt),+) => {
37 $(print_inner!($kind $data));+
41 macro_rules! define_scoped_cx {
43 #[allow(unused_macros)]
44 macro_rules! scoped_cx {
51 static FORCE_IMPL_FILENAME_LINE: Cell<bool> = Cell::new(false);
52 static SHOULD_PREFIX_WITH_CRATE: Cell<bool> = Cell::new(false);
55 /// Force us to name impls with just the filename/line number. We
56 /// normally try to use types. But at some points, notably while printing
57 /// cycle errors, this can result in extra or suboptimal error output,
58 /// so this variable disables that check.
59 pub fn with_forced_impl_filename_line<F: FnOnce() -> R, R>(f: F) -> R {
60 FORCE_IMPL_FILENAME_LINE.with(|force| {
61 let old = force.get();
69 /// Adds the `crate::` prefix to paths where appropriate.
70 pub fn with_crate_prefix<F: FnOnce() -> R, R>(f: F) -> R {
71 SHOULD_PREFIX_WITH_CRATE.with(|flag| {
80 /// The "region highlights" are used to control region printing during
81 /// specific error messages. When a "region highlight" is enabled, it
82 /// gives an alternate way to print specific regions. For now, we
83 /// always print those regions using a number, so something like "`'0`".
85 /// Regions not selected by the region highlight mode are presently
87 #[derive(Copy, Clone, Default)]
88 pub struct RegionHighlightMode {
89 /// If enabled, when we see the selected region, use "`'N`"
90 /// instead of the ordinary behavior.
91 highlight_regions: [Option<(ty::RegionKind, usize)>; 3],
93 /// If enabled, when printing a "free region" that originated from
94 /// the given `ty::BoundRegion`, print it as "`'1`". Free regions that would ordinarily
95 /// have names print as normal.
97 /// This is used when you have a signature like `fn foo(x: &u32,
98 /// y: &'a u32)` and we want to give a name to the region of the
100 highlight_bound_region: Option<(ty::BoundRegion, usize)>,
103 impl RegionHighlightMode {
104 /// If `region` and `number` are both `Some`, invokes
105 /// `highlighting_region`.
106 pub fn maybe_highlighting_region(
108 region: Option<ty::Region<'_>>,
109 number: Option<usize>,
111 if let Some(k) = region {
112 if let Some(n) = number {
113 self.highlighting_region(k, n);
118 /// Highlights the region inference variable `vid` as `'N`.
119 pub fn highlighting_region(
121 region: ty::Region<'_>,
124 let num_slots = self.highlight_regions.len();
125 let first_avail_slot = self.highlight_regions.iter_mut()
126 .filter(|s| s.is_none())
130 "can only highlight {} placeholders at a time",
134 *first_avail_slot = Some((*region, number));
137 /// Convenience wrapper for `highlighting_region`.
138 pub fn highlighting_region_vid(
143 self.highlighting_region(&ty::ReVar(vid), number)
146 /// Returns `Some(n)` with the number to use for the given region, if any.
147 fn region_highlighted(&self, region: ty::Region<'_>) -> Option<usize> {
151 .filter_map(|h| match h {
152 Some((r, n)) if r == region => Some(*n),
158 /// Highlight the given bound region.
159 /// We can only highlight one bound region at a time. See
160 /// the field `highlight_bound_region` for more detailed notes.
161 pub fn highlighting_bound_region(
166 assert!(self.highlight_bound_region.is_none());
167 self.highlight_bound_region = Some((br, number));
171 /// Trait for printers that pretty-print using `fmt::Write` to the printer.
172 pub trait PrettyPrinter:
181 /// Enter a nested print context, for pretty-printing
182 /// nested components in some larger context.
183 fn nest<'a, 'gcx, 'tcx, E>(
184 self: PrintCx<'a, 'gcx, 'tcx, Self>,
185 f: impl FnOnce(PrintCx<'_, 'gcx, 'tcx, Self>) -> Result<Self, E>,
186 ) -> Result<PrintCx<'a, 'gcx, 'tcx, Self>, E> {
187 let printer = f(PrintCx {
189 printer: self.printer,
199 /// Like `print_def_path` but for value paths.
201 self: PrintCx<'_, '_, 'tcx, Self>,
203 substs: Option<SubstsRef<'tcx>>,
204 ) -> Result<Self::Path, Self::Error> {
205 self.print_def_path(def_id, substs, iter::empty())
209 self: PrintCx<'_, '_, 'tcx, Self>,
210 value: &ty::Binder<T>,
211 ) -> Result<Self, Self::Error>
212 where T: Print<'tcx, Self, Output = Self, Error = Self::Error> + TypeFoldable<'tcx>
214 value.skip_binder().print(self)
217 /// Print `<...>` around what `f` prints.
218 fn generic_delimiters<'gcx, 'tcx>(
219 self: PrintCx<'_, 'gcx, 'tcx, Self>,
220 f: impl FnOnce(PrintCx<'_, 'gcx, 'tcx, Self>) -> Result<Self, Self::Error>,
221 ) -> Result<Self, Self::Error>;
223 /// Return `true` if the region should be printed in path generic args
224 /// even when it's `'_`, such as in e.g. `Foo<'_, '_, '_>`.
225 fn always_print_region_in_paths(
226 self: &PrintCx<'_, '_, '_, Self>,
227 _region: ty::Region<'_>,
232 // HACK(eddyb) Trying to print a lifetime might not print anything, which
233 // may need special handling in the caller (of `ty::RegionKind::print`).
234 // To avoid printing to a temporary string (which isn't even supported),
235 // the `print_region_outputs_anything` method can instead be used to
236 // determine this, ahead of time.
238 // NB: this must be kept in sync with the implementation of `print_region`.
239 fn print_region_outputs_anything(
240 self: &PrintCx<'_, '_, '_, Self>,
241 region: ty::Region<'_>,
245 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
246 // HACK(eddyb) get rid of `def_path_str` and/or pass `Namespace` explicitly always
247 // (but also some things just print a `DefId` generally so maybe we need this?)
248 fn guess_def_namespace(self, def_id: DefId) -> Namespace {
249 match self.def_key(def_id).disambiguated_data.data {
250 DefPathData::ValueNs(..) |
251 DefPathData::EnumVariant(..) |
252 DefPathData::Field(..) |
253 DefPathData::AnonConst |
254 DefPathData::ConstParam(..) |
255 DefPathData::ClosureExpr |
256 DefPathData::StructCtor => Namespace::ValueNS,
258 DefPathData::MacroDef(..) => Namespace::MacroNS,
260 _ => Namespace::TypeNS,
264 /// Returns a string identifying this `DefId. This string is
265 /// suitable for user output.
266 pub fn def_path_str(self, def_id: DefId) -> String {
267 let ns = self.guess_def_namespace(def_id);
268 debug!("def_path_str: def_id={:?}, ns={:?}", def_id, ns);
269 let mut s = String::new();
270 let _ = PrintCx::with(self, FmtPrinter::new(&mut s, ns), |cx| {
271 cx.print_def_path(def_id, None, iter::empty())
277 pub struct FmtPrinter<F: fmt::Write> {
281 pub region_highlight_mode: RegionHighlightMode,
284 impl<F: fmt::Write> FmtPrinter<F> {
285 pub fn new(fmt: F, ns: Namespace) -> Self {
289 in_value: ns == Namespace::ValueNS,
290 region_highlight_mode: RegionHighlightMode::default(),
295 impl<'gcx, 'tcx, P: PrettyPrinter> PrintCx<'_, 'gcx, 'tcx, P> {
296 /// If possible, this returns a global path resolving to `def_id` that is visible
297 /// from at least one local module and returns true. If the crate defining `def_id` is
298 /// declared with an `extern crate`, the path is guaranteed to use the `extern crate`.
299 fn try_print_visible_def_path(
302 ) -> Result<(P, bool), P::Error> {
303 define_scoped_cx!(self);
305 debug!("try_print_visible_def_path: def_id={:?}", def_id);
307 // If `def_id` is a direct or injected extern crate, return the
308 // path to the crate followed by the path to the item within the crate.
309 if def_id.index == CRATE_DEF_INDEX {
310 let cnum = def_id.krate;
312 if cnum == LOCAL_CRATE {
313 return Ok((self.path_crate(cnum)?, true));
316 // In local mode, when we encounter a crate other than
317 // LOCAL_CRATE, execution proceeds in one of two ways:
319 // 1. for a direct dependency, where user added an
320 // `extern crate` manually, we put the `extern
321 // crate` as the parent. So you wind up with
322 // something relative to the current crate.
323 // 2. for an extern inferred from a path or an indirect crate,
324 // where there is no explicit `extern crate`, we just prepend
326 match *self.tcx.extern_crate(def_id) {
328 src: ExternCrateSource::Extern(def_id),
333 debug!("try_print_visible_def_path: def_id={:?}", def_id);
334 return Ok((if !span.is_dummy() {
335 self.print_def_path(def_id, None, iter::empty())?
337 self.path_crate(cnum)?
341 return Ok((self.path_crate(cnum)?, true));
347 if def_id.is_local() {
348 return Ok((self.printer, false));
351 let visible_parent_map = self.tcx.visible_parent_map(LOCAL_CRATE);
353 let mut cur_def_key = self.tcx.def_key(def_id);
354 debug!("try_print_visible_def_path: cur_def_key={:?}", cur_def_key);
356 // For a UnitStruct or TupleStruct we want the name of its parent rather than <unnamed>.
357 if let DefPathData::StructCtor = cur_def_key.disambiguated_data.data {
360 index: cur_def_key.parent.expect("DefPathData::StructCtor missing a parent"),
363 cur_def_key = self.tcx.def_key(parent);
366 let visible_parent = match visible_parent_map.get(&def_id).cloned() {
367 Some(parent) => parent,
368 None => return Ok((self.printer, false)),
370 // HACK(eddyb) this uses `nest` to avoid knowing ahead of time whether
371 // the entire path will succeed or not. To support printers that do not
372 // implement `PrettyPrinter`, a `Vec` or linked list on the stack would
373 // need to be built, before starting to print anything.
374 let mut prefix_success = false;
376 let (printer, success) = cx.try_print_visible_def_path(visible_parent)?;
377 prefix_success = success;
381 return Ok((self.printer, false));
383 let actual_parent = self.tcx.parent(def_id);
385 "try_print_visible_def_path: visible_parent={:?} actual_parent={:?}",
386 visible_parent, actual_parent,
389 let data = cur_def_key.disambiguated_data.data;
391 "try_print_visible_def_path: data={:?} visible_parent={:?} actual_parent={:?}",
392 data, visible_parent, actual_parent,
395 let symbol = match data {
396 // In order to output a path that could actually be imported (valid and visible),
397 // we need to handle re-exports correctly.
399 // For example, take `std::os::unix::process::CommandExt`, this trait is actually
400 // defined at `std::sys::unix::ext::process::CommandExt` (at time of writing).
402 // `std::os::unix` rexports the contents of `std::sys::unix::ext`. `std::sys` is
403 // private so the "true" path to `CommandExt` isn't accessible.
405 // In this case, the `visible_parent_map` will look something like this:
407 // (child) -> (parent)
408 // `std::sys::unix::ext::process::CommandExt` -> `std::sys::unix::ext::process`
409 // `std::sys::unix::ext::process` -> `std::sys::unix::ext`
410 // `std::sys::unix::ext` -> `std::os`
412 // This is correct, as the visible parent of `std::sys::unix::ext` is in fact
415 // When printing the path to `CommandExt` and looking at the `cur_def_key` that
416 // corresponds to `std::sys::unix::ext`, we would normally print `ext` and then go
417 // to the parent - resulting in a mangled path like
418 // `std::os::ext::process::CommandExt`.
420 // Instead, we must detect that there was a re-export and instead print `unix`
421 // (which is the name `std::sys::unix::ext` was re-exported as in `std::os`). To
422 // do this, we compare the parent of `std::sys::unix::ext` (`std::sys::unix`) with
423 // the visible parent (`std::os`). If these do not match, then we iterate over
424 // the children of the visible parent (as was done when computing
425 // `visible_parent_map`), looking for the specific child we currently have and then
426 // have access to the re-exported name.
427 DefPathData::Module(actual_name) |
428 DefPathData::TypeNs(actual_name) if Some(visible_parent) != actual_parent => {
429 self.tcx.item_children(visible_parent)
431 .find(|child| child.def.def_id() == def_id)
432 .map(|child| child.ident.as_str())
433 .unwrap_or_else(|| actual_name.as_str())
436 data.get_opt_name().map(|n| n.as_str()).unwrap_or_else(|| {
437 // Re-exported `extern crate` (#43189).
438 if let DefPathData::CrateRoot = data {
439 self.tcx.original_crate_name(def_id.krate).as_str()
441 Symbol::intern("<unnamed>").as_str()
446 debug!("try_print_visible_def_path: symbol={:?}", symbol);
447 Ok((self.path_append(|cx| Ok(cx.printer), &symbol)?, true))
450 pub fn pretty_path_qualified(
453 trait_ref: Option<ty::TraitRef<'tcx>>,
454 ) -> Result<P::Path, P::Error> {
455 if trait_ref.is_none() {
456 // Inherent impls. Try to print `Foo::bar` for an inherent
457 // impl on `Foo`, but fallback to `<Foo>::bar` if self-type is
458 // anything other than a simple path.
460 ty::Adt(..) | ty::Foreign(_) |
461 ty::Bool | ty::Char | ty::Str |
462 ty::Int(_) | ty::Uint(_) | ty::Float(_) => {
463 return self_ty.print(self);
470 self.generic_delimiters(|mut cx| {
471 define_scoped_cx!(cx);
474 if let Some(trait_ref) = trait_ref {
475 p!(write(" as "), print(trait_ref));
481 pub fn pretty_path_append_impl(
483 print_prefix: impl FnOnce(
484 PrintCx<'_, 'gcx, 'tcx, P>,
485 ) -> Result<P::Path, P::Error>,
487 trait_ref: Option<ty::TraitRef<'tcx>>,
488 ) -> Result<P::Path, P::Error> {
489 self = self.nest(print_prefix)?;
491 self.generic_delimiters(|mut cx| {
492 define_scoped_cx!(cx);
495 if let Some(trait_ref) = trait_ref {
496 p!(print(trait_ref), write(" for "));
504 pub fn pretty_path_generic_args(
506 print_prefix: impl FnOnce(
507 PrintCx<'_, 'gcx, 'tcx, P>,
508 ) -> Result<P::Path, P::Error>,
509 params: &[ty::GenericParamDef],
510 substs: SubstsRef<'tcx>,
511 projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
512 ) -> Result<P::Path, P::Error> {
513 self = self.nest(print_prefix)?;
515 // Don't print `'_` if there's no printed region.
516 let print_regions = params.iter().any(|param| {
517 match substs[param.index as usize].unpack() {
518 UnpackedKind::Lifetime(r) => {
519 self.always_print_region_in_paths(r) ||
520 self.print_region_outputs_anything(r)
526 // Don't print args that are the defaults of their respective parameters.
527 let num_supplied_defaults = if self.tcx.sess.verbose() {
530 params.iter().rev().take_while(|param| {
532 ty::GenericParamDefKind::Lifetime => false,
533 ty::GenericParamDefKind::Type { has_default, .. } => {
534 has_default && substs[param.index as usize] == Kind::from(
535 self.tcx.type_of(param.def_id).subst(self.tcx, substs)
538 ty::GenericParamDefKind::Const => false, // FIXME(const_generics:defaults)
543 let params = ¶ms[..params.len() - num_supplied_defaults];
544 let mut args = params.iter().map(|param| {
545 substs[param.index as usize]
548 UnpackedKind::Lifetime(_) => print_regions,
552 let arg0 = args.next();
554 let mut projections = projections;
555 let projection0 = projections.next();
557 if arg0.is_none() && projection0.is_none() {
558 return Ok(self.printer);
561 self.generic_delimiters(|mut cx| {
562 define_scoped_cx!(cx);
564 let mut empty = true;
565 let mut maybe_comma = |cx: &mut Self| {
570 write!(cx.printer, ", ")
574 for arg in arg0.into_iter().chain(args) {
575 maybe_comma(&mut cx)?;
577 if let UnpackedKind::Lifetime(region) = arg.unpack() {
578 if !cx.print_region_outputs_anything(region) {
579 // This happens when the value of the region
580 // parameter is not easily serialized. This may be
581 // because the user omitted it in the first place,
582 // or because it refers to some block in the code,
583 // etc. I'm not sure how best to serialize this.
593 for projection in projection0.into_iter().chain(projections) {
594 maybe_comma(&mut cx)?;
596 p!(write("{}=", cx.tcx.associated_item(projection.item_def_id).ident),
597 print(projection.ty));
605 impl<F: fmt::Write> fmt::Write for FmtPrinter<F> {
606 fn write_str(&mut self, s: &str) -> fmt::Result {
607 self.empty &= s.is_empty();
608 self.fmt.write_str(s)
612 impl<F: fmt::Write> Printer for FmtPrinter<F> {
613 type Error = fmt::Error;
620 mut self: PrintCx<'_, '_, 'tcx, Self>,
622 substs: Option<SubstsRef<'tcx>>,
623 projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
624 ) -> Result<Self::Path, Self::Error> {
625 // FIXME(eddyb) avoid querying `tcx.generics_of` and `tcx.def_key`
626 // both here and in `default_print_def_path`.
627 let generics = substs.map(|_| self.tcx.generics_of(def_id));
628 if generics.as_ref().and_then(|g| g.parent).is_none() {
629 let mut visible_path_success = false;
630 self = self.nest(|cx| {
631 let (printer, success) = cx.try_print_visible_def_path(def_id)?;
632 visible_path_success = success;
635 if visible_path_success {
636 return if let (Some(generics), Some(substs)) = (generics, substs) {
637 let has_own_self = generics.has_self && generics.parent_count == 0;
638 let params = &generics.params[has_own_self as usize..];
639 self.path_generic_args(|cx| Ok(cx.printer), params, substs, projections)
646 let key = self.tcx.def_key(def_id);
647 if let DefPathData::Impl = key.disambiguated_data.data {
648 // Always use types for non-local impls, where types are always
649 // available, and filename/line-number is mostly uninteresting.
651 !def_id.is_local() || {
652 // Otherwise, use filename/line-number if forced.
653 let force_no_types = FORCE_IMPL_FILENAME_LINE.with(|f| f.get());
658 // If no type info is available, fall back to
659 // pretty printing some span information. This should
660 // only occur very early in the compiler pipeline.
661 let parent_def_id = DefId { index: key.parent.unwrap(), ..def_id };
662 let span = self.tcx.def_span(def_id);
663 return self.path_append(
664 |cx| cx.print_def_path(parent_def_id, None, iter::empty()),
665 &format!("<impl at {:?}>", span),
670 self.default_print_def_path(def_id, substs, projections)
674 self: PrintCx<'_, '_, '_, Self>,
675 region: ty::Region<'_>,
676 ) -> Result<Self::Region, Self::Error> {
677 self.pretty_print_region(region)
681 self: PrintCx<'_, '_, 'tcx, Self>,
683 ) -> Result<Self::Type, Self::Error> {
684 self.pretty_print_type(ty)
688 mut self: PrintCx<'_, '_, '_, Self>,
690 ) -> Result<Self::Path, Self::Error> {
691 if cnum == LOCAL_CRATE {
692 if self.tcx.sess.rust_2018() {
693 // We add the `crate::` keyword on Rust 2018, only when desired.
694 if SHOULD_PREFIX_WITH_CRATE.with(|flag| flag.get()) {
695 write!(self.printer, "{}", keywords::Crate.name())?;
700 write!(self.printer, "{}", self.tcx.crate_name(cnum))?;
705 self: PrintCx<'_, '_, 'tcx, Self>,
707 trait_ref: Option<ty::TraitRef<'tcx>>,
708 ) -> Result<Self::Path, Self::Error> {
709 self.pretty_path_qualified(self_ty, trait_ref)
712 fn path_append_impl<'gcx, 'tcx>(
713 self: PrintCx<'_, 'gcx, 'tcx, Self>,
714 print_prefix: impl FnOnce(
715 PrintCx<'_, 'gcx, 'tcx, Self>,
716 ) -> Result<Self::Path, Self::Error>,
718 trait_ref: Option<ty::TraitRef<'tcx>>,
719 ) -> Result<Self::Path, Self::Error> {
720 self.pretty_path_append_impl(|cx| {
721 let mut printer = print_prefix(cx)?;
723 // HACK(eddyb) this accounts for `generic_delimiters`
724 // printing `::<` instead of `<` if `in_value` is set.
725 if !printer.empty && !printer.in_value {
726 write!(printer, "::")?;
730 }, self_ty, trait_ref)
732 fn path_append<'gcx, 'tcx>(
733 self: PrintCx<'_, 'gcx, 'tcx, Self>,
734 print_prefix: impl FnOnce(
735 PrintCx<'_, 'gcx, 'tcx, Self>,
736 ) -> Result<Self::Path, Self::Error>,
738 ) -> Result<Self::Path, Self::Error> {
739 let mut printer = print_prefix(self)?;
741 // FIXME(eddyb) `text` should never be empty, but it
742 // currently is for `extern { ... }` "foreign modules".
743 if !text.is_empty() {
745 write!(printer, "::")?;
747 write!(printer, "{}", text)?;
752 fn path_generic_args<'gcx, 'tcx>(
753 self: PrintCx<'_, 'gcx, 'tcx, Self>,
754 print_prefix: impl FnOnce(
755 PrintCx<'_, 'gcx, 'tcx, Self>,
756 ) -> Result<Self::Path, Self::Error>,
757 params: &[ty::GenericParamDef],
758 substs: SubstsRef<'tcx>,
759 projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
760 ) -> Result<Self::Path, Self::Error> {
761 self.pretty_path_generic_args(print_prefix, params, substs, projections)
765 impl<F: fmt::Write> PrettyPrinter for FmtPrinter<F> {
766 fn nest<'a, 'gcx, 'tcx, E>(
767 mut self: PrintCx<'a, 'gcx, 'tcx, Self>,
768 f: impl FnOnce(PrintCx<'_, 'gcx, 'tcx, Self>) -> Result<Self, E>,
769 ) -> Result<PrintCx<'a, 'gcx, 'tcx, Self>, E> {
770 let was_empty = std::mem::replace(&mut self.printer.empty, true);
771 let mut printer = f(PrintCx {
773 printer: self.printer,
776 printer.empty &= was_empty;
785 mut self: PrintCx<'_, '_, 'tcx, Self>,
787 substs: Option<SubstsRef<'tcx>>,
788 ) -> Result<Self::Path, Self::Error> {
789 let was_in_value = std::mem::replace(&mut self.printer.in_value, true);
790 let mut printer = self.print_def_path(def_id, substs, iter::empty())?;
791 printer.in_value = was_in_value;
797 self: PrintCx<'_, '_, 'tcx, Self>,
798 value: &ty::Binder<T>,
799 ) -> Result<Self, Self::Error>
800 where T: Print<'tcx, Self, Output = Self, Error = Self::Error> + TypeFoldable<'tcx>
802 self.pretty_in_binder(value)
805 fn generic_delimiters<'gcx, 'tcx>(
806 mut self: PrintCx<'_, 'gcx, 'tcx, Self>,
807 f: impl FnOnce(PrintCx<'_, 'gcx, 'tcx, Self>) -> Result<Self, Self::Error>,
808 ) -> Result<Self, Self::Error> {
809 if !self.printer.empty && self.printer.in_value {
810 write!(self.printer, "::<")?;
812 write!(self.printer, "<")?;
815 let was_in_value = std::mem::replace(&mut self.printer.in_value, false);
816 let mut printer = f(self)?;
817 printer.in_value = was_in_value;
819 write!(printer, ">")?;
823 fn always_print_region_in_paths(
824 self: &PrintCx<'_, '_, '_, Self>,
825 region: ty::Region<'_>,
827 *region != ty::ReErased
830 fn print_region_outputs_anything(
831 self: &PrintCx<'_, '_, '_, Self>,
832 region: ty::Region<'_>,
834 let highlight = self.printer.region_highlight_mode;
835 if highlight.region_highlighted(region).is_some() {
839 if self.tcx.sess.verbose() {
843 let identify_regions = self.tcx.sess.opts.debugging_opts.identify_regions;
846 ty::ReEarlyBound(ref data) => {
847 data.name != "" && data.name != "'_"
850 ty::ReLateBound(_, br) |
851 ty::ReFree(ty::FreeRegion { bound_region: br, .. }) |
852 ty::RePlaceholder(ty::Placeholder { name: br, .. }) => {
853 if let ty::BrNamed(_, name) = br {
854 if name != "" && name != "'_" {
859 if let Some((region, _)) = highlight.highlight_bound_region {
869 ty::ReVar(_) if identify_regions => true,
873 ty::ReErased => false,
877 ty::ReClosureBound(_) => true,
882 // HACK(eddyb) limited to `FmtPrinter` because of `region_highlight_mode`.
883 impl<F: fmt::Write> FmtPrinter<F> {
884 pub fn pretty_print_region(
885 mut self: PrintCx<'_, '_, '_, Self>,
886 region: ty::Region<'_>,
887 ) -> Result<Self, fmt::Error> {
888 define_scoped_cx!(self);
890 // Watch out for region highlights.
891 let highlight = self.printer.region_highlight_mode;
892 if let Some(n) = highlight.region_highlighted(region) {
894 return Ok(self.printer);
897 if self.tcx.sess.verbose() {
898 p!(write("{:?}", region));
899 return Ok(self.printer);
902 let identify_regions = self.tcx.sess.opts.debugging_opts.identify_regions;
904 // These printouts are concise. They do not contain all the information
905 // the user might want to diagnose an error, but there is basically no way
906 // to fit that into a short string. Hence the recommendation to use
907 // `explain_region()` or `note_and_explain_region()`.
909 ty::ReEarlyBound(ref data) => {
910 if data.name != "'_" {
911 p!(write("{}", data.name));
914 ty::ReLateBound(_, br) |
915 ty::ReFree(ty::FreeRegion { bound_region: br, .. }) |
916 ty::RePlaceholder(ty::Placeholder { name: br, .. }) => {
917 if let ty::BrNamed(_, name) = br {
918 if name != "" && name != "'_" {
919 p!(write("{}", name));
920 return Ok(self.printer);
924 if let Some((region, counter)) = highlight.highlight_bound_region {
926 p!(write("'{}", counter));
930 ty::ReScope(scope) if identify_regions => {
932 region::ScopeData::Node =>
933 p!(write("'{}s", scope.item_local_id().as_usize())),
934 region::ScopeData::CallSite =>
935 p!(write("'{}cs", scope.item_local_id().as_usize())),
936 region::ScopeData::Arguments =>
937 p!(write("'{}as", scope.item_local_id().as_usize())),
938 region::ScopeData::Destruction =>
939 p!(write("'{}ds", scope.item_local_id().as_usize())),
940 region::ScopeData::Remainder(first_statement_index) => p!(write(
942 scope.item_local_id().as_usize(),
943 first_statement_index.index()
947 ty::ReVar(region_vid) if identify_regions => {
948 p!(write("{:?}", region_vid));
953 ty::ReStatic => p!(write("'static")),
954 ty::ReEmpty => p!(write("'<empty>")),
956 // The user should never encounter these in unsubstituted form.
957 ty::ReClosureBound(vid) => p!(write("{:?}", vid)),
964 impl<'gcx, 'tcx, P: PrettyPrinter> PrintCx<'_, 'gcx, 'tcx, P> {
965 pub fn pretty_print_type(
968 ) -> Result<P::Type, P::Error> {
969 define_scoped_cx!(self);
972 ty::Bool => p!(write("bool")),
973 ty::Char => p!(write("char")),
974 ty::Int(t) => p!(write("{}", t.ty_to_string())),
975 ty::Uint(t) => p!(write("{}", t.ty_to_string())),
976 ty::Float(t) => p!(write("{}", t.ty_to_string())),
977 ty::RawPtr(ref tm) => {
978 p!(write("*{} ", match tm.mutbl {
979 hir::MutMutable => "mut",
980 hir::MutImmutable => "const",
984 ty::Ref(r, ty, mutbl) => {
986 if self.print_region_outputs_anything(r) {
987 p!(print(r), write(" "));
989 p!(print(ty::TypeAndMut { ty, mutbl }))
991 ty::Never => p!(write("!")),
992 ty::Tuple(ref tys) => {
994 let mut tys = tys.iter();
995 if let Some(&ty) = tys.next() {
996 p!(print(ty), write(","));
997 if let Some(&ty) = tys.next() {
998 p!(write(" "), print(ty));
1000 p!(write(", "), print(ty));
1006 ty::FnDef(def_id, substs) => {
1007 let sig = self.tcx.fn_sig(def_id).subst(self.tcx, substs);
1008 p!(print(sig), write(" {{"));
1009 nest!(|cx| cx.print_value_path(def_id, Some(substs)));
1012 ty::FnPtr(ref bare_fn) => {
1015 ty::Infer(infer_ty) => p!(write("{}", infer_ty)),
1016 ty::Error => p!(write("[type error]")),
1017 ty::Param(ref param_ty) => p!(write("{}", param_ty)),
1018 ty::Bound(debruijn, bound_ty) => {
1019 match bound_ty.kind {
1020 ty::BoundTyKind::Anon => {
1021 if debruijn == ty::INNERMOST {
1022 p!(write("^{}", bound_ty.var.index()))
1024 p!(write("^{}_{}", debruijn.index(), bound_ty.var.index()))
1028 ty::BoundTyKind::Param(p) => p!(write("{}", p)),
1031 ty::Adt(def, substs) => {
1032 nest!(|cx| cx.print_def_path(def.did, Some(substs), iter::empty()));
1034 ty::Dynamic(data, r) => {
1035 let print_r = self.print_region_outputs_anything(r);
1039 p!(write("dyn "), print(data));
1041 p!(write(" + "), print(r), write(")"));
1044 ty::Foreign(def_id) => {
1045 nest!(|cx| cx.print_def_path(def_id, None, iter::empty()));
1047 ty::Projection(ref data) => p!(print(data)),
1048 ty::UnnormalizedProjection(ref data) => {
1049 p!(write("Unnormalized("), print(data), write(")"))
1051 ty::Placeholder(placeholder) => {
1052 p!(write("Placeholder({:?})", placeholder))
1054 ty::Opaque(def_id, substs) => {
1055 // FIXME(eddyb) print this with `print_def_path`.
1056 if self.tcx.sess.verbose() {
1057 p!(write("Opaque({:?}, {:?})", def_id, substs));
1058 return Ok(self.printer);
1061 let def_key = self.tcx.def_key(def_id);
1062 if let Some(name) = def_key.disambiguated_data.data.get_opt_name() {
1063 p!(write("{}", name));
1064 let mut substs = substs.iter();
1065 // FIXME(eddyb) print this with `print_def_path`.
1066 if let Some(first) = substs.next() {
1069 for subst in substs {
1070 p!(write(", "), print(subst));
1074 return Ok(self.printer);
1076 // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
1077 // by looking up the projections associated with the def_id.
1078 let bounds = self.tcx.predicates_of(def_id).instantiate(self.tcx, substs);
1080 let mut first = true;
1081 let mut is_sized = false;
1083 for predicate in bounds.predicates {
1084 if let Some(trait_ref) = predicate.to_opt_poly_trait_ref() {
1085 // Don't print +Sized, but rather +?Sized if absent.
1086 if Some(trait_ref.def_id()) == self.tcx.lang_items().sized_trait() {
1092 write("{}", if first { " " } else { "+" }),
1098 p!(write("{}?Sized", if first { " " } else { "+" }));
1100 p!(write(" Sized"));
1103 ty::Str => p!(write("str")),
1104 ty::Generator(did, substs, movability) => {
1105 let upvar_tys = substs.upvar_tys(did, self.tcx);
1106 let witness = substs.witness(did, self.tcx);
1107 if movability == hir::GeneratorMovability::Movable {
1108 p!(write("[generator"));
1110 p!(write("[static generator"));
1113 // FIXME(eddyb) should use `def_span`.
1114 if let Some(hir_id) = self.tcx.hir().as_local_hir_id(did) {
1115 p!(write("@{:?}", self.tcx.hir().span_by_hir_id(hir_id)));
1117 for (freevar, upvar_ty) in self.tcx.freevars(did)
1119 .map_or(&[][..], |fv| &fv[..])
1126 self.tcx.hir().name(freevar.var_id())),
1131 // cross-crate closure types should only be
1132 // visible in codegen bug reports, I imagine.
1133 p!(write("@{:?}", did));
1135 for (index, upvar_ty) in upvar_tys.enumerate() {
1137 write("{}{}:", sep, index),
1143 p!(write(" "), print(witness), write("]"))
1145 ty::GeneratorWitness(types) => {
1146 nest!(|cx| cx.in_binder(&types))
1148 ty::Closure(did, substs) => {
1149 let upvar_tys = substs.upvar_tys(did, self.tcx);
1150 p!(write("[closure"));
1152 // FIXME(eddyb) should use `def_span`.
1153 if let Some(hir_id) = self.tcx.hir().as_local_hir_id(did) {
1154 if self.tcx.sess.opts.debugging_opts.span_free_formats {
1155 p!(write("@{:?}", hir_id));
1157 p!(write("@{:?}", self.tcx.hir().span_by_hir_id(hir_id)));
1160 for (freevar, upvar_ty) in self.tcx.freevars(did)
1162 .map_or(&[][..], |fv| &fv[..])
1169 self.tcx.hir().name(freevar.var_id())),
1174 // cross-crate closure types should only be
1175 // visible in codegen bug reports, I imagine.
1176 p!(write("@{:?}", did));
1178 for (index, upvar_ty) in upvar_tys.enumerate() {
1180 write("{}{}:", sep, index),
1186 if self.tcx.sess.verbose() {
1188 " closure_kind_ty={:?} closure_sig_ty={:?}",
1189 substs.closure_kind_ty(did, self.tcx),
1190 substs.closure_sig_ty(did, self.tcx)
1196 ty::Array(ty, sz) => {
1197 p!(write("["), print(ty), write("; "));
1199 ty::LazyConst::Unevaluated(_def_id, _substs) => {
1202 ty::LazyConst::Evaluated(c) => {
1204 ConstValue::Infer(..) => p!(write("_")),
1205 ConstValue::Param(ParamConst { name, .. }) =>
1206 p!(write("{}", name)),
1207 _ => p!(write("{}", c.unwrap_usize(self.tcx))),
1214 p!(write("["), print(ty), write("]"))
1221 pub fn pretty_fn_sig(
1223 inputs: &[Ty<'tcx>],
1226 ) -> Result<P, fmt::Error> {
1227 define_scoped_cx!(self);
1230 let mut inputs = inputs.iter();
1231 if let Some(&ty) = inputs.next() {
1234 p!(write(", "), print(ty));
1241 if !output.is_unit() {
1242 p!(write(" -> "), print(output));
1248 pub fn pretty_in_binder<T>(mut self, value: &ty::Binder<T>) -> Result<P, fmt::Error>
1249 where T: Print<'tcx, P, Output = P, Error = fmt::Error> + TypeFoldable<'tcx>
1251 fn name_by_region_index(index: usize) -> InternedString {
1253 0 => Symbol::intern("'r"),
1254 1 => Symbol::intern("'s"),
1255 i => Symbol::intern(&format!("'t{}", i-2)),
1259 // Replace any anonymous late-bound regions with named
1260 // variants, using gensym'd identifiers, so that we can
1261 // clearly differentiate between named and unnamed regions in
1262 // the output. We'll probably want to tweak this over time to
1263 // decide just how much information to give.
1264 if self.config.binder_depth == 0 {
1265 self.prepare_late_bound_region_info(value);
1268 let mut empty = true;
1269 let mut start_or_continue = |cx: &mut Self, start: &str, cont: &str| {
1270 write!(cx.printer, "{}", if empty {
1278 define_scoped_cx!(self);
1280 let old_region_index = self.config.region_index;
1281 let mut region_index = old_region_index;
1282 let new_value = self.tcx.replace_late_bound_regions(value, |br| {
1283 let _ = start_or_continue(&mut self, "for<", ", ");
1285 ty::BrNamed(_, name) => {
1286 let _ = write!(self.printer, "{}", name);
1293 let name = name_by_region_index(region_index);
1295 if !self.is_name_used(&name) {
1299 let _ = write!(self.printer, "{}", name);
1300 ty::BrNamed(DefId::local(CRATE_DEF_INDEX), name)
1303 self.tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br))
1305 start_or_continue(&mut self, "", "> ")?;
1307 // Push current state to gcx, and restore after writing new_value.
1308 self.config.binder_depth += 1;
1309 self.config.region_index = region_index;
1310 let result = new_value.print(PrintCx {
1312 printer: self.printer,
1313 config: self.config,
1315 self.config.region_index = old_region_index;
1316 self.config.binder_depth -= 1;
1320 fn prepare_late_bound_region_info<T>(&mut self, value: &ty::Binder<T>)
1321 where T: TypeFoldable<'tcx>
1324 struct LateBoundRegionNameCollector(FxHashSet<InternedString>);
1325 impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector {
1326 fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
1328 ty::ReLateBound(_, ty::BrNamed(_, name)) => {
1329 self.0.insert(name);
1333 r.super_visit_with(self)
1337 let mut collector = LateBoundRegionNameCollector(Default::default());
1338 value.visit_with(&mut collector);
1339 self.config.used_region_names = Some(collector.0);
1340 self.config.region_index = 0;
1343 fn is_name_used(&self, name: &InternedString) -> bool {
1344 match self.config.used_region_names {
1345 Some(ref names) => names.contains(name),
1351 impl<T, P: PrettyPrinter> Print<'tcx, P> for ty::Binder<T>
1352 where T: Print<'tcx, P, Output = P, Error = P::Error> + TypeFoldable<'tcx>
1355 type Error = P::Error;
1356 fn print(&self, cx: PrintCx<'_, '_, 'tcx, P>) -> Result<Self::Output, Self::Error> {