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