]>
Commit | Line | Data |
---|---|---|
2b03887a | 1 | use crate::ty::GenericArg; |
353b0b11 | 2 | use crate::ty::{self, 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 | ||
ed00b5ec | 13 | pub type PrintError = std::fmt::Error; |
532ac7d7 | 14 | |
ed00b5ec FG |
15 | pub trait Print<'tcx, P> { |
16 | fn print(&self, cx: &mut P) -> Result<(), PrintError>; | |
532ac7d7 XL |
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`. | |
e1599b0c XL |
26 | // |
27 | // FIXME(eddyb) find a better name; this is more general than "printing". | |
dc9dc135 | 28 | pub trait Printer<'tcx>: Sized { |
a2a8927a | 29 | fn tcx<'a>(&'a self) -> TyCtxt<'tcx>; |
532ac7d7 XL |
30 | |
31 | fn print_def_path( | |
ed00b5ec | 32 | &mut self, |
532ac7d7 | 33 | def_id: DefId, |
add651ee | 34 | args: &'tcx [GenericArg<'tcx>], |
ed00b5ec | 35 | ) -> Result<(), PrintError> { |
add651ee | 36 | self.default_print_def_path(def_id, args) |
532ac7d7 | 37 | } |
e1599b0c | 38 | |
532ac7d7 | 39 | fn print_impl_path( |
ed00b5ec | 40 | &mut self, |
532ac7d7 | 41 | impl_def_id: DefId, |
add651ee | 42 | args: &'tcx [GenericArg<'tcx>], |
532ac7d7 XL |
43 | self_ty: Ty<'tcx>, |
44 | trait_ref: Option<ty::TraitRef<'tcx>>, | |
ed00b5ec | 45 | ) -> Result<(), PrintError> { |
add651ee | 46 | self.default_print_impl_path(impl_def_id, args, self_ty, trait_ref) |
532ac7d7 XL |
47 | } |
48 | ||
ed00b5ec | 49 | fn print_region(&mut self, region: ty::Region<'tcx>) -> Result<(), PrintError>; |
532ac7d7 | 50 | |
ed00b5ec | 51 | fn print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError>; |
532ac7d7 XL |
52 | |
53 | fn print_dyn_existential( | |
ed00b5ec | 54 | &mut self, |
487cf647 | 55 | predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, |
ed00b5ec | 56 | ) -> Result<(), PrintError>; |
532ac7d7 | 57 | |
ed00b5ec | 58 | fn print_const(&mut self, ct: ty::Const<'tcx>) -> Result<(), PrintError>; |
dc9dc135 | 59 | |
ed00b5ec | 60 | fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError>; |
e1599b0c | 61 | |
532ac7d7 | 62 | fn path_qualified( |
ed00b5ec | 63 | &mut self, |
532ac7d7 XL |
64 | self_ty: Ty<'tcx>, |
65 | trait_ref: Option<ty::TraitRef<'tcx>>, | |
ed00b5ec | 66 | ) -> Result<(), PrintError>; |
532ac7d7 XL |
67 | |
68 | fn path_append_impl( | |
ed00b5ec FG |
69 | &mut self, |
70 | print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, | |
532ac7d7 XL |
71 | disambiguated_data: &DisambiguatedDefPathData, |
72 | self_ty: Ty<'tcx>, | |
73 | trait_ref: Option<ty::TraitRef<'tcx>>, | |
ed00b5ec | 74 | ) -> Result<(), PrintError>; |
e1599b0c | 75 | |
532ac7d7 | 76 | fn path_append( |
ed00b5ec FG |
77 | &mut self, |
78 | print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, | |
532ac7d7 | 79 | disambiguated_data: &DisambiguatedDefPathData, |
ed00b5ec | 80 | ) -> Result<(), PrintError>; |
e1599b0c | 81 | |
532ac7d7 | 82 | fn path_generic_args( |
ed00b5ec FG |
83 | &mut self, |
84 | print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, | |
e74abb32 | 85 | args: &[GenericArg<'tcx>], |
ed00b5ec | 86 | ) -> Result<(), PrintError>; |
532ac7d7 | 87 | |
74b04a01 | 88 | // Defaults (should not be overridden): |
532ac7d7 | 89 | |
c295e0f8 | 90 | #[instrument(skip(self), level = "debug")] |
532ac7d7 | 91 | fn default_print_def_path( |
ed00b5ec | 92 | &mut self, |
532ac7d7 | 93 | def_id: DefId, |
add651ee | 94 | args: &'tcx [GenericArg<'tcx>], |
ed00b5ec | 95 | ) -> Result<(), PrintError> { |
532ac7d7 | 96 | let key = self.tcx().def_key(def_id); |
c295e0f8 | 97 | debug!(?key); |
532ac7d7 XL |
98 | |
99 | match key.disambiguated_data.data { | |
100 | DefPathData::CrateRoot => { | |
101 | assert!(key.parent.is_none()); | |
102 | self.path_crate(def_id.krate) | |
103 | } | |
104 | ||
105 | DefPathData::Impl => { | |
106 | let generics = self.tcx().generics_of(def_id); | |
9ffffee4 | 107 | let self_ty = self.tcx().type_of(def_id); |
9c376795 | 108 | let impl_trait_ref = self.tcx().impl_trait_ref(def_id); |
add651ee | 109 | let (self_ty, impl_trait_ref) = if args.len() >= generics.count() { |
04454e1e | 110 | ( |
add651ee FG |
111 | self_ty.instantiate(self.tcx(), args), |
112 | impl_trait_ref.map(|i| i.instantiate(self.tcx(), args)), | |
04454e1e FG |
113 | ) |
114 | } else { | |
add651ee FG |
115 | ( |
116 | self_ty.instantiate_identity(), | |
117 | impl_trait_ref.map(|i| i.instantiate_identity()), | |
118 | ) | |
04454e1e | 119 | }; |
add651ee | 120 | self.print_impl_path(def_id, args, self_ty, impl_trait_ref) |
532ac7d7 XL |
121 | } |
122 | ||
123 | _ => { | |
124 | let parent_def_id = DefId { index: key.parent.unwrap(), ..def_id }; | |
125 | ||
add651ee | 126 | let mut parent_args = args; |
532ac7d7 | 127 | let mut trait_qualify_parent = false; |
add651ee | 128 | if !args.is_empty() { |
532ac7d7 | 129 | let generics = self.tcx().generics_of(def_id); |
add651ee | 130 | parent_args = &args[..generics.parent_count.min(args.len())]; |
532ac7d7 XL |
131 | |
132 | match key.disambiguated_data.data { | |
133 | // Closures' own generics are only captures, don't print them. | |
4b012472 | 134 | DefPathData::Closure => {} |
04454e1e FG |
135 | // This covers both `DefKind::AnonConst` and `DefKind::InlineConst`. |
136 | // Anon consts doesn't have their own generics, and inline consts' own | |
137 | // generics are their inferred types, so don't print them. | |
138 | DefPathData::AnonConst => {} | |
532ac7d7 XL |
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. | |
dfeec247 | 142 | _ => { |
add651ee FG |
143 | if !generics.params.is_empty() && args.len() >= generics.count() { |
144 | let args = generics.own_args_no_defaults(self.tcx(), args); | |
dfeec247 | 145 | return self.path_generic_args( |
add651ee | 146 | |cx| cx.print_def_path(def_id, parent_args), |
dfeec247 XL |
147 | args, |
148 | ); | |
149 | } | |
532ac7d7 XL |
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. | |
dfeec247 XL |
155 | trait_qualify_parent = generics.has_self |
156 | && generics.parent == Some(parent_def_id) | |
add651ee | 157 | && parent_args.len() == generics.parent_count |
dfeec247 | 158 | && self.tcx().generics_of(parent_def_id).parent_count == 0; |
532ac7d7 XL |
159 | } |
160 | ||
161 | self.path_append( | |
ed00b5ec | 162 | |cx: &mut Self| { |
dfeec247 | 163 | if trait_qualify_parent { |
49aad941 FG |
164 | let trait_ref = ty::TraitRef::new( |
165 | cx.tcx(), | |
166 | parent_def_id, | |
add651ee | 167 | parent_args.iter().copied(), |
49aad941 | 168 | ); |
dfeec247 XL |
169 | cx.path_qualified(trait_ref.self_ty(), Some(trait_ref)) |
170 | } else { | |
add651ee | 171 | cx.print_def_path(parent_def_id, parent_args) |
dfeec247 | 172 | } |
532ac7d7 XL |
173 | }, |
174 | &key.disambiguated_data, | |
175 | ) | |
176 | } | |
177 | } | |
178 | } | |
179 | ||
532ac7d7 | 180 | fn default_print_impl_path( |
ed00b5ec | 181 | &mut self, |
532ac7d7 | 182 | impl_def_id: DefId, |
add651ee | 183 | _args: &'tcx [GenericArg<'tcx>], |
532ac7d7 XL |
184 | self_ty: Ty<'tcx>, |
185 | impl_trait_ref: Option<ty::TraitRef<'tcx>>, | |
ed00b5ec | 186 | ) -> Result<(), PrintError> { |
dfeec247 XL |
187 | debug!( |
188 | "default_print_impl_path: impl_def_id={:?}, self_ty={}, impl_trait_ref={:?}", | |
189 | impl_def_id, self_ty, impl_trait_ref | |
190 | ); | |
532ac7d7 XL |
191 | |
192 | let key = self.tcx().def_key(impl_def_id); | |
193 | let parent_def_id = DefId { index: key.parent.unwrap(), ..impl_def_id }; | |
194 | ||
195 | // Decide whether to print the parent path for the impl. | |
196 | // Logically, since impls are global, it's never needed, but | |
197 | // users may find it useful. Currently, we omit the parent if | |
198 | // the impl is either in the same module as the self-type or | |
199 | // as the trait. | |
200 | let in_self_mod = match characteristic_def_id_of_type(self_ty) { | |
201 | None => false, | |
04454e1e | 202 | Some(ty_def_id) => self.tcx().parent(ty_def_id) == parent_def_id, |
532ac7d7 XL |
203 | }; |
204 | let in_trait_mod = match impl_trait_ref { | |
205 | None => false, | |
04454e1e | 206 | Some(trait_ref) => self.tcx().parent(trait_ref.def_id) == parent_def_id, |
532ac7d7 XL |
207 | }; |
208 | ||
209 | if !in_self_mod && !in_trait_mod { | |
210 | // If the impl is not co-located with either self-type or | |
211 | // trait-type, then fallback to a format that identifies | |
212 | // the module more clearly. | |
213 | self.path_append_impl( | |
214 | |cx| cx.print_def_path(parent_def_id, &[]), | |
215 | &key.disambiguated_data, | |
216 | self_ty, | |
217 | impl_trait_ref, | |
218 | ) | |
219 | } else { | |
220 | // Otherwise, try to give a good form that would be valid language | |
221 | // syntax. Preferably using associated item notation. | |
222 | self.path_qualified(self_ty, impl_trait_ref) | |
223 | } | |
224 | } | |
225 | } | |
226 | ||
227 | /// As a heuristic, when we see an impl, if we see that the | |
228 | /// 'self type' is a type defined in the same module as the impl, | |
229 | /// we can omit including the path to the impl itself. This | |
230 | /// function tries to find a "characteristic `DefId`" for a | |
231 | /// type. It's just a heuristic so it makes some questionable | |
232 | /// decisions and we may want to adjust it later. | |
6c58768f XL |
233 | /// |
234 | /// Visited set is needed to avoid full iteration over | |
235 | /// deeply nested tuples that have no DefId. | |
236 | fn characteristic_def_id_of_type_cached<'a>( | |
237 | ty: Ty<'a>, | |
29967ef6 | 238 | visited: &mut SsoHashSet<Ty<'a>>, |
6c58768f | 239 | ) -> Option<DefId> { |
1b1a35ee | 240 | match *ty.kind() { |
5e7ed085 | 241 | ty::Adt(adt_def, _) => Some(adt_def.did()), |
532ac7d7 XL |
242 | |
243 | ty::Dynamic(data, ..) => data.principal_def_id(), | |
244 | ||
6c58768f XL |
245 | ty::Array(subty, _) | ty::Slice(subty) => { |
246 | characteristic_def_id_of_type_cached(subty, visited) | |
247 | } | |
532ac7d7 | 248 | |
6c58768f | 249 | ty::RawPtr(mt) => characteristic_def_id_of_type_cached(mt.ty, visited), |
532ac7d7 | 250 | |
6c58768f | 251 | ty::Ref(_, ty, _) => characteristic_def_id_of_type_cached(ty, visited), |
532ac7d7 | 252 | |
4b012472 | 253 | ty::Tuple(tys) => tys.iter().find_map(|ty| { |
6c58768f XL |
254 | if visited.insert(ty) { |
255 | return characteristic_def_id_of_type_cached(ty, visited); | |
256 | } | |
257 | return None; | |
258 | }), | |
dfeec247 XL |
259 | |
260 | ty::FnDef(def_id, _) | |
261 | | ty::Closure(def_id, _) | |
ed00b5ec FG |
262 | | ty::Coroutine(def_id, _, _) |
263 | | ty::CoroutineWitness(def_id, _) | |
dfeec247 XL |
264 | | ty::Foreign(def_id) => Some(def_id), |
265 | ||
266 | ty::Bool | |
267 | | ty::Char | |
268 | | ty::Int(_) | |
269 | | ty::Uint(_) | |
270 | | ty::Str | |
271 | | ty::FnPtr(_) | |
9c376795 | 272 | | ty::Alias(..) |
dfeec247 | 273 | | ty::Placeholder(..) |
dfeec247 | 274 | | ty::Param(_) |
dfeec247 XL |
275 | | ty::Infer(_) |
276 | | ty::Bound(..) | |
f035d41b | 277 | | ty::Error(_) |
dfeec247 XL |
278 | | ty::Never |
279 | | ty::Float(_) => None, | |
532ac7d7 XL |
280 | } |
281 | } | |
6c58768f | 282 | pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> { |
29967ef6 | 283 | characteristic_def_id_of_type_cached(ty, &mut SsoHashSet::new()) |
6c58768f | 284 | } |
532ac7d7 | 285 | |
923072b8 | 286 | impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::Region<'tcx> { |
ed00b5ec | 287 | fn print(&self, cx: &mut P) -> Result<(), PrintError> { |
5099ac24 | 288 | cx.print_region(*self) |
532ac7d7 XL |
289 | } |
290 | } | |
291 | ||
dc9dc135 | 292 | impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for Ty<'tcx> { |
ed00b5ec | 293 | fn print(&self, cx: &mut P) -> Result<(), PrintError> { |
5099ac24 | 294 | cx.print_type(*self) |
532ac7d7 XL |
295 | } |
296 | } | |
297 | ||
487cf647 | 298 | impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> { |
ed00b5ec | 299 | fn print(&self, cx: &mut P) -> Result<(), PrintError> { |
532ac7d7 XL |
300 | cx.print_dyn_existential(self) |
301 | } | |
302 | } | |
dc9dc135 | 303 | |
5099ac24 | 304 | impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::Const<'tcx> { |
ed00b5ec | 305 | fn print(&self, cx: &mut P) -> Result<(), PrintError> { |
5099ac24 | 306 | cx.print_const(*self) |
dc9dc135 XL |
307 | } |
308 | } | |
2b03887a FG |
309 | |
310 | // This is only used by query descriptions | |
add651ee FG |
311 | pub fn describe_as_module(def_id: impl Into<LocalDefId>, tcx: TyCtxt<'_>) -> String { |
312 | let def_id = def_id.into(); | |
2b03887a FG |
313 | if def_id.is_top_level_module() { |
314 | "top-level module".to_string() | |
315 | } else { | |
49aad941 | 316 | format!("module `{}`", tcx.def_path_str(def_id)) |
2b03887a FG |
317 | } |
318 | } |