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        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                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::Projection | ty::Opaque, ty::AliasTy { def_id, args, .. })
57            | ty::Closure(def_id, args)
58            | ty::CoroutineClosure(def_id, args)
59            | ty::Coroutine(def_id, args) => self.print_def_path(def_id, args),
60            ty::Foreign(def_id) => self.print_def_path(def_id, &[]),
61
62            ty::Alias(ty::Free, _) => bug!("type_name: unexpected free alias"),
63            ty::Alias(ty::Inherent, _) => bug!("type_name: unexpected inherent projection"),
64            ty::CoroutineWitness(..) => bug!("type_name: unexpected `CoroutineWitness`"),
65        }
66    }
67
68    fn print_const(&mut self, ct: ty::Const<'tcx>) -> Result<(), PrintError> {
69        self.pretty_print_const(ct, false)
70    }
71
72    fn print_dyn_existential(
73        &mut self,
74        predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
75    ) -> Result<(), PrintError> {
76        self.pretty_print_dyn_existential(predicates)
77    }
78
79    fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
80        self.path.push_str(self.tcx.crate_name(cnum).as_str());
81        Ok(())
82    }
83
84    fn print_path_with_qualified(
85        &mut self,
86        self_ty: Ty<'tcx>,
87        trait_ref: Option<ty::TraitRef<'tcx>>,
88    ) -> Result<(), PrintError> {
89        self.pretty_print_path_with_qualified(self_ty, trait_ref)
90    }
91
92    fn print_path_with_impl(
93        &mut self,
94        print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
95        self_ty: Ty<'tcx>,
96        trait_ref: Option<ty::TraitRef<'tcx>>,
97    ) -> Result<(), PrintError> {
98        self.pretty_print_path_with_impl(
99            |cx| {
100                print_prefix(cx)?;
101
102                cx.path.push_str("::");
103
104                Ok(())
105            },
106            self_ty,
107            trait_ref,
108        )
109    }
110
111    fn print_path_with_simple(
112        &mut self,
113        print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
114        disambiguated_data: &DisambiguatedDefPathData,
115    ) -> Result<(), PrintError> {
116        print_prefix(self)?;
117
118        write!(self.path, "::{}", disambiguated_data.data).unwrap();
119
120        Ok(())
121    }
122
123    fn print_path_with_generic_args(
124        &mut self,
125        print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
126        args: &[GenericArg<'tcx>],
127    ) -> Result<(), PrintError> {
128        print_prefix(self)?;
129        if !args.is_empty() {
130            self.generic_delimiters(|cx| cx.comma_sep(args.iter().copied()))
131        } else {
132            Ok(())
133        }
134    }
135
136    fn print_coroutine_with_kind(
137        &mut self,
138        def_id: DefId,
139        parent_args: &'tcx [GenericArg<'tcx>],
140        kind: Ty<'tcx>,
141    ) -> Result<(), PrintError> {
142        self.print_def_path(def_id, parent_args)?;
143
144        let ty::Coroutine(_, args) = self.tcx.type_of(def_id).instantiate_identity().kind() else {
145            // Could be `ty::Error`.
146            return Ok(());
147        };
148
149        let default_kind = args.as_coroutine().kind_ty();
150
151        match kind.to_opt_closure_kind() {
152            _ if kind == default_kind => {
153                // No need to mark the closure if it's the deduced coroutine kind.
154            }
155            Some(ty::ClosureKind::Fn) | None => {
156                // Should never happen. Just don't mark anything rather than panicking.
157            }
158            Some(ty::ClosureKind::FnMut) => self.path.push_str("::{{call_mut}}"),
159            Some(ty::ClosureKind::FnOnce) => self.path.push_str("::{{call_once}}"),
160        }
161
162        Ok(())
163    }
164}
165
166impl<'tcx> PrettyPrinter<'tcx> for TypeNamePrinter<'tcx> {
167    fn should_print_optional_region(&self, region: ty::Region<'_>) -> bool {
168        // Bound regions are always printed (as `'_`), which gives some idea that they are special,
169        // even though the `for` is omitted by the pretty printer.
170        // E.g. `for<'a, 'b> fn(&'a u32, &'b u32)` is printed as "fn(&'_ u32, &'_ u32)".
171        let kind = region.kind();
172        match region.kind() {
173            ty::ReErased | ty::ReEarlyParam(_) | ty::ReStatic => false,
174            ty::ReBound(..) => true,
175            _ => panic!("type_name unhandled region: {kind:?}"),
176        }
177    }
178
179    fn generic_delimiters(
180        &mut self,
181        f: impl FnOnce(&mut Self) -> Result<(), PrintError>,
182    ) -> Result<(), PrintError> {
183        write!(self, "<")?;
184
185        f(self)?;
186
187        write!(self, ">")?;
188
189        Ok(())
190    }
191
192    fn should_print_verbose(&self) -> bool {
193        // `std::any::type_name` should never print verbose type names
194        false
195    }
196}
197
198impl Write for TypeNamePrinter<'_> {
199    fn write_str(&mut self, s: &str) -> std::fmt::Result {
200        self.path.push_str(s);
201        Ok(())
202    }
203}
204
205pub fn type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> String {
206    let mut p = TypeNamePrinter { tcx, path: String::new() };
207    p.print_type(ty).unwrap();
208    p.path
209}