]> git.lizzy.rs Git - rust.git/blob - src/librustc/ty/print.rs
053a7531cadd66c986888c1731b4bcf8ecaf4c94
[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::{Subst, SubstsRef};
6 use crate::middle::cstore::{ExternCrate, ExternCrateSource};
7 use syntax::ast;
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;
15 use std::ops::Deref;
16
17 thread_local! {
18     static FORCE_ABSOLUTE: Cell<bool> = Cell::new(false);
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 /// Enforces that def_path_str always returns an absolute path and
24 /// also enables "type-based" impl paths. This is used when building
25 /// symbols that contain types, where we want the crate name to be
26 /// part of the symbol.
27 pub fn with_forced_absolute_paths<F: FnOnce() -> R, R>(f: F) -> R {
28     FORCE_ABSOLUTE.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 /// Force us to name impls with just the filename/line number. We
38 /// normally try to use types. But at some points, notably while printing
39 /// cycle errors, this can result in extra or suboptimal error output,
40 /// so this variable disables that check.
41 pub fn with_forced_impl_filename_line<F: FnOnce() -> R, R>(f: F) -> R {
42     FORCE_IMPL_FILENAME_LINE.with(|force| {
43         let old = force.get();
44         force.set(true);
45         let result = f();
46         force.set(old);
47         result
48     })
49 }
50
51 /// Adds the `crate::` prefix to paths where appropriate.
52 pub fn with_crate_prefix<F: FnOnce() -> R, R>(f: F) -> R {
53     SHOULD_PREFIX_WITH_CRATE.with(|flag| {
54         let old = flag.get();
55         flag.set(true);
56         let result = f();
57         flag.set(old);
58         result
59     })
60 }
61
62 // FIXME(eddyb) this module uses `pub(crate)` for things used only
63 // from `ppaux` - when that is removed, they can be re-privatized.
64
65 struct LateBoundRegionNameCollector(FxHashSet<InternedString>);
66 impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector {
67     fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
68         match *r {
69             ty::ReLateBound(_, ty::BrNamed(_, name)) => {
70                 self.0.insert(name);
71             },
72             _ => {},
73         }
74         r.super_visit_with(self)
75     }
76 }
77
78 pub struct PrintCx<'a, 'gcx, 'tcx, P> {
79     pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
80     pub printer: P,
81     pub(crate) is_debug: bool,
82     pub(crate) is_verbose: bool,
83     pub(crate) identify_regions: bool,
84     pub(crate) used_region_names: Option<FxHashSet<InternedString>>,
85     pub(crate) region_index: usize,
86     pub(crate) binder_depth: usize,
87 }
88
89 // HACK(eddyb) this is solely for `self: &mut PrintCx<Self>`, e.g. to
90 // implement traits on the printer and call the methods on the context.
91 impl<P> Deref for PrintCx<'_, '_, '_, P> {
92     type Target = P;
93     fn deref(&self) -> &P {
94         &self.printer
95     }
96 }
97
98 impl<P> PrintCx<'a, 'gcx, 'tcx, P> {
99     pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, printer: P) -> Self {
100         PrintCx {
101             tcx,
102             printer,
103             is_debug: false,
104             is_verbose: tcx.sess.verbose(),
105             identify_regions: tcx.sess.opts.debugging_opts.identify_regions,
106             used_region_names: None,
107             region_index: 0,
108             binder_depth: 0,
109         }
110     }
111
112     pub(crate) fn with<R>(printer: P, f: impl FnOnce(PrintCx<'_, '_, '_, P>) -> R) -> R {
113         ty::tls::with(|tcx| f(PrintCx::new(tcx, printer)))
114     }
115     pub(crate) fn prepare_late_bound_region_info<T>(&mut self, value: &ty::Binder<T>)
116     where T: TypeFoldable<'tcx>
117     {
118         let mut collector = LateBoundRegionNameCollector(Default::default());
119         value.visit_with(&mut collector);
120         self.used_region_names = Some(collector.0);
121         self.region_index = 0;
122     }
123 }
124
125 pub trait Print<'tcx, P> {
126     type Output;
127
128     fn print(&self, cx: &mut PrintCx<'_, '_, 'tcx, P>) -> Self::Output;
129     fn print_display(&self, cx: &mut PrintCx<'_, '_, 'tcx, P>) -> Self::Output {
130         let old_debug = cx.is_debug;
131         cx.is_debug = false;
132         let result = self.print(cx);
133         cx.is_debug = old_debug;
134         result
135     }
136     fn print_debug(&self, cx: &mut PrintCx<'_, '_, 'tcx, P>) -> Self::Output {
137         let old_debug = cx.is_debug;
138         cx.is_debug = true;
139         let result = self.print(cx);
140         cx.is_debug = old_debug;
141         result
142     }
143 }
144
145 pub trait Printer: Sized {
146     type Path;
147
148     fn print_def_path(
149         self: &mut PrintCx<'_, '_, 'tcx, Self>,
150         def_id: DefId,
151         substs: Option<SubstsRef<'tcx>>,
152         ns: Namespace,
153     ) -> Self::Path {
154         self.default_print_def_path(def_id, substs, ns)
155     }
156     fn print_impl_path(
157         self: &mut PrintCx<'_, '_, 'tcx, Self>,
158         impl_def_id: DefId,
159         substs: Option<SubstsRef<'tcx>>,
160         ns: Namespace,
161     ) -> Self::Path {
162         self.default_print_impl_path(impl_def_id, substs, ns)
163     }
164
165     fn path_crate(self: &mut PrintCx<'_, '_, '_, Self>, cnum: CrateNum) -> Self::Path;
166     fn path_impl(self: &mut PrintCx<'_, '_, '_, Self>, text: &str) -> Self::Path;
167     fn path_append(
168         self: &mut PrintCx<'_, '_, '_, Self>,
169         path: Self::Path,
170         text: &str,
171     ) -> Self::Path;
172 }
173
174 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
175     // HACK(eddyb) get rid of `def_path_str` and/or pass `Namespace` explicitly always
176     // (but also some things just print a `DefId` generally so maybe we need this?)
177     fn guess_def_namespace(self, def_id: DefId) -> Namespace {
178         match self.def_key(def_id).disambiguated_data.data {
179             DefPathData::ValueNs(..) |
180             DefPathData::EnumVariant(..) |
181             DefPathData::Field(..) |
182             DefPathData::AnonConst |
183             DefPathData::ClosureExpr |
184             DefPathData::StructCtor => Namespace::ValueNS,
185
186             DefPathData::MacroDef(..) => Namespace::MacroNS,
187
188             _ => Namespace::TypeNS,
189         }
190     }
191
192     /// Returns a string identifying this `DefId`. This string is
193     /// suitable for user output. It is relative to the current crate
194     /// root, unless with_forced_absolute_paths was used.
195     pub fn def_path_str_with_substs_and_ns(
196         self,
197         def_id: DefId,
198         substs: Option<SubstsRef<'tcx>>,
199         ns: Namespace,
200     ) -> String {
201         debug!("def_path_str: def_id={:?}, substs={:?}, ns={:?}", def_id, substs, ns);
202         if FORCE_ABSOLUTE.with(|force| force.get()) {
203             PrintCx::new(self, AbsolutePathPrinter).print_def_path(def_id, substs, ns)
204         } else {
205             PrintCx::new(self, LocalPathPrinter).print_def_path(def_id, substs, ns)
206         }
207     }
208
209     /// Returns a string identifying this `DefId`. This string is
210     /// suitable for user output. It is relative to the current crate
211     /// root, unless with_forced_absolute_paths was used.
212     pub fn def_path_str(self, def_id: DefId) -> String {
213         let ns = self.guess_def_namespace(def_id);
214         self.def_path_str_with_substs_and_ns(def_id, None, ns)
215     }
216
217     /// Returns a string identifying this local node-id.
218     // FIXME(eddyb) remove in favor of calling `def_path_str` directly.
219     pub fn node_path_str(self, id: ast::NodeId) -> String {
220         self.def_path_str(self.hir().local_def_id(id))
221     }
222
223     /// Returns a string identifying this `DefId`. This string is
224     /// suitable for user output. It always begins with a crate identifier.
225     pub fn absolute_def_path_str(self, def_id: DefId) -> String {
226         debug!("absolute_def_path_str: def_id={:?}", def_id);
227         let ns = self.guess_def_namespace(def_id);
228         PrintCx::new(self, AbsolutePathPrinter).print_def_path(def_id, None, ns)
229     }
230 }
231
232 impl<P: Printer> PrintCx<'a, 'gcx, 'tcx, P> {
233     pub fn default_print_def_path(
234         &mut self,
235         def_id: DefId,
236         substs: Option<SubstsRef<'tcx>>,
237         ns: Namespace,
238     ) -> P::Path {
239         debug!("default_print_def_path: def_id={:?}, substs={:?}, ns={:?}", def_id, substs, ns);
240         let key = self.tcx.def_key(def_id);
241         debug!("default_print_def_path: key={:?}", key);
242         match key.disambiguated_data.data {
243             DefPathData::CrateRoot => {
244                 assert!(key.parent.is_none());
245                 self.path_crate(def_id.krate)
246             }
247
248             DefPathData::Impl => {
249                 self.print_impl_path(def_id, substs, ns)
250             }
251
252             // Unclear if there is any value in distinguishing these.
253             // Probably eventually (and maybe we would even want
254             // finer-grained distinctions, e.g., between enum/struct).
255             data @ DefPathData::Misc |
256             data @ DefPathData::TypeNs(..) |
257             data @ DefPathData::Trait(..) |
258             data @ DefPathData::TraitAlias(..) |
259             data @ DefPathData::AssocTypeInTrait(..) |
260             data @ DefPathData::AssocTypeInImpl(..) |
261             data @ DefPathData::AssocExistentialInImpl(..) |
262             data @ DefPathData::ValueNs(..) |
263             data @ DefPathData::Module(..) |
264             data @ DefPathData::TypeParam(..) |
265             data @ DefPathData::LifetimeParam(..) |
266             data @ DefPathData::ConstParam(..) |
267             data @ DefPathData::EnumVariant(..) |
268             data @ DefPathData::Field(..) |
269             data @ DefPathData::AnonConst |
270             data @ DefPathData::MacroDef(..) |
271             data @ DefPathData::ClosureExpr |
272             data @ DefPathData::ImplTrait |
273             data @ DefPathData::GlobalMetaData(..) => {
274                 let parent_did = self.tcx.parent(def_id).unwrap();
275                 let path = self.print_def_path(parent_did, None, ns);
276                 self.path_append(path, &data.as_interned_str().as_symbol().as_str())
277             },
278
279             DefPathData::StructCtor => { // present `X` instead of `X::{{constructor}}`
280                 let parent_def_id = self.tcx.parent(def_id).unwrap();
281                 self.print_def_path(parent_def_id, substs, ns)
282             }
283         }
284     }
285
286     fn default_print_impl_path(
287         &mut self,
288         impl_def_id: DefId,
289         substs: Option<SubstsRef<'tcx>>,
290         ns: Namespace,
291     ) -> P::Path {
292         debug!("default_print_impl_path: impl_def_id={:?}", impl_def_id);
293         let parent_def_id = self.tcx.parent(impl_def_id).unwrap();
294
295         // Decide whether to print the parent path for the impl.
296         // Logically, since impls are global, it's never needed, but
297         // users may find it useful. Currently, we omit the parent if
298         // the impl is either in the same module as the self-type or
299         // as the trait.
300         let mut self_ty = self.tcx.type_of(impl_def_id);
301         if let Some(substs) = substs {
302             self_ty = self_ty.subst(self.tcx, substs);
303         }
304         let in_self_mod = match characteristic_def_id_of_type(self_ty) {
305             None => false,
306             Some(ty_def_id) => self.tcx.parent(ty_def_id) == Some(parent_def_id),
307         };
308
309         let mut impl_trait_ref = self.tcx.impl_trait_ref(impl_def_id);
310         if let Some(substs) = substs {
311             impl_trait_ref = impl_trait_ref.subst(self.tcx, substs);
312         }
313         let in_trait_mod = match impl_trait_ref {
314             None => false,
315             Some(trait_ref) => self.tcx.parent(trait_ref.def_id) == Some(parent_def_id),
316         };
317
318         if !in_self_mod && !in_trait_mod {
319             // If the impl is not co-located with either self-type or
320             // trait-type, then fallback to a format that identifies
321             // the module more clearly.
322             let path = self.print_def_path(parent_def_id, None, ns);
323             if let Some(trait_ref) = impl_trait_ref {
324                 return self.path_append(path, &format!("<impl {} for {}>", trait_ref, self_ty));
325             } else {
326                 return self.path_append(path, &format!("<impl {}>", self_ty));
327             }
328         }
329
330         // Otherwise, try to give a good form that would be valid language
331         // syntax. Preferably using associated item notation.
332
333         if let Some(trait_ref) = impl_trait_ref {
334             // Trait impls.
335             return self.path_impl(&format!("<{} as {}>", self_ty, trait_ref));
336         }
337
338         // Inherent impls. Try to print `Foo::bar` for an inherent
339         // impl on `Foo`, but fallback to `<Foo>::bar` if self-type is
340         // anything other than a simple path.
341         match self_ty.sty {
342             ty::Adt(adt_def, substs) => {
343                 // FIXME(eddyb) this should recurse to build the path piecewise.
344                 // self.print_def_path(adt_def.did, Some(substs), ns)
345                 let mut s = String::new();
346                 crate::util::ppaux::parameterized(&mut s, adt_def.did, substs, ns).unwrap();
347                 self.path_impl(&s)
348             }
349
350             ty::Foreign(did) => self.print_def_path(did, None, ns),
351
352             ty::Bool |
353             ty::Char |
354             ty::Int(_) |
355             ty::Uint(_) |
356             ty::Float(_) |
357             ty::Str => {
358                 self.path_impl(&self_ty.to_string())
359             }
360
361             _ => {
362                 self.path_impl(&format!("<{}>", self_ty))
363             }
364         }
365     }
366 }
367
368 /// As a heuristic, when we see an impl, if we see that the
369 /// 'self type' is a type defined in the same module as the impl,
370 /// we can omit including the path to the impl itself. This
371 /// function tries to find a "characteristic `DefId`" for a
372 /// type. It's just a heuristic so it makes some questionable
373 /// decisions and we may want to adjust it later.
374 pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> {
375     match ty.sty {
376         ty::Adt(adt_def, _) => Some(adt_def.did),
377
378         ty::Dynamic(data, ..) => data.principal_def_id(),
379
380         ty::Array(subty, _) |
381         ty::Slice(subty) => characteristic_def_id_of_type(subty),
382
383         ty::RawPtr(mt) => characteristic_def_id_of_type(mt.ty),
384
385         ty::Ref(_, ty, _) => characteristic_def_id_of_type(ty),
386
387         ty::Tuple(ref tys) => tys.iter()
388                                    .filter_map(|ty| characteristic_def_id_of_type(ty))
389                                    .next(),
390
391         ty::FnDef(def_id, _) |
392         ty::Closure(def_id, _) |
393         ty::Generator(def_id, _, _) |
394         ty::Foreign(def_id) => Some(def_id),
395
396         ty::Bool |
397         ty::Char |
398         ty::Int(_) |
399         ty::Uint(_) |
400         ty::Str |
401         ty::FnPtr(_) |
402         ty::Projection(_) |
403         ty::Placeholder(..) |
404         ty::UnnormalizedProjection(..) |
405         ty::Param(_) |
406         ty::Opaque(..) |
407         ty::Infer(_) |
408         ty::Bound(..) |
409         ty::Error |
410         ty::GeneratorWitness(..) |
411         ty::Never |
412         ty::Float(_) => None,
413     }
414 }
415
416 // FIXME(eddyb) remove, alongside `FORCE_ABSOLUTE` and `absolute_def_path_str`.
417 struct AbsolutePathPrinter;
418
419 impl Printer for AbsolutePathPrinter {
420     type Path = String;
421
422     fn path_crate(self: &mut PrintCx<'_, '_, '_, Self>, cnum: CrateNum) -> Self::Path {
423         self.tcx.original_crate_name(cnum).to_string()
424     }
425     fn path_impl(self: &mut PrintCx<'_, '_, '_, Self>, text: &str) -> Self::Path {
426         text.to_string()
427     }
428     fn path_append(
429         self: &mut PrintCx<'_, '_, '_, Self>,
430         mut path: Self::Path,
431         text: &str,
432     ) -> Self::Path {
433         if !path.is_empty() {
434             path.push_str("::");
435         }
436         path.push_str(text);
437         path
438     }
439 }
440
441 pub struct FmtPrinter<F: fmt::Write> {
442     pub fmt: F,
443 }
444
445 // FIXME(eddyb) integrate into `FmtPrinter`.
446 struct LocalPathPrinter;
447
448 impl LocalPathPrinter {
449     /// If possible, this returns a global path resolving to `def_id` that is visible
450     /// from at least one local module and returns true. If the crate defining `def_id` is
451     /// declared with an `extern crate`, the path is guaranteed to use the `extern crate`.
452     fn try_print_visible_def_path(
453         self: &mut PrintCx<'_, '_, '_, Self>,
454         def_id: DefId,
455         ns: Namespace,
456     ) -> Option<<Self as Printer>::Path> {
457         debug!("try_print_visible_def_path: def_id={:?}", def_id);
458
459         // If `def_id` is a direct or injected extern crate, return the
460         // path to the crate followed by the path to the item within the crate.
461         if def_id.index == CRATE_DEF_INDEX {
462             let cnum = def_id.krate;
463
464             if cnum == LOCAL_CRATE {
465                 return Some(self.path_crate(cnum));
466             }
467
468             // In local mode, when we encounter a crate other than
469             // LOCAL_CRATE, execution proceeds in one of two ways:
470             //
471             // 1. for a direct dependency, where user added an
472             //    `extern crate` manually, we put the `extern
473             //    crate` as the parent. So you wind up with
474             //    something relative to the current crate.
475             // 2. for an extern inferred from a path or an indirect crate,
476             //    where there is no explicit `extern crate`, we just prepend
477             //    the crate name.
478             match *self.tcx.extern_crate(def_id) {
479                 Some(ExternCrate {
480                     src: ExternCrateSource::Extern(def_id),
481                     direct: true,
482                     span,
483                     ..
484                 }) => {
485                     debug!("try_print_visible_def_path: def_id={:?}", def_id);
486                     let path = if !span.is_dummy() {
487                         self.print_def_path(def_id, None, ns)
488                     } else {
489                         self.path_crate(cnum)
490                     };
491                     return Some(path);
492                 }
493                 None => {
494                     return Some(self.path_crate(cnum));
495                 }
496                 _ => {},
497             }
498         }
499
500         if def_id.is_local() {
501             return None;
502         }
503
504         let visible_parent_map = self.tcx.visible_parent_map(LOCAL_CRATE);
505
506         let mut cur_def_key = self.tcx.def_key(def_id);
507         debug!("try_print_visible_def_path: cur_def_key={:?}", cur_def_key);
508
509         // For a UnitStruct or TupleStruct we want the name of its parent rather than <unnamed>.
510         if let DefPathData::StructCtor = cur_def_key.disambiguated_data.data {
511             let parent = DefId {
512                 krate: def_id.krate,
513                 index: cur_def_key.parent.expect("DefPathData::StructCtor missing a parent"),
514             };
515
516             cur_def_key = self.tcx.def_key(parent);
517         }
518
519         let visible_parent = visible_parent_map.get(&def_id).cloned()?;
520         let path = self.try_print_visible_def_path(visible_parent, ns)?;
521         let actual_parent = self.tcx.parent(def_id);
522
523         let data = cur_def_key.disambiguated_data.data;
524         debug!(
525             "try_print_visible_def_path: data={:?} visible_parent={:?} actual_parent={:?}",
526             data, visible_parent, actual_parent,
527         );
528
529         let symbol = match data {
530             // In order to output a path that could actually be imported (valid and visible),
531             // we need to handle re-exports correctly.
532             //
533             // For example, take `std::os::unix::process::CommandExt`, this trait is actually
534             // defined at `std::sys::unix::ext::process::CommandExt` (at time of writing).
535             //
536             // `std::os::unix` rexports the contents of `std::sys::unix::ext`. `std::sys` is
537             // private so the "true" path to `CommandExt` isn't accessible.
538             //
539             // In this case, the `visible_parent_map` will look something like this:
540             //
541             // (child) -> (parent)
542             // `std::sys::unix::ext::process::CommandExt` -> `std::sys::unix::ext::process`
543             // `std::sys::unix::ext::process` -> `std::sys::unix::ext`
544             // `std::sys::unix::ext` -> `std::os`
545             //
546             // This is correct, as the visible parent of `std::sys::unix::ext` is in fact
547             // `std::os`.
548             //
549             // When printing the path to `CommandExt` and looking at the `cur_def_key` that
550             // corresponds to `std::sys::unix::ext`, we would normally print `ext` and then go
551             // to the parent - resulting in a mangled path like
552             // `std::os::ext::process::CommandExt`.
553             //
554             // Instead, we must detect that there was a re-export and instead print `unix`
555             // (which is the name `std::sys::unix::ext` was re-exported as in `std::os`). To
556             // do this, we compare the parent of `std::sys::unix::ext` (`std::sys::unix`) with
557             // the visible parent (`std::os`). If these do not match, then we iterate over
558             // the children of the visible parent (as was done when computing
559             // `visible_parent_map`), looking for the specific child we currently have and then
560             // have access to the re-exported name.
561             DefPathData::Module(actual_name) |
562             DefPathData::TypeNs(actual_name) if Some(visible_parent) != actual_parent => {
563                 self.tcx.item_children(visible_parent)
564                     .iter()
565                     .find(|child| child.def.def_id() == def_id)
566                     .map(|child| child.ident.as_str())
567                     .unwrap_or_else(|| actual_name.as_str())
568             }
569             _ => {
570                 data.get_opt_name().map(|n| n.as_str()).unwrap_or_else(|| {
571                     // Re-exported `extern crate` (#43189).
572                     if let DefPathData::CrateRoot = data {
573                         self.tcx.original_crate_name(def_id.krate).as_str()
574                     } else {
575                         Symbol::intern("<unnamed>").as_str()
576                     }
577                 })
578             },
579         };
580         debug!("try_print_visible_def_path: symbol={:?}", symbol);
581         Some(self.path_append(path, &symbol))
582     }
583 }
584
585 impl Printer for LocalPathPrinter {
586     type Path = String;
587
588     fn print_def_path(
589         self: &mut PrintCx<'_, '_, 'tcx, Self>,
590         def_id: DefId,
591         substs: Option<SubstsRef<'tcx>>,
592         ns: Namespace,
593     ) -> Self::Path {
594         self.try_print_visible_def_path(def_id, ns)
595             .unwrap_or_else(|| self.default_print_def_path(def_id, substs, ns))
596     }
597     fn print_impl_path(
598         self: &mut PrintCx<'_, '_, 'tcx, Self>,
599         impl_def_id: DefId,
600         substs: Option<SubstsRef<'tcx>>,
601         ns: Namespace,
602     ) -> Self::Path {
603         // Always use types for non-local impls, where types are always
604         // available, and filename/line-number is mostly uninteresting.
605         let use_types = !impl_def_id.is_local() || {
606             // Otherwise, use filename/line-number if forced.
607             let force_no_types = FORCE_IMPL_FILENAME_LINE.with(|f| f.get());
608             !force_no_types
609         };
610
611         if !use_types {
612             // If no type info is available, fall back to
613             // pretty printing some span information. This should
614             // only occur very early in the compiler pipeline.
615             // FIXME(eddyb) this should just be using `tcx.def_span(impl_def_id)`
616             let parent_def_id = self.tcx.parent(impl_def_id).unwrap();
617             let path = self.print_def_path(parent_def_id, None, ns);
618             let span = self.tcx.def_span(impl_def_id);
619             return self.path_append(path, &format!("<impl at {:?}>", span));
620         }
621
622         self.default_print_impl_path(impl_def_id, substs, ns)
623     }
624
625     fn path_crate(self: &mut PrintCx<'_, '_, '_, Self>, cnum: CrateNum) -> Self::Path {
626         if cnum == LOCAL_CRATE {
627             if self.tcx.sess.rust_2018() {
628                 // We add the `crate::` keyword on Rust 2018, only when desired.
629                 if SHOULD_PREFIX_WITH_CRATE.with(|flag| flag.get()) {
630                     return keywords::Crate.name().to_string();
631                 }
632             }
633             String::new()
634         } else {
635             self.tcx.crate_name(cnum).to_string()
636         }
637     }
638     fn path_impl(self: &mut PrintCx<'_, '_, '_, Self>, text: &str) -> Self::Path {
639         text.to_string()
640     }
641     fn path_append(
642         self: &mut PrintCx<'_, '_, '_, Self>,
643         mut path: Self::Path,
644         text: &str,
645     ) -> Self::Path {
646         if !path.is_empty() {
647             path.push_str("::");
648         }
649         path.push_str(text);
650         path
651     }
652 }