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