]>
Commit | Line | Data |
---|---|---|
d9579d0f AL |
1 | // Type Names for Debug Info. |
2 | ||
532ac7d7 | 3 | use rustc_data_structures::fx::FxHashSet; |
dfeec247 XL |
4 | use rustc_hir as hir; |
5 | use rustc_hir::def_id::DefId; | |
ba9703b0 | 6 | use rustc_middle::ty::{self, subst::SubstsRef, Ty, TyCtxt}; |
d9579d0f | 7 | |
1b1a35ee XL |
8 | use std::fmt::Write; |
9 | ||
d9579d0f | 10 | // Compute the name of the type as it should be stored in debuginfo. Does not do |
0731742a | 11 | // any caching, i.e., calling the function twice with the same type will also do |
d9579d0f | 12 | // the work twice. The `qualified` parameter only affects the first level of the |
0731742a | 13 | // type name, further levels (i.e., type parameters) are always fully qualified. |
dc9dc135 XL |
14 | pub fn compute_debuginfo_type_name<'tcx>( |
15 | tcx: TyCtxt<'tcx>, | |
16 | t: Ty<'tcx>, | |
17 | qualified: bool, | |
18 | ) -> String { | |
d9579d0f | 19 | let mut result = String::with_capacity(64); |
532ac7d7 | 20 | let mut visited = FxHashSet::default(); |
48663c56 | 21 | push_debuginfo_type_name(tcx, t, qualified, &mut result, &mut visited); |
d9579d0f AL |
22 | result |
23 | } | |
24 | ||
25 | // Pushes the name of the type as it should be stored in debuginfo on the | |
26 | // `output` String. See also compute_debuginfo_type_name(). | |
dc9dc135 XL |
27 | pub fn push_debuginfo_type_name<'tcx>( |
28 | tcx: TyCtxt<'tcx>, | |
29 | t: Ty<'tcx>, | |
30 | qualified: bool, | |
31 | output: &mut String, | |
32 | visited: &mut FxHashSet<Ty<'tcx>>, | |
33 | ) { | |
3b2f2976 XL |
34 | // When targeting MSVC, emit C++ style type names for compatibility with |
35 | // .natvis visualizers (and perhaps other existing native debuggers?) | |
29967ef6 | 36 | let cpp_like_names = tcx.sess.target.is_like_msvc; |
3b2f2976 | 37 | |
1b1a35ee | 38 | match *t.kind() { |
b7449926 XL |
39 | ty::Bool => output.push_str("bool"), |
40 | ty::Char => output.push_str("char"), | |
41 | ty::Str => output.push_str("str"), | |
1b1a35ee | 42 | ty::Never => output.push('!'), |
60c5eb7d XL |
43 | ty::Int(int_ty) => output.push_str(int_ty.name_str()), |
44 | ty::Uint(uint_ty) => output.push_str(uint_ty.name_str()), | |
45 | ty::Float(float_ty) => output.push_str(float_ty.name_str()), | |
48663c56 | 46 | ty::Foreign(def_id) => push_item_name(tcx, def_id, qualified, output), |
b7449926 | 47 | ty::Adt(def, substs) => { |
48663c56 XL |
48 | push_item_name(tcx, def.did, qualified, output); |
49 | push_type_params(tcx, substs, output, visited); | |
dfeec247 | 50 | } |
b7449926 | 51 | ty::Tuple(component_types) => { |
f035d41b XL |
52 | if cpp_like_names { |
53 | output.push_str("tuple<"); | |
54 | } else { | |
55 | output.push('('); | |
56 | } | |
57 | ||
f9f354fc | 58 | for component_type in component_types { |
48663c56 | 59 | push_debuginfo_type_name(tcx, component_type.expect_ty(), true, output, visited); |
d9579d0f AL |
60 | output.push_str(", "); |
61 | } | |
62 | if !component_types.is_empty() { | |
63 | output.pop(); | |
64 | output.pop(); | |
65 | } | |
f035d41b XL |
66 | |
67 | if cpp_like_names { | |
68 | output.push('>'); | |
69 | } else { | |
70 | output.push(')'); | |
71 | } | |
dfeec247 XL |
72 | } |
73 | ty::RawPtr(ty::TypeAndMut { ty: inner_type, mutbl }) => { | |
3b2f2976 XL |
74 | if !cpp_like_names { |
75 | output.push('*'); | |
76 | } | |
d9579d0f | 77 | match mutbl { |
dfeec247 XL |
78 | hir::Mutability::Not => output.push_str("const "), |
79 | hir::Mutability::Mut => output.push_str("mut "), | |
d9579d0f AL |
80 | } |
81 | ||
48663c56 | 82 | push_debuginfo_type_name(tcx, inner_type, true, output, visited); |
3b2f2976 XL |
83 | |
84 | if cpp_like_names { | |
85 | output.push('*'); | |
86 | } | |
dfeec247 | 87 | } |
b7449926 | 88 | ty::Ref(_, inner_type, mutbl) => { |
3b2f2976 XL |
89 | if !cpp_like_names { |
90 | output.push('&'); | |
91 | } | |
60c5eb7d | 92 | output.push_str(mutbl.prefix_str()); |
d9579d0f | 93 | |
48663c56 | 94 | push_debuginfo_type_name(tcx, inner_type, true, output, visited); |
3b2f2976 XL |
95 | |
96 | if cpp_like_names { | |
97 | output.push('*'); | |
98 | } | |
dfeec247 | 99 | } |
b7449926 | 100 | ty::Array(inner_type, len) => { |
62682a34 | 101 | output.push('['); |
48663c56 | 102 | push_debuginfo_type_name(tcx, inner_type, true, output, visited); |
416331ca | 103 | output.push_str(&format!("; {}", len.eval_usize(tcx, ty::ParamEnv::reveal_all()))); |
62682a34 | 104 | output.push(']'); |
dfeec247 | 105 | } |
b7449926 | 106 | ty::Slice(inner_type) => { |
3b2f2976 XL |
107 | if cpp_like_names { |
108 | output.push_str("slice<"); | |
109 | } else { | |
110 | output.push('['); | |
111 | } | |
112 | ||
48663c56 | 113 | push_debuginfo_type_name(tcx, inner_type, true, output, visited); |
3b2f2976 XL |
114 | |
115 | if cpp_like_names { | |
116 | output.push('>'); | |
117 | } else { | |
118 | output.push(']'); | |
119 | } | |
dfeec247 | 120 | } |
b7449926 | 121 | ty::Dynamic(ref trait_data, ..) => { |
0731742a | 122 | if let Some(principal) = trait_data.principal() { |
dfeec247 XL |
123 | let principal = tcx |
124 | .normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &principal); | |
48663c56 XL |
125 | push_item_name(tcx, principal.def_id, false, output); |
126 | push_type_params(tcx, principal.substs, output, visited); | |
0731742a XL |
127 | } else { |
128 | output.push_str("dyn '_"); | |
129 | } | |
dfeec247 | 130 | } |
b7449926 | 131 | ty::FnDef(..) | ty::FnPtr(_) => { |
532ac7d7 XL |
132 | // We've encountered a weird 'recursive type' |
133 | // Currently, the only way to generate such a type | |
134 | // is by using 'impl trait': | |
135 | // | |
136 | // fn foo() -> impl Copy { foo } | |
137 | // | |
138 | // There's not really a sensible name we can generate, | |
139 | // since we don't include 'impl trait' types (e.g. ty::Opaque) | |
140 | // in the output | |
141 | // | |
142 | // Since we need to generate *something*, we just | |
143 | // use a dummy string that should make it clear | |
144 | // that something unusual is going on | |
145 | if !visited.insert(t) { | |
146 | output.push_str("<recursive_type>"); | |
147 | return; | |
148 | } | |
149 | ||
48663c56 | 150 | let sig = t.fn_sig(tcx); |
60c5eb7d | 151 | output.push_str(sig.unsafety().prefix_str()); |
d9579d0f | 152 | |
8bb4bdeb | 153 | let abi = sig.abi(); |
48663c56 | 154 | if abi != rustc_target::spec::abi::Abi::Rust { |
d9579d0f AL |
155 | output.push_str("extern \""); |
156 | output.push_str(abi.name()); | |
157 | output.push_str("\" "); | |
158 | } | |
159 | ||
160 | output.push_str("fn("); | |
161 | ||
48663c56 | 162 | let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); |
476ff2be SL |
163 | if !sig.inputs().is_empty() { |
164 | for ¶meter_type in sig.inputs() { | |
48663c56 | 165 | push_debuginfo_type_name(tcx, parameter_type, true, output, visited); |
d9579d0f AL |
166 | output.push_str(", "); |
167 | } | |
168 | output.pop(); | |
169 | output.pop(); | |
170 | } | |
171 | ||
532ac7d7 | 172 | if sig.c_variadic { |
476ff2be | 173 | if !sig.inputs().is_empty() { |
d9579d0f AL |
174 | output.push_str(", ..."); |
175 | } else { | |
176 | output.push_str("..."); | |
177 | } | |
178 | } | |
179 | ||
180 | output.push(')'); | |
181 | ||
b7449926 | 182 | if !sig.output().is_unit() { |
5bcae85e | 183 | output.push_str(" -> "); |
48663c56 | 184 | push_debuginfo_type_name(tcx, sig.output(), true, output, visited); |
d9579d0f | 185 | } |
532ac7d7 | 186 | |
532ac7d7 XL |
187 | // We only keep the type in 'visited' |
188 | // for the duration of the body of this method. | |
189 | // It's fine for a particular function type | |
190 | // to show up multiple times in one overall type | |
191 | // (e.g. MyType<fn() -> u8, fn() -> u8> | |
192 | // | |
193 | // We only care about avoiding recursing | |
194 | // directly back to the type we're currently | |
195 | // processing | |
196 | visited.remove(t); | |
dfeec247 | 197 | } |
416331ca XL |
198 | ty::Closure(def_id, ..) => { |
199 | output.push_str(&format!( | |
200 | "closure-{}", | |
201 | tcx.def_key(def_id).disambiguated_data.disambiguator | |
202 | )); | |
d9579d0f | 203 | } |
416331ca XL |
204 | ty::Generator(def_id, ..) => { |
205 | output.push_str(&format!( | |
206 | "generator-{}", | |
207 | tcx.def_key(def_id).disambiguated_data.disambiguator | |
208 | )); | |
ea8adc8c | 209 | } |
3dfed10e XL |
210 | // Type parameters from polymorphized functions. |
211 | ty::Param(_) => { | |
212 | output.push_str(&format!("{:?}", t)); | |
213 | } | |
f035d41b | 214 | ty::Error(_) |
dfeec247 XL |
215 | | ty::Infer(_) |
216 | | ty::Placeholder(..) | |
dfeec247 XL |
217 | | ty::Projection(..) |
218 | | ty::Bound(..) | |
219 | | ty::Opaque(..) | |
3dfed10e | 220 | | ty::GeneratorWitness(..) => { |
dfeec247 XL |
221 | bug!( |
222 | "debuginfo: Trying to create type name for \ | |
223 | unexpected type: {:?}", | |
224 | t | |
225 | ); | |
d9579d0f AL |
226 | } |
227 | } | |
228 | ||
dc9dc135 | 229 | fn push_item_name(tcx: TyCtxt<'tcx>, def_id: DefId, qualified: bool, output: &mut String) { |
54a0048b | 230 | if qualified { |
48663c56 XL |
231 | output.push_str(&tcx.crate_name(def_id.krate).as_str()); |
232 | for path_element in tcx.def_path(def_id).data { | |
1b1a35ee | 233 | write!(output, "::{}", path_element.data).unwrap(); |
d9579d0f | 234 | } |
54a0048b | 235 | } else { |
48663c56 | 236 | output.push_str(&tcx.item_name(def_id).as_str()); |
54a0048b | 237 | } |
d9579d0f AL |
238 | } |
239 | ||
532ac7d7 | 240 | // Pushes the type parameters in the given `InternalSubsts` to the output string. |
d9579d0f AL |
241 | // This ignores region parameters, since they can't reliably be |
242 | // reconstructed for items from non-local crates. For local crates, this | |
243 | // would be possible but with inlining and LTO we have to use the least | |
244 | // common denominator - otherwise we would run into conflicts. | |
dc9dc135 XL |
245 | fn push_type_params<'tcx>( |
246 | tcx: TyCtxt<'tcx>, | |
247 | substs: SubstsRef<'tcx>, | |
248 | output: &mut String, | |
249 | visited: &mut FxHashSet<Ty<'tcx>>, | |
250 | ) { | |
9e0c209e | 251 | if substs.types().next().is_none() { |
d9579d0f AL |
252 | return; |
253 | } | |
254 | ||
255 | output.push('<'); | |
256 | ||
9e0c209e | 257 | for type_parameter in substs.types() { |
48663c56 | 258 | push_debuginfo_type_name(tcx, type_parameter, true, output, visited); |
d9579d0f AL |
259 | output.push_str(", "); |
260 | } | |
261 | ||
262 | output.pop(); | |
263 | output.pop(); | |
264 | ||
265 | output.push('>'); | |
266 | } | |
267 | } |