]> git.lizzy.rs Git - rust.git/blob - src/librustc/util/ppaux.rs
d4111e0375f1613a12b09aff43915208937c6141
[rust.git] / src / librustc / util / ppaux.rs
1 use crate::hir::def::Namespace;
2 use crate::hir::def_id::DefId;
3 use crate::middle::region;
4 use crate::ty::subst::{Kind, Subst, SubstsRef, UnpackedKind};
5 use crate::ty::{BrAnon, BrEnv, BrFresh, BrNamed};
6 use crate::ty::{Bool, Char, Adt};
7 use crate::ty::{Error, Str, Array, Slice, Float, FnDef, FnPtr};
8 use crate::ty::{Param, Bound, RawPtr, Ref, Never, Tuple};
9 use crate::ty::{Closure, Generator, GeneratorWitness, Foreign, Projection, Opaque};
10 use crate::ty::{Placeholder, UnnormalizedProjection, Dynamic, Int, Uint, Infer};
11 use crate::ty::{self, ParamConst, Ty, TypeFoldable};
12 use crate::ty::print::{FmtPrinter, PrettyPrinter, PrintCx, Print, Printer};
13 use crate::mir::interpret::ConstValue;
14
15 use std::fmt::{self, Write as _};
16 use std::iter;
17 use std::usize;
18
19 use rustc_target::spec::abi::Abi;
20 use syntax::ast::CRATE_NODE_ID;
21 use syntax::symbol::{Symbol, InternedString};
22 use crate::hir;
23
24 macro_rules! gen_display_debug_body {
25     ( $with:path ) => {
26         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27             PrintCx::with_tls_tcx(FmtPrinter::new(f), |cx| {
28                 $with(&cx.tcx.lift(self).expect("could not lift for printing"), cx)?;
29                 Ok(())
30             })
31         }
32     };
33 }
34 macro_rules! gen_display_debug {
35     ( ($($x:tt)+) $target:ty, display yes ) => {
36         impl<$($x)+> fmt::Display for $target {
37             gen_display_debug_body! { Print::print_display }
38         }
39     };
40     ( () $target:ty, display yes ) => {
41         impl fmt::Display for $target {
42             gen_display_debug_body! { Print::print_display }
43         }
44     };
45     ( ($($x:tt)+) $target:ty, debug yes ) => {
46         impl<$($x)+> fmt::Debug for $target {
47             gen_display_debug_body! { Print::print_debug }
48         }
49     };
50     ( () $target:ty, debug yes ) => {
51         impl fmt::Debug for $target {
52             gen_display_debug_body! { Print::print_debug }
53         }
54     };
55     ( $generic:tt $target:ty, $t:ident no ) => {};
56 }
57 macro_rules! gen_print_impl {
58     ( ($($x:tt)+) $target:ty, ($self:ident, $cx:ident) $disp:block $dbg:block ) => {
59         impl<$($x)+, P: PrettyPrinter> Print<'tcx, P> for $target {
60             type Output = P;
61             type Error = fmt::Error;
62             fn print(&$self, $cx: PrintCx<'_, '_, 'tcx, P>) -> Result<Self::Output, Self::Error> {
63                 #[allow(unused_mut)]
64                 let mut $cx = $cx;
65                 let _: () = {
66                     define_scoped_cx!($cx);
67
68                     if $cx.config.is_debug $dbg
69                     else $disp
70                 };
71                 Ok($cx.printer)
72             }
73         }
74     };
75     ( () $target:ty, ($self:ident, $cx:ident) $disp:block $dbg:block ) => {
76         impl<P: PrettyPrinter> Print<'tcx, P> for $target {
77             type Output = P;
78             type Error = fmt::Error;
79             fn print(&$self, $cx: PrintCx<'_, '_, 'tcx, P>) -> Result<Self::Output, Self::Error> {
80                 #[allow(unused_mut)]
81                 let mut $cx = $cx;
82                 let _: () = {
83                     define_scoped_cx!($cx);
84
85                     if $cx.config.is_debug $dbg
86                     else $disp
87                 };
88                 Ok($cx.printer)
89             }
90         }
91     };
92     ( $generic:tt $target:ty,
93       $vars:tt $gendisp:ident $disp:block $gendbg:ident $dbg:block ) => {
94         gen_print_impl! { $generic $target, $vars $disp $dbg }
95         gen_display_debug! { $generic $target, display $gendisp }
96         gen_display_debug! { $generic $target, debug $gendbg }
97     }
98 }
99 macro_rules! define_print {
100     ( $generic:tt $target:ty,
101       $vars:tt { display $disp:block debug $dbg:block } ) => {
102         gen_print_impl! { $generic $target, $vars yes $disp yes $dbg }
103     };
104     ( $generic:tt $target:ty,
105       $vars:tt { debug $dbg:block display $disp:block } ) => {
106         gen_print_impl! { $generic $target, $vars yes $disp yes $dbg }
107     };
108     ( $generic:tt $target:ty,
109       $vars:tt { debug $dbg:block } ) => {
110         gen_print_impl! { $generic $target, $vars no {
111             bug!(concat!("display not implemented for ", stringify!($target)));
112         } yes $dbg }
113     };
114     ( $generic:tt $target:ty,
115       ($self:ident, $cx:ident) { display $disp:block } ) => {
116         gen_print_impl! { $generic $target, ($self, $cx) yes $disp no {
117             write!($cx.printer, "{:?}", $self)?
118         } }
119     };
120 }
121 macro_rules! define_print_multi {
122     ( [ $($generic:tt $target:ty),* ] $vars:tt $def:tt ) => {
123         $(define_print! { $generic $target, $vars $def })*
124     };
125 }
126 macro_rules! nest {
127     ($closure:expr) => {
128         scoped_cx!() = scoped_cx!().nest($closure)?
129     }
130 }
131 macro_rules! print_inner {
132     (write ($($data:expr),+)) => {
133         write!(scoped_cx!().printer, $($data),+)?
134     };
135     ($kind:ident ($data:expr)) => {
136         nest!(|cx| $data.$kind(cx))
137     };
138 }
139 macro_rules! p {
140     ($($kind:ident $data:tt),+) => {
141         {
142             $(print_inner!($kind $data));+
143         }
144     };
145 }
146 macro_rules! define_scoped_cx {
147     ($cx:ident) => {
148         #[allow(unused_macros)]
149         macro_rules! scoped_cx {
150             () => ($cx)
151         }
152     };
153 }
154
155 impl<P: PrettyPrinter> PrintCx<'a, 'gcx, 'tcx, P> {
156     fn fn_sig(
157         mut self,
158         inputs: &[Ty<'tcx>],
159         c_variadic: bool,
160         output: Ty<'tcx>,
161     ) -> Result<P, fmt::Error> {
162         define_scoped_cx!(self);
163
164         p!(write("("));
165         let mut inputs = inputs.iter();
166         if let Some(&ty) = inputs.next() {
167             p!(print_display(ty));
168             for &ty in inputs {
169                 p!(write(", "), print_display(ty));
170             }
171             if c_variadic {
172                 p!(write(", ..."));
173             }
174         }
175         p!(write(")"));
176         if !output.is_unit() {
177             p!(write(" -> "), print_display(output));
178         }
179
180         Ok(self.printer)
181     }
182
183     fn in_binder<T>(mut self, value: &ty::Binder<T>) -> Result<P, fmt::Error>
184         where T: Print<'tcx, P, Output = P, Error = fmt::Error> + TypeFoldable<'tcx>
185     {
186         fn name_by_region_index(index: usize) -> InternedString {
187             match index {
188                 0 => Symbol::intern("'r"),
189                 1 => Symbol::intern("'s"),
190                 i => Symbol::intern(&format!("'t{}", i-2)),
191             }.as_interned_str()
192         }
193
194         // Replace any anonymous late-bound regions with named
195         // variants, using gensym'd identifiers, so that we can
196         // clearly differentiate between named and unnamed regions in
197         // the output. We'll probably want to tweak this over time to
198         // decide just how much information to give.
199         if self.config.binder_depth == 0 {
200             self.prepare_late_bound_region_info(value);
201         }
202
203         let mut empty = true;
204         let mut start_or_continue = |cx: &mut Self, start: &str, cont: &str| {
205             write!(cx.printer, "{}", if empty {
206                 empty = false;
207                 start
208             } else {
209                 cont
210             })
211         };
212
213         // NOTE(eddyb) this must be below `start_or_continue`'s definition
214         // as that also has a `define_scoped_cx` and that kind of shadowing
215         // is disallowed (name resolution thinks `scoped_cx!` is ambiguous).
216         define_scoped_cx!(self);
217
218         let old_region_index = self.config.region_index;
219         let mut region_index = old_region_index;
220         let new_value = self.tcx.replace_late_bound_regions(value, |br| {
221             let _ = start_or_continue(&mut self, "for<", ", ");
222             let br = match br {
223                 ty::BrNamed(_, name) => {
224                     let _ = write!(self.printer, "{}", name);
225                     br
226                 }
227                 ty::BrAnon(_) |
228                 ty::BrFresh(_) |
229                 ty::BrEnv => {
230                     let name = loop {
231                         let name = name_by_region_index(region_index);
232                         region_index += 1;
233                         if !self.is_name_used(&name) {
234                             break name;
235                         }
236                     };
237                     let _ = write!(self.printer, "{}", name);
238                     ty::BrNamed(self.tcx.hir().local_def_id(CRATE_NODE_ID), name)
239                 }
240             };
241             self.tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br))
242         }).0;
243         start_or_continue(&mut self, "", "> ")?;
244
245         // Push current state to gcx, and restore after writing new_value.
246         self.config.binder_depth += 1;
247         self.config.region_index = region_index;
248         let result = new_value.print_display(PrintCx {
249             tcx: self.tcx,
250             printer: self.printer,
251             config: self.config,
252         });
253         self.config.region_index = old_region_index;
254         self.config.binder_depth -= 1;
255         result
256     }
257
258     fn is_name_used(&self, name: &InternedString) -> bool {
259         match self.config.used_region_names {
260             Some(ref names) => names.contains(name),
261             None => false,
262         }
263     }
264 }
265
266 pub fn parameterized<F: fmt::Write>(
267     f: &mut F,
268     did: DefId,
269     substs: SubstsRef<'_>,
270     ns: Namespace,
271 ) -> fmt::Result {
272     PrintCx::with_tls_tcx(FmtPrinter::new(f), |cx| {
273         let substs = cx.tcx.lift(&substs).expect("could not lift for printing");
274         cx.print_def_path(did, Some(substs), ns, iter::empty())?;
275         Ok(())
276     })
277 }
278
279 define_print! {
280     ('tcx) &'tcx ty::List<ty::ExistentialPredicate<'tcx>>, (self, cx) {
281         display {
282             // Generate the main trait ref, including associated types.
283             let mut first = true;
284
285             if let Some(principal) = self.principal() {
286                 let mut resugared_principal = false;
287
288                 // Special-case `Fn(...) -> ...` and resugar it.
289                 let fn_trait_kind = cx.tcx.lang_items().fn_trait_kind(principal.def_id);
290                 if !cx.config.is_verbose && fn_trait_kind.is_some() {
291                     if let ty::Tuple(ref args) = principal.substs.type_at(0).sty {
292                         let mut projections = self.projection_bounds();
293                         if let (Some(proj), None) = (projections.next(), projections.next()) {
294                             nest!(|cx| cx.print_def_path(
295                                 principal.def_id,
296                                 None,
297                                 Namespace::TypeNS,
298                                 iter::empty(),
299                             ));
300                             nest!(|cx| cx.fn_sig(args, false, proj.ty));
301                             resugared_principal = true;
302                         }
303                     }
304                 }
305
306                 if !resugared_principal {
307                     // Use a type that can't appear in defaults of type parameters.
308                     let dummy_self = cx.tcx.mk_infer(ty::FreshTy(0));
309                     let principal = principal.with_self_ty(cx.tcx, dummy_self);
310                     nest!(|cx| cx.print_def_path(
311                         principal.def_id,
312                         Some(principal.substs),
313                         Namespace::TypeNS,
314                         self.projection_bounds(),
315                     ));
316                 }
317                 first = false;
318             }
319
320             // Builtin bounds.
321             // FIXME(eddyb) avoid printing twice (needed to ensure
322             // that the auto traits are sorted *and* printed via cx).
323             let mut auto_traits: Vec<_> = self.auto_traits().map(|did| {
324                 (cx.tcx.def_path_str(did), did)
325             }).collect();
326
327             // The auto traits come ordered by `DefPathHash`. While
328             // `DefPathHash` is *stable* in the sense that it depends on
329             // neither the host nor the phase of the moon, it depends
330             // "pseudorandomly" on the compiler version and the target.
331             //
332             // To avoid that causing instabilities in compiletest
333             // output, sort the auto-traits alphabetically.
334             auto_traits.sort();
335
336             for (_, def_id) in auto_traits {
337                 if !first {
338                     p!(write(" + "));
339                 }
340                 first = false;
341
342                 nest!(|cx| cx.print_def_path(
343                     def_id,
344                     None,
345                     Namespace::TypeNS,
346                     iter::empty(),
347                 ));
348             }
349         }
350     }
351 }
352
353 impl fmt::Debug for ty::GenericParamDef {
354     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
355         let type_name = match self.kind {
356             ty::GenericParamDefKind::Lifetime => "Lifetime",
357             ty::GenericParamDefKind::Type { .. } => "Type",
358             ty::GenericParamDefKind::Const => "Const",
359         };
360         write!(f, "{}({}, {:?}, {})",
361                type_name,
362                self.name,
363                self.def_id,
364                self.index)
365     }
366 }
367
368 impl fmt::Debug for ty::TraitDef {
369     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
370         PrintCx::with_tls_tcx(FmtPrinter::new(f), |cx| {
371             cx.print_def_path(
372                 self.def_id,
373                 None,
374                 Namespace::TypeNS,
375                 iter::empty(),
376             )?;
377             Ok(())
378         })
379     }
380 }
381
382 impl fmt::Debug for ty::AdtDef {
383     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
384         PrintCx::with_tls_tcx(FmtPrinter::new(f), |cx| {
385             cx.print_def_path(
386                 self.did,
387                 None,
388                 Namespace::TypeNS,
389                 iter::empty(),
390             )?;
391             Ok(())
392         })
393     }
394 }
395
396 impl<'tcx> fmt::Debug for ty::ClosureUpvar<'tcx> {
397     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
398         write!(f, "ClosureUpvar({:?},{:?})",
399                self.def,
400                self.ty)
401     }
402 }
403
404 impl fmt::Debug for ty::UpvarId {
405     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
406         PrintCx::with_tls_tcx(FmtPrinter::new(f), |mut cx| {
407             define_scoped_cx!(cx);
408             p!(write("UpvarId({:?};`{}`;{:?})",
409                 self.var_path.hir_id,
410                 cx.tcx.hir().name_by_hir_id(self.var_path.hir_id),
411                 self.closure_expr_id));
412             Ok(())
413         })
414     }
415 }
416
417 impl<'tcx> fmt::Debug for ty::UpvarBorrow<'tcx> {
418     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
419         write!(f, "UpvarBorrow({:?}, {:?})",
420                self.kind, self.region)
421     }
422 }
423
424 define_print! {
425     ('tcx) &'tcx ty::List<Ty<'tcx>>, (self, cx) {
426         display {
427             p!(write("{{"));
428             let mut tys = self.iter();
429             if let Some(&ty) = tys.next() {
430                 p!(print(ty));
431                 for &ty in tys {
432                     p!(write(", "), print(ty));
433                 }
434             }
435             p!(write("}}"))
436         }
437     }
438 }
439
440 define_print! {
441     ('tcx) ty::TypeAndMut<'tcx>, (self, cx) {
442         display {
443             p!(
444                    write("{}", if self.mutbl == hir::MutMutable { "mut " } else { "" }),
445                    print(self.ty))
446         }
447     }
448 }
449
450 define_print! {
451     ('tcx) ty::ExistentialTraitRef<'tcx>, (self, cx) {
452         display {
453             let dummy_self = cx.tcx.mk_infer(ty::FreshTy(0));
454
455             let trait_ref = *ty::Binder::bind(*self)
456                 .with_self_ty(cx.tcx, dummy_self)
457                 .skip_binder();
458             p!(print_display(trait_ref))
459         }
460         debug {
461             p!(print_display(self))
462         }
463     }
464 }
465
466 define_print! {
467     ('tcx) ty::adjustment::Adjustment<'tcx>, (self, cx) {
468         debug {
469             p!(write("{:?} -> ", self.kind), print(self.target))
470         }
471     }
472 }
473
474 define_print! {
475     () ty::BoundRegion, (self, cx) {
476         display {
477             if cx.config.is_verbose {
478                 return self.print_debug(cx);
479             }
480
481             if let BrNamed(_, name) = *self {
482                 if name != "" && name != "'_" {
483                     p!(write("{}", name));
484                     return Ok(cx.printer);
485                 }
486             }
487
488             let highlight = cx.printer.region_highlight_mode();
489             if let Some((region, counter)) = highlight.highlight_bound_region {
490                 if *self == region {
491                     p!(write("'{}", counter));
492                 }
493             }
494         }
495         debug {
496             match *self {
497                 BrAnon(n) => p!(write("BrAnon({:?})", n)),
498                 BrFresh(n) => p!(write("BrFresh({:?})", n)),
499                 BrNamed(did, name) => {
500                     p!(write("BrNamed({:?}:{:?}, {})",
501                            did.krate, did.index, name))
502                 }
503                 BrEnv => p!(write("BrEnv")),
504             }
505         }
506     }
507 }
508
509 // HACK(eddyb) (see `ty::RegionKind::display_outputs_anything`)
510 //
511 // NB: this must be kept in sync with the printing logic above.
512 impl ty::BoundRegion {
513     fn display_outputs_anything<P>(&self, cx: &PrintCx<'_, '_, '_, P>) -> bool
514         where P: PrettyPrinter
515     {
516         if cx.config.is_verbose {
517             return true;
518         }
519
520         if let BrNamed(_, name) = *self {
521             if name != "" && name != "'_" {
522                 return true;
523             }
524         }
525
526         let highlight = cx.printer.region_highlight_mode();
527         if let Some((region, _)) = highlight.highlight_bound_region {
528             if *self == region {
529                 return true;
530             }
531         }
532
533         false
534     }
535 }
536
537 define_print! {
538     () ty::PlaceholderRegion, (self, cx) {
539         display {
540             if cx.config.is_verbose {
541                 return self.print_debug(cx);
542             }
543
544             let highlight = cx.printer.region_highlight_mode();
545             if let Some(counter) = highlight.placeholder_highlight(*self) {
546                 p!(write("'{}", counter));
547             } else {
548                 p!(print_display(self.name));
549             }
550         }
551     }
552 }
553
554 // HACK(eddyb) (see `ty::RegionKind::display_outputs_anything`)
555 //
556 // NB: this must be kept in sync with the printing logic above.
557 impl ty::PlaceholderRegion {
558     fn display_outputs_anything<P>(&self, cx: &PrintCx<'_, '_, '_, P>) -> bool
559         where P: PrettyPrinter
560     {
561         if cx.config.is_verbose {
562             return true;
563         }
564
565         let highlight = cx.printer.region_highlight_mode();
566         if highlight.placeholder_highlight(*self).is_some() {
567             return true;
568         }
569
570         self.name.display_outputs_anything(cx)
571     }
572 }
573
574 define_print! {
575     () ty::RegionKind, (self, cx) {
576         display {
577             if cx.config.is_verbose {
578                 return self.print_debug(cx);
579             }
580
581             // Watch out for region highlights.
582             if let Some(n) = cx.printer.region_highlight_mode().region_highlighted(self) {
583                 p!(write("'{}", n));
584                 return Ok(cx.printer);
585             }
586
587             // These printouts are concise.  They do not contain all the information
588             // the user might want to diagnose an error, but there is basically no way
589             // to fit that into a short string.  Hence the recommendation to use
590             // `explain_region()` or `note_and_explain_region()`.
591             match *self {
592                 ty::ReEarlyBound(ref data) => {
593                     if data.name != "'_" {
594                         p!(write("{}", data.name))
595                     }
596                 }
597                 ty::ReLateBound(_, br) |
598                 ty::ReFree(ty::FreeRegion { bound_region: br, .. }) => {
599                     p!(print_display(br))
600                 }
601                 ty::RePlaceholder(p) => {
602                     p!(print_display(p))
603                 }
604                 ty::ReScope(scope) if cx.config.identify_regions => {
605                     match scope.data {
606                         region::ScopeData::Node =>
607                             p!(write("'{}s", scope.item_local_id().as_usize())),
608                         region::ScopeData::CallSite =>
609                             p!(write("'{}cs", scope.item_local_id().as_usize())),
610                         region::ScopeData::Arguments =>
611                             p!(write("'{}as", scope.item_local_id().as_usize())),
612                         region::ScopeData::Destruction =>
613                             p!(write("'{}ds", scope.item_local_id().as_usize())),
614                         region::ScopeData::Remainder(first_statement_index) => p!(write(
615                             "'{}_{}rs",
616                             scope.item_local_id().as_usize(),
617                             first_statement_index.index()
618                         )),
619                     }
620                 }
621                 ty::ReVar(region_vid) if cx.config.identify_regions => {
622                     p!(print_debug(region_vid))
623                 }
624                 ty::ReVar(region_vid) => {
625                     p!(print_display(region_vid))
626                 }
627                 ty::ReScope(_) |
628                 ty::ReErased => {}
629                 ty::ReStatic => p!(write("'static")),
630                 ty::ReEmpty => p!(write("'<empty>")),
631
632                 // The user should never encounter these in unsubstituted form.
633                 ty::ReClosureBound(vid) => p!(write("{:?}", vid)),
634             }
635         }
636         debug {
637             match *self {
638                 ty::ReEarlyBound(ref data) => {
639                     p!(write("ReEarlyBound({}, {})",
640                            data.index,
641                            data.name))
642                 }
643
644                 ty::ReClosureBound(ref vid) => {
645                     p!(write("ReClosureBound({:?})",
646                            vid))
647                 }
648
649                 ty::ReLateBound(binder_id, ref bound_region) => {
650                     p!(write("ReLateBound({:?}, ", binder_id),
651                        print_debug(bound_region),
652                        write(")"))
653                 }
654
655                 ty::ReFree(ref fr) => p!(print_debug(fr)),
656
657                 ty::ReScope(id) => {
658                     p!(write("ReScope({:?})", id))
659                 }
660
661                 ty::ReStatic => p!(write("ReStatic")),
662
663                 ty::ReVar(ref vid) => {
664                     p!(print_debug(vid))
665                 }
666
667                 ty::RePlaceholder(placeholder) => {
668                     p!(write("RePlaceholder("), print_debug(placeholder), write(")"))
669                 }
670
671                 ty::ReEmpty => p!(write("ReEmpty")),
672
673                 ty::ReErased => p!(write("ReErased"))
674             }
675         }
676     }
677 }
678
679 // HACK(eddyb) Trying to print a lifetime might not print anything, which
680 // may need special handling in the caller (of `ty::RegionKind::print`).
681 // To avoid printing to a temporary string, the `display_outputs_anything`
682 // method can instead be used to determine this, ahead of time.
683 //
684 // NB: this must be kept in sync with the printing logic above.
685 impl ty::RegionKind {
686     // HACK(eddyb) `pub(crate)` only for `ty::print`.
687     pub(crate) fn display_outputs_anything<P>(&self, cx: &PrintCx<'_, '_, '_, P>) -> bool
688         where P: PrettyPrinter
689     {
690         if cx.config.is_verbose {
691             return true;
692         }
693
694         if cx.printer.region_highlight_mode().region_highlighted(self).is_some() {
695             return true;
696         }
697
698         match *self {
699             ty::ReEarlyBound(ref data) => {
700                 data.name != "" && data.name != "'_"
701             }
702
703             ty::ReLateBound(_, br) |
704             ty::ReFree(ty::FreeRegion { bound_region: br, .. }) => {
705                 br.display_outputs_anything(cx)
706             }
707
708             ty::RePlaceholder(p) => p.display_outputs_anything(cx),
709
710             ty::ReScope(_) |
711             ty::ReVar(_) if cx.config.identify_regions => true,
712
713             ty::ReVar(region_vid) => region_vid.display_outputs_anything(cx),
714
715             ty::ReScope(_) |
716             ty::ReErased => false,
717
718             ty::ReStatic |
719             ty::ReEmpty |
720             ty::ReClosureBound(_) => true,
721         }
722     }
723 }
724
725 define_print! {
726     () ty::FreeRegion, (self, cx) {
727         debug {
728             p!(write("ReFree({:?}, {:?})", self.scope, self.bound_region))
729         }
730     }
731 }
732
733 define_print! {
734     () ty::Variance, (self, cx) {
735         debug {
736             cx.printer.write_str(match *self {
737                 ty::Covariant => "+",
738                 ty::Contravariant => "-",
739                 ty::Invariant => "o",
740                 ty::Bivariant => "*",
741             })?
742         }
743     }
744 }
745
746 define_print! {
747     ('tcx) ty::FnSig<'tcx>, (self, cx) {
748         display {
749             if self.unsafety == hir::Unsafety::Unsafe {
750                 p!(write("unsafe "));
751             }
752
753             if self.abi != Abi::Rust {
754                 p!(write("extern {} ", self.abi));
755             }
756
757             p!(write("fn"));
758             nest!(|cx| cx.fn_sig(self.inputs(), self.c_variadic, self.output()));
759         }
760         debug {
761             p!(write("({:?}; c_variadic: {})->{:?}",
762                 self.inputs(), self.c_variadic, self.output()))
763         }
764     }
765 }
766
767 impl fmt::Debug for ty::TyVid {
768     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
769         write!(f, "_#{}t", self.index)
770     }
771 }
772
773 impl<'tcx> fmt::Debug for ty::ConstVid<'tcx> {
774     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
775         write!(f, "_#{}f", self.index)
776     }
777 }
778
779 impl fmt::Debug for ty::IntVid {
780     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
781         write!(f, "_#{}i", self.index)
782     }
783 }
784
785 impl fmt::Debug for ty::FloatVid {
786     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
787         write!(f, "_#{}f", self.index)
788     }
789 }
790
791 define_print! {
792     () ty::RegionVid, (self, cx) {
793         display {
794             if cx.config.is_verbose {
795                 return self.print_debug(cx);
796             }
797
798             let highlight = cx.printer.region_highlight_mode();
799             if let Some(counter) = highlight.region_highlighted(&ty::ReVar(*self)) {
800                 p!(write("'{}", counter));
801             }
802         }
803         debug {
804             // HACK(eddyb) this is duplicated from `display` printing,
805             // to keep NLL borrowck working even with `-Zverbose`.
806             let highlight = cx.printer.region_highlight_mode();
807             if let Some(counter) = highlight.region_highlighted(&ty::ReVar(*self)) {
808                 p!(write("'{}", counter));
809             } else {
810                 p!(write("'_#{}r", self.index()));
811             }
812         }
813     }
814 }
815
816 // HACK(eddyb) (see `ty::RegionKind::display_outputs_anything`)
817 //
818 // NB: this must be kept in sync with the printing logic above.
819 impl ty::RegionVid {
820     fn display_outputs_anything<P>(&self, cx: &PrintCx<'_, '_, '_, P>) -> bool
821         where P: PrettyPrinter
822     {
823         if cx.config.is_verbose {
824             return true;
825         }
826
827         let highlight = cx.printer.region_highlight_mode();
828         if highlight.region_highlighted(&ty::ReVar(*self)).is_some() {
829             return true;
830         }
831
832         false
833     }
834 }
835
836 define_print! {
837     () ty::InferTy, (self, cx) {
838         display {
839             if cx.config.is_verbose {
840                 return self.print_debug(cx);
841             }
842             match *self {
843                 ty::TyVar(_) => p!(write("_")),
844                 ty::IntVar(_) => p!(write("{}", "{integer}")),
845                 ty::FloatVar(_) => p!(write("{}", "{float}")),
846                 ty::FreshTy(v) => p!(write("FreshTy({})", v)),
847                 ty::FreshIntTy(v) => p!(write("FreshIntTy({})", v)),
848                 ty::FreshFloatTy(v) => p!(write("FreshFloatTy({})", v))
849             }
850         }
851         debug {
852             match *self {
853                 ty::TyVar(ref v) => p!(write("{:?}", v)),
854                 ty::IntVar(ref v) => p!(write("{:?}", v)),
855                 ty::FloatVar(ref v) => p!(write("{:?}", v)),
856                 ty::FreshTy(v) => p!(write("FreshTy({:?})", v)),
857                 ty::FreshIntTy(v) => p!(write("FreshIntTy({:?})", v)),
858                 ty::FreshFloatTy(v) => p!(write("FreshFloatTy({:?})", v))
859             }
860         }
861     }
862 }
863
864 impl fmt::Debug for ty::IntVarValue {
865     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
866         match *self {
867             ty::IntType(ref v) => v.fmt(f),
868             ty::UintType(ref v) => v.fmt(f),
869         }
870     }
871 }
872
873 impl fmt::Debug for ty::FloatVarValue {
874     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
875         self.0.fmt(f)
876     }
877 }
878
879 // The generic impl doesn't work yet because projections are not
880 // normalized under HRTB.
881 /*impl<T> fmt::Display for ty::Binder<T>
882     where T: fmt::Display + for<'a> ty::Lift<'a>,
883           for<'a> <T as ty::Lift<'a>>::Lifted: fmt::Display + TypeFoldable<'a>
884 {
885     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
886         PrintCx::with_tls_tcx(|cx| cx.in_binder(cx.tcx.lift(self)
887             .expect("could not lift for printing")))
888     }
889 }*/
890
891 define_print_multi! {
892     [
893     ('tcx) ty::Binder<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>,
894     ('tcx) ty::Binder<ty::TraitRef<'tcx>>,
895     ('tcx) ty::Binder<ty::FnSig<'tcx>>,
896     ('tcx) ty::Binder<ty::TraitPredicate<'tcx>>,
897     ('tcx) ty::Binder<ty::SubtypePredicate<'tcx>>,
898     ('tcx) ty::Binder<ty::ProjectionPredicate<'tcx>>,
899     ('tcx) ty::Binder<ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>,
900     ('tcx) ty::Binder<ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>>
901     ]
902     (self, cx) {
903         display {
904             nest!(|cx| cx.in_binder(self))
905         }
906     }
907 }
908
909 define_print! {
910     ('tcx) ty::TraitRef<'tcx>, (self, cx) {
911         display {
912             nest!(|cx| cx.print_def_path(
913                 self.def_id,
914                 Some(self.substs),
915                 Namespace::TypeNS,
916                 iter::empty(),
917             ));
918         }
919         debug {
920             nest!(|cx| cx.path_qualified(self.self_ty(), Some(*self), Namespace::TypeNS));
921         }
922     }
923 }
924
925 define_print! {
926     ('tcx) ty::Ty<'tcx>, (self, cx) {
927         display {
928             match self.sty {
929                 Bool => p!(write("bool")),
930                 Char => p!(write("char")),
931                 Int(t) => p!(write("{}", t.ty_to_string())),
932                 Uint(t) => p!(write("{}", t.ty_to_string())),
933                 Float(t) => p!(write("{}", t.ty_to_string())),
934                 RawPtr(ref tm) => {
935                     p!(write("*{} ", match tm.mutbl {
936                         hir::MutMutable => "mut",
937                         hir::MutImmutable => "const",
938                     }));
939                     p!(print(tm.ty))
940                 }
941                 Ref(r, ty, mutbl) => {
942                     p!(write("&"));
943                     if r.display_outputs_anything(&cx) {
944                         p!(print_display(r), write(" "));
945                     }
946                     p!(print(ty::TypeAndMut { ty, mutbl }))
947                 }
948                 Never => p!(write("!")),
949                 Tuple(ref tys) => {
950                     p!(write("("));
951                     let mut tys = tys.iter();
952                     if let Some(&ty) = tys.next() {
953                         p!(print(ty), write(","));
954                         if let Some(&ty) = tys.next() {
955                             p!(write(" "), print(ty));
956                             for &ty in tys {
957                                 p!(write(", "), print(ty));
958                             }
959                         }
960                     }
961                     p!(write(")"))
962                 }
963                 FnDef(def_id, substs) => {
964                     let sig = cx.tcx.fn_sig(def_id).subst(cx.tcx, substs);
965                     p!(print(sig), write(" {{"));
966                     nest!(|cx| cx.print_def_path(
967                         def_id,
968                         Some(substs),
969                         Namespace::ValueNS,
970                         iter::empty(),
971                     ));
972                     p!(write("}}"))
973                 }
974                 FnPtr(ref bare_fn) => {
975                     p!(print(bare_fn))
976                 }
977                 Infer(infer_ty) => p!(write("{}", infer_ty)),
978                 Error => p!(write("[type error]")),
979                 Param(ref param_ty) => p!(write("{}", param_ty)),
980                 Bound(debruijn, bound_ty) => {
981                     match bound_ty.kind {
982                         ty::BoundTyKind::Anon => {
983                             if debruijn == ty::INNERMOST {
984                                 p!(write("^{}", bound_ty.var.index()))
985                             } else {
986                                 p!(write("^{}_{}", debruijn.index(), bound_ty.var.index()))
987                             }
988                         }
989
990                         ty::BoundTyKind::Param(p) => p!(write("{}", p)),
991                     }
992                 }
993                 Adt(def, substs) => {
994                     nest!(|cx| cx.print_def_path(
995                         def.did,
996                         Some(substs),
997                         Namespace::TypeNS,
998                         iter::empty(),
999                     ));
1000                 }
1001                 Dynamic(data, r) => {
1002                     let print_r = r.display_outputs_anything(&cx);
1003                     if print_r {
1004                         p!(write("("));
1005                     }
1006                     p!(write("dyn "), print(data));
1007                     if print_r {
1008                         p!(write(" + "), print_display(r), write(")"));
1009                     }
1010                 }
1011                 Foreign(def_id) => {
1012                     nest!(|cx| cx.print_def_path(
1013                         def_id,
1014                         None,
1015                         Namespace::TypeNS,
1016                         iter::empty(),
1017                     ));
1018                 }
1019                 Projection(ref data) => p!(print(data)),
1020                 UnnormalizedProjection(ref data) => {
1021                     p!(write("Unnormalized("), print(data), write(")"))
1022                 }
1023                 Placeholder(placeholder) => {
1024                     p!(write("Placeholder({:?})", placeholder))
1025                 }
1026                 Opaque(def_id, substs) => {
1027                     if cx.config.is_verbose {
1028                         p!(write("Opaque({:?}, {:?})", def_id, substs));
1029                         return Ok(cx.printer);
1030                     }
1031
1032                     let def_key = cx.tcx.def_key(def_id);
1033                     if let Some(name) = def_key.disambiguated_data.data.get_opt_name() {
1034                         p!(write("{}", name));
1035                         let mut substs = substs.iter();
1036                         // FIXME(eddyb) print this with `print_def_path`.
1037                         if let Some(first) = substs.next() {
1038                             p!(write("::<"));
1039                             p!(print_display(first));
1040                             for subst in substs {
1041                                 p!(write(", "), print_display(subst));
1042                             }
1043                             p!(write(">"));
1044                         }
1045                         return Ok(cx.printer);
1046                     }
1047                     // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
1048                     // by looking up the projections associated with the def_id.
1049                     let bounds = cx.tcx.predicates_of(def_id).instantiate(cx.tcx, substs);
1050
1051                     let mut first = true;
1052                     let mut is_sized = false;
1053                     p!(write("impl"));
1054                     for predicate in bounds.predicates {
1055                         if let Some(trait_ref) = predicate.to_opt_poly_trait_ref() {
1056                             // Don't print +Sized, but rather +?Sized if absent.
1057                             if Some(trait_ref.def_id()) == cx.tcx.lang_items().sized_trait() {
1058                                 is_sized = true;
1059                                 continue;
1060                             }
1061
1062                             p!(
1063                                     write("{}", if first { " " } else { "+" }),
1064                                     print(trait_ref));
1065                             first = false;
1066                         }
1067                     }
1068                     if !is_sized {
1069                         p!(write("{}?Sized", if first { " " } else { "+" }));
1070                     } else if first {
1071                         p!(write(" Sized"));
1072                     }
1073                 }
1074                 Str => p!(write("str")),
1075                 Generator(did, substs, movability) => {
1076                     let upvar_tys = substs.upvar_tys(did, cx.tcx);
1077                     let witness = substs.witness(did, cx.tcx);
1078                     if movability == hir::GeneratorMovability::Movable {
1079                         p!(write("[generator"));
1080                     } else {
1081                         p!(write("[static generator"));
1082                     }
1083
1084                     // FIXME(eddyb) should use `def_span`.
1085                     if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(did) {
1086                         p!(write("@{:?}", cx.tcx.hir().span_by_hir_id(hir_id)));
1087                         let mut sep = " ";
1088                         for (freevar, upvar_ty) in cx.tcx.freevars(did)
1089                             .as_ref()
1090                             .map_or(&[][..], |fv| &fv[..])
1091                             .iter()
1092                             .zip(upvar_tys)
1093                         {
1094                             p!(
1095                                 write("{}{}:",
1096                                         sep,
1097                                         cx.tcx.hir().name(freevar.var_id())),
1098                                 print(upvar_ty));
1099                             sep = ", ";
1100                         }
1101                     } else {
1102                         // cross-crate closure types should only be
1103                         // visible in codegen bug reports, I imagine.
1104                         p!(write("@{:?}", did));
1105                         let mut sep = " ";
1106                         for (index, upvar_ty) in upvar_tys.enumerate() {
1107                             p!(
1108                                    write("{}{}:", sep, index),
1109                                    print(upvar_ty));
1110                             sep = ", ";
1111                         }
1112                     }
1113
1114                     p!(write(" "), print(witness), write("]"))
1115                 },
1116                 GeneratorWitness(types) => {
1117                     nest!(|cx| cx.in_binder(&types))
1118                 }
1119                 Closure(did, substs) => {
1120                     let upvar_tys = substs.upvar_tys(did, cx.tcx);
1121                     p!(write("[closure"));
1122
1123                     // FIXME(eddyb) should use `def_span`.
1124                     if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(did) {
1125                         if cx.tcx.sess.opts.debugging_opts.span_free_formats {
1126                             p!(write("@{:?}", hir_id));
1127                         } else {
1128                             p!(write("@{:?}", cx.tcx.hir().span_by_hir_id(hir_id)));
1129                         }
1130                         let mut sep = " ";
1131                         for (freevar, upvar_ty) in cx.tcx.freevars(did)
1132                             .as_ref()
1133                             .map_or(&[][..], |fv| &fv[..])
1134                             .iter()
1135                             .zip(upvar_tys)
1136                         {
1137                             p!(
1138                                 write("{}{}:",
1139                                         sep,
1140                                         cx.tcx.hir().name(freevar.var_id())),
1141                                 print(upvar_ty));
1142                             sep = ", ";
1143                         }
1144                     } else {
1145                         // cross-crate closure types should only be
1146                         // visible in codegen bug reports, I imagine.
1147                         p!(write("@{:?}", did));
1148                         let mut sep = " ";
1149                         for (index, upvar_ty) in upvar_tys.enumerate() {
1150                             p!(
1151                                    write("{}{}:", sep, index),
1152                                    print(upvar_ty));
1153                             sep = ", ";
1154                         }
1155                     }
1156
1157                     if cx.config.is_verbose {
1158                         p!(write(
1159                             " closure_kind_ty={:?} closure_sig_ty={:?}",
1160                             substs.closure_kind_ty(did, cx.tcx),
1161                             substs.closure_sig_ty(did, cx.tcx)
1162                         ));
1163                     }
1164
1165                     p!(write("]"))
1166                 },
1167                 Array(ty, sz) => {
1168                     p!(write("["), print(ty), write("; "));
1169                     match sz {
1170                         ty::LazyConst::Unevaluated(_def_id, _substs) => {
1171                             p!(write("_"));
1172                         }
1173                         ty::LazyConst::Evaluated(c) => {
1174                             match c.val {
1175                                 ConstValue::Infer(..) => p!(write("_")),
1176                                 ConstValue::Param(ParamConst { name, .. }) =>
1177                                     p!(write("{}", name)),
1178                                 _ => p!(write("{}", c.unwrap_usize(cx.tcx))),
1179                             }
1180                         }
1181                     }
1182                     p!(write("]"))
1183                 }
1184                 Slice(ty) => {
1185                     p!(write("["), print(ty), write("]"))
1186                 }
1187             }
1188         }
1189         debug {
1190             p!(print_display(self))
1191         }
1192     }
1193 }
1194
1195 define_print! {
1196     ('tcx) ConstValue<'tcx>, (self, cx) {
1197         display {
1198             match self {
1199                 ConstValue::Infer(..) => p!(write("_")),
1200                 ConstValue::Param(ParamConst { name, .. }) => p!(write("{}", name)),
1201                 _ => p!(write("{:?}", self)),
1202             }
1203         }
1204     }
1205 }
1206
1207 define_print! {
1208     ('tcx) ty::Const<'tcx>, (self, cx) {
1209         display {
1210             p!(write("{} : {}", self.val, self.ty))
1211         }
1212     }
1213 }
1214
1215 define_print! {
1216     ('tcx) ty::LazyConst<'tcx>, (self, cx) {
1217         display {
1218             match self {
1219                 // FIXME(const_generics) this should print at least the type.
1220                 ty::LazyConst::Unevaluated(..) => p!(write("_ : _")),
1221                 ty::LazyConst::Evaluated(c) => p!(write("{}", c)),
1222             }
1223         }
1224     }
1225 }
1226
1227 define_print! {
1228     () ty::ParamTy, (self, cx) {
1229         display {
1230             p!(write("{}", self.name))
1231         }
1232         debug {
1233             p!(write("{}/#{}", self.name, self.idx))
1234         }
1235     }
1236 }
1237
1238 define_print! {
1239     () ty::ParamConst, (self, cx) {
1240         display {
1241             p!(write("{}", self.name))
1242         }
1243         debug {
1244             p!(write("{}/#{}", self.name, self.index))
1245         }
1246     }
1247 }
1248
1249 // Similar problem to `Binder<T>`, can't define a generic impl.
1250 define_print_multi! {
1251     [
1252     ('tcx) ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>,
1253     ('tcx) ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>
1254     ]
1255     (self, cx) {
1256         display {
1257             p!(print(self.0), write(" : "), print(self.1))
1258         }
1259     }
1260 }
1261
1262 define_print! {
1263     ('tcx) ty::SubtypePredicate<'tcx>, (self, cx) {
1264         display {
1265             p!(print(self.a), write(" <: "), print(self.b))
1266         }
1267     }
1268 }
1269
1270 define_print! {
1271     ('tcx) ty::TraitPredicate<'tcx>, (self, cx) {
1272         debug {
1273             p!(write("TraitPredicate({:?})",
1274                    self.trait_ref))
1275         }
1276         display {
1277             p!(print(self.trait_ref.self_ty()), write(": "), print(self.trait_ref))
1278         }
1279     }
1280 }
1281
1282 define_print! {
1283     ('tcx) ty::ProjectionPredicate<'tcx>, (self, cx) {
1284         debug {
1285             p!(
1286                    write("ProjectionPredicate("),
1287                    print(self.projection_ty),
1288                    write(", "),
1289                    print(self.ty),
1290                    write(")"))
1291         }
1292         display {
1293             p!(print(self.projection_ty), write(" == "), print(self.ty))
1294         }
1295     }
1296 }
1297
1298 define_print! {
1299     ('tcx) ty::ProjectionTy<'tcx>, (self, cx) {
1300         display {
1301             nest!(|cx| cx.print_def_path(
1302                 self.item_def_id,
1303                 Some(self.substs),
1304                 Namespace::TypeNS,
1305                 iter::empty(),
1306             ));
1307         }
1308     }
1309 }
1310
1311 define_print! {
1312     () ty::ClosureKind, (self, cx) {
1313         display {
1314             match *self {
1315                 ty::ClosureKind::Fn => p!(write("Fn")),
1316                 ty::ClosureKind::FnMut => p!(write("FnMut")),
1317                 ty::ClosureKind::FnOnce => p!(write("FnOnce")),
1318             }
1319         }
1320     }
1321 }
1322
1323 define_print! {
1324     ('tcx) ty::Predicate<'tcx>, (self, cx) {
1325         display {
1326             match *self {
1327                 ty::Predicate::Trait(ref data) => p!(print(data)),
1328                 ty::Predicate::Subtype(ref predicate) => p!(print(predicate)),
1329                 ty::Predicate::RegionOutlives(ref predicate) => p!(print(predicate)),
1330                 ty::Predicate::TypeOutlives(ref predicate) => p!(print(predicate)),
1331                 ty::Predicate::Projection(ref predicate) => p!(print(predicate)),
1332                 ty::Predicate::WellFormed(ty) => p!(print(ty), write(" well-formed")),
1333                 ty::Predicate::ObjectSafe(trait_def_id) => {
1334                     p!(write("the trait `"));
1335                     nest!(|cx| cx.print_def_path(
1336                         trait_def_id,
1337                         None,
1338                         Namespace::TypeNS,
1339                         iter::empty(),
1340                     ));
1341                     p!(write("` is object-safe"))
1342                 }
1343                 ty::Predicate::ClosureKind(closure_def_id, _closure_substs, kind) => {
1344                     p!(write("the closure `"));
1345                     nest!(|cx| cx.print_def_path(
1346                         closure_def_id,
1347                         None,
1348                         Namespace::ValueNS,
1349                         iter::empty(),
1350                     ));
1351                     p!(write("` implements the trait `{}`", kind))
1352                 }
1353                 ty::Predicate::ConstEvaluatable(def_id, substs) => {
1354                     p!(write("the constant `"));
1355                     nest!(|cx| cx.print_def_path(
1356                         def_id,
1357                         Some(substs),
1358                         Namespace::ValueNS,
1359                         iter::empty(),
1360                     ));
1361                     p!(write("` can be evaluated"))
1362                 }
1363             }
1364         }
1365         debug {
1366             match *self {
1367                 ty::Predicate::Trait(ref a) => p!(print(a)),
1368                 ty::Predicate::Subtype(ref pair) => p!(print(pair)),
1369                 ty::Predicate::RegionOutlives(ref pair) => p!(print(pair)),
1370                 ty::Predicate::TypeOutlives(ref pair) => p!(print(pair)),
1371                 ty::Predicate::Projection(ref pair) => p!(print(pair)),
1372                 ty::Predicate::WellFormed(ty) => p!(print(ty)),
1373                 ty::Predicate::ObjectSafe(trait_def_id) => {
1374                     p!(write("ObjectSafe({:?})", trait_def_id))
1375                 }
1376                 ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
1377                     p!(write("ClosureKind({:?}, {:?}, {:?})",
1378                         closure_def_id, closure_substs, kind))
1379                 }
1380                 ty::Predicate::ConstEvaluatable(def_id, substs) => {
1381                     p!(write("ConstEvaluatable({:?}, {:?})", def_id, substs))
1382                 }
1383             }
1384         }
1385     }
1386 }
1387
1388 define_print! {
1389     ('tcx) Kind<'tcx>, (self, cx) {
1390         display {
1391             match self.unpack() {
1392                 UnpackedKind::Lifetime(lt) => p!(print(lt)),
1393                 UnpackedKind::Type(ty) => p!(print(ty)),
1394                 UnpackedKind::Const(ct) => p!(print(ct)),
1395             }
1396         }
1397         debug {
1398             match self.unpack() {
1399                 UnpackedKind::Lifetime(lt) => p!(print(lt)),
1400                 UnpackedKind::Type(ty) => p!(print(ty)),
1401                 UnpackedKind::Const(ct) => p!(print(ct)),
1402             }
1403         }
1404     }
1405 }