1use std::path::PathBuf;
2
3use hir::def::Namespace;
4use rustc_data_structures::fx::FxHashSet;
5use rustc_data_structures::sso::SsoHashSet;
6use rustc_hir as hir;
7use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
8use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
9use tracing::{debug, instrument, trace};
10
11use crate::ty::{self, GenericArg, ShortInstance, Ty, TyCtxt};
12
13mod pretty;
15pub use self::pretty::*;
16use super::Lift;
17
18pub type PrintError = std::fmt::Error;
19
20pub trait Print<'tcx, P> {
21 fn print(&self, cx: &mut P) -> Result<(), PrintError>;
22}
23
24pub trait Printer<'tcx>: Sized {
34 fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
35
36 fn print_def_path(
37 &mut self,
38 def_id: DefId,
39 args: &'tcx [GenericArg<'tcx>],
40 ) -> Result<(), PrintError> {
41 self.default_print_def_path(def_id, args)
42 }
43
44 fn print_impl_path(
45 &mut self,
46 impl_def_id: DefId,
47 args: &'tcx [GenericArg<'tcx>],
48 ) -> Result<(), PrintError> {
49 let tcx = self.tcx();
50 let self_ty = tcx.type_of(impl_def_id);
51 let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
52 let (self_ty, impl_trait_ref) = if tcx.generics_of(impl_def_id).count() <= args.len() {
53 (
54 self_ty.instantiate(tcx, args),
55 impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate(tcx, args)),
56 )
57 } else {
58 (
61 self_ty.instantiate_identity(),
62 impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate_identity()),
63 )
64 };
65
66 self.default_print_impl_path(impl_def_id, self_ty, impl_trait_ref)
67 }
68
69 fn print_region(&mut self, region: ty::Region<'tcx>) -> Result<(), PrintError>;
70
71 fn print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError>;
72
73 fn print_dyn_existential(
74 &mut self,
75 predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
76 ) -> Result<(), PrintError>;
77
78 fn print_const(&mut self, ct: ty::Const<'tcx>) -> Result<(), PrintError>;
79
80 fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError>;
81
82 fn path_qualified(
83 &mut self,
84 self_ty: Ty<'tcx>,
85 trait_ref: Option<ty::TraitRef<'tcx>>,
86 ) -> Result<(), PrintError>;
87
88 fn path_append_impl(
89 &mut self,
90 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
91 disambiguated_data: &DisambiguatedDefPathData,
92 self_ty: Ty<'tcx>,
93 trait_ref: Option<ty::TraitRef<'tcx>>,
94 ) -> Result<(), PrintError>;
95
96 fn path_append(
97 &mut self,
98 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
99 disambiguated_data: &DisambiguatedDefPathData,
100 ) -> Result<(), PrintError>;
101
102 fn path_generic_args(
103 &mut self,
104 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
105 args: &[GenericArg<'tcx>],
106 ) -> Result<(), PrintError>;
107
108 fn should_truncate(&mut self) -> bool {
109 false
110 }
111
112 #[instrument(skip(self), level = "debug")]
115 fn default_print_def_path(
116 &mut self,
117 def_id: DefId,
118 args: &'tcx [GenericArg<'tcx>],
119 ) -> Result<(), PrintError> {
120 let key = self.tcx().def_key(def_id);
121 debug!(?key);
122
123 match key.disambiguated_data.data {
124 DefPathData::CrateRoot => {
125 assert!(key.parent.is_none());
126 self.path_crate(def_id.krate)
127 }
128
129 DefPathData::Impl => self.print_impl_path(def_id, args),
130
131 _ => {
132 let parent_def_id = DefId { index: key.parent.unwrap(), ..def_id };
133
134 let mut parent_args = args;
135 let mut trait_qualify_parent = false;
136 if !args.is_empty() {
137 let generics = self.tcx().generics_of(def_id);
138 parent_args = &args[..generics.parent_count.min(args.len())];
139
140 match key.disambiguated_data.data {
141 DefPathData::Closure => {
142 if let Some(hir::CoroutineKind::Desugared(
145 _,
146 hir::CoroutineSource::Closure,
147 )) = self.tcx().coroutine_kind(def_id)
148 && args.len() > parent_args.len()
149 {
150 return self.path_generic_args(
151 |cx| cx.print_def_path(def_id, parent_args),
152 &args[..parent_args.len() + 1][..1],
153 );
154 } else {
155 }
157 }
158 DefPathData::SyntheticCoroutineBody => {
159 }
162 DefPathData::AnonConst => {}
166
167 _ => {
170 if !generics.is_own_empty() && args.len() >= generics.count() {
171 let args = generics.own_args_no_defaults(self.tcx(), args);
172 return self.path_generic_args(
173 |cx| cx.print_def_path(def_id, parent_args),
174 args,
175 );
176 }
177 }
178 }
179
180 trait_qualify_parent = generics.has_self
183 && generics.parent == Some(parent_def_id)
184 && parent_args.len() == generics.parent_count
185 && self.tcx().generics_of(parent_def_id).parent_count == 0;
186 }
187
188 self.path_append(
189 |cx: &mut Self| {
190 if trait_qualify_parent {
191 let trait_ref = ty::TraitRef::new(
192 cx.tcx(),
193 parent_def_id,
194 parent_args.iter().copied(),
195 );
196 cx.path_qualified(trait_ref.self_ty(), Some(trait_ref))
197 } else {
198 cx.print_def_path(parent_def_id, parent_args)
199 }
200 },
201 &key.disambiguated_data,
202 )
203 }
204 }
205 }
206
207 fn default_print_impl_path(
208 &mut self,
209 impl_def_id: DefId,
210 self_ty: Ty<'tcx>,
211 impl_trait_ref: Option<ty::TraitRef<'tcx>>,
212 ) -> Result<(), PrintError> {
213 debug!(
214 "default_print_impl_path: impl_def_id={:?}, self_ty={}, impl_trait_ref={:?}",
215 impl_def_id, self_ty, impl_trait_ref
216 );
217
218 let key = self.tcx().def_key(impl_def_id);
219 let parent_def_id = DefId { index: key.parent.unwrap(), ..impl_def_id };
220
221 let in_self_mod = match characteristic_def_id_of_type(self_ty) {
227 None => false,
228 Some(ty_def_id) => self.tcx().parent(ty_def_id) == parent_def_id,
229 };
230 let in_trait_mod = match impl_trait_ref {
231 None => false,
232 Some(trait_ref) => self.tcx().parent(trait_ref.def_id) == parent_def_id,
233 };
234
235 if !in_self_mod && !in_trait_mod {
236 self.path_append_impl(
240 |cx| cx.print_def_path(parent_def_id, &[]),
241 &key.disambiguated_data,
242 self_ty,
243 impl_trait_ref,
244 )
245 } else {
246 self.path_qualified(self_ty, impl_trait_ref)
249 }
250 }
251}
252
253fn characteristic_def_id_of_type_cached<'a>(
263 ty: Ty<'a>,
264 visited: &mut SsoHashSet<Ty<'a>>,
265) -> Option<DefId> {
266 match *ty.kind() {
267 ty::Adt(adt_def, _) => Some(adt_def.did()),
268
269 ty::Dynamic(data, ..) => data.principal_def_id(),
270
271 ty::Pat(subty, _) | ty::Array(subty, _) | ty::Slice(subty) => {
272 characteristic_def_id_of_type_cached(subty, visited)
273 }
274
275 ty::RawPtr(ty, _) => characteristic_def_id_of_type_cached(ty, visited),
276
277 ty::Ref(_, ty, _) => characteristic_def_id_of_type_cached(ty, visited),
278
279 ty::Tuple(tys) => tys.iter().find_map(|ty| {
280 if visited.insert(ty) {
281 return characteristic_def_id_of_type_cached(ty, visited);
282 }
283 return None;
284 }),
285
286 ty::FnDef(def_id, _)
287 | ty::Closure(def_id, _)
288 | ty::CoroutineClosure(def_id, _)
289 | ty::Coroutine(def_id, _)
290 | ty::CoroutineWitness(def_id, _)
291 | ty::Foreign(def_id) => Some(def_id),
292
293 ty::Bool
294 | ty::Char
295 | ty::Int(_)
296 | ty::Uint(_)
297 | ty::Str
298 | ty::FnPtr(..)
299 | ty::UnsafeBinder(_)
300 | ty::Alias(..)
301 | ty::Placeholder(..)
302 | ty::Param(_)
303 | ty::Infer(_)
304 | ty::Bound(..)
305 | ty::Error(_)
306 | ty::Never
307 | ty::Float(_) => None,
308 }
309}
310pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> {
311 characteristic_def_id_of_type_cached(ty, &mut SsoHashSet::new())
312}
313
314impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::Region<'tcx> {
315 fn print(&self, cx: &mut P) -> Result<(), PrintError> {
316 cx.print_region(*self)
317 }
318}
319
320impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for Ty<'tcx> {
321 fn print(&self, cx: &mut P) -> Result<(), PrintError> {
322 cx.print_type(*self)
323 }
324}
325
326impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> {
327 fn print(&self, cx: &mut P) -> Result<(), PrintError> {
328 cx.print_dyn_existential(self)
329 }
330}
331
332impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::Const<'tcx> {
333 fn print(&self, cx: &mut P) -> Result<(), PrintError> {
334 cx.print_const(*self)
335 }
336}
337
338pub fn describe_as_module(def_id: impl Into<LocalDefId>, tcx: TyCtxt<'_>) -> String {
340 let def_id = def_id.into();
341 if def_id.is_top_level_module() {
342 "top-level module".to_string()
343 } else {
344 format!("module `{}`", tcx.def_path_str(def_id))
345 }
346}
347
348impl<T> rustc_type_ir::ir_print::IrPrint<T> for TyCtxt<'_>
349where
350 T: Copy + for<'a, 'tcx> Lift<TyCtxt<'tcx>, Lifted: Print<'tcx, FmtPrinter<'a, 'tcx>>>,
351{
352 fn print(t: &T, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
353 ty::tls::with(|tcx| {
354 let mut cx = FmtPrinter::new(tcx, Namespace::TypeNS);
355 tcx.lift(*t).expect("could not lift for printing").print(&mut cx)?;
356 fmt.write_str(&cx.into_buffer())?;
357 Ok(())
358 })
359 }
360
361 fn print_debug(t: &T, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
362 with_no_trimmed_paths!(Self::print(t, fmt))
363 }
364}
365
366pub fn shrunk_instance_name<'tcx>(
372 tcx: TyCtxt<'tcx>,
373 instance: ty::Instance<'tcx>,
374) -> (String, Option<PathBuf>) {
375 let s = instance.to_string();
376
377 if s.chars().nth(33).is_some() {
380 let shrunk = format!("{}", ShortInstance(instance, 4));
381 if shrunk == s {
382 return (s, None);
383 }
384
385 let path = tcx.output_filenames(()).temp_path_for_diagnostic("long-type.txt");
386 let written_to_path = std::fs::write(&path, s).ok().map(|_| path);
387
388 (shrunk, written_to_path)
389 } else {
390 (s, None)
391 }
392}