]> git.lizzy.rs Git - rust.git/blob - src/librustc/ty/print/mod.rs
Rollup merge of #61389 - Zoxc:arena-cleanup, r=eddyb
[rust.git] / src / librustc / ty / print / mod.rs
1 use crate::hir::map::{DefPathData, DisambiguatedDefPathData};
2 use crate::hir::def_id::{CrateNum, DefId};
3 use crate::ty::{self, DefIdTree, Ty, TyCtxt};
4 use crate::ty::subst::{Kind, Subst};
5
6 use rustc_data_structures::fx::FxHashSet;
7
8 // `pretty` is a separate module only for organization.
9 mod pretty;
10 pub use self::pretty::*;
11
12 pub trait Print<'gcx, 'tcx, P> {
13     type Output;
14     type Error;
15
16     fn print(&self, cx: P) -> Result<Self::Output, Self::Error>;
17 }
18
19 /// Interface for outputting user-facing "type-system entities"
20 /// (paths, types, lifetimes, constants, etc.) as a side-effect
21 /// (e.g. formatting, like `PrettyPrinter` implementors do) or by
22 /// constructing some alternative representation (e.g. an AST),
23 /// which the associated types allow passing through the methods.
24 ///
25 /// For pretty-printing/formatting in particular, see `PrettyPrinter`.
26 // FIXME(eddyb) find a better name, this is more general than "printing".
27 pub trait Printer<'gcx: 'tcx, 'tcx>: Sized {
28     type Error;
29
30     type Path;
31     type Region;
32     type Type;
33     type DynExistential;
34     type Const;
35
36     fn tcx(&'a self) -> TyCtxt<'a, 'gcx, 'tcx>;
37
38     fn print_def_path(
39         self,
40         def_id: DefId,
41         substs: &'tcx [Kind<'tcx>],
42     ) -> Result<Self::Path, Self::Error> {
43         self.default_print_def_path(def_id, substs)
44     }
45     fn print_impl_path(
46         self,
47         impl_def_id: DefId,
48         substs: &'tcx [Kind<'tcx>],
49         self_ty: Ty<'tcx>,
50         trait_ref: Option<ty::TraitRef<'tcx>>,
51     ) -> Result<Self::Path, Self::Error> {
52         self.default_print_impl_path(impl_def_id, substs, self_ty, trait_ref)
53     }
54
55     fn print_region(
56         self,
57         region: ty::Region<'_>,
58     ) -> Result<Self::Region, Self::Error>;
59
60     fn print_type(
61         self,
62         ty: Ty<'tcx>,
63     ) -> Result<Self::Type, Self::Error>;
64
65     fn print_dyn_existential(
66         self,
67         predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>,
68     ) -> Result<Self::DynExistential, Self::Error>;
69
70     fn print_const(
71         self,
72         ct: &'tcx ty::Const<'tcx>,
73     ) -> Result<Self::Const, Self::Error>;
74
75     fn path_crate(
76         self,
77         cnum: CrateNum,
78     ) -> Result<Self::Path, Self::Error>;
79     fn path_qualified(
80         self,
81         self_ty: Ty<'tcx>,
82         trait_ref: Option<ty::TraitRef<'tcx>>,
83     ) -> Result<Self::Path, Self::Error>;
84
85     fn path_append_impl(
86         self,
87         print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
88         disambiguated_data: &DisambiguatedDefPathData,
89         self_ty: Ty<'tcx>,
90         trait_ref: Option<ty::TraitRef<'tcx>>,
91     ) -> Result<Self::Path, Self::Error>;
92     fn path_append(
93         self,
94         print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
95         disambiguated_data: &DisambiguatedDefPathData,
96     ) -> Result<Self::Path, Self::Error>;
97     fn path_generic_args(
98         self,
99         print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
100         args: &[Kind<'tcx>],
101     ) -> Result<Self::Path, Self::Error>;
102
103     // Defaults (should not be overriden):
104
105     fn default_print_def_path(
106         self,
107         def_id: DefId,
108         substs: &'tcx [Kind<'tcx>],
109     ) -> Result<Self::Path, Self::Error> {
110         debug!("default_print_def_path: def_id={:?}, substs={:?}", def_id, substs);
111         let key = self.tcx().def_key(def_id);
112         debug!("default_print_def_path: key={:?}", key);
113
114         match key.disambiguated_data.data {
115             DefPathData::CrateRoot => {
116                 assert!(key.parent.is_none());
117                 self.path_crate(def_id.krate)
118             }
119
120             DefPathData::Impl => {
121                 let generics = self.tcx().generics_of(def_id);
122                 let mut self_ty = self.tcx().type_of(def_id);
123                 let mut impl_trait_ref = self.tcx().impl_trait_ref(def_id);
124                 if substs.len() >= generics.count() {
125                     self_ty = self_ty.subst(self.tcx(), substs);
126                     impl_trait_ref = impl_trait_ref.subst(self.tcx(), substs);
127                 }
128                 self.print_impl_path(def_id, substs, self_ty, impl_trait_ref)
129             }
130
131             _ => {
132                 let parent_def_id = DefId { index: key.parent.unwrap(), ..def_id };
133
134                 let mut parent_substs = substs;
135                 let mut trait_qualify_parent = false;
136                 if !substs.is_empty() {
137                     let generics = self.tcx().generics_of(def_id);
138                     parent_substs = &substs[..generics.parent_count.min(substs.len())];
139
140                     match key.disambiguated_data.data {
141                         // Closures' own generics are only captures, don't print them.
142                         DefPathData::ClosureExpr => {}
143
144                         // If we have any generic arguments to print, we do that
145                         // on top of the same path, but without its own generics.
146                         _ => if !generics.params.is_empty() && substs.len() >= generics.count() {
147                             let args = self.generic_args_to_print(generics, substs);
148                             return self.path_generic_args(
149                                 |cx| cx.print_def_path(def_id, parent_substs),
150                                 args,
151                             );
152                         }
153                     }
154
155                     // FIXME(eddyb) try to move this into the parent's printing
156                     // logic, instead of doing it when printing the child.
157                     trait_qualify_parent =
158                         generics.has_self &&
159                         generics.parent == Some(parent_def_id) &&
160                         parent_substs.len() == generics.parent_count &&
161                         self.tcx().generics_of(parent_def_id).parent_count == 0;
162                 }
163
164                 self.path_append(
165                     |cx: Self| if trait_qualify_parent {
166                         let trait_ref = ty::TraitRef::new(
167                             parent_def_id,
168                             cx.tcx().intern_substs(parent_substs),
169                         );
170                         cx.path_qualified(trait_ref.self_ty(), Some(trait_ref))
171                     } else {
172                         cx.print_def_path(parent_def_id, parent_substs)
173                     },
174                     &key.disambiguated_data,
175                 )
176             }
177         }
178     }
179
180     fn generic_args_to_print(
181         &self,
182         generics: &'tcx ty::Generics,
183         substs: &'tcx [Kind<'tcx>],
184     ) -> &'tcx [Kind<'tcx>] {
185         let mut own_params = generics.parent_count..generics.count();
186
187         // Don't print args for `Self` parameters (of traits).
188         if generics.has_self && own_params.start == 0 {
189             own_params.start = 1;
190         }
191
192         // Don't print args that are the defaults of their respective parameters.
193         own_params.end -= generics.params.iter().rev().take_while(|param| {
194             match param.kind {
195                 ty::GenericParamDefKind::Lifetime => false,
196                 ty::GenericParamDefKind::Type { has_default, .. } => {
197                     has_default && substs[param.index as usize] == Kind::from(
198                         self.tcx().type_of(param.def_id).subst(self.tcx(), substs)
199                     )
200                 }
201                 ty::GenericParamDefKind::Const => false, // FIXME(const_generics:defaults)
202             }
203         }).count();
204
205         &substs[own_params]
206     }
207
208     fn default_print_impl_path(
209         self,
210         impl_def_id: DefId,
211         _substs: &'tcx [Kind<'tcx>],
212         self_ty: Ty<'tcx>,
213         impl_trait_ref: Option<ty::TraitRef<'tcx>>,
214     ) -> Result<Self::Path, Self::Error> {
215         debug!("default_print_impl_path: impl_def_id={:?}, self_ty={}, impl_trait_ref={:?}",
216                impl_def_id, self_ty, impl_trait_ref);
217
218         let key = self.tcx().def_key(impl_def_id);
219         let parent_def_id = DefId { index: key.parent.unwrap(), ..impl_def_id };
220
221         // Decide whether to print the parent path for the impl.
222         // Logically, since impls are global, it's never needed, but
223         // users may find it useful. Currently, we omit the parent if
224         // the impl is either in the same module as the self-type or
225         // as the trait.
226         let in_self_mod = match characteristic_def_id_of_type(self_ty) {
227             None => false,
228             Some(ty_def_id) => self.tcx().parent(ty_def_id) == Some(parent_def_id),
229         };
230         let in_trait_mod = match impl_trait_ref {
231             None => false,
232             Some(trait_ref) => self.tcx().parent(trait_ref.def_id) == Some(parent_def_id),
233         };
234
235         if !in_self_mod && !in_trait_mod {
236             // If the impl is not co-located with either self-type or
237             // trait-type, then fallback to a format that identifies
238             // the module more clearly.
239             self.path_append_impl(
240                 |cx| cx.print_def_path(parent_def_id, &[]),
241                 &key.disambiguated_data,
242                 self_ty,
243                 impl_trait_ref,
244             )
245         } else {
246             // Otherwise, try to give a good form that would be valid language
247             // syntax. Preferably using associated item notation.
248             self.path_qualified(self_ty, impl_trait_ref)
249         }
250     }
251 }
252
253 /// As a heuristic, when we see an impl, if we see that the
254 /// 'self type' is a type defined in the same module as the impl,
255 /// we can omit including the path to the impl itself. This
256 /// function tries to find a "characteristic `DefId`" for a
257 /// type. It's just a heuristic so it makes some questionable
258 /// decisions and we may want to adjust it later.
259 pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> {
260     match ty.sty {
261         ty::Adt(adt_def, _) => Some(adt_def.did),
262
263         ty::Dynamic(data, ..) => data.principal_def_id(),
264
265         ty::Array(subty, _) |
266         ty::Slice(subty) => characteristic_def_id_of_type(subty),
267
268         ty::RawPtr(mt) => characteristic_def_id_of_type(mt.ty),
269
270         ty::Ref(_, ty, _) => characteristic_def_id_of_type(ty),
271
272         ty::Tuple(ref tys) => tys.iter()
273                                    .filter_map(|ty| characteristic_def_id_of_type(ty.expect_ty()))
274                                    .next(),
275
276         ty::FnDef(def_id, _) |
277         ty::Closure(def_id, _) |
278         ty::Generator(def_id, _, _) |
279         ty::Foreign(def_id) => Some(def_id),
280
281         ty::Bool |
282         ty::Char |
283         ty::Int(_) |
284         ty::Uint(_) |
285         ty::Str |
286         ty::FnPtr(_) |
287         ty::Projection(_) |
288         ty::Placeholder(..) |
289         ty::UnnormalizedProjection(..) |
290         ty::Param(_) |
291         ty::Opaque(..) |
292         ty::Infer(_) |
293         ty::Bound(..) |
294         ty::Error |
295         ty::GeneratorWitness(..) |
296         ty::Never |
297         ty::Float(_) => None,
298     }
299 }
300
301 impl<'gcx: 'tcx, 'tcx, P: Printer<'gcx, 'tcx>> Print<'gcx, 'tcx, P> for ty::RegionKind {
302     type Output = P::Region;
303     type Error = P::Error;
304     fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
305         cx.print_region(self)
306     }
307 }
308
309 impl<'gcx: 'tcx, 'tcx, P: Printer<'gcx, 'tcx>> Print<'gcx, 'tcx, P> for ty::Region<'_> {
310     type Output = P::Region;
311     type Error = P::Error;
312     fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
313         cx.print_region(self)
314     }
315 }
316
317 impl<'gcx: 'tcx, 'tcx, P: Printer<'gcx, 'tcx>> Print<'gcx, 'tcx, P> for Ty<'tcx> {
318     type Output = P::Type;
319     type Error = P::Error;
320     fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
321         cx.print_type(self)
322     }
323 }
324
325 impl<'gcx: 'tcx, 'tcx, P: Printer<'gcx, 'tcx>> Print<'gcx, 'tcx, P>
326     for &'tcx ty::List<ty::ExistentialPredicate<'tcx>>
327 {
328     type Output = P::DynExistential;
329     type Error = P::Error;
330     fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
331         cx.print_dyn_existential(self)
332     }
333 }
334
335 impl<'gcx: 'tcx, 'tcx, P: Printer<'gcx, 'tcx>> Print<'gcx, 'tcx, P> for &'tcx ty::Const<'tcx> {
336     type Output = P::Const;
337     type Error = P::Error;
338     fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
339         cx.print_const(self)
340     }
341 }