]>
Commit | Line | Data |
---|---|---|
2b03887a | 1 | use crate::ty::GenericArg; |
dfeec247 | 2 | use crate::ty::{self, DefIdTree, Ty, TyCtxt}; |
532ac7d7 XL |
3 | |
4 | use rustc_data_structures::fx::FxHashSet; | |
29967ef6 | 5 | use rustc_data_structures::sso::SsoHashSet; |
2b03887a | 6 | use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; |
ba9703b0 | 7 | use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; |
532ac7d7 XL |
8 | |
9 | // `pretty` is a separate module only for organization. | |
10 | mod pretty; | |
11 | pub use self::pretty::*; | |
12 | ||
dc9dc135 XL |
13 | // FIXME(eddyb) false positive, the lifetime parameters are used with `P: Printer<...>`. |
14 | #[allow(unused_lifetimes)] | |
15 | pub trait Print<'tcx, P> { | |
532ac7d7 XL |
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`. | |
e1599b0c XL |
29 | // |
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 | |
a2a8927a | 40 | fn tcx<'a>(&'a self) -> TyCtxt<'tcx>; |
532ac7d7 XL |
41 | |
42 | fn print_def_path( | |
43 | self, | |
44 | def_id: DefId, | |
e74abb32 | 45 | substs: &'tcx [GenericArg<'tcx>], |
532ac7d7 XL |
46 | ) -> Result<Self::Path, Self::Error> { |
47 | self.default_print_def_path(def_id, substs) | |
48 | } | |
e1599b0c | 49 | |
532ac7d7 XL |
50 | fn print_impl_path( |
51 | self, | |
52 | impl_def_id: DefId, | |
e74abb32 | 53 | substs: &'tcx [GenericArg<'tcx>], |
532ac7d7 XL |
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 | ||
923072b8 | 60 | fn print_region(self, region: ty::Region<'tcx>) -> Result<Self::Region, Self::Error>; |
532ac7d7 | 61 | |
dfeec247 | 62 | fn print_type(self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error>; |
532ac7d7 XL |
63 | |
64 | fn print_dyn_existential( | |
65 | self, | |
487cf647 | 66 | predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, |
532ac7d7 XL |
67 | ) -> Result<Self::DynExistential, Self::Error>; |
68 | ||
5099ac24 | 69 | fn print_const(self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error>; |
dc9dc135 | 70 | |
dfeec247 | 71 | fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error>; |
e1599b0c | 72 | |
532ac7d7 XL |
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>; | |
e1599b0c | 86 | |
532ac7d7 XL |
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>; | |
e1599b0c | 92 | |
532ac7d7 XL |
93 | fn path_generic_args( |
94 | self, | |
95 | print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, | |
e74abb32 | 96 | args: &[GenericArg<'tcx>], |
532ac7d7 XL |
97 | ) -> Result<Self::Path, Self::Error>; |
98 | ||
74b04a01 | 99 | // Defaults (should not be overridden): |
532ac7d7 | 100 | |
c295e0f8 | 101 | #[instrument(skip(self), level = "debug")] |
532ac7d7 XL |
102 | fn default_print_def_path( |
103 | self, | |
104 | def_id: DefId, | |
e74abb32 | 105 | substs: &'tcx [GenericArg<'tcx>], |
532ac7d7 | 106 | ) -> Result<Self::Path, Self::Error> { |
532ac7d7 | 107 | let key = self.tcx().def_key(def_id); |
c295e0f8 | 108 | debug!(?key); |
532ac7d7 XL |
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); | |
04454e1e | 118 | let self_ty = self.tcx().bound_type_of(def_id); |
f25598a0 | 119 | let impl_trait_ref = self.tcx().impl_trait_ref(def_id); |
04454e1e FG |
120 | let (self_ty, impl_trait_ref) = if substs.len() >= generics.count() { |
121 | ( | |
122 | self_ty.subst(self.tcx(), substs), | |
123 | impl_trait_ref.map(|i| i.subst(self.tcx(), substs)), | |
124 | ) | |
125 | } else { | |
126 | (self_ty.0, impl_trait_ref.map(|i| i.0)) | |
127 | }; | |
532ac7d7 XL |
128 | self.print_impl_path(def_id, substs, self_ty, impl_trait_ref) |
129 | } | |
130 | ||
131 | _ => { | |
132 | let parent_def_id = DefId { index: key.parent.unwrap(), ..def_id }; | |
133 | ||
134 | let mut parent_substs = substs; | |
135 | let mut trait_qualify_parent = false; | |
136 | if !substs.is_empty() { | |
137 | let generics = self.tcx().generics_of(def_id); | |
138 | parent_substs = &substs[..generics.parent_count.min(substs.len())]; | |
139 | ||
140 | match key.disambiguated_data.data { | |
141 | // Closures' own generics are only captures, don't print them. | |
142 | DefPathData::ClosureExpr => {} | |
04454e1e FG |
143 | // This covers both `DefKind::AnonConst` and `DefKind::InlineConst`. |
144 | // Anon consts doesn't have their own generics, and inline consts' own | |
145 | // generics are their inferred types, so don't print them. | |
146 | DefPathData::AnonConst => {} | |
532ac7d7 XL |
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. | |
dfeec247 XL |
150 | _ => { |
151 | if !generics.params.is_empty() && substs.len() >= generics.count() { | |
923072b8 | 152 | let args = generics.own_substs_no_defaults(self.tcx(), substs); |
dfeec247 XL |
153 | return self.path_generic_args( |
154 | |cx| cx.print_def_path(def_id, parent_substs), | |
155 | args, | |
156 | ); | |
157 | } | |
532ac7d7 XL |
158 | } |
159 | } | |
160 | ||
161 | // FIXME(eddyb) try to move this into the parent's printing | |
162 | // logic, instead of doing it when printing the child. | |
dfeec247 XL |
163 | trait_qualify_parent = generics.has_self |
164 | && generics.parent == Some(parent_def_id) | |
165 | && parent_substs.len() == generics.parent_count | |
166 | && self.tcx().generics_of(parent_def_id).parent_count == 0; | |
532ac7d7 XL |
167 | } |
168 | ||
169 | self.path_append( | |
dfeec247 XL |
170 | |cx: Self| { |
171 | if trait_qualify_parent { | |
f25598a0 FG |
172 | let trait_ref = |
173 | cx.tcx().mk_trait_ref(parent_def_id, parent_substs.iter().copied()); | |
dfeec247 XL |
174 | cx.path_qualified(trait_ref.self_ty(), Some(trait_ref)) |
175 | } else { | |
176 | cx.print_def_path(parent_def_id, parent_substs) | |
177 | } | |
532ac7d7 XL |
178 | }, |
179 | &key.disambiguated_data, | |
180 | ) | |
181 | } | |
182 | } | |
183 | } | |
184 | ||
532ac7d7 XL |
185 | fn default_print_impl_path( |
186 | self, | |
187 | impl_def_id: DefId, | |
e74abb32 | 188 | _substs: &'tcx [GenericArg<'tcx>], |
532ac7d7 XL |
189 | self_ty: Ty<'tcx>, |
190 | impl_trait_ref: Option<ty::TraitRef<'tcx>>, | |
191 | ) -> Result<Self::Path, Self::Error> { | |
dfeec247 XL |
192 | debug!( |
193 | "default_print_impl_path: impl_def_id={:?}, self_ty={}, impl_trait_ref={:?}", | |
194 | impl_def_id, self_ty, impl_trait_ref | |
195 | ); | |
532ac7d7 XL |
196 | |
197 | let key = self.tcx().def_key(impl_def_id); | |
198 | let parent_def_id = DefId { index: key.parent.unwrap(), ..impl_def_id }; | |
199 | ||
200 | // Decide whether to print the parent path for the impl. | |
201 | // Logically, since impls are global, it's never needed, but | |
202 | // users may find it useful. Currently, we omit the parent if | |
203 | // the impl is either in the same module as the self-type or | |
204 | // as the trait. | |
205 | let in_self_mod = match characteristic_def_id_of_type(self_ty) { | |
206 | None => false, | |
04454e1e | 207 | Some(ty_def_id) => self.tcx().parent(ty_def_id) == parent_def_id, |
532ac7d7 XL |
208 | }; |
209 | let in_trait_mod = match impl_trait_ref { | |
210 | None => false, | |
04454e1e | 211 | Some(trait_ref) => self.tcx().parent(trait_ref.def_id) == parent_def_id, |
532ac7d7 XL |
212 | }; |
213 | ||
214 | if !in_self_mod && !in_trait_mod { | |
215 | // If the impl is not co-located with either self-type or | |
216 | // trait-type, then fallback to a format that identifies | |
217 | // the module more clearly. | |
218 | self.path_append_impl( | |
219 | |cx| cx.print_def_path(parent_def_id, &[]), | |
220 | &key.disambiguated_data, | |
221 | self_ty, | |
222 | impl_trait_ref, | |
223 | ) | |
224 | } else { | |
225 | // Otherwise, try to give a good form that would be valid language | |
226 | // syntax. Preferably using associated item notation. | |
227 | self.path_qualified(self_ty, impl_trait_ref) | |
228 | } | |
229 | } | |
230 | } | |
231 | ||
232 | /// As a heuristic, when we see an impl, if we see that the | |
233 | /// 'self type' is a type defined in the same module as the impl, | |
234 | /// we can omit including the path to the impl itself. This | |
235 | /// function tries to find a "characteristic `DefId`" for a | |
236 | /// type. It's just a heuristic so it makes some questionable | |
237 | /// decisions and we may want to adjust it later. | |
6c58768f XL |
238 | /// |
239 | /// Visited set is needed to avoid full iteration over | |
240 | /// deeply nested tuples that have no DefId. | |
241 | fn characteristic_def_id_of_type_cached<'a>( | |
242 | ty: Ty<'a>, | |
29967ef6 | 243 | visited: &mut SsoHashSet<Ty<'a>>, |
6c58768f | 244 | ) -> Option<DefId> { |
1b1a35ee | 245 | match *ty.kind() { |
5e7ed085 | 246 | ty::Adt(adt_def, _) => Some(adt_def.did()), |
532ac7d7 XL |
247 | |
248 | ty::Dynamic(data, ..) => data.principal_def_id(), | |
249 | ||
6c58768f XL |
250 | ty::Array(subty, _) | ty::Slice(subty) => { |
251 | characteristic_def_id_of_type_cached(subty, visited) | |
252 | } | |
532ac7d7 | 253 | |
6c58768f | 254 | ty::RawPtr(mt) => characteristic_def_id_of_type_cached(mt.ty, visited), |
532ac7d7 | 255 | |
6c58768f | 256 | ty::Ref(_, ty, _) => characteristic_def_id_of_type_cached(ty, visited), |
532ac7d7 | 257 | |
6c58768f | 258 | ty::Tuple(ref tys) => tys.iter().find_map(|ty| { |
6c58768f XL |
259 | if visited.insert(ty) { |
260 | return characteristic_def_id_of_type_cached(ty, visited); | |
261 | } | |
262 | return None; | |
263 | }), | |
dfeec247 XL |
264 | |
265 | ty::FnDef(def_id, _) | |
266 | | ty::Closure(def_id, _) | |
267 | | ty::Generator(def_id, _, _) | |
268 | | ty::Foreign(def_id) => Some(def_id), | |
269 | ||
270 | ty::Bool | |
271 | | ty::Char | |
272 | | ty::Int(_) | |
273 | | ty::Uint(_) | |
274 | | ty::Str | |
275 | | ty::FnPtr(_) | |
f25598a0 | 276 | | ty::Alias(..) |
dfeec247 | 277 | | ty::Placeholder(..) |
dfeec247 | 278 | | ty::Param(_) |
dfeec247 XL |
279 | | ty::Infer(_) |
280 | | ty::Bound(..) | |
f035d41b | 281 | | ty::Error(_) |
dfeec247 XL |
282 | | ty::GeneratorWitness(..) |
283 | | ty::Never | |
284 | | ty::Float(_) => None, | |
532ac7d7 XL |
285 | } |
286 | } | |
6c58768f | 287 | pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> { |
29967ef6 | 288 | characteristic_def_id_of_type_cached(ty, &mut SsoHashSet::new()) |
6c58768f | 289 | } |
532ac7d7 | 290 | |
923072b8 | 291 | impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::Region<'tcx> { |
532ac7d7 XL |
292 | type Output = P::Region; |
293 | type Error = P::Error; | |
294 | fn print(&self, cx: P) -> Result<Self::Output, Self::Error> { | |
5099ac24 | 295 | cx.print_region(*self) |
532ac7d7 XL |
296 | } |
297 | } | |
298 | ||
dc9dc135 | 299 | impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for Ty<'tcx> { |
532ac7d7 XL |
300 | type Output = P::Type; |
301 | type Error = P::Error; | |
923072b8 | 302 | |
532ac7d7 | 303 | fn print(&self, cx: P) -> Result<Self::Output, Self::Error> { |
5099ac24 | 304 | cx.print_type(*self) |
532ac7d7 XL |
305 | } |
306 | } | |
307 | ||
487cf647 | 308 | impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> { |
532ac7d7 XL |
309 | type Output = P::DynExistential; |
310 | type Error = P::Error; | |
311 | fn print(&self, cx: P) -> Result<Self::Output, Self::Error> { | |
312 | cx.print_dyn_existential(self) | |
313 | } | |
314 | } | |
dc9dc135 | 315 | |
5099ac24 | 316 | impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::Const<'tcx> { |
dc9dc135 XL |
317 | type Output = P::Const; |
318 | type Error = P::Error; | |
319 | fn print(&self, cx: P) -> Result<Self::Output, Self::Error> { | |
5099ac24 | 320 | cx.print_const(*self) |
dc9dc135 XL |
321 | } |
322 | } | |
2b03887a FG |
323 | |
324 | // This is only used by query descriptions | |
325 | pub fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String { | |
326 | if def_id.is_top_level_module() { | |
327 | "top-level module".to_string() | |
328 | } else { | |
329 | format!("module `{}`", tcx.def_path_str(def_id.to_def_id())) | |
330 | } | |
331 | } |