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, GenericArgKind, 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        // This is reachable (via `pretty_print_dyn_existential`) even though
22        // `<Self As PrettyPrinter>::should_print_region` returns false. See #144994.
23        Ok(())
24    }
25
26    fn print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> {
27        match *ty.kind() {
28            // Types without identity.
29            ty::Bool
30            | ty::Char
31            | ty::Int(_)
32            | ty::Uint(_)
33            | ty::Float(_)
34            | ty::Str
35            | ty::Pat(_, _)
36            | ty::Array(_, _)
37            | ty::Slice(_)
38            | ty::RawPtr(_, _)
39            | ty::Ref(_, _, _)
40            | ty::FnPtr(..)
41            | ty::Never
42            | ty::Tuple(_)
43            | ty::Dynamic(_, _, _)
44            | ty::UnsafeBinder(_) => self.pretty_print_type(ty),
45
46            // Placeholders (all printed as `_` to uniformize them).
47            ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => {
48                write!(self, "_")?;
49                Ok(())
50            }
51
52            // Types with identity (print the module path).
53            ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), args)
54            | ty::FnDef(def_id, args)
55            | ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, args, .. })
56            | ty::Closure(def_id, args)
57            | ty::CoroutineClosure(def_id, args)
58            | ty::Coroutine(def_id, args) => self.print_def_path(def_id, args),
59            ty::Foreign(def_id) => self.print_def_path(def_id, &[]),
60
61            ty::Alias(ty::Free, _) => bug!("type_name: unexpected free alias"),
62            ty::Alias(ty::Inherent, _) => bug!("type_name: unexpected inherent projection"),
63            ty::CoroutineWitness(..) => bug!("type_name: unexpected `CoroutineWitness`"),
64        }
65    }
66
67    fn print_const(&mut self, ct: ty::Const<'tcx>) -> Result<(), PrintError> {
68        self.pretty_print_const(ct, false)
69    }
70
71    fn print_dyn_existential(
72        &mut self,
73        predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
74    ) -> Result<(), PrintError> {
75        self.pretty_print_dyn_existential(predicates)
76    }
77
78    fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
79        self.path.push_str(self.tcx.crate_name(cnum).as_str());
80        Ok(())
81    }
82
83    fn print_path_with_qualified(
84        &mut self,
85        self_ty: Ty<'tcx>,
86        trait_ref: Option<ty::TraitRef<'tcx>>,
87    ) -> Result<(), PrintError> {
88        self.pretty_print_path_with_qualified(self_ty, trait_ref)
89    }
90
91    fn print_path_with_impl(
92        &mut self,
93        print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
94        self_ty: Ty<'tcx>,
95        trait_ref: Option<ty::TraitRef<'tcx>>,
96    ) -> Result<(), PrintError> {
97        self.pretty_print_path_with_impl(
98            |cx| {
99                print_prefix(cx)?;
100
101                cx.path.push_str("::");
102
103                Ok(())
104            },
105            self_ty,
106            trait_ref,
107        )
108    }
109
110    fn print_path_with_simple(
111        &mut self,
112        print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
113        disambiguated_data: &DisambiguatedDefPathData,
114    ) -> Result<(), PrintError> {
115        print_prefix(self)?;
116
117        write!(self.path, "::{}", disambiguated_data.data).unwrap();
118
119        Ok(())
120    }
121
122    fn print_path_with_generic_args(
123        &mut self,
124        print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
125        args: &[GenericArg<'tcx>],
126    ) -> Result<(), PrintError> {
127        print_prefix(self)?;
128        let args =
129            args.iter().cloned().filter(|arg| !matches!(arg.kind(), GenericArgKind::Lifetime(_)));
130        if args.clone().next().is_some() {
131            self.generic_delimiters(|cx| cx.comma_sep(args))
132        } else {
133            Ok(())
134        }
135    }
136}
137
138impl<'tcx> PrettyPrinter<'tcx> for TypeNamePrinter<'tcx> {
139    fn should_print_region(&self, _region: ty::Region<'_>) -> bool {
140        false
141    }
142
143    fn generic_delimiters(
144        &mut self,
145        f: impl FnOnce(&mut Self) -> Result<(), PrintError>,
146    ) -> Result<(), PrintError> {
147        write!(self, "<")?;
148
149        f(self)?;
150
151        write!(self, ">")?;
152
153        Ok(())
154    }
155
156    fn should_print_verbose(&self) -> bool {
157        // `std::any::type_name` should never print verbose type names
158        false
159    }
160}
161
162impl Write for TypeNamePrinter<'_> {
163    fn write_str(&mut self, s: &str) -> std::fmt::Result {
164        self.path.push_str(s);
165        Ok(())
166    }
167}
168
169pub fn type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> String {
170    let mut p = TypeNamePrinter { tcx, path: String::new() };
171    p.print_type(ty).unwrap();
172    p.path
173}