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