]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_middle/src/ty/print/mod.rs
New upstream version 1.76.0+dfsg1
[rustc.git] / compiler / rustc_middle / src / ty / print / mod.rs
CommitLineData
2b03887a 1use crate::ty::GenericArg;
353b0b11 2use crate::ty::{self, 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
ed00b5ec 13pub type PrintError = std::fmt::Error;
532ac7d7 14
ed00b5ec
FG
15pub 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 28pub 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.
236fn 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 282pub 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 286impl<'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 292impl<'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 298impl<'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 304impl<'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
311pub 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}