1use std::cell::Cell;
2use std::fmt::{self, Write as _};
3use std::iter;
4use std::ops::{Deref, DerefMut};
5
6use rustc_abi::{ExternAbi, Size};
7use rustc_apfloat::Float;
8use rustc_apfloat::ieee::{Double, Half, Quad, Single};
9use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
10use rustc_data_structures::unord::UnordMap;
11use rustc_hir as hir;
12use rustc_hir::LangItem;
13use rustc_hir::def::{self, CtorKind, DefKind, Namespace};
14use rustc_hir::def_id::{CRATE_DEF_ID, DefIdMap, DefIdSet, LOCAL_CRATE, ModDefId};
15use rustc_hir::definitions::{DefKey, DefPathDataName};
16use rustc_macros::{Lift, extension};
17use rustc_session::Limit;
18use rustc_session::cstore::{ExternCrate, ExternCrateSource};
19use rustc_span::{FileNameDisplayPreference, Ident, Symbol, kw, sym};
20use rustc_type_ir::{Upcast as _, elaborate};
21use smallvec::SmallVec;
22
23use super::*;
25use crate::mir::interpret::{AllocRange, GlobalAlloc, Pointer, Provenance, Scalar};
26use crate::query::{IntoQueryParam, Providers};
27use crate::ty::{
28 ConstInt, Expr, GenericArgKind, ParamConst, ScalarInt, Term, TermKind, TraitPredicate,
29 TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
30};
31
32macro_rules! p {
33 (@$lit:literal) => {
34 write!(scoped_cx!(), $lit)?
35 };
36 (@write($($data:expr),+)) => {
37 write!(scoped_cx!(), $($data),+)?
38 };
39 (@print($x:expr)) => {
40 $x.print(scoped_cx!())?
41 };
42 (@$method:ident($($arg:expr),*)) => {
43 scoped_cx!().$method($($arg),*)?
44 };
45 ($($elem:tt $(($($args:tt)*))?),+) => {{
46 $(p!(@ $elem $(($($args)*))?);)+
47 }};
48}
49macro_rules! define_scoped_cx {
50 ($cx:ident) => {
51 macro_rules! scoped_cx {
52 () => {
53 $cx
54 };
55 }
56 };
57}
58
59thread_local! {
60 static FORCE_IMPL_FILENAME_LINE: Cell<bool> = const { Cell::new(false) };
61 static SHOULD_PREFIX_WITH_CRATE: Cell<bool> = const { Cell::new(false) };
62 static NO_TRIMMED_PATH: Cell<bool> = const { Cell::new(false) };
63 static FORCE_TRIMMED_PATH: Cell<bool> = const { Cell::new(false) };
64 static REDUCED_QUERIES: Cell<bool> = const { Cell::new(false) };
65 static NO_VISIBLE_PATH: Cell<bool> = const { Cell::new(false) };
66}
67
68macro_rules! define_helper {
69 ($($(#[$a:meta])* fn $name:ident($helper:ident, $tl:ident);)+) => {
70 $(
71 #[must_use]
72 pub struct $helper(bool);
73
74 impl $helper {
75 pub fn new() -> $helper {
76 $helper($tl.with(|c| c.replace(true)))
77 }
78 }
79
80 $(#[$a])*
81 pub macro $name($e:expr) {
82 {
83 let _guard = $helper::new();
84 $e
85 }
86 }
87
88 impl Drop for $helper {
89 fn drop(&mut self) {
90 $tl.with(|c| c.set(self.0))
91 }
92 }
93
94 pub fn $name() -> bool {
95 $tl.with(|c| c.get())
96 }
97 )+
98 }
99}
100
101define_helper!(
102 fn with_reduced_queries(ReducedQueriesGuard, REDUCED_QUERIES);
110 fn with_forced_impl_filename_line(ForcedImplGuard, FORCE_IMPL_FILENAME_LINE);
115 fn with_crate_prefix(CratePrefixGuard, SHOULD_PREFIX_WITH_CRATE);
117 fn with_no_trimmed_paths(NoTrimmedGuard, NO_TRIMMED_PATH);
121 fn with_forced_trimmed_paths(ForceTrimmedGuard, FORCE_TRIMMED_PATH);
122 fn with_no_visible_paths(NoVisibleGuard, NO_VISIBLE_PATH);
125);
126
127pub macro with_no_queries($e:expr) {{
129 $crate::ty::print::with_reduced_queries!($crate::ty::print::with_forced_impl_filename_line!(
130 $crate::ty::print::with_no_trimmed_paths!($crate::ty::print::with_no_visible_paths!(
131 $crate::ty::print::with_forced_impl_filename_line!($e)
132 ))
133 ))
134}}
135
136#[derive(Copy, Clone, Default)]
144pub struct RegionHighlightMode<'tcx> {
145 highlight_regions: [Option<(ty::Region<'tcx>, usize)>; 3],
148
149 highlight_bound_region: Option<(ty::BoundRegionKind, usize)>,
157}
158
159impl<'tcx> RegionHighlightMode<'tcx> {
160 pub fn maybe_highlighting_region(
163 &mut self,
164 region: Option<ty::Region<'tcx>>,
165 number: Option<usize>,
166 ) {
167 if let Some(k) = region {
168 if let Some(n) = number {
169 self.highlighting_region(k, n);
170 }
171 }
172 }
173
174 pub fn highlighting_region(&mut self, region: ty::Region<'tcx>, number: usize) {
176 let num_slots = self.highlight_regions.len();
177 let first_avail_slot =
178 self.highlight_regions.iter_mut().find(|s| s.is_none()).unwrap_or_else(|| {
179 bug!("can only highlight {} placeholders at a time", num_slots,)
180 });
181 *first_avail_slot = Some((region, number));
182 }
183
184 pub fn highlighting_region_vid(
186 &mut self,
187 tcx: TyCtxt<'tcx>,
188 vid: ty::RegionVid,
189 number: usize,
190 ) {
191 self.highlighting_region(ty::Region::new_var(tcx, vid), number)
192 }
193
194 fn region_highlighted(&self, region: ty::Region<'tcx>) -> Option<usize> {
196 self.highlight_regions.iter().find_map(|h| match h {
197 Some((r, n)) if *r == region => Some(*n),
198 _ => None,
199 })
200 }
201
202 pub fn highlighting_bound_region(&mut self, br: ty::BoundRegionKind, number: usize) {
206 assert!(self.highlight_bound_region.is_none());
207 self.highlight_bound_region = Some((br, number));
208 }
209}
210
211pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
213 fn print_value_path(
215 &mut self,
216 def_id: DefId,
217 args: &'tcx [GenericArg<'tcx>],
218 ) -> Result<(), PrintError> {
219 self.print_def_path(def_id, args)
220 }
221
222 fn in_binder<T>(&mut self, value: &ty::Binder<'tcx, T>) -> Result<(), PrintError>
223 where
224 T: Print<'tcx, Self> + TypeFoldable<TyCtxt<'tcx>>,
225 {
226 value.as_ref().skip_binder().print(self)
227 }
228
229 fn wrap_binder<T, F: FnOnce(&T, &mut Self) -> Result<(), fmt::Error>>(
230 &mut self,
231 value: &ty::Binder<'tcx, T>,
232 f: F,
233 ) -> Result<(), PrintError>
234 where
235 T: Print<'tcx, Self> + TypeFoldable<TyCtxt<'tcx>>,
236 {
237 f(value.as_ref().skip_binder(), self)
238 }
239
240 fn comma_sep<T>(&mut self, mut elems: impl Iterator<Item = T>) -> Result<(), PrintError>
242 where
243 T: Print<'tcx, Self>,
244 {
245 if let Some(first) = elems.next() {
246 first.print(self)?;
247 for elem in elems {
248 self.write_str(", ")?;
249 elem.print(self)?;
250 }
251 }
252 Ok(())
253 }
254
255 fn typed_value(
257 &mut self,
258 f: impl FnOnce(&mut Self) -> Result<(), PrintError>,
259 t: impl FnOnce(&mut Self) -> Result<(), PrintError>,
260 conversion: &str,
261 ) -> Result<(), PrintError> {
262 self.write_str("{")?;
263 f(self)?;
264 self.write_str(conversion)?;
265 t(self)?;
266 self.write_str("}")?;
267 Ok(())
268 }
269
270 fn parenthesized(
272 &mut self,
273 f: impl FnOnce(&mut Self) -> Result<(), PrintError>,
274 ) -> Result<(), PrintError> {
275 self.write_str("(")?;
276 f(self)?;
277 self.write_str(")")?;
278 Ok(())
279 }
280
281 fn maybe_parenthesized(
283 &mut self,
284 f: impl FnOnce(&mut Self) -> Result<(), PrintError>,
285 parenthesized: bool,
286 ) -> Result<(), PrintError> {
287 if parenthesized {
288 self.parenthesized(f)?;
289 } else {
290 f(self)?;
291 }
292 Ok(())
293 }
294
295 fn generic_delimiters(
297 &mut self,
298 f: impl FnOnce(&mut Self) -> Result<(), PrintError>,
299 ) -> Result<(), PrintError>;
300
301 fn should_print_region(&self, region: ty::Region<'tcx>) -> bool;
305
306 fn reset_type_limit(&mut self) {}
307
308 fn try_print_visible_def_path(&mut self, def_id: DefId) -> Result<bool, PrintError> {
314 if with_no_visible_paths() {
315 return Ok(false);
316 }
317
318 let mut callers = Vec::new();
319 self.try_print_visible_def_path_recur(def_id, &mut callers)
320 }
321
322 fn force_print_trimmed_def_path(&mut self, def_id: DefId) -> Result<bool, PrintError> {
328 let key = self.tcx().def_key(def_id);
329 let visible_parent_map = self.tcx().visible_parent_map(());
330 let kind = self.tcx().def_kind(def_id);
331
332 let get_local_name = |this: &Self, name, def_id, key: DefKey| {
333 if let Some(visible_parent) = visible_parent_map.get(&def_id)
334 && let actual_parent = this.tcx().opt_parent(def_id)
335 && let DefPathData::TypeNs(_) = key.disambiguated_data.data
336 && Some(*visible_parent) != actual_parent
337 {
338 this.tcx()
339 .module_children(ModDefId::new_unchecked(*visible_parent))
341 .iter()
342 .filter(|child| child.res.opt_def_id() == Some(def_id))
343 .find(|child| child.vis.is_public() && child.ident.name != kw::Underscore)
344 .map(|child| child.ident.name)
345 .unwrap_or(name)
346 } else {
347 name
348 }
349 };
350 if let DefKind::Variant = kind
351 && let Some(symbol) = self.tcx().trimmed_def_paths(()).get(&def_id)
352 {
353 self.write_str(get_local_name(self, *symbol, def_id, key).as_str())?;
355 return Ok(true);
356 }
357 if let Some(symbol) = key.get_opt_name() {
358 if let DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy = kind
359 && let Some(parent) = self.tcx().opt_parent(def_id)
360 && let parent_key = self.tcx().def_key(parent)
361 && let Some(symbol) = parent_key.get_opt_name()
362 {
363 self.write_str(get_local_name(self, symbol, parent, parent_key).as_str())?;
365 self.write_str("::")?;
366 } else if let DefKind::Variant = kind
367 && let Some(parent) = self.tcx().opt_parent(def_id)
368 && let parent_key = self.tcx().def_key(parent)
369 && let Some(symbol) = parent_key.get_opt_name()
370 {
371 self.write_str(get_local_name(self, symbol, parent, parent_key).as_str())?;
376 self.write_str("::")?;
377 } else if let DefKind::Struct
378 | DefKind::Union
379 | DefKind::Enum
380 | DefKind::Trait
381 | DefKind::TyAlias
382 | DefKind::Fn
383 | DefKind::Const
384 | DefKind::Static { .. } = kind
385 {
386 } else {
387 return Ok(false);
389 }
390 self.write_str(get_local_name(self, symbol, def_id, key).as_str())?;
391 return Ok(true);
392 }
393 Ok(false)
394 }
395
396 fn try_print_trimmed_def_path(&mut self, def_id: DefId) -> Result<bool, PrintError> {
398 if with_forced_trimmed_paths() && self.force_print_trimmed_def_path(def_id)? {
399 return Ok(true);
400 }
401 if self.tcx().sess.opts.unstable_opts.trim_diagnostic_paths
402 && self.tcx().sess.opts.trimmed_def_paths
403 && !with_no_trimmed_paths()
404 && !with_crate_prefix()
405 && let Some(symbol) = self.tcx().trimmed_def_paths(()).get(&def_id)
406 {
407 write!(self, "{}", Ident::with_dummy_span(*symbol))?;
408 Ok(true)
409 } else {
410 Ok(false)
411 }
412 }
413
414 fn try_print_visible_def_path_recur(
428 &mut self,
429 def_id: DefId,
430 callers: &mut Vec<DefId>,
431 ) -> Result<bool, PrintError> {
432 debug!("try_print_visible_def_path: def_id={:?}", def_id);
433
434 if let Some(cnum) = def_id.as_crate_root() {
437 if cnum == LOCAL_CRATE {
438 self.path_crate(cnum)?;
439 return Ok(true);
440 }
441
442 match self.tcx().extern_crate(cnum) {
453 Some(&ExternCrate { src, dependency_of, span, .. }) => match (src, dependency_of) {
454 (ExternCrateSource::Extern(def_id), LOCAL_CRATE) => {
455 if span.is_dummy() {
462 self.path_crate(cnum)?;
463 return Ok(true);
464 }
465
466 with_no_visible_paths!(self.print_def_path(def_id, &[])?);
472
473 return Ok(true);
474 }
475 (ExternCrateSource::Path, LOCAL_CRATE) => {
476 self.path_crate(cnum)?;
477 return Ok(true);
478 }
479 _ => {}
480 },
481 None => {
482 self.path_crate(cnum)?;
483 return Ok(true);
484 }
485 }
486 }
487
488 if def_id.is_local() {
489 return Ok(false);
490 }
491
492 let visible_parent_map = self.tcx().visible_parent_map(());
493
494 let mut cur_def_key = self.tcx().def_key(def_id);
495 debug!("try_print_visible_def_path: cur_def_key={:?}", cur_def_key);
496
497 if let DefPathData::Ctor = cur_def_key.disambiguated_data.data {
499 let parent = DefId {
500 krate: def_id.krate,
501 index: cur_def_key
502 .parent
503 .expect("`DefPathData::Ctor` / `VariantData` missing a parent"),
504 };
505
506 cur_def_key = self.tcx().def_key(parent);
507 }
508
509 let Some(visible_parent) = visible_parent_map.get(&def_id).cloned() else {
510 return Ok(false);
511 };
512
513 let actual_parent = self.tcx().opt_parent(def_id);
514 debug!(
515 "try_print_visible_def_path: visible_parent={:?} actual_parent={:?}",
516 visible_parent, actual_parent,
517 );
518
519 let mut data = cur_def_key.disambiguated_data.data;
520 debug!(
521 "try_print_visible_def_path: data={:?} visible_parent={:?} actual_parent={:?}",
522 data, visible_parent, actual_parent,
523 );
524
525 match data {
526 DefPathData::TypeNs(ref mut name) if Some(visible_parent) != actual_parent => {
558 let reexport = self
561 .tcx()
562 .module_children(ModDefId::new_unchecked(visible_parent))
564 .iter()
565 .filter(|child| child.res.opt_def_id() == Some(def_id))
566 .find(|child| child.vis.is_public() && child.ident.name != kw::Underscore)
567 .map(|child| child.ident.name);
568
569 if let Some(new_name) = reexport {
570 *name = new_name;
571 } else {
572 return Ok(false);
574 }
575 }
576 DefPathData::CrateRoot => {
578 data = DefPathData::TypeNs(self.tcx().crate_name(def_id.krate));
579 }
580 _ => {}
581 }
582 debug!("try_print_visible_def_path: data={:?}", data);
583
584 if callers.contains(&visible_parent) {
585 return Ok(false);
586 }
587 callers.push(visible_parent);
588 match self.try_print_visible_def_path_recur(visible_parent, callers)? {
593 false => return Ok(false),
594 true => {}
595 }
596 callers.pop();
597 self.path_append(|_| Ok(()), &DisambiguatedDefPathData { data, disambiguator: 0 })?;
598 Ok(true)
599 }
600
601 fn pretty_path_qualified(
602 &mut self,
603 self_ty: Ty<'tcx>,
604 trait_ref: Option<ty::TraitRef<'tcx>>,
605 ) -> Result<(), PrintError> {
606 if trait_ref.is_none() {
607 match self_ty.kind() {
611 ty::Adt(..)
612 | ty::Foreign(_)
613 | ty::Bool
614 | ty::Char
615 | ty::Str
616 | ty::Int(_)
617 | ty::Uint(_)
618 | ty::Float(_) => {
619 return self_ty.print(self);
620 }
621
622 _ => {}
623 }
624 }
625
626 self.generic_delimiters(|cx| {
627 define_scoped_cx!(cx);
628
629 p!(print(self_ty));
630 if let Some(trait_ref) = trait_ref {
631 p!(" as ", print(trait_ref.print_only_trait_path()));
632 }
633 Ok(())
634 })
635 }
636
637 fn pretty_path_append_impl(
638 &mut self,
639 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
640 self_ty: Ty<'tcx>,
641 trait_ref: Option<ty::TraitRef<'tcx>>,
642 ) -> Result<(), PrintError> {
643 print_prefix(self)?;
644
645 self.generic_delimiters(|cx| {
646 define_scoped_cx!(cx);
647
648 p!("impl ");
649 if let Some(trait_ref) = trait_ref {
650 p!(print(trait_ref.print_only_trait_path()), " for ");
651 }
652 p!(print(self_ty));
653
654 Ok(())
655 })
656 }
657
658 fn pretty_print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> {
659 define_scoped_cx!(self);
660
661 match *ty.kind() {
662 ty::Bool => p!("bool"),
663 ty::Char => p!("char"),
664 ty::Int(t) => p!(write("{}", t.name_str())),
665 ty::Uint(t) => p!(write("{}", t.name_str())),
666 ty::Float(t) => p!(write("{}", t.name_str())),
667 ty::Pat(ty, pat) => {
668 p!("(", print(ty), ") is ", write("{pat:?}"))
669 }
670 ty::RawPtr(ty, mutbl) => {
671 p!(write("*{} ", mutbl.ptr_str()));
672 p!(print(ty))
673 }
674 ty::Ref(r, ty, mutbl) => {
675 p!("&");
676 if self.should_print_region(r) {
677 p!(print(r), " ");
678 }
679 p!(print(ty::TypeAndMut { ty, mutbl }))
680 }
681 ty::Never => p!("!"),
682 ty::Tuple(tys) => {
683 p!("(", comma_sep(tys.iter()));
684 if tys.len() == 1 {
685 p!(",");
686 }
687 p!(")")
688 }
689 ty::FnDef(def_id, args) => {
690 if with_reduced_queries() {
691 p!(print_def_path(def_id, args));
692 } else {
693 let mut sig = self.tcx().fn_sig(def_id).instantiate(self.tcx(), args);
694 if self.tcx().codegen_fn_attrs(def_id).safe_target_features {
695 p!("#[target_features] ");
696 sig = sig.map_bound(|mut sig| {
697 sig.safety = hir::Safety::Safe;
698 sig
699 });
700 }
701 p!(print(sig), " {{", print_value_path(def_id, args), "}}");
702 }
703 }
704 ty::FnPtr(ref sig_tys, hdr) => p!(print(sig_tys.with(hdr))),
705 ty::UnsafeBinder(ref bound_ty) => {
706 self.wrap_binder(bound_ty, |ty, cx| cx.pretty_print_type(*ty))?;
708 }
709 ty::Infer(infer_ty) => {
710 if self.should_print_verbose() {
711 p!(write("{:?}", ty.kind()));
712 return Ok(());
713 }
714
715 if let ty::TyVar(ty_vid) = infer_ty {
716 if let Some(name) = self.ty_infer_name(ty_vid) {
717 p!(write("{}", name))
718 } else {
719 p!(write("{}", infer_ty))
720 }
721 } else {
722 p!(write("{}", infer_ty))
723 }
724 }
725 ty::Error(_) => p!("{{type error}}"),
726 ty::Param(ref param_ty) => p!(print(param_ty)),
727 ty::Bound(debruijn, bound_ty) => match bound_ty.kind {
728 ty::BoundTyKind::Anon => {
729 rustc_type_ir::debug_bound_var(self, debruijn, bound_ty.var)?
730 }
731 ty::BoundTyKind::Param(_, s) => match self.should_print_verbose() {
732 true => p!(write("{:?}", ty.kind())),
733 false => p!(write("{s}")),
734 },
735 },
736 ty::Adt(def, args) => {
737 p!(print_def_path(def.did(), args));
738 }
739 ty::Dynamic(data, r, repr) => {
740 let print_r = self.should_print_region(r);
741 if print_r {
742 p!("(");
743 }
744 match repr {
745 ty::Dyn => p!("dyn "),
746 ty::DynStar => p!("dyn* "),
747 }
748 p!(print(data));
749 if print_r {
750 p!(" + ", print(r), ")");
751 }
752 }
753 ty::Foreign(def_id) => {
754 p!(print_def_path(def_id, &[]));
755 }
756 ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ref data) => {
757 p!(print(data))
758 }
759 ty::Placeholder(placeholder) => match placeholder.bound.kind {
760 ty::BoundTyKind::Anon => p!(write("{placeholder:?}")),
761 ty::BoundTyKind::Param(_, name) => match self.should_print_verbose() {
762 true => p!(write("{:?}", ty.kind())),
763 false => p!(write("{name}")),
764 },
765 },
766 ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
767 if self.should_print_verbose() {
776 p!(write("Opaque({:?}, {})", def_id, args.print_as_list()));
778 return Ok(());
779 }
780
781 let parent = self.tcx().parent(def_id);
782 match self.tcx().def_kind(parent) {
783 DefKind::TyAlias | DefKind::AssocTy => {
784 if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: d, .. }) =
787 *self.tcx().type_of(parent).instantiate_identity().kind()
788 {
789 if d == def_id {
790 p!(print_def_path(parent, args));
793 return Ok(());
794 }
795 }
796 p!(print_def_path(def_id, args));
798 return Ok(());
799 }
800 _ => {
801 if with_reduced_queries() {
802 p!(print_def_path(def_id, &[]));
803 return Ok(());
804 } else {
805 return self.pretty_print_opaque_impl_type(def_id, args);
806 }
807 }
808 }
809 }
810 ty::Str => p!("str"),
811 ty::Coroutine(did, args) => {
812 p!("{{");
813 let coroutine_kind = self.tcx().coroutine_kind(did).unwrap();
814 let should_print_movability = self.should_print_verbose()
815 || matches!(coroutine_kind, hir::CoroutineKind::Coroutine(_));
816
817 if should_print_movability {
818 match coroutine_kind.movability() {
819 hir::Movability::Movable => {}
820 hir::Movability::Static => p!("static "),
821 }
822 }
823
824 if !self.should_print_verbose() {
825 p!(write("{}", coroutine_kind));
826 if coroutine_kind.is_fn_like() {
827 let did_of_the_fn_item = self.tcx().parent(did);
834 p!(" of ", print_def_path(did_of_the_fn_item, args), "()");
835 } else if let Some(local_did) = did.as_local() {
836 let span = self.tcx().def_span(local_did);
837 p!(write(
838 "@{}",
839 self.tcx().sess.source_map().span_to_embeddable_string(span)
842 ));
843 } else {
844 p!("@", print_def_path(did, args));
845 }
846 } else {
847 p!(print_def_path(did, args));
848 p!(
849 " upvar_tys=",
850 print(args.as_coroutine().tupled_upvars_ty()),
851 " resume_ty=",
852 print(args.as_coroutine().resume_ty()),
853 " yield_ty=",
854 print(args.as_coroutine().yield_ty()),
855 " return_ty=",
856 print(args.as_coroutine().return_ty()),
857 " witness=",
858 print(args.as_coroutine().witness())
859 );
860 }
861
862 p!("}}")
863 }
864 ty::CoroutineWitness(did, args) => {
865 p!(write("{{"));
866 if !self.tcx().sess.verbose_internals() {
867 p!("coroutine witness");
868 if let Some(did) = did.as_local() {
869 let span = self.tcx().def_span(did);
870 p!(write(
871 "@{}",
872 self.tcx().sess.source_map().span_to_embeddable_string(span)
875 ));
876 } else {
877 p!(write("@"), print_def_path(did, args));
878 }
879 } else {
880 p!(print_def_path(did, args));
881 }
882
883 p!("}}")
884 }
885 ty::Closure(did, args) => {
886 p!(write("{{"));
887 if !self.should_print_verbose() {
888 p!(write("closure"));
889 if self.should_truncate() {
890 write!(self, "@...}}")?;
891 return Ok(());
892 } else {
893 if let Some(did) = did.as_local() {
894 if self.tcx().sess.opts.unstable_opts.span_free_formats {
895 p!("@", print_def_path(did.to_def_id(), args));
896 } else {
897 let span = self.tcx().def_span(did);
898 let preference = if with_forced_trimmed_paths() {
899 FileNameDisplayPreference::Short
900 } else {
901 FileNameDisplayPreference::Remapped
902 };
903 p!(write(
904 "@{}",
905 self.tcx().sess.source_map().span_to_string(span, preference)
908 ));
909 }
910 } else {
911 p!(write("@"), print_def_path(did, args));
912 }
913 }
914 } else {
915 p!(print_def_path(did, args));
916 p!(
917 " closure_kind_ty=",
918 print(args.as_closure().kind_ty()),
919 " closure_sig_as_fn_ptr_ty=",
920 print(args.as_closure().sig_as_fn_ptr_ty()),
921 " upvar_tys=",
922 print(args.as_closure().tupled_upvars_ty())
923 );
924 }
925 p!("}}");
926 }
927 ty::CoroutineClosure(did, args) => {
928 p!(write("{{"));
929 if !self.should_print_verbose() {
930 match self.tcx().coroutine_kind(self.tcx().coroutine_for_closure(did)).unwrap()
931 {
932 hir::CoroutineKind::Desugared(
933 hir::CoroutineDesugaring::Async,
934 hir::CoroutineSource::Closure,
935 ) => p!("async closure"),
936 hir::CoroutineKind::Desugared(
937 hir::CoroutineDesugaring::AsyncGen,
938 hir::CoroutineSource::Closure,
939 ) => p!("async gen closure"),
940 hir::CoroutineKind::Desugared(
941 hir::CoroutineDesugaring::Gen,
942 hir::CoroutineSource::Closure,
943 ) => p!("gen closure"),
944 _ => unreachable!(
945 "coroutine from coroutine-closure should have CoroutineSource::Closure"
946 ),
947 }
948 if let Some(did) = did.as_local() {
949 if self.tcx().sess.opts.unstable_opts.span_free_formats {
950 p!("@", print_def_path(did.to_def_id(), args));
951 } else {
952 let span = self.tcx().def_span(did);
953 let preference = if with_forced_trimmed_paths() {
954 FileNameDisplayPreference::Short
955 } else {
956 FileNameDisplayPreference::Remapped
957 };
958 p!(write(
959 "@{}",
960 self.tcx().sess.source_map().span_to_string(span, preference)
963 ));
964 }
965 } else {
966 p!(write("@"), print_def_path(did, args));
967 }
968 } else {
969 p!(print_def_path(did, args));
970 p!(
971 " closure_kind_ty=",
972 print(args.as_coroutine_closure().kind_ty()),
973 " signature_parts_ty=",
974 print(args.as_coroutine_closure().signature_parts_ty()),
975 " upvar_tys=",
976 print(args.as_coroutine_closure().tupled_upvars_ty()),
977 " coroutine_captures_by_ref_ty=",
978 print(args.as_coroutine_closure().coroutine_captures_by_ref_ty()),
979 " coroutine_witness_ty=",
980 print(args.as_coroutine_closure().coroutine_witness_ty())
981 );
982 }
983 p!("}}");
984 }
985 ty::Array(ty, sz) => p!("[", print(ty), "; ", print(sz), "]"),
986 ty::Slice(ty) => p!("[", print(ty), "]"),
987 }
988
989 Ok(())
990 }
991
992 fn pretty_print_opaque_impl_type(
993 &mut self,
994 def_id: DefId,
995 args: ty::GenericArgsRef<'tcx>,
996 ) -> Result<(), PrintError> {
997 let tcx = self.tcx();
998
999 let bounds = tcx.explicit_item_bounds(def_id);
1002
1003 let mut traits = FxIndexMap::default();
1004 let mut fn_traits = FxIndexMap::default();
1005 let mut has_sized_bound = false;
1006 let mut has_negative_sized_bound = false;
1007 let mut lifetimes = SmallVec::<[ty::Region<'tcx>; 1]>::new();
1008
1009 for (predicate, _) in bounds.iter_instantiated_copied(tcx, args) {
1010 let bound_predicate = predicate.kind();
1011
1012 match bound_predicate.skip_binder() {
1013 ty::ClauseKind::Trait(pred) => {
1014 if tcx.is_lang_item(pred.def_id(), LangItem::Sized) {
1016 match pred.polarity {
1017 ty::PredicatePolarity::Positive => {
1018 has_sized_bound = true;
1019 continue;
1020 }
1021 ty::PredicatePolarity::Negative => has_negative_sized_bound = true,
1022 }
1023 }
1024
1025 self.insert_trait_and_projection(
1026 bound_predicate.rebind(pred),
1027 None,
1028 &mut traits,
1029 &mut fn_traits,
1030 );
1031 }
1032 ty::ClauseKind::Projection(pred) => {
1033 let proj = bound_predicate.rebind(pred);
1034 let trait_ref = proj.map_bound(|proj| TraitPredicate {
1035 trait_ref: proj.projection_term.trait_ref(tcx),
1036 polarity: ty::PredicatePolarity::Positive,
1037 });
1038
1039 self.insert_trait_and_projection(
1040 trait_ref,
1041 Some((proj.item_def_id(), proj.term())),
1042 &mut traits,
1043 &mut fn_traits,
1044 );
1045 }
1046 ty::ClauseKind::TypeOutlives(outlives) => {
1047 lifetimes.push(outlives.1);
1048 }
1049 _ => {}
1050 }
1051 }
1052
1053 write!(self, "impl ")?;
1054
1055 let mut first = true;
1056 let paren_needed = fn_traits.len() > 1 || traits.len() > 0 || !has_sized_bound;
1058
1059 for ((bound_args, is_async), entry) in fn_traits {
1060 write!(self, "{}", if first { "" } else { " + " })?;
1061 write!(self, "{}", if paren_needed { "(" } else { "" })?;
1062
1063 let trait_def_id = if is_async {
1064 tcx.async_fn_trait_kind_to_def_id(entry.kind).expect("expected AsyncFn lang items")
1065 } else {
1066 tcx.fn_trait_kind_to_def_id(entry.kind).expect("expected Fn lang items")
1067 };
1068
1069 if let Some(return_ty) = entry.return_ty {
1070 self.wrap_binder(&bound_args, |args, cx| {
1071 define_scoped_cx!(cx);
1072 p!(write("{}", tcx.item_name(trait_def_id)));
1073 p!("(");
1074
1075 for (idx, ty) in args.iter().enumerate() {
1076 if idx > 0 {
1077 p!(", ");
1078 }
1079 p!(print(ty));
1080 }
1081
1082 p!(")");
1083 if let Some(ty) = return_ty.skip_binder().as_type() {
1084 if !ty.is_unit() {
1085 p!(" -> ", print(return_ty));
1086 }
1087 }
1088 p!(write("{}", if paren_needed { ")" } else { "" }));
1089
1090 first = false;
1091 Ok(())
1092 })?;
1093 } else {
1094 traits.insert(
1096 bound_args.map_bound(|args| ty::TraitPredicate {
1097 polarity: ty::PredicatePolarity::Positive,
1098 trait_ref: ty::TraitRef::new(tcx, trait_def_id, [Ty::new_tup(tcx, args)]),
1099 }),
1100 FxIndexMap::default(),
1101 );
1102 }
1103 }
1104
1105 for (trait_pred, assoc_items) in traits {
1107 write!(self, "{}", if first { "" } else { " + " })?;
1108
1109 self.wrap_binder(&trait_pred, |trait_pred, cx| {
1110 define_scoped_cx!(cx);
1111
1112 if trait_pred.polarity == ty::PredicatePolarity::Negative {
1113 p!("!");
1114 }
1115 p!(print(trait_pred.trait_ref.print_only_trait_name()));
1116
1117 let generics = tcx.generics_of(trait_pred.def_id());
1118 let own_args = generics.own_args_no_defaults(tcx, trait_pred.trait_ref.args);
1119
1120 if !own_args.is_empty() || !assoc_items.is_empty() {
1121 let mut first = true;
1122
1123 for ty in own_args {
1124 if first {
1125 p!("<");
1126 first = false;
1127 } else {
1128 p!(", ");
1129 }
1130 p!(print(ty));
1131 }
1132
1133 for (assoc_item_def_id, term) in assoc_items {
1134 let term = if let Some(ty) = term.skip_binder().as_type()
1137 && let ty::Alias(ty::Projection, proj) = ty.kind()
1138 && let Some(assoc) = tcx.opt_associated_item(proj.def_id)
1139 && assoc
1140 .trait_container(tcx)
1141 .is_some_and(|def_id| tcx.is_lang_item(def_id, LangItem::Coroutine))
1142 && assoc.name == rustc_span::sym::Return
1143 {
1144 if let ty::Coroutine(_, args) = args.type_at(0).kind() {
1145 let return_ty = args.as_coroutine().return_ty();
1146 if !return_ty.is_ty_var() {
1147 return_ty.into()
1148 } else {
1149 continue;
1150 }
1151 } else {
1152 continue;
1153 }
1154 } else {
1155 term.skip_binder()
1156 };
1157
1158 if first {
1159 p!("<");
1160 first = false;
1161 } else {
1162 p!(", ");
1163 }
1164
1165 p!(write("{} = ", tcx.associated_item(assoc_item_def_id).name));
1166
1167 match term.unpack() {
1168 TermKind::Ty(ty) => p!(print(ty)),
1169 TermKind::Const(c) => p!(print(c)),
1170 };
1171 }
1172
1173 if !first {
1174 p!(">");
1175 }
1176 }
1177
1178 first = false;
1179 Ok(())
1180 })?;
1181 }
1182
1183 let add_sized = has_sized_bound && (first || has_negative_sized_bound);
1184 let add_maybe_sized = !has_sized_bound && !has_negative_sized_bound;
1185 if add_sized || add_maybe_sized {
1186 if !first {
1187 write!(self, " + ")?;
1188 }
1189 if add_maybe_sized {
1190 write!(self, "?")?;
1191 }
1192 write!(self, "Sized")?;
1193 }
1194
1195 if !with_forced_trimmed_paths() {
1196 for re in lifetimes {
1197 write!(self, " + ")?;
1198 self.print_region(re)?;
1199 }
1200 }
1201
1202 if self.tcx().features().return_type_notation()
1203 && let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. }) =
1204 self.tcx().opt_rpitit_info(def_id)
1205 && let ty::Alias(_, alias_ty) =
1206 self.tcx().fn_sig(fn_def_id).skip_binder().output().skip_binder().kind()
1207 && alias_ty.def_id == def_id
1208 && let generics = self.tcx().generics_of(fn_def_id)
1209 && generics.own_params.iter().all(|param| matches!(param.kind, ty::GenericParamDefKind::Lifetime))
1211 {
1212 let num_args = generics.count();
1213 write!(self, " {{ ")?;
1214 self.print_def_path(fn_def_id, &args[..num_args])?;
1215 write!(self, "(..) }}")?;
1216 }
1217
1218 Ok(())
1219 }
1220
1221 fn insert_trait_and_projection(
1224 &mut self,
1225 trait_pred: ty::PolyTraitPredicate<'tcx>,
1226 proj_ty: Option<(DefId, ty::Binder<'tcx, Term<'tcx>>)>,
1227 traits: &mut FxIndexMap<
1228 ty::PolyTraitPredicate<'tcx>,
1229 FxIndexMap<DefId, ty::Binder<'tcx, Term<'tcx>>>,
1230 >,
1231 fn_traits: &mut FxIndexMap<
1232 (ty::Binder<'tcx, &'tcx ty::List<Ty<'tcx>>>, bool),
1233 OpaqueFnEntry<'tcx>,
1234 >,
1235 ) {
1236 let tcx = self.tcx();
1237 let trait_def_id = trait_pred.def_id();
1238
1239 let fn_trait_and_async = if let Some(kind) = tcx.fn_trait_kind_from_def_id(trait_def_id) {
1240 Some((kind, false))
1241 } else if let Some(kind) = tcx.async_fn_trait_kind_from_def_id(trait_def_id) {
1242 Some((kind, true))
1243 } else {
1244 None
1245 };
1246
1247 if trait_pred.polarity() == ty::PredicatePolarity::Positive
1248 && let Some((kind, is_async)) = fn_trait_and_async
1249 && let ty::Tuple(types) = *trait_pred.skip_binder().trait_ref.args.type_at(1).kind()
1250 {
1251 let entry = fn_traits
1252 .entry((trait_pred.rebind(types), is_async))
1253 .or_insert_with(|| OpaqueFnEntry { kind, return_ty: None });
1254 if kind.extends(entry.kind) {
1255 entry.kind = kind;
1256 }
1257 if let Some((proj_def_id, proj_ty)) = proj_ty
1258 && tcx.item_name(proj_def_id) == sym::Output
1259 {
1260 entry.return_ty = Some(proj_ty);
1261 }
1262 return;
1263 }
1264
1265 traits.entry(trait_pred).or_default().extend(proj_ty);
1267 }
1268
1269 fn pretty_print_inherent_projection(
1270 &mut self,
1271 alias_ty: ty::AliasTerm<'tcx>,
1272 ) -> Result<(), PrintError> {
1273 let def_key = self.tcx().def_key(alias_ty.def_id);
1274 self.path_generic_args(
1275 |cx| {
1276 cx.path_append(
1277 |cx| cx.path_qualified(alias_ty.self_ty(), None),
1278 &def_key.disambiguated_data,
1279 )
1280 },
1281 &alias_ty.args[1..],
1282 )
1283 }
1284
1285 fn ty_infer_name(&self, _: ty::TyVid) -> Option<Symbol> {
1286 None
1287 }
1288
1289 fn const_infer_name(&self, _: ty::ConstVid) -> Option<Symbol> {
1290 None
1291 }
1292
1293 fn pretty_print_dyn_existential(
1294 &mut self,
1295 predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
1296 ) -> Result<(), PrintError> {
1297 let mut first = true;
1299
1300 if let Some(bound_principal) = predicates.principal() {
1301 self.wrap_binder(&bound_principal, |principal, cx| {
1302 define_scoped_cx!(cx);
1303 p!(print_def_path(principal.def_id, &[]));
1304
1305 let mut resugared = false;
1306
1307 let fn_trait_kind = cx.tcx().fn_trait_kind_from_def_id(principal.def_id);
1309 if !cx.should_print_verbose() && fn_trait_kind.is_some() {
1310 if let ty::Tuple(tys) = principal.args.type_at(0).kind() {
1311 let mut projections = predicates.projection_bounds();
1312 if let (Some(proj), None) = (projections.next(), projections.next()) {
1313 p!(pretty_fn_sig(
1314 tys,
1315 false,
1316 proj.skip_binder().term.as_type().expect("Return type was a const")
1317 ));
1318 resugared = true;
1319 }
1320 }
1321 }
1322
1323 if !resugared {
1326 let principal_with_self =
1327 principal.with_self_ty(cx.tcx(), cx.tcx().types.trait_object_dummy_self);
1328
1329 let args = cx
1330 .tcx()
1331 .generics_of(principal_with_self.def_id)
1332 .own_args_no_defaults(cx.tcx(), principal_with_self.args);
1333
1334 let bound_principal_with_self = bound_principal
1335 .with_self_ty(cx.tcx(), cx.tcx().types.trait_object_dummy_self);
1336
1337 let clause: ty::Clause<'tcx> = bound_principal_with_self.upcast(cx.tcx());
1338 let super_projections: Vec<_> = elaborate::elaborate(cx.tcx(), [clause])
1339 .filter_only_self()
1340 .filter_map(|clause| clause.as_projection_clause())
1341 .collect();
1342
1343 let mut projections: Vec<_> = predicates
1344 .projection_bounds()
1345 .filter(|&proj| {
1346 let proj_is_implied = super_projections.iter().any(|&super_proj| {
1348 let super_proj = super_proj.map_bound(|super_proj| {
1349 ty::ExistentialProjection::erase_self_ty(cx.tcx(), super_proj)
1350 });
1351
1352 let proj = cx.tcx().erase_regions(proj);
1357 let proj = cx.tcx().anonymize_bound_vars(proj);
1358 let super_proj = cx.tcx().erase_regions(super_proj);
1359 let super_proj = cx.tcx().anonymize_bound_vars(super_proj);
1360
1361 proj == super_proj
1362 });
1363 !proj_is_implied
1364 })
1365 .map(|proj| {
1366 proj.skip_binder()
1369 })
1370 .collect();
1371
1372 projections
1373 .sort_by_cached_key(|proj| cx.tcx().item_name(proj.def_id).to_string());
1374
1375 if !args.is_empty() || !projections.is_empty() {
1376 p!(generic_delimiters(|cx| {
1377 cx.comma_sep(args.iter().copied())?;
1378 if !args.is_empty() && !projections.is_empty() {
1379 write!(cx, ", ")?;
1380 }
1381 cx.comma_sep(projections.iter().copied())
1382 }));
1383 }
1384 }
1385 Ok(())
1386 })?;
1387
1388 first = false;
1389 }
1390
1391 define_scoped_cx!(self);
1392
1393 let mut auto_traits: Vec<_> = predicates.auto_traits().collect();
1397
1398 auto_traits.sort_by_cached_key(|did| with_no_trimmed_paths!(self.tcx().def_path_str(*did)));
1406
1407 for def_id in auto_traits {
1408 if !first {
1409 p!(" + ");
1410 }
1411 first = false;
1412
1413 p!(print_def_path(def_id, &[]));
1414 }
1415
1416 Ok(())
1417 }
1418
1419 fn pretty_fn_sig(
1420 &mut self,
1421 inputs: &[Ty<'tcx>],
1422 c_variadic: bool,
1423 output: Ty<'tcx>,
1424 ) -> Result<(), PrintError> {
1425 define_scoped_cx!(self);
1426
1427 p!("(", comma_sep(inputs.iter().copied()));
1428 if c_variadic {
1429 if !inputs.is_empty() {
1430 p!(", ");
1431 }
1432 p!("...");
1433 }
1434 p!(")");
1435 if !output.is_unit() {
1436 p!(" -> ", print(output));
1437 }
1438
1439 Ok(())
1440 }
1441
1442 fn pretty_print_const(
1443 &mut self,
1444 ct: ty::Const<'tcx>,
1445 print_ty: bool,
1446 ) -> Result<(), PrintError> {
1447 define_scoped_cx!(self);
1448
1449 if self.should_print_verbose() {
1450 p!(write("{:?}", ct));
1451 return Ok(());
1452 }
1453
1454 match ct.kind() {
1455 ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, args }) => {
1456 match self.tcx().def_kind(def) {
1457 DefKind::Const | DefKind::AssocConst => {
1458 p!(print_value_path(def, args))
1459 }
1460 DefKind::AnonConst => {
1461 if def.is_local()
1462 && let span = self.tcx().def_span(def)
1463 && let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span)
1464 {
1465 p!(write("{}", snip))
1466 } else {
1467 p!(write(
1473 "{}::{}",
1474 self.tcx().crate_name(def.krate),
1475 self.tcx().def_path(def).to_string_no_crate_verbose()
1476 ))
1477 }
1478 }
1479 defkind => bug!("`{:?}` has unexpected defkind {:?}", ct, defkind),
1480 }
1481 }
1482 ty::ConstKind::Infer(infer_ct) => match infer_ct {
1483 ty::InferConst::Var(ct_vid) if let Some(name) = self.const_infer_name(ct_vid) => {
1484 p!(write("{}", name))
1485 }
1486 _ => write!(self, "_")?,
1487 },
1488 ty::ConstKind::Param(ParamConst { name, .. }) => p!(write("{}", name)),
1489 ty::ConstKind::Value(cv) => {
1490 return self.pretty_print_const_valtree(cv, print_ty);
1491 }
1492
1493 ty::ConstKind::Bound(debruijn, bound_var) => {
1494 rustc_type_ir::debug_bound_var(self, debruijn, bound_var)?
1495 }
1496 ty::ConstKind::Placeholder(placeholder) => p!(write("{placeholder:?}")),
1497 ty::ConstKind::Expr(expr) => self.pretty_print_const_expr(expr, print_ty)?,
1500 ty::ConstKind::Error(_) => p!("{{const error}}"),
1501 };
1502 Ok(())
1503 }
1504
1505 fn pretty_print_const_expr(
1506 &mut self,
1507 expr: Expr<'tcx>,
1508 print_ty: bool,
1509 ) -> Result<(), PrintError> {
1510 define_scoped_cx!(self);
1511 match expr.kind {
1512 ty::ExprKind::Binop(op) => {
1513 let (_, _, c1, c2) = expr.binop_args();
1514
1515 let precedence = |binop: crate::mir::BinOp| {
1516 use rustc_ast::util::parser::AssocOp;
1517 AssocOp::from_ast_binop(binop.to_hir_binop()).precedence()
1518 };
1519 let op_precedence = precedence(op);
1520 let formatted_op = op.to_hir_binop().as_str();
1521 let (lhs_parenthesized, rhs_parenthesized) = match (c1.kind(), c2.kind()) {
1522 (
1523 ty::ConstKind::Expr(ty::Expr { kind: ty::ExprKind::Binop(lhs_op), .. }),
1524 ty::ConstKind::Expr(ty::Expr { kind: ty::ExprKind::Binop(rhs_op), .. }),
1525 ) => (precedence(lhs_op) < op_precedence, precedence(rhs_op) < op_precedence),
1526 (
1527 ty::ConstKind::Expr(ty::Expr { kind: ty::ExprKind::Binop(lhs_op), .. }),
1528 ty::ConstKind::Expr(_),
1529 ) => (precedence(lhs_op) < op_precedence, true),
1530 (
1531 ty::ConstKind::Expr(_),
1532 ty::ConstKind::Expr(ty::Expr { kind: ty::ExprKind::Binop(rhs_op), .. }),
1533 ) => (true, precedence(rhs_op) < op_precedence),
1534 (ty::ConstKind::Expr(_), ty::ConstKind::Expr(_)) => (true, true),
1535 (
1536 ty::ConstKind::Expr(ty::Expr { kind: ty::ExprKind::Binop(lhs_op), .. }),
1537 _,
1538 ) => (precedence(lhs_op) < op_precedence, false),
1539 (
1540 _,
1541 ty::ConstKind::Expr(ty::Expr { kind: ty::ExprKind::Binop(rhs_op), .. }),
1542 ) => (false, precedence(rhs_op) < op_precedence),
1543 (ty::ConstKind::Expr(_), _) => (true, false),
1544 (_, ty::ConstKind::Expr(_)) => (false, true),
1545 _ => (false, false),
1546 };
1547
1548 self.maybe_parenthesized(
1549 |this| this.pretty_print_const(c1, print_ty),
1550 lhs_parenthesized,
1551 )?;
1552 p!(write(" {formatted_op} "));
1553 self.maybe_parenthesized(
1554 |this| this.pretty_print_const(c2, print_ty),
1555 rhs_parenthesized,
1556 )?;
1557 }
1558 ty::ExprKind::UnOp(op) => {
1559 let (_, ct) = expr.unop_args();
1560
1561 use crate::mir::UnOp;
1562 let formatted_op = match op {
1563 UnOp::Not => "!",
1564 UnOp::Neg => "-",
1565 UnOp::PtrMetadata => "PtrMetadata",
1566 };
1567 let parenthesized = match ct.kind() {
1568 _ if op == UnOp::PtrMetadata => true,
1569 ty::ConstKind::Expr(ty::Expr { kind: ty::ExprKind::UnOp(c_op), .. }) => {
1570 c_op != op
1571 }
1572 ty::ConstKind::Expr(_) => true,
1573 _ => false,
1574 };
1575 p!(write("{formatted_op}"));
1576 self.maybe_parenthesized(
1577 |this| this.pretty_print_const(ct, print_ty),
1578 parenthesized,
1579 )?
1580 }
1581 ty::ExprKind::FunctionCall => {
1582 let (_, fn_def, fn_args) = expr.call_args();
1583
1584 write!(self, "(")?;
1585 self.pretty_print_const(fn_def, print_ty)?;
1586 p!(")(", comma_sep(fn_args), ")");
1587 }
1588 ty::ExprKind::Cast(kind) => {
1589 let (_, value, to_ty) = expr.cast_args();
1590
1591 use ty::abstract_const::CastKind;
1592 if kind == CastKind::As || (kind == CastKind::Use && self.should_print_verbose()) {
1593 let parenthesized = match value.kind() {
1594 ty::ConstKind::Expr(ty::Expr {
1595 kind: ty::ExprKind::Cast { .. }, ..
1596 }) => false,
1597 ty::ConstKind::Expr(_) => true,
1598 _ => false,
1599 };
1600 self.maybe_parenthesized(
1601 |this| {
1602 this.typed_value(
1603 |this| this.pretty_print_const(value, print_ty),
1604 |this| this.pretty_print_type(to_ty),
1605 " as ",
1606 )
1607 },
1608 parenthesized,
1609 )?;
1610 } else {
1611 self.pretty_print_const(value, print_ty)?
1612 }
1613 }
1614 }
1615 Ok(())
1616 }
1617
1618 fn pretty_print_const_scalar(
1619 &mut self,
1620 scalar: Scalar,
1621 ty: Ty<'tcx>,
1622 ) -> Result<(), PrintError> {
1623 match scalar {
1624 Scalar::Ptr(ptr, _size) => self.pretty_print_const_scalar_ptr(ptr, ty),
1625 Scalar::Int(int) => {
1626 self.pretty_print_const_scalar_int(int, ty, true)
1627 }
1628 }
1629 }
1630
1631 fn pretty_print_const_scalar_ptr(
1632 &mut self,
1633 ptr: Pointer,
1634 ty: Ty<'tcx>,
1635 ) -> Result<(), PrintError> {
1636 define_scoped_cx!(self);
1637
1638 let (prov, offset) = ptr.into_parts();
1639 match ty.kind() {
1640 ty::Ref(_, inner, _) => {
1642 if let ty::Array(elem, ct_len) = inner.kind()
1643 && let ty::Uint(ty::UintTy::U8) = elem.kind()
1644 && let Some(len) = ct_len.try_to_target_usize(self.tcx())
1645 {
1646 match self.tcx().try_get_global_alloc(prov.alloc_id()) {
1647 Some(GlobalAlloc::Memory(alloc)) => {
1648 let range = AllocRange { start: offset, size: Size::from_bytes(len) };
1649 if let Ok(byte_str) =
1650 alloc.inner().get_bytes_strip_provenance(&self.tcx(), range)
1651 {
1652 p!(pretty_print_byte_str(byte_str))
1653 } else {
1654 p!("<too short allocation>")
1655 }
1656 }
1657 Some(GlobalAlloc::Static(def_id)) => {
1659 p!(write("<static({:?})>", def_id))
1660 }
1661 Some(GlobalAlloc::Function { .. }) => p!("<function>"),
1662 Some(GlobalAlloc::VTable(..)) => p!("<vtable>"),
1663 None => p!("<dangling pointer>"),
1664 }
1665 return Ok(());
1666 }
1667 }
1668 ty::FnPtr(..) => {
1669 if let Some(GlobalAlloc::Function { instance, .. }) =
1672 self.tcx().try_get_global_alloc(prov.alloc_id())
1673 {
1674 self.typed_value(
1675 |this| this.print_value_path(instance.def_id(), instance.args),
1676 |this| this.print_type(ty),
1677 " as ",
1678 )?;
1679 return Ok(());
1680 }
1681 }
1682 _ => {}
1683 }
1684 self.pretty_print_const_pointer(ptr, ty)?;
1686 Ok(())
1687 }
1688
1689 fn pretty_print_const_scalar_int(
1690 &mut self,
1691 int: ScalarInt,
1692 ty: Ty<'tcx>,
1693 print_ty: bool,
1694 ) -> Result<(), PrintError> {
1695 define_scoped_cx!(self);
1696
1697 match ty.kind() {
1698 ty::Bool if int == ScalarInt::FALSE => p!("false"),
1700 ty::Bool if int == ScalarInt::TRUE => p!("true"),
1701 ty::Float(fty) => match fty {
1703 ty::FloatTy::F16 => {
1704 let val = Half::try_from(int).unwrap();
1705 p!(write("{}{}f16", val, if val.is_finite() { "" } else { "_" }))
1706 }
1707 ty::FloatTy::F32 => {
1708 let val = Single::try_from(int).unwrap();
1709 p!(write("{}{}f32", val, if val.is_finite() { "" } else { "_" }))
1710 }
1711 ty::FloatTy::F64 => {
1712 let val = Double::try_from(int).unwrap();
1713 p!(write("{}{}f64", val, if val.is_finite() { "" } else { "_" }))
1714 }
1715 ty::FloatTy::F128 => {
1716 let val = Quad::try_from(int).unwrap();
1717 p!(write("{}{}f128", val, if val.is_finite() { "" } else { "_" }))
1718 }
1719 },
1720 ty::Uint(_) | ty::Int(_) => {
1722 let int =
1723 ConstInt::new(int, matches!(ty.kind(), ty::Int(_)), ty.is_ptr_sized_integral());
1724 if print_ty { p!(write("{:#?}", int)) } else { p!(write("{:?}", int)) }
1725 }
1726 ty::Char if char::try_from(int).is_ok() => {
1728 p!(write("{:?}", char::try_from(int).unwrap()))
1729 }
1730 ty::Ref(..) | ty::RawPtr(_, _) | ty::FnPtr(..) => {
1732 let data = int.to_bits(self.tcx().data_layout.pointer_size);
1733 self.typed_value(
1734 |this| {
1735 write!(this, "0x{data:x}")?;
1736 Ok(())
1737 },
1738 |this| this.print_type(ty),
1739 " as ",
1740 )?;
1741 }
1742 ty::Pat(base_ty, pat) if self.tcx().validate_scalar_in_layout(int, ty) => {
1743 self.pretty_print_const_scalar_int(int, *base_ty, print_ty)?;
1744 p!(write(" is {pat:?}"));
1745 }
1746 _ => {
1748 let print = |this: &mut Self| {
1749 if int.size() == Size::ZERO {
1750 write!(this, "transmute(())")?;
1751 } else {
1752 write!(this, "transmute(0x{int:x})")?;
1753 }
1754 Ok(())
1755 };
1756 if print_ty {
1757 self.typed_value(print, |this| this.print_type(ty), ": ")?
1758 } else {
1759 print(self)?
1760 };
1761 }
1762 }
1763 Ok(())
1764 }
1765
1766 fn pretty_print_const_pointer<Prov: Provenance>(
1769 &mut self,
1770 _: Pointer<Prov>,
1771 ty: Ty<'tcx>,
1772 ) -> Result<(), PrintError> {
1773 self.typed_value(
1774 |this| {
1775 this.write_str("&_")?;
1776 Ok(())
1777 },
1778 |this| this.print_type(ty),
1779 ": ",
1780 )
1781 }
1782
1783 fn pretty_print_byte_str(&mut self, byte_str: &'tcx [u8]) -> Result<(), PrintError> {
1784 write!(self, "b\"{}\"", byte_str.escape_ascii())?;
1785 Ok(())
1786 }
1787
1788 fn pretty_print_const_valtree(
1789 &mut self,
1790 cv: ty::Value<'tcx>,
1791 print_ty: bool,
1792 ) -> Result<(), PrintError> {
1793 define_scoped_cx!(self);
1794
1795 if self.should_print_verbose() {
1796 p!(write("ValTree({:?}: ", cv.valtree), print(cv.ty), ")");
1797 return Ok(());
1798 }
1799
1800 let u8_type = self.tcx().types.u8;
1801 match (*cv.valtree, *cv.ty.kind()) {
1802 (ty::ValTreeKind::Branch(_), ty::Ref(_, inner_ty, _)) => match inner_ty.kind() {
1803 ty::Slice(t) if *t == u8_type => {
1804 let bytes = cv.try_to_raw_bytes(self.tcx()).unwrap_or_else(|| {
1805 bug!(
1806 "expected to convert valtree {:?} to raw bytes for type {:?}",
1807 cv.valtree,
1808 t
1809 )
1810 });
1811 return self.pretty_print_byte_str(bytes);
1812 }
1813 ty::Str => {
1814 let bytes = cv.try_to_raw_bytes(self.tcx()).unwrap_or_else(|| {
1815 bug!("expected to convert valtree to raw bytes for type {:?}", cv.ty)
1816 });
1817 p!(write("{:?}", String::from_utf8_lossy(bytes)));
1818 return Ok(());
1819 }
1820 _ => {
1821 let cv = ty::Value { valtree: cv.valtree, ty: inner_ty };
1822 p!("&");
1823 p!(pretty_print_const_valtree(cv, print_ty));
1824 return Ok(());
1825 }
1826 },
1827 (ty::ValTreeKind::Branch(_), ty::Array(t, _)) if t == u8_type => {
1828 let bytes = cv.try_to_raw_bytes(self.tcx()).unwrap_or_else(|| {
1829 bug!("expected to convert valtree to raw bytes for type {:?}", t)
1830 });
1831 p!("*");
1832 p!(pretty_print_byte_str(bytes));
1833 return Ok(());
1834 }
1835 (ty::ValTreeKind::Branch(_), ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) => {
1837 let contents = self.tcx().destructure_const(ty::Const::new_value(
1838 self.tcx(),
1839 cv.valtree,
1840 cv.ty,
1841 ));
1842 let fields = contents.fields.iter().copied();
1843 match *cv.ty.kind() {
1844 ty::Array(..) => {
1845 p!("[", comma_sep(fields), "]");
1846 }
1847 ty::Tuple(..) => {
1848 p!("(", comma_sep(fields));
1849 if contents.fields.len() == 1 {
1850 p!(",");
1851 }
1852 p!(")");
1853 }
1854 ty::Adt(def, _) if def.variants().is_empty() => {
1855 self.typed_value(
1856 |this| {
1857 write!(this, "unreachable()")?;
1858 Ok(())
1859 },
1860 |this| this.print_type(cv.ty),
1861 ": ",
1862 )?;
1863 }
1864 ty::Adt(def, args) => {
1865 let variant_idx =
1866 contents.variant.expect("destructed const of adt without variant idx");
1867 let variant_def = &def.variant(variant_idx);
1868 p!(print_value_path(variant_def.def_id, args));
1869 match variant_def.ctor_kind() {
1870 Some(CtorKind::Const) => {}
1871 Some(CtorKind::Fn) => {
1872 p!("(", comma_sep(fields), ")");
1873 }
1874 None => {
1875 p!(" {{ ");
1876 let mut first = true;
1877 for (field_def, field) in iter::zip(&variant_def.fields, fields) {
1878 if !first {
1879 p!(", ");
1880 }
1881 p!(write("{}: ", field_def.name), print(field));
1882 first = false;
1883 }
1884 p!(" }}");
1885 }
1886 }
1887 }
1888 _ => unreachable!(),
1889 }
1890 return Ok(());
1891 }
1892 (ty::ValTreeKind::Leaf(leaf), ty::Ref(_, inner_ty, _)) => {
1893 p!(write("&"));
1894 return self.pretty_print_const_scalar_int(*leaf, inner_ty, print_ty);
1895 }
1896 (ty::ValTreeKind::Leaf(leaf), _) => {
1897 return self.pretty_print_const_scalar_int(*leaf, cv.ty, print_ty);
1898 }
1899 (_, ty::FnDef(def_id, args)) => {
1900 p!(print_value_path(def_id, args));
1902 return Ok(());
1903 }
1904 _ => {}
1907 }
1908
1909 if cv.valtree.is_zst() {
1911 p!(write("<ZST>"));
1912 } else {
1913 p!(write("{:?}", cv.valtree));
1914 }
1915 if print_ty {
1916 p!(": ", print(cv.ty));
1917 }
1918 Ok(())
1919 }
1920
1921 fn pretty_closure_as_impl(
1922 &mut self,
1923 closure: ty::ClosureArgs<TyCtxt<'tcx>>,
1924 ) -> Result<(), PrintError> {
1925 let sig = closure.sig();
1926 let kind = closure.kind_ty().to_opt_closure_kind().unwrap_or(ty::ClosureKind::Fn);
1927
1928 write!(self, "impl ")?;
1929 self.wrap_binder(&sig, |sig, cx| {
1930 define_scoped_cx!(cx);
1931
1932 p!(write("{kind}("));
1933 for (i, arg) in sig.inputs()[0].tuple_fields().iter().enumerate() {
1934 if i > 0 {
1935 p!(", ");
1936 }
1937 p!(print(arg));
1938 }
1939 p!(")");
1940
1941 if !sig.output().is_unit() {
1942 p!(" -> ", print(sig.output()));
1943 }
1944
1945 Ok(())
1946 })
1947 }
1948
1949 fn pretty_print_bound_constness(
1950 &mut self,
1951 constness: ty::BoundConstness,
1952 ) -> Result<(), PrintError> {
1953 define_scoped_cx!(self);
1954
1955 match constness {
1956 ty::BoundConstness::Const => {
1957 p!("const ");
1958 }
1959 ty::BoundConstness::Maybe => {
1960 p!("~const ");
1961 }
1962 }
1963 Ok(())
1964 }
1965
1966 fn should_print_verbose(&self) -> bool {
1967 self.tcx().sess.verbose_internals()
1968 }
1969}
1970
1971pub(crate) fn pretty_print_const<'tcx>(
1972 c: ty::Const<'tcx>,
1973 fmt: &mut fmt::Formatter<'_>,
1974 print_types: bool,
1975) -> fmt::Result {
1976 ty::tls::with(|tcx| {
1977 let literal = tcx.lift(c).unwrap();
1978 let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS);
1979 cx.print_alloc_ids = true;
1980 cx.pretty_print_const(literal, print_types)?;
1981 fmt.write_str(&cx.into_buffer())?;
1982 Ok(())
1983 })
1984}
1985
1986pub struct FmtPrinter<'a, 'tcx>(Box<FmtPrinterData<'a, 'tcx>>);
1988
1989pub struct FmtPrinterData<'a, 'tcx> {
1990 tcx: TyCtxt<'tcx>,
1991 fmt: String,
1992
1993 empty_path: bool,
1994 in_value: bool,
1995 pub print_alloc_ids: bool,
1996
1997 used_region_names: FxHashSet<Symbol>,
1999
2000 region_index: usize,
2001 binder_depth: usize,
2002 printed_type_count: usize,
2003 type_length_limit: Limit,
2004
2005 pub region_highlight_mode: RegionHighlightMode<'tcx>,
2006
2007 pub ty_infer_name_resolver: Option<Box<dyn Fn(ty::TyVid) -> Option<Symbol> + 'a>>,
2008 pub const_infer_name_resolver: Option<Box<dyn Fn(ty::ConstVid) -> Option<Symbol> + 'a>>,
2009}
2010
2011impl<'a, 'tcx> Deref for FmtPrinter<'a, 'tcx> {
2012 type Target = FmtPrinterData<'a, 'tcx>;
2013 fn deref(&self) -> &Self::Target {
2014 &self.0
2015 }
2016}
2017
2018impl DerefMut for FmtPrinter<'_, '_> {
2019 fn deref_mut(&mut self) -> &mut Self::Target {
2020 &mut self.0
2021 }
2022}
2023
2024impl<'a, 'tcx> FmtPrinter<'a, 'tcx> {
2025 pub fn new(tcx: TyCtxt<'tcx>, ns: Namespace) -> Self {
2026 let limit =
2027 if with_reduced_queries() { Limit::new(1048576) } else { tcx.type_length_limit() };
2028 Self::new_with_limit(tcx, ns, limit)
2029 }
2030
2031 pub fn print_string(
2032 tcx: TyCtxt<'tcx>,
2033 ns: Namespace,
2034 f: impl FnOnce(&mut Self) -> Result<(), PrintError>,
2035 ) -> Result<String, PrintError> {
2036 let mut c = FmtPrinter::new(tcx, ns);
2037 f(&mut c)?;
2038 Ok(c.into_buffer())
2039 }
2040
2041 pub fn new_with_limit(tcx: TyCtxt<'tcx>, ns: Namespace, type_length_limit: Limit) -> Self {
2042 FmtPrinter(Box::new(FmtPrinterData {
2043 tcx,
2044 fmt: String::with_capacity(64),
2047 empty_path: false,
2048 in_value: ns == Namespace::ValueNS,
2049 print_alloc_ids: false,
2050 used_region_names: Default::default(),
2051 region_index: 0,
2052 binder_depth: 0,
2053 printed_type_count: 0,
2054 type_length_limit,
2055 region_highlight_mode: RegionHighlightMode::default(),
2056 ty_infer_name_resolver: None,
2057 const_infer_name_resolver: None,
2058 }))
2059 }
2060
2061 pub fn into_buffer(self) -> String {
2062 self.0.fmt
2063 }
2064}
2065
2066fn guess_def_namespace(tcx: TyCtxt<'_>, def_id: DefId) -> Namespace {
2069 match tcx.def_key(def_id).disambiguated_data.data {
2070 DefPathData::TypeNs(..) | DefPathData::CrateRoot | DefPathData::OpaqueTy => {
2071 Namespace::TypeNS
2072 }
2073
2074 DefPathData::ValueNs(..)
2075 | DefPathData::AnonConst
2076 | DefPathData::Closure
2077 | DefPathData::Ctor => Namespace::ValueNS,
2078
2079 DefPathData::MacroNs(..) => Namespace::MacroNS,
2080
2081 _ => Namespace::TypeNS,
2082 }
2083}
2084
2085impl<'t> TyCtxt<'t> {
2086 pub fn def_path_str(self, def_id: impl IntoQueryParam<DefId>) -> String {
2089 self.def_path_str_with_args(def_id, &[])
2090 }
2091
2092 pub fn def_path_str_with_args(
2093 self,
2094 def_id: impl IntoQueryParam<DefId>,
2095 args: &'t [GenericArg<'t>],
2096 ) -> String {
2097 let def_id = def_id.into_query_param();
2098 let ns = guess_def_namespace(self, def_id);
2099 debug!("def_path_str: def_id={:?}, ns={:?}", def_id, ns);
2100
2101 FmtPrinter::print_string(self, ns, |cx| cx.print_def_path(def_id, args)).unwrap()
2102 }
2103
2104 pub fn value_path_str_with_args(
2105 self,
2106 def_id: impl IntoQueryParam<DefId>,
2107 args: &'t [GenericArg<'t>],
2108 ) -> String {
2109 let def_id = def_id.into_query_param();
2110 let ns = guess_def_namespace(self, def_id);
2111 debug!("value_path_str: def_id={:?}, ns={:?}", def_id, ns);
2112
2113 FmtPrinter::print_string(self, ns, |cx| cx.print_value_path(def_id, args)).unwrap()
2114 }
2115}
2116
2117impl fmt::Write for FmtPrinter<'_, '_> {
2118 fn write_str(&mut self, s: &str) -> fmt::Result {
2119 self.fmt.push_str(s);
2120 Ok(())
2121 }
2122}
2123
2124impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> {
2125 fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
2126 self.tcx
2127 }
2128
2129 fn print_def_path(
2130 &mut self,
2131 def_id: DefId,
2132 args: &'tcx [GenericArg<'tcx>],
2133 ) -> Result<(), PrintError> {
2134 if args.is_empty() {
2135 match self.try_print_trimmed_def_path(def_id)? {
2136 true => return Ok(()),
2137 false => {}
2138 }
2139
2140 match self.try_print_visible_def_path(def_id)? {
2141 true => return Ok(()),
2142 false => {}
2143 }
2144 }
2145
2146 let key = self.tcx.def_key(def_id);
2147 if let DefPathData::Impl = key.disambiguated_data.data {
2148 let use_types = !def_id.is_local() || {
2151 let force_no_types = with_forced_impl_filename_line();
2153 !force_no_types
2154 };
2155
2156 if !use_types {
2157 let parent_def_id = DefId { index: key.parent.unwrap(), ..def_id };
2161 let span = self.tcx.def_span(def_id);
2162
2163 self.print_def_path(parent_def_id, &[])?;
2164
2165 if !self.empty_path {
2168 write!(self, "::")?;
2169 }
2170 write!(
2171 self,
2172 "<impl at {}>",
2173 self.tcx.sess.source_map().span_to_embeddable_string(span)
2176 )?;
2177 self.empty_path = false;
2178
2179 return Ok(());
2180 }
2181 }
2182
2183 self.default_print_def_path(def_id, args)
2184 }
2185
2186 fn print_region(&mut self, region: ty::Region<'tcx>) -> Result<(), PrintError> {
2187 self.pretty_print_region(region)
2188 }
2189
2190 fn print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> {
2191 match ty.kind() {
2192 ty::Tuple(tys) if tys.len() == 0 && self.should_truncate() => {
2193 self.printed_type_count += 1;
2195 self.pretty_print_type(ty)
2196 }
2197 ty::Adt(..)
2198 | ty::Foreign(_)
2199 | ty::Pat(..)
2200 | ty::RawPtr(..)
2201 | ty::Ref(..)
2202 | ty::FnDef(..)
2203 | ty::FnPtr(..)
2204 | ty::UnsafeBinder(..)
2205 | ty::Dynamic(..)
2206 | ty::Closure(..)
2207 | ty::CoroutineClosure(..)
2208 | ty::Coroutine(..)
2209 | ty::CoroutineWitness(..)
2210 | ty::Tuple(_)
2211 | ty::Alias(..)
2212 | ty::Param(_)
2213 | ty::Bound(..)
2214 | ty::Placeholder(_)
2215 | ty::Error(_)
2216 if self.should_truncate() =>
2217 {
2218 write!(self, "...")?;
2221 Ok(())
2222 }
2223 _ => {
2224 self.printed_type_count += 1;
2225 self.pretty_print_type(ty)
2226 }
2227 }
2228 }
2229
2230 fn should_truncate(&mut self) -> bool {
2231 !self.type_length_limit.value_within_limit(self.printed_type_count)
2232 }
2233
2234 fn print_dyn_existential(
2235 &mut self,
2236 predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
2237 ) -> Result<(), PrintError> {
2238 self.pretty_print_dyn_existential(predicates)
2239 }
2240
2241 fn print_const(&mut self, ct: ty::Const<'tcx>) -> Result<(), PrintError> {
2242 self.pretty_print_const(ct, false)
2243 }
2244
2245 fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
2246 self.empty_path = true;
2247 if cnum == LOCAL_CRATE {
2248 if self.tcx.sess.at_least_rust_2018() {
2249 if with_crate_prefix() {
2251 write!(self, "{}", kw::Crate)?;
2252 self.empty_path = false;
2253 }
2254 }
2255 } else {
2256 write!(self, "{}", self.tcx.crate_name(cnum))?;
2257 self.empty_path = false;
2258 }
2259 Ok(())
2260 }
2261
2262 fn path_qualified(
2263 &mut self,
2264 self_ty: Ty<'tcx>,
2265 trait_ref: Option<ty::TraitRef<'tcx>>,
2266 ) -> Result<(), PrintError> {
2267 self.pretty_path_qualified(self_ty, trait_ref)?;
2268 self.empty_path = false;
2269 Ok(())
2270 }
2271
2272 fn path_append_impl(
2273 &mut self,
2274 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
2275 _disambiguated_data: &DisambiguatedDefPathData,
2276 self_ty: Ty<'tcx>,
2277 trait_ref: Option<ty::TraitRef<'tcx>>,
2278 ) -> Result<(), PrintError> {
2279 self.pretty_path_append_impl(
2280 |cx| {
2281 print_prefix(cx)?;
2282 if !cx.empty_path {
2283 write!(cx, "::")?;
2284 }
2285
2286 Ok(())
2287 },
2288 self_ty,
2289 trait_ref,
2290 )?;
2291 self.empty_path = false;
2292 Ok(())
2293 }
2294
2295 fn path_append(
2296 &mut self,
2297 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
2298 disambiguated_data: &DisambiguatedDefPathData,
2299 ) -> Result<(), PrintError> {
2300 print_prefix(self)?;
2301
2302 if let DefPathData::ForeignMod | DefPathData::Ctor = disambiguated_data.data {
2304 return Ok(());
2305 }
2306
2307 let name = disambiguated_data.data.name();
2308 if !self.empty_path {
2309 write!(self, "::")?;
2310 }
2311
2312 if let DefPathDataName::Named(name) = name {
2313 if Ident::with_dummy_span(name).is_raw_guess() {
2314 write!(self, "r#")?;
2315 }
2316 }
2317
2318 let verbose = self.should_print_verbose();
2319 disambiguated_data.fmt_maybe_verbose(self, verbose)?;
2320
2321 self.empty_path = false;
2322
2323 Ok(())
2324 }
2325
2326 fn path_generic_args(
2327 &mut self,
2328 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
2329 args: &[GenericArg<'tcx>],
2330 ) -> Result<(), PrintError> {
2331 print_prefix(self)?;
2332
2333 if !args.is_empty() {
2334 if self.in_value {
2335 write!(self, "::")?;
2336 }
2337 self.generic_delimiters(|cx| cx.comma_sep(args.iter().copied()))
2338 } else {
2339 Ok(())
2340 }
2341 }
2342}
2343
2344impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> {
2345 fn ty_infer_name(&self, id: ty::TyVid) -> Option<Symbol> {
2346 self.0.ty_infer_name_resolver.as_ref().and_then(|func| func(id))
2347 }
2348
2349 fn reset_type_limit(&mut self) {
2350 self.printed_type_count = 0;
2351 }
2352
2353 fn const_infer_name(&self, id: ty::ConstVid) -> Option<Symbol> {
2354 self.0.const_infer_name_resolver.as_ref().and_then(|func| func(id))
2355 }
2356
2357 fn print_value_path(
2358 &mut self,
2359 def_id: DefId,
2360 args: &'tcx [GenericArg<'tcx>],
2361 ) -> Result<(), PrintError> {
2362 let was_in_value = std::mem::replace(&mut self.in_value, true);
2363 self.print_def_path(def_id, args)?;
2364 self.in_value = was_in_value;
2365
2366 Ok(())
2367 }
2368
2369 fn in_binder<T>(&mut self, value: &ty::Binder<'tcx, T>) -> Result<(), PrintError>
2370 where
2371 T: Print<'tcx, Self> + TypeFoldable<TyCtxt<'tcx>>,
2372 {
2373 self.pretty_in_binder(value)
2374 }
2375
2376 fn wrap_binder<T, C: FnOnce(&T, &mut Self) -> Result<(), PrintError>>(
2377 &mut self,
2378 value: &ty::Binder<'tcx, T>,
2379 f: C,
2380 ) -> Result<(), PrintError>
2381 where
2382 T: Print<'tcx, Self> + TypeFoldable<TyCtxt<'tcx>>,
2383 {
2384 self.pretty_wrap_binder(value, f)
2385 }
2386
2387 fn typed_value(
2388 &mut self,
2389 f: impl FnOnce(&mut Self) -> Result<(), PrintError>,
2390 t: impl FnOnce(&mut Self) -> Result<(), PrintError>,
2391 conversion: &str,
2392 ) -> Result<(), PrintError> {
2393 self.write_str("{")?;
2394 f(self)?;
2395 self.write_str(conversion)?;
2396 let was_in_value = std::mem::replace(&mut self.in_value, false);
2397 t(self)?;
2398 self.in_value = was_in_value;
2399 self.write_str("}")?;
2400 Ok(())
2401 }
2402
2403 fn generic_delimiters(
2404 &mut self,
2405 f: impl FnOnce(&mut Self) -> Result<(), PrintError>,
2406 ) -> Result<(), PrintError> {
2407 write!(self, "<")?;
2408
2409 let was_in_value = std::mem::replace(&mut self.in_value, false);
2410 f(self)?;
2411 self.in_value = was_in_value;
2412
2413 write!(self, ">")?;
2414 Ok(())
2415 }
2416
2417 fn should_print_region(&self, region: ty::Region<'tcx>) -> bool {
2418 let highlight = self.region_highlight_mode;
2419 if highlight.region_highlighted(region).is_some() {
2420 return true;
2421 }
2422
2423 if self.should_print_verbose() {
2424 return true;
2425 }
2426
2427 if with_forced_trimmed_paths() {
2428 return false;
2429 }
2430
2431 let identify_regions = self.tcx.sess.opts.unstable_opts.identify_regions;
2432
2433 match *region {
2434 ty::ReEarlyParam(ref data) => data.has_name(),
2435
2436 ty::ReLateParam(ty::LateParamRegion { kind, .. }) => kind.is_named(),
2437 ty::ReBound(_, ty::BoundRegion { kind: br, .. })
2438 | ty::RePlaceholder(ty::Placeholder {
2439 bound: ty::BoundRegion { kind: br, .. }, ..
2440 }) => {
2441 if br.is_named() {
2442 return true;
2443 }
2444
2445 if let Some((region, _)) = highlight.highlight_bound_region {
2446 if br == region {
2447 return true;
2448 }
2449 }
2450
2451 false
2452 }
2453
2454 ty::ReVar(_) if identify_regions => true,
2455
2456 ty::ReVar(_) | ty::ReErased | ty::ReError(_) => false,
2457
2458 ty::ReStatic => true,
2459 }
2460 }
2461
2462 fn pretty_print_const_pointer<Prov: Provenance>(
2463 &mut self,
2464 p: Pointer<Prov>,
2465 ty: Ty<'tcx>,
2466 ) -> Result<(), PrintError> {
2467 let print = |this: &mut Self| {
2468 define_scoped_cx!(this);
2469 if this.print_alloc_ids {
2470 p!(write("{:?}", p));
2471 } else {
2472 p!("&_");
2473 }
2474 Ok(())
2475 };
2476 self.typed_value(print, |this| this.print_type(ty), ": ")
2477 }
2478}
2479
2480impl<'tcx> FmtPrinter<'_, 'tcx> {
2482 pub fn pretty_print_region(&mut self, region: ty::Region<'tcx>) -> Result<(), fmt::Error> {
2483 define_scoped_cx!(self);
2484
2485 let highlight = self.region_highlight_mode;
2487 if let Some(n) = highlight.region_highlighted(region) {
2488 p!(write("'{}", n));
2489 return Ok(());
2490 }
2491
2492 if self.should_print_verbose() {
2493 p!(write("{:?}", region));
2494 return Ok(());
2495 }
2496
2497 let identify_regions = self.tcx.sess.opts.unstable_opts.identify_regions;
2498
2499 match *region {
2504 ty::ReEarlyParam(ref data) => {
2505 if data.name != kw::Empty {
2506 p!(write("{}", data.name));
2507 return Ok(());
2508 }
2509 }
2510 ty::ReLateParam(ty::LateParamRegion { kind, .. }) => {
2511 if let Some(name) = kind.get_name() {
2512 p!(write("{}", name));
2513 return Ok(());
2514 }
2515 }
2516 ty::ReBound(_, ty::BoundRegion { kind: br, .. })
2517 | ty::RePlaceholder(ty::Placeholder {
2518 bound: ty::BoundRegion { kind: br, .. }, ..
2519 }) => {
2520 if let ty::BoundRegionKind::Named(_, name) = br
2521 && br.is_named()
2522 {
2523 p!(write("{}", name));
2524 return Ok(());
2525 }
2526
2527 if let Some((region, counter)) = highlight.highlight_bound_region {
2528 if br == region {
2529 p!(write("'{}", counter));
2530 return Ok(());
2531 }
2532 }
2533 }
2534 ty::ReVar(region_vid) if identify_regions => {
2535 p!(write("{:?}", region_vid));
2536 return Ok(());
2537 }
2538 ty::ReVar(_) => {}
2539 ty::ReErased => {}
2540 ty::ReError(_) => {}
2541 ty::ReStatic => {
2542 p!("'static");
2543 return Ok(());
2544 }
2545 }
2546
2547 p!("'_");
2548
2549 Ok(())
2550 }
2551}
2552
2553struct RegionFolder<'a, 'tcx> {
2555 tcx: TyCtxt<'tcx>,
2556 current_index: ty::DebruijnIndex,
2557 region_map: UnordMap<ty::BoundRegion, ty::Region<'tcx>>,
2558 name: &'a mut (
2559 dyn FnMut(
2560 Option<ty::DebruijnIndex>, ty::DebruijnIndex, ty::BoundRegion,
2563 ) -> ty::Region<'tcx>
2564 + 'a
2565 ),
2566}
2567
2568impl<'a, 'tcx> ty::TypeFolder<TyCtxt<'tcx>> for RegionFolder<'a, 'tcx> {
2569 fn cx(&self) -> TyCtxt<'tcx> {
2570 self.tcx
2571 }
2572
2573 fn fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
2574 &mut self,
2575 t: ty::Binder<'tcx, T>,
2576 ) -> ty::Binder<'tcx, T> {
2577 self.current_index.shift_in(1);
2578 let t = t.super_fold_with(self);
2579 self.current_index.shift_out(1);
2580 t
2581 }
2582
2583 fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
2584 match *t.kind() {
2585 _ if t.has_vars_bound_at_or_above(self.current_index) || t.has_placeholders() => {
2586 return t.super_fold_with(self);
2587 }
2588 _ => {}
2589 }
2590 t
2591 }
2592
2593 fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
2594 let name = &mut self.name;
2595 let region = match *r {
2596 ty::ReBound(db, br) if db >= self.current_index => {
2597 *self.region_map.entry(br).or_insert_with(|| name(Some(db), self.current_index, br))
2598 }
2599 ty::RePlaceholder(ty::PlaceholderRegion {
2600 bound: ty::BoundRegion { kind, .. },
2601 ..
2602 }) => {
2603 match kind {
2606 ty::BoundRegionKind::Anon | ty::BoundRegionKind::ClosureEnv => r,
2607 _ => {
2608 let br = ty::BoundRegion { var: ty::BoundVar::ZERO, kind };
2610 *self
2611 .region_map
2612 .entry(br)
2613 .or_insert_with(|| name(None, self.current_index, br))
2614 }
2615 }
2616 }
2617 _ => return r,
2618 };
2619 if let ty::ReBound(debruijn1, br) = *region {
2620 assert_eq!(debruijn1, ty::INNERMOST);
2621 ty::Region::new_bound(self.tcx, self.current_index, br)
2622 } else {
2623 region
2624 }
2625 }
2626}
2627
2628impl<'tcx> FmtPrinter<'_, 'tcx> {
2631 pub fn name_all_regions<T>(
2632 &mut self,
2633 value: &ty::Binder<'tcx, T>,
2634 ) -> Result<(T, UnordMap<ty::BoundRegion, ty::Region<'tcx>>), fmt::Error>
2635 where
2636 T: Print<'tcx, Self> + TypeFoldable<TyCtxt<'tcx>>,
2637 {
2638 fn name_by_region_index(
2639 index: usize,
2640 available_names: &mut Vec<Symbol>,
2641 num_available: usize,
2642 ) -> Symbol {
2643 if let Some(name) = available_names.pop() {
2644 name
2645 } else {
2646 Symbol::intern(&format!("'z{}", index - num_available))
2647 }
2648 }
2649
2650 debug!("name_all_regions");
2651
2652 if self.binder_depth == 0 {
2658 self.prepare_region_info(value);
2659 }
2660
2661 debug!("self.used_region_names: {:?}", self.used_region_names);
2662
2663 let mut empty = true;
2664 let mut start_or_continue = |cx: &mut Self, start: &str, cont: &str| {
2665 let w = if empty {
2666 empty = false;
2667 start
2668 } else {
2669 cont
2670 };
2671 let _ = write!(cx, "{w}");
2672 };
2673 let do_continue = |cx: &mut Self, cont: Symbol| {
2674 let _ = write!(cx, "{cont}");
2675 };
2676
2677 let possible_names = ('a'..='z').rev().map(|s| Symbol::intern(&format!("'{s}")));
2678
2679 let mut available_names = possible_names
2680 .filter(|name| !self.used_region_names.contains(name))
2681 .collect::<Vec<_>>();
2682 debug!(?available_names);
2683 let num_available = available_names.len();
2684
2685 let mut region_index = self.region_index;
2686 let mut next_name = |this: &Self| {
2687 let mut name;
2688
2689 loop {
2690 name = name_by_region_index(region_index, &mut available_names, num_available);
2691 region_index += 1;
2692
2693 if !this.used_region_names.contains(&name) {
2694 break;
2695 }
2696 }
2697
2698 name
2699 };
2700
2701 let (new_value, map) = if self.should_print_verbose() {
2706 for var in value.bound_vars().iter() {
2707 start_or_continue(self, "for<", ", ");
2708 write!(self, "{var:?}")?;
2709 }
2710 start_or_continue(self, "", "> ");
2711 (value.clone().skip_binder(), UnordMap::default())
2712 } else {
2713 let tcx = self.tcx;
2714
2715 let trim_path = with_forced_trimmed_paths();
2716 let mut name = |lifetime_idx: Option<ty::DebruijnIndex>,
2722 binder_level_idx: ty::DebruijnIndex,
2723 br: ty::BoundRegion| {
2724 let (name, kind) = match br.kind {
2725 ty::BoundRegionKind::Anon | ty::BoundRegionKind::ClosureEnv => {
2726 let name = next_name(self);
2727
2728 if let Some(lt_idx) = lifetime_idx {
2729 if lt_idx > binder_level_idx {
2730 let kind =
2731 ty::BoundRegionKind::Named(CRATE_DEF_ID.to_def_id(), name);
2732 return ty::Region::new_bound(
2733 tcx,
2734 ty::INNERMOST,
2735 ty::BoundRegion { var: br.var, kind },
2736 );
2737 }
2738 }
2739
2740 (name, ty::BoundRegionKind::Named(CRATE_DEF_ID.to_def_id(), name))
2741 }
2742 ty::BoundRegionKind::Named(def_id, kw::UnderscoreLifetime | kw::Empty) => {
2743 let name = next_name(self);
2744
2745 if let Some(lt_idx) = lifetime_idx {
2746 if lt_idx > binder_level_idx {
2747 let kind = ty::BoundRegionKind::Named(def_id, name);
2748 return ty::Region::new_bound(
2749 tcx,
2750 ty::INNERMOST,
2751 ty::BoundRegion { var: br.var, kind },
2752 );
2753 }
2754 }
2755
2756 (name, ty::BoundRegionKind::Named(def_id, name))
2757 }
2758 ty::BoundRegionKind::Named(_, name) => {
2759 if let Some(lt_idx) = lifetime_idx {
2760 if lt_idx > binder_level_idx {
2761 let kind = br.kind;
2762 return ty::Region::new_bound(
2763 tcx,
2764 ty::INNERMOST,
2765 ty::BoundRegion { var: br.var, kind },
2766 );
2767 }
2768 }
2769
2770 (name, br.kind)
2771 }
2772 };
2773
2774 if !trim_path {
2775 start_or_continue(self, "for<", ", ");
2776 do_continue(self, name);
2777 }
2778 ty::Region::new_bound(tcx, ty::INNERMOST, ty::BoundRegion { var: br.var, kind })
2779 };
2780 let mut folder = RegionFolder {
2781 tcx,
2782 current_index: ty::INNERMOST,
2783 name: &mut name,
2784 region_map: UnordMap::default(),
2785 };
2786 let new_value = value.clone().skip_binder().fold_with(&mut folder);
2787 let region_map = folder.region_map;
2788 if !trim_path {
2789 start_or_continue(self, "", "> ");
2790 }
2791 (new_value, region_map)
2792 };
2793
2794 self.binder_depth += 1;
2795 self.region_index = region_index;
2796 Ok((new_value, map))
2797 }
2798
2799 pub fn pretty_in_binder<T>(&mut self, value: &ty::Binder<'tcx, T>) -> Result<(), fmt::Error>
2800 where
2801 T: Print<'tcx, Self> + TypeFoldable<TyCtxt<'tcx>>,
2802 {
2803 let old_region_index = self.region_index;
2804 let (new_value, _) = self.name_all_regions(value)?;
2805 new_value.print(self)?;
2806 self.region_index = old_region_index;
2807 self.binder_depth -= 1;
2808 Ok(())
2809 }
2810
2811 pub fn pretty_wrap_binder<T, C: FnOnce(&T, &mut Self) -> Result<(), fmt::Error>>(
2812 &mut self,
2813 value: &ty::Binder<'tcx, T>,
2814 f: C,
2815 ) -> Result<(), fmt::Error>
2816 where
2817 T: Print<'tcx, Self> + TypeFoldable<TyCtxt<'tcx>>,
2818 {
2819 let old_region_index = self.region_index;
2820 let (new_value, _) = self.name_all_regions(value)?;
2821 f(&new_value, self)?;
2822 self.region_index = old_region_index;
2823 self.binder_depth -= 1;
2824 Ok(())
2825 }
2826
2827 fn prepare_region_info<T>(&mut self, value: &ty::Binder<'tcx, T>)
2828 where
2829 T: TypeVisitable<TyCtxt<'tcx>>,
2830 {
2831 struct RegionNameCollector<'tcx> {
2832 used_region_names: FxHashSet<Symbol>,
2833 type_collector: SsoHashSet<Ty<'tcx>>,
2834 }
2835
2836 impl<'tcx> RegionNameCollector<'tcx> {
2837 fn new() -> Self {
2838 RegionNameCollector {
2839 used_region_names: Default::default(),
2840 type_collector: SsoHashSet::new(),
2841 }
2842 }
2843 }
2844
2845 impl<'tcx> ty::visit::TypeVisitor<TyCtxt<'tcx>> for RegionNameCollector<'tcx> {
2846 fn visit_region(&mut self, r: ty::Region<'tcx>) {
2847 trace!("address: {:p}", r.0.0);
2848
2849 if let Some(name) = r.get_name() {
2853 self.used_region_names.insert(name);
2854 }
2855 }
2856
2857 fn visit_ty(&mut self, ty: Ty<'tcx>) {
2860 let not_previously_inserted = self.type_collector.insert(ty);
2861 if not_previously_inserted {
2862 ty.super_visit_with(self)
2863 }
2864 }
2865 }
2866
2867 let mut collector = RegionNameCollector::new();
2868 value.visit_with(&mut collector);
2869 self.used_region_names = collector.used_region_names;
2870 self.region_index = 0;
2871 }
2872}
2873
2874impl<'tcx, T, P: PrettyPrinter<'tcx>> Print<'tcx, P> for ty::Binder<'tcx, T>
2875where
2876 T: Print<'tcx, P> + TypeFoldable<TyCtxt<'tcx>>,
2877{
2878 fn print(&self, cx: &mut P) -> Result<(), PrintError> {
2879 cx.in_binder(self)
2880 }
2881}
2882
2883impl<'tcx, T, P: PrettyPrinter<'tcx>> Print<'tcx, P> for ty::OutlivesPredicate<'tcx, T>
2884where
2885 T: Print<'tcx, P>,
2886{
2887 fn print(&self, cx: &mut P) -> Result<(), PrintError> {
2888 define_scoped_cx!(cx);
2889 p!(print(self.0), ": ", print(self.1));
2890 Ok(())
2891 }
2892}
2893
2894#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)]
2898pub struct TraitRefPrintOnlyTraitPath<'tcx>(ty::TraitRef<'tcx>);
2899
2900impl<'tcx> rustc_errors::IntoDiagArg for TraitRefPrintOnlyTraitPath<'tcx> {
2901 fn into_diag_arg(self) -> rustc_errors::DiagArgValue {
2902 self.to_string().into_diag_arg()
2903 }
2904}
2905
2906impl<'tcx> fmt::Debug for TraitRefPrintOnlyTraitPath<'tcx> {
2907 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2908 fmt::Display::fmt(self, f)
2909 }
2910}
2911
2912#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)]
2915pub struct TraitRefPrintSugared<'tcx>(ty::TraitRef<'tcx>);
2916
2917impl<'tcx> rustc_errors::IntoDiagArg for TraitRefPrintSugared<'tcx> {
2918 fn into_diag_arg(self) -> rustc_errors::DiagArgValue {
2919 self.to_string().into_diag_arg()
2920 }
2921}
2922
2923impl<'tcx> fmt::Debug for TraitRefPrintSugared<'tcx> {
2924 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2925 fmt::Display::fmt(self, f)
2926 }
2927}
2928
2929#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)]
2933pub struct TraitRefPrintOnlyTraitName<'tcx>(ty::TraitRef<'tcx>);
2934
2935impl<'tcx> fmt::Debug for TraitRefPrintOnlyTraitName<'tcx> {
2936 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2937 fmt::Display::fmt(self, f)
2938 }
2939}
2940
2941#[extension(pub trait PrintTraitRefExt<'tcx>)]
2942impl<'tcx> ty::TraitRef<'tcx> {
2943 fn print_only_trait_path(self) -> TraitRefPrintOnlyTraitPath<'tcx> {
2944 TraitRefPrintOnlyTraitPath(self)
2945 }
2946
2947 fn print_trait_sugared(self) -> TraitRefPrintSugared<'tcx> {
2948 TraitRefPrintSugared(self)
2949 }
2950
2951 fn print_only_trait_name(self) -> TraitRefPrintOnlyTraitName<'tcx> {
2952 TraitRefPrintOnlyTraitName(self)
2953 }
2954}
2955
2956#[extension(pub trait PrintPolyTraitRefExt<'tcx>)]
2957impl<'tcx> ty::Binder<'tcx, ty::TraitRef<'tcx>> {
2958 fn print_only_trait_path(self) -> ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>> {
2959 self.map_bound(|tr| tr.print_only_trait_path())
2960 }
2961
2962 fn print_trait_sugared(self) -> ty::Binder<'tcx, TraitRefPrintSugared<'tcx>> {
2963 self.map_bound(|tr| tr.print_trait_sugared())
2964 }
2965}
2966
2967#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)]
2968pub struct TraitPredPrintModifiersAndPath<'tcx>(ty::TraitPredicate<'tcx>);
2969
2970impl<'tcx> fmt::Debug for TraitPredPrintModifiersAndPath<'tcx> {
2971 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2972 fmt::Display::fmt(self, f)
2973 }
2974}
2975
2976#[extension(pub trait PrintTraitPredicateExt<'tcx>)]
2977impl<'tcx> ty::TraitPredicate<'tcx> {
2978 fn print_modifiers_and_trait_path(self) -> TraitPredPrintModifiersAndPath<'tcx> {
2979 TraitPredPrintModifiersAndPath(self)
2980 }
2981}
2982
2983#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift, Hash)]
2984pub struct TraitPredPrintWithBoundConstness<'tcx>(
2985 ty::TraitPredicate<'tcx>,
2986 Option<ty::BoundConstness>,
2987);
2988
2989impl<'tcx> fmt::Debug for TraitPredPrintWithBoundConstness<'tcx> {
2990 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2991 fmt::Display::fmt(self, f)
2992 }
2993}
2994
2995#[extension(pub trait PrintPolyTraitPredicateExt<'tcx>)]
2996impl<'tcx> ty::PolyTraitPredicate<'tcx> {
2997 fn print_modifiers_and_trait_path(
2998 self,
2999 ) -> ty::Binder<'tcx, TraitPredPrintModifiersAndPath<'tcx>> {
3000 self.map_bound(TraitPredPrintModifiersAndPath)
3001 }
3002
3003 fn print_with_bound_constness(
3004 self,
3005 constness: Option<ty::BoundConstness>,
3006 ) -> ty::Binder<'tcx, TraitPredPrintWithBoundConstness<'tcx>> {
3007 self.map_bound(|trait_pred| TraitPredPrintWithBoundConstness(trait_pred, constness))
3008 }
3009}
3010
3011#[derive(Debug, Copy, Clone, Lift)]
3012pub struct PrintClosureAsImpl<'tcx> {
3013 pub closure: ty::ClosureArgs<TyCtxt<'tcx>>,
3014}
3015
3016macro_rules! forward_display_to_print {
3017 ($($ty:ty),+) => {
3018 $(#[allow(unused_lifetimes)] impl<'tcx> fmt::Display for $ty {
3020 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3021 ty::tls::with(|tcx| {
3022 let mut cx = FmtPrinter::new(tcx, Namespace::TypeNS);
3023 tcx.lift(*self)
3024 .expect("could not lift for printing")
3025 .print(&mut cx)?;
3026 f.write_str(&cx.into_buffer())?;
3027 Ok(())
3028 })
3029 }
3030 })+
3031 };
3032}
3033
3034macro_rules! define_print {
3035 (($self:ident, $cx:ident): $($ty:ty $print:block)+) => {
3036 $(impl<'tcx, P: PrettyPrinter<'tcx>> Print<'tcx, P> for $ty {
3037 fn print(&$self, $cx: &mut P) -> Result<(), PrintError> {
3038 define_scoped_cx!($cx);
3039 let _: () = $print;
3040 Ok(())
3041 }
3042 })+
3043 };
3044}
3045
3046macro_rules! define_print_and_forward_display {
3047 (($self:ident, $cx:ident): $($ty:ty $print:block)+) => {
3048 define_print!(($self, $cx): $($ty $print)*);
3049 forward_display_to_print!($($ty),+);
3050 };
3051}
3052
3053forward_display_to_print! {
3054 ty::Region<'tcx>,
3055 Ty<'tcx>,
3056 &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
3057 ty::Const<'tcx>
3058}
3059
3060define_print! {
3061 (self, cx):
3062
3063 ty::FnSig<'tcx> {
3064 p!(write("{}", self.safety.prefix_str()));
3065
3066 if self.abi != ExternAbi::Rust {
3067 p!(write("extern {} ", self.abi));
3068 }
3069
3070 p!("fn", pretty_fn_sig(self.inputs(), self.c_variadic, self.output()));
3071 }
3072
3073 ty::TraitRef<'tcx> {
3074 p!(write("<{} as {}>", self.self_ty(), self.print_only_trait_path()))
3075 }
3076
3077 ty::AliasTy<'tcx> {
3078 let alias_term: ty::AliasTerm<'tcx> = (*self).into();
3079 p!(print(alias_term))
3080 }
3081
3082 ty::AliasTerm<'tcx> {
3083 match self.kind(cx.tcx()) {
3084 ty::AliasTermKind::InherentTy => p!(pretty_print_inherent_projection(*self)),
3085 ty::AliasTermKind::ProjectionTy
3086 | ty::AliasTermKind::WeakTy
3087 | ty::AliasTermKind::OpaqueTy
3088 | ty::AliasTermKind::UnevaluatedConst
3089 | ty::AliasTermKind::ProjectionConst => {
3090 if !(cx.should_print_verbose() || with_reduced_queries())
3094 && cx.tcx().is_impl_trait_in_trait(self.def_id)
3095 {
3096 return cx.pretty_print_opaque_impl_type(self.def_id, self.args);
3097 } else {
3098 p!(print_def_path(self.def_id, self.args));
3099 }
3100 }
3101 }
3102 }
3103
3104 ty::TraitPredicate<'tcx> {
3105 p!(print(self.trait_ref.self_ty()), ": ");
3106 if let ty::PredicatePolarity::Negative = self.polarity {
3107 p!("!");
3108 }
3109 p!(print(self.trait_ref.print_trait_sugared()))
3110 }
3111
3112 ty::HostEffectPredicate<'tcx> {
3113 let constness = match self.constness {
3114 ty::BoundConstness::Const => { "const" }
3115 ty::BoundConstness::Maybe => { "~const" }
3116 };
3117 p!(print(self.trait_ref.self_ty()), ": {constness} ");
3118 p!(print(self.trait_ref.print_trait_sugared()))
3119 }
3120
3121 ty::TypeAndMut<'tcx> {
3122 p!(write("{}", self.mutbl.prefix_str()), print(self.ty))
3123 }
3124
3125 ty::ClauseKind<'tcx> {
3126 match *self {
3127 ty::ClauseKind::Trait(ref data) => {
3128 p!(print(data))
3129 }
3130 ty::ClauseKind::RegionOutlives(predicate) => p!(print(predicate)),
3131 ty::ClauseKind::TypeOutlives(predicate) => p!(print(predicate)),
3132 ty::ClauseKind::Projection(predicate) => p!(print(predicate)),
3133 ty::ClauseKind::HostEffect(predicate) => p!(print(predicate)),
3134 ty::ClauseKind::ConstArgHasType(ct, ty) => {
3135 p!("the constant `", print(ct), "` has type `", print(ty), "`")
3136 },
3137 ty::ClauseKind::WellFormed(arg) => p!(print(arg), " well-formed"),
3138 ty::ClauseKind::ConstEvaluatable(ct) => {
3139 p!("the constant `", print(ct), "` can be evaluated")
3140 }
3141 }
3142 }
3143
3144 ty::PredicateKind<'tcx> {
3145 match *self {
3146 ty::PredicateKind::Clause(data) => {
3147 p!(print(data))
3148 }
3149 ty::PredicateKind::Subtype(predicate) => p!(print(predicate)),
3150 ty::PredicateKind::Coerce(predicate) => p!(print(predicate)),
3151 ty::PredicateKind::DynCompatible(trait_def_id) => {
3152 p!("the trait `", print_def_path(trait_def_id, &[]), "` is dyn-compatible")
3153 }
3154 ty::PredicateKind::ConstEquate(c1, c2) => {
3155 p!("the constant `", print(c1), "` equals `", print(c2), "`")
3156 }
3157 ty::PredicateKind::Ambiguous => p!("ambiguous"),
3158 ty::PredicateKind::NormalizesTo(data) => p!(print(data)),
3159 ty::PredicateKind::AliasRelate(t1, t2, dir) => p!(print(t1), write(" {} ", dir), print(t2)),
3160 }
3161 }
3162
3163 ty::ExistentialPredicate<'tcx> {
3164 match *self {
3165 ty::ExistentialPredicate::Trait(x) => p!(print(x)),
3166 ty::ExistentialPredicate::Projection(x) => p!(print(x)),
3167 ty::ExistentialPredicate::AutoTrait(def_id) => {
3168 p!(print_def_path(def_id, &[]));
3169 }
3170 }
3171 }
3172
3173 ty::ExistentialTraitRef<'tcx> {
3174 let dummy_self = Ty::new_fresh(cx.tcx(), 0);
3176 let trait_ref = self.with_self_ty(cx.tcx(), dummy_self);
3177 p!(print(trait_ref.print_only_trait_path()))
3178 }
3179
3180 ty::ExistentialProjection<'tcx> {
3181 let name = cx.tcx().associated_item(self.def_id).name;
3182 let args = &self.args[cx.tcx().generics_of(self.def_id).parent_count - 1..];
3185 p!(path_generic_args(|cx| write!(cx, "{name}"), args), " = ", print(self.term))
3186 }
3187
3188 ty::ProjectionPredicate<'tcx> {
3189 p!(print(self.projection_term), " == ");
3190 cx.reset_type_limit();
3191 p!(print(self.term))
3192 }
3193
3194 ty::SubtypePredicate<'tcx> {
3195 p!(print(self.a), " <: ");
3196 cx.reset_type_limit();
3197 p!(print(self.b))
3198 }
3199
3200 ty::CoercePredicate<'tcx> {
3201 p!(print(self.a), " -> ");
3202 cx.reset_type_limit();
3203 p!(print(self.b))
3204 }
3205
3206 ty::NormalizesTo<'tcx> {
3207 p!(print(self.alias), " normalizes-to ");
3208 cx.reset_type_limit();
3209 p!(print(self.term))
3210 }
3211}
3212
3213define_print_and_forward_display! {
3214 (self, cx):
3215
3216 &'tcx ty::List<Ty<'tcx>> {
3217 p!("{{", comma_sep(self.iter()), "}}")
3218 }
3219
3220 TraitRefPrintOnlyTraitPath<'tcx> {
3221 p!(print_def_path(self.0.def_id, self.0.args));
3222 }
3223
3224 TraitRefPrintSugared<'tcx> {
3225 if !with_reduced_queries()
3226 && cx.tcx().trait_def(self.0.def_id).paren_sugar
3227 && let ty::Tuple(args) = self.0.args.type_at(1).kind()
3228 {
3229 p!(write("{}", cx.tcx().item_name(self.0.def_id)), "(");
3230 for (i, arg) in args.iter().enumerate() {
3231 if i > 0 {
3232 p!(", ");
3233 }
3234 p!(print(arg));
3235 }
3236 p!(")");
3237 } else {
3238 p!(print_def_path(self.0.def_id, self.0.args));
3239 }
3240 }
3241
3242 TraitRefPrintOnlyTraitName<'tcx> {
3243 p!(print_def_path(self.0.def_id, &[]));
3244 }
3245
3246 TraitPredPrintModifiersAndPath<'tcx> {
3247 if let ty::PredicatePolarity::Negative = self.0.polarity {
3248 p!("!")
3249 }
3250 p!(print(self.0.trait_ref.print_trait_sugared()));
3251 }
3252
3253 TraitPredPrintWithBoundConstness<'tcx> {
3254 p!(print(self.0.trait_ref.self_ty()), ": ");
3255 if let Some(constness) = self.1 {
3256 p!(pretty_print_bound_constness(constness));
3257 }
3258 if let ty::PredicatePolarity::Negative = self.0.polarity {
3259 p!("!");
3260 }
3261 p!(print(self.0.trait_ref.print_trait_sugared()))
3262 }
3263
3264 PrintClosureAsImpl<'tcx> {
3265 p!(pretty_closure_as_impl(self.closure))
3266 }
3267
3268 ty::ParamTy {
3269 p!(write("{}", self.name))
3270 }
3271
3272 ty::ParamConst {
3273 p!(write("{}", self.name))
3274 }
3275
3276 ty::Term<'tcx> {
3277 match self.unpack() {
3278 ty::TermKind::Ty(ty) => p!(print(ty)),
3279 ty::TermKind::Const(c) => p!(print(c)),
3280 }
3281 }
3282
3283 ty::Predicate<'tcx> {
3284 p!(print(self.kind()))
3285 }
3286
3287 ty::Clause<'tcx> {
3288 p!(print(self.kind()))
3289 }
3290
3291 GenericArg<'tcx> {
3292 match self.unpack() {
3293 GenericArgKind::Lifetime(lt) => p!(print(lt)),
3294 GenericArgKind::Type(ty) => p!(print(ty)),
3295 GenericArgKind::Const(ct) => p!(print(ct)),
3296 }
3297 }
3298}
3299
3300fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, Namespace, DefId)) {
3301 let hir = tcx.hir();
3303 for id in hir.items() {
3304 if matches!(tcx.def_kind(id.owner_id), DefKind::Use) {
3305 continue;
3306 }
3307
3308 let item = hir.item(id);
3309 if item.ident.name == kw::Empty {
3310 continue;
3311 }
3312
3313 let def_id = item.owner_id.to_def_id();
3314 let ns = tcx.def_kind(def_id).ns().unwrap_or(Namespace::TypeNS);
3315 collect_fn(&item.ident, ns, def_id);
3316 }
3317
3318 let queue = &mut Vec::new();
3320 let mut seen_defs: DefIdSet = Default::default();
3321
3322 for &cnum in tcx.crates(()).iter() {
3323 match tcx.extern_crate(cnum) {
3325 None => continue,
3326 Some(extern_crate) => {
3327 if !extern_crate.is_direct() {
3328 continue;
3329 }
3330 }
3331 }
3332
3333 queue.push(cnum.as_def_id());
3334 }
3335
3336 while let Some(def) = queue.pop() {
3338 for child in tcx.module_children(def).iter() {
3339 if !child.vis.is_public() {
3340 continue;
3341 }
3342
3343 match child.res {
3344 def::Res::Def(DefKind::AssocTy, _) => {}
3345 def::Res::Def(DefKind::TyAlias, _) => {}
3346 def::Res::Def(defkind, def_id) => {
3347 if let Some(ns) = defkind.ns() {
3348 collect_fn(&child.ident, ns, def_id);
3349 }
3350
3351 if matches!(defkind, DefKind::Mod | DefKind::Enum | DefKind::Trait)
3352 && seen_defs.insert(def_id)
3353 {
3354 queue.push(def_id);
3355 }
3356 }
3357 _ => {}
3358 }
3359 }
3360 }
3361}
3362
3363pub fn trimmed_def_paths(tcx: TyCtxt<'_>, (): ()) -> DefIdMap<Symbol> {
3379 tcx.sess.record_trimmed_def_paths();
3386
3387 let unique_symbols_rev: &mut FxHashMap<(Namespace, Symbol), Option<DefId>> =
3390 &mut FxHashMap::default();
3391
3392 for symbol_set in tcx.resolutions(()).glob_map.values() {
3393 for symbol in symbol_set {
3394 unique_symbols_rev.insert((Namespace::TypeNS, *symbol), None);
3395 unique_symbols_rev.insert((Namespace::ValueNS, *symbol), None);
3396 unique_symbols_rev.insert((Namespace::MacroNS, *symbol), None);
3397 }
3398 }
3399
3400 for_each_def(tcx, |ident, ns, def_id| {
3401 use std::collections::hash_map::Entry::{Occupied, Vacant};
3402
3403 match unique_symbols_rev.entry((ns, ident.name)) {
3404 Occupied(mut v) => match v.get() {
3405 None => {}
3406 Some(existing) => {
3407 if *existing != def_id {
3408 v.insert(None);
3409 }
3410 }
3411 },
3412 Vacant(v) => {
3413 v.insert(Some(def_id));
3414 }
3415 }
3416 });
3417
3418 let mut map: DefIdMap<Symbol> = Default::default();
3420 for ((_, symbol), opt_def_id) in unique_symbols_rev.drain() {
3421 use std::collections::hash_map::Entry::{Occupied, Vacant};
3422
3423 if let Some(def_id) = opt_def_id {
3424 match map.entry(def_id) {
3425 Occupied(mut v) => {
3426 if *v.get() != symbol && v.get().as_str() > symbol.as_str() {
3435 v.insert(symbol);
3436 }
3437 }
3438 Vacant(v) => {
3439 v.insert(symbol);
3440 }
3441 }
3442 }
3443 }
3444
3445 map
3446}
3447
3448pub fn provide(providers: &mut Providers) {
3449 *providers = Providers { trimmed_def_paths, ..*providers };
3450}
3451
3452pub struct OpaqueFnEntry<'tcx> {
3453 kind: ty::ClosureKind,
3454 return_ty: Option<ty::Binder<'tcx, Term<'tcx>>>,
3455}