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        match region.kind() {
172            ty::ReErased | ty::ReEarlyParam(_) => false,
173            ty::ReBound(..) => true,
174            _ => unreachable!(),
175        }
176    }
177
178    fn generic_delimiters(
179        &mut self,
180        f: impl FnOnce(&mut Self) -> Result<(), PrintError>,
181    ) -> Result<(), PrintError> {
182        write!(self, "<")?;
183
184        f(self)?;
185
186        write!(self, ">")?;
187
188        Ok(())
189    }
190
191    fn should_print_verbose(&self) -> bool {
192        // `std::any::type_name` should never print verbose type names
193        false
194    }
195}
196
197impl Write for TypeNamePrinter<'_> {
198    fn write_str(&mut self, s: &str) -> std::fmt::Result {
199        self.path.push_str(s);
200        Ok(())
201    }
202}
203
204pub fn type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> String {
205    let mut p = TypeNamePrinter { tcx, path: String::new() };
206    p.print_type(ty).unwrap();
207    p.path
208}