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 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 ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => {
46 write!(self, "_")?;
47 Ok(())
48 }
49
50 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 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}