rustc_const_eval/util/
type_name.rs

1use std::fmt::Write;
2
3use rustc_data_structures::intern::Interned;
4use rustc_hir::def_id::CrateNum;
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
137impl<'tcx> PrettyPrinter<'tcx> for TypeNamePrinter<'tcx> {
138    fn should_print_optional_region(&self, _region: ty::Region<'_>) -> bool {
139        // Bound regions are always printed (as `'_`), which gives some idea that they are special,
140        // even though the `for` is omitted by the pretty printer.
141        // E.g. `for<'a, 'b> fn(&'a u32, &'b u32)` is printed as "fn(&'_ u32, &'_ u32)".
142        match _region.kind() {
143            ty::ReErased => false,
144            ty::ReBound(..) => true,
145            _ => unreachable!(),
146        }
147    }
148
149    fn generic_delimiters(
150        &mut self,
151        f: impl FnOnce(&mut Self) -> Result<(), PrintError>,
152    ) -> Result<(), PrintError> {
153        write!(self, "<")?;
154
155        f(self)?;
156
157        write!(self, ">")?;
158
159        Ok(())
160    }
161
162    fn should_print_verbose(&self) -> bool {
163        // `std::any::type_name` should never print verbose type names
164        false
165    }
166}
167
168impl Write for TypeNamePrinter<'_> {
169    fn write_str(&mut self, s: &str) -> std::fmt::Result {
170        self.path.push_str(s);
171        Ok(())
172    }
173}
174
175pub fn type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> String {
176    let mut p = TypeNamePrinter { tcx, path: String::new() };
177    p.print_type(ty).unwrap();
178    p.path
179}