]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_middle/src/ty/print/mod.rs
New upstream version 1.51.0+dfsg1
[rustc.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 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<ty::ExistentialPredicate<'tcx>>>,
67 ) -> Result<Self::DynExistential, Self::Error>;
68
69 fn print_const(self, ct: &'tcx 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 fn default_print_def_path(
102 self,
103 def_id: DefId,
104 substs: &'tcx [GenericArg<'tcx>],
105 ) -> Result<Self::Path, Self::Error> {
106 debug!("default_print_def_path: def_id={:?}, substs={:?}", def_id, substs);
107 let key = self.tcx().def_key(def_id);
108 debug!("default_print_def_path: key={:?}", 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| {
197 match param.kind {
198 ty::GenericParamDefKind::Lifetime => false,
199 ty::GenericParamDefKind::Type { has_default, .. } => {
200 has_default
201 && substs[param.index as usize]
202 == GenericArg::from(
203 self.tcx().type_of(param.def_id).subst(self.tcx(), substs),
204 )
205 }
206 ty::GenericParamDefKind::Const => false, // FIXME(const_generics_defaults)
207 }
208 })
209 .count();
210
211 &substs[own_params]
212 }
213
214 fn default_print_impl_path(
215 self,
216 impl_def_id: DefId,
217 _substs: &'tcx [GenericArg<'tcx>],
218 self_ty: Ty<'tcx>,
219 impl_trait_ref: Option<ty::TraitRef<'tcx>>,
220 ) -> Result<Self::Path, Self::Error> {
221 debug!(
222 "default_print_impl_path: impl_def_id={:?}, self_ty={}, impl_trait_ref={:?}",
223 impl_def_id, self_ty, impl_trait_ref
224 );
225
226 let key = self.tcx().def_key(impl_def_id);
227 let parent_def_id = DefId { index: key.parent.unwrap(), ..impl_def_id };
228
229 // Decide whether to print the parent path for the impl.
230 // Logically, since impls are global, it's never needed, but
231 // users may find it useful. Currently, we omit the parent if
232 // the impl is either in the same module as the self-type or
233 // as the trait.
234 let in_self_mod = match characteristic_def_id_of_type(self_ty) {
235 None => false,
236 Some(ty_def_id) => self.tcx().parent(ty_def_id) == Some(parent_def_id),
237 };
238 let in_trait_mod = match impl_trait_ref {
239 None => false,
240 Some(trait_ref) => self.tcx().parent(trait_ref.def_id) == Some(parent_def_id),
241 };
242
243 if !in_self_mod && !in_trait_mod {
244 // If the impl is not co-located with either self-type or
245 // trait-type, then fallback to a format that identifies
246 // the module more clearly.
247 self.path_append_impl(
248 |cx| cx.print_def_path(parent_def_id, &[]),
249 &key.disambiguated_data,
250 self_ty,
251 impl_trait_ref,
252 )
253 } else {
254 // Otherwise, try to give a good form that would be valid language
255 // syntax. Preferably using associated item notation.
256 self.path_qualified(self_ty, impl_trait_ref)
257 }
258 }
259 }
260
261 /// As a heuristic, when we see an impl, if we see that the
262 /// 'self type' is a type defined in the same module as the impl,
263 /// we can omit including the path to the impl itself. This
264 /// function tries to find a "characteristic `DefId`" for a
265 /// type. It's just a heuristic so it makes some questionable
266 /// decisions and we may want to adjust it later.
267 ///
268 /// Visited set is needed to avoid full iteration over
269 /// deeply nested tuples that have no DefId.
270 fn characteristic_def_id_of_type_cached<'a>(
271 ty: Ty<'a>,
272 visited: &mut SsoHashSet<Ty<'a>>,
273 ) -> Option<DefId> {
274 match *ty.kind() {
275 ty::Adt(adt_def, _) => Some(adt_def.did),
276
277 ty::Dynamic(data, ..) => data.principal_def_id(),
278
279 ty::Array(subty, _) | ty::Slice(subty) => {
280 characteristic_def_id_of_type_cached(subty, visited)
281 }
282
283 ty::RawPtr(mt) => characteristic_def_id_of_type_cached(mt.ty, visited),
284
285 ty::Ref(_, ty, _) => characteristic_def_id_of_type_cached(ty, visited),
286
287 ty::Tuple(ref tys) => tys.iter().find_map(|ty| {
288 let ty = ty.expect_ty();
289 if visited.insert(ty) {
290 return characteristic_def_id_of_type_cached(ty, visited);
291 }
292 return None;
293 }),
294
295 ty::FnDef(def_id, _)
296 | ty::Closure(def_id, _)
297 | ty::Generator(def_id, _, _)
298 | ty::Foreign(def_id) => Some(def_id),
299
300 ty::Bool
301 | ty::Char
302 | ty::Int(_)
303 | ty::Uint(_)
304 | ty::Str
305 | ty::FnPtr(_)
306 | ty::Projection(_)
307 | ty::Placeholder(..)
308 | ty::Param(_)
309 | ty::Opaque(..)
310 | ty::Infer(_)
311 | ty::Bound(..)
312 | ty::Error(_)
313 | ty::GeneratorWitness(..)
314 | ty::Never
315 | ty::Float(_) => None,
316 }
317 }
318 pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> {
319 characteristic_def_id_of_type_cached(ty, &mut SsoHashSet::new())
320 }
321
322 impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::RegionKind {
323 type Output = P::Region;
324 type Error = P::Error;
325 fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
326 cx.print_region(self)
327 }
328 }
329
330 impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::Region<'_> {
331 type Output = P::Region;
332 type Error = P::Error;
333 fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
334 cx.print_region(self)
335 }
336 }
337
338 impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for Ty<'tcx> {
339 type Output = P::Type;
340 type Error = P::Error;
341 fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
342 cx.print_type(self)
343 }
344 }
345
346 impl<'tcx, P: Printer<'tcx>> Print<'tcx, P>
347 for &'tcx ty::List<ty::Binder<ty::ExistentialPredicate<'tcx>>>
348 {
349 type Output = P::DynExistential;
350 type Error = P::Error;
351 fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
352 cx.print_dyn_existential(self)
353 }
354 }
355
356 impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for &'tcx ty::Const<'tcx> {
357 type Output = P::Const;
358 type Error = P::Error;
359 fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
360 cx.print_const(self)
361 }
362 }