]> git.lizzy.rs Git - rust.git/blob - src/librustc/ty/print/mod.rs
rustc: split out the pretty-printing parts of ty::print into a separate module.
[rust.git] / src / librustc / ty / print / mod.rs
1 use crate::hir::map::DefPathData;
2 use crate::hir::def_id::{CrateNum, DefId};
3 use crate::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable};
4 use crate::ty::subst::{Subst, SubstsRef};
5
6 use rustc_data_structures::fx::FxHashSet;
7 use syntax::symbol::InternedString;
8
9 use std::iter;
10 use std::ops::Deref;
11
12 // `pretty` is a separate module only for organization.
13 mod pretty;
14 pub use self::pretty::*;
15
16 // FIXME(eddyb) this module uses `pub(crate)` for things used only
17 // from `ppaux` - when that is removed, they can be re-privatized.
18
19 struct LateBoundRegionNameCollector(FxHashSet<InternedString>);
20 impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector {
21     fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
22         match *r {
23             ty::ReLateBound(_, ty::BrNamed(_, name)) => {
24                 self.0.insert(name);
25             },
26             _ => {},
27         }
28         r.super_visit_with(self)
29     }
30 }
31
32 pub(crate) struct PrintConfig {
33     pub(crate) is_debug: bool,
34     pub(crate) is_verbose: bool,
35     pub(crate) identify_regions: bool,
36     used_region_names: Option<FxHashSet<InternedString>>,
37     region_index: usize,
38     binder_depth: usize,
39 }
40
41 impl PrintConfig {
42     fn new(tcx: TyCtxt<'_, '_, '_>) -> Self {
43         PrintConfig {
44             is_debug: false,
45             is_verbose: tcx.sess.verbose(),
46             identify_regions: tcx.sess.opts.debugging_opts.identify_regions,
47             used_region_names: None,
48             region_index: 0,
49             binder_depth: 0,
50         }
51     }
52 }
53
54 pub struct PrintCx<'a, 'gcx, 'tcx, P> {
55     pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
56     pub printer: P,
57     pub(crate) config: &'a mut PrintConfig,
58 }
59
60 // HACK(eddyb) this is solely for `self: PrintCx<Self>`, e.g. to
61 // implement traits on the printer and call the methods on the context.
62 impl<P> Deref for PrintCx<'_, '_, '_, P> {
63     type Target = P;
64     fn deref(&self) -> &P {
65         &self.printer
66     }
67 }
68
69 impl<'a, 'gcx, 'tcx, P> PrintCx<'a, 'gcx, 'tcx, P> {
70     pub fn with<R>(
71         tcx: TyCtxt<'a, 'gcx, 'tcx>,
72         printer: P,
73         f: impl FnOnce(PrintCx<'_, 'gcx, 'tcx, P>) -> R,
74     ) -> R {
75         f(PrintCx {
76             tcx,
77             printer,
78             config: &mut PrintConfig::new(tcx),
79         })
80     }
81
82     pub(crate) fn with_tls_tcx<R>(printer: P, f: impl FnOnce(PrintCx<'_, '_, '_, P>) -> R) -> R {
83         ty::tls::with(|tcx| PrintCx::with(tcx, printer, f))
84     }
85     fn prepare_late_bound_region_info<T>(&mut self, value: &ty::Binder<T>)
86     where T: TypeFoldable<'tcx>
87     {
88         let mut collector = LateBoundRegionNameCollector(Default::default());
89         value.visit_with(&mut collector);
90         self.config.used_region_names = Some(collector.0);
91         self.config.region_index = 0;
92     }
93 }
94
95 pub trait Print<'tcx, P> {
96     type Output;
97     type Error;
98
99     fn print(&self, cx: PrintCx<'_, '_, 'tcx, P>) -> Result<Self::Output, Self::Error>;
100     fn print_display(
101         &self,
102         cx: PrintCx<'_, '_, 'tcx, P>,
103     ) -> Result<Self::Output, Self::Error> {
104         let old_debug = cx.config.is_debug;
105         cx.config.is_debug = false;
106         let result = self.print(PrintCx {
107             tcx: cx.tcx,
108             printer: cx.printer,
109             config: cx.config,
110         });
111         cx.config.is_debug = old_debug;
112         result
113     }
114     fn print_debug(&self, cx: PrintCx<'_, '_, 'tcx, P>) -> Result<Self::Output, Self::Error> {
115         let old_debug = cx.config.is_debug;
116         cx.config.is_debug = true;
117         let result = self.print(PrintCx {
118             tcx: cx.tcx,
119             printer: cx.printer,
120             config: cx.config,
121         });
122         cx.config.is_debug = old_debug;
123         result
124     }
125 }
126
127 pub trait Printer: Sized {
128     type Error;
129
130     type Path;
131     type Region;
132     type Type;
133
134     fn print_def_path(
135         self: PrintCx<'_, '_, 'tcx, Self>,
136         def_id: DefId,
137         substs: Option<SubstsRef<'tcx>>,
138         projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
139     ) -> Result<Self::Path, Self::Error> {
140         self.default_print_def_path(def_id, substs, projections)
141     }
142     fn print_impl_path(
143         self: PrintCx<'_, '_, 'tcx, Self>,
144         impl_def_id: DefId,
145         substs: Option<SubstsRef<'tcx>>,
146         self_ty: Ty<'tcx>,
147         trait_ref: Option<ty::TraitRef<'tcx>>,
148     ) -> Result<Self::Path, Self::Error> {
149         self.default_print_impl_path(impl_def_id, substs, self_ty, trait_ref)
150     }
151
152     fn print_region(
153         self: PrintCx<'_, '_, '_, Self>,
154         region: ty::Region<'_>,
155     ) -> Result<Self::Region, Self::Error>;
156
157     fn print_type(
158         self: PrintCx<'_, '_, 'tcx, Self>,
159         ty: Ty<'tcx>,
160     ) -> Result<Self::Type, Self::Error>;
161
162     fn path_crate(
163         self: PrintCx<'_, '_, '_, Self>,
164         cnum: CrateNum,
165     ) -> Result<Self::Path, Self::Error>;
166     fn path_qualified(
167         self: PrintCx<'_, '_, 'tcx, Self>,
168         self_ty: Ty<'tcx>,
169         trait_ref: Option<ty::TraitRef<'tcx>>,
170     ) -> Result<Self::Path, Self::Error>;
171
172     fn path_append_impl<'gcx, 'tcx>(
173         self: PrintCx<'_, 'gcx, 'tcx, Self>,
174         print_prefix: impl FnOnce(
175             PrintCx<'_, 'gcx, 'tcx, Self>,
176         ) -> Result<Self::Path, Self::Error>,
177         self_ty: Ty<'tcx>,
178         trait_ref: Option<ty::TraitRef<'tcx>>,
179     ) -> Result<Self::Path, Self::Error>;
180     fn path_append<'gcx, 'tcx>(
181         self: PrintCx<'_, 'gcx, 'tcx, Self>,
182         print_prefix: impl FnOnce(
183             PrintCx<'_, 'gcx, 'tcx, Self>,
184         ) -> Result<Self::Path, Self::Error>,
185         text: &str,
186     ) -> Result<Self::Path, Self::Error>;
187     fn path_generic_args<'gcx, 'tcx>(
188         self: PrintCx<'_, 'gcx, 'tcx, Self>,
189         print_prefix: impl FnOnce(
190             PrintCx<'_, 'gcx, 'tcx, Self>,
191         ) -> Result<Self::Path, Self::Error>,
192         params: &[ty::GenericParamDef],
193         substs: SubstsRef<'tcx>,
194         projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
195     ) -> Result<Self::Path, Self::Error>;
196 }
197
198 impl<P: Printer> PrintCx<'a, 'gcx, 'tcx, P> {
199     pub fn default_print_def_path(
200         self,
201         def_id: DefId,
202         substs: Option<SubstsRef<'tcx>>,
203         projections: impl Iterator<Item = ty::ExistentialProjection<'tcx>>,
204     ) -> Result<P::Path, P::Error> {
205         debug!("default_print_def_path: def_id={:?}, substs={:?}", def_id, substs);
206         let key = self.tcx.def_key(def_id);
207         debug!("default_print_def_path: key={:?}", key);
208
209         match key.disambiguated_data.data {
210             DefPathData::CrateRoot => {
211                 assert!(key.parent.is_none());
212                 self.path_crate(def_id.krate)
213             }
214
215             DefPathData::Impl => {
216                 let mut self_ty = self.tcx.type_of(def_id);
217                 if let Some(substs) = substs {
218                     self_ty = self_ty.subst(self.tcx, substs);
219                 }
220
221                 let mut impl_trait_ref = self.tcx.impl_trait_ref(def_id);
222                 if let Some(substs) = substs {
223                     impl_trait_ref = impl_trait_ref.subst(self.tcx, substs);
224                 }
225                 self.print_impl_path(def_id, substs, self_ty, impl_trait_ref)
226             }
227
228             _ => {
229                 let generics = substs.map(|_| self.tcx.generics_of(def_id));
230                 let generics_parent = generics.as_ref().and_then(|g| g.parent);
231                 let parent_def_id = DefId { index: key.parent.unwrap(), ..def_id };
232                 let print_parent_path = |cx: PrintCx<'_, 'gcx, 'tcx, P>| {
233                     if let Some(generics_parent_def_id) = generics_parent {
234                         assert_eq!(parent_def_id, generics_parent_def_id);
235
236                         // FIXME(eddyb) try to move this into the parent's printing
237                         // logic, instead of doing it when printing the child.
238                         let parent_generics = cx.tcx.generics_of(parent_def_id);
239                         let parent_has_own_self =
240                             parent_generics.has_self && parent_generics.parent_count == 0;
241                         if let (Some(substs), true) = (substs, parent_has_own_self) {
242                             let trait_ref = ty::TraitRef::new(parent_def_id, substs);
243                             cx.path_qualified(trait_ref.self_ty(), Some(trait_ref))
244                         } else {
245                             cx.print_def_path(parent_def_id, substs, iter::empty())
246                         }
247                     } else {
248                         cx.print_def_path(parent_def_id, None, iter::empty())
249                     }
250                 };
251                 let print_path = |cx: PrintCx<'_, 'gcx, 'tcx, P>| {
252                     match key.disambiguated_data.data {
253                         // Skip `::{{constructor}}` on tuple/unit structs.
254                         DefPathData::StructCtor => print_parent_path(cx),
255
256                         _ => {
257                             cx.path_append(
258                                 print_parent_path,
259                                 &key.disambiguated_data.data.as_interned_str().as_str(),
260                             )
261                         }
262                     }
263                 };
264
265                 if let (Some(generics), Some(substs)) = (generics, substs) {
266                     let has_own_self = generics.has_self && generics.parent_count == 0;
267                     let params = &generics.params[has_own_self as usize..];
268                     self.path_generic_args(print_path, params, substs, projections)
269                 } else {
270                     print_path(self)
271                 }
272             }
273         }
274     }
275
276     fn default_print_impl_path(
277         self,
278         impl_def_id: DefId,
279         _substs: Option<SubstsRef<'tcx>>,
280         self_ty: Ty<'tcx>,
281         impl_trait_ref: Option<ty::TraitRef<'tcx>>,
282     ) -> Result<P::Path, P::Error> {
283         debug!("default_print_impl_path: impl_def_id={:?}, self_ty={}, impl_trait_ref={:?}",
284                impl_def_id, self_ty, impl_trait_ref);
285
286         // Decide whether to print the parent path for the impl.
287         // Logically, since impls are global, it's never needed, but
288         // users may find it useful. Currently, we omit the parent if
289         // the impl is either in the same module as the self-type or
290         // as the trait.
291         let parent_def_id = self.tcx.parent(impl_def_id).unwrap();
292         let in_self_mod = match characteristic_def_id_of_type(self_ty) {
293             None => false,
294             Some(ty_def_id) => self.tcx.parent(ty_def_id) == Some(parent_def_id),
295         };
296         let in_trait_mod = match impl_trait_ref {
297             None => false,
298             Some(trait_ref) => self.tcx.parent(trait_ref.def_id) == Some(parent_def_id),
299         };
300
301         if !in_self_mod && !in_trait_mod {
302             // If the impl is not co-located with either self-type or
303             // trait-type, then fallback to a format that identifies
304             // the module more clearly.
305             self.path_append_impl(
306                 |cx| cx.print_def_path(parent_def_id, None, iter::empty()),
307                 self_ty,
308                 impl_trait_ref,
309             )
310         } else {
311             // Otherwise, try to give a good form that would be valid language
312             // syntax. Preferably using associated item notation.
313             self.path_qualified(self_ty, impl_trait_ref)
314         }
315     }
316 }
317
318 /// As a heuristic, when we see an impl, if we see that the
319 /// 'self type' is a type defined in the same module as the impl,
320 /// we can omit including the path to the impl itself. This
321 /// function tries to find a "characteristic `DefId`" for a
322 /// type. It's just a heuristic so it makes some questionable
323 /// decisions and we may want to adjust it later.
324 pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> {
325     match ty.sty {
326         ty::Adt(adt_def, _) => Some(adt_def.did),
327
328         ty::Dynamic(data, ..) => data.principal_def_id(),
329
330         ty::Array(subty, _) |
331         ty::Slice(subty) => characteristic_def_id_of_type(subty),
332
333         ty::RawPtr(mt) => characteristic_def_id_of_type(mt.ty),
334
335         ty::Ref(_, ty, _) => characteristic_def_id_of_type(ty),
336
337         ty::Tuple(ref tys) => tys.iter()
338                                    .filter_map(|ty| characteristic_def_id_of_type(ty))
339                                    .next(),
340
341         ty::FnDef(def_id, _) |
342         ty::Closure(def_id, _) |
343         ty::Generator(def_id, _, _) |
344         ty::Foreign(def_id) => Some(def_id),
345
346         ty::Bool |
347         ty::Char |
348         ty::Int(_) |
349         ty::Uint(_) |
350         ty::Str |
351         ty::FnPtr(_) |
352         ty::Projection(_) |
353         ty::Placeholder(..) |
354         ty::UnnormalizedProjection(..) |
355         ty::Param(_) |
356         ty::Opaque(..) |
357         ty::Infer(_) |
358         ty::Bound(..) |
359         ty::Error |
360         ty::GeneratorWitness(..) |
361         ty::Never |
362         ty::Float(_) => None,
363     }
364 }