1 use crate::hir::def::Namespace;
2 use crate::hir::map::DefPathData;
3 use crate::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
4 use crate::middle::region;
5 use crate::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable};
6 use crate::ty::subst::{Kind, Subst, SubstsRef, UnpackedKind};
7 use crate::middle::cstore::{ExternCrate, ExternCrateSource};
8 use syntax::symbol::{keywords, Symbol};
10 use rustc_data_structures::fx::FxHashSet;
11 use syntax::symbol::InternedString;
14 use std::fmt::{self, Write as _};
19 static FORCE_IMPL_FILENAME_LINE: Cell<bool> = Cell::new(false);
20 static SHOULD_PREFIX_WITH_CRATE: Cell<bool> = Cell::new(false);
23 /// Force us to name impls with just the filename/line number. We
24 /// normally try to use types. But at some points, notably while printing
25 /// cycle errors, this can result in extra or suboptimal error output,
26 /// so this variable disables that check.
27 pub fn with_forced_impl_filename_line<F: FnOnce() -> R, R>(f: F) -> R {
28 FORCE_IMPL_FILENAME_LINE.with(|force| {
29 let old = force.get();
37 /// Adds the `crate::` prefix to paths where appropriate.
38 pub fn with_crate_prefix<F: FnOnce() -> R, R>(f: F) -> R {
39 SHOULD_PREFIX_WITH_CRATE.with(|flag| {
48 // FIXME(eddyb) this module uses `pub(crate)` for things used only
49 // from `ppaux` - when that is removed, they can be re-privatized.
51 /// The "region highlights" are used to control region printing during
52 /// specific error messages. When a "region highlight" is enabled, it
53 /// gives an alternate way to print specific regions. For now, we
54 /// always print those regions using a number, so something like "`'0`".
56 /// Regions not selected by the region highlight mode are presently
58 #[derive(Copy, Clone, Default)]
59 pub struct RegionHighlightMode {
60 /// If enabled, when we see the selected region, use "`'N`"
61 /// instead of the ordinary behavior.
62 highlight_regions: [Option<(ty::RegionKind, usize)>; 3],
64 /// If enabled, when printing a "free region" that originated from
65 /// the given `ty::BoundRegion`, print it as "`'1`". Free regions that would ordinarily
66 /// have names print as normal.
68 /// This is used when you have a signature like `fn foo(x: &u32,
69 /// y: &'a u32)` and we want to give a name to the region of the
71 highlight_bound_region: Option<(ty::BoundRegion, usize)>,
74 impl RegionHighlightMode {
75 /// If `region` and `number` are both `Some`, invokes
76 /// `highlighting_region`.
77 pub fn maybe_highlighting_region(
79 region: Option<ty::Region<'_>>,
80 number: Option<usize>,
82 if let Some(k) = region {
83 if let Some(n) = number {
84 self.highlighting_region(k, n);
89 /// Highlights the region inference variable `vid` as `'N`.
90 pub fn highlighting_region(
92 region: ty::Region<'_>,
95 let num_slots = self.highlight_regions.len();
96 let first_avail_slot = self.highlight_regions.iter_mut()
97 .filter(|s| s.is_none())
101 "can only highlight {} placeholders at a time",
105 *first_avail_slot = Some((*region, number));
108 /// Convenience wrapper for `highlighting_region`.
109 pub fn highlighting_region_vid(
114 self.highlighting_region(&ty::ReVar(vid), number)
117 /// Returns `Some(n)` with the number to use for the given region, if any.
118 fn region_highlighted(&self, region: ty::Region<'_>) -> Option<usize> {
122 .filter_map(|h| match h {
123 Some((r, n)) if r == region => Some(*n),
129 /// Highlight the given bound region.
130 /// We can only highlight one bound region at a time. See
131 /// the field `highlight_bound_region` for more detailed notes.
132 pub fn highlighting_bound_region(
137 assert!(self.highlight_bound_region.is_none());
138 self.highlight_bound_region = Some((br, number));
142 struct LateBoundRegionNameCollector(FxHashSet<InternedString>);
143 impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector {
144 fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
146 ty::ReLateBound(_, ty::BrNamed(_, name)) => {
151 r.super_visit_with(self)
155 pub(crate) struct PrintConfig {
156 pub(crate) is_debug: bool,
157 pub(crate) is_verbose: bool,
158 pub(crate) identify_regions: bool,
159 pub(crate) used_region_names: Option<FxHashSet<InternedString>>,
160 pub(crate) region_index: usize,
161 pub(crate) binder_depth: usize,
165 pub(crate) fn new(tcx: TyCtxt<'_, '_, '_>) -> Self {
168 is_verbose: tcx.sess.verbose(),
169 identify_regions: tcx.sess.opts.debugging_opts.identify_regions,
170 used_region_names: None,
177 pub struct PrintCx<'a, 'gcx, 'tcx, P> {
178 pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
180 pub(crate) config: &'a mut PrintConfig,
183 // HACK(eddyb) this is solely for `self: PrintCx<Self>`, e.g. to
184 // implement traits on the printer and call the methods on the context.
185 impl<P> Deref for PrintCx<'_, '_, '_, P> {
187 fn deref(&self) -> &P {
192 impl<'a, 'gcx, 'tcx, P> PrintCx<'a, 'gcx, 'tcx, P> {
194 tcx: TyCtxt<'a, 'gcx, 'tcx>,
196 f: impl FnOnce(PrintCx<'_, 'gcx, 'tcx, P>) -> R,
201 config: &mut PrintConfig::new(tcx),
205 pub(crate) fn with_tls_tcx<R>(printer: P, f: impl FnOnce(PrintCx<'_, '_, '_, P>) -> R) -> R {
206 ty::tls::with(|tcx| PrintCx::with(tcx, printer, f))
208 pub(crate) fn prepare_late_bound_region_info<T>(&mut self, value: &ty::Binder<T>)
209 where T: TypeFoldable<'tcx>
211 let mut collector = LateBoundRegionNameCollector(Default::default());
212 value.visit_with(&mut collector);
213 self.config.used_region_names = Some(collector.0);
214 self.config.region_index = 0;
218 pub trait Print<'tcx, P> {
222 fn print(&self, cx: PrintCx<'_, '_, 'tcx, P>) -> Result<Self::Output, Self::Error>;
225 cx: PrintCx<'_, '_, 'tcx, P>,
226 ) -> Result<Self::Output, Self::Error> {
227 let old_debug = cx.config.is_debug;
228 cx.config.is_debug = false;
229 let result = self.print(PrintCx {
234 cx.config.is_debug = old_debug;
237 fn print_debug(&self, cx: PrintCx<'_, '_, 'tcx, P>) -> Result<Self::Output, Self::Error> {
238 let old_debug = cx.config.is_debug;
239 cx.config.is_debug = true;
240 let result = self.print(PrintCx {
245 cx.config.is_debug = old_debug;
250 pub trait Printer: Sized {
258 self: PrintCx<'_, '_, 'tcx, Self>,
260 substs: Option<SubstsRef<'tcx>>,
261 projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
262 ) -> Result<Self::Path, Self::Error> {
263 self.default_print_def_path(def_id, substs, projections)
266 self: PrintCx<'_, '_, 'tcx, Self>,
268 substs: Option<SubstsRef<'tcx>>,
270 trait_ref: Option<ty::TraitRef<'tcx>>,
271 ) -> Result<Self::Path, Self::Error> {
272 self.default_print_impl_path(impl_def_id, substs, self_ty, trait_ref)
276 self: PrintCx<'_, '_, '_, Self>,
277 region: ty::Region<'_>,
278 ) -> Result<Self::Region, Self::Error>;
281 self: PrintCx<'_, '_, 'tcx, Self>,
283 ) -> Result<Self::Type, Self::Error>;
286 self: PrintCx<'_, '_, '_, Self>,
288 ) -> Result<Self::Path, Self::Error>;
290 self: PrintCx<'_, '_, 'tcx, Self>,
292 trait_ref: Option<ty::TraitRef<'tcx>>,
293 ) -> Result<Self::Path, Self::Error>;
295 fn path_append_impl<'gcx, 'tcx>(
296 self: PrintCx<'_, 'gcx, 'tcx, Self>,
297 print_prefix: impl FnOnce(
298 PrintCx<'_, 'gcx, 'tcx, Self>,
299 ) -> Result<Self::Path, Self::Error>,
301 trait_ref: Option<ty::TraitRef<'tcx>>,
302 ) -> Result<Self::Path, Self::Error>;
303 fn path_append<'gcx, 'tcx>(
304 self: PrintCx<'_, 'gcx, 'tcx, Self>,
305 print_prefix: impl FnOnce(
306 PrintCx<'_, 'gcx, 'tcx, Self>,
307 ) -> Result<Self::Path, Self::Error>,
309 ) -> Result<Self::Path, Self::Error>;
310 fn path_generic_args<'gcx, 'tcx>(
311 self: PrintCx<'_, 'gcx, 'tcx, Self>,
312 print_prefix: impl FnOnce(
313 PrintCx<'_, 'gcx, 'tcx, Self>,
314 ) -> Result<Self::Path, Self::Error>,
315 params: &[ty::GenericParamDef],
316 substs: SubstsRef<'tcx>,
317 projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
318 ) -> Result<Self::Path, Self::Error>;
321 /// Trait for printers that pretty-print using `fmt::Write` to the printer.
322 pub trait PrettyPrinter:
331 /// Enter a nested print context, for pretty-printing
332 /// nested components in some larger context.
333 fn nest<'a, 'gcx, 'tcx, E>(
334 self: PrintCx<'a, 'gcx, 'tcx, Self>,
335 f: impl FnOnce(PrintCx<'_, 'gcx, 'tcx, Self>) -> Result<Self, E>,
336 ) -> Result<PrintCx<'a, 'gcx, 'tcx, Self>, E> {
337 let printer = f(PrintCx {
339 printer: self.printer,
349 /// Like `print_def_path` but for value paths.
351 self: PrintCx<'_, '_, 'tcx, Self>,
353 substs: Option<SubstsRef<'tcx>>,
354 ) -> Result<Self::Path, Self::Error> {
355 self.print_def_path(def_id, substs, iter::empty())
358 /// Print `<...>` around what `f` prints.
359 fn generic_delimiters<'gcx, 'tcx>(
360 self: PrintCx<'_, 'gcx, 'tcx, Self>,
361 f: impl FnOnce(PrintCx<'_, 'gcx, 'tcx, Self>) -> Result<Self, Self::Error>,
362 ) -> Result<Self, Self::Error>;
364 /// Return `true` if the region should be printed in path generic args
365 /// even when it's `'_`, such as in e.g. `Foo<'_, '_, '_>`.
366 fn always_print_region_in_paths(
367 self: &PrintCx<'_, '_, '_, Self>,
368 _region: ty::Region<'_>,
373 // HACK(eddyb) Trying to print a lifetime might not print anything, which
374 // may need special handling in the caller (of `ty::RegionKind::print`).
375 // To avoid printing to a temporary string (which isn't even supported),
376 // the `print_region_outputs_anything` method can instead be used to
377 // determine this, ahead of time.
379 // NB: this must be kept in sync with the implementation of `print_region`.
380 fn print_region_outputs_anything(
381 self: &PrintCx<'_, '_, '_, Self>,
382 region: ty::Region<'_>,
387 ($cx:ident, $closure:expr) => {
388 $cx = $cx.nest($closure)?
392 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
393 // HACK(eddyb) get rid of `def_path_str` and/or pass `Namespace` explicitly always
394 // (but also some things just print a `DefId` generally so maybe we need this?)
395 fn guess_def_namespace(self, def_id: DefId) -> Namespace {
396 match self.def_key(def_id).disambiguated_data.data {
397 DefPathData::ValueNs(..) |
398 DefPathData::EnumVariant(..) |
399 DefPathData::Field(..) |
400 DefPathData::AnonConst |
401 DefPathData::ConstParam(..) |
402 DefPathData::ClosureExpr |
403 DefPathData::StructCtor => Namespace::ValueNS,
405 DefPathData::MacroDef(..) => Namespace::MacroNS,
407 _ => Namespace::TypeNS,
411 /// Returns a string identifying this `DefId`. This string is
412 /// suitable for user output.
413 pub fn def_path_str(self, def_id: DefId) -> String {
414 let ns = self.guess_def_namespace(def_id);
415 debug!("def_path_str: def_id={:?}, ns={:?}", def_id, ns);
416 let mut s = String::new();
417 let _ = PrintCx::with(self, FmtPrinter::new(&mut s, ns), |cx| {
418 cx.print_def_path(def_id, None, iter::empty())
424 impl<P: Printer> PrintCx<'a, 'gcx, 'tcx, P> {
425 pub fn default_print_def_path(
428 substs: Option<SubstsRef<'tcx>>,
429 projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
430 ) -> Result<P::Path, P::Error> {
431 debug!("default_print_def_path: def_id={:?}, substs={:?}", def_id, substs);
432 let key = self.tcx.def_key(def_id);
433 debug!("default_print_def_path: key={:?}", key);
435 match key.disambiguated_data.data {
436 DefPathData::CrateRoot => {
437 assert!(key.parent.is_none());
438 self.path_crate(def_id.krate)
441 DefPathData::Impl => {
442 let mut self_ty = self.tcx.type_of(def_id);
443 if let Some(substs) = substs {
444 self_ty = self_ty.subst(self.tcx, substs);
447 let mut impl_trait_ref = self.tcx.impl_trait_ref(def_id);
448 if let Some(substs) = substs {
449 impl_trait_ref = impl_trait_ref.subst(self.tcx, substs);
451 self.print_impl_path(def_id, substs, self_ty, impl_trait_ref)
455 let generics = substs.map(|_| self.tcx.generics_of(def_id));
456 let generics_parent = generics.as_ref().and_then(|g| g.parent);
457 let parent_def_id = DefId { index: key.parent.unwrap(), ..def_id };
458 let print_parent_path = |cx: PrintCx<'_, 'gcx, 'tcx, P>| {
459 if let Some(generics_parent_def_id) = generics_parent {
460 assert_eq!(parent_def_id, generics_parent_def_id);
462 // FIXME(eddyb) try to move this into the parent's printing
463 // logic, instead of doing it when printing the child.
464 let parent_generics = cx.tcx.generics_of(parent_def_id);
465 let parent_has_own_self =
466 parent_generics.has_self && parent_generics.parent_count == 0;
467 if let (Some(substs), true) = (substs, parent_has_own_self) {
468 let trait_ref = ty::TraitRef::new(parent_def_id, substs);
469 cx.path_qualified(trait_ref.self_ty(), Some(trait_ref))
471 cx.print_def_path(parent_def_id, substs, iter::empty())
474 cx.print_def_path(parent_def_id, None, iter::empty())
477 let print_path = |cx: PrintCx<'_, 'gcx, 'tcx, P>| {
478 match key.disambiguated_data.data {
479 // Skip `::{{constructor}}` on tuple/unit structs.
480 DefPathData::StructCtor => print_parent_path(cx),
485 &key.disambiguated_data.data.as_interned_str().as_str(),
491 if let (Some(generics), Some(substs)) = (generics, substs) {
492 let has_own_self = generics.has_self && generics.parent_count == 0;
493 let params = &generics.params[has_own_self as usize..];
494 self.path_generic_args(print_path, params, substs, projections)
502 fn default_print_impl_path(
505 _substs: Option<SubstsRef<'tcx>>,
507 impl_trait_ref: Option<ty::TraitRef<'tcx>>,
508 ) -> Result<P::Path, P::Error> {
509 debug!("default_print_impl_path: impl_def_id={:?}, self_ty={}, impl_trait_ref={:?}",
510 impl_def_id, self_ty, impl_trait_ref);
512 // Decide whether to print the parent path for the impl.
513 // Logically, since impls are global, it's never needed, but
514 // users may find it useful. Currently, we omit the parent if
515 // the impl is either in the same module as the self-type or
517 let parent_def_id = self.tcx.parent(impl_def_id).unwrap();
518 let in_self_mod = match characteristic_def_id_of_type(self_ty) {
520 Some(ty_def_id) => self.tcx.parent(ty_def_id) == Some(parent_def_id),
522 let in_trait_mod = match impl_trait_ref {
524 Some(trait_ref) => self.tcx.parent(trait_ref.def_id) == Some(parent_def_id),
527 if !in_self_mod && !in_trait_mod {
528 // If the impl is not co-located with either self-type or
529 // trait-type, then fallback to a format that identifies
530 // the module more clearly.
531 self.path_append_impl(
532 |cx| cx.print_def_path(parent_def_id, None, iter::empty()),
537 // Otherwise, try to give a good form that would be valid language
538 // syntax. Preferably using associated item notation.
539 self.path_qualified(self_ty, impl_trait_ref)
544 /// As a heuristic, when we see an impl, if we see that the
545 /// 'self type' is a type defined in the same module as the impl,
546 /// we can omit including the path to the impl itself. This
547 /// function tries to find a "characteristic `DefId`" for a
548 /// type. It's just a heuristic so it makes some questionable
549 /// decisions and we may want to adjust it later.
550 pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> {
552 ty::Adt(adt_def, _) => Some(adt_def.did),
554 ty::Dynamic(data, ..) => data.principal_def_id(),
556 ty::Array(subty, _) |
557 ty::Slice(subty) => characteristic_def_id_of_type(subty),
559 ty::RawPtr(mt) => characteristic_def_id_of_type(mt.ty),
561 ty::Ref(_, ty, _) => characteristic_def_id_of_type(ty),
563 ty::Tuple(ref tys) => tys.iter()
564 .filter_map(|ty| characteristic_def_id_of_type(ty))
567 ty::FnDef(def_id, _) |
568 ty::Closure(def_id, _) |
569 ty::Generator(def_id, _, _) |
570 ty::Foreign(def_id) => Some(def_id),
579 ty::Placeholder(..) |
580 ty::UnnormalizedProjection(..) |
586 ty::GeneratorWitness(..) |
588 ty::Float(_) => None,
592 pub struct FmtPrinter<F: fmt::Write> {
596 pub region_highlight_mode: RegionHighlightMode,
599 impl<F: fmt::Write> FmtPrinter<F> {
600 pub fn new(fmt: F, ns: Namespace) -> Self {
604 in_value: ns == Namespace::ValueNS,
605 region_highlight_mode: RegionHighlightMode::default(),
610 impl<'gcx, 'tcx, P: PrettyPrinter> PrintCx<'_, 'gcx, 'tcx, P> {
611 /// If possible, this returns a global path resolving to `def_id` that is visible
612 /// from at least one local module and returns true. If the crate defining `def_id` is
613 /// declared with an `extern crate`, the path is guaranteed to use the `extern crate`.
614 fn try_print_visible_def_path(
617 ) -> Result<(P, bool), P::Error> {
618 debug!("try_print_visible_def_path: def_id={:?}", def_id);
620 // If `def_id` is a direct or injected extern crate, return the
621 // path to the crate followed by the path to the item within the crate.
622 if def_id.index == CRATE_DEF_INDEX {
623 let cnum = def_id.krate;
625 if cnum == LOCAL_CRATE {
626 return Ok((self.path_crate(cnum)?, true));
629 // In local mode, when we encounter a crate other than
630 // LOCAL_CRATE, execution proceeds in one of two ways:
632 // 1. for a direct dependency, where user added an
633 // `extern crate` manually, we put the `extern
634 // crate` as the parent. So you wind up with
635 // something relative to the current crate.
636 // 2. for an extern inferred from a path or an indirect crate,
637 // where there is no explicit `extern crate`, we just prepend
639 match *self.tcx.extern_crate(def_id) {
641 src: ExternCrateSource::Extern(def_id),
646 debug!("try_print_visible_def_path: def_id={:?}", def_id);
647 return Ok((if !span.is_dummy() {
648 self.print_def_path(def_id, None, iter::empty())?
650 self.path_crate(cnum)?
654 return Ok((self.path_crate(cnum)?, true));
660 if def_id.is_local() {
661 return Ok((self.printer, false));
664 let visible_parent_map = self.tcx.visible_parent_map(LOCAL_CRATE);
666 let mut cur_def_key = self.tcx.def_key(def_id);
667 debug!("try_print_visible_def_path: cur_def_key={:?}", cur_def_key);
669 // For a UnitStruct or TupleStruct we want the name of its parent rather than <unnamed>.
670 if let DefPathData::StructCtor = cur_def_key.disambiguated_data.data {
673 index: cur_def_key.parent.expect("DefPathData::StructCtor missing a parent"),
676 cur_def_key = self.tcx.def_key(parent);
679 let visible_parent = match visible_parent_map.get(&def_id).cloned() {
680 Some(parent) => parent,
681 None => return Ok((self.printer, false)),
683 // HACK(eddyb) this uses `nest` to avoid knowing ahead of time whether
684 // the entire path will succeed or not. To support printers that do not
685 // implement `PrettyPrinter`, a `Vec` or linked list on the stack would
686 // need to be built, before starting to print anything.
687 let mut prefix_success = false;
689 let (printer, success) = cx.try_print_visible_def_path(visible_parent)?;
690 prefix_success = success;
694 return Ok((self.printer, false));
696 let actual_parent = self.tcx.parent(def_id);
698 let data = cur_def_key.disambiguated_data.data;
700 "try_print_visible_def_path: data={:?} visible_parent={:?} actual_parent={:?}",
701 data, visible_parent, actual_parent,
704 let symbol = match data {
705 // In order to output a path that could actually be imported (valid and visible),
706 // we need to handle re-exports correctly.
708 // For example, take `std::os::unix::process::CommandExt`, this trait is actually
709 // defined at `std::sys::unix::ext::process::CommandExt` (at time of writing).
711 // `std::os::unix` rexports the contents of `std::sys::unix::ext`. `std::sys` is
712 // private so the "true" path to `CommandExt` isn't accessible.
714 // In this case, the `visible_parent_map` will look something like this:
716 // (child) -> (parent)
717 // `std::sys::unix::ext::process::CommandExt` -> `std::sys::unix::ext::process`
718 // `std::sys::unix::ext::process` -> `std::sys::unix::ext`
719 // `std::sys::unix::ext` -> `std::os`
721 // This is correct, as the visible parent of `std::sys::unix::ext` is in fact
724 // When printing the path to `CommandExt` and looking at the `cur_def_key` that
725 // corresponds to `std::sys::unix::ext`, we would normally print `ext` and then go
726 // to the parent - resulting in a mangled path like
727 // `std::os::ext::process::CommandExt`.
729 // Instead, we must detect that there was a re-export and instead print `unix`
730 // (which is the name `std::sys::unix::ext` was re-exported as in `std::os`). To
731 // do this, we compare the parent of `std::sys::unix::ext` (`std::sys::unix`) with
732 // the visible parent (`std::os`). If these do not match, then we iterate over
733 // the children of the visible parent (as was done when computing
734 // `visible_parent_map`), looking for the specific child we currently have and then
735 // have access to the re-exported name.
736 DefPathData::Module(actual_name) |
737 DefPathData::TypeNs(actual_name) if Some(visible_parent) != actual_parent => {
738 self.tcx.item_children(visible_parent)
740 .find(|child| child.def.def_id() == def_id)
741 .map(|child| child.ident.as_str())
742 .unwrap_or_else(|| actual_name.as_str())
745 data.get_opt_name().map(|n| n.as_str()).unwrap_or_else(|| {
746 // Re-exported `extern crate` (#43189).
747 if let DefPathData::CrateRoot = data {
748 self.tcx.original_crate_name(def_id.krate).as_str()
750 Symbol::intern("<unnamed>").as_str()
755 debug!("try_print_visible_def_path: symbol={:?}", symbol);
756 Ok((self.path_append(|cx| Ok(cx.printer), &symbol)?, true))
759 pub fn pretty_path_qualified(
762 trait_ref: Option<ty::TraitRef<'tcx>>,
763 ) -> Result<P::Path, P::Error> {
764 if trait_ref.is_none() {
765 // Inherent impls. Try to print `Foo::bar` for an inherent
766 // impl on `Foo`, but fallback to `<Foo>::bar` if self-type is
767 // anything other than a simple path.
769 ty::Adt(..) | ty::Foreign(_) |
770 ty::Bool | ty::Char | ty::Str |
771 ty::Int(_) | ty::Uint(_) | ty::Float(_) => {
772 return self_ty.print_display(self);
779 self.generic_delimiters(|mut cx| {
780 nest!(cx, |cx| self_ty.print_display(cx));
781 if let Some(trait_ref) = trait_ref {
782 write!(cx.printer, " as ")?;
783 nest!(cx, |cx| trait_ref.print_display(cx));
789 pub fn pretty_path_append_impl(
791 print_prefix: impl FnOnce(
792 PrintCx<'_, 'gcx, 'tcx, P>,
793 ) -> Result<P::Path, P::Error>,
795 trait_ref: Option<ty::TraitRef<'tcx>>,
796 ) -> Result<P::Path, P::Error> {
797 nest!(self, print_prefix);
799 self.generic_delimiters(|mut cx| {
800 write!(cx.printer, "impl ")?;
801 if let Some(trait_ref) = trait_ref {
802 nest!(cx, |cx| trait_ref.print_display(cx));
803 write!(cx.printer, " for ")?;
805 nest!(cx, |cx| self_ty.print_display(cx));
811 pub fn pretty_path_generic_args(
813 print_prefix: impl FnOnce(
814 PrintCx<'_, 'gcx, 'tcx, P>,
815 ) -> Result<P::Path, P::Error>,
816 params: &[ty::GenericParamDef],
817 substs: SubstsRef<'tcx>,
818 projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
819 ) -> Result<P::Path, P::Error> {
820 nest!(self, |cx| print_prefix(cx));
822 // Don't print `'_` if there's no printed region.
823 let print_regions = params.iter().any(|param| {
824 match substs[param.index as usize].unpack() {
825 UnpackedKind::Lifetime(r) => {
826 self.always_print_region_in_paths(r) ||
827 self.print_region_outputs_anything(r)
833 // Don't print args that are the defaults of their respective parameters.
834 let num_supplied_defaults = if self.config.is_verbose {
837 params.iter().rev().take_while(|param| {
839 ty::GenericParamDefKind::Lifetime => false,
840 ty::GenericParamDefKind::Type { has_default, .. } => {
841 has_default && substs[param.index as usize] == Kind::from(
842 self.tcx.type_of(param.def_id).subst(self.tcx, substs)
845 ty::GenericParamDefKind::Const => false, // FIXME(const_generics:defaults)
850 let params = ¶ms[..params.len() - num_supplied_defaults];
851 let mut args = params.iter().map(|param| {
852 substs[param.index as usize].unpack()
855 UnpackedKind::Lifetime(_) => print_regions,
859 let arg0 = args.next();
861 let mut projections = projections;
862 let projection0 = projections.next();
864 if arg0.is_none() && projection0.is_none() {
865 return Ok(self.printer);
868 self.generic_delimiters(|mut cx| {
869 let mut empty = true;
870 let mut maybe_comma = |cx: &mut Self| {
875 write!(cx.printer, ", ")
879 for arg in arg0.into_iter().chain(args) {
880 maybe_comma(&mut cx)?;
883 UnpackedKind::Lifetime(region) => {
884 if !cx.print_region_outputs_anything(region) {
885 // This happens when the value of the region
886 // parameter is not easily serialized. This may be
887 // because the user omitted it in the first place,
888 // or because it refers to some block in the code,
889 // etc. I'm not sure how best to serialize this.
890 write!(cx.printer, "'_")?;
892 nest!(cx, |cx| region.print_display(cx));
895 UnpackedKind::Type(ty) => {
896 nest!(cx, |cx| ty.print_display(cx));
898 UnpackedKind::Const(ct) => {
899 nest!(cx, |cx| ct.print_display(cx));
904 for projection in projection0.into_iter().chain(projections) {
905 maybe_comma(&mut cx)?;
907 write!(cx.printer, "{}=",
908 cx.tcx.associated_item(projection.item_def_id).ident)?;
909 nest!(cx, |cx| projection.ty.print_display(cx));
917 impl<F: fmt::Write> fmt::Write for FmtPrinter<F> {
918 fn write_str(&mut self, s: &str) -> fmt::Result {
919 self.empty &= s.is_empty();
920 self.fmt.write_str(s)
924 impl<F: fmt::Write> Printer for FmtPrinter<F> {
925 type Error = fmt::Error;
932 mut self: PrintCx<'_, '_, 'tcx, Self>,
934 substs: Option<SubstsRef<'tcx>>,
935 projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
936 ) -> Result<Self::Path, Self::Error> {
937 // FIXME(eddyb) avoid querying `tcx.generics_of` and `tcx.def_key`
938 // both here and in `default_print_def_path`.
939 let generics = substs.map(|_| self.tcx.generics_of(def_id));
940 if generics.as_ref().and_then(|g| g.parent).is_none() {
941 let mut visible_path_success = false;
943 let (printer, success) = cx.try_print_visible_def_path(def_id)?;
944 visible_path_success = success;
947 if visible_path_success {
948 return if let (Some(generics), Some(substs)) = (generics, substs) {
949 let has_own_self = generics.has_self && generics.parent_count == 0;
950 let params = &generics.params[has_own_self as usize..];
951 self.path_generic_args(|cx| Ok(cx.printer), params, substs, projections)
958 let key = self.tcx.def_key(def_id);
959 if let DefPathData::Impl = key.disambiguated_data.data {
960 // Always use types for non-local impls, where types are always
961 // available, and filename/line-number is mostly uninteresting.
963 !def_id.is_local() || {
964 // Otherwise, use filename/line-number if forced.
965 let force_no_types = FORCE_IMPL_FILENAME_LINE.with(|f| f.get());
970 // If no type info is available, fall back to
971 // pretty printing some span information. This should
972 // only occur very early in the compiler pipeline.
973 let parent_def_id = DefId { index: key.parent.unwrap(), ..def_id };
974 let span = self.tcx.def_span(def_id);
975 return self.path_append(
976 |cx| cx.print_def_path(parent_def_id, None, iter::empty()),
977 &format!("<impl at {:?}>", span),
982 self.default_print_def_path(def_id, substs, projections)
986 mut self: PrintCx<'_, '_, '_, Self>,
987 region: ty::Region<'_>,
988 ) -> Result<Self::Region, Self::Error> {
989 // Watch out for region highlights.
990 let highlight = self.printer.region_highlight_mode;
991 if let Some(n) = highlight.region_highlighted(region) {
992 write!(self.printer, "'{}", n)?;
993 return Ok(self.printer);
996 if self.config.is_verbose {
997 return region.print_debug(self);
1000 // These printouts are concise. They do not contain all the information
1001 // the user might want to diagnose an error, but there is basically no way
1002 // to fit that into a short string. Hence the recommendation to use
1003 // `explain_region()` or `note_and_explain_region()`.
1005 ty::ReEarlyBound(ref data) => {
1006 if data.name != "'_" {
1007 write!(self.printer, "{}", data.name)?;
1010 ty::ReLateBound(_, br) |
1011 ty::ReFree(ty::FreeRegion { bound_region: br, .. }) |
1012 ty::RePlaceholder(ty::Placeholder { name: br, .. }) => {
1013 if let ty::BrNamed(_, name) = br {
1014 if name != "" && name != "'_" {
1015 write!(self.printer, "{}", name)?;
1016 return Ok(self.printer);
1020 if let Some((region, counter)) = highlight.highlight_bound_region {
1022 write!(self.printer, "'{}", counter)?;
1026 ty::ReScope(scope) if self.config.identify_regions => {
1028 region::ScopeData::Node =>
1029 write!(self.printer, "'{}s", scope.item_local_id().as_usize())?,
1030 region::ScopeData::CallSite =>
1031 write!(self.printer, "'{}cs", scope.item_local_id().as_usize())?,
1032 region::ScopeData::Arguments =>
1033 write!(self.printer, "'{}as", scope.item_local_id().as_usize())?,
1034 region::ScopeData::Destruction =>
1035 write!(self.printer, "'{}ds", scope.item_local_id().as_usize())?,
1036 region::ScopeData::Remainder(first_statement_index) => write!(self.printer,
1038 scope.item_local_id().as_usize(),
1039 first_statement_index.index()
1043 ty::ReVar(region_vid) if self.config.identify_regions => {
1044 write!(self.printer, "{:?}", region_vid)?;
1049 ty::ReStatic => write!(self.printer, "'static")?,
1050 ty::ReEmpty => write!(self.printer, "'<empty>")?,
1052 // The user should never encounter these in unsubstituted form.
1053 ty::ReClosureBound(vid) => write!(self.printer, "{:?}", vid)?,
1060 self: PrintCx<'_, '_, 'tcx, Self>,
1062 ) -> Result<Self::Type, Self::Error> {
1063 self.pretty_print_type(ty)
1067 mut self: PrintCx<'_, '_, '_, Self>,
1069 ) -> Result<Self::Path, Self::Error> {
1070 if cnum == LOCAL_CRATE {
1071 if self.tcx.sess.rust_2018() {
1072 // We add the `crate::` keyword on Rust 2018, only when desired.
1073 if SHOULD_PREFIX_WITH_CRATE.with(|flag| flag.get()) {
1074 write!(self.printer, "{}", keywords::Crate.name())?;
1079 write!(self.printer, "{}", self.tcx.crate_name(cnum))?;
1084 self: PrintCx<'_, '_, 'tcx, Self>,
1086 trait_ref: Option<ty::TraitRef<'tcx>>,
1087 ) -> Result<Self::Path, Self::Error> {
1088 self.pretty_path_qualified(self_ty, trait_ref)
1091 fn path_append_impl<'gcx, 'tcx>(
1092 self: PrintCx<'_, 'gcx, 'tcx, Self>,
1093 print_prefix: impl FnOnce(
1094 PrintCx<'_, 'gcx, 'tcx, Self>,
1095 ) -> Result<Self::Path, Self::Error>,
1097 trait_ref: Option<ty::TraitRef<'tcx>>,
1098 ) -> Result<Self::Path, Self::Error> {
1099 self.pretty_path_append_impl(|cx| {
1100 let mut printer = print_prefix(cx)?;
1102 // HACK(eddyb) this accounts for `generic_delimiters`
1103 // printing `::<` instead of `<` if `in_value` is set.
1104 if !printer.empty && !printer.in_value {
1105 write!(printer, "::")?;
1109 }, self_ty, trait_ref)
1111 fn path_append<'gcx, 'tcx>(
1112 self: PrintCx<'_, 'gcx, 'tcx, Self>,
1113 print_prefix: impl FnOnce(
1114 PrintCx<'_, 'gcx, 'tcx, Self>,
1115 ) -> Result<Self::Path, Self::Error>,
1117 ) -> Result<Self::Path, Self::Error> {
1118 let mut printer = print_prefix(self)?;
1120 // FIXME(eddyb) `text` should never be empty, but it
1121 // currently is for `extern { ... }` "foreign modules".
1122 if !text.is_empty() {
1124 write!(printer, "::")?;
1126 write!(printer, "{}", text)?;
1131 fn path_generic_args<'gcx, 'tcx>(
1132 self: PrintCx<'_, 'gcx, 'tcx, Self>,
1133 print_prefix: impl FnOnce(
1134 PrintCx<'_, 'gcx, 'tcx, Self>,
1135 ) -> Result<Self::Path, Self::Error>,
1136 params: &[ty::GenericParamDef],
1137 substs: SubstsRef<'tcx>,
1138 projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
1139 ) -> Result<Self::Path, Self::Error> {
1140 self.pretty_path_generic_args(print_prefix, params, substs, projections)
1144 impl<F: fmt::Write> PrettyPrinter for FmtPrinter<F> {
1145 fn nest<'a, 'gcx, 'tcx, E>(
1146 mut self: PrintCx<'a, 'gcx, 'tcx, Self>,
1147 f: impl FnOnce(PrintCx<'_, 'gcx, 'tcx, Self>) -> Result<Self, E>,
1148 ) -> Result<PrintCx<'a, 'gcx, 'tcx, Self>, E> {
1149 let was_empty = std::mem::replace(&mut self.printer.empty, true);
1150 let mut printer = f(PrintCx {
1152 printer: self.printer,
1153 config: self.config,
1155 printer.empty &= was_empty;
1159 config: self.config,
1163 fn print_value_path(
1164 mut self: PrintCx<'_, '_, 'tcx, Self>,
1166 substs: Option<SubstsRef<'tcx>>,
1167 ) -> Result<Self::Path, Self::Error> {
1168 let was_in_value = std::mem::replace(&mut self.printer.in_value, true);
1169 let mut printer = self.print_def_path(def_id, substs, iter::empty())?;
1170 printer.in_value = was_in_value;
1175 fn generic_delimiters<'gcx, 'tcx>(
1176 mut self: PrintCx<'_, 'gcx, 'tcx, Self>,
1177 f: impl FnOnce(PrintCx<'_, 'gcx, 'tcx, Self>) -> Result<Self, Self::Error>,
1178 ) -> Result<Self, Self::Error> {
1179 if !self.printer.empty && self.printer.in_value {
1180 write!(self.printer, "::<")?;
1182 write!(self.printer, "<")?;
1185 let was_in_value = std::mem::replace(&mut self.printer.in_value, false);
1186 let mut printer = f(self)?;
1187 printer.in_value = was_in_value;
1189 write!(printer, ">")?;
1193 fn always_print_region_in_paths(
1194 self: &PrintCx<'_, '_, '_, Self>,
1195 region: ty::Region<'_>,
1197 *region != ty::ReErased
1200 fn print_region_outputs_anything(
1201 self: &PrintCx<'_, '_, '_, Self>,
1202 region: ty::Region<'_>,
1204 let highlight = self.printer.region_highlight_mode;
1205 if highlight.region_highlighted(region).is_some() {
1209 if self.config.is_verbose {
1214 ty::ReEarlyBound(ref data) => {
1215 data.name != "" && data.name != "'_"
1218 ty::ReLateBound(_, br) |
1219 ty::ReFree(ty::FreeRegion { bound_region: br, .. }) |
1220 ty::RePlaceholder(ty::Placeholder { name: br, .. }) => {
1221 if let ty::BrNamed(_, name) = br {
1222 if name != "" && name != "'_" {
1227 if let Some((region, _)) = highlight.highlight_bound_region {
1237 ty::ReVar(_) if self.config.identify_regions => true,
1241 ty::ReErased => false,
1245 ty::ReClosureBound(_) => true,