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