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