]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_middle/src/ty/print/mod.rs
New upstream version 1.68.2+dfsg1
[rustc.git] / compiler / rustc_middle / src / ty / print / mod.rs
CommitLineData
2b03887a 1use crate::ty::GenericArg;
dfeec247 2use crate::ty::{self, DefIdTree, Ty, TyCtxt};
532ac7d7
XL
3
4use rustc_data_structures::fx::FxHashSet;
29967ef6 5use rustc_data_structures::sso::SsoHashSet;
2b03887a 6use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
ba9703b0 7use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
532ac7d7
XL
8
9// `pretty` is a separate module only for organization.
10mod pretty;
11pub use self::pretty::*;
12
dc9dc135
XL
13// FIXME(eddyb) false positive, the lifetime parameters are used with `P: Printer<...>`.
14#[allow(unused_lifetimes)]
15pub 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 31pub 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.
241fn 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 287pub 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 291impl<'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 299impl<'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 308impl<'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 316impl<'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
325pub 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}