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