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