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::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable};
5 use crate::ty::subst::{Kind, Subst, SubstsRef, UnpackedKind};
6 use crate::middle::cstore::{ExternCrate, ExternCrateSource};
7 use syntax::symbol::{keywords, Symbol};
9 use rustc_data_structures::fx::FxHashSet;
10 use syntax::symbol::InternedString;
13 use std::fmt::{self, Write as _};
18 static FORCE_IMPL_FILENAME_LINE: Cell<bool> = Cell::new(false);
19 static SHOULD_PREFIX_WITH_CRATE: Cell<bool> = Cell::new(false);
22 /// Force us to name impls with just the filename/line number. We
23 /// normally try to use types. But at some points, notably while printing
24 /// cycle errors, this can result in extra or suboptimal error output,
25 /// so this variable disables that check.
26 pub fn with_forced_impl_filename_line<F: FnOnce() -> R, R>(f: F) -> R {
27 FORCE_IMPL_FILENAME_LINE.with(|force| {
28 let old = force.get();
36 /// Adds the `crate::` prefix to paths where appropriate.
37 pub fn with_crate_prefix<F: FnOnce() -> R, R>(f: F) -> R {
38 SHOULD_PREFIX_WITH_CRATE.with(|flag| {
47 // FIXME(eddyb) this module uses `pub(crate)` for things used only
48 // from `ppaux` - when that is removed, they can be re-privatized.
50 /// The "region highlights" are used to control region printing during
51 /// specific error messages. When a "region highlight" is enabled, it
52 /// gives an alternate way to print specific regions. For now, we
53 /// always print those regions using a number, so something like "`'0`".
55 /// Regions not selected by the region highlight mode are presently
57 #[derive(Copy, Clone, Default)]
58 pub struct RegionHighlightMode {
59 /// If enabled, when we see the selected region, use "`'N`"
60 /// instead of the ordinary behavior.
61 highlight_regions: [Option<(ty::RegionKind, usize)>; 3],
63 /// If enabled, when printing a "free region" that originated from
64 /// the given `ty::BoundRegion`, print it as "`'1`". Free regions that would ordinarily
65 /// have names print as normal.
67 /// This is used when you have a signature like `fn foo(x: &u32,
68 /// y: &'a u32)` and we want to give a name to the region of the
70 pub(crate) highlight_bound_region: Option<(ty::BoundRegion, usize)>,
73 impl RegionHighlightMode {
74 /// If `region` and `number` are both `Some`, invokes
75 /// `highlighting_region`.
76 pub fn maybe_highlighting_region(
78 region: Option<ty::Region<'_>>,
79 number: Option<usize>,
81 if let Some(k) = region {
82 if let Some(n) = number {
83 self.highlighting_region(k, n);
88 /// Highlights the region inference variable `vid` as `'N`.
89 pub fn highlighting_region(
91 region: ty::Region<'_>,
94 let num_slots = self.highlight_regions.len();
95 let first_avail_slot = self.highlight_regions.iter_mut()
96 .filter(|s| s.is_none())
100 "can only highlight {} placeholders at a time",
104 *first_avail_slot = Some((*region, number));
107 /// Convenience wrapper for `highlighting_region`.
108 pub fn highlighting_region_vid(
113 self.highlighting_region(&ty::ReVar(vid), number)
116 /// 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> {
121 .filter_map(|h| match h {
122 Some((r, n)) if r == region => Some(*n),
128 /// Highlight the given bound region.
129 /// We can only highlight one bound region at a time. See
130 /// the field `highlight_bound_region` for more detailed notes.
131 pub fn highlighting_bound_region(
136 assert!(self.highlight_bound_region.is_none());
137 self.highlight_bound_region = Some((br, number));
141 struct LateBoundRegionNameCollector(FxHashSet<InternedString>);
142 impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector {
143 fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
145 ty::ReLateBound(_, ty::BrNamed(_, name)) => {
150 r.super_visit_with(self)
154 pub(crate) struct PrintConfig {
155 pub(crate) is_debug: bool,
156 pub(crate) is_verbose: bool,
157 pub(crate) identify_regions: bool,
158 pub(crate) used_region_names: Option<FxHashSet<InternedString>>,
159 pub(crate) region_index: usize,
160 pub(crate) binder_depth: usize,
164 pub(crate) fn new(tcx: TyCtxt<'_, '_, '_>) -> Self {
167 is_verbose: tcx.sess.verbose(),
168 identify_regions: tcx.sess.opts.debugging_opts.identify_regions,
169 used_region_names: None,
176 pub struct PrintCx<'a, 'gcx, 'tcx, P> {
177 pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
179 pub(crate) config: &'a mut PrintConfig,
182 // HACK(eddyb) this is solely for `self: PrintCx<Self>`, e.g. to
183 // implement traits on the printer and call the methods on the context.
184 impl<P> Deref for PrintCx<'_, '_, '_, P> {
186 fn deref(&self) -> &P {
191 impl<'a, 'gcx, 'tcx, P> PrintCx<'a, 'gcx, 'tcx, P> {
193 tcx: TyCtxt<'a, 'gcx, 'tcx>,
195 f: impl FnOnce(PrintCx<'_, 'gcx, 'tcx, P>) -> R,
200 config: &mut PrintConfig::new(tcx),
204 pub(crate) fn with_tls_tcx<R>(printer: P, f: impl FnOnce(PrintCx<'_, '_, '_, P>) -> R) -> R {
205 ty::tls::with(|tcx| PrintCx::with(tcx, printer, f))
207 pub(crate) fn prepare_late_bound_region_info<T>(&mut self, value: &ty::Binder<T>)
208 where T: TypeFoldable<'tcx>
210 let mut collector = LateBoundRegionNameCollector(Default::default());
211 value.visit_with(&mut collector);
212 self.config.used_region_names = Some(collector.0);
213 self.config.region_index = 0;
217 pub trait Print<'tcx, P> {
221 fn print(&self, cx: PrintCx<'_, '_, 'tcx, P>) -> Result<Self::Output, Self::Error>;
224 cx: PrintCx<'_, '_, 'tcx, P>,
225 ) -> Result<Self::Output, Self::Error> {
226 let old_debug = cx.config.is_debug;
227 cx.config.is_debug = false;
228 let result = self.print(PrintCx {
233 cx.config.is_debug = old_debug;
236 fn print_debug(&self, cx: PrintCx<'_, '_, 'tcx, P>) -> Result<Self::Output, Self::Error> {
237 let old_debug = cx.config.is_debug;
238 cx.config.is_debug = true;
239 let result = self.print(PrintCx {
244 cx.config.is_debug = old_debug;
249 pub trait Printer: Sized {
255 self: PrintCx<'_, '_, 'tcx, Self>,
257 substs: Option<SubstsRef<'tcx>>,
259 projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
260 ) -> Result<Self::Path, Self::Error> {
261 self.default_print_def_path(def_id, substs, ns, projections)
264 self: PrintCx<'_, '_, 'tcx, Self>,
266 substs: Option<SubstsRef<'tcx>>,
269 trait_ref: Option<ty::TraitRef<'tcx>>,
270 ) -> Result<Self::Path, Self::Error> {
271 self.default_print_impl_path(impl_def_id, substs, ns, self_ty, trait_ref)
275 self: PrintCx<'_, '_, '_, Self>,
277 ) -> Result<Self::Path, Self::Error>;
279 self: PrintCx<'_, '_, 'tcx, Self>,
281 trait_ref: Option<ty::TraitRef<'tcx>>,
283 ) -> Result<Self::Path, Self::Error>;
285 fn path_append_impl<'gcx, 'tcx>(
286 self: PrintCx<'_, 'gcx, 'tcx, Self>,
287 print_prefix: impl FnOnce(
288 PrintCx<'_, 'gcx, 'tcx, Self>,
289 ) -> Result<Self::Path, Self::Error>,
291 trait_ref: Option<ty::TraitRef<'tcx>>,
292 ) -> Result<Self::Path, Self::Error>;
293 fn path_append<'gcx, 'tcx>(
294 self: PrintCx<'_, 'gcx, 'tcx, Self>,
295 print_prefix: impl FnOnce(
296 PrintCx<'_, 'gcx, 'tcx, Self>,
297 ) -> Result<Self::Path, Self::Error>,
299 ) -> Result<Self::Path, Self::Error>;
300 fn path_generic_args<'gcx, 'tcx>(
301 self: PrintCx<'_, 'gcx, 'tcx, Self>,
302 print_prefix: impl FnOnce(
303 PrintCx<'_, 'gcx, 'tcx, Self>,
304 ) -> Result<Self::Path, Self::Error>,
305 params: &[ty::GenericParamDef],
306 substs: SubstsRef<'tcx>,
308 projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
309 ) -> Result<Self::Path, Self::Error>;
312 /// Trait for printers that pretty-print using `fmt::Write` to the printer.
313 pub trait PrettyPrinter: Printer<Error = fmt::Error, Path = Self> + fmt::Write {
314 /// Enter a nested print context, for pretty-printing
315 /// nested components in some larger context.
316 fn nest<'a, 'gcx, 'tcx, E>(
317 self: PrintCx<'a, 'gcx, 'tcx, Self>,
318 f: impl for<'b> FnOnce(PrintCx<'b, 'gcx, 'tcx, Self>) -> Result<Self, E>,
319 ) -> Result<PrintCx<'a, 'gcx, 'tcx, Self>, E> {
320 let printer = f(PrintCx {
322 printer: self.printer,
332 fn region_highlight_mode(&self) -> RegionHighlightMode {
333 RegionHighlightMode::default()
338 ($cx:ident, $closure:expr) => {
339 $cx = $cx.nest($closure)?
343 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
344 // HACK(eddyb) get rid of `def_path_str` and/or pass `Namespace` explicitly always
345 // (but also some things just print a `DefId` generally so maybe we need this?)
346 fn guess_def_namespace(self, def_id: DefId) -> Namespace {
347 match self.def_key(def_id).disambiguated_data.data {
348 DefPathData::ValueNs(..) |
349 DefPathData::EnumVariant(..) |
350 DefPathData::Field(..) |
351 DefPathData::AnonConst |
352 DefPathData::ConstParam(..) |
353 DefPathData::ClosureExpr |
354 DefPathData::StructCtor => Namespace::ValueNS,
356 DefPathData::MacroDef(..) => Namespace::MacroNS,
358 _ => Namespace::TypeNS,
362 /// Returns a string identifying this `DefId`. This string is
363 /// suitable for user output.
364 pub fn def_path_str(self, def_id: DefId) -> String {
365 let ns = self.guess_def_namespace(def_id);
366 debug!("def_path_str: def_id={:?}, ns={:?}", def_id, ns);
367 let mut s = String::new();
368 let _ = PrintCx::with(self, FmtPrinter::new(&mut s), |cx| {
369 cx.print_def_path(def_id, None, ns, iter::empty())
375 impl<P: Printer> PrintCx<'a, 'gcx, 'tcx, P> {
376 pub fn default_print_def_path(
379 substs: Option<SubstsRef<'tcx>>,
381 projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
382 ) -> Result<P::Path, P::Error> {
383 debug!("default_print_def_path: def_id={:?}, substs={:?}, ns={:?}", def_id, substs, ns);
384 let key = self.tcx.def_key(def_id);
385 debug!("default_print_def_path: key={:?}", key);
387 match key.disambiguated_data.data {
388 DefPathData::CrateRoot => {
389 assert!(key.parent.is_none());
390 self.path_crate(def_id.krate)
393 DefPathData::Impl => {
394 let mut self_ty = self.tcx.type_of(def_id);
395 if let Some(substs) = substs {
396 self_ty = self_ty.subst(self.tcx, substs);
399 let mut impl_trait_ref = self.tcx.impl_trait_ref(def_id);
400 if let Some(substs) = substs {
401 impl_trait_ref = impl_trait_ref.subst(self.tcx, substs);
403 self.print_impl_path(def_id, substs, ns, self_ty, impl_trait_ref)
407 let generics = substs.map(|_| self.tcx.generics_of(def_id));
408 let generics_parent = generics.as_ref().and_then(|g| g.parent);
409 let parent_def_id = DefId { index: key.parent.unwrap(), ..def_id };
410 let print_parent_path = |cx: PrintCx<'_, 'gcx, 'tcx, P>| {
411 if let Some(generics_parent_def_id) = generics_parent {
412 assert_eq!(parent_def_id, generics_parent_def_id);
414 // FIXME(eddyb) try to move this into the parent's printing
415 // logic, instead of doing it when printing the child.
416 let parent_generics = cx.tcx.generics_of(parent_def_id);
417 let parent_has_own_self =
418 parent_generics.has_self && parent_generics.parent_count == 0;
419 if let (Some(substs), true) = (substs, parent_has_own_self) {
420 let trait_ref = ty::TraitRef::new(parent_def_id, substs);
421 cx.path_qualified(trait_ref.self_ty(), Some(trait_ref), ns)
423 cx.print_def_path(parent_def_id, substs, ns, iter::empty())
426 cx.print_def_path(parent_def_id, None, ns, iter::empty())
429 let print_path = |cx: PrintCx<'_, 'gcx, 'tcx, P>| {
430 match key.disambiguated_data.data {
431 // Skip `::{{constructor}}` on tuple/unit structs.
432 DefPathData::StructCtor => print_parent_path(cx),
437 &key.disambiguated_data.data.as_interned_str().as_str(),
443 if let (Some(generics), Some(substs)) = (generics, substs) {
444 let has_own_self = generics.has_self && generics.parent_count == 0;
445 let params = &generics.params[has_own_self as usize..];
446 self.path_generic_args(print_path, params, substs, ns, projections)
454 fn default_print_impl_path(
457 _substs: Option<SubstsRef<'tcx>>,
460 impl_trait_ref: Option<ty::TraitRef<'tcx>>,
461 ) -> Result<P::Path, P::Error> {
462 debug!("default_print_impl_path: impl_def_id={:?}, self_ty={}, impl_trait_ref={:?}",
463 impl_def_id, self_ty, impl_trait_ref);
465 // Decide whether to print the parent path for the impl.
466 // Logically, since impls are global, it's never needed, but
467 // users may find it useful. Currently, we omit the parent if
468 // the impl is either in the same module as the self-type or
470 let parent_def_id = self.tcx.parent(impl_def_id).unwrap();
471 let in_self_mod = match characteristic_def_id_of_type(self_ty) {
473 Some(ty_def_id) => self.tcx.parent(ty_def_id) == Some(parent_def_id),
475 let in_trait_mod = match impl_trait_ref {
477 Some(trait_ref) => self.tcx.parent(trait_ref.def_id) == Some(parent_def_id),
480 if !in_self_mod && !in_trait_mod {
481 // If the impl is not co-located with either self-type or
482 // trait-type, then fallback to a format that identifies
483 // the module more clearly.
484 self.path_append_impl(
485 |cx| cx.print_def_path(parent_def_id, None, ns, iter::empty()),
490 // Otherwise, try to give a good form that would be valid language
491 // syntax. Preferably using associated item notation.
492 self.path_qualified(self_ty, impl_trait_ref, ns)
497 /// As a heuristic, when we see an impl, if we see that the
498 /// 'self type' is a type defined in the same module as the impl,
499 /// we can omit including the path to the impl itself. This
500 /// function tries to find a "characteristic `DefId`" for a
501 /// type. It's just a heuristic so it makes some questionable
502 /// decisions and we may want to adjust it later.
503 pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> {
505 ty::Adt(adt_def, _) => Some(adt_def.did),
507 ty::Dynamic(data, ..) => data.principal_def_id(),
509 ty::Array(subty, _) |
510 ty::Slice(subty) => characteristic_def_id_of_type(subty),
512 ty::RawPtr(mt) => characteristic_def_id_of_type(mt.ty),
514 ty::Ref(_, ty, _) => characteristic_def_id_of_type(ty),
516 ty::Tuple(ref tys) => tys.iter()
517 .filter_map(|ty| characteristic_def_id_of_type(ty))
520 ty::FnDef(def_id, _) |
521 ty::Closure(def_id, _) |
522 ty::Generator(def_id, _, _) |
523 ty::Foreign(def_id) => Some(def_id),
532 ty::Placeholder(..) |
533 ty::UnnormalizedProjection(..) |
539 ty::GeneratorWitness(..) |
541 ty::Float(_) => None,
545 pub struct FmtPrinter<F: fmt::Write> {
548 pub region_highlight_mode: RegionHighlightMode,
551 impl<F: fmt::Write> FmtPrinter<F> {
552 pub fn new(fmt: F) -> Self {
556 region_highlight_mode: RegionHighlightMode::default(),
561 impl<'gcx, 'tcx, P: PrettyPrinter> PrintCx<'_, 'gcx, 'tcx, P> {
562 /// If possible, this returns a global path resolving to `def_id` that is visible
563 /// from at least one local module and returns true. If the crate defining `def_id` is
564 /// declared with an `extern crate`, the path is guaranteed to use the `extern crate`.
565 fn try_print_visible_def_path(
568 ) -> Result<(P, bool), P::Error> {
569 debug!("try_print_visible_def_path: def_id={:?}", def_id);
571 // If `def_id` is a direct or injected extern crate, return the
572 // path to the crate followed by the path to the item within the crate.
573 if def_id.index == CRATE_DEF_INDEX {
574 let cnum = def_id.krate;
576 if cnum == LOCAL_CRATE {
577 return Ok((self.path_crate(cnum)?, true));
580 // In local mode, when we encounter a crate other than
581 // LOCAL_CRATE, execution proceeds in one of two ways:
583 // 1. for a direct dependency, where user added an
584 // `extern crate` manually, we put the `extern
585 // crate` as the parent. So you wind up with
586 // something relative to the current crate.
587 // 2. for an extern inferred from a path or an indirect crate,
588 // where there is no explicit `extern crate`, we just prepend
590 match *self.tcx.extern_crate(def_id) {
592 src: ExternCrateSource::Extern(def_id),
597 debug!("try_print_visible_def_path: def_id={:?}", def_id);
598 return Ok((if !span.is_dummy() {
599 self.print_def_path(def_id, None, Namespace::TypeNS, iter::empty())?
601 self.path_crate(cnum)?
605 return Ok((self.path_crate(cnum)?, true));
611 if def_id.is_local() {
612 return Ok((self.printer, false));
615 let visible_parent_map = self.tcx.visible_parent_map(LOCAL_CRATE);
617 let mut cur_def_key = self.tcx.def_key(def_id);
618 debug!("try_print_visible_def_path: cur_def_key={:?}", cur_def_key);
620 // For a UnitStruct or TupleStruct we want the name of its parent rather than <unnamed>.
621 if let DefPathData::StructCtor = cur_def_key.disambiguated_data.data {
624 index: cur_def_key.parent.expect("DefPathData::StructCtor missing a parent"),
627 cur_def_key = self.tcx.def_key(parent);
630 let visible_parent = match visible_parent_map.get(&def_id).cloned() {
631 Some(parent) => parent,
632 None => return Ok((self.printer, false)),
634 // HACK(eddyb) this uses `nest` to avoid knowing ahead of time whether
635 // the entire path will succeed or not. To support printers that do not
636 // implement `PrettyPrinter`, a `Vec` or linked list on the stack would
637 // need to be built, before starting to print anything.
638 let mut prefix_success = false;
640 let (printer, success) = cx.try_print_visible_def_path(visible_parent)?;
641 prefix_success = success;
645 return Ok((self.printer, false));
647 let actual_parent = self.tcx.parent(def_id);
649 let data = cur_def_key.disambiguated_data.data;
651 "try_print_visible_def_path: data={:?} visible_parent={:?} actual_parent={:?}",
652 data, visible_parent, actual_parent,
655 let symbol = match data {
656 // In order to output a path that could actually be imported (valid and visible),
657 // we need to handle re-exports correctly.
659 // For example, take `std::os::unix::process::CommandExt`, this trait is actually
660 // defined at `std::sys::unix::ext::process::CommandExt` (at time of writing).
662 // `std::os::unix` rexports the contents of `std::sys::unix::ext`. `std::sys` is
663 // private so the "true" path to `CommandExt` isn't accessible.
665 // In this case, the `visible_parent_map` will look something like this:
667 // (child) -> (parent)
668 // `std::sys::unix::ext::process::CommandExt` -> `std::sys::unix::ext::process`
669 // `std::sys::unix::ext::process` -> `std::sys::unix::ext`
670 // `std::sys::unix::ext` -> `std::os`
672 // This is correct, as the visible parent of `std::sys::unix::ext` is in fact
675 // When printing the path to `CommandExt` and looking at the `cur_def_key` that
676 // corresponds to `std::sys::unix::ext`, we would normally print `ext` and then go
677 // to the parent - resulting in a mangled path like
678 // `std::os::ext::process::CommandExt`.
680 // Instead, we must detect that there was a re-export and instead print `unix`
681 // (which is the name `std::sys::unix::ext` was re-exported as in `std::os`). To
682 // do this, we compare the parent of `std::sys::unix::ext` (`std::sys::unix`) with
683 // the visible parent (`std::os`). If these do not match, then we iterate over
684 // the children of the visible parent (as was done when computing
685 // `visible_parent_map`), looking for the specific child we currently have and then
686 // have access to the re-exported name.
687 DefPathData::Module(actual_name) |
688 DefPathData::TypeNs(actual_name) if Some(visible_parent) != actual_parent => {
689 self.tcx.item_children(visible_parent)
691 .find(|child| child.def.def_id() == def_id)
692 .map(|child| child.ident.as_str())
693 .unwrap_or_else(|| actual_name.as_str())
696 data.get_opt_name().map(|n| n.as_str()).unwrap_or_else(|| {
697 // Re-exported `extern crate` (#43189).
698 if let DefPathData::CrateRoot = data {
699 self.tcx.original_crate_name(def_id.krate).as_str()
701 Symbol::intern("<unnamed>").as_str()
706 debug!("try_print_visible_def_path: symbol={:?}", symbol);
707 Ok((self.path_append(|cx| Ok(cx.printer), &symbol)?, true))
710 pub fn pretty_path_qualified(
713 trait_ref: Option<ty::TraitRef<'tcx>>,
715 ) -> Result<P::Path, P::Error> {
716 if trait_ref.is_none() {
717 // Inherent impls. Try to print `Foo::bar` for an inherent
718 // impl on `Foo`, but fallback to `<Foo>::bar` if self-type is
719 // anything other than a simple path.
721 ty::Adt(adt_def, substs) => {
722 return self.print_def_path(adt_def.did, Some(substs), ns, iter::empty());
724 ty::Foreign(did) => {
725 return self.print_def_path(did, None, ns, iter::empty());
728 ty::Bool | ty::Char | ty::Str |
729 ty::Int(_) | ty::Uint(_) | ty::Float(_) => {
730 return self_ty.print_display(self);
737 write!(self.printer, "<")?;
738 nest!(self, |cx| self_ty.print_display(cx));
739 if let Some(trait_ref) = trait_ref {
740 write!(self.printer, " as ")?;
741 nest!(self, |cx| cx.print_def_path(
743 Some(trait_ref.substs),
748 write!(self.printer, ">")?;
753 pub fn pretty_path_append_impl(
755 print_prefix: impl FnOnce(
756 PrintCx<'_, 'gcx, 'tcx, P>,
757 ) -> Result<P::Path, P::Error>,
759 trait_ref: Option<ty::TraitRef<'tcx>>,
760 ) -> Result<P::Path, P::Error> {
761 // HACK(eddyb) going through `path_append` means symbol name
762 // computation gets to handle its equivalent of `::` correctly.
763 nest!(self, |cx| cx.path_append(print_prefix, "<impl "));
764 if let Some(trait_ref) = trait_ref {
765 nest!(self, |cx| trait_ref.print_display(cx));
766 write!(self.printer, " for ")?;
768 nest!(self, |cx| self_ty.print_display(cx));
769 write!(self.printer, ">")?;
774 pub fn pretty_path_generic_args(
776 print_prefix: impl FnOnce(
777 PrintCx<'_, 'gcx, 'tcx, P>,
778 ) -> Result<P::Path, P::Error>,
779 params: &[ty::GenericParamDef],
780 substs: SubstsRef<'tcx>,
782 projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
783 ) -> Result<P::Path, P::Error> {
784 nest!(self, |cx| print_prefix(cx));
786 let mut empty = true;
787 let mut start_or_continue = |cx: &mut Self, start: &str, cont: &str| {
788 write!(cx.printer, "{}", if empty {
796 let start = if ns == Namespace::ValueNS { "::<" } else { "<" };
798 // Don't print any regions if they're all erased.
799 let print_regions = params.iter().any(|param| {
800 match substs[param.index as usize].unpack() {
801 UnpackedKind::Lifetime(r) => *r != ty::ReErased,
806 // Don't print args that are the defaults of their respective parameters.
807 let num_supplied_defaults = if self.config.is_verbose {
810 params.iter().rev().take_while(|param| {
812 ty::GenericParamDefKind::Lifetime => false,
813 ty::GenericParamDefKind::Type { has_default, .. } => {
814 has_default && substs[param.index as usize] == Kind::from(
815 self.tcx.type_of(param.def_id).subst(self.tcx, substs)
818 ty::GenericParamDefKind::Const => false, // FIXME(const_generics:defaults)
823 for param in ¶ms[..params.len() - num_supplied_defaults] {
824 match substs[param.index as usize].unpack() {
825 UnpackedKind::Lifetime(region) => {
829 start_or_continue(&mut self, start, ", ")?;
830 if !region.display_outputs_anything(&self) {
831 // This happens when the value of the region
832 // parameter is not easily serialized. This may be
833 // because the user omitted it in the first place,
834 // or because it refers to some block in the code,
835 // etc. I'm not sure how best to serialize this.
836 write!(self.printer, "'_")?;
838 nest!(self, |cx| region.print_display(cx));
841 UnpackedKind::Type(ty) => {
842 start_or_continue(&mut self, start, ", ")?;
843 nest!(self, |cx| ty.print_display(cx));
845 UnpackedKind::Const(ct) => {
846 start_or_continue(self, start, ", ")?;
847 ct.print_display(self)?;
852 for projection in projections {
853 start_or_continue(&mut self, start, ", ")?;
854 write!(self.printer, "{}=",
855 self.tcx.associated_item(projection.item_def_id).ident)?;
856 nest!(self, |cx| projection.ty.print_display(cx));
859 start_or_continue(&mut self, "", ">")?;
865 impl<F: fmt::Write> fmt::Write for FmtPrinter<F> {
866 fn write_str(&mut self, s: &str) -> fmt::Result {
867 self.empty &= s.is_empty();
868 self.fmt.write_str(s)
872 impl<F: fmt::Write> Printer for FmtPrinter<F> {
873 type Error = fmt::Error;
878 mut self: PrintCx<'_, '_, 'tcx, Self>,
880 substs: Option<SubstsRef<'tcx>>,
882 projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
883 ) -> Result<Self::Path, Self::Error> {
884 // FIXME(eddyb) avoid querying `tcx.generics_of` and `tcx.def_key`
885 // both here and in `default_print_def_path`.
886 let generics = substs.map(|_| self.tcx.generics_of(def_id));
887 if generics.as_ref().and_then(|g| g.parent).is_none() {
888 let mut visible_path_success = false;
890 let (printer, success) = cx.try_print_visible_def_path(def_id)?;
891 visible_path_success = success;
894 if visible_path_success {
895 return if let (Some(generics), Some(substs)) = (generics, substs) {
896 let has_own_self = generics.has_self && generics.parent_count == 0;
897 let params = &generics.params[has_own_self as usize..];
898 self.path_generic_args(|cx| Ok(cx.printer), params, substs, ns, projections)
905 let key = self.tcx.def_key(def_id);
906 if let DefPathData::Impl = key.disambiguated_data.data {
907 // Always use types for non-local impls, where types are always
908 // available, and filename/line-number is mostly uninteresting.
910 !def_id.is_local() || {
911 // Otherwise, use filename/line-number if forced.
912 let force_no_types = FORCE_IMPL_FILENAME_LINE.with(|f| f.get());
917 // If no type info is available, fall back to
918 // pretty printing some span information. This should
919 // only occur very early in the compiler pipeline.
920 let parent_def_id = DefId { index: key.parent.unwrap(), ..def_id };
921 let span = self.tcx.def_span(def_id);
922 return self.path_append(
923 |cx| cx.print_def_path(parent_def_id, None, ns, iter::empty()),
924 &format!("<impl at {:?}>", span),
929 self.default_print_def_path(def_id, substs, ns, projections)
933 mut self: PrintCx<'_, '_, '_, Self>,
935 ) -> Result<Self::Path, Self::Error> {
936 if cnum == LOCAL_CRATE {
937 if self.tcx.sess.rust_2018() {
938 // We add the `crate::` keyword on Rust 2018, only when desired.
939 if SHOULD_PREFIX_WITH_CRATE.with(|flag| flag.get()) {
940 write!(self.printer, "{}", keywords::Crate.name())?;
945 write!(self.printer, "{}", self.tcx.crate_name(cnum))?;
950 self: PrintCx<'_, '_, 'tcx, Self>,
952 trait_ref: Option<ty::TraitRef<'tcx>>,
954 ) -> Result<Self::Path, Self::Error> {
955 self.pretty_path_qualified(self_ty, trait_ref, ns)
958 fn path_append_impl<'gcx, 'tcx>(
959 self: PrintCx<'_, 'gcx, 'tcx, Self>,
960 print_prefix: impl FnOnce(
961 PrintCx<'_, 'gcx, 'tcx, Self>,
962 ) -> Result<Self::Path, Self::Error>,
964 trait_ref: Option<ty::TraitRef<'tcx>>,
965 ) -> Result<Self::Path, Self::Error> {
966 self.pretty_path_append_impl(print_prefix, self_ty, trait_ref)
968 fn path_append<'gcx, 'tcx>(
969 self: PrintCx<'_, 'gcx, 'tcx, Self>,
970 print_prefix: impl FnOnce(
971 PrintCx<'_, 'gcx, 'tcx, Self>,
972 ) -> Result<Self::Path, Self::Error>,
974 ) -> Result<Self::Path, Self::Error> {
975 let mut printer = print_prefix(self)?;
977 // FIXME(eddyb) `text` should never be empty, but it
978 // currently is for `extern { ... }` "foreign modules".
979 if !text.is_empty() {
981 write!(printer, "::")?;
983 write!(printer, "{}", text)?;
988 fn path_generic_args<'gcx, 'tcx>(
989 self: PrintCx<'_, 'gcx, 'tcx, Self>,
990 print_prefix: impl FnOnce(
991 PrintCx<'_, 'gcx, 'tcx, Self>,
992 ) -> Result<Self::Path, Self::Error>,
993 params: &[ty::GenericParamDef],
994 substs: SubstsRef<'tcx>,
996 projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
997 ) -> Result<Self::Path, Self::Error> {
998 self.pretty_path_generic_args(print_prefix, params, substs, ns, projections)
1002 impl<F: fmt::Write> PrettyPrinter for FmtPrinter<F> {
1003 fn nest<'a, 'gcx, 'tcx, E>(
1004 mut self: PrintCx<'a, 'gcx, 'tcx, Self>,
1005 f: impl for<'b> FnOnce(PrintCx<'b, 'gcx, 'tcx, Self>) -> Result<Self, E>,
1006 ) -> Result<PrintCx<'a, 'gcx, 'tcx, Self>, E> {
1007 let was_empty = std::mem::replace(&mut self.printer.empty, true);
1008 let mut printer = f(PrintCx {
1010 printer: self.printer,
1011 config: self.config,
1013 printer.empty &= was_empty;
1017 config: self.config,
1021 fn region_highlight_mode(&self) -> RegionHighlightMode {
1022 self.region_highlight_mode