]> git.lizzy.rs Git - rust.git/blob - src/librustc/ty/print/mod.rs
rustc: move ty/print.rs to ty/print/mod.rs.
[rust.git] / src / librustc / ty / print / mod.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     type Type;
256
257     fn print_def_path(
258         self: PrintCx<'_, '_, 'tcx, Self>,
259         def_id: DefId,
260         substs: Option<SubstsRef<'tcx>>,
261         projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
262     ) -> Result<Self::Path, Self::Error> {
263         self.default_print_def_path(def_id, substs, projections)
264     }
265     fn print_impl_path(
266         self: PrintCx<'_, '_, 'tcx, Self>,
267         impl_def_id: DefId,
268         substs: Option<SubstsRef<'tcx>>,
269         self_ty: Ty<'tcx>,
270         trait_ref: Option<ty::TraitRef<'tcx>>,
271     ) -> Result<Self::Path, Self::Error> {
272         self.default_print_impl_path(impl_def_id, substs, self_ty, trait_ref)
273     }
274
275     fn print_region(
276         self: PrintCx<'_, '_, '_, Self>,
277         region: ty::Region<'_>,
278     ) -> Result<Self::Region, Self::Error>;
279
280     fn print_type(
281         self: PrintCx<'_, '_, 'tcx, Self>,
282         ty: Ty<'tcx>,
283     ) -> Result<Self::Type, Self::Error>;
284
285     fn path_crate(
286         self: PrintCx<'_, '_, '_, Self>,
287         cnum: CrateNum,
288     ) -> Result<Self::Path, Self::Error>;
289     fn path_qualified(
290         self: PrintCx<'_, '_, 'tcx, Self>,
291         self_ty: Ty<'tcx>,
292         trait_ref: Option<ty::TraitRef<'tcx>>,
293     ) -> Result<Self::Path, Self::Error>;
294
295     fn path_append_impl<'gcx, 'tcx>(
296         self: PrintCx<'_, 'gcx, 'tcx, Self>,
297         print_prefix: impl FnOnce(
298             PrintCx<'_, 'gcx, 'tcx, Self>,
299         ) -> Result<Self::Path, Self::Error>,
300         self_ty: Ty<'tcx>,
301         trait_ref: Option<ty::TraitRef<'tcx>>,
302     ) -> Result<Self::Path, Self::Error>;
303     fn path_append<'gcx, 'tcx>(
304         self: PrintCx<'_, 'gcx, 'tcx, Self>,
305         print_prefix: impl FnOnce(
306             PrintCx<'_, 'gcx, 'tcx, Self>,
307         ) -> Result<Self::Path, Self::Error>,
308         text: &str,
309     ) -> Result<Self::Path, Self::Error>;
310     fn path_generic_args<'gcx, 'tcx>(
311         self: PrintCx<'_, 'gcx, 'tcx, Self>,
312         print_prefix: impl FnOnce(
313             PrintCx<'_, 'gcx, 'tcx, Self>,
314         ) -> Result<Self::Path, Self::Error>,
315         params: &[ty::GenericParamDef],
316         substs: SubstsRef<'tcx>,
317         projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
318     ) -> Result<Self::Path, Self::Error>;
319 }
320
321 /// Trait for printers that pretty-print using `fmt::Write` to the printer.
322 pub trait PrettyPrinter:
323     Printer<
324         Error = fmt::Error,
325         Path = Self,
326         Region = Self,
327         Type = Self,
328     > +
329     fmt::Write
330 {
331     /// Enter a nested print context, for pretty-printing
332     /// nested components in some larger context.
333     fn nest<'a, 'gcx, 'tcx, E>(
334         self: PrintCx<'a, 'gcx, 'tcx, Self>,
335         f: impl FnOnce(PrintCx<'_, 'gcx, 'tcx, Self>) -> Result<Self, E>,
336     ) -> Result<PrintCx<'a, 'gcx, 'tcx, Self>, E> {
337         let printer = f(PrintCx {
338             tcx: self.tcx,
339             printer: self.printer,
340             config: self.config,
341         })?;
342         Ok(PrintCx {
343             tcx: self.tcx,
344             printer,
345             config: self.config,
346         })
347     }
348
349     /// Like `print_def_path` but for value paths.
350     fn print_value_path(
351         self: PrintCx<'_, '_, 'tcx, Self>,
352         def_id: DefId,
353         substs: Option<SubstsRef<'tcx>>,
354     ) -> Result<Self::Path, Self::Error> {
355         self.print_def_path(def_id, substs, iter::empty())
356     }
357
358     /// Print `<...>` around what `f` prints.
359     fn generic_delimiters<'gcx, 'tcx>(
360         self: PrintCx<'_, 'gcx, 'tcx, Self>,
361         f: impl FnOnce(PrintCx<'_, 'gcx, 'tcx, Self>) -> Result<Self, Self::Error>,
362     ) -> Result<Self, Self::Error>;
363
364     /// Return `true` if the region should be printed in path generic args
365     /// even when it's `'_`, such as in e.g. `Foo<'_, '_, '_>`.
366     fn always_print_region_in_paths(
367         self: &PrintCx<'_, '_, '_, Self>,
368         _region: ty::Region<'_>,
369     ) -> bool {
370         false
371     }
372
373     // HACK(eddyb) Trying to print a lifetime might not print anything, which
374     // may need special handling in the caller (of `ty::RegionKind::print`).
375     // To avoid printing to a temporary string (which isn't even supported),
376     // the `print_region_outputs_anything` method can instead be used to
377     // determine this, ahead of time.
378     //
379     // NB: this must be kept in sync with the implementation of `print_region`.
380     fn print_region_outputs_anything(
381         self: &PrintCx<'_, '_, '_, Self>,
382         region: ty::Region<'_>,
383     ) -> bool;
384 }
385
386 macro_rules! nest {
387     ($cx:ident, $closure:expr) => {
388         $cx = $cx.nest($closure)?
389     }
390 }
391
392 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
393     // HACK(eddyb) get rid of `def_path_str` and/or pass `Namespace` explicitly always
394     // (but also some things just print a `DefId` generally so maybe we need this?)
395     fn guess_def_namespace(self, def_id: DefId) -> Namespace {
396         match self.def_key(def_id).disambiguated_data.data {
397             DefPathData::ValueNs(..) |
398             DefPathData::EnumVariant(..) |
399             DefPathData::Field(..) |
400             DefPathData::AnonConst |
401             DefPathData::ConstParam(..) |
402             DefPathData::ClosureExpr |
403             DefPathData::StructCtor => Namespace::ValueNS,
404
405             DefPathData::MacroDef(..) => Namespace::MacroNS,
406
407             _ => Namespace::TypeNS,
408         }
409     }
410
411     /// Returns a string identifying this `DefId`. This string is
412     /// suitable for user output.
413     pub fn def_path_str(self, def_id: DefId) -> String {
414         let ns = self.guess_def_namespace(def_id);
415         debug!("def_path_str: def_id={:?}, ns={:?}", def_id, ns);
416         let mut s = String::new();
417         let _ = PrintCx::with(self, FmtPrinter::new(&mut s, ns), |cx| {
418             cx.print_def_path(def_id, None, iter::empty())
419         });
420         s
421     }
422 }
423
424 impl<P: Printer> PrintCx<'a, 'gcx, 'tcx, P> {
425     pub fn default_print_def_path(
426         self,
427         def_id: DefId,
428         substs: Option<SubstsRef<'tcx>>,
429         projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
430     ) -> Result<P::Path, P::Error> {
431         debug!("default_print_def_path: def_id={:?}, substs={:?}", def_id, substs);
432         let key = self.tcx.def_key(def_id);
433         debug!("default_print_def_path: key={:?}", key);
434
435         match key.disambiguated_data.data {
436             DefPathData::CrateRoot => {
437                 assert!(key.parent.is_none());
438                 self.path_crate(def_id.krate)
439             }
440
441             DefPathData::Impl => {
442                 let mut self_ty = self.tcx.type_of(def_id);
443                 if let Some(substs) = substs {
444                     self_ty = self_ty.subst(self.tcx, substs);
445                 }
446
447                 let mut impl_trait_ref = self.tcx.impl_trait_ref(def_id);
448                 if let Some(substs) = substs {
449                     impl_trait_ref = impl_trait_ref.subst(self.tcx, substs);
450                 }
451                 self.print_impl_path(def_id, substs, self_ty, impl_trait_ref)
452             }
453
454             _ => {
455                 let generics = substs.map(|_| self.tcx.generics_of(def_id));
456                 let generics_parent = generics.as_ref().and_then(|g| g.parent);
457                 let parent_def_id = DefId { index: key.parent.unwrap(), ..def_id };
458                 let print_parent_path = |cx: PrintCx<'_, 'gcx, 'tcx, P>| {
459                     if let Some(generics_parent_def_id) = generics_parent {
460                         assert_eq!(parent_def_id, generics_parent_def_id);
461
462                         // FIXME(eddyb) try to move this into the parent's printing
463                         // logic, instead of doing it when printing the child.
464                         let parent_generics = cx.tcx.generics_of(parent_def_id);
465                         let parent_has_own_self =
466                             parent_generics.has_self && parent_generics.parent_count == 0;
467                         if let (Some(substs), true) = (substs, parent_has_own_self) {
468                             let trait_ref = ty::TraitRef::new(parent_def_id, substs);
469                             cx.path_qualified(trait_ref.self_ty(), Some(trait_ref))
470                         } else {
471                             cx.print_def_path(parent_def_id, substs, iter::empty())
472                         }
473                     } else {
474                         cx.print_def_path(parent_def_id, None, iter::empty())
475                     }
476                 };
477                 let print_path = |cx: PrintCx<'_, 'gcx, 'tcx, P>| {
478                     match key.disambiguated_data.data {
479                         // Skip `::{{constructor}}` on tuple/unit structs.
480                         DefPathData::StructCtor => print_parent_path(cx),
481
482                         _ => {
483                             cx.path_append(
484                                 print_parent_path,
485                                 &key.disambiguated_data.data.as_interned_str().as_str(),
486                             )
487                         }
488                     }
489                 };
490
491                 if let (Some(generics), Some(substs)) = (generics, substs) {
492                     let has_own_self = generics.has_self && generics.parent_count == 0;
493                     let params = &generics.params[has_own_self as usize..];
494                     self.path_generic_args(print_path, params, substs, projections)
495                 } else {
496                     print_path(self)
497                 }
498             }
499         }
500     }
501
502     fn default_print_impl_path(
503         self,
504         impl_def_id: DefId,
505         _substs: Option<SubstsRef<'tcx>>,
506         self_ty: Ty<'tcx>,
507         impl_trait_ref: Option<ty::TraitRef<'tcx>>,
508     ) -> Result<P::Path, P::Error> {
509         debug!("default_print_impl_path: impl_def_id={:?}, self_ty={}, impl_trait_ref={:?}",
510                impl_def_id, self_ty, impl_trait_ref);
511
512         // Decide whether to print the parent path for the impl.
513         // Logically, since impls are global, it's never needed, but
514         // users may find it useful. Currently, we omit the parent if
515         // the impl is either in the same module as the self-type or
516         // as the trait.
517         let parent_def_id = self.tcx.parent(impl_def_id).unwrap();
518         let in_self_mod = match characteristic_def_id_of_type(self_ty) {
519             None => false,
520             Some(ty_def_id) => self.tcx.parent(ty_def_id) == Some(parent_def_id),
521         };
522         let in_trait_mod = match impl_trait_ref {
523             None => false,
524             Some(trait_ref) => self.tcx.parent(trait_ref.def_id) == Some(parent_def_id),
525         };
526
527         if !in_self_mod && !in_trait_mod {
528             // If the impl is not co-located with either self-type or
529             // trait-type, then fallback to a format that identifies
530             // the module more clearly.
531             self.path_append_impl(
532                 |cx| cx.print_def_path(parent_def_id, None, iter::empty()),
533                 self_ty,
534                 impl_trait_ref,
535             )
536         } else {
537             // Otherwise, try to give a good form that would be valid language
538             // syntax. Preferably using associated item notation.
539             self.path_qualified(self_ty, impl_trait_ref)
540         }
541     }
542 }
543
544 /// As a heuristic, when we see an impl, if we see that the
545 /// 'self type' is a type defined in the same module as the impl,
546 /// we can omit including the path to the impl itself. This
547 /// function tries to find a "characteristic `DefId`" for a
548 /// type. It's just a heuristic so it makes some questionable
549 /// decisions and we may want to adjust it later.
550 pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> {
551     match ty.sty {
552         ty::Adt(adt_def, _) => Some(adt_def.did),
553
554         ty::Dynamic(data, ..) => data.principal_def_id(),
555
556         ty::Array(subty, _) |
557         ty::Slice(subty) => characteristic_def_id_of_type(subty),
558
559         ty::RawPtr(mt) => characteristic_def_id_of_type(mt.ty),
560
561         ty::Ref(_, ty, _) => characteristic_def_id_of_type(ty),
562
563         ty::Tuple(ref tys) => tys.iter()
564                                    .filter_map(|ty| characteristic_def_id_of_type(ty))
565                                    .next(),
566
567         ty::FnDef(def_id, _) |
568         ty::Closure(def_id, _) |
569         ty::Generator(def_id, _, _) |
570         ty::Foreign(def_id) => Some(def_id),
571
572         ty::Bool |
573         ty::Char |
574         ty::Int(_) |
575         ty::Uint(_) |
576         ty::Str |
577         ty::FnPtr(_) |
578         ty::Projection(_) |
579         ty::Placeholder(..) |
580         ty::UnnormalizedProjection(..) |
581         ty::Param(_) |
582         ty::Opaque(..) |
583         ty::Infer(_) |
584         ty::Bound(..) |
585         ty::Error |
586         ty::GeneratorWitness(..) |
587         ty::Never |
588         ty::Float(_) => None,
589     }
590 }
591
592 pub struct FmtPrinter<F: fmt::Write> {
593     pub(crate) fmt: F,
594     empty: bool,
595     in_value: bool,
596     pub region_highlight_mode: RegionHighlightMode,
597 }
598
599 impl<F: fmt::Write> FmtPrinter<F> {
600     pub fn new(fmt: F, ns: Namespace) -> Self {
601         FmtPrinter {
602             fmt,
603             empty: true,
604             in_value: ns == Namespace::ValueNS,
605             region_highlight_mode: RegionHighlightMode::default(),
606         }
607     }
608 }
609
610 impl<'gcx, 'tcx, P: PrettyPrinter> PrintCx<'_, 'gcx, 'tcx, P> {
611     /// If possible, this returns a global path resolving to `def_id` that is visible
612     /// from at least one local module and returns true. If the crate defining `def_id` is
613     /// declared with an `extern crate`, the path is guaranteed to use the `extern crate`.
614     fn try_print_visible_def_path(
615         mut self,
616         def_id: DefId,
617     ) -> Result<(P, bool), P::Error> {
618         debug!("try_print_visible_def_path: def_id={:?}", def_id);
619
620         // If `def_id` is a direct or injected extern crate, return the
621         // path to the crate followed by the path to the item within the crate.
622         if def_id.index == CRATE_DEF_INDEX {
623             let cnum = def_id.krate;
624
625             if cnum == LOCAL_CRATE {
626                 return Ok((self.path_crate(cnum)?, true));
627             }
628
629             // In local mode, when we encounter a crate other than
630             // LOCAL_CRATE, execution proceeds in one of two ways:
631             //
632             // 1. for a direct dependency, where user added an
633             //    `extern crate` manually, we put the `extern
634             //    crate` as the parent. So you wind up with
635             //    something relative to the current crate.
636             // 2. for an extern inferred from a path or an indirect crate,
637             //    where there is no explicit `extern crate`, we just prepend
638             //    the crate name.
639             match *self.tcx.extern_crate(def_id) {
640                 Some(ExternCrate {
641                     src: ExternCrateSource::Extern(def_id),
642                     direct: true,
643                     span,
644                     ..
645                 }) => {
646                     debug!("try_print_visible_def_path: def_id={:?}", def_id);
647                     return Ok((if !span.is_dummy() {
648                         self.print_def_path(def_id, None, iter::empty())?
649                     } else {
650                         self.path_crate(cnum)?
651                     }, true));
652                 }
653                 None => {
654                     return Ok((self.path_crate(cnum)?, true));
655                 }
656                 _ => {},
657             }
658         }
659
660         if def_id.is_local() {
661             return Ok((self.printer, false));
662         }
663
664         let visible_parent_map = self.tcx.visible_parent_map(LOCAL_CRATE);
665
666         let mut cur_def_key = self.tcx.def_key(def_id);
667         debug!("try_print_visible_def_path: cur_def_key={:?}", cur_def_key);
668
669         // For a UnitStruct or TupleStruct we want the name of its parent rather than <unnamed>.
670         if let DefPathData::StructCtor = cur_def_key.disambiguated_data.data {
671             let parent = DefId {
672                 krate: def_id.krate,
673                 index: cur_def_key.parent.expect("DefPathData::StructCtor missing a parent"),
674             };
675
676             cur_def_key = self.tcx.def_key(parent);
677         }
678
679         let visible_parent = match visible_parent_map.get(&def_id).cloned() {
680             Some(parent) => parent,
681             None => return Ok((self.printer, false)),
682         };
683         // HACK(eddyb) this uses `nest` to avoid knowing ahead of time whether
684         // the entire path will succeed or not. To support printers that do not
685         // implement `PrettyPrinter`, a `Vec` or linked list on the stack would
686         // need to be built, before starting to print anything.
687         let mut prefix_success = false;
688         nest!(self, |cx| {
689             let (printer, success) = cx.try_print_visible_def_path(visible_parent)?;
690             prefix_success = success;
691             Ok(printer)
692         });
693         if !prefix_success {
694             return Ok((self.printer, false));
695         };
696         let actual_parent = self.tcx.parent(def_id);
697
698         let data = cur_def_key.disambiguated_data.data;
699         debug!(
700             "try_print_visible_def_path: data={:?} visible_parent={:?} actual_parent={:?}",
701             data, visible_parent, actual_parent,
702         );
703
704         let symbol = match data {
705             // In order to output a path that could actually be imported (valid and visible),
706             // we need to handle re-exports correctly.
707             //
708             // For example, take `std::os::unix::process::CommandExt`, this trait is actually
709             // defined at `std::sys::unix::ext::process::CommandExt` (at time of writing).
710             //
711             // `std::os::unix` rexports the contents of `std::sys::unix::ext`. `std::sys` is
712             // private so the "true" path to `CommandExt` isn't accessible.
713             //
714             // In this case, the `visible_parent_map` will look something like this:
715             //
716             // (child) -> (parent)
717             // `std::sys::unix::ext::process::CommandExt` -> `std::sys::unix::ext::process`
718             // `std::sys::unix::ext::process` -> `std::sys::unix::ext`
719             // `std::sys::unix::ext` -> `std::os`
720             //
721             // This is correct, as the visible parent of `std::sys::unix::ext` is in fact
722             // `std::os`.
723             //
724             // When printing the path to `CommandExt` and looking at the `cur_def_key` that
725             // corresponds to `std::sys::unix::ext`, we would normally print `ext` and then go
726             // to the parent - resulting in a mangled path like
727             // `std::os::ext::process::CommandExt`.
728             //
729             // Instead, we must detect that there was a re-export and instead print `unix`
730             // (which is the name `std::sys::unix::ext` was re-exported as in `std::os`). To
731             // do this, we compare the parent of `std::sys::unix::ext` (`std::sys::unix`) with
732             // the visible parent (`std::os`). If these do not match, then we iterate over
733             // the children of the visible parent (as was done when computing
734             // `visible_parent_map`), looking for the specific child we currently have and then
735             // have access to the re-exported name.
736             DefPathData::Module(actual_name) |
737             DefPathData::TypeNs(actual_name) if Some(visible_parent) != actual_parent => {
738                 self.tcx.item_children(visible_parent)
739                     .iter()
740                     .find(|child| child.def.def_id() == def_id)
741                     .map(|child| child.ident.as_str())
742                     .unwrap_or_else(|| actual_name.as_str())
743             }
744             _ => {
745                 data.get_opt_name().map(|n| n.as_str()).unwrap_or_else(|| {
746                     // Re-exported `extern crate` (#43189).
747                     if let DefPathData::CrateRoot = data {
748                         self.tcx.original_crate_name(def_id.krate).as_str()
749                     } else {
750                         Symbol::intern("<unnamed>").as_str()
751                     }
752                 })
753             },
754         };
755         debug!("try_print_visible_def_path: symbol={:?}", symbol);
756         Ok((self.path_append(|cx| Ok(cx.printer), &symbol)?, true))
757     }
758
759     pub fn pretty_path_qualified(
760         self,
761         self_ty: Ty<'tcx>,
762         trait_ref: Option<ty::TraitRef<'tcx>>,
763     ) -> Result<P::Path, P::Error> {
764         if trait_ref.is_none() {
765             // Inherent impls. Try to print `Foo::bar` for an inherent
766             // impl on `Foo`, but fallback to `<Foo>::bar` if self-type is
767             // anything other than a simple path.
768             match self_ty.sty {
769                 ty::Adt(..) | ty::Foreign(_) |
770                 ty::Bool | ty::Char | ty::Str |
771                 ty::Int(_) | ty::Uint(_) | ty::Float(_) => {
772                     return self_ty.print_display(self);
773                 }
774
775                 _ => {}
776             }
777         }
778
779         self.generic_delimiters(|mut cx| {
780             nest!(cx, |cx| self_ty.print_display(cx));
781             if let Some(trait_ref) = trait_ref {
782                 write!(cx.printer, " as ")?;
783                 nest!(cx, |cx| trait_ref.print_display(cx));
784             }
785             Ok(cx.printer)
786         })
787     }
788
789     pub fn pretty_path_append_impl(
790         mut self,
791         print_prefix: impl FnOnce(
792             PrintCx<'_, 'gcx, 'tcx, P>,
793         ) -> Result<P::Path, P::Error>,
794         self_ty: Ty<'tcx>,
795         trait_ref: Option<ty::TraitRef<'tcx>>,
796     ) -> Result<P::Path, P::Error> {
797         nest!(self, print_prefix);
798
799         self.generic_delimiters(|mut cx| {
800             write!(cx.printer, "impl ")?;
801             if let Some(trait_ref) = trait_ref {
802                 nest!(cx, |cx| trait_ref.print_display(cx));
803                 write!(cx.printer, " for ")?;
804             }
805             nest!(cx, |cx| self_ty.print_display(cx));
806
807             Ok(cx.printer)
808         })
809     }
810
811     pub fn pretty_path_generic_args(
812         mut self,
813         print_prefix: impl FnOnce(
814             PrintCx<'_, 'gcx, 'tcx, P>,
815         ) -> Result<P::Path, P::Error>,
816         params: &[ty::GenericParamDef],
817         substs: SubstsRef<'tcx>,
818         projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
819     ) -> Result<P::Path, P::Error> {
820         nest!(self, |cx| print_prefix(cx));
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         let params = &params[..params.len() - num_supplied_defaults];
851         let mut args = params.iter().map(|param| {
852             substs[param.index as usize].unpack()
853         }).filter(|arg| {
854             match arg {
855                 UnpackedKind::Lifetime(_) => print_regions,
856                 _ => true,
857             }
858         });
859         let arg0 = args.next();
860
861         let mut projections = projections;
862         let projection0 = projections.next();
863
864         if arg0.is_none() && projection0.is_none() {
865             return Ok(self.printer);
866         }
867
868         self.generic_delimiters(|mut cx| {
869             let mut empty = true;
870             let mut maybe_comma = |cx: &mut Self| {
871                 if empty {
872                     empty = false;
873                     Ok(())
874                 } else {
875                     write!(cx.printer, ", ")
876                 }
877             };
878
879             for arg in arg0.into_iter().chain(args) {
880                 maybe_comma(&mut cx)?;
881
882                 match arg {
883                     UnpackedKind::Lifetime(region) => {
884                         if !cx.print_region_outputs_anything(region) {
885                             // This happens when the value of the region
886                             // parameter is not easily serialized. This may be
887                             // because the user omitted it in the first place,
888                             // or because it refers to some block in the code,
889                             // etc. I'm not sure how best to serialize this.
890                             write!(cx.printer, "'_")?;
891                         } else {
892                             nest!(cx, |cx| region.print_display(cx));
893                         }
894                     }
895                     UnpackedKind::Type(ty) => {
896                         nest!(cx, |cx| ty.print_display(cx));
897                     }
898                     UnpackedKind::Const(ct) => {
899                         nest!(cx, |cx| ct.print_display(cx));
900                     }
901                 }
902             }
903
904             for projection in projection0.into_iter().chain(projections) {
905                 maybe_comma(&mut cx)?;
906
907                 write!(cx.printer, "{}=",
908                     cx.tcx.associated_item(projection.item_def_id).ident)?;
909                 nest!(cx, |cx| projection.ty.print_display(cx));
910             }
911
912             Ok(cx.printer)
913         })
914     }
915 }
916
917 impl<F: fmt::Write> fmt::Write for FmtPrinter<F> {
918     fn write_str(&mut self, s: &str) -> fmt::Result {
919         self.empty &= s.is_empty();
920         self.fmt.write_str(s)
921     }
922 }
923
924 impl<F: fmt::Write> Printer for FmtPrinter<F> {
925     type Error = fmt::Error;
926
927     type Path = Self;
928     type Region = Self;
929     type Type = Self;
930
931     fn print_def_path(
932         mut self: PrintCx<'_, '_, 'tcx, Self>,
933         def_id: DefId,
934         substs: Option<SubstsRef<'tcx>>,
935         projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
936     ) -> Result<Self::Path, Self::Error> {
937         // FIXME(eddyb) avoid querying `tcx.generics_of` and `tcx.def_key`
938         // both here and in `default_print_def_path`.
939         let generics = substs.map(|_| self.tcx.generics_of(def_id));
940         if generics.as_ref().and_then(|g| g.parent).is_none() {
941             let mut visible_path_success = false;
942             nest!(self, |cx| {
943                 let (printer, success) = cx.try_print_visible_def_path(def_id)?;
944                 visible_path_success = success;
945                 Ok(printer)
946             });
947             if visible_path_success {
948                 return if let (Some(generics), Some(substs)) = (generics, substs) {
949                     let has_own_self = generics.has_self && generics.parent_count == 0;
950                     let params = &generics.params[has_own_self as usize..];
951                     self.path_generic_args(|cx| Ok(cx.printer), params, substs, projections)
952                 } else {
953                     Ok(self.printer)
954                 };
955             }
956         }
957
958         let key = self.tcx.def_key(def_id);
959         if let DefPathData::Impl = key.disambiguated_data.data {
960             // Always use types for non-local impls, where types are always
961             // available, and filename/line-number is mostly uninteresting.
962             let use_types =
963                 !def_id.is_local() || {
964                     // Otherwise, use filename/line-number if forced.
965                     let force_no_types = FORCE_IMPL_FILENAME_LINE.with(|f| f.get());
966                     !force_no_types
967                 };
968
969             if !use_types {
970                 // If no type info is available, fall back to
971                 // pretty printing some span information. This should
972                 // only occur very early in the compiler pipeline.
973                 let parent_def_id = DefId { index: key.parent.unwrap(), ..def_id };
974                 let span = self.tcx.def_span(def_id);
975                 return self.path_append(
976                     |cx| cx.print_def_path(parent_def_id, None, iter::empty()),
977                     &format!("<impl at {:?}>", span),
978                 );
979             }
980         }
981
982         self.default_print_def_path(def_id, substs, projections)
983     }
984
985     fn print_region(
986         mut self: PrintCx<'_, '_, '_, Self>,
987         region: ty::Region<'_>,
988     ) -> Result<Self::Region, Self::Error> {
989         // Watch out for region highlights.
990         let highlight = self.printer.region_highlight_mode;
991         if let Some(n) = highlight.region_highlighted(region) {
992             write!(self.printer, "'{}", n)?;
993             return Ok(self.printer);
994         }
995
996         if self.config.is_verbose {
997             return region.print_debug(self);
998         }
999
1000         // These printouts are concise.  They do not contain all the information
1001         // the user might want to diagnose an error, but there is basically no way
1002         // to fit that into a short string.  Hence the recommendation to use
1003         // `explain_region()` or `note_and_explain_region()`.
1004         match *region {
1005             ty::ReEarlyBound(ref data) => {
1006                 if data.name != "'_" {
1007                     write!(self.printer, "{}", data.name)?;
1008                 }
1009             }
1010             ty::ReLateBound(_, br) |
1011             ty::ReFree(ty::FreeRegion { bound_region: br, .. }) |
1012             ty::RePlaceholder(ty::Placeholder { name: br, .. }) => {
1013                 if let ty::BrNamed(_, name) = br {
1014                     if name != "" && name != "'_" {
1015                         write!(self.printer, "{}", name)?;
1016                         return Ok(self.printer);
1017                     }
1018                 }
1019
1020                 if let Some((region, counter)) = highlight.highlight_bound_region {
1021                     if br == region {
1022                         write!(self.printer, "'{}", counter)?;
1023                     }
1024                 }
1025             }
1026             ty::ReScope(scope) if self.config.identify_regions => {
1027                 match scope.data {
1028                     region::ScopeData::Node =>
1029                         write!(self.printer, "'{}s", scope.item_local_id().as_usize())?,
1030                     region::ScopeData::CallSite =>
1031                         write!(self.printer, "'{}cs", scope.item_local_id().as_usize())?,
1032                     region::ScopeData::Arguments =>
1033                         write!(self.printer, "'{}as", scope.item_local_id().as_usize())?,
1034                     region::ScopeData::Destruction =>
1035                         write!(self.printer, "'{}ds", scope.item_local_id().as_usize())?,
1036                     region::ScopeData::Remainder(first_statement_index) => write!(self.printer,
1037                         "'{}_{}rs",
1038                         scope.item_local_id().as_usize(),
1039                         first_statement_index.index()
1040                     )?,
1041                 }
1042             }
1043             ty::ReVar(region_vid) if self.config.identify_regions => {
1044                 write!(self.printer, "{:?}", region_vid)?;
1045             }
1046             ty::ReVar(_) => {}
1047             ty::ReScope(_) |
1048             ty::ReErased => {}
1049             ty::ReStatic => write!(self.printer, "'static")?,
1050             ty::ReEmpty => write!(self.printer, "'<empty>")?,
1051
1052             // The user should never encounter these in unsubstituted form.
1053             ty::ReClosureBound(vid) => write!(self.printer, "{:?}", vid)?,
1054         }
1055
1056         Ok(self.printer)
1057     }
1058
1059     fn print_type(
1060         self: PrintCx<'_, '_, 'tcx, Self>,
1061         ty: Ty<'tcx>,
1062     ) -> Result<Self::Type, Self::Error> {
1063         self.pretty_print_type(ty)
1064     }
1065
1066     fn path_crate(
1067         mut self: PrintCx<'_, '_, '_, Self>,
1068         cnum: CrateNum,
1069     ) -> Result<Self::Path, Self::Error> {
1070         if cnum == LOCAL_CRATE {
1071             if self.tcx.sess.rust_2018() {
1072                 // We add the `crate::` keyword on Rust 2018, only when desired.
1073                 if SHOULD_PREFIX_WITH_CRATE.with(|flag| flag.get()) {
1074                     write!(self.printer, "{}", keywords::Crate.name())?;
1075                 }
1076             }
1077             Ok(self.printer)
1078         } else {
1079             write!(self.printer, "{}", self.tcx.crate_name(cnum))?;
1080             Ok(self.printer)
1081         }
1082     }
1083     fn path_qualified(
1084         self: PrintCx<'_, '_, 'tcx, Self>,
1085         self_ty: Ty<'tcx>,
1086         trait_ref: Option<ty::TraitRef<'tcx>>,
1087     ) -> Result<Self::Path, Self::Error> {
1088         self.pretty_path_qualified(self_ty, trait_ref)
1089     }
1090
1091     fn path_append_impl<'gcx, 'tcx>(
1092         self: PrintCx<'_, 'gcx, 'tcx, Self>,
1093         print_prefix: impl FnOnce(
1094             PrintCx<'_, 'gcx, 'tcx, Self>,
1095         ) -> Result<Self::Path, Self::Error>,
1096         self_ty: Ty<'tcx>,
1097         trait_ref: Option<ty::TraitRef<'tcx>>,
1098     ) -> Result<Self::Path, Self::Error> {
1099         self.pretty_path_append_impl(|cx| {
1100             let mut printer = print_prefix(cx)?;
1101
1102             // HACK(eddyb) this accounts for `generic_delimiters`
1103             // printing `::<` instead of `<` if `in_value` is set.
1104             if !printer.empty && !printer.in_value {
1105                 write!(printer, "::")?;
1106             }
1107
1108             Ok(printer)
1109         }, self_ty, trait_ref)
1110     }
1111     fn path_append<'gcx, 'tcx>(
1112         self: PrintCx<'_, 'gcx, 'tcx, Self>,
1113         print_prefix: impl FnOnce(
1114             PrintCx<'_, 'gcx, 'tcx, Self>,
1115         ) -> Result<Self::Path, Self::Error>,
1116         text: &str,
1117     ) -> Result<Self::Path, Self::Error> {
1118         let mut printer = print_prefix(self)?;
1119
1120         // FIXME(eddyb) `text` should never be empty, but it
1121         // currently is for `extern { ... }` "foreign modules".
1122         if !text.is_empty() {
1123             if !printer.empty {
1124                 write!(printer, "::")?;
1125             }
1126             write!(printer, "{}", text)?;
1127         }
1128
1129         Ok(printer)
1130     }
1131     fn path_generic_args<'gcx, 'tcx>(
1132         self: PrintCx<'_, 'gcx, 'tcx, Self>,
1133         print_prefix: impl FnOnce(
1134             PrintCx<'_, 'gcx, 'tcx, Self>,
1135         ) -> Result<Self::Path, Self::Error>,
1136         params: &[ty::GenericParamDef],
1137         substs: SubstsRef<'tcx>,
1138         projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
1139     ) -> Result<Self::Path, Self::Error> {
1140         self.pretty_path_generic_args(print_prefix, params, substs, projections)
1141     }
1142 }
1143
1144 impl<F: fmt::Write> PrettyPrinter for FmtPrinter<F> {
1145     fn nest<'a, 'gcx, 'tcx, E>(
1146         mut self: PrintCx<'a, 'gcx, 'tcx, Self>,
1147         f: impl FnOnce(PrintCx<'_, 'gcx, 'tcx, Self>) -> Result<Self, E>,
1148     ) -> Result<PrintCx<'a, 'gcx, 'tcx, Self>, E> {
1149         let was_empty = std::mem::replace(&mut self.printer.empty, true);
1150         let mut printer = f(PrintCx {
1151             tcx: self.tcx,
1152             printer: self.printer,
1153             config: self.config,
1154         })?;
1155         printer.empty &= was_empty;
1156         Ok(PrintCx {
1157             tcx: self.tcx,
1158             printer,
1159             config: self.config,
1160         })
1161     }
1162
1163     fn print_value_path(
1164         mut self: PrintCx<'_, '_, 'tcx, Self>,
1165         def_id: DefId,
1166         substs: Option<SubstsRef<'tcx>>,
1167     ) -> Result<Self::Path, Self::Error> {
1168         let was_in_value = std::mem::replace(&mut self.printer.in_value, true);
1169         let mut printer = self.print_def_path(def_id, substs, iter::empty())?;
1170         printer.in_value = was_in_value;
1171
1172         Ok(printer)
1173     }
1174
1175     fn generic_delimiters<'gcx, 'tcx>(
1176         mut self: PrintCx<'_, 'gcx, 'tcx, Self>,
1177         f: impl FnOnce(PrintCx<'_, 'gcx, 'tcx, Self>) -> Result<Self, Self::Error>,
1178     ) -> Result<Self, Self::Error> {
1179         if !self.printer.empty && self.printer.in_value {
1180             write!(self.printer, "::<")?;
1181         } else {
1182             write!(self.printer, "<")?;
1183         }
1184
1185         let was_in_value = std::mem::replace(&mut self.printer.in_value, false);
1186         let mut printer = f(self)?;
1187         printer.in_value = was_in_value;
1188
1189         write!(printer, ">")?;
1190         Ok(printer)
1191     }
1192
1193     fn always_print_region_in_paths(
1194         self: &PrintCx<'_, '_, '_, Self>,
1195         region: ty::Region<'_>,
1196     ) -> bool {
1197         *region != ty::ReErased
1198     }
1199
1200     fn print_region_outputs_anything(
1201         self: &PrintCx<'_, '_, '_, Self>,
1202         region: ty::Region<'_>,
1203     ) -> bool {
1204         let highlight = self.printer.region_highlight_mode;
1205         if highlight.region_highlighted(region).is_some() {
1206             return true;
1207         }
1208
1209         if self.config.is_verbose {
1210             return true;
1211         }
1212
1213         match *region {
1214             ty::ReEarlyBound(ref data) => {
1215                 data.name != "" && data.name != "'_"
1216             }
1217
1218             ty::ReLateBound(_, br) |
1219             ty::ReFree(ty::FreeRegion { bound_region: br, .. }) |
1220             ty::RePlaceholder(ty::Placeholder { name: br, .. }) => {
1221                 if let ty::BrNamed(_, name) = br {
1222                     if name != "" && name != "'_" {
1223                         return true;
1224                     }
1225                 }
1226
1227                 if let Some((region, _)) = highlight.highlight_bound_region {
1228                     if br == region {
1229                         return true;
1230                     }
1231                 }
1232
1233                 false
1234             }
1235
1236             ty::ReScope(_) |
1237             ty::ReVar(_) if self.config.identify_regions => true,
1238
1239             ty::ReVar(_) |
1240             ty::ReScope(_) |
1241             ty::ReErased => false,
1242
1243             ty::ReStatic |
1244             ty::ReEmpty |
1245             ty::ReClosureBound(_) => true,
1246         }
1247     }
1248 }