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