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