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 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 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 ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => {
49 self.write_fmt(format_args!("_"))write!(self, "_")?;
50 Ok(())
51 }
52
53 ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), args)
55 | ty::Alias(
56 _,
57 ty::AliasTy {
58 kind: ty::Projection { def_id } | ty::Opaque { def_id }, 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::FnDef(def_id, args) => self.print_def_path(def_id, args.no_bound_vars().unwrap()),
67 ty::Alias(_, ty::AliasTy { kind: ty::Free { .. }, .. }) => {
68 ::rustc_middle::util::bug::bug_fmt(format_args!("type_name: unexpected free alias"))bug!("type_name: unexpected free alias")
69 }
70 ty::Alias(_, ty::AliasTy { kind: ty::Inherent { .. }, .. }) => {
71 ::rustc_middle::util::bug::bug_fmt(format_args!("type_name: unexpected inherent projection"))bug!("type_name: unexpected inherent projection")
72 }
73 ty::CoroutineWitness(..) => ::rustc_middle::util::bug::bug_fmt(format_args!("type_name: unexpected `CoroutineWitness`"))bug!("type_name: unexpected `CoroutineWitness`"),
74 }
75 }
76
77 fn print_const(&mut self, ct: ty::Const<'tcx>) -> Result<(), PrintError> {
78 self.pretty_print_const(ct, false)
79 }
80
81 fn print_dyn_existential(
82 &mut self,
83 predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
84 ) -> Result<(), PrintError> {
85 self.pretty_print_dyn_existential(predicates)
86 }
87
88 fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
89 self.path.push_str(self.tcx.crate_name(cnum).as_str());
90 Ok(())
91 }
92
93 fn print_path_with_qualified(
94 &mut self,
95 self_ty: Ty<'tcx>,
96 trait_ref: Option<ty::TraitRef<'tcx>>,
97 ) -> Result<(), PrintError> {
98 self.pretty_print_path_with_qualified(self_ty, trait_ref)
99 }
100
101 fn print_path_with_impl(
102 &mut self,
103 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
104 self_ty: Ty<'tcx>,
105 trait_ref: Option<ty::TraitRef<'tcx>>,
106 ) -> Result<(), PrintError> {
107 self.pretty_print_path_with_impl(
108 |cx| {
109 print_prefix(cx)?;
110
111 cx.path.push_str("::");
112
113 Ok(())
114 },
115 self_ty,
116 trait_ref,
117 )
118 }
119
120 fn print_path_with_simple(
121 &mut self,
122 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
123 disambiguated_data: &DisambiguatedDefPathData,
124 ) -> Result<(), PrintError> {
125 print_prefix(self)?;
126
127 self.path.write_fmt(format_args!("::{0}", disambiguated_data.data))write!(self.path, "::{}", disambiguated_data.data).unwrap();
128
129 Ok(())
130 }
131
132 fn print_path_with_generic_args(
133 &mut self,
134 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
135 args: &[GenericArg<'tcx>],
136 ) -> Result<(), PrintError> {
137 print_prefix(self)?;
138 if !args.is_empty() {
139 self.generic_delimiters(|cx| cx.comma_sep(args.iter().copied()))
140 } else {
141 Ok(())
142 }
143 }
144
145 fn print_coroutine_with_kind(
146 &mut self,
147 def_id: DefId,
148 parent_args: &'tcx [GenericArg<'tcx>],
149 kind: Ty<'tcx>,
150 ) -> Result<(), PrintError> {
151 self.print_def_path(def_id, parent_args)?;
152
153 let ty::Coroutine(_, args) =
154 self.tcx.type_of(def_id).instantiate_identity().skip_norm_wip().kind()
155 else {
156 return Ok(());
158 };
159
160 let default_kind = args.as_coroutine().kind_ty();
161
162 match kind.to_opt_closure_kind() {
163 _ if kind == default_kind => {
164 }
166 Some(ty::ClosureKind::Fn) | None => {
167 }
169 Some(ty::ClosureKind::FnMut) => self.path.push_str("::{{call_mut}}"),
170 Some(ty::ClosureKind::FnOnce) => self.path.push_str("::{{call_once}}"),
171 }
172
173 Ok(())
174 }
175}
176
177impl<'tcx> PrettyPrinter<'tcx> for TypeNamePrinter<'tcx> {
178 fn should_print_optional_region(&self, region: ty::Region<'_>) -> bool {
179 let kind = region.kind();
183 match region.kind() {
184 ty::ReErased | ty::ReEarlyParam(_) | ty::ReStatic => false,
185 ty::ReBound(..) => true,
186 _ => {
::core::panicking::panic_fmt(format_args!("type_name unhandled region: {0:?}",
kind));
}panic!("type_name unhandled region: {kind:?}"),
187 }
188 }
189
190 fn generic_delimiters(
191 &mut self,
192 f: impl FnOnce(&mut Self) -> Result<(), PrintError>,
193 ) -> Result<(), PrintError> {
194 self.write_fmt(format_args!("<"))write!(self, "<")?;
195
196 f(self)?;
197
198 self.write_fmt(format_args!(">"))write!(self, ">")?;
199
200 Ok(())
201 }
202
203 fn should_print_verbose(&self) -> bool {
204 false
206 }
207}
208
209impl Write for TypeNamePrinter<'_> {
210 fn write_str(&mut self, s: &str) -> std::fmt::Result {
211 self.path.push_str(s);
212 Ok(())
213 }
214}
215
216pub fn type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> String {
217 let mut p = TypeNamePrinter { tcx, path: String::new() };
218 p.print_type(ty).unwrap();
219 p.path
220}