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::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            // Could be `ty::Error`.
157            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                // No need to mark the closure if it's the deduced coroutine kind.
165            }
166            Some(ty::ClosureKind::Fn) | None => {
167                // Should never happen. Just don't mark anything rather than panicking.
168            }
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        // Bound regions are always printed (as `'_`), which gives some idea that they are special,
180        // even though the `for` is omitted by the pretty printer.
181        // E.g. `for<'a, 'b> fn(&'a u32, &'b u32)` is printed as "fn(&'_ u32, &'_ u32)".
182        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        // `std::any::type_name` should never print verbose type names
205        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}