Skip to main content

rustc_const_eval/util/
type_name.rs

1use std::fmt::Write;
2
3use rustc_data_structures::intern::Interned;
4use rustc_hir::def_id::{CrateNum, DefId};
5use rustc_hir::definitions::DisambiguatedDefPathData;
6use rustc_middle::bug;
7use rustc_middle::ty::print::{PrettyPrinter, PrintError, Printer};
8use rustc_middle::ty::{self, GenericArg, Ty, TyCtxt};
9
10struct TypeNamePrinter<'tcx> {
11    tcx: TyCtxt<'tcx>,
12    path: String,
13}
14
15impl<'tcx> Printer<'tcx> for TypeNamePrinter<'tcx> {
16    fn tcx(&self) -> TyCtxt<'tcx> {
17        self.tcx
18    }
19
20    fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> {
21        // FIXME: most regions have been erased by the time this code runs.
22        // Just printing `'_` is a bit hacky but gives mostly good results, and
23        // doing better is difficult. See `should_print_optional_region`.
24        self.write_fmt(format_args!("\'_"))write!(self, "'_")
25    }
26
27    fn print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> {
28        match *ty.kind() {
29            // Types without identity.
30            ty::Bool
31            | ty::Char
32            | ty::Int(_)
33            | ty::Uint(_)
34            | ty::Float(_)
35            | ty::Str
36            | ty::Pat(_, _)
37            | ty::Array(_, _)
38            | ty::Slice(_)
39            | ty::RawPtr(_, _)
40            | ty::Ref(_, _, _)
41            | ty::FnPtr(..)
42            | ty::Never
43            | ty::Tuple(_)
44            | ty::Dynamic(_, _)
45            | ty::UnsafeBinder(_) => self.pretty_print_type(ty),
46
47            // Placeholders (all printed as `_` to uniformize them).
48            ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => {
49                self.write_fmt(format_args!("_"))write!(self, "_")?;
50                Ok(())
51            }
52
53            // Types with identity (print the module path).
54            ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), args)
55            | ty::FnDef(def_id, args)
56            | ty::Alias(ty::AliasTy {
57                kind: ty::Projection { def_id } | ty::Opaque { def_id },
58                args,
59                ..
60            })
61            | ty::Closure(def_id, args)
62            | ty::CoroutineClosure(def_id, args)
63            | ty::Coroutine(def_id, args) => self.print_def_path(def_id, args),
64            ty::Foreign(def_id) => self.print_def_path(def_id, &[]),
65
66            ty::Alias(ty::AliasTy { kind: ty::Free { .. }, .. }) => {
67                ::rustc_middle::util::bug::bug_fmt(format_args!("type_name: unexpected free alias"))bug!("type_name: unexpected free alias")
68            }
69            ty::Alias(ty::AliasTy { kind: ty::Inherent { .. }, .. }) => {
70                ::rustc_middle::util::bug::bug_fmt(format_args!("type_name: unexpected inherent projection"))bug!("type_name: unexpected inherent projection")
71            }
72            ty::CoroutineWitness(..) => ::rustc_middle::util::bug::bug_fmt(format_args!("type_name: unexpected `CoroutineWitness`"))bug!("type_name: unexpected `CoroutineWitness`"),
73        }
74    }
75
76    fn print_const(&mut self, ct: ty::Const<'tcx>) -> Result<(), PrintError> {
77        self.pretty_print_const(ct, false)
78    }
79
80    fn print_dyn_existential(
81        &mut self,
82        predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
83    ) -> Result<(), PrintError> {
84        self.pretty_print_dyn_existential(predicates)
85    }
86
87    fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
88        self.path.push_str(self.tcx.crate_name(cnum).as_str());
89        Ok(())
90    }
91
92    fn print_path_with_qualified(
93        &mut self,
94        self_ty: Ty<'tcx>,
95        trait_ref: Option<ty::TraitRef<'tcx>>,
96    ) -> Result<(), PrintError> {
97        self.pretty_print_path_with_qualified(self_ty, trait_ref)
98    }
99
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        self.pretty_print_path_with_impl(
107            |cx| {
108                print_prefix(cx)?;
109
110                cx.path.push_str("::");
111
112                Ok(())
113            },
114            self_ty,
115            trait_ref,
116        )
117    }
118
119    fn print_path_with_simple(
120        &mut self,
121        print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
122        disambiguated_data: &DisambiguatedDefPathData,
123    ) -> Result<(), PrintError> {
124        print_prefix(self)?;
125
126        self.path.write_fmt(format_args!("::{0}", disambiguated_data.data))write!(self.path, "::{}", disambiguated_data.data).unwrap();
127
128        Ok(())
129    }
130
131    fn print_path_with_generic_args(
132        &mut self,
133        print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
134        args: &[GenericArg<'tcx>],
135    ) -> Result<(), PrintError> {
136        print_prefix(self)?;
137        if !args.is_empty() {
138            self.generic_delimiters(|cx| cx.comma_sep(args.iter().copied()))
139        } else {
140            Ok(())
141        }
142    }
143
144    fn print_coroutine_with_kind(
145        &mut self,
146        def_id: DefId,
147        parent_args: &'tcx [GenericArg<'tcx>],
148        kind: Ty<'tcx>,
149    ) -> Result<(), PrintError> {
150        self.print_def_path(def_id, parent_args)?;
151
152        let ty::Coroutine(_, args) =
153            self.tcx.type_of(def_id).instantiate_identity().skip_norm_wip().kind()
154        else {
155            // Could be `ty::Error`.
156            return Ok(());
157        };
158
159        let default_kind = args.as_coroutine().kind_ty();
160
161        match kind.to_opt_closure_kind() {
162            _ if kind == default_kind => {
163                // No need to mark the closure if it's the deduced coroutine kind.
164            }
165            Some(ty::ClosureKind::Fn) | None => {
166                // Should never happen. Just don't mark anything rather than panicking.
167            }
168            Some(ty::ClosureKind::FnMut) => self.path.push_str("::{{call_mut}}"),
169            Some(ty::ClosureKind::FnOnce) => self.path.push_str("::{{call_once}}"),
170        }
171
172        Ok(())
173    }
174}
175
176impl<'tcx> PrettyPrinter<'tcx> for TypeNamePrinter<'tcx> {
177    fn should_print_optional_region(&self, region: ty::Region<'_>) -> bool {
178        // Bound regions are always printed (as `'_`), which gives some idea that they are special,
179        // even though the `for` is omitted by the pretty printer.
180        // E.g. `for<'a, 'b> fn(&'a u32, &'b u32)` is printed as "fn(&'_ u32, &'_ u32)".
181        let kind = region.kind();
182        match region.kind() {
183            ty::ReErased | ty::ReEarlyParam(_) | ty::ReStatic => false,
184            ty::ReBound(..) => true,
185            _ => {
    ::core::panicking::panic_fmt(format_args!("type_name unhandled region: {0:?}",
            kind));
}panic!("type_name unhandled region: {kind:?}"),
186        }
187    }
188
189    fn generic_delimiters(
190        &mut self,
191        f: impl FnOnce(&mut Self) -> Result<(), PrintError>,
192    ) -> Result<(), PrintError> {
193        self.write_fmt(format_args!("<"))write!(self, "<")?;
194
195        f(self)?;
196
197        self.write_fmt(format_args!(">"))write!(self, ">")?;
198
199        Ok(())
200    }
201
202    fn should_print_verbose(&self) -> bool {
203        // `std::any::type_name` should never print verbose type names
204        false
205    }
206}
207
208impl Write for TypeNamePrinter<'_> {
209    fn write_str(&mut self, s: &str) -> std::fmt::Result {
210        self.path.push_str(s);
211        Ok(())
212    }
213}
214
215pub fn type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> String {
216    let mut p = TypeNamePrinter { tcx, path: String::new() };
217    p.print_type(ty).unwrap();
218    p.path
219}