rustc_middle/ty/print/
mod.rs

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
11// `pretty` is a separate module only for organization.
12mod 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
22/// A trait that "prints" user-facing type system entities: paths, types, lifetimes, constants,
23/// etc. "Printing" here means building up a representation of the entity's path, usually as a
24/// `String` (e.g. "std::io::Read") or a `Vec<Symbol>` (e.g. `[sym::std, sym::io, sym::Read]`). The
25/// representation is built up by appending one or more pieces. The specific details included in
26/// the built-up representation depend on the purpose of the printer. The more advanced printers
27/// also rely on the `PrettyPrinter` sub-trait.
28pub trait Printer<'tcx>: Sized {
29    fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
30
31    /// Appends a representation of an entity with a normal path, e.g. "std::io::Read".
32    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    /// Like `print_def_path`, but for `DefPathData::Impl`.
41    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            // We are probably printing a nested item inside of an impl.
56            // Use the identity substitutions for the impl.
57            (
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    /// Appends a representation of a region.
67    fn print_region(&mut self, region: ty::Region<'tcx>) -> Result<(), PrintError>;
68
69    /// Appends a representation of a type.
70    fn print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError>;
71
72    /// Appends a representation of a list of `PolyExistentialPredicate`s.
73    fn print_dyn_existential(
74        &mut self,
75        predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
76    ) -> Result<(), PrintError>;
77
78    /// Appends a representation of a const.
79    fn print_const(&mut self, ct: ty::Const<'tcx>) -> Result<(), PrintError>;
80
81    /// Appends a representation of a crate name, e.g. `std`, or even ``.
82    fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError>;
83
84    /// Appends a representation of a (full or partial) simple path, in two parts. `print_prefix`,
85    /// when called, appends the representation of the leading segments. The rest of the method
86    /// appends the representation of the final segment, the details of which are in
87    /// `disambiguated_data`.
88    ///
89    /// E.g. `std::io` + `Read` -> `std::io::Read`.
90    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    /// Similar to `print_path_with_simple`, but the final segment is an `impl` segment.
97    ///
98    /// E.g. `slice` + `<impl [T]>` -> `slice::<impl [T]>`, which may then be further appended to,
99    /// giving a longer path representation such as `slice::<impl [T]>::to_vec_in::ConvertVec`.
100    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    /// Appends a representation of a path ending in generic args, in two parts. `print_prefix`,
108    /// when called, appends the leading segments. The rest of the method appends the
109    /// representation of the generic args. (Some printers choose to skip appending the generic
110    /// args.)
111    ///
112    /// E.g. `ImplementsTraitForUsize` + `<usize>` -> `ImplementsTraitForUsize<usize>`.
113    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    /// Appends a representation of a qualified path segment, e.g. `<OsString as From<&T>>`.
120    /// If `trait_ref` is `None`, it may fall back to simpler forms, e.g. `<Vec<T>>` or just `Foo`.
121    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    // Defaults (should not be overridden):
128
129    #[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                            // We need to additionally print the `kind` field of a coroutine if
158                            // it is desugared from a coroutine-closure.
159                            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                                // Closures' own generics are only captures, don't print them.
171                            }
172                        }
173                        DefPathData::SyntheticCoroutineBody => {
174                            // Synthetic coroutine bodies have no distinct generics, since like
175                            // closures they're all just internal state of the coroutine.
176                        }
177                        // This covers both `DefKind::AnonConst` and `DefKind::InlineConst`.
178                        // Anon consts doesn't have their own generics, and inline consts' own
179                        // generics are their inferred types, so don't print them.
180                        DefPathData::AnonConst => {}
181
182                        // If we have any generic arguments to print, we do that
183                        // on top of the same path, but without its own generics.
184                        _ => {
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                    // FIXME(eddyb) try to move this into the parent's printing
196                    // logic, instead of doing it when printing the child.
197                    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        // Decide whether to print the parent path for the impl.
237        // Logically, since impls are global, it's never needed, but
238        // users may find it useful. Currently, we omit the parent if
239        // the impl is either in the same module as the self-type or
240        // as the trait.
241        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            // If the impl is not co-located with either self-type or
252            // trait-type, then fallback to a format that identifies
253            // the module more clearly.
254            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            // Otherwise, try to give a good form that would be valid language
261            // syntax. Preferably using associated item notation.
262            self.print_path_with_qualified(self_ty, impl_trait_ref)
263        }
264    }
265}
266
267/// As a heuristic, when we see an impl, if we see that the
268/// 'self type' is a type defined in the same module as the impl,
269/// we can omit including the path to the impl itself. This
270/// function tries to find a "characteristic `DefId`" for a
271/// type. It's just a heuristic so it makes some questionable
272/// decisions and we may want to adjust it later.
273///
274/// Visited set is needed to avoid full iteration over
275/// deeply nested tuples that have no DefId.
276fn 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
389// This is only used by query descriptions
390pub 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}