]>
Commit | Line | Data |
---|---|---|
dc9dc135 XL |
1 | use rustc_data_structures::base_n; |
2 | use rustc_data_structures::fx::{FxHashMap, FxHashSet}; | |
5e7ed085 | 3 | use rustc_data_structures::intern::Interned; |
dfeec247 | 4 | use rustc_hir as hir; |
94222f64 | 5 | use rustc_hir::def::CtorKind; |
dfeec247 | 6 | use rustc_hir::def_id::{CrateNum, DefId}; |
ba9703b0 | 7 | use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; |
136023e0 | 8 | use rustc_middle::ty::layout::IntegerExt; |
ba9703b0 | 9 | use rustc_middle::ty::print::{Print, Printer}; |
04454e1e | 10 | use rustc_middle::ty::{ |
064997fb | 11 | self, EarlyBinder, FloatTy, Instance, IntTy, Ty, TyCtxt, TypeVisitable, UintTy, |
04454e1e | 12 | }; |
2b03887a | 13 | use rustc_middle::ty::{GenericArg, GenericArgKind}; |
a2a8927a | 14 | use rustc_span::symbol::kw; |
136023e0 | 15 | use rustc_target::abi::Integer; |
dc9dc135 | 16 | use rustc_target::spec::abi::Abi; |
dc9dc135 XL |
17 | |
18 | use std::fmt::Write; | |
94222f64 | 19 | use std::iter; |
dc9dc135 XL |
20 | use std::ops::Range; |
21 | ||
a2a8927a | 22 | pub(super) fn mangle<'tcx>( |
dc9dc135 XL |
23 | tcx: TyCtxt<'tcx>, |
24 | instance: Instance<'tcx>, | |
25 | instantiating_crate: Option<CrateNum>, | |
26 | ) -> String { | |
27 | let def_id = instance.def_id(); | |
28 | // FIXME(eddyb) this should ideally not be needed. | |
dfeec247 | 29 | let substs = tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), instance.substs); |
dc9dc135 XL |
30 | |
31 | let prefix = "_R"; | |
94222f64 | 32 | let mut cx = &mut SymbolMangler { |
dc9dc135 | 33 | tcx, |
94222f64 XL |
34 | start_offset: prefix.len(), |
35 | paths: FxHashMap::default(), | |
36 | types: FxHashMap::default(), | |
37 | consts: FxHashMap::default(), | |
dc9dc135 XL |
38 | binders: vec![], |
39 | out: String::from(prefix), | |
40 | }; | |
ba9703b0 XL |
41 | |
42 | // Append `::{shim:...#0}` to shims that can coexist with a non-shim instance. | |
43 | let shim_kind = match instance.def { | |
064997fb | 44 | ty::InstanceDef::VTableShim(_) => Some("vtable"), |
ba9703b0 XL |
45 | ty::InstanceDef::ReifyShim(_) => Some("reify"), |
46 | ||
47 | _ => None, | |
48 | }; | |
49 | ||
50 | cx = if let Some(shim_kind) = shim_kind { | |
51 | cx.path_append_ns(|cx| cx.print_def_path(def_id, substs), 'S', 0, shim_kind).unwrap() | |
dc9dc135 XL |
52 | } else { |
53 | cx.print_def_path(def_id, substs).unwrap() | |
54 | }; | |
55 | if let Some(instantiating_crate) = instantiating_crate { | |
56 | cx = cx.print_def_path(instantiating_crate.as_def_id(), &[]).unwrap(); | |
57 | } | |
94222f64 | 58 | std::mem::take(&mut cx.out) |
dc9dc135 XL |
59 | } |
60 | ||
923072b8 FG |
61 | pub(super) fn mangle_typeid_for_trait_ref<'tcx>( |
62 | tcx: TyCtxt<'tcx>, | |
63 | trait_ref: ty::PolyExistentialTraitRef<'tcx>, | |
64 | ) -> String { | |
65 | // FIXME(flip1995): See comment in `mangle_typeid_for_fnabi`. | |
66 | let mut cx = &mut SymbolMangler { | |
67 | tcx, | |
68 | start_offset: 0, | |
69 | paths: FxHashMap::default(), | |
70 | types: FxHashMap::default(), | |
71 | consts: FxHashMap::default(), | |
72 | binders: vec![], | |
73 | out: String::new(), | |
74 | }; | |
75 | cx = cx.print_def_path(trait_ref.def_id(), &[]).unwrap(); | |
76 | std::mem::take(&mut cx.out) | |
77 | } | |
78 | ||
dc9dc135 XL |
79 | struct BinderLevel { |
80 | /// The range of distances from the root of what's | |
81 | /// being printed, to the lifetimes in a binder. | |
82 | /// Specifically, a `BrAnon(i)` lifetime has depth | |
83 | /// `lifetime_depths.start + i`, going away from the | |
84 | /// the root and towards its use site, as `i` increases. | |
85 | /// This is used to flatten rustc's pairing of `BrAnon` | |
86 | /// (intra-binder disambiguation) with a `DebruijnIndex` | |
87 | /// (binder addressing), to "true" de Bruijn indices, | |
88 | /// by subtracting the depth of a certain lifetime, from | |
89 | /// the innermost depth at its use site. | |
90 | lifetime_depths: Range<u32>, | |
91 | } | |
92 | ||
93 | struct SymbolMangler<'tcx> { | |
94 | tcx: TyCtxt<'tcx>, | |
dc9dc135 XL |
95 | binders: Vec<BinderLevel>, |
96 | out: String, | |
94222f64 XL |
97 | |
98 | /// The length of the prefix in `out` (e.g. 2 for `_R`). | |
99 | start_offset: usize, | |
100 | /// The values are start positions in `out`, in bytes. | |
101 | paths: FxHashMap<(DefId, &'tcx [GenericArg<'tcx>]), usize>, | |
102 | types: FxHashMap<Ty<'tcx>, usize>, | |
5099ac24 | 103 | consts: FxHashMap<ty::Const<'tcx>, usize>, |
dc9dc135 XL |
104 | } |
105 | ||
a2a8927a | 106 | impl<'tcx> SymbolMangler<'tcx> { |
dc9dc135 XL |
107 | fn push(&mut self, s: &str) { |
108 | self.out.push_str(s); | |
109 | } | |
110 | ||
111 | /// Push a `_`-terminated base 62 integer, using the format | |
112 | /// specified in the RFC as `<base-62-number>`, that is: | |
113 | /// * `x = 0` is encoded as just the `"_"` terminator | |
114 | /// * `x > 0` is encoded as `x - 1` in base 62, followed by `"_"`, | |
115 | /// e.g. `1` becomes `"0_"`, `62` becomes `"Z_"`, etc. | |
116 | fn push_integer_62(&mut self, x: u64) { | |
117 | if let Some(x) = x.checked_sub(1) { | |
118 | base_n::push_str(x as u128, 62, &mut self.out); | |
119 | } | |
120 | self.push("_"); | |
121 | } | |
122 | ||
123 | /// Push a `tag`-prefixed base 62 integer, when larger than `0`, that is: | |
124 | /// * `x = 0` is encoded as `""` (nothing) | |
125 | /// * `x > 0` is encoded as the `tag` followed by `push_integer_62(x - 1)` | |
126 | /// e.g. `1` becomes `tag + "_"`, `2` becomes `tag + "0_"`, etc. | |
127 | fn push_opt_integer_62(&mut self, tag: &str, x: u64) { | |
128 | if let Some(x) = x.checked_sub(1) { | |
129 | self.push(tag); | |
130 | self.push_integer_62(x); | |
131 | } | |
132 | } | |
133 | ||
134 | fn push_disambiguator(&mut self, dis: u64) { | |
135 | self.push_opt_integer_62("s", dis); | |
136 | } | |
137 | ||
138 | fn push_ident(&mut self, ident: &str) { | |
139 | let mut use_punycode = false; | |
140 | for b in ident.bytes() { | |
141 | match b { | |
142 | b'_' | b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' => {} | |
143 | 0x80..=0xff => use_punycode = true, | |
144 | _ => bug!("symbol_names: bad byte {} in ident {:?}", b, ident), | |
145 | } | |
146 | } | |
147 | ||
148 | let punycode_string; | |
149 | let ident = if use_punycode { | |
150 | self.push("u"); | |
151 | ||
152 | // FIXME(eddyb) we should probably roll our own punycode implementation. | |
29967ef6 | 153 | let mut punycode_bytes = match punycode::encode(ident) { |
dc9dc135 XL |
154 | Ok(s) => s.into_bytes(), |
155 | Err(()) => bug!("symbol_names: punycode encoding failed for ident {:?}", ident), | |
156 | }; | |
157 | ||
158 | // Replace `-` with `_`. | |
159 | if let Some(c) = punycode_bytes.iter_mut().rfind(|&&mut c| c == b'-') { | |
160 | *c = b'_'; | |
161 | } | |
162 | ||
163 | // FIXME(eddyb) avoid rechecking UTF-8 validity. | |
164 | punycode_string = String::from_utf8(punycode_bytes).unwrap(); | |
165 | &punycode_string | |
166 | } else { | |
167 | ident | |
168 | }; | |
169 | ||
170 | let _ = write!(self.out, "{}", ident.len()); | |
171 | ||
172 | // Write a separating `_` if necessary (leading digit or `_`). | |
1b1a35ee XL |
173 | if let Some('_' | '0'..='9') = ident.chars().next() { |
174 | self.push("_"); | |
dc9dc135 XL |
175 | } |
176 | ||
177 | self.push(ident); | |
178 | } | |
179 | ||
94222f64 XL |
180 | fn path_append_ns<'a>( |
181 | mut self: &'a mut Self, | |
182 | print_prefix: impl FnOnce(&'a mut Self) -> Result<&'a mut Self, !>, | |
dc9dc135 XL |
183 | ns: char, |
184 | disambiguator: u64, | |
185 | name: &str, | |
94222f64 | 186 | ) -> Result<&'a mut Self, !> { |
dc9dc135 XL |
187 | self.push("N"); |
188 | self.out.push(ns); | |
189 | self = print_prefix(self)?; | |
190 | self.push_disambiguator(disambiguator as u64); | |
191 | self.push_ident(name); | |
192 | Ok(self) | |
193 | } | |
194 | ||
94222f64 | 195 | fn print_backref(&mut self, i: usize) -> Result<&mut Self, !> { |
dc9dc135 | 196 | self.push("B"); |
94222f64 | 197 | self.push_integer_62((i - self.start_offset) as u64); |
dc9dc135 XL |
198 | Ok(self) |
199 | } | |
200 | ||
94222f64 XL |
201 | fn in_binder<'a, T>( |
202 | mut self: &'a mut Self, | |
cdc7bbd5 | 203 | value: &ty::Binder<'tcx, T>, |
94222f64 XL |
204 | print_value: impl FnOnce(&'a mut Self, &T) -> Result<&'a mut Self, !>, |
205 | ) -> Result<&'a mut Self, !> | |
dfeec247 | 206 | where |
064997fb | 207 | T: TypeVisitable<'tcx>, |
dc9dc135 XL |
208 | { |
209 | let regions = if value.has_late_bound_regions() { | |
210 | self.tcx.collect_referenced_late_bound_regions(value) | |
211 | } else { | |
212 | FxHashSet::default() | |
213 | }; | |
214 | ||
215 | let mut lifetime_depths = | |
216 | self.binders.last().map(|b| b.lifetime_depths.end).map_or(0..0, |i| i..i); | |
217 | ||
dfeec247 XL |
218 | let lifetimes = regions |
219 | .into_iter() | |
29967ef6 | 220 | .map(|br| match br { |
487cf647 | 221 | ty::BrAnon(i, _) => i, |
29967ef6 | 222 | _ => bug!("symbol_names: non-anonymized region `{:?}` in `{:?}`", br, value), |
dfeec247 XL |
223 | }) |
224 | .max() | |
225 | .map_or(0, |max| max + 1); | |
dc9dc135 XL |
226 | |
227 | self.push_opt_integer_62("G", lifetimes as u64); | |
228 | lifetime_depths.end += lifetimes; | |
229 | ||
230 | self.binders.push(BinderLevel { lifetime_depths }); | |
f035d41b | 231 | self = print_value(self, value.as_ref().skip_binder())?; |
dc9dc135 XL |
232 | self.binders.pop(); |
233 | ||
234 | Ok(self) | |
235 | } | |
236 | } | |
237 | ||
a2a8927a | 238 | impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { |
dc9dc135 XL |
239 | type Error = !; |
240 | ||
241 | type Path = Self; | |
242 | type Region = Self; | |
243 | type Type = Self; | |
244 | type DynExistential = Self; | |
245 | type Const = Self; | |
246 | ||
247 | fn tcx(&self) -> TyCtxt<'tcx> { | |
248 | self.tcx | |
249 | } | |
250 | ||
251 | fn print_def_path( | |
252 | mut self, | |
253 | def_id: DefId, | |
e74abb32 | 254 | substs: &'tcx [GenericArg<'tcx>], |
dc9dc135 | 255 | ) -> Result<Self::Path, Self::Error> { |
94222f64 | 256 | if let Some(&i) = self.paths.get(&(def_id, substs)) { |
dc9dc135 XL |
257 | return self.print_backref(i); |
258 | } | |
259 | let start = self.out.len(); | |
260 | ||
261 | self = self.default_print_def_path(def_id, substs)?; | |
262 | ||
263 | // Only cache paths that do not refer to an enclosing | |
264 | // binder (which would change depending on context). | |
265 | if !substs.iter().any(|k| k.has_escaping_bound_vars()) { | |
94222f64 | 266 | self.paths.insert((def_id, substs), start); |
dc9dc135 XL |
267 | } |
268 | Ok(self) | |
269 | } | |
270 | ||
271 | fn print_impl_path( | |
29967ef6 | 272 | mut self, |
dc9dc135 | 273 | impl_def_id: DefId, |
e74abb32 | 274 | substs: &'tcx [GenericArg<'tcx>], |
dc9dc135 XL |
275 | mut self_ty: Ty<'tcx>, |
276 | mut impl_trait_ref: Option<ty::TraitRef<'tcx>>, | |
277 | ) -> Result<Self::Path, Self::Error> { | |
278 | let key = self.tcx.def_key(impl_def_id); | |
279 | let parent_def_id = DefId { index: key.parent.unwrap(), ..impl_def_id }; | |
280 | ||
3dfed10e | 281 | let mut param_env = self.tcx.param_env_reveal_all_normalized(impl_def_id); |
dc9dc135 | 282 | if !substs.is_empty() { |
04454e1e | 283 | param_env = EarlyBinder(param_env).subst(self.tcx, substs); |
dc9dc135 XL |
284 | } |
285 | ||
286 | match &mut impl_trait_ref { | |
287 | Some(impl_trait_ref) => { | |
288 | assert_eq!(impl_trait_ref.self_ty(), self_ty); | |
dfeec247 | 289 | *impl_trait_ref = self.tcx.normalize_erasing_regions(param_env, *impl_trait_ref); |
dc9dc135 XL |
290 | self_ty = impl_trait_ref.self_ty(); |
291 | } | |
292 | None => { | |
293 | self_ty = self.tcx.normalize_erasing_regions(param_env, self_ty); | |
294 | } | |
295 | } | |
296 | ||
29967ef6 XL |
297 | self.push(match impl_trait_ref { |
298 | Some(_) => "X", | |
299 | None => "M", | |
300 | }); | |
301 | ||
302 | // Encode impl generic params if the substitutions contain parameters (implying | |
303 | // polymorphization is enabled) and this isn't an inherent impl. | |
2b03887a | 304 | if impl_trait_ref.is_some() && substs.iter().any(|a| a.has_non_region_param()) { |
29967ef6 XL |
305 | self = self.path_generic_args( |
306 | |this| { | |
307 | this.path_append_ns( | |
308 | |cx| cx.print_def_path(parent_def_id, &[]), | |
309 | 'I', | |
310 | key.disambiguated_data.disambiguator as u64, | |
311 | "", | |
312 | ) | |
313 | }, | |
314 | substs, | |
315 | )?; | |
316 | } else { | |
317 | self.push_disambiguator(key.disambiguated_data.disambiguator as u64); | |
318 | self = self.print_def_path(parent_def_id, &[])?; | |
319 | } | |
320 | ||
321 | self = self_ty.print(self)?; | |
322 | ||
323 | if let Some(trait_ref) = impl_trait_ref { | |
324 | self = self.print_def_path(trait_ref.def_id, trait_ref.substs)?; | |
325 | } | |
326 | ||
327 | Ok(self) | |
dc9dc135 XL |
328 | } |
329 | ||
94222f64 | 330 | fn print_region(self, region: ty::Region<'_>) -> Result<Self::Region, Self::Error> { |
dc9dc135 XL |
331 | let i = match *region { |
332 | // Erased lifetimes use the index 0, for a | |
333 | // shorter mangling of `L_`. | |
334 | ty::ReErased => 0, | |
335 | ||
336 | // Late-bound lifetimes use indices starting at 1, | |
337 | // see `BinderLevel` for more details. | |
487cf647 | 338 | ty::ReLateBound(debruijn, ty::BoundRegion { kind: ty::BrAnon(i, _), .. }) => { |
dc9dc135 XL |
339 | let binder = &self.binders[self.binders.len() - 1 - debruijn.index()]; |
340 | let depth = binder.lifetime_depths.start + i; | |
341 | ||
342 | 1 + (self.binders.last().unwrap().lifetime_depths.end - 1 - depth) | |
343 | } | |
344 | ||
345 | _ => bug!("symbol_names: non-erased region `{:?}`", region), | |
346 | }; | |
347 | self.push("L"); | |
348 | self.push_integer_62(i as u64); | |
349 | Ok(self) | |
350 | } | |
351 | ||
dfeec247 | 352 | fn print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> { |
dc9dc135 | 353 | // Basic types, never cached (single-character). |
1b1a35ee | 354 | let basic_type = match ty.kind() { |
dc9dc135 XL |
355 | ty::Bool => "b", |
356 | ty::Char => "c", | |
357 | ty::Str => "e", | |
358 | ty::Tuple(_) if ty.is_unit() => "u", | |
359 | ty::Int(IntTy::I8) => "a", | |
360 | ty::Int(IntTy::I16) => "s", | |
361 | ty::Int(IntTy::I32) => "l", | |
362 | ty::Int(IntTy::I64) => "x", | |
363 | ty::Int(IntTy::I128) => "n", | |
364 | ty::Int(IntTy::Isize) => "i", | |
365 | ty::Uint(UintTy::U8) => "h", | |
366 | ty::Uint(UintTy::U16) => "t", | |
367 | ty::Uint(UintTy::U32) => "m", | |
368 | ty::Uint(UintTy::U64) => "y", | |
369 | ty::Uint(UintTy::U128) => "o", | |
370 | ty::Uint(UintTy::Usize) => "j", | |
371 | ty::Float(FloatTy::F32) => "f", | |
372 | ty::Float(FloatTy::F64) => "d", | |
373 | ty::Never => "z", | |
374 | ||
375 | // Placeholders (should be demangled as `_`). | |
f035d41b | 376 | ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => "p", |
dc9dc135 XL |
377 | |
378 | _ => "", | |
379 | }; | |
380 | if !basic_type.is_empty() { | |
381 | self.push(basic_type); | |
382 | return Ok(self); | |
383 | } | |
384 | ||
94222f64 | 385 | if let Some(&i) = self.types.get(&ty) { |
dc9dc135 XL |
386 | return self.print_backref(i); |
387 | } | |
388 | let start = self.out.len(); | |
389 | ||
1b1a35ee | 390 | match *ty.kind() { |
dc9dc135 | 391 | // Basic types, handled above. |
dfeec247 XL |
392 | ty::Bool | ty::Char | ty::Str | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Never => { |
393 | unreachable!() | |
394 | } | |
dc9dc135 XL |
395 | ty::Tuple(_) if ty.is_unit() => unreachable!(), |
396 | ||
397 | // Placeholders, also handled as part of basic types. | |
f035d41b | 398 | ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => { |
dfeec247 XL |
399 | unreachable!() |
400 | } | |
dc9dc135 XL |
401 | |
402 | ty::Ref(r, ty, mutbl) => { | |
403 | self.push(match mutbl { | |
dfeec247 XL |
404 | hir::Mutability::Not => "R", |
405 | hir::Mutability::Mut => "Q", | |
dc9dc135 | 406 | }); |
5099ac24 | 407 | if !r.is_erased() { |
dc9dc135 XL |
408 | self = r.print(self)?; |
409 | } | |
410 | self = ty.print(self)?; | |
411 | } | |
412 | ||
413 | ty::RawPtr(mt) => { | |
414 | self.push(match mt.mutbl { | |
dfeec247 XL |
415 | hir::Mutability::Not => "P", |
416 | hir::Mutability::Mut => "O", | |
dc9dc135 XL |
417 | }); |
418 | self = mt.ty.print(self)?; | |
419 | } | |
420 | ||
421 | ty::Array(ty, len) => { | |
422 | self.push("A"); | |
423 | self = ty.print(self)?; | |
424 | self = self.print_const(len)?; | |
425 | } | |
426 | ty::Slice(ty) => { | |
427 | self.push("S"); | |
428 | self = ty.print(self)?; | |
429 | } | |
430 | ||
431 | ty::Tuple(tys) => { | |
432 | self.push("T"); | |
5e7ed085 | 433 | for ty in tys.iter() { |
dc9dc135 XL |
434 | self = ty.print(self)?; |
435 | } | |
436 | self.push("E"); | |
437 | } | |
438 | ||
439 | // Mangle all nominal types as paths. | |
5e7ed085 | 440 | ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), substs) |
dfeec247 XL |
441 | | ty::FnDef(def_id, substs) |
442 | | ty::Opaque(def_id, substs) | |
443 | | ty::Projection(ty::ProjectionTy { item_def_id: def_id, substs }) | |
dfeec247 XL |
444 | | ty::Closure(def_id, substs) |
445 | | ty::Generator(def_id, substs, _) => { | |
dc9dc135 XL |
446 | self = self.print_def_path(def_id, substs)?; |
447 | } | |
448 | ty::Foreign(def_id) => { | |
449 | self = self.print_def_path(def_id, &[])?; | |
450 | } | |
451 | ||
452 | ty::FnPtr(sig) => { | |
453 | self.push("F"); | |
454 | self = self.in_binder(&sig, |mut cx, sig| { | |
455 | if sig.unsafety == hir::Unsafety::Unsafe { | |
456 | cx.push("U"); | |
457 | } | |
458 | match sig.abi { | |
459 | Abi::Rust => {} | |
6a06907d | 460 | Abi::C { unwind: false } => cx.push("KC"), |
dc9dc135 XL |
461 | abi => { |
462 | cx.push("K"); | |
463 | let name = abi.name(); | |
464 | if name.contains('-') { | |
465 | cx.push_ident(&name.replace('-', "_")); | |
466 | } else { | |
467 | cx.push_ident(name); | |
468 | } | |
469 | } | |
470 | } | |
471 | for &ty in sig.inputs() { | |
472 | cx = ty.print(cx)?; | |
473 | } | |
474 | if sig.c_variadic { | |
475 | cx.push("v"); | |
476 | } | |
477 | cx.push("E"); | |
478 | sig.output().print(cx) | |
479 | })?; | |
480 | } | |
481 | ||
f2b60f7d FG |
482 | ty::Dynamic(predicates, r, kind) => { |
483 | self.push(match kind { | |
484 | ty::Dyn => "D", | |
485 | // FIXME(dyn-star): need to update v0 mangling docs | |
486 | ty::DynStar => "D*", | |
487 | }); | |
fc512014 | 488 | self = self.print_dyn_existential(predicates)?; |
dc9dc135 XL |
489 | self = r.print(self)?; |
490 | } | |
491 | ||
dfeec247 | 492 | ty::GeneratorWitness(_) => bug!("symbol_names: unexpected `GeneratorWitness`"), |
dc9dc135 XL |
493 | } |
494 | ||
495 | // Only cache types that do not refer to an enclosing | |
496 | // binder (which would change depending on context). | |
497 | if !ty.has_escaping_bound_vars() { | |
94222f64 | 498 | self.types.insert(ty, start); |
dc9dc135 XL |
499 | } |
500 | Ok(self) | |
501 | } | |
502 | ||
503 | fn print_dyn_existential( | |
504 | mut self, | |
487cf647 | 505 | predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, |
dc9dc135 | 506 | ) -> Result<Self::DynExistential, Self::Error> { |
17df50a5 XL |
507 | // Okay, so this is a bit tricky. Imagine we have a trait object like |
508 | // `dyn for<'a> Foo<'a, Bar = &'a ()>`. When we mangle this, the | |
509 | // output looks really close to the syntax, where the `Bar = &'a ()` bit | |
510 | // is under the same binders (`['a]`) as the `Foo<'a>` bit. However, we | |
511 | // actually desugar these into two separate `ExistentialPredicate`s. We | |
512 | // can't enter/exit the "binder scope" twice though, because then we | |
513 | // would mangle the binders twice. (Also, side note, we merging these | |
514 | // two is kind of difficult, because of potential HRTBs in the Projection | |
515 | // predicate.) | |
516 | // | |
517 | // Also worth mentioning: imagine that we instead had | |
518 | // `dyn for<'a> Foo<'a, Bar = &'a ()> + Send`. In this case, `Send` is | |
519 | // under the same binders as `Foo`. Currently, this doesn't matter, | |
520 | // because only *auto traits* are allowed other than the principal trait | |
521 | // and all auto traits don't have any generics. Two things could | |
522 | // make this not an "okay" mangling: | |
523 | // 1) Instead of mangling only *used* | |
524 | // bound vars, we want to mangle *all* bound vars (`for<'b> Send` is a | |
525 | // valid trait predicate); | |
526 | // 2) We allow multiple "principal" traits in the future, or at least | |
527 | // allow in any form another trait predicate that can take generics. | |
528 | // | |
529 | // Here we assume that predicates have the following structure: | |
530 | // [<Trait> [{<Projection>}]] [{<Auto>}] | |
531 | // Since any predicates after the first one shouldn't change the binders, | |
532 | // just put them all in the binders of the first. | |
533 | self = self.in_binder(&predicates[0], |mut cx, _| { | |
534 | for predicate in predicates.iter() { | |
535 | // It would be nice to be able to validate bound vars here, but | |
536 | // projections can actually include bound vars from super traits | |
537 | // because of HRTBs (only in the `Self` type). Also, auto traits | |
538 | // could have different bound vars *anyways*. | |
539 | match predicate.as_ref().skip_binder() { | |
fc512014 XL |
540 | ty::ExistentialPredicate::Trait(trait_ref) => { |
541 | // Use a type that can't appear in defaults of type parameters. | |
542 | let dummy_self = cx.tcx.mk_ty_infer(ty::FreshTy(0)); | |
543 | let trait_ref = trait_ref.with_self_ty(cx.tcx, dummy_self); | |
544 | cx = cx.print_def_path(trait_ref.def_id, trait_ref.substs)?; | |
545 | } | |
546 | ty::ExistentialPredicate::Projection(projection) => { | |
5099ac24 | 547 | let name = cx.tcx.associated_item(projection.item_def_id).name; |
fc512014 | 548 | cx.push("p"); |
a2a8927a | 549 | cx.push_ident(name.as_str()); |
f2b60f7d FG |
550 | cx = match projection.term.unpack() { |
551 | ty::TermKind::Ty(ty) => ty.print(cx), | |
552 | ty::TermKind::Const(c) => c.print(cx), | |
5099ac24 | 553 | }?; |
fc512014 XL |
554 | } |
555 | ty::ExistentialPredicate::AutoTrait(def_id) => { | |
556 | cx = cx.print_def_path(*def_id, &[])?; | |
557 | } | |
dc9dc135 | 558 | } |
17df50a5 XL |
559 | } |
560 | Ok(cx) | |
561 | })?; | |
562 | ||
dc9dc135 XL |
563 | self.push("E"); |
564 | Ok(self) | |
565 | } | |
566 | ||
5099ac24 | 567 | fn print_const(mut self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> { |
94222f64 XL |
568 | // We only mangle a typed value if the const can be evaluated. |
569 | let ct = ct.eval(self.tcx, ty::ParamEnv::reveal_all()); | |
923072b8 | 570 | match ct.kind() { |
94222f64 XL |
571 | ty::ConstKind::Value(_) => {} |
572 | ||
573 | // Placeholders (should be demangled as `_`). | |
574 | // NOTE(eddyb) despite `Unevaluated` having a `DefId` (and therefore | |
575 | // a path), even for it we still need to encode a placeholder, as | |
576 | // the path could refer back to e.g. an `impl` using the constant. | |
577 | ty::ConstKind::Unevaluated(_) | |
487cf647 | 578 | | ty::ConstKind::Expr(_) |
94222f64 XL |
579 | | ty::ConstKind::Param(_) |
580 | | ty::ConstKind::Infer(_) | |
581 | | ty::ConstKind::Bound(..) | |
582 | | ty::ConstKind::Placeholder(_) | |
583 | | ty::ConstKind::Error(_) => { | |
584 | // Never cached (single-character). | |
585 | self.push("p"); | |
586 | return Ok(self); | |
587 | } | |
588 | } | |
589 | ||
590 | if let Some(&i) = self.consts.get(&ct) { | |
dc9dc135 XL |
591 | return self.print_backref(i); |
592 | } | |
923072b8 | 593 | |
dc9dc135 | 594 | let start = self.out.len(); |
923072b8 | 595 | let ty = ct.ty(); |
dc9dc135 | 596 | |
923072b8 | 597 | match ty.kind() { |
94222f64 | 598 | ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Char => { |
923072b8 | 599 | self = ty.print(self)?; |
94222f64 | 600 | |
923072b8 | 601 | let mut bits = ct.eval_bits(self.tcx, ty::ParamEnv::reveal_all(), ty); |
94222f64 XL |
602 | |
603 | // Negative integer values are mangled using `n` as a "sign prefix". | |
923072b8 | 604 | if let ty::Int(ity) = ty.kind() { |
94222f64 XL |
605 | let val = |
606 | Integer::from_int_ty(&self.tcx, *ity).size().sign_extend(bits) as i128; | |
29967ef6 | 607 | if val < 0 { |
94222f64 | 608 | self.push("n"); |
29967ef6 | 609 | } |
94222f64 XL |
610 | bits = val.unsigned_abs(); |
611 | } | |
612 | ||
613 | let _ = write!(self.out, "{:x}_", bits); | |
29967ef6 | 614 | } |
94222f64 | 615 | |
923072b8 FG |
616 | // FIXME(valtrees): Remove the special case for `str` |
617 | // here and fully support unsized constants. | |
618 | ty::Ref(_, inner_ty, mutbl) => { | |
619 | self.push(match mutbl { | |
620 | hir::Mutability::Not => "R", | |
621 | hir::Mutability::Mut => "Q", | |
622 | }); | |
623 | ||
624 | match inner_ty.kind() { | |
487cf647 | 625 | ty::Str if mutbl.is_not() => { |
923072b8 FG |
626 | match ct.kind() { |
627 | ty::ConstKind::Value(valtree) => { | |
628 | let slice = | |
629 | valtree.try_to_raw_bytes(self.tcx(), ty).unwrap_or_else(|| { | |
630 | bug!( | |
631 | "expected to get raw bytes from valtree {:?} for type {:}", | |
632 | valtree, ty | |
633 | ) | |
634 | }); | |
635 | let s = std::str::from_utf8(slice).expect("non utf8 str from miri"); | |
636 | ||
637 | self.push("e"); | |
638 | ||
639 | // FIXME(eddyb) use a specialized hex-encoding loop. | |
640 | for byte in s.bytes() { | |
641 | let _ = write!(self.out, "{:02x}", byte); | |
642 | } | |
643 | ||
644 | self.push("_"); | |
645 | } | |
646 | ||
647 | _ => { | |
648 | bug!("symbol_names: unsupported `&str` constant: {:?}", ct); | |
649 | } | |
94222f64 | 650 | } |
94222f64 | 651 | } |
94222f64 | 652 | _ => { |
923072b8 FG |
653 | let pointee_ty = ct |
654 | .ty() | |
655 | .builtin_deref(true) | |
656 | .expect("tried to dereference on non-ptr type") | |
657 | .ty; | |
487cf647 | 658 | let dereferenced_const = self.tcx.mk_const(ct.kind(), pointee_ty); |
923072b8 | 659 | self = dereferenced_const.print(self)?; |
94222f64 XL |
660 | } |
661 | } | |
662 | } | |
663 | ||
923072b8 FG |
664 | ty::Array(..) | ty::Tuple(..) | ty::Adt(..) | ty::Slice(_) => { |
665 | let contents = self.tcx.destructure_const(ct); | |
94222f64 XL |
666 | let fields = contents.fields.iter().copied(); |
667 | ||
668 | let print_field_list = |mut this: Self| { | |
669 | for field in fields.clone() { | |
670 | this = field.print(this)?; | |
671 | } | |
672 | this.push("E"); | |
673 | Ok(this) | |
674 | }; | |
675 | ||
5099ac24 | 676 | match *ct.ty().kind() { |
923072b8 | 677 | ty::Array(..) | ty::Slice(_) => { |
94222f64 XL |
678 | self.push("A"); |
679 | self = print_field_list(self)?; | |
680 | } | |
681 | ty::Tuple(..) => { | |
682 | self.push("T"); | |
683 | self = print_field_list(self)?; | |
684 | } | |
685 | ty::Adt(def, substs) => { | |
686 | let variant_idx = | |
687 | contents.variant.expect("destructed const of adt without variant idx"); | |
5e7ed085 | 688 | let variant_def = &def.variant(variant_idx); |
94222f64 XL |
689 | |
690 | self.push("V"); | |
691 | self = self.print_def_path(variant_def.def_id, substs)?; | |
692 | ||
487cf647 FG |
693 | match variant_def.ctor_kind() { |
694 | Some(CtorKind::Const) => { | |
94222f64 XL |
695 | self.push("U"); |
696 | } | |
487cf647 | 697 | Some(CtorKind::Fn) => { |
94222f64 XL |
698 | self.push("T"); |
699 | self = print_field_list(self)?; | |
700 | } | |
487cf647 | 701 | None => { |
94222f64 XL |
702 | self.push("S"); |
703 | for (field_def, field) in iter::zip(&variant_def.fields, fields) { | |
704 | // HACK(eddyb) this mimics `path_append`, | |
705 | // instead of simply using `field_def.ident`, | |
706 | // just to be able to handle disambiguators. | |
707 | let disambiguated_field = | |
708 | self.tcx.def_key(field_def.did).disambiguated_data; | |
a2a8927a | 709 | let field_name = disambiguated_field.data.get_opt_name(); |
94222f64 XL |
710 | self.push_disambiguator( |
711 | disambiguated_field.disambiguator as u64, | |
712 | ); | |
a2a8927a | 713 | self.push_ident(field_name.unwrap_or(kw::Empty).as_str()); |
94222f64 XL |
714 | |
715 | self = field.print(self)?; | |
716 | } | |
717 | self.push("E"); | |
718 | } | |
719 | } | |
720 | } | |
721 | _ => unreachable!(), | |
722 | } | |
723 | } | |
dc9dc135 | 724 | _ => { |
5099ac24 | 725 | bug!("symbol_names: unsupported constant of type `{}` ({:?})", ct.ty(), ct); |
dc9dc135 | 726 | } |
dc9dc135 XL |
727 | } |
728 | ||
729 | // Only cache consts that do not refer to an enclosing | |
730 | // binder (which would change depending on context). | |
731 | if !ct.has_escaping_bound_vars() { | |
94222f64 | 732 | self.consts.insert(ct, start); |
dc9dc135 XL |
733 | } |
734 | Ok(self) | |
735 | } | |
736 | ||
94222f64 | 737 | fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> { |
dc9dc135 | 738 | self.push("C"); |
136023e0 XL |
739 | let stable_crate_id = self.tcx.def_path_hash(cnum.as_def_id()).stable_crate_id(); |
740 | self.push_disambiguator(stable_crate_id.to_u64()); | |
a2a8927a XL |
741 | let name = self.tcx.crate_name(cnum); |
742 | self.push_ident(name.as_str()); | |
dc9dc135 XL |
743 | Ok(self) |
744 | } | |
29967ef6 | 745 | |
dc9dc135 XL |
746 | fn path_qualified( |
747 | mut self, | |
748 | self_ty: Ty<'tcx>, | |
749 | trait_ref: Option<ty::TraitRef<'tcx>>, | |
750 | ) -> Result<Self::Path, Self::Error> { | |
751 | assert!(trait_ref.is_some()); | |
752 | let trait_ref = trait_ref.unwrap(); | |
753 | ||
754 | self.push("Y"); | |
755 | self = self_ty.print(self)?; | |
756 | self.print_def_path(trait_ref.def_id, trait_ref.substs) | |
757 | } | |
758 | ||
759 | fn path_append_impl( | |
29967ef6 XL |
760 | self, |
761 | _: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, | |
762 | _: &DisambiguatedDefPathData, | |
763 | _: Ty<'tcx>, | |
764 | _: Option<ty::TraitRef<'tcx>>, | |
dc9dc135 | 765 | ) -> Result<Self::Path, Self::Error> { |
29967ef6 XL |
766 | // Inlined into `print_impl_path` |
767 | unreachable!() | |
dc9dc135 | 768 | } |
29967ef6 | 769 | |
dc9dc135 XL |
770 | fn path_append( |
771 | self, | |
772 | print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, | |
773 | disambiguated_data: &DisambiguatedDefPathData, | |
774 | ) -> Result<Self::Path, Self::Error> { | |
775 | let ns = match disambiguated_data.data { | |
5099ac24 FG |
776 | // Extern block segments can be skipped, names from extern blocks |
777 | // are effectively living in their parent modules. | |
778 | DefPathData::ForeignMod => return print_prefix(self), | |
a2a8927a | 779 | |
dc9dc135 XL |
780 | // Uppercase categories are more stable than lowercase ones. |
781 | DefPathData::TypeNs(_) => 't', | |
782 | DefPathData::ValueNs(_) => 'v', | |
783 | DefPathData::ClosureExpr => 'C', | |
784 | DefPathData::Ctor => 'c', | |
785 | DefPathData::AnonConst => 'k', | |
786 | DefPathData::ImplTrait => 'i', | |
787 | ||
788 | // These should never show up as `path_append` arguments. | |
789 | DefPathData::CrateRoot | |
04454e1e FG |
790 | | DefPathData::Use |
791 | | DefPathData::GlobalAsm | |
dc9dc135 XL |
792 | | DefPathData::Impl |
793 | | DefPathData::MacroNs(_) | |
60c5eb7d | 794 | | DefPathData::LifetimeNs(_) => { |
dc9dc135 XL |
795 | bug!("symbol_names: unexpected DefPathData: {:?}", disambiguated_data.data) |
796 | } | |
797 | }; | |
798 | ||
a2a8927a | 799 | let name = disambiguated_data.data.get_opt_name(); |
dc9dc135 XL |
800 | |
801 | self.path_append_ns( | |
802 | print_prefix, | |
803 | ns, | |
804 | disambiguated_data.disambiguator as u64, | |
a2a8927a | 805 | name.unwrap_or(kw::Empty).as_str(), |
dc9dc135 XL |
806 | ) |
807 | } | |
29967ef6 | 808 | |
dc9dc135 XL |
809 | fn path_generic_args( |
810 | mut self, | |
811 | print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, | |
e74abb32 | 812 | args: &[GenericArg<'tcx>], |
dc9dc135 XL |
813 | ) -> Result<Self::Path, Self::Error> { |
814 | // Don't print any regions if they're all erased. | |
dfeec247 | 815 | let print_regions = args.iter().any(|arg| match arg.unpack() { |
5099ac24 | 816 | GenericArgKind::Lifetime(r) => !r.is_erased(), |
dfeec247 | 817 | _ => false, |
dc9dc135 | 818 | }); |
dfeec247 XL |
819 | let args = args.iter().cloned().filter(|arg| match arg.unpack() { |
820 | GenericArgKind::Lifetime(_) => print_regions, | |
821 | _ => true, | |
dc9dc135 XL |
822 | }); |
823 | ||
824 | if args.clone().next().is_none() { | |
825 | return print_prefix(self); | |
826 | } | |
827 | ||
828 | self.push("I"); | |
829 | self = print_prefix(self)?; | |
830 | for arg in args { | |
831 | match arg.unpack() { | |
e74abb32 | 832 | GenericArgKind::Lifetime(lt) => { |
dc9dc135 XL |
833 | self = lt.print(self)?; |
834 | } | |
e74abb32 | 835 | GenericArgKind::Type(ty) => { |
dc9dc135 XL |
836 | self = ty.print(self)?; |
837 | } | |
e74abb32 | 838 | GenericArgKind::Const(c) => { |
dc9dc135 | 839 | self.push("K"); |
3dfed10e | 840 | self = c.print(self)?; |
dc9dc135 XL |
841 | } |
842 | } | |
843 | } | |
844 | self.push("E"); | |
845 | ||
846 | Ok(self) | |
847 | } | |
848 | } |