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