]>
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 XL |
9 | use rustc_middle::ty::print::{Print, Printer}; |
10 | use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst}; | |
04454e1e | 11 | use rustc_middle::ty::{ |
064997fb | 12 | self, EarlyBinder, FloatTy, Instance, IntTy, Ty, TyCtxt, TypeVisitable, UintTy, |
04454e1e | 13 | }; |
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 XL |
220 | .map(|br| match br { |
221 | ty::BrAnon(i) => i, | |
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. | |
5099ac24 | 304 | if impl_trait_ref.is_some() && substs.iter().any(|a| a.has_param_types_or_consts()) { |
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. | |
cdc7bbd5 | 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 | ||
482 | ty::Dynamic(predicates, r) => { | |
483 | self.push("D"); | |
fc512014 | 484 | self = self.print_dyn_existential(predicates)?; |
dc9dc135 XL |
485 | self = r.print(self)?; |
486 | } | |
487 | ||
dfeec247 | 488 | ty::GeneratorWitness(_) => bug!("symbol_names: unexpected `GeneratorWitness`"), |
dc9dc135 XL |
489 | } |
490 | ||
491 | // Only cache types that do not refer to an enclosing | |
492 | // binder (which would change depending on context). | |
493 | if !ty.has_escaping_bound_vars() { | |
94222f64 | 494 | self.types.insert(ty, start); |
dc9dc135 XL |
495 | } |
496 | Ok(self) | |
497 | } | |
498 | ||
499 | fn print_dyn_existential( | |
500 | mut self, | |
cdc7bbd5 | 501 | predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>, |
dc9dc135 | 502 | ) -> Result<Self::DynExistential, Self::Error> { |
17df50a5 XL |
503 | // Okay, so this is a bit tricky. Imagine we have a trait object like |
504 | // `dyn for<'a> Foo<'a, Bar = &'a ()>`. When we mangle this, the | |
505 | // output looks really close to the syntax, where the `Bar = &'a ()` bit | |
506 | // is under the same binders (`['a]`) as the `Foo<'a>` bit. However, we | |
507 | // actually desugar these into two separate `ExistentialPredicate`s. We | |
508 | // can't enter/exit the "binder scope" twice though, because then we | |
509 | // would mangle the binders twice. (Also, side note, we merging these | |
510 | // two is kind of difficult, because of potential HRTBs in the Projection | |
511 | // predicate.) | |
512 | // | |
513 | // Also worth mentioning: imagine that we instead had | |
514 | // `dyn for<'a> Foo<'a, Bar = &'a ()> + Send`. In this case, `Send` is | |
515 | // under the same binders as `Foo`. Currently, this doesn't matter, | |
516 | // because only *auto traits* are allowed other than the principal trait | |
517 | // and all auto traits don't have any generics. Two things could | |
518 | // make this not an "okay" mangling: | |
519 | // 1) Instead of mangling only *used* | |
520 | // bound vars, we want to mangle *all* bound vars (`for<'b> Send` is a | |
521 | // valid trait predicate); | |
522 | // 2) We allow multiple "principal" traits in the future, or at least | |
523 | // allow in any form another trait predicate that can take generics. | |
524 | // | |
525 | // Here we assume that predicates have the following structure: | |
526 | // [<Trait> [{<Projection>}]] [{<Auto>}] | |
527 | // Since any predicates after the first one shouldn't change the binders, | |
528 | // just put them all in the binders of the first. | |
529 | self = self.in_binder(&predicates[0], |mut cx, _| { | |
530 | for predicate in predicates.iter() { | |
531 | // It would be nice to be able to validate bound vars here, but | |
532 | // projections can actually include bound vars from super traits | |
533 | // because of HRTBs (only in the `Self` type). Also, auto traits | |
534 | // could have different bound vars *anyways*. | |
535 | match predicate.as_ref().skip_binder() { | |
fc512014 XL |
536 | ty::ExistentialPredicate::Trait(trait_ref) => { |
537 | // Use a type that can't appear in defaults of type parameters. | |
538 | let dummy_self = cx.tcx.mk_ty_infer(ty::FreshTy(0)); | |
539 | let trait_ref = trait_ref.with_self_ty(cx.tcx, dummy_self); | |
540 | cx = cx.print_def_path(trait_ref.def_id, trait_ref.substs)?; | |
541 | } | |
542 | ty::ExistentialPredicate::Projection(projection) => { | |
5099ac24 | 543 | let name = cx.tcx.associated_item(projection.item_def_id).name; |
fc512014 | 544 | cx.push("p"); |
a2a8927a | 545 | cx.push_ident(name.as_str()); |
5099ac24 FG |
546 | cx = match projection.term { |
547 | ty::Term::Ty(ty) => ty.print(cx), | |
548 | ty::Term::Const(c) => c.print(cx), | |
549 | }?; | |
fc512014 XL |
550 | } |
551 | ty::ExistentialPredicate::AutoTrait(def_id) => { | |
552 | cx = cx.print_def_path(*def_id, &[])?; | |
553 | } | |
dc9dc135 | 554 | } |
17df50a5 XL |
555 | } |
556 | Ok(cx) | |
557 | })?; | |
558 | ||
dc9dc135 XL |
559 | self.push("E"); |
560 | Ok(self) | |
561 | } | |
562 | ||
5099ac24 | 563 | fn print_const(mut self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> { |
94222f64 XL |
564 | // We only mangle a typed value if the const can be evaluated. |
565 | let ct = ct.eval(self.tcx, ty::ParamEnv::reveal_all()); | |
923072b8 | 566 | match ct.kind() { |
94222f64 XL |
567 | ty::ConstKind::Value(_) => {} |
568 | ||
569 | // Placeholders (should be demangled as `_`). | |
570 | // NOTE(eddyb) despite `Unevaluated` having a `DefId` (and therefore | |
571 | // a path), even for it we still need to encode a placeholder, as | |
572 | // the path could refer back to e.g. an `impl` using the constant. | |
573 | ty::ConstKind::Unevaluated(_) | |
574 | | ty::ConstKind::Param(_) | |
575 | | ty::ConstKind::Infer(_) | |
576 | | ty::ConstKind::Bound(..) | |
577 | | ty::ConstKind::Placeholder(_) | |
578 | | ty::ConstKind::Error(_) => { | |
579 | // Never cached (single-character). | |
580 | self.push("p"); | |
581 | return Ok(self); | |
582 | } | |
583 | } | |
584 | ||
585 | if let Some(&i) = self.consts.get(&ct) { | |
dc9dc135 XL |
586 | return self.print_backref(i); |
587 | } | |
923072b8 | 588 | |
dc9dc135 | 589 | let start = self.out.len(); |
923072b8 | 590 | let ty = ct.ty(); |
dc9dc135 | 591 | |
923072b8 | 592 | match ty.kind() { |
94222f64 | 593 | ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Char => { |
923072b8 | 594 | self = ty.print(self)?; |
94222f64 | 595 | |
923072b8 | 596 | let mut bits = ct.eval_bits(self.tcx, ty::ParamEnv::reveal_all(), ty); |
94222f64 XL |
597 | |
598 | // Negative integer values are mangled using `n` as a "sign prefix". | |
923072b8 | 599 | if let ty::Int(ity) = ty.kind() { |
94222f64 XL |
600 | let val = |
601 | Integer::from_int_ty(&self.tcx, *ity).size().sign_extend(bits) as i128; | |
29967ef6 | 602 | if val < 0 { |
94222f64 | 603 | self.push("n"); |
29967ef6 | 604 | } |
94222f64 XL |
605 | bits = val.unsigned_abs(); |
606 | } | |
607 | ||
608 | let _ = write!(self.out, "{:x}_", bits); | |
29967ef6 | 609 | } |
94222f64 | 610 | |
923072b8 FG |
611 | // FIXME(valtrees): Remove the special case for `str` |
612 | // here and fully support unsized constants. | |
613 | ty::Ref(_, inner_ty, mutbl) => { | |
614 | self.push(match mutbl { | |
615 | hir::Mutability::Not => "R", | |
616 | hir::Mutability::Mut => "Q", | |
617 | }); | |
618 | ||
619 | match inner_ty.kind() { | |
620 | ty::Str if *mutbl == hir::Mutability::Not => { | |
621 | match ct.kind() { | |
622 | ty::ConstKind::Value(valtree) => { | |
623 | let slice = | |
624 | valtree.try_to_raw_bytes(self.tcx(), ty).unwrap_or_else(|| { | |
625 | bug!( | |
626 | "expected to get raw bytes from valtree {:?} for type {:}", | |
627 | valtree, ty | |
628 | ) | |
629 | }); | |
630 | let s = std::str::from_utf8(slice).expect("non utf8 str from miri"); | |
631 | ||
632 | self.push("e"); | |
633 | ||
634 | // FIXME(eddyb) use a specialized hex-encoding loop. | |
635 | for byte in s.bytes() { | |
636 | let _ = write!(self.out, "{:02x}", byte); | |
637 | } | |
638 | ||
639 | self.push("_"); | |
640 | } | |
641 | ||
642 | _ => { | |
643 | bug!("symbol_names: unsupported `&str` constant: {:?}", ct); | |
644 | } | |
94222f64 | 645 | } |
94222f64 | 646 | } |
94222f64 | 647 | _ => { |
923072b8 FG |
648 | let pointee_ty = ct |
649 | .ty() | |
650 | .builtin_deref(true) | |
651 | .expect("tried to dereference on non-ptr type") | |
652 | .ty; | |
653 | let dereferenced_const = | |
654 | self.tcx.mk_const(ty::ConstS { kind: ct.kind(), ty: pointee_ty }); | |
655 | self = dereferenced_const.print(self)?; | |
94222f64 XL |
656 | } |
657 | } | |
658 | } | |
659 | ||
923072b8 FG |
660 | ty::Array(..) | ty::Tuple(..) | ty::Adt(..) | ty::Slice(_) => { |
661 | let contents = self.tcx.destructure_const(ct); | |
94222f64 XL |
662 | let fields = contents.fields.iter().copied(); |
663 | ||
664 | let print_field_list = |mut this: Self| { | |
665 | for field in fields.clone() { | |
666 | this = field.print(this)?; | |
667 | } | |
668 | this.push("E"); | |
669 | Ok(this) | |
670 | }; | |
671 | ||
5099ac24 | 672 | match *ct.ty().kind() { |
923072b8 | 673 | ty::Array(..) | ty::Slice(_) => { |
94222f64 XL |
674 | self.push("A"); |
675 | self = print_field_list(self)?; | |
676 | } | |
677 | ty::Tuple(..) => { | |
678 | self.push("T"); | |
679 | self = print_field_list(self)?; | |
680 | } | |
681 | ty::Adt(def, substs) => { | |
682 | let variant_idx = | |
683 | contents.variant.expect("destructed const of adt without variant idx"); | |
5e7ed085 | 684 | let variant_def = &def.variant(variant_idx); |
94222f64 XL |
685 | |
686 | self.push("V"); | |
687 | self = self.print_def_path(variant_def.def_id, substs)?; | |
688 | ||
689 | match variant_def.ctor_kind { | |
690 | CtorKind::Const => { | |
691 | self.push("U"); | |
692 | } | |
693 | CtorKind::Fn => { | |
694 | self.push("T"); | |
695 | self = print_field_list(self)?; | |
696 | } | |
697 | CtorKind::Fictive => { | |
698 | self.push("S"); | |
699 | for (field_def, field) in iter::zip(&variant_def.fields, fields) { | |
700 | // HACK(eddyb) this mimics `path_append`, | |
701 | // instead of simply using `field_def.ident`, | |
702 | // just to be able to handle disambiguators. | |
703 | let disambiguated_field = | |
704 | self.tcx.def_key(field_def.did).disambiguated_data; | |
a2a8927a | 705 | let field_name = disambiguated_field.data.get_opt_name(); |
94222f64 XL |
706 | self.push_disambiguator( |
707 | disambiguated_field.disambiguator as u64, | |
708 | ); | |
a2a8927a | 709 | self.push_ident(field_name.unwrap_or(kw::Empty).as_str()); |
94222f64 XL |
710 | |
711 | self = field.print(self)?; | |
712 | } | |
713 | self.push("E"); | |
714 | } | |
715 | } | |
716 | } | |
717 | _ => unreachable!(), | |
718 | } | |
719 | } | |
dc9dc135 | 720 | _ => { |
5099ac24 | 721 | bug!("symbol_names: unsupported constant of type `{}` ({:?})", ct.ty(), ct); |
dc9dc135 | 722 | } |
dc9dc135 XL |
723 | } |
724 | ||
725 | // Only cache consts that do not refer to an enclosing | |
726 | // binder (which would change depending on context). | |
727 | if !ct.has_escaping_bound_vars() { | |
94222f64 | 728 | self.consts.insert(ct, start); |
dc9dc135 XL |
729 | } |
730 | Ok(self) | |
731 | } | |
732 | ||
94222f64 | 733 | fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> { |
dc9dc135 | 734 | self.push("C"); |
136023e0 XL |
735 | let stable_crate_id = self.tcx.def_path_hash(cnum.as_def_id()).stable_crate_id(); |
736 | self.push_disambiguator(stable_crate_id.to_u64()); | |
a2a8927a XL |
737 | let name = self.tcx.crate_name(cnum); |
738 | self.push_ident(name.as_str()); | |
dc9dc135 XL |
739 | Ok(self) |
740 | } | |
29967ef6 | 741 | |
dc9dc135 XL |
742 | fn path_qualified( |
743 | mut self, | |
744 | self_ty: Ty<'tcx>, | |
745 | trait_ref: Option<ty::TraitRef<'tcx>>, | |
746 | ) -> Result<Self::Path, Self::Error> { | |
747 | assert!(trait_ref.is_some()); | |
748 | let trait_ref = trait_ref.unwrap(); | |
749 | ||
750 | self.push("Y"); | |
751 | self = self_ty.print(self)?; | |
752 | self.print_def_path(trait_ref.def_id, trait_ref.substs) | |
753 | } | |
754 | ||
755 | fn path_append_impl( | |
29967ef6 XL |
756 | self, |
757 | _: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, | |
758 | _: &DisambiguatedDefPathData, | |
759 | _: Ty<'tcx>, | |
760 | _: Option<ty::TraitRef<'tcx>>, | |
dc9dc135 | 761 | ) -> Result<Self::Path, Self::Error> { |
29967ef6 XL |
762 | // Inlined into `print_impl_path` |
763 | unreachable!() | |
dc9dc135 | 764 | } |
29967ef6 | 765 | |
dc9dc135 XL |
766 | fn path_append( |
767 | self, | |
768 | print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, | |
769 | disambiguated_data: &DisambiguatedDefPathData, | |
770 | ) -> Result<Self::Path, Self::Error> { | |
771 | let ns = match disambiguated_data.data { | |
5099ac24 FG |
772 | // Extern block segments can be skipped, names from extern blocks |
773 | // are effectively living in their parent modules. | |
774 | DefPathData::ForeignMod => return print_prefix(self), | |
a2a8927a | 775 | |
dc9dc135 XL |
776 | // Uppercase categories are more stable than lowercase ones. |
777 | DefPathData::TypeNs(_) => 't', | |
778 | DefPathData::ValueNs(_) => 'v', | |
779 | DefPathData::ClosureExpr => 'C', | |
780 | DefPathData::Ctor => 'c', | |
781 | DefPathData::AnonConst => 'k', | |
782 | DefPathData::ImplTrait => 'i', | |
783 | ||
784 | // These should never show up as `path_append` arguments. | |
785 | DefPathData::CrateRoot | |
04454e1e FG |
786 | | DefPathData::Use |
787 | | DefPathData::GlobalAsm | |
dc9dc135 XL |
788 | | DefPathData::Impl |
789 | | DefPathData::MacroNs(_) | |
60c5eb7d | 790 | | DefPathData::LifetimeNs(_) => { |
dc9dc135 XL |
791 | bug!("symbol_names: unexpected DefPathData: {:?}", disambiguated_data.data) |
792 | } | |
793 | }; | |
794 | ||
a2a8927a | 795 | let name = disambiguated_data.data.get_opt_name(); |
dc9dc135 XL |
796 | |
797 | self.path_append_ns( | |
798 | print_prefix, | |
799 | ns, | |
800 | disambiguated_data.disambiguator as u64, | |
a2a8927a | 801 | name.unwrap_or(kw::Empty).as_str(), |
dc9dc135 XL |
802 | ) |
803 | } | |
29967ef6 | 804 | |
dc9dc135 XL |
805 | fn path_generic_args( |
806 | mut self, | |
807 | print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, | |
e74abb32 | 808 | args: &[GenericArg<'tcx>], |
dc9dc135 XL |
809 | ) -> Result<Self::Path, Self::Error> { |
810 | // Don't print any regions if they're all erased. | |
dfeec247 | 811 | let print_regions = args.iter().any(|arg| match arg.unpack() { |
5099ac24 | 812 | GenericArgKind::Lifetime(r) => !r.is_erased(), |
dfeec247 | 813 | _ => false, |
dc9dc135 | 814 | }); |
dfeec247 XL |
815 | let args = args.iter().cloned().filter(|arg| match arg.unpack() { |
816 | GenericArgKind::Lifetime(_) => print_regions, | |
817 | _ => true, | |
dc9dc135 XL |
818 | }); |
819 | ||
820 | if args.clone().next().is_none() { | |
821 | return print_prefix(self); | |
822 | } | |
823 | ||
824 | self.push("I"); | |
825 | self = print_prefix(self)?; | |
826 | for arg in args { | |
827 | match arg.unpack() { | |
e74abb32 | 828 | GenericArgKind::Lifetime(lt) => { |
dc9dc135 XL |
829 | self = lt.print(self)?; |
830 | } | |
e74abb32 | 831 | GenericArgKind::Type(ty) => { |
dc9dc135 XL |
832 | self = ty.print(self)?; |
833 | } | |
e74abb32 | 834 | GenericArgKind::Const(c) => { |
dc9dc135 | 835 | self.push("K"); |
3dfed10e | 836 | self = c.print(self)?; |
dc9dc135 XL |
837 | } |
838 | } | |
839 | } | |
840 | self.push("E"); | |
841 | ||
842 | Ok(self) | |
843 | } | |
844 | } |