]> git.lizzy.rs Git - rust.git/blob - src/librustc/ty/print.rs
rustc: split off most of ty::print::PrintCx's fields into a separate struct.
[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::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable};
5 use crate::ty::subst::{Kind, Subst, SubstsRef, UnpackedKind};
6 use crate::middle::cstore::{ExternCrate, ExternCrateSource};
7 use syntax::symbol::{keywords, Symbol};
8
9 use rustc_data_structures::fx::FxHashSet;
10 use syntax::symbol::InternedString;
11
12 use std::cell::Cell;
13 use std::fmt::{self, Write as _};
14 use std::iter;
15 use std::ops::Deref;
16
17 thread_local! {
18     static FORCE_IMPL_FILENAME_LINE: Cell<bool> = Cell::new(false);
19     static SHOULD_PREFIX_WITH_CRATE: Cell<bool> = Cell::new(false);
20 }
21
22 /// Force us to name impls with just the filename/line number. We
23 /// normally try to use types. But at some points, notably while printing
24 /// cycle errors, this can result in extra or suboptimal error output,
25 /// so this variable disables that check.
26 pub fn with_forced_impl_filename_line<F: FnOnce() -> R, R>(f: F) -> R {
27     FORCE_IMPL_FILENAME_LINE.with(|force| {
28         let old = force.get();
29         force.set(true);
30         let result = f();
31         force.set(old);
32         result
33     })
34 }
35
36 /// Adds the `crate::` prefix to paths where appropriate.
37 pub fn with_crate_prefix<F: FnOnce() -> R, R>(f: F) -> R {
38     SHOULD_PREFIX_WITH_CRATE.with(|flag| {
39         let old = flag.get();
40         flag.set(true);
41         let result = f();
42         flag.set(old);
43         result
44     })
45 }
46
47 // FIXME(eddyb) this module uses `pub(crate)` for things used only
48 // from `ppaux` - when that is removed, they can be re-privatized.
49
50 struct LateBoundRegionNameCollector(FxHashSet<InternedString>);
51 impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector {
52     fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
53         match *r {
54             ty::ReLateBound(_, ty::BrNamed(_, name)) => {
55                 self.0.insert(name);
56             },
57             _ => {},
58         }
59         r.super_visit_with(self)
60     }
61 }
62
63 pub(crate) struct PrintConfig {
64     pub(crate) is_debug: bool,
65     pub(crate) is_verbose: bool,
66     pub(crate) identify_regions: bool,
67     pub(crate) used_region_names: Option<FxHashSet<InternedString>>,
68     pub(crate) region_index: usize,
69     pub(crate) binder_depth: usize,
70 }
71
72 impl PrintConfig {
73     pub(crate) fn new(tcx: TyCtxt<'_, '_, '_>) -> Self {
74         PrintConfig {
75             is_debug: false,
76             is_verbose: tcx.sess.verbose(),
77             identify_regions: tcx.sess.opts.debugging_opts.identify_regions,
78             used_region_names: None,
79             region_index: 0,
80             binder_depth: 0,
81         }
82     }
83 }
84
85 pub struct PrintCx<'a, 'gcx, 'tcx, P> {
86     pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
87     pub printer: P,
88     pub(crate) config: &'a mut PrintConfig,
89 }
90
91 // HACK(eddyb) this is solely for `self: &mut PrintCx<Self>`, e.g. to
92 // implement traits on the printer and call the methods on the context.
93 impl<P> Deref for PrintCx<'_, '_, '_, P> {
94     type Target = P;
95     fn deref(&self) -> &P {
96         &self.printer
97     }
98 }
99
100 impl<'a, 'gcx, 'tcx, P> PrintCx<'a, 'gcx, 'tcx, P> {
101     pub fn with<R>(
102         tcx: TyCtxt<'a, 'gcx, 'tcx>,
103         printer: P,
104         f: impl FnOnce(PrintCx<'_, 'gcx, 'tcx, P>) -> R,
105     ) -> R {
106         f(PrintCx {
107             tcx,
108             printer,
109             config: &mut PrintConfig::new(tcx),
110         })
111     }
112
113     pub(crate) fn with_tls_tcx<R>(printer: P, f: impl FnOnce(PrintCx<'_, '_, '_, P>) -> R) -> R {
114         ty::tls::with(|tcx| PrintCx::with(tcx, printer, f))
115     }
116     pub(crate) fn prepare_late_bound_region_info<T>(&mut self, value: &ty::Binder<T>)
117     where T: TypeFoldable<'tcx>
118     {
119         let mut collector = LateBoundRegionNameCollector(Default::default());
120         value.visit_with(&mut collector);
121         self.config.used_region_names = Some(collector.0);
122         self.config.region_index = 0;
123     }
124 }
125
126 pub trait Print<'tcx, P> {
127     type Output;
128     type Error;
129
130     fn print(&self, cx: &mut PrintCx<'_, '_, 'tcx, P>) -> Result<Self::Output, Self::Error>;
131     fn print_display(
132         &self,
133         cx: &mut PrintCx<'_, '_, 'tcx, P>,
134     ) -> Result<Self::Output, Self::Error> {
135         let old_debug = cx.config.is_debug;
136         cx.config.is_debug = false;
137         let result = self.print(cx);
138         cx.config.is_debug = old_debug;
139         result
140     }
141     fn print_debug(&self, cx: &mut PrintCx<'_, '_, 'tcx, P>) -> Result<Self::Output, Self::Error> {
142         let old_debug = cx.config.is_debug;
143         cx.config.is_debug = true;
144         let result = self.print(cx);
145         cx.config.is_debug = old_debug;
146         result
147     }
148 }
149
150 pub trait Printer: Sized {
151     type Error;
152
153     type Path;
154
155     fn print_def_path(
156         self: &mut PrintCx<'_, '_, 'tcx, Self>,
157         def_id: DefId,
158         substs: Option<SubstsRef<'tcx>>,
159         ns: Namespace,
160         projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
161     ) -> Result<Self::Path, Self::Error> {
162         self.default_print_def_path(def_id, substs, ns, projections)
163     }
164     fn print_impl_path(
165         self: &mut PrintCx<'_, '_, 'tcx, Self>,
166         impl_def_id: DefId,
167         substs: Option<SubstsRef<'tcx>>,
168         ns: Namespace,
169         self_ty: Ty<'tcx>,
170         trait_ref: Option<ty::TraitRef<'tcx>>,
171     ) -> Result<Self::Path, Self::Error> {
172         self.default_print_impl_path(impl_def_id, substs, ns, self_ty, trait_ref)
173     }
174
175     fn path_crate(
176         self: &mut PrintCx<'_, '_, '_, Self>,
177         cnum: CrateNum,
178     ) -> Result<Self::Path, Self::Error>;
179     fn path_qualified(
180         self: &mut PrintCx<'_, '_, 'tcx, Self>,
181         impl_prefix: Option<Self::Path>,
182         self_ty: Ty<'tcx>,
183         trait_ref: Option<ty::TraitRef<'tcx>>,
184         ns: Namespace,
185     ) -> Result<Self::Path, Self::Error>;
186     fn path_append(
187         self: &mut PrintCx<'_, '_, '_, Self>,
188         path: Self::Path,
189         text: &str,
190     ) -> Result<Self::Path, Self::Error>;
191     fn path_generic_args(
192         self: &mut PrintCx<'_, '_, 'tcx, Self>,
193         path: Self::Path,
194         params: &[ty::GenericParamDef],
195         substs: SubstsRef<'tcx>,
196         ns: Namespace,
197         projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
198     ) -> Result<Self::Path, Self::Error>;
199 }
200
201 #[must_use]
202 pub struct PrettyPath {
203     pub empty: bool,
204 }
205
206 /// Trait for printers that pretty-print using `fmt::Write` to the printer.
207 pub trait PrettyPrinter: Printer<Error = fmt::Error, Path = PrettyPath> + fmt::Write {}
208
209 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
210     // HACK(eddyb) get rid of `def_path_str` and/or pass `Namespace` explicitly always
211     // (but also some things just print a `DefId` generally so maybe we need this?)
212     fn guess_def_namespace(self, def_id: DefId) -> Namespace {
213         match self.def_key(def_id).disambiguated_data.data {
214             DefPathData::ValueNs(..) |
215             DefPathData::EnumVariant(..) |
216             DefPathData::Field(..) |
217             DefPathData::AnonConst |
218             DefPathData::ConstParam(..) |
219             DefPathData::ClosureExpr |
220             DefPathData::StructCtor => Namespace::ValueNS,
221
222             DefPathData::MacroDef(..) => Namespace::MacroNS,
223
224             _ => Namespace::TypeNS,
225         }
226     }
227
228     /// Returns a string identifying this `DefId`. This string is
229     /// suitable for user output.
230     pub fn def_path_str(self, def_id: DefId) -> String {
231         let ns = self.guess_def_namespace(def_id);
232         debug!("def_path_str: def_id={:?}, ns={:?}", def_id, ns);
233         let mut s = String::new();
234         let _ = PrintCx::with(self, FmtPrinter { fmt: &mut s }, |mut cx| {
235             cx.print_def_path(def_id, None, ns, iter::empty())
236         });
237         s
238     }
239 }
240
241 impl<P: Printer> PrintCx<'a, 'gcx, 'tcx, P> {
242     pub fn default_print_def_path(
243         &mut self,
244         def_id: DefId,
245         substs: Option<SubstsRef<'tcx>>,
246         ns: Namespace,
247         projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
248     ) -> Result<P::Path, P::Error> {
249         debug!("default_print_def_path: def_id={:?}, substs={:?}, ns={:?}", def_id, substs, ns);
250         let key = self.tcx.def_key(def_id);
251         debug!("default_print_def_path: key={:?}", key);
252
253         match key.disambiguated_data.data {
254             DefPathData::CrateRoot => {
255                 assert!(key.parent.is_none());
256                 self.path_crate(def_id.krate)
257             }
258
259             DefPathData::Impl => {
260                 let mut self_ty = self.tcx.type_of(def_id);
261                 if let Some(substs) = substs {
262                     self_ty = self_ty.subst(self.tcx, substs);
263                 }
264
265                 let mut impl_trait_ref = self.tcx.impl_trait_ref(def_id);
266                 if let Some(substs) = substs {
267                     impl_trait_ref = impl_trait_ref.subst(self.tcx, substs);
268                 }
269                 self.print_impl_path(def_id, substs, ns, self_ty, impl_trait_ref)
270             }
271
272             _ => {
273                 let generics = substs.map(|_| self.tcx.generics_of(def_id));
274                 let generics_parent = generics.as_ref().and_then(|g| g.parent);
275                 let parent_def_id = DefId { index: key.parent.unwrap(), ..def_id };
276                 let path = if let Some(generics_parent_def_id) = generics_parent {
277                     assert_eq!(parent_def_id, generics_parent_def_id);
278
279                     // FIXME(eddyb) try to move this into the parent's printing
280                     // logic, instead of doing it when printing the child.
281                     let parent_generics = self.tcx.generics_of(parent_def_id);
282                     let parent_has_own_self =
283                         parent_generics.has_self && parent_generics.parent_count == 0;
284                     if let (Some(substs), true) = (substs, parent_has_own_self) {
285                         let trait_ref = ty::TraitRef::new(parent_def_id, substs);
286                         self.path_qualified(None, trait_ref.self_ty(), Some(trait_ref), ns)?
287                     } else {
288                         self.print_def_path(parent_def_id, substs, ns, iter::empty())?
289                     }
290                 } else {
291                     self.print_def_path(parent_def_id, None, ns, iter::empty())?
292                 };
293                 let path = match key.disambiguated_data.data {
294                     // Skip `::{{constructor}}` on tuple/unit structs.
295                     DefPathData::StructCtor => path,
296
297                     _ => {
298                         self.path_append(
299                             path,
300                             &key.disambiguated_data.data.as_interned_str().as_str(),
301                         )?
302                     }
303                 };
304
305                 if let (Some(generics), Some(substs)) = (generics, substs) {
306                     let has_own_self = generics.has_self && generics.parent_count == 0;
307                     let params = &generics.params[has_own_self as usize..];
308                     self.path_generic_args(path, params, substs, ns, projections)
309                 } else {
310                     Ok(path)
311                 }
312             }
313         }
314     }
315
316     fn default_print_impl_path(
317         &mut self,
318         impl_def_id: DefId,
319         _substs: Option<SubstsRef<'tcx>>,
320         ns: Namespace,
321         self_ty: Ty<'tcx>,
322         impl_trait_ref: Option<ty::TraitRef<'tcx>>,
323     ) -> Result<P::Path, P::Error> {
324         debug!("default_print_impl_path: impl_def_id={:?}, self_ty={}, impl_trait_ref={:?}",
325                impl_def_id, self_ty, impl_trait_ref);
326
327         // Decide whether to print the parent path for the impl.
328         // Logically, since impls are global, it's never needed, but
329         // users may find it useful. Currently, we omit the parent if
330         // the impl is either in the same module as the self-type or
331         // as the trait.
332         let parent_def_id = self.tcx.parent(impl_def_id).unwrap();
333         let in_self_mod = match characteristic_def_id_of_type(self_ty) {
334             None => false,
335             Some(ty_def_id) => self.tcx.parent(ty_def_id) == Some(parent_def_id),
336         };
337         let in_trait_mod = match impl_trait_ref {
338             None => false,
339             Some(trait_ref) => self.tcx.parent(trait_ref.def_id) == Some(parent_def_id),
340         };
341
342         let prefix_path = if !in_self_mod && !in_trait_mod {
343             // If the impl is not co-located with either self-type or
344             // trait-type, then fallback to a format that identifies
345             // the module more clearly.
346             Some(self.print_def_path(parent_def_id, None, ns, iter::empty())?)
347         } else {
348             // Otherwise, try to give a good form that would be valid language
349             // syntax. Preferably using associated item notation.
350             None
351         };
352
353         self.path_qualified(prefix_path, self_ty, impl_trait_ref, ns)
354     }
355 }
356
357 /// As a heuristic, when we see an impl, if we see that the
358 /// 'self type' is a type defined in the same module as the impl,
359 /// we can omit including the path to the impl itself. This
360 /// function tries to find a "characteristic `DefId`" for a
361 /// type. It's just a heuristic so it makes some questionable
362 /// decisions and we may want to adjust it later.
363 pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> {
364     match ty.sty {
365         ty::Adt(adt_def, _) => Some(adt_def.did),
366
367         ty::Dynamic(data, ..) => data.principal_def_id(),
368
369         ty::Array(subty, _) |
370         ty::Slice(subty) => characteristic_def_id_of_type(subty),
371
372         ty::RawPtr(mt) => characteristic_def_id_of_type(mt.ty),
373
374         ty::Ref(_, ty, _) => characteristic_def_id_of_type(ty),
375
376         ty::Tuple(ref tys) => tys.iter()
377                                    .filter_map(|ty| characteristic_def_id_of_type(ty))
378                                    .next(),
379
380         ty::FnDef(def_id, _) |
381         ty::Closure(def_id, _) |
382         ty::Generator(def_id, _, _) |
383         ty::Foreign(def_id) => Some(def_id),
384
385         ty::Bool |
386         ty::Char |
387         ty::Int(_) |
388         ty::Uint(_) |
389         ty::Str |
390         ty::FnPtr(_) |
391         ty::Projection(_) |
392         ty::Placeholder(..) |
393         ty::UnnormalizedProjection(..) |
394         ty::Param(_) |
395         ty::Opaque(..) |
396         ty::Infer(_) |
397         ty::Bound(..) |
398         ty::Error |
399         ty::GeneratorWitness(..) |
400         ty::Never |
401         ty::Float(_) => None,
402     }
403 }
404
405 pub struct FmtPrinter<F: fmt::Write> {
406     pub fmt: F,
407 }
408
409 impl<P: PrettyPrinter> PrintCx<'a, 'gcx, 'tcx, P> {
410     /// If possible, this returns a global path resolving to `def_id` that is visible
411     /// from at least one local module and returns true. If the crate defining `def_id` is
412     /// declared with an `extern crate`, the path is guaranteed to use the `extern crate`.
413     fn try_print_visible_def_path(&mut self, def_id: DefId) -> Result<Option<P::Path>, P::Error> {
414         debug!("try_print_visible_def_path: def_id={:?}", def_id);
415
416         // If `def_id` is a direct or injected extern crate, return the
417         // path to the crate followed by the path to the item within the crate.
418         if def_id.index == CRATE_DEF_INDEX {
419             let cnum = def_id.krate;
420
421             if cnum == LOCAL_CRATE {
422                 return Ok(Some(self.path_crate(cnum)?));
423             }
424
425             // In local mode, when we encounter a crate other than
426             // LOCAL_CRATE, execution proceeds in one of two ways:
427             //
428             // 1. for a direct dependency, where user added an
429             //    `extern crate` manually, we put the `extern
430             //    crate` as the parent. So you wind up with
431             //    something relative to the current crate.
432             // 2. for an extern inferred from a path or an indirect crate,
433             //    where there is no explicit `extern crate`, we just prepend
434             //    the crate name.
435             match *self.tcx.extern_crate(def_id) {
436                 Some(ExternCrate {
437                     src: ExternCrateSource::Extern(def_id),
438                     direct: true,
439                     span,
440                     ..
441                 }) => {
442                     debug!("try_print_visible_def_path: def_id={:?}", def_id);
443                     let path = if !span.is_dummy() {
444                         self.print_def_path(def_id, None, Namespace::TypeNS, iter::empty())?
445                     } else {
446                         self.path_crate(cnum)?
447                     };
448                     return Ok(Some(path));
449                 }
450                 None => {
451                     return Ok(Some(self.path_crate(cnum)?));
452                 }
453                 _ => {},
454             }
455         }
456
457         if def_id.is_local() {
458             return Ok(None);
459         }
460
461         let visible_parent_map = self.tcx.visible_parent_map(LOCAL_CRATE);
462
463         let mut cur_def_key = self.tcx.def_key(def_id);
464         debug!("try_print_visible_def_path: cur_def_key={:?}", cur_def_key);
465
466         // For a UnitStruct or TupleStruct we want the name of its parent rather than <unnamed>.
467         if let DefPathData::StructCtor = cur_def_key.disambiguated_data.data {
468             let parent = DefId {
469                 krate: def_id.krate,
470                 index: cur_def_key.parent.expect("DefPathData::StructCtor missing a parent"),
471             };
472
473             cur_def_key = self.tcx.def_key(parent);
474         }
475
476         let visible_parent = match visible_parent_map.get(&def_id).cloned() {
477             Some(parent) => parent,
478             None => return Ok(None),
479         };
480         let path = match self.try_print_visible_def_path(visible_parent)? {
481             Some(path) => path,
482             None => return Ok(None),
483         };
484         let actual_parent = self.tcx.parent(def_id);
485
486         let data = cur_def_key.disambiguated_data.data;
487         debug!(
488             "try_print_visible_def_path: data={:?} visible_parent={:?} actual_parent={:?}",
489             data, visible_parent, actual_parent,
490         );
491
492         let symbol = match data {
493             // In order to output a path that could actually be imported (valid and visible),
494             // we need to handle re-exports correctly.
495             //
496             // For example, take `std::os::unix::process::CommandExt`, this trait is actually
497             // defined at `std::sys::unix::ext::process::CommandExt` (at time of writing).
498             //
499             // `std::os::unix` rexports the contents of `std::sys::unix::ext`. `std::sys` is
500             // private so the "true" path to `CommandExt` isn't accessible.
501             //
502             // In this case, the `visible_parent_map` will look something like this:
503             //
504             // (child) -> (parent)
505             // `std::sys::unix::ext::process::CommandExt` -> `std::sys::unix::ext::process`
506             // `std::sys::unix::ext::process` -> `std::sys::unix::ext`
507             // `std::sys::unix::ext` -> `std::os`
508             //
509             // This is correct, as the visible parent of `std::sys::unix::ext` is in fact
510             // `std::os`.
511             //
512             // When printing the path to `CommandExt` and looking at the `cur_def_key` that
513             // corresponds to `std::sys::unix::ext`, we would normally print `ext` and then go
514             // to the parent - resulting in a mangled path like
515             // `std::os::ext::process::CommandExt`.
516             //
517             // Instead, we must detect that there was a re-export and instead print `unix`
518             // (which is the name `std::sys::unix::ext` was re-exported as in `std::os`). To
519             // do this, we compare the parent of `std::sys::unix::ext` (`std::sys::unix`) with
520             // the visible parent (`std::os`). If these do not match, then we iterate over
521             // the children of the visible parent (as was done when computing
522             // `visible_parent_map`), looking for the specific child we currently have and then
523             // have access to the re-exported name.
524             DefPathData::Module(actual_name) |
525             DefPathData::TypeNs(actual_name) if Some(visible_parent) != actual_parent => {
526                 self.tcx.item_children(visible_parent)
527                     .iter()
528                     .find(|child| child.def.def_id() == def_id)
529                     .map(|child| child.ident.as_str())
530                     .unwrap_or_else(|| actual_name.as_str())
531             }
532             _ => {
533                 data.get_opt_name().map(|n| n.as_str()).unwrap_or_else(|| {
534                     // Re-exported `extern crate` (#43189).
535                     if let DefPathData::CrateRoot = data {
536                         self.tcx.original_crate_name(def_id.krate).as_str()
537                     } else {
538                         Symbol::intern("<unnamed>").as_str()
539                     }
540                 })
541             },
542         };
543         debug!("try_print_visible_def_path: symbol={:?}", symbol);
544         Ok(Some(self.path_append(path, &symbol)?))
545     }
546
547     pub fn pretty_path_qualified(
548         &mut self,
549         impl_prefix: Option<P::Path>,
550         self_ty: Ty<'tcx>,
551         trait_ref: Option<ty::TraitRef<'tcx>>,
552         ns: Namespace,
553     ) -> Result<P::Path, P::Error> {
554         if let Some(prefix) = impl_prefix {
555             // HACK(eddyb) going through `path_append` means symbol name
556             // computation gets to handle its equivalent of `::` correctly.
557             let _ = self.path_append(prefix, "<impl ")?;
558             if let Some(trait_ref) = trait_ref {
559                 trait_ref.print_display(self)?;
560                 write!(self.printer, " for ")?;
561             }
562             self_ty.print_display(self)?;
563             write!(self.printer, ">")?;
564             return Ok(PrettyPath { empty: false });
565         }
566
567         if trait_ref.is_none() {
568             // Inherent impls. Try to print `Foo::bar` for an inherent
569             // impl on `Foo`, but fallback to `<Foo>::bar` if self-type is
570             // anything other than a simple path.
571             match self_ty.sty {
572                 ty::Adt(adt_def, substs) => {
573                     return self.print_def_path(adt_def.did, Some(substs), ns, iter::empty());
574                 }
575                 ty::Foreign(did) => {
576                     return self.print_def_path(did, None, ns, iter::empty());
577                 }
578
579                 ty::Bool | ty::Char | ty::Str |
580                 ty::Int(_) | ty::Uint(_) | ty::Float(_) => {
581                     self_ty.print_display(self)?;
582                     return Ok(PrettyPath { empty: false });
583                 }
584
585                 _ => {}
586             }
587         }
588
589         write!(self.printer, "<")?;
590         self_ty.print_display(self)?;
591         if let Some(trait_ref) = trait_ref {
592             write!(self.printer, " as ")?;
593             let _ = self.print_def_path(
594                 trait_ref.def_id,
595                 Some(trait_ref.substs),
596                 Namespace::TypeNS,
597                 iter::empty(),
598             )?;
599         }
600         write!(self.printer, ">")?;
601         Ok(PrettyPath { empty: false })
602     }
603
604     pub fn pretty_path_generic_args(
605         &mut self,
606         path: P::Path,
607         params: &[ty::GenericParamDef],
608         substs: SubstsRef<'tcx>,
609         ns: Namespace,
610         projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
611     ) -> Result<P::Path, P::Error> {
612         let mut empty = true;
613         let mut start_or_continue = |cx: &mut Self, start: &str, cont: &str| {
614             if empty {
615                 empty = false;
616                 write!(cx.printer, "{}", start)
617             } else {
618                 write!(cx.printer, "{}", cont)
619             }
620         };
621
622         let start = if ns == Namespace::ValueNS { "::<" } else { "<" };
623
624         // Don't print any regions if they're all erased.
625         let print_regions = params.iter().any(|param| {
626             match substs[param.index as usize].unpack() {
627                 UnpackedKind::Lifetime(r) => *r != ty::ReErased,
628                 _ => false,
629             }
630         });
631
632         // Don't print args that are the defaults of their respective parameters.
633         let num_supplied_defaults = if self.config.is_verbose {
634             0
635         } else {
636             params.iter().rev().take_while(|param| {
637                 match param.kind {
638                     ty::GenericParamDefKind::Lifetime => false,
639                     ty::GenericParamDefKind::Type { has_default, .. } => {
640                         has_default && substs[param.index as usize] == Kind::from(
641                             self.tcx.type_of(param.def_id).subst(self.tcx, substs)
642                         )
643                     }
644                     ty::GenericParamDefKind::Const => false, // FIXME(const_generics:defaults)
645                 }
646             }).count()
647         };
648
649         for param in &params[..params.len() - num_supplied_defaults] {
650             match substs[param.index as usize].unpack() {
651                 UnpackedKind::Lifetime(region) => {
652                     if !print_regions {
653                         continue;
654                     }
655                     start_or_continue(self, start, ", ")?;
656                     if !region.display_outputs_anything(self) {
657                         // This happens when the value of the region
658                         // parameter is not easily serialized. This may be
659                         // because the user omitted it in the first place,
660                         // or because it refers to some block in the code,
661                         // etc. I'm not sure how best to serialize this.
662                         write!(self.printer, "'_")?;
663                     } else {
664                         region.print_display(self)?;
665                     }
666                 }
667                 UnpackedKind::Type(ty) => {
668                     start_or_continue(self, start, ", ")?;
669                     ty.print_display(self)?;
670                 }
671                 UnpackedKind::Const(ct) => {
672                     start_or_continue(self, start, ", ")?;
673                     ct.print_display(self)?;
674                 }
675             }
676         }
677
678         for projection in projections {
679             start_or_continue(self, start, ", ")?;
680             write!(self.printer, "{}=",
681                    self.tcx.associated_item(projection.item_def_id).ident)?;
682             projection.ty.print_display(self)?;
683         }
684
685         start_or_continue(self, "", ">")?;
686
687         Ok(path)
688     }
689 }
690
691 impl<F: fmt::Write> fmt::Write for FmtPrinter<F> {
692     fn write_str(&mut self, s: &str) -> fmt::Result {
693         self.fmt.write_str(s)
694     }
695 }
696
697 impl<F: fmt::Write> Printer for FmtPrinter<F> {
698     type Error = fmt::Error;
699
700     type Path = PrettyPath;
701
702     fn print_def_path(
703         self: &mut PrintCx<'_, '_, 'tcx, Self>,
704         def_id: DefId,
705         substs: Option<SubstsRef<'tcx>>,
706         ns: Namespace,
707         projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
708     ) -> Result<Self::Path, Self::Error> {
709         // FIXME(eddyb) avoid querying `tcx.generics_of` and `tcx.def_key`
710         // both here and in `default_print_def_path`.
711         let generics = substs.map(|_| self.tcx.generics_of(def_id));
712         if generics.as_ref().and_then(|g| g.parent).is_none() {
713             if let Some(path) = self.try_print_visible_def_path(def_id)? {
714                 let path = if let (Some(generics), Some(substs)) = (generics, substs) {
715                     let has_own_self = generics.has_self && generics.parent_count == 0;
716                     let params = &generics.params[has_own_self as usize..];
717                     self.path_generic_args(path, params, substs, ns, projections)?
718                 } else {
719                     path
720                 };
721                 return Ok(path);
722             }
723         }
724
725         let key = self.tcx.def_key(def_id);
726         if let DefPathData::Impl = key.disambiguated_data.data {
727             // Always use types for non-local impls, where types are always
728             // available, and filename/line-number is mostly uninteresting.
729             let use_types =
730                 !def_id.is_local() || {
731                     // Otherwise, use filename/line-number if forced.
732                     let force_no_types = FORCE_IMPL_FILENAME_LINE.with(|f| f.get());
733                     !force_no_types
734                 };
735
736             if !use_types {
737                 // If no type info is available, fall back to
738                 // pretty printing some span information. This should
739                 // only occur very early in the compiler pipeline.
740                 let parent_def_id = DefId { index: key.parent.unwrap(), ..def_id };
741                 let path = self.print_def_path(parent_def_id, None, ns, iter::empty())?;
742                 let span = self.tcx.def_span(def_id);
743                 return self.path_append(path, &format!("<impl at {:?}>", span));
744             }
745         }
746
747         self.default_print_def_path(def_id, substs, ns, projections)
748     }
749
750     fn path_crate(
751         self: &mut PrintCx<'_, '_, '_, Self>,
752         cnum: CrateNum,
753     ) -> Result<Self::Path, Self::Error> {
754         if cnum == LOCAL_CRATE {
755             if self.tcx.sess.rust_2018() {
756                 // We add the `crate::` keyword on Rust 2018, only when desired.
757                 if SHOULD_PREFIX_WITH_CRATE.with(|flag| flag.get()) {
758                     write!(self.printer, "{}", keywords::Crate.name())?;
759                     return Ok(PrettyPath { empty: false });
760                 }
761             }
762             Ok(PrettyPath { empty: true })
763         } else {
764             write!(self.printer, "{}", self.tcx.crate_name(cnum))?;
765             Ok(PrettyPath { empty: false })
766         }
767     }
768     fn path_qualified(
769         self: &mut PrintCx<'_, '_, 'tcx, Self>,
770         impl_prefix: Option<Self::Path>,
771         self_ty: Ty<'tcx>,
772         trait_ref: Option<ty::TraitRef<'tcx>>,
773         ns: Namespace,
774     ) -> Result<Self::Path, Self::Error> {
775         self.pretty_path_qualified(impl_prefix, self_ty, trait_ref, ns)
776     }
777     fn path_append(
778         self: &mut PrintCx<'_, '_, '_, Self>,
779         path: Self::Path,
780         text: &str,
781     ) -> Result<Self::Path, Self::Error> {
782         // FIXME(eddyb) this shouldn't happen, but is currently
783         // the case for `extern { ... }` "foreign modules".
784         if text.is_empty() {
785             return Ok(path);
786         }
787
788         if !path.empty {
789             write!(self.printer, "::")?;
790         }
791         write!(self.printer, "{}", text)?;
792         Ok(PrettyPath { empty: false })
793     }
794     fn path_generic_args(
795         self: &mut PrintCx<'_, '_, 'tcx, Self>,
796         path: Self::Path,
797         params: &[ty::GenericParamDef],
798         substs: SubstsRef<'tcx>,
799         ns: Namespace,
800         projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
801     ) -> Result<Self::Path, Self::Error> {
802         self.pretty_path_generic_args(path, params, substs, ns, projections)
803     }
804 }
805
806 impl<F: fmt::Write> PrettyPrinter for FmtPrinter<F> {}