1 use rustc_ast
::ast
::{FloatTy, IntTy, UintTy}
;
2 use rustc_data_structures
::base_n
;
3 use rustc_data_structures
::fx
::{FxHashMap, FxHashSet}
;
5 use rustc_hir
::def_id
::{CrateNum, DefId}
;
6 use rustc_hir
::definitions
::{DefPathData, DisambiguatedDefPathData}
;
7 use rustc_middle
::ty
::print
::{Print, Printer}
;
8 use rustc_middle
::ty
::subst
::{GenericArg, GenericArgKind, Subst}
;
9 use rustc_middle
::ty
::{self, Instance, Ty, TyCtxt, TypeFoldable}
;
10 use rustc_target
::spec
::abi
::Abi
;
17 instance
: Instance
<'tcx
>,
18 instantiating_crate
: Option
<CrateNum
>,
20 let def_id
= instance
.def_id();
21 // FIXME(eddyb) this should ideally not be needed.
22 let substs
= tcx
.normalize_erasing_regions(ty
::ParamEnv
::reveal_all(), instance
.substs
);
25 let mut cx
= SymbolMangler
{
27 compress
: Some(Box
::new(CompressionCaches
{
28 start_offset
: prefix
.len(),
30 paths
: FxHashMap
::default(),
31 types
: FxHashMap
::default(),
32 consts
: FxHashMap
::default(),
35 out
: String
::from(prefix
),
38 // Append `::{shim:...#0}` to shims that can coexist with a non-shim instance.
39 let shim_kind
= match instance
.def
{
40 ty
::InstanceDef
::VtableShim(_
) => Some("vtable"),
41 ty
::InstanceDef
::ReifyShim(_
) => Some("reify"),
46 cx
= if let Some(shim_kind
) = shim_kind
{
47 cx
.path_append_ns(|cx
| cx
.print_def_path(def_id
, substs
), 'S'
, 0, shim_kind
).unwrap()
49 cx
.print_def_path(def_id
, substs
).unwrap()
51 if let Some(instantiating_crate
) = instantiating_crate
{
52 cx
= cx
.print_def_path(instantiating_crate
.as_def_id(), &[]).unwrap();
57 struct CompressionCaches
<'tcx
> {
58 // The length of the prefix in `out` (e.g. 2 for `_R`).
61 // The values are start positions in `out`, in bytes.
62 paths
: FxHashMap
<(DefId
, &'tcx
[GenericArg
<'tcx
>]), usize>,
63 types
: FxHashMap
<Ty
<'tcx
>, usize>,
64 consts
: FxHashMap
<&'tcx ty
::Const
<'tcx
>, usize>,
68 /// The range of distances from the root of what's
69 /// being printed, to the lifetimes in a binder.
70 /// Specifically, a `BrAnon(i)` lifetime has depth
71 /// `lifetime_depths.start + i`, going away from the
72 /// the root and towards its use site, as `i` increases.
73 /// This is used to flatten rustc's pairing of `BrAnon`
74 /// (intra-binder disambiguation) with a `DebruijnIndex`
75 /// (binder addressing), to "true" de Bruijn indices,
76 /// by subtracting the depth of a certain lifetime, from
77 /// the innermost depth at its use site.
78 lifetime_depths
: Range
<u32>,
81 struct SymbolMangler
<'tcx
> {
83 compress
: Option
<Box
<CompressionCaches
<'tcx
>>>,
84 binders
: Vec
<BinderLevel
>,
88 impl SymbolMangler
<'tcx
> {
89 fn push(&mut self, s
: &str) {
93 /// Push a `_`-terminated base 62 integer, using the format
94 /// specified in the RFC as `<base-62-number>`, that is:
95 /// * `x = 0` is encoded as just the `"_"` terminator
96 /// * `x > 0` is encoded as `x - 1` in base 62, followed by `"_"`,
97 /// e.g. `1` becomes `"0_"`, `62` becomes `"Z_"`, etc.
98 fn push_integer_62(&mut self, x
: u64) {
99 if let Some(x
) = x
.checked_sub(1) {
100 base_n
::push_str(x
as u128
, 62, &mut self.out
);
105 /// Push a `tag`-prefixed base 62 integer, when larger than `0`, that is:
106 /// * `x = 0` is encoded as `""` (nothing)
107 /// * `x > 0` is encoded as the `tag` followed by `push_integer_62(x - 1)`
108 /// e.g. `1` becomes `tag + "_"`, `2` becomes `tag + "0_"`, etc.
109 fn push_opt_integer_62(&mut self, tag
: &str, x
: u64) {
110 if let Some(x
) = x
.checked_sub(1) {
112 self.push_integer_62(x
);
116 fn push_disambiguator(&mut self, dis
: u64) {
117 self.push_opt_integer_62("s", dis
);
120 fn push_ident(&mut self, ident
: &str) {
121 let mut use_punycode
= false;
122 for b
in ident
.bytes() {
124 b'_'
| b'a'
..=b'z'
| b'A'
..=b'Z'
| b'
0'
..=b'
9'
=> {}
125 0x80..=0xff => use_punycode
= true,
126 _
=> bug
!("symbol_names: bad byte {} in ident {:?}", b
, ident
),
131 let ident
= if use_punycode
{
134 // FIXME(eddyb) we should probably roll our own punycode implementation.
135 let mut punycode_bytes
= match ::punycode
::encode(ident
) {
136 Ok(s
) => s
.into_bytes(),
137 Err(()) => bug
!("symbol_names: punycode encoding failed for ident {:?}", ident
),
140 // Replace `-` with `_`.
141 if let Some(c
) = punycode_bytes
.iter_mut().rfind(|&&mut c
| c
== b'
-'
) {
145 // FIXME(eddyb) avoid rechecking UTF-8 validity.
146 punycode_string
= String
::from_utf8(punycode_bytes
).unwrap();
152 let _
= write
!(self.out
, "{}", ident
.len());
154 // Write a separating `_` if necessary (leading digit or `_`).
155 match ident
.chars().next() {
156 Some('_'
| '
0'
..='
9'
) => {
167 print_prefix
: impl FnOnce(Self) -> Result
<Self, !>,
171 ) -> Result
<Self, !> {
174 self = print_prefix(self)?
;
175 self.push_disambiguator(disambiguator
as u64);
176 self.push_ident(name
);
180 fn print_backref(mut self, i
: usize) -> Result
<Self, !> {
182 self.push_integer_62((i
- self.compress
.as_ref().unwrap().start_offset
) as u64);
188 value
: &ty
::Binder
<T
>,
189 print_value
: impl FnOnce(Self, &T
) -> Result
<Self, !>,
192 T
: TypeFoldable
<'tcx
>,
194 let regions
= if value
.has_late_bound_regions() {
195 self.tcx
.collect_referenced_late_bound_regions(value
)
200 let mut lifetime_depths
=
201 self.binders
.last().map(|b
| b
.lifetime_depths
.end
).map_or(0..0, |i
| i
..i
);
203 let lifetimes
= regions
208 // FIXME(eddyb) for some reason, `anonymize_late_bound_regions` starts at `1`.
212 _
=> bug
!("symbol_names: non-anonymized region `{:?}` in `{:?}`", br
, value
),
216 .map_or(0, |max
| max
+ 1);
218 self.push_opt_integer_62("G", lifetimes
as u64);
219 lifetime_depths
.end
+= lifetimes
;
221 self.binders
.push(BinderLevel { lifetime_depths }
);
222 self = print_value(self, value
.skip_binder())?
;
229 impl Printer
<'tcx
> for SymbolMangler
<'tcx
> {
235 type DynExistential
= Self;
238 fn tcx(&self) -> TyCtxt
<'tcx
> {
245 substs
: &'tcx
[GenericArg
<'tcx
>],
246 ) -> Result
<Self::Path
, Self::Error
> {
247 if let Some(&i
) = self.compress
.as_ref().and_then(|c
| c
.paths
.get(&(def_id
, substs
))) {
248 return self.print_backref(i
);
250 let start
= self.out
.len();
252 self = self.default_print_def_path(def_id
, substs
)?
;
254 // Only cache paths that do not refer to an enclosing
255 // binder (which would change depending on context).
256 if !substs
.iter().any(|k
| k
.has_escaping_bound_vars()) {
257 if let Some(c
) = &mut self.compress
{
258 c
.paths
.insert((def_id
, substs
), start
);
267 substs
: &'tcx
[GenericArg
<'tcx
>],
268 mut self_ty
: Ty
<'tcx
>,
269 mut impl_trait_ref
: Option
<ty
::TraitRef
<'tcx
>>,
270 ) -> Result
<Self::Path
, Self::Error
> {
271 let key
= self.tcx
.def_key(impl_def_id
);
272 let parent_def_id
= DefId { index: key.parent.unwrap(), ..impl_def_id }
;
274 let mut param_env
= self.tcx
.param_env(impl_def_id
).with_reveal_all();
275 if !substs
.is_empty() {
276 param_env
= param_env
.subst(self.tcx
, substs
);
279 match &mut impl_trait_ref
{
280 Some(impl_trait_ref
) => {
281 assert_eq
!(impl_trait_ref
.self_ty(), self_ty
);
282 *impl_trait_ref
= self.tcx
.normalize_erasing_regions(param_env
, *impl_trait_ref
);
283 self_ty
= impl_trait_ref
.self_ty();
286 self_ty
= self.tcx
.normalize_erasing_regions(param_env
, self_ty
);
290 self.path_append_impl(
291 |cx
| cx
.print_def_path(parent_def_id
, &[]),
292 &key
.disambiguated_data
,
298 fn print_region(mut self, region
: ty
::Region
<'_
>) -> Result
<Self::Region
, Self::Error
> {
299 let i
= match *region
{
300 // Erased lifetimes use the index 0, for a
301 // shorter mangling of `L_`.
304 // Late-bound lifetimes use indices starting at 1,
305 // see `BinderLevel` for more details.
306 ty
::ReLateBound(debruijn
, ty
::BrAnon(i
)) => {
307 // FIXME(eddyb) for some reason, `anonymize_late_bound_regions` starts at `1`.
311 let binder
= &self.binders
[self.binders
.len() - 1 - debruijn
.index()];
312 let depth
= binder
.lifetime_depths
.start
+ i
;
314 1 + (self.binders
.last().unwrap().lifetime_depths
.end
- 1 - depth
)
317 _
=> bug
!("symbol_names: non-erased region `{:?}`", region
),
320 self.push_integer_62(i
as u64);
324 fn print_type(mut self, ty
: Ty
<'tcx
>) -> Result
<Self::Type
, Self::Error
> {
325 // Basic types, never cached (single-character).
326 let basic_type
= match ty
.kind
{
330 ty
::Tuple(_
) if ty
.is_unit() => "u",
331 ty
::Int(IntTy
::I8
) => "a",
332 ty
::Int(IntTy
::I16
) => "s",
333 ty
::Int(IntTy
::I32
) => "l",
334 ty
::Int(IntTy
::I64
) => "x",
335 ty
::Int(IntTy
::I128
) => "n",
336 ty
::Int(IntTy
::Isize
) => "i",
337 ty
::Uint(UintTy
::U8
) => "h",
338 ty
::Uint(UintTy
::U16
) => "t",
339 ty
::Uint(UintTy
::U32
) => "m",
340 ty
::Uint(UintTy
::U64
) => "y",
341 ty
::Uint(UintTy
::U128
) => "o",
342 ty
::Uint(UintTy
::Usize
) => "j",
343 ty
::Float(FloatTy
::F32
) => "f",
344 ty
::Float(FloatTy
::F64
) => "d",
347 // Placeholders (should be demangled as `_`).
348 ty
::Param(_
) | ty
::Bound(..) | ty
::Placeholder(_
) | ty
::Infer(_
) | ty
::Error
=> "p",
352 if !basic_type
.is_empty() {
353 self.push(basic_type
);
357 if let Some(&i
) = self.compress
.as_ref().and_then(|c
| c
.types
.get(&ty
)) {
358 return self.print_backref(i
);
360 let start
= self.out
.len();
363 // Basic types, handled above.
364 ty
::Bool
| ty
::Char
| ty
::Str
| ty
::Int(_
) | ty
::Uint(_
) | ty
::Float(_
) | ty
::Never
=> {
367 ty
::Tuple(_
) if ty
.is_unit() => unreachable
!(),
369 // Placeholders, also handled as part of basic types.
370 ty
::Param(_
) | ty
::Bound(..) | ty
::Placeholder(_
) | ty
::Infer(_
) | ty
::Error
=> {
374 ty
::Ref(r
, ty
, mutbl
) => {
375 self.push(match mutbl
{
376 hir
::Mutability
::Not
=> "R",
377 hir
::Mutability
::Mut
=> "Q",
379 if *r
!= ty
::ReErased
{
380 self = r
.print(self)?
;
382 self = ty
.print(self)?
;
386 self.push(match mt
.mutbl
{
387 hir
::Mutability
::Not
=> "P",
388 hir
::Mutability
::Mut
=> "O",
390 self = mt
.ty
.print(self)?
;
393 ty
::Array(ty
, len
) => {
395 self = ty
.print(self)?
;
396 self = self.print_const(len
)?
;
400 self = ty
.print(self)?
;
405 for ty
in tys
.iter().map(|k
| k
.expect_ty()) {
406 self = ty
.print(self)?
;
411 // Mangle all nominal types as paths.
412 ty
::Adt(&ty
::AdtDef { did: def_id, .. }
, substs
)
413 | ty
::FnDef(def_id
, substs
)
414 | ty
::Opaque(def_id
, substs
)
415 | ty
::Projection(ty
::ProjectionTy { item_def_id: def_id, substs }
)
416 | ty
::UnnormalizedProjection(ty
::ProjectionTy { item_def_id: def_id, substs }
)
417 | ty
::Closure(def_id
, substs
)
418 | ty
::Generator(def_id
, substs
, _
) => {
419 self = self.print_def_path(def_id
, substs
)?
;
421 ty
::Foreign(def_id
) => {
422 self = self.print_def_path(def_id
, &[])?
;
427 self = self.in_binder(&sig
, |mut cx
, sig
| {
428 if sig
.unsafety
== hir
::Unsafety
::Unsafe
{
433 Abi
::C
=> cx
.push("KC"),
436 let name
= abi
.name();
437 if name
.contains('
-'
) {
438 cx
.push_ident(&name
.replace('
-'
, "_"));
444 for &ty
in sig
.inputs() {
451 sig
.output().print(cx
)
455 ty
::Dynamic(predicates
, r
) => {
457 self = self.in_binder(&predicates
, |cx
, predicates
| {
458 cx
.print_dyn_existential(predicates
)
460 self = r
.print(self)?
;
463 ty
::GeneratorWitness(_
) => bug
!("symbol_names: unexpected `GeneratorWitness`"),
466 // Only cache types that do not refer to an enclosing
467 // binder (which would change depending on context).
468 if !ty
.has_escaping_bound_vars() {
469 if let Some(c
) = &mut self.compress
{
470 c
.types
.insert(ty
, start
);
476 fn print_dyn_existential(
478 predicates
: &'tcx ty
::List
<ty
::ExistentialPredicate
<'tcx
>>,
479 ) -> Result
<Self::DynExistential
, Self::Error
> {
480 for predicate
in predicates
{
482 ty
::ExistentialPredicate
::Trait(trait_ref
) => {
483 // Use a type that can't appear in defaults of type parameters.
484 let dummy_self
= self.tcx
.mk_ty_infer(ty
::FreshTy(0));
485 let trait_ref
= trait_ref
.with_self_ty(self.tcx
, dummy_self
);
486 self = self.print_def_path(trait_ref
.def_id
, trait_ref
.substs
)?
;
488 ty
::ExistentialPredicate
::Projection(projection
) => {
489 let name
= self.tcx
.associated_item(projection
.item_def_id
).ident
;
491 self.push_ident(&name
.as_str());
492 self = projection
.ty
.print(self)?
;
494 ty
::ExistentialPredicate
::AutoTrait(def_id
) => {
495 self = self.print_def_path(def_id
, &[])?
;
503 fn print_const(mut self, ct
: &'tcx ty
::Const
<'tcx
>) -> Result
<Self::Const
, Self::Error
> {
504 if let Some(&i
) = self.compress
.as_ref().and_then(|c
| c
.consts
.get(&ct
)) {
505 return self.print_backref(i
);
507 let start
= self.out
.len();
512 bug
!("symbol_names: unsupported constant of type `{}` ({:?})", ct
.ty
, ct
);
515 self = ct
.ty
.print(self)?
;
517 if let Some(bits
) = ct
.try_eval_bits(self.tcx
, ty
::ParamEnv
::reveal_all(), ct
.ty
) {
518 let _
= write
!(self.out
, "{:x}_", bits
);
520 // NOTE(eddyb) despite having the path, we need to
521 // encode a placeholder, as the path could refer
522 // back to e.g. an `impl` using the constant.
526 // Only cache consts that do not refer to an enclosing
527 // binder (which would change depending on context).
528 if !ct
.has_escaping_bound_vars() {
529 if let Some(c
) = &mut self.compress
{
530 c
.consts
.insert(ct
, start
);
536 fn path_crate(mut self, cnum
: CrateNum
) -> Result
<Self::Path
, Self::Error
> {
538 let fingerprint
= self.tcx
.crate_disambiguator(cnum
).to_fingerprint();
539 self.push_disambiguator(fingerprint
.to_smaller_hash());
540 let name
= self.tcx
.original_crate_name(cnum
).as_str();
541 self.push_ident(&name
);
547 trait_ref
: Option
<ty
::TraitRef
<'tcx
>>,
548 ) -> Result
<Self::Path
, Self::Error
> {
549 assert
!(trait_ref
.is_some());
550 let trait_ref
= trait_ref
.unwrap();
553 self = self_ty
.print(self)?
;
554 self.print_def_path(trait_ref
.def_id
, trait_ref
.substs
)
559 print_prefix
: impl FnOnce(Self) -> Result
<Self::Path
, Self::Error
>,
560 disambiguated_data
: &DisambiguatedDefPathData
,
562 trait_ref
: Option
<ty
::TraitRef
<'tcx
>>,
563 ) -> Result
<Self::Path
, Self::Error
> {
564 self.push(match trait_ref
{
568 self.push_disambiguator(disambiguated_data
.disambiguator
as u64);
569 self = print_prefix(self)?
;
570 self = self_ty
.print(self)?
;
571 if let Some(trait_ref
) = trait_ref
{
572 self = self.print_def_path(trait_ref
.def_id
, trait_ref
.substs
)?
;
578 print_prefix
: impl FnOnce(Self) -> Result
<Self::Path
, Self::Error
>,
579 disambiguated_data
: &DisambiguatedDefPathData
,
580 ) -> Result
<Self::Path
, Self::Error
> {
581 let ns
= match disambiguated_data
.data
{
582 // Uppercase categories are more stable than lowercase ones.
583 DefPathData
::TypeNs(_
) => 't'
,
584 DefPathData
::ValueNs(_
) => 'v'
,
585 DefPathData
::ClosureExpr
=> 'C'
,
586 DefPathData
::Ctor
=> 'c'
,
587 DefPathData
::AnonConst
=> 'k'
,
588 DefPathData
::ImplTrait
=> 'i'
,
590 // These should never show up as `path_append` arguments.
591 DefPathData
::CrateRoot
594 | DefPathData
::MacroNs(_
)
595 | DefPathData
::LifetimeNs(_
) => {
596 bug
!("symbol_names: unexpected DefPathData: {:?}", disambiguated_data
.data
)
600 let name
= disambiguated_data
.data
.get_opt_name().map(|s
| s
.as_str());
605 disambiguated_data
.disambiguator
as u64,
606 name
.as_ref().map_or("", |s
| &s
[..]),
609 fn path_generic_args(
611 print_prefix
: impl FnOnce(Self) -> Result
<Self::Path
, Self::Error
>,
612 args
: &[GenericArg
<'tcx
>],
613 ) -> Result
<Self::Path
, Self::Error
> {
614 // Don't print any regions if they're all erased.
615 let print_regions
= args
.iter().any(|arg
| match arg
.unpack() {
616 GenericArgKind
::Lifetime(r
) => *r
!= ty
::ReErased
,
619 let args
= args
.iter().cloned().filter(|arg
| match arg
.unpack() {
620 GenericArgKind
::Lifetime(_
) => print_regions
,
624 if args
.clone().next().is_none() {
625 return print_prefix(self);
629 self = print_prefix(self)?
;
632 GenericArgKind
::Lifetime(lt
) => {
633 self = lt
.print(self)?
;
635 GenericArgKind
::Type(ty
) => {
636 self = ty
.print(self)?
;
638 GenericArgKind
::Const(c
) => {
640 // FIXME(const_generics) implement `ty::print::Print` on `ty::Const`.
641 // self = c.print(self)?;
642 self = self.print_const(c
)?
;