1use hir::def::Namespace;
2use rustc_data_structures::fx::FxHashSet;
3use rustc_data_structures::sso::SsoHashSet;
4use rustc_hir as hir;
5use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
6use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
7use tracing::{debug, instrument, trace};
8
9use crate::ty::{self, GenericArg, Ty, TyCtxt};
10
11mod pretty;
13pub use self::pretty::*;
14use super::Lift;
15
16pub type PrintError = std::fmt::Error;
17
18pub trait Print<'tcx, P> {
19 fn print(&self, p: &mut P) -> Result<(), PrintError>;
20}
21
22pub trait Printer<'tcx>: Sized {
29 fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
30
31 fn print_def_path(
33 &mut self,
34 def_id: DefId,
35 args: &'tcx [GenericArg<'tcx>],
36 ) -> Result<(), PrintError> {
37 self.default_print_def_path(def_id, args)
38 }
39
40 fn print_impl_path(
42 &mut self,
43 impl_def_id: DefId,
44 args: &'tcx [GenericArg<'tcx>],
45 ) -> Result<(), PrintError> {
46 let tcx = self.tcx();
47 let self_ty = tcx.type_of(impl_def_id);
48 let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
49 let (self_ty, impl_trait_ref) = if tcx.generics_of(impl_def_id).count() <= args.len() {
50 (
51 self_ty.instantiate(tcx, args),
52 impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate(tcx, args)),
53 )
54 } else {
55 (
58 self_ty.instantiate_identity(),
59 impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate_identity()),
60 )
61 };
62
63 self.default_print_impl_path(impl_def_id, self_ty, impl_trait_ref)
64 }
65
66 fn print_region(&mut self, region: ty::Region<'tcx>) -> Result<(), PrintError>;
68
69 fn print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError>;
71
72 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>;
80
81 fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError>;
83
84 fn print_path_with_simple(
91 &mut self,
92 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
93 disambiguated_data: &DisambiguatedDefPathData,
94 ) -> Result<(), PrintError>;
95
96 fn print_path_with_impl(
101 &mut self,
102 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
103 self_ty: Ty<'tcx>,
104 trait_ref: Option<ty::TraitRef<'tcx>>,
105 ) -> Result<(), PrintError>;
106
107 fn print_path_with_generic_args(
114 &mut self,
115 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
116 args: &[GenericArg<'tcx>],
117 ) -> Result<(), PrintError>;
118
119 fn print_path_with_qualified(
122 &mut self,
123 self_ty: Ty<'tcx>,
124 trait_ref: Option<ty::TraitRef<'tcx>>,
125 ) -> Result<(), PrintError>;
126
127 #[instrument(skip(self), level = "debug")]
130 fn default_print_def_path(
131 &mut self,
132 def_id: DefId,
133 args: &'tcx [GenericArg<'tcx>],
134 ) -> Result<(), PrintError> {
135 let key = self.tcx().def_key(def_id);
136 debug!(?key);
137
138 match key.disambiguated_data.data {
139 DefPathData::CrateRoot => {
140 assert!(key.parent.is_none());
141 self.print_crate_name(def_id.krate)
142 }
143
144 DefPathData::Impl => self.print_impl_path(def_id, args),
145
146 _ => {
147 let parent_def_id = DefId { index: key.parent.unwrap(), ..def_id };
148
149 let mut parent_args = args;
150 let mut trait_qualify_parent = false;
151 if !args.is_empty() {
152 let generics = self.tcx().generics_of(def_id);
153 parent_args = &args[..generics.parent_count.min(args.len())];
154
155 match key.disambiguated_data.data {
156 DefPathData::Closure => {
157 if let Some(hir::CoroutineKind::Desugared(
160 _,
161 hir::CoroutineSource::Closure,
162 )) = self.tcx().coroutine_kind(def_id)
163 && args.len() > parent_args.len()
164 {
165 return self.print_path_with_generic_args(
166 |p| p.print_def_path(def_id, parent_args),
167 &args[..parent_args.len() + 1][..1],
168 );
169 } else {
170 }
172 }
173 DefPathData::SyntheticCoroutineBody => {
174 }
177 DefPathData::AnonConst => {}
181
182 _ => {
185 if !generics.is_own_empty() && args.len() >= generics.count() {
186 let args = generics.own_args_no_defaults(self.tcx(), args);
187 return self.print_path_with_generic_args(
188 |p| p.print_def_path(def_id, parent_args),
189 args,
190 );
191 }
192 }
193 }
194
195 trait_qualify_parent = generics.has_self
198 && generics.parent == Some(parent_def_id)
199 && parent_args.len() == generics.parent_count
200 && self.tcx().generics_of(parent_def_id).parent_count == 0;
201 }
202
203 self.print_path_with_simple(
204 |p: &mut Self| {
205 if trait_qualify_parent {
206 let trait_ref = ty::TraitRef::new(
207 p.tcx(),
208 parent_def_id,
209 parent_args.iter().copied(),
210 );
211 p.print_path_with_qualified(trait_ref.self_ty(), Some(trait_ref))
212 } else {
213 p.print_def_path(parent_def_id, parent_args)
214 }
215 },
216 &key.disambiguated_data,
217 )
218 }
219 }
220 }
221
222 fn default_print_impl_path(
223 &mut self,
224 impl_def_id: DefId,
225 self_ty: Ty<'tcx>,
226 impl_trait_ref: Option<ty::TraitRef<'tcx>>,
227 ) -> Result<(), PrintError> {
228 debug!(
229 "default_print_impl_path: impl_def_id={:?}, self_ty={}, impl_trait_ref={:?}",
230 impl_def_id, self_ty, impl_trait_ref
231 );
232
233 let key = self.tcx().def_key(impl_def_id);
234 let parent_def_id = DefId { index: key.parent.unwrap(), ..impl_def_id };
235
236 let in_self_mod = match characteristic_def_id_of_type(self_ty) {
242 None => false,
243 Some(ty_def_id) => self.tcx().parent(ty_def_id) == parent_def_id,
244 };
245 let in_trait_mod = match impl_trait_ref {
246 None => false,
247 Some(trait_ref) => self.tcx().parent(trait_ref.def_id) == parent_def_id,
248 };
249
250 if !in_self_mod && !in_trait_mod {
251 self.print_path_with_impl(
255 |p| p.print_def_path(parent_def_id, &[]),
256 self_ty,
257 impl_trait_ref,
258 )
259 } else {
260 self.print_path_with_qualified(self_ty, impl_trait_ref)
263 }
264 }
265}
266
267fn characteristic_def_id_of_type_cached<'a>(
277 ty: Ty<'a>,
278 visited: &mut SsoHashSet<Ty<'a>>,
279) -> Option<DefId> {
280 match *ty.kind() {
281 ty::Adt(adt_def, _) => Some(adt_def.did()),
282
283 ty::Dynamic(data, ..) => data.principal_def_id(),
284
285 ty::Pat(subty, _) | ty::Array(subty, _) | ty::Slice(subty) => {
286 characteristic_def_id_of_type_cached(subty, visited)
287 }
288
289 ty::RawPtr(ty, _) => characteristic_def_id_of_type_cached(ty, visited),
290
291 ty::Ref(_, ty, _) => characteristic_def_id_of_type_cached(ty, visited),
292
293 ty::Tuple(tys) => tys.iter().find_map(|ty| {
294 if visited.insert(ty) {
295 return characteristic_def_id_of_type_cached(ty, visited);
296 }
297 return None;
298 }),
299
300 ty::FnDef(def_id, _)
301 | ty::Closure(def_id, _)
302 | ty::CoroutineClosure(def_id, _)
303 | ty::Coroutine(def_id, _)
304 | ty::CoroutineWitness(def_id, _)
305 | ty::Foreign(def_id) => Some(def_id),
306
307 ty::Bool
308 | ty::Char
309 | ty::Int(_)
310 | ty::Uint(_)
311 | ty::Str
312 | ty::FnPtr(..)
313 | ty::UnsafeBinder(_)
314 | ty::Alias(..)
315 | ty::Placeholder(..)
316 | ty::Param(_)
317 | ty::Infer(_)
318 | ty::Bound(..)
319 | ty::Error(_)
320 | ty::Never
321 | ty::Float(_) => None,
322 }
323}
324pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> {
325 characteristic_def_id_of_type_cached(ty, &mut SsoHashSet::new())
326}
327
328impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::Region<'tcx> {
329 fn print(&self, p: &mut P) -> Result<(), PrintError> {
330 p.print_region(*self)
331 }
332}
333
334impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for Ty<'tcx> {
335 fn print(&self, p: &mut P) -> Result<(), PrintError> {
336 p.print_type(*self)
337 }
338}
339
340impl<'tcx, P: Printer<'tcx> + std::fmt::Write> Print<'tcx, P> for ty::Instance<'tcx> {
341 fn print(&self, cx: &mut P) -> Result<(), PrintError> {
342 cx.print_def_path(self.def_id(), self.args)?;
343 match self.def {
344 ty::InstanceKind::Item(_) => {}
345 ty::InstanceKind::VTableShim(_) => cx.write_str(" - shim(vtable)")?,
346 ty::InstanceKind::ReifyShim(_, None) => cx.write_str(" - shim(reify)")?,
347 ty::InstanceKind::ReifyShim(_, Some(ty::ReifyReason::FnPtr)) => {
348 cx.write_str(" - shim(reify-fnptr)")?
349 }
350 ty::InstanceKind::ReifyShim(_, Some(ty::ReifyReason::Vtable)) => {
351 cx.write_str(" - shim(reify-vtable)")?
352 }
353 ty::InstanceKind::ThreadLocalShim(_) => cx.write_str(" - shim(tls)")?,
354 ty::InstanceKind::Intrinsic(_) => cx.write_str(" - intrinsic")?,
355 ty::InstanceKind::Virtual(_, num) => cx.write_str(&format!(" - virtual#{num}"))?,
356 ty::InstanceKind::FnPtrShim(_, ty) => cx.write_str(&format!(" - shim({ty})"))?,
357 ty::InstanceKind::ClosureOnceShim { .. } => cx.write_str(" - shim")?,
358 ty::InstanceKind::ConstructCoroutineInClosureShim { .. } => cx.write_str(" - shim")?,
359 ty::InstanceKind::DropGlue(_, None) => cx.write_str(" - shim(None)")?,
360 ty::InstanceKind::DropGlue(_, Some(ty)) => {
361 cx.write_str(&format!(" - shim(Some({ty}))"))?
362 }
363 ty::InstanceKind::CloneShim(_, ty) => cx.write_str(&format!(" - shim({ty})"))?,
364 ty::InstanceKind::FnPtrAddrShim(_, ty) => cx.write_str(&format!(" - shim({ty})"))?,
365 ty::InstanceKind::FutureDropPollShim(_, proxy_ty, impl_ty) => {
366 cx.write_str(&format!(" - dropshim({proxy_ty}-{impl_ty})"))?
367 }
368 ty::InstanceKind::AsyncDropGlue(_, ty) => cx.write_str(&format!(" - shim({ty})"))?,
369 ty::InstanceKind::AsyncDropGlueCtorShim(_, ty) => {
370 cx.write_str(&format!(" - shim(Some({ty}))"))?
371 }
372 };
373 Ok(())
374 }
375}
376
377impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> {
378 fn print(&self, p: &mut P) -> Result<(), PrintError> {
379 p.print_dyn_existential(self)
380 }
381}
382
383impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::Const<'tcx> {
384 fn print(&self, p: &mut P) -> Result<(), PrintError> {
385 p.print_const(*self)
386 }
387}
388
389pub fn describe_as_module(def_id: impl Into<LocalDefId>, tcx: TyCtxt<'_>) -> String {
391 let def_id = def_id.into();
392 if def_id.is_top_level_module() {
393 "top-level module".to_string()
394 } else {
395 format!("module `{}`", tcx.def_path_str(def_id))
396 }
397}
398
399impl<T> rustc_type_ir::ir_print::IrPrint<T> for TyCtxt<'_>
400where
401 T: Copy + for<'a, 'tcx> Lift<TyCtxt<'tcx>, Lifted: Print<'tcx, FmtPrinter<'a, 'tcx>>>,
402{
403 fn print(t: &T, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
404 ty::tls::with(|tcx| {
405 let mut p = FmtPrinter::new(tcx, Namespace::TypeNS);
406 tcx.lift(*t).expect("could not lift for printing").print(&mut p)?;
407 fmt.write_str(&p.into_buffer())?;
408 Ok(())
409 })
410 }
411
412 fn print_debug(t: &T, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
413 with_no_trimmed_paths!(Self::print(t, fmt))
414 }
415}