]> git.lizzy.rs Git - rust.git/blob - src/librustc/ty/print/pretty.rs
rustc: remove obsolete hacks from ppaux, relating to normalization under HRTB.
[rust.git] / src / librustc / ty / print / pretty.rs
1 use crate::hir;
2 use crate::hir::def::Namespace;
3 use crate::hir::map::DefPathData;
4 use crate::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
5 use crate::middle::cstore::{ExternCrate, ExternCrateSource};
6 use crate::middle::region;
7 use crate::ty::{self, DefIdTree, ParamConst, Ty, TyCtxt, TypeFoldable};
8 use crate::ty::subst::{Kind, Subst, SubstsRef, UnpackedKind};
9 use crate::mir::interpret::ConstValue;
10 use syntax::symbol::{keywords, Symbol};
11
12 use syntax::symbol::InternedString;
13
14 use std::cell::Cell;
15 use std::fmt::{self, Write as _};
16 use std::iter;
17
18 // `pretty` is a separate module only for organization.
19 use super::*;
20
21 macro_rules! nest {
22     ($closure:expr) => {
23         scoped_cx!() = scoped_cx!().nest($closure)?
24     }
25 }
26 macro_rules! print_inner {
27     (write ($($data:expr),+)) => {
28         write!(scoped_cx!().printer, $($data),+)?
29     };
30     ($kind:ident ($data:expr)) => {
31         nest!(|cx| $data.$kind(cx))
32     };
33 }
34 macro_rules! p {
35     ($($kind:ident $data:tt),+) => {
36         {
37             $(print_inner!($kind $data));+
38         }
39     };
40 }
41 macro_rules! define_scoped_cx {
42     ($cx:ident) => {
43         #[allow(unused_macros)]
44         macro_rules! scoped_cx {
45             () => ($cx)
46         }
47     };
48 }
49
50 thread_local! {
51     static FORCE_IMPL_FILENAME_LINE: Cell<bool> = Cell::new(false);
52     static SHOULD_PREFIX_WITH_CRATE: Cell<bool> = Cell::new(false);
53 }
54
55 /// Force us to name impls with just the filename/line number. We
56 /// normally try to use types. But at some points, notably while printing
57 /// cycle errors, this can result in extra or suboptimal error output,
58 /// so this variable disables that check.
59 pub fn with_forced_impl_filename_line<F: FnOnce() -> R, R>(f: F) -> R {
60     FORCE_IMPL_FILENAME_LINE.with(|force| {
61         let old = force.get();
62         force.set(true);
63         let result = f();
64         force.set(old);
65         result
66     })
67 }
68
69 /// Adds the `crate::` prefix to paths where appropriate.
70 pub fn with_crate_prefix<F: FnOnce() -> R, R>(f: F) -> R {
71     SHOULD_PREFIX_WITH_CRATE.with(|flag| {
72         let old = flag.get();
73         flag.set(true);
74         let result = f();
75         flag.set(old);
76         result
77     })
78 }
79
80 /// The "region highlights" are used to control region printing during
81 /// specific error messages. When a "region highlight" is enabled, it
82 /// gives an alternate way to print specific regions. For now, we
83 /// always print those regions using a number, so something like "`'0`".
84 ///
85 /// Regions not selected by the region highlight mode are presently
86 /// unaffected.
87 #[derive(Copy, Clone, Default)]
88 pub struct RegionHighlightMode {
89     /// If enabled, when we see the selected region, use "`'N`"
90     /// instead of the ordinary behavior.
91     highlight_regions: [Option<(ty::RegionKind, usize)>; 3],
92
93     /// If enabled, when printing a "free region" that originated from
94     /// the given `ty::BoundRegion`, print it as "`'1`". Free regions that would ordinarily
95     /// have names print as normal.
96     ///
97     /// This is used when you have a signature like `fn foo(x: &u32,
98     /// y: &'a u32)` and we want to give a name to the region of the
99     /// reference `x`.
100     highlight_bound_region: Option<(ty::BoundRegion, usize)>,
101 }
102
103 impl RegionHighlightMode {
104     /// If `region` and `number` are both `Some`, invokes
105     /// `highlighting_region`.
106     pub fn maybe_highlighting_region(
107         &mut self,
108         region: Option<ty::Region<'_>>,
109         number: Option<usize>,
110     ) {
111         if let Some(k) = region {
112             if let Some(n) = number {
113                 self.highlighting_region(k, n);
114             }
115         }
116     }
117
118     /// Highlights the region inference variable `vid` as `'N`.
119     pub fn highlighting_region(
120         &mut self,
121         region: ty::Region<'_>,
122         number: usize,
123     ) {
124         let num_slots = self.highlight_regions.len();
125         let first_avail_slot = self.highlight_regions.iter_mut()
126             .filter(|s| s.is_none())
127             .next()
128             .unwrap_or_else(|| {
129                 bug!(
130                     "can only highlight {} placeholders at a time",
131                     num_slots,
132                 )
133             });
134         *first_avail_slot = Some((*region, number));
135     }
136
137     /// Convenience wrapper for `highlighting_region`.
138     pub fn highlighting_region_vid(
139         &mut self,
140         vid: ty::RegionVid,
141         number: usize,
142     ) {
143         self.highlighting_region(&ty::ReVar(vid), number)
144     }
145
146     /// Returns `Some(n)` with the number to use for the given region, if any.
147     fn region_highlighted(&self, region: ty::Region<'_>) -> Option<usize> {
148         self
149             .highlight_regions
150             .iter()
151             .filter_map(|h| match h {
152                 Some((r, n)) if r == region => Some(*n),
153                 _ => None,
154             })
155             .next()
156     }
157
158     /// Highlight the given bound region.
159     /// We can only highlight one bound region at a time. See
160     /// the field `highlight_bound_region` for more detailed notes.
161     pub fn highlighting_bound_region(
162         &mut self,
163         br: ty::BoundRegion,
164         number: usize,
165     ) {
166         assert!(self.highlight_bound_region.is_none());
167         self.highlight_bound_region = Some((br, number));
168     }
169 }
170
171 /// Trait for printers that pretty-print using `fmt::Write` to the printer.
172 pub trait PrettyPrinter:
173     Printer<
174         Error = fmt::Error,
175         Path = Self,
176         Region = Self,
177         Type = Self,
178     > +
179     fmt::Write
180 {
181     /// Enter a nested print context, for pretty-printing
182     /// nested components in some larger context.
183     fn nest<'a, 'gcx, 'tcx, E>(
184         self: PrintCx<'a, 'gcx, 'tcx, Self>,
185         f: impl FnOnce(PrintCx<'_, 'gcx, 'tcx, Self>) -> Result<Self, E>,
186     ) -> Result<PrintCx<'a, 'gcx, 'tcx, Self>, E> {
187         let printer = f(PrintCx {
188             tcx: self.tcx,
189             printer: self.printer,
190             config: self.config,
191         })?;
192         Ok(PrintCx {
193             tcx: self.tcx,
194             printer,
195             config: self.config,
196         })
197     }
198
199     /// Like `print_def_path` but for value paths.
200     fn print_value_path(
201         self: PrintCx<'_, '_, 'tcx, Self>,
202         def_id: DefId,
203         substs: Option<SubstsRef<'tcx>>,
204     ) -> Result<Self::Path, Self::Error> {
205         self.print_def_path(def_id, substs, iter::empty())
206     }
207
208     fn in_binder<T>(
209         self: PrintCx<'_, '_, 'tcx, Self>,
210         value: &ty::Binder<T>,
211     ) -> Result<Self, Self::Error>
212         where T: Print<'tcx, Self, Output = Self, Error = Self::Error> + TypeFoldable<'tcx>
213     {
214         value.skip_binder().print(self)
215     }
216
217     /// Print `<...>` around what `f` prints.
218     fn generic_delimiters<'gcx, 'tcx>(
219         self: PrintCx<'_, 'gcx, 'tcx, Self>,
220         f: impl FnOnce(PrintCx<'_, 'gcx, 'tcx, Self>) -> Result<Self, Self::Error>,
221     ) -> Result<Self, Self::Error>;
222
223     /// Return `true` if the region should be printed in path generic args
224     /// even when it's `'_`, such as in e.g. `Foo<'_, '_, '_>`.
225     fn always_print_region_in_paths(
226         self: &PrintCx<'_, '_, '_, Self>,
227         _region: ty::Region<'_>,
228     ) -> bool {
229         false
230     }
231
232     // HACK(eddyb) Trying to print a lifetime might not print anything, which
233     // may need special handling in the caller (of `ty::RegionKind::print`).
234     // To avoid printing to a temporary string (which isn't even supported),
235     // the `print_region_outputs_anything` method can instead be used to
236     // determine this, ahead of time.
237     //
238     // NB: this must be kept in sync with the implementation of `print_region`.
239     fn print_region_outputs_anything(
240         self: &PrintCx<'_, '_, '_, Self>,
241         region: ty::Region<'_>,
242     ) -> bool;
243 }
244
245 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
246     // HACK(eddyb) get rid of `def_path_str` and/or pass `Namespace` explicitly always
247     // (but also some things just print a `DefId` generally so maybe we need this?)
248     fn guess_def_namespace(self, def_id: DefId) -> Namespace {
249         match self.def_key(def_id).disambiguated_data.data {
250             DefPathData::ValueNs(..) |
251             DefPathData::EnumVariant(..) |
252             DefPathData::Field(..) |
253             DefPathData::AnonConst |
254             DefPathData::ConstParam(..) |
255             DefPathData::ClosureExpr |
256             DefPathData::StructCtor => Namespace::ValueNS,
257
258             DefPathData::MacroDef(..) => Namespace::MacroNS,
259
260             _ => Namespace::TypeNS,
261         }
262     }
263
264     /// Returns a string identifying this `DefId. This string is
265     /// suitable for user output.
266     pub fn def_path_str(self, def_id: DefId) -> String {
267         let ns = self.guess_def_namespace(def_id);
268         debug!("def_path_str: def_id={:?}, ns={:?}", def_id, ns);
269         let mut s = String::new();
270         let _ = PrintCx::with(self, FmtPrinter::new(&mut s, ns), |cx| {
271             cx.print_def_path(def_id, None, iter::empty())
272         });
273         s
274     }
275 }
276
277 pub struct FmtPrinter<F: fmt::Write> {
278     fmt: F,
279     empty: bool,
280     in_value: bool,
281     pub region_highlight_mode: RegionHighlightMode,
282 }
283
284 impl<F: fmt::Write> FmtPrinter<F> {
285     pub fn new(fmt: F, ns: Namespace) -> Self {
286         FmtPrinter {
287             fmt,
288             empty: true,
289             in_value: ns == Namespace::ValueNS,
290             region_highlight_mode: RegionHighlightMode::default(),
291         }
292     }
293 }
294
295 impl<'gcx, 'tcx, P: PrettyPrinter> PrintCx<'_, 'gcx, 'tcx, P> {
296     /// If possible, this returns a global path resolving to `def_id` that is visible
297     /// from at least one local module and returns true. If the crate defining `def_id` is
298     /// declared with an `extern crate`, the path is guaranteed to use the `extern crate`.
299     fn try_print_visible_def_path(
300         mut self,
301         def_id: DefId,
302     ) -> Result<(P, bool), P::Error> {
303         define_scoped_cx!(self);
304
305         debug!("try_print_visible_def_path: def_id={:?}", def_id);
306
307         // If `def_id` is a direct or injected extern crate, return the
308         // path to the crate followed by the path to the item within the crate.
309         if def_id.index == CRATE_DEF_INDEX {
310             let cnum = def_id.krate;
311
312             if cnum == LOCAL_CRATE {
313                 return Ok((self.path_crate(cnum)?, true));
314             }
315
316             // In local mode, when we encounter a crate other than
317             // LOCAL_CRATE, execution proceeds in one of two ways:
318             //
319             // 1. for a direct dependency, where user added an
320             //    `extern crate` manually, we put the `extern
321             //    crate` as the parent. So you wind up with
322             //    something relative to the current crate.
323             // 2. for an extern inferred from a path or an indirect crate,
324             //    where there is no explicit `extern crate`, we just prepend
325             //    the crate name.
326             match *self.tcx.extern_crate(def_id) {
327                 Some(ExternCrate {
328                     src: ExternCrateSource::Extern(def_id),
329                     direct: true,
330                     span,
331                     ..
332                 }) => {
333                     debug!("try_print_visible_def_path: def_id={:?}", def_id);
334                     return Ok((if !span.is_dummy() {
335                         self.print_def_path(def_id, None, iter::empty())?
336                     } else {
337                         self.path_crate(cnum)?
338                     }, true));
339                 }
340                 None => {
341                     return Ok((self.path_crate(cnum)?, true));
342                 }
343                 _ => {},
344             }
345         }
346
347         if def_id.is_local() {
348             return Ok((self.printer, false));
349         }
350
351         let visible_parent_map = self.tcx.visible_parent_map(LOCAL_CRATE);
352
353         let mut cur_def_key = self.tcx.def_key(def_id);
354         debug!("try_print_visible_def_path: cur_def_key={:?}", cur_def_key);
355
356         // For a UnitStruct or TupleStruct we want the name of its parent rather than <unnamed>.
357         if let DefPathData::StructCtor = cur_def_key.disambiguated_data.data {
358             let parent = DefId {
359                 krate: def_id.krate,
360                 index: cur_def_key.parent.expect("DefPathData::StructCtor missing a parent"),
361             };
362
363             cur_def_key = self.tcx.def_key(parent);
364         }
365
366         let visible_parent = match visible_parent_map.get(&def_id).cloned() {
367             Some(parent) => parent,
368             None => return Ok((self.printer, false)),
369         };
370         // HACK(eddyb) this uses `nest` to avoid knowing ahead of time whether
371         // the entire path will succeed or not. To support printers that do not
372         // implement `PrettyPrinter`, a `Vec` or linked list on the stack would
373         // need to be built, before starting to print anything.
374         let mut prefix_success = false;
375         nest!(|cx| {
376             let (printer, success) = cx.try_print_visible_def_path(visible_parent)?;
377             prefix_success = success;
378             Ok(printer)
379         });
380         if !prefix_success {
381             return Ok((self.printer, false));
382         };
383         let actual_parent = self.tcx.parent(def_id);
384         debug!(
385             "try_print_visible_def_path: visible_parent={:?} actual_parent={:?}",
386             visible_parent, actual_parent,
387         );
388
389         let data = cur_def_key.disambiguated_data.data;
390         debug!(
391             "try_print_visible_def_path: data={:?} visible_parent={:?} actual_parent={:?}",
392             data, visible_parent, actual_parent,
393         );
394
395         let symbol = match data {
396             // In order to output a path that could actually be imported (valid and visible),
397             // we need to handle re-exports correctly.
398             //
399             // For example, take `std::os::unix::process::CommandExt`, this trait is actually
400             // defined at `std::sys::unix::ext::process::CommandExt` (at time of writing).
401             //
402             // `std::os::unix` rexports the contents of `std::sys::unix::ext`. `std::sys` is
403             // private so the "true" path to `CommandExt` isn't accessible.
404             //
405             // In this case, the `visible_parent_map` will look something like this:
406             //
407             // (child) -> (parent)
408             // `std::sys::unix::ext::process::CommandExt` -> `std::sys::unix::ext::process`
409             // `std::sys::unix::ext::process` -> `std::sys::unix::ext`
410             // `std::sys::unix::ext` -> `std::os`
411             //
412             // This is correct, as the visible parent of `std::sys::unix::ext` is in fact
413             // `std::os`.
414             //
415             // When printing the path to `CommandExt` and looking at the `cur_def_key` that
416             // corresponds to `std::sys::unix::ext`, we would normally print `ext` and then go
417             // to the parent - resulting in a mangled path like
418             // `std::os::ext::process::CommandExt`.
419             //
420             // Instead, we must detect that there was a re-export and instead print `unix`
421             // (which is the name `std::sys::unix::ext` was re-exported as in `std::os`). To
422             // do this, we compare the parent of `std::sys::unix::ext` (`std::sys::unix`) with
423             // the visible parent (`std::os`). If these do not match, then we iterate over
424             // the children of the visible parent (as was done when computing
425             // `visible_parent_map`), looking for the specific child we currently have and then
426             // have access to the re-exported name.
427             DefPathData::Module(actual_name) |
428             DefPathData::TypeNs(actual_name) if Some(visible_parent) != actual_parent => {
429                 self.tcx.item_children(visible_parent)
430                     .iter()
431                     .find(|child| child.def.def_id() == def_id)
432                     .map(|child| child.ident.as_str())
433                     .unwrap_or_else(|| actual_name.as_str())
434             }
435             _ => {
436                 data.get_opt_name().map(|n| n.as_str()).unwrap_or_else(|| {
437                     // Re-exported `extern crate` (#43189).
438                     if let DefPathData::CrateRoot = data {
439                         self.tcx.original_crate_name(def_id.krate).as_str()
440                     } else {
441                         Symbol::intern("<unnamed>").as_str()
442                     }
443                 })
444             },
445         };
446         debug!("try_print_visible_def_path: symbol={:?}", symbol);
447         Ok((self.path_append(|cx| Ok(cx.printer), &symbol)?, true))
448     }
449
450     pub fn pretty_path_qualified(
451         self,
452         self_ty: Ty<'tcx>,
453         trait_ref: Option<ty::TraitRef<'tcx>>,
454     ) -> Result<P::Path, P::Error> {
455         if trait_ref.is_none() {
456             // Inherent impls. Try to print `Foo::bar` for an inherent
457             // impl on `Foo`, but fallback to `<Foo>::bar` if self-type is
458             // anything other than a simple path.
459             match self_ty.sty {
460                 ty::Adt(..) | ty::Foreign(_) |
461                 ty::Bool | ty::Char | ty::Str |
462                 ty::Int(_) | ty::Uint(_) | ty::Float(_) => {
463                     return self_ty.print(self);
464                 }
465
466                 _ => {}
467             }
468         }
469
470         self.generic_delimiters(|mut cx| {
471             define_scoped_cx!(cx);
472
473             p!(print(self_ty));
474             if let Some(trait_ref) = trait_ref {
475                 p!(write(" as "), print(trait_ref));
476             }
477             Ok(cx.printer)
478         })
479     }
480
481     pub fn pretty_path_append_impl(
482         mut self,
483         print_prefix: impl FnOnce(
484             PrintCx<'_, 'gcx, 'tcx, P>,
485         ) -> Result<P::Path, P::Error>,
486         self_ty: Ty<'tcx>,
487         trait_ref: Option<ty::TraitRef<'tcx>>,
488     ) -> Result<P::Path, P::Error> {
489         self = self.nest(print_prefix)?;
490
491         self.generic_delimiters(|mut cx| {
492             define_scoped_cx!(cx);
493
494             p!(write("impl "));
495             if let Some(trait_ref) = trait_ref {
496                 p!(print(trait_ref), write(" for "));
497             }
498             p!(print(self_ty));
499
500             Ok(cx.printer)
501         })
502     }
503
504     pub fn pretty_path_generic_args(
505         mut self,
506         print_prefix: impl FnOnce(
507             PrintCx<'_, 'gcx, 'tcx, P>,
508         ) -> Result<P::Path, P::Error>,
509         params: &[ty::GenericParamDef],
510         substs: SubstsRef<'tcx>,
511         projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
512     ) -> Result<P::Path, P::Error> {
513         self = self.nest(print_prefix)?;
514
515         // Don't print `'_` if there's no printed region.
516         let print_regions = params.iter().any(|param| {
517             match substs[param.index as usize].unpack() {
518                 UnpackedKind::Lifetime(r) => {
519                     self.always_print_region_in_paths(r) ||
520                     self.print_region_outputs_anything(r)
521                 }
522                 _ => false,
523             }
524         });
525
526         // Don't print args that are the defaults of their respective parameters.
527         let num_supplied_defaults = if self.tcx.sess.verbose() {
528             0
529         } else {
530             params.iter().rev().take_while(|param| {
531                 match param.kind {
532                     ty::GenericParamDefKind::Lifetime => false,
533                     ty::GenericParamDefKind::Type { has_default, .. } => {
534                         has_default && substs[param.index as usize] == Kind::from(
535                             self.tcx.type_of(param.def_id).subst(self.tcx, substs)
536                         )
537                     }
538                     ty::GenericParamDefKind::Const => false, // FIXME(const_generics:defaults)
539                 }
540             }).count()
541         };
542
543         let params = &params[..params.len() - num_supplied_defaults];
544         let mut args = params.iter().map(|param| {
545             substs[param.index as usize]
546         }).filter(|arg| {
547             match arg.unpack() {
548                 UnpackedKind::Lifetime(_) => print_regions,
549                 _ => true,
550             }
551         });
552         let arg0 = args.next();
553
554         let mut projections = projections;
555         let projection0 = projections.next();
556
557         if arg0.is_none() && projection0.is_none() {
558             return Ok(self.printer);
559         }
560
561         self.generic_delimiters(|mut cx| {
562             define_scoped_cx!(cx);
563
564             let mut empty = true;
565             let mut maybe_comma = |cx: &mut Self| {
566                 if empty {
567                     empty = false;
568                     Ok(())
569                 } else {
570                     write!(cx.printer, ", ")
571                 }
572             };
573
574             for arg in arg0.into_iter().chain(args) {
575                 maybe_comma(&mut cx)?;
576
577                 if let UnpackedKind::Lifetime(region) = arg.unpack() {
578                     if !cx.print_region_outputs_anything(region) {
579                         // This happens when the value of the region
580                         // parameter is not easily serialized. This may be
581                         // because the user omitted it in the first place,
582                         // or because it refers to some block in the code,
583                         // etc. I'm not sure how best to serialize this.
584                         p!(write("'_"));
585
586                         continue;
587                     }
588                 }
589
590                 p!(print(arg));
591             }
592
593             for projection in projection0.into_iter().chain(projections) {
594                 maybe_comma(&mut cx)?;
595
596                 p!(write("{}=", cx.tcx.associated_item(projection.item_def_id).ident),
597                    print(projection.ty));
598             }
599
600             Ok(cx.printer)
601         })
602     }
603 }
604
605 impl<F: fmt::Write> fmt::Write for FmtPrinter<F> {
606     fn write_str(&mut self, s: &str) -> fmt::Result {
607         self.empty &= s.is_empty();
608         self.fmt.write_str(s)
609     }
610 }
611
612 impl<F: fmt::Write> Printer for FmtPrinter<F> {
613     type Error = fmt::Error;
614
615     type Path = Self;
616     type Region = Self;
617     type Type = Self;
618
619     fn print_def_path(
620         mut self: PrintCx<'_, '_, 'tcx, Self>,
621         def_id: DefId,
622         substs: Option<SubstsRef<'tcx>>,
623         projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
624     ) -> Result<Self::Path, Self::Error> {
625         // FIXME(eddyb) avoid querying `tcx.generics_of` and `tcx.def_key`
626         // both here and in `default_print_def_path`.
627         let generics = substs.map(|_| self.tcx.generics_of(def_id));
628         if generics.as_ref().and_then(|g| g.parent).is_none() {
629             let mut visible_path_success = false;
630             self = self.nest(|cx| {
631                 let (printer, success) = cx.try_print_visible_def_path(def_id)?;
632                 visible_path_success = success;
633                 Ok(printer)
634             })?;
635             if visible_path_success {
636                 return if let (Some(generics), Some(substs)) = (generics, substs) {
637                     let has_own_self = generics.has_self && generics.parent_count == 0;
638                     let params = &generics.params[has_own_self as usize..];
639                     self.path_generic_args(|cx| Ok(cx.printer), params, substs, projections)
640                 } else {
641                     Ok(self.printer)
642                 };
643             }
644         }
645
646         let key = self.tcx.def_key(def_id);
647         if let DefPathData::Impl = key.disambiguated_data.data {
648             // Always use types for non-local impls, where types are always
649             // available, and filename/line-number is mostly uninteresting.
650             let use_types =
651                 !def_id.is_local() || {
652                     // Otherwise, use filename/line-number if forced.
653                     let force_no_types = FORCE_IMPL_FILENAME_LINE.with(|f| f.get());
654                     !force_no_types
655                 };
656
657             if !use_types {
658                 // If no type info is available, fall back to
659                 // pretty printing some span information. This should
660                 // only occur very early in the compiler pipeline.
661                 let parent_def_id = DefId { index: key.parent.unwrap(), ..def_id };
662                 let span = self.tcx.def_span(def_id);
663                 return self.path_append(
664                     |cx| cx.print_def_path(parent_def_id, None, iter::empty()),
665                     &format!("<impl at {:?}>", span),
666                 );
667             }
668         }
669
670         self.default_print_def_path(def_id, substs, projections)
671     }
672
673     fn print_region(
674         self: PrintCx<'_, '_, '_, Self>,
675         region: ty::Region<'_>,
676     ) -> Result<Self::Region, Self::Error> {
677         self.pretty_print_region(region)
678     }
679
680     fn print_type(
681         self: PrintCx<'_, '_, 'tcx, Self>,
682         ty: Ty<'tcx>,
683     ) -> Result<Self::Type, Self::Error> {
684         self.pretty_print_type(ty)
685     }
686
687     fn path_crate(
688         mut self: PrintCx<'_, '_, '_, Self>,
689         cnum: CrateNum,
690     ) -> Result<Self::Path, Self::Error> {
691         if cnum == LOCAL_CRATE {
692             if self.tcx.sess.rust_2018() {
693                 // We add the `crate::` keyword on Rust 2018, only when desired.
694                 if SHOULD_PREFIX_WITH_CRATE.with(|flag| flag.get()) {
695                     write!(self.printer, "{}", keywords::Crate.name())?;
696                 }
697             }
698             Ok(self.printer)
699         } else {
700             write!(self.printer, "{}", self.tcx.crate_name(cnum))?;
701             Ok(self.printer)
702         }
703     }
704     fn path_qualified(
705         self: PrintCx<'_, '_, 'tcx, Self>,
706         self_ty: Ty<'tcx>,
707         trait_ref: Option<ty::TraitRef<'tcx>>,
708     ) -> Result<Self::Path, Self::Error> {
709         self.pretty_path_qualified(self_ty, trait_ref)
710     }
711
712     fn path_append_impl<'gcx, 'tcx>(
713         self: PrintCx<'_, 'gcx, 'tcx, Self>,
714         print_prefix: impl FnOnce(
715             PrintCx<'_, 'gcx, 'tcx, Self>,
716         ) -> Result<Self::Path, Self::Error>,
717         self_ty: Ty<'tcx>,
718         trait_ref: Option<ty::TraitRef<'tcx>>,
719     ) -> Result<Self::Path, Self::Error> {
720         self.pretty_path_append_impl(|cx| {
721             let mut printer = print_prefix(cx)?;
722
723             // HACK(eddyb) this accounts for `generic_delimiters`
724             // printing `::<` instead of `<` if `in_value` is set.
725             if !printer.empty && !printer.in_value {
726                 write!(printer, "::")?;
727             }
728
729             Ok(printer)
730         }, self_ty, trait_ref)
731     }
732     fn path_append<'gcx, 'tcx>(
733         self: PrintCx<'_, 'gcx, 'tcx, Self>,
734         print_prefix: impl FnOnce(
735             PrintCx<'_, 'gcx, 'tcx, Self>,
736         ) -> Result<Self::Path, Self::Error>,
737         text: &str,
738     ) -> Result<Self::Path, Self::Error> {
739         let mut printer = print_prefix(self)?;
740
741         // FIXME(eddyb) `text` should never be empty, but it
742         // currently is for `extern { ... }` "foreign modules".
743         if !text.is_empty() {
744             if !printer.empty {
745                 write!(printer, "::")?;
746             }
747             write!(printer, "{}", text)?;
748         }
749
750         Ok(printer)
751     }
752     fn path_generic_args<'gcx, 'tcx>(
753         self: PrintCx<'_, 'gcx, 'tcx, Self>,
754         print_prefix: impl FnOnce(
755             PrintCx<'_, 'gcx, 'tcx, Self>,
756         ) -> Result<Self::Path, Self::Error>,
757         params: &[ty::GenericParamDef],
758         substs: SubstsRef<'tcx>,
759         projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
760     ) -> Result<Self::Path, Self::Error> {
761         self.pretty_path_generic_args(print_prefix, params, substs, projections)
762     }
763 }
764
765 impl<F: fmt::Write> PrettyPrinter for FmtPrinter<F> {
766     fn nest<'a, 'gcx, 'tcx, E>(
767         mut self: PrintCx<'a, 'gcx, 'tcx, Self>,
768         f: impl FnOnce(PrintCx<'_, 'gcx, 'tcx, Self>) -> Result<Self, E>,
769     ) -> Result<PrintCx<'a, 'gcx, 'tcx, Self>, E> {
770         let was_empty = std::mem::replace(&mut self.printer.empty, true);
771         let mut printer = f(PrintCx {
772             tcx: self.tcx,
773             printer: self.printer,
774             config: self.config,
775         })?;
776         printer.empty &= was_empty;
777         Ok(PrintCx {
778             tcx: self.tcx,
779             printer,
780             config: self.config,
781         })
782     }
783
784     fn print_value_path(
785         mut self: PrintCx<'_, '_, 'tcx, Self>,
786         def_id: DefId,
787         substs: Option<SubstsRef<'tcx>>,
788     ) -> Result<Self::Path, Self::Error> {
789         let was_in_value = std::mem::replace(&mut self.printer.in_value, true);
790         let mut printer = self.print_def_path(def_id, substs, iter::empty())?;
791         printer.in_value = was_in_value;
792
793         Ok(printer)
794     }
795
796     fn in_binder<T>(
797         self: PrintCx<'_, '_, 'tcx, Self>,
798         value: &ty::Binder<T>,
799     ) -> Result<Self, Self::Error>
800         where T: Print<'tcx, Self, Output = Self, Error = Self::Error> + TypeFoldable<'tcx>
801     {
802         self.pretty_in_binder(value)
803     }
804
805     fn generic_delimiters<'gcx, 'tcx>(
806         mut self: PrintCx<'_, 'gcx, 'tcx, Self>,
807         f: impl FnOnce(PrintCx<'_, 'gcx, 'tcx, Self>) -> Result<Self, Self::Error>,
808     ) -> Result<Self, Self::Error> {
809         if !self.printer.empty && self.printer.in_value {
810             write!(self.printer, "::<")?;
811         } else {
812             write!(self.printer, "<")?;
813         }
814
815         let was_in_value = std::mem::replace(&mut self.printer.in_value, false);
816         let mut printer = f(self)?;
817         printer.in_value = was_in_value;
818
819         write!(printer, ">")?;
820         Ok(printer)
821     }
822
823     fn always_print_region_in_paths(
824         self: &PrintCx<'_, '_, '_, Self>,
825         region: ty::Region<'_>,
826     ) -> bool {
827         *region != ty::ReErased
828     }
829
830     fn print_region_outputs_anything(
831         self: &PrintCx<'_, '_, '_, Self>,
832         region: ty::Region<'_>,
833     ) -> bool {
834         let highlight = self.printer.region_highlight_mode;
835         if highlight.region_highlighted(region).is_some() {
836             return true;
837         }
838
839         if self.tcx.sess.verbose() {
840             return true;
841         }
842
843         let identify_regions = self.tcx.sess.opts.debugging_opts.identify_regions;
844
845         match *region {
846             ty::ReEarlyBound(ref data) => {
847                 data.name != "" && data.name != "'_"
848             }
849
850             ty::ReLateBound(_, br) |
851             ty::ReFree(ty::FreeRegion { bound_region: br, .. }) |
852             ty::RePlaceholder(ty::Placeholder { name: br, .. }) => {
853                 if let ty::BrNamed(_, name) = br {
854                     if name != "" && name != "'_" {
855                         return true;
856                     }
857                 }
858
859                 if let Some((region, _)) = highlight.highlight_bound_region {
860                     if br == region {
861                         return true;
862                     }
863                 }
864
865                 false
866             }
867
868             ty::ReScope(_) |
869             ty::ReVar(_) if identify_regions => true,
870
871             ty::ReVar(_) |
872             ty::ReScope(_) |
873             ty::ReErased => false,
874
875             ty::ReStatic |
876             ty::ReEmpty |
877             ty::ReClosureBound(_) => true,
878         }
879     }
880 }
881
882 // HACK(eddyb) limited to `FmtPrinter` because of `region_highlight_mode`.
883 impl<F: fmt::Write> FmtPrinter<F> {
884     pub fn pretty_print_region(
885         mut self: PrintCx<'_, '_, '_, Self>,
886         region: ty::Region<'_>,
887     ) -> Result<Self, fmt::Error> {
888         define_scoped_cx!(self);
889
890         // Watch out for region highlights.
891         let highlight = self.printer.region_highlight_mode;
892         if let Some(n) = highlight.region_highlighted(region) {
893             p!(write("'{}", n));
894             return Ok(self.printer);
895         }
896
897         if self.tcx.sess.verbose() {
898             p!(write("{:?}", region));
899             return Ok(self.printer);
900         }
901
902         let identify_regions = self.tcx.sess.opts.debugging_opts.identify_regions;
903
904         // These printouts are concise.  They do not contain all the information
905         // the user might want to diagnose an error, but there is basically no way
906         // to fit that into a short string.  Hence the recommendation to use
907         // `explain_region()` or `note_and_explain_region()`.
908         match *region {
909             ty::ReEarlyBound(ref data) => {
910                 if data.name != "'_" {
911                     p!(write("{}", data.name));
912                 }
913             }
914             ty::ReLateBound(_, br) |
915             ty::ReFree(ty::FreeRegion { bound_region: br, .. }) |
916             ty::RePlaceholder(ty::Placeholder { name: br, .. }) => {
917                 if let ty::BrNamed(_, name) = br {
918                     if name != "" && name != "'_" {
919                         p!(write("{}", name));
920                         return Ok(self.printer);
921                     }
922                 }
923
924                 if let Some((region, counter)) = highlight.highlight_bound_region {
925                     if br == region {
926                         p!(write("'{}", counter));
927                     }
928                 }
929             }
930             ty::ReScope(scope) if identify_regions => {
931                 match scope.data {
932                     region::ScopeData::Node =>
933                         p!(write("'{}s", scope.item_local_id().as_usize())),
934                     region::ScopeData::CallSite =>
935                         p!(write("'{}cs", scope.item_local_id().as_usize())),
936                     region::ScopeData::Arguments =>
937                         p!(write("'{}as", scope.item_local_id().as_usize())),
938                     region::ScopeData::Destruction =>
939                         p!(write("'{}ds", scope.item_local_id().as_usize())),
940                     region::ScopeData::Remainder(first_statement_index) => p!(write(
941                         "'{}_{}rs",
942                         scope.item_local_id().as_usize(),
943                         first_statement_index.index()
944                     )),
945                 }
946             }
947             ty::ReVar(region_vid) if identify_regions => {
948                 p!(write("{:?}", region_vid));
949             }
950             ty::ReVar(_) => {}
951             ty::ReScope(_) |
952             ty::ReErased => {}
953             ty::ReStatic => p!(write("'static")),
954             ty::ReEmpty => p!(write("'<empty>")),
955
956             // The user should never encounter these in unsubstituted form.
957             ty::ReClosureBound(vid) => p!(write("{:?}", vid)),
958         }
959
960         Ok(self.printer)
961     }
962 }
963
964 impl<'gcx, 'tcx, P: PrettyPrinter> PrintCx<'_, 'gcx, 'tcx, P> {
965     pub fn pretty_print_type(
966         mut self,
967         ty: Ty<'tcx>,
968     ) -> Result<P::Type, P::Error> {
969         define_scoped_cx!(self);
970
971         match ty.sty {
972             ty::Bool => p!(write("bool")),
973             ty::Char => p!(write("char")),
974             ty::Int(t) => p!(write("{}", t.ty_to_string())),
975             ty::Uint(t) => p!(write("{}", t.ty_to_string())),
976             ty::Float(t) => p!(write("{}", t.ty_to_string())),
977             ty::RawPtr(ref tm) => {
978                 p!(write("*{} ", match tm.mutbl {
979                     hir::MutMutable => "mut",
980                     hir::MutImmutable => "const",
981                 }));
982                 p!(print(tm.ty))
983             }
984             ty::Ref(r, ty, mutbl) => {
985                 p!(write("&"));
986                 if self.print_region_outputs_anything(r) {
987                     p!(print(r), write(" "));
988                 }
989                 p!(print(ty::TypeAndMut { ty, mutbl }))
990             }
991             ty::Never => p!(write("!")),
992             ty::Tuple(ref tys) => {
993                 p!(write("("));
994                 let mut tys = tys.iter();
995                 if let Some(&ty) = tys.next() {
996                     p!(print(ty), write(","));
997                     if let Some(&ty) = tys.next() {
998                         p!(write(" "), print(ty));
999                         for &ty in tys {
1000                             p!(write(", "), print(ty));
1001                         }
1002                     }
1003                 }
1004                 p!(write(")"))
1005             }
1006             ty::FnDef(def_id, substs) => {
1007                 let sig = self.tcx.fn_sig(def_id).subst(self.tcx, substs);
1008                 p!(print(sig), write(" {{"));
1009                 nest!(|cx| cx.print_value_path(def_id, Some(substs)));
1010                 p!(write("}}"))
1011             }
1012             ty::FnPtr(ref bare_fn) => {
1013                 p!(print(bare_fn))
1014             }
1015             ty::Infer(infer_ty) => p!(write("{}", infer_ty)),
1016             ty::Error => p!(write("[type error]")),
1017             ty::Param(ref param_ty) => p!(write("{}", param_ty)),
1018             ty::Bound(debruijn, bound_ty) => {
1019                 match bound_ty.kind {
1020                     ty::BoundTyKind::Anon => {
1021                         if debruijn == ty::INNERMOST {
1022                             p!(write("^{}", bound_ty.var.index()))
1023                         } else {
1024                             p!(write("^{}_{}", debruijn.index(), bound_ty.var.index()))
1025                         }
1026                     }
1027
1028                     ty::BoundTyKind::Param(p) => p!(write("{}", p)),
1029                 }
1030             }
1031             ty::Adt(def, substs) => {
1032                 nest!(|cx| cx.print_def_path(def.did, Some(substs), iter::empty()));
1033             }
1034             ty::Dynamic(data, r) => {
1035                 let print_r = self.print_region_outputs_anything(r);
1036                 if print_r {
1037                     p!(write("("));
1038                 }
1039                 p!(write("dyn "), print(data));
1040                 if print_r {
1041                     p!(write(" + "), print(r), write(")"));
1042                 }
1043             }
1044             ty::Foreign(def_id) => {
1045                 nest!(|cx| cx.print_def_path(def_id, None, iter::empty()));
1046             }
1047             ty::Projection(ref data) => p!(print(data)),
1048             ty::UnnormalizedProjection(ref data) => {
1049                 p!(write("Unnormalized("), print(data), write(")"))
1050             }
1051             ty::Placeholder(placeholder) => {
1052                 p!(write("Placeholder({:?})", placeholder))
1053             }
1054             ty::Opaque(def_id, substs) => {
1055                 // FIXME(eddyb) print this with `print_def_path`.
1056                 if self.tcx.sess.verbose() {
1057                     p!(write("Opaque({:?}, {:?})", def_id, substs));
1058                     return Ok(self.printer);
1059                 }
1060
1061                 let def_key = self.tcx.def_key(def_id);
1062                 if let Some(name) = def_key.disambiguated_data.data.get_opt_name() {
1063                     p!(write("{}", name));
1064                     let mut substs = substs.iter();
1065                     // FIXME(eddyb) print this with `print_def_path`.
1066                     if let Some(first) = substs.next() {
1067                         p!(write("::<"));
1068                         p!(print(first));
1069                         for subst in substs {
1070                             p!(write(", "), print(subst));
1071                         }
1072                         p!(write(">"));
1073                     }
1074                     return Ok(self.printer);
1075                 }
1076                 // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
1077                 // by looking up the projections associated with the def_id.
1078                 let bounds = self.tcx.predicates_of(def_id).instantiate(self.tcx, substs);
1079
1080                 let mut first = true;
1081                 let mut is_sized = false;
1082                 p!(write("impl"));
1083                 for predicate in bounds.predicates {
1084                     if let Some(trait_ref) = predicate.to_opt_poly_trait_ref() {
1085                         // Don't print +Sized, but rather +?Sized if absent.
1086                         if Some(trait_ref.def_id()) == self.tcx.lang_items().sized_trait() {
1087                             is_sized = true;
1088                             continue;
1089                         }
1090
1091                         p!(
1092                                 write("{}", if first { " " } else { "+" }),
1093                                 print(trait_ref));
1094                         first = false;
1095                     }
1096                 }
1097                 if !is_sized {
1098                     p!(write("{}?Sized", if first { " " } else { "+" }));
1099                 } else if first {
1100                     p!(write(" Sized"));
1101                 }
1102             }
1103             ty::Str => p!(write("str")),
1104             ty::Generator(did, substs, movability) => {
1105                 let upvar_tys = substs.upvar_tys(did, self.tcx);
1106                 let witness = substs.witness(did, self.tcx);
1107                 if movability == hir::GeneratorMovability::Movable {
1108                     p!(write("[generator"));
1109                 } else {
1110                     p!(write("[static generator"));
1111                 }
1112
1113                 // FIXME(eddyb) should use `def_span`.
1114                 if let Some(hir_id) = self.tcx.hir().as_local_hir_id(did) {
1115                     p!(write("@{:?}", self.tcx.hir().span_by_hir_id(hir_id)));
1116                     let mut sep = " ";
1117                     for (freevar, upvar_ty) in self.tcx.freevars(did)
1118                         .as_ref()
1119                         .map_or(&[][..], |fv| &fv[..])
1120                         .iter()
1121                         .zip(upvar_tys)
1122                     {
1123                         p!(
1124                             write("{}{}:",
1125                                     sep,
1126                                     self.tcx.hir().name(freevar.var_id())),
1127                             print(upvar_ty));
1128                         sep = ", ";
1129                     }
1130                 } else {
1131                     // cross-crate closure types should only be
1132                     // visible in codegen bug reports, I imagine.
1133                     p!(write("@{:?}", did));
1134                     let mut sep = " ";
1135                     for (index, upvar_ty) in upvar_tys.enumerate() {
1136                         p!(
1137                                 write("{}{}:", sep, index),
1138                                 print(upvar_ty));
1139                         sep = ", ";
1140                     }
1141                 }
1142
1143                 p!(write(" "), print(witness), write("]"))
1144             },
1145             ty::GeneratorWitness(types) => {
1146                 nest!(|cx| cx.in_binder(&types))
1147             }
1148             ty::Closure(did, substs) => {
1149                 let upvar_tys = substs.upvar_tys(did, self.tcx);
1150                 p!(write("[closure"));
1151
1152                 // FIXME(eddyb) should use `def_span`.
1153                 if let Some(hir_id) = self.tcx.hir().as_local_hir_id(did) {
1154                     if self.tcx.sess.opts.debugging_opts.span_free_formats {
1155                         p!(write("@{:?}", hir_id));
1156                     } else {
1157                         p!(write("@{:?}", self.tcx.hir().span_by_hir_id(hir_id)));
1158                     }
1159                     let mut sep = " ";
1160                     for (freevar, upvar_ty) in self.tcx.freevars(did)
1161                         .as_ref()
1162                         .map_or(&[][..], |fv| &fv[..])
1163                         .iter()
1164                         .zip(upvar_tys)
1165                     {
1166                         p!(
1167                             write("{}{}:",
1168                                     sep,
1169                                     self.tcx.hir().name(freevar.var_id())),
1170                             print(upvar_ty));
1171                         sep = ", ";
1172                     }
1173                 } else {
1174                     // cross-crate closure types should only be
1175                     // visible in codegen bug reports, I imagine.
1176                     p!(write("@{:?}", did));
1177                     let mut sep = " ";
1178                     for (index, upvar_ty) in upvar_tys.enumerate() {
1179                         p!(
1180                                 write("{}{}:", sep, index),
1181                                 print(upvar_ty));
1182                         sep = ", ";
1183                     }
1184                 }
1185
1186                 if self.tcx.sess.verbose() {
1187                     p!(write(
1188                         " closure_kind_ty={:?} closure_sig_ty={:?}",
1189                         substs.closure_kind_ty(did, self.tcx),
1190                         substs.closure_sig_ty(did, self.tcx)
1191                     ));
1192                 }
1193
1194                 p!(write("]"))
1195             },
1196             ty::Array(ty, sz) => {
1197                 p!(write("["), print(ty), write("; "));
1198                 match sz {
1199                     ty::LazyConst::Unevaluated(_def_id, _substs) => {
1200                         p!(write("_"));
1201                     }
1202                     ty::LazyConst::Evaluated(c) => {
1203                         match c.val {
1204                             ConstValue::Infer(..) => p!(write("_")),
1205                             ConstValue::Param(ParamConst { name, .. }) =>
1206                                 p!(write("{}", name)),
1207                             _ => p!(write("{}", c.unwrap_usize(self.tcx))),
1208                         }
1209                     }
1210                 }
1211                 p!(write("]"))
1212             }
1213             ty::Slice(ty) => {
1214                 p!(write("["), print(ty), write("]"))
1215             }
1216         }
1217
1218         Ok(self.printer)
1219     }
1220
1221     pub fn pretty_fn_sig(
1222         mut self,
1223         inputs: &[Ty<'tcx>],
1224         c_variadic: bool,
1225         output: Ty<'tcx>,
1226     ) -> Result<P, fmt::Error> {
1227         define_scoped_cx!(self);
1228
1229         p!(write("("));
1230         let mut inputs = inputs.iter();
1231         if let Some(&ty) = inputs.next() {
1232             p!(print(ty));
1233             for &ty in inputs {
1234                 p!(write(", "), print(ty));
1235             }
1236             if c_variadic {
1237                 p!(write(", ..."));
1238             }
1239         }
1240         p!(write(")"));
1241         if !output.is_unit() {
1242             p!(write(" -> "), print(output));
1243         }
1244
1245         Ok(self.printer)
1246     }
1247
1248     pub fn pretty_in_binder<T>(mut self, value: &ty::Binder<T>) -> Result<P, fmt::Error>
1249         where T: Print<'tcx, P, Output = P, Error = fmt::Error> + TypeFoldable<'tcx>
1250     {
1251         fn name_by_region_index(index: usize) -> InternedString {
1252             match index {
1253                 0 => Symbol::intern("'r"),
1254                 1 => Symbol::intern("'s"),
1255                 i => Symbol::intern(&format!("'t{}", i-2)),
1256             }.as_interned_str()
1257         }
1258
1259         // Replace any anonymous late-bound regions with named
1260         // variants, using gensym'd identifiers, so that we can
1261         // clearly differentiate between named and unnamed regions in
1262         // the output. We'll probably want to tweak this over time to
1263         // decide just how much information to give.
1264         if self.config.binder_depth == 0 {
1265             self.prepare_late_bound_region_info(value);
1266         }
1267
1268         let mut empty = true;
1269         let mut start_or_continue = |cx: &mut Self, start: &str, cont: &str| {
1270             write!(cx.printer, "{}", if empty {
1271                 empty = false;
1272                 start
1273             } else {
1274                 cont
1275             })
1276         };
1277
1278         define_scoped_cx!(self);
1279
1280         let old_region_index = self.config.region_index;
1281         let mut region_index = old_region_index;
1282         let new_value = self.tcx.replace_late_bound_regions(value, |br| {
1283             let _ = start_or_continue(&mut self, "for<", ", ");
1284             let br = match br {
1285                 ty::BrNamed(_, name) => {
1286                     let _ = write!(self.printer, "{}", name);
1287                     br
1288                 }
1289                 ty::BrAnon(_) |
1290                 ty::BrFresh(_) |
1291                 ty::BrEnv => {
1292                     let name = loop {
1293                         let name = name_by_region_index(region_index);
1294                         region_index += 1;
1295                         if !self.is_name_used(&name) {
1296                             break name;
1297                         }
1298                     };
1299                     let _ = write!(self.printer, "{}", name);
1300                     ty::BrNamed(DefId::local(CRATE_DEF_INDEX), name)
1301                 }
1302             };
1303             self.tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br))
1304         }).0;
1305         start_or_continue(&mut self, "", "> ")?;
1306
1307         // Push current state to gcx, and restore after writing new_value.
1308         self.config.binder_depth += 1;
1309         self.config.region_index = region_index;
1310         let result = new_value.print(PrintCx {
1311             tcx: self.tcx,
1312             printer: self.printer,
1313             config: self.config,
1314         });
1315         self.config.region_index = old_region_index;
1316         self.config.binder_depth -= 1;
1317         result
1318     }
1319
1320     fn prepare_late_bound_region_info<T>(&mut self, value: &ty::Binder<T>)
1321     where T: TypeFoldable<'tcx>
1322     {
1323
1324         struct LateBoundRegionNameCollector(FxHashSet<InternedString>);
1325         impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector {
1326             fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
1327                 match *r {
1328                     ty::ReLateBound(_, ty::BrNamed(_, name)) => {
1329                         self.0.insert(name);
1330                     },
1331                     _ => {},
1332                 }
1333                 r.super_visit_with(self)
1334             }
1335         }
1336
1337         let mut collector = LateBoundRegionNameCollector(Default::default());
1338         value.visit_with(&mut collector);
1339         self.config.used_region_names = Some(collector.0);
1340         self.config.region_index = 0;
1341     }
1342
1343     fn is_name_used(&self, name: &InternedString) -> bool {
1344         match self.config.used_region_names {
1345             Some(ref names) => names.contains(name),
1346             None => false,
1347         }
1348     }
1349 }
1350
1351 impl<T, P: PrettyPrinter> Print<'tcx, P> for ty::Binder<T>
1352     where T: Print<'tcx, P, Output = P, Error = P::Error> + TypeFoldable<'tcx>
1353 {
1354     type Output = P;
1355     type Error = P::Error;
1356     fn print(&self, cx: PrintCx<'_, '_, 'tcx, P>) -> Result<Self::Output, Self::Error> {
1357         cx.in_binder(self)
1358     }
1359 }