1use std::fmt::Write;
2use std::hash::Hasher;
3use std::iter;
4use std::ops::Range;
5
6use rustc_abi::{ExternAbi, Integer};
7use rustc_data_structures::base_n::ToBaseN;
8use rustc_data_structures::fx::FxHashMap;
9use rustc_data_structures::intern::Interned;
10use rustc_data_structures::stable_hasher::StableHasher;
11use rustc_hashes::Hash64;
12use rustc_hir as hir;
13use rustc_hir::def::CtorKind;
14use rustc_hir::def_id::{CrateNum, DefId};
15use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
16use rustc_middle::bug;
17use rustc_middle::ty::layout::IntegerExt;
18use rustc_middle::ty::print::{Print, PrintError, Printer};
19use rustc_middle::ty::{
20 self, FloatTy, GenericArg, GenericArgKind, Instance, IntTy, ReifyReason, Ty, TyCtxt,
21 TypeVisitable, TypeVisitableExt, UintTy,
22};
23use rustc_span::kw;
24
25pub(super) fn mangle<'tcx>(
26 tcx: TyCtxt<'tcx>,
27 instance: Instance<'tcx>,
28 instantiating_crate: Option<CrateNum>,
29) -> String {
30 let def_id = instance.def_id();
31 let args = tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), instance.args);
33
34 let prefix = "_R";
35 let mut cx: SymbolMangler<'_> = SymbolMangler {
36 tcx,
37 start_offset: prefix.len(),
38 paths: FxHashMap::default(),
39 types: FxHashMap::default(),
40 consts: FxHashMap::default(),
41 binders: vec![],
42 out: String::from(prefix),
43 };
44
45 let shim_kind = match instance.def {
47 ty::InstanceKind::ThreadLocalShim(_) => Some("tls"),
48 ty::InstanceKind::VTableShim(_) => Some("vtable"),
49 ty::InstanceKind::ReifyShim(_, None) => Some("reify"),
50 ty::InstanceKind::ReifyShim(_, Some(ReifyReason::FnPtr)) => Some("reify_fnptr"),
51 ty::InstanceKind::ReifyShim(_, Some(ReifyReason::Vtable)) => Some("reify_vtable"),
52
53 ty::InstanceKind::ConstructCoroutineInClosureShim { receiver_by_ref: true, .. } => {
56 Some("by_move")
57 }
58 ty::InstanceKind::ConstructCoroutineInClosureShim { receiver_by_ref: false, .. } => {
59 Some("by_ref")
60 }
61
62 _ => None,
63 };
64
65 if let Some(shim_kind) = shim_kind {
66 cx.path_append_ns(|cx| cx.print_def_path(def_id, args), 'S', 0, shim_kind).unwrap()
67 } else {
68 cx.print_def_path(def_id, args).unwrap()
69 };
70 if let Some(instantiating_crate) = instantiating_crate {
71 cx.print_def_path(instantiating_crate.as_def_id(), &[]).unwrap();
72 }
73 std::mem::take(&mut cx.out)
74}
75
76pub fn mangle_internal_symbol<'tcx>(tcx: TyCtxt<'tcx>, item_name: &str) -> String {
77 if item_name == "rust_eh_personality" {
78 return "rust_eh_personality".to_owned();
80 } else if item_name == "__rust_no_alloc_shim_is_unstable" {
81 return "__rust_no_alloc_shim_is_unstable".to_owned();
84 }
85
86 let prefix = "_R";
87 let mut cx: SymbolMangler<'_> = SymbolMangler {
88 tcx,
89 start_offset: prefix.len(),
90 paths: FxHashMap::default(),
91 types: FxHashMap::default(),
92 consts: FxHashMap::default(),
93 binders: vec![],
94 out: String::from(prefix),
95 };
96
97 cx.path_append_ns(
98 |cx| {
99 cx.push("C");
100 cx.push_disambiguator({
101 let mut hasher = StableHasher::new();
102 hasher.write(tcx.sess.cfg_version.as_bytes());
108
109 let hash: Hash64 = hasher.finish();
110 hash.as_u64()
111 });
112 cx.push_ident("__rustc");
113 Ok(())
114 },
115 'v',
116 0,
117 item_name,
118 )
119 .unwrap();
120
121 std::mem::take(&mut cx.out)
122}
123
124pub(super) fn mangle_typeid_for_trait_ref<'tcx>(
125 tcx: TyCtxt<'tcx>,
126 trait_ref: ty::ExistentialTraitRef<'tcx>,
127) -> String {
128 let mut cx = SymbolMangler {
130 tcx,
131 start_offset: 0,
132 paths: FxHashMap::default(),
133 types: FxHashMap::default(),
134 consts: FxHashMap::default(),
135 binders: vec![],
136 out: String::new(),
137 };
138 cx.print_def_path(trait_ref.def_id, &[]).unwrap();
139 std::mem::take(&mut cx.out)
140}
141
142struct BinderLevel {
143 lifetime_depths: Range<u32>,
154}
155
156struct SymbolMangler<'tcx> {
157 tcx: TyCtxt<'tcx>,
158 binders: Vec<BinderLevel>,
159 out: String,
160
161 start_offset: usize,
163 paths: FxHashMap<(DefId, &'tcx [GenericArg<'tcx>]), usize>,
165 types: FxHashMap<Ty<'tcx>, usize>,
166 consts: FxHashMap<ty::Const<'tcx>, usize>,
167}
168
169impl<'tcx> SymbolMangler<'tcx> {
170 fn push(&mut self, s: &str) {
171 self.out.push_str(s);
172 }
173
174 fn push_integer_62(&mut self, x: u64) {
180 push_integer_62(x, &mut self.out)
181 }
182
183 fn push_opt_integer_62(&mut self, tag: &str, x: u64) {
188 if let Some(x) = x.checked_sub(1) {
189 self.push(tag);
190 self.push_integer_62(x);
191 }
192 }
193
194 fn push_disambiguator(&mut self, dis: u64) {
195 self.push_opt_integer_62("s", dis);
196 }
197
198 fn push_ident(&mut self, ident: &str) {
199 push_ident(ident, &mut self.out)
200 }
201
202 fn path_append_ns(
203 &mut self,
204 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
205 ns: char,
206 disambiguator: u64,
207 name: &str,
208 ) -> Result<(), PrintError> {
209 self.push("N");
210 self.out.push(ns);
211 print_prefix(self)?;
212 self.push_disambiguator(disambiguator);
213 self.push_ident(name);
214 Ok(())
215 }
216
217 fn print_backref(&mut self, i: usize) -> Result<(), PrintError> {
218 self.push("B");
219 self.push_integer_62((i - self.start_offset) as u64);
220 Ok(())
221 }
222
223 fn wrap_binder<T>(
224 &mut self,
225 value: &ty::Binder<'tcx, T>,
226 print_value: impl FnOnce(&mut Self, &T) -> Result<(), PrintError>,
227 ) -> Result<(), PrintError>
228 where
229 T: TypeVisitable<TyCtxt<'tcx>>,
230 {
231 let mut lifetime_depths =
232 self.binders.last().map(|b| b.lifetime_depths.end).map_or(0..0, |i| i..i);
233
234 let lifetimes = value
236 .bound_vars()
237 .iter()
238 .filter(|var| matches!(var, ty::BoundVariableKind::Region(..)))
239 .count() as u32;
240
241 self.push_opt_integer_62("G", lifetimes as u64);
242 lifetime_depths.end += lifetimes;
243
244 self.binders.push(BinderLevel { lifetime_depths });
245 print_value(self, value.as_ref().skip_binder())?;
246 self.binders.pop();
247
248 Ok(())
249 }
250}
251
252impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
253 fn tcx(&self) -> TyCtxt<'tcx> {
254 self.tcx
255 }
256
257 fn print_def_path(
258 &mut self,
259 def_id: DefId,
260 args: &'tcx [GenericArg<'tcx>],
261 ) -> Result<(), PrintError> {
262 if let Some(&i) = self.paths.get(&(def_id, args)) {
263 return self.print_backref(i);
264 }
265 let start = self.out.len();
266
267 self.default_print_def_path(def_id, args)?;
268
269 if !args.iter().any(|k| k.has_escaping_bound_vars()) {
272 self.paths.insert((def_id, args), start);
273 }
274 Ok(())
275 }
276
277 fn print_impl_path(
278 &mut self,
279 impl_def_id: DefId,
280 args: &'tcx [GenericArg<'tcx>],
281 ) -> Result<(), PrintError> {
282 let key = self.tcx.def_key(impl_def_id);
283 let parent_def_id = DefId { index: key.parent.unwrap(), ..impl_def_id };
284
285 let self_ty = self.tcx.type_of(impl_def_id);
286 let impl_trait_ref = self.tcx.impl_trait_ref(impl_def_id);
287 let generics = self.tcx.generics_of(impl_def_id);
288 let (typing_env, mut self_ty, mut impl_trait_ref) = if generics.count() > args.len()
302 || &args[..generics.count()]
303 == self
304 .tcx
305 .erase_regions(ty::GenericArgs::identity_for_item(self.tcx, impl_def_id))
306 .as_slice()
307 {
308 (
309 ty::TypingEnv::post_analysis(self.tcx, impl_def_id),
310 self_ty.instantiate_identity(),
311 impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate_identity()),
312 )
313 } else {
314 assert!(
315 !args.has_non_region_param(),
316 "should not be mangling partially substituted \
317 polymorphic instance: {impl_def_id:?} {args:?}"
318 );
319 (
320 ty::TypingEnv::fully_monomorphized(),
321 self_ty.instantiate(self.tcx, args),
322 impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate(self.tcx, args)),
323 )
324 };
325
326 match &mut impl_trait_ref {
327 Some(impl_trait_ref) => {
328 assert_eq!(impl_trait_ref.self_ty(), self_ty);
329 *impl_trait_ref = self.tcx.normalize_erasing_regions(typing_env, *impl_trait_ref);
330 self_ty = impl_trait_ref.self_ty();
331 }
332 None => {
333 self_ty = self.tcx.normalize_erasing_regions(typing_env, self_ty);
334 }
335 }
336
337 self.push(match impl_trait_ref {
338 Some(_) => "X",
339 None => "M",
340 });
341
342 if impl_trait_ref.is_some() && args.iter().any(|a| a.has_non_region_param()) {
345 self.path_generic_args(
346 |this| {
347 this.path_append_ns(
348 |cx| cx.print_def_path(parent_def_id, &[]),
349 'I',
350 key.disambiguated_data.disambiguator as u64,
351 "",
352 )
353 },
354 args,
355 )?;
356 } else {
357 self.push_disambiguator(key.disambiguated_data.disambiguator as u64);
358 self.print_def_path(parent_def_id, &[])?;
359 }
360
361 self_ty.print(self)?;
362
363 if let Some(trait_ref) = impl_trait_ref {
364 self.print_def_path(trait_ref.def_id, trait_ref.args)?;
365 }
366
367 Ok(())
368 }
369
370 fn print_region(&mut self, region: ty::Region<'_>) -> Result<(), PrintError> {
371 let i = match *region {
372 ty::ReErased => 0,
375
376 ty::ReBound(debruijn, ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon }) => {
379 let binder = &self.binders[self.binders.len() - 1 - debruijn.index()];
380 let depth = binder.lifetime_depths.start + var.as_u32();
381
382 1 + (self.binders.last().unwrap().lifetime_depths.end - 1 - depth)
383 }
384
385 _ => bug!("symbol_names: non-erased region `{:?}`", region),
386 };
387 self.push("L");
388 self.push_integer_62(i as u64);
389 Ok(())
390 }
391
392 fn print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> {
393 let basic_type = match ty.kind() {
395 ty::Bool => "b",
396 ty::Char => "c",
397 ty::Str => "e",
398 ty::Tuple(_) if ty.is_unit() => "u",
399 ty::Int(IntTy::I8) => "a",
400 ty::Int(IntTy::I16) => "s",
401 ty::Int(IntTy::I32) => "l",
402 ty::Int(IntTy::I64) => "x",
403 ty::Int(IntTy::I128) => "n",
404 ty::Int(IntTy::Isize) => "i",
405 ty::Uint(UintTy::U8) => "h",
406 ty::Uint(UintTy::U16) => "t",
407 ty::Uint(UintTy::U32) => "m",
408 ty::Uint(UintTy::U64) => "y",
409 ty::Uint(UintTy::U128) => "o",
410 ty::Uint(UintTy::Usize) => "j",
411 ty::Float(FloatTy::F16) => "C3f16",
412 ty::Float(FloatTy::F32) => "f",
413 ty::Float(FloatTy::F64) => "d",
414 ty::Float(FloatTy::F128) => "C4f128",
415 ty::Never => "z",
416
417 ty::Param(_) => "p",
420
421 ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => bug!(),
422
423 _ => "",
424 };
425 if !basic_type.is_empty() {
426 self.push(basic_type);
427 return Ok(());
428 }
429
430 if let Some(&i) = self.types.get(&ty) {
431 return self.print_backref(i);
432 }
433 let start = self.out.len();
434
435 match *ty.kind() {
436 ty::Bool | ty::Char | ty::Str | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Never => {
438 unreachable!()
439 }
440 ty::Tuple(_) if ty.is_unit() => unreachable!(),
441
442 ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => {
444 unreachable!()
445 }
446
447 ty::Ref(r, ty, mutbl) => {
448 self.push(match mutbl {
449 hir::Mutability::Not => "R",
450 hir::Mutability::Mut => "Q",
451 });
452 if !r.is_erased() {
453 r.print(self)?;
454 }
455 ty.print(self)?;
456 }
457
458 ty::RawPtr(ty, mutbl) => {
459 self.push(match mutbl {
460 hir::Mutability::Not => "P",
461 hir::Mutability::Mut => "O",
462 });
463 ty.print(self)?;
464 }
465
466 ty::Pat(ty, pat) => match *pat {
467 ty::PatternKind::Range { start, end } => {
468 let consts = [start, end];
469 self.push("T");
472 ty.print(self)?;
473 for ct in consts {
474 Ty::new_array_with_const_len(self.tcx, self.tcx.types.unit, ct)
475 .print(self)?;
476 }
477 self.push("E");
478 }
479 },
480
481 ty::Array(ty, len) => {
482 self.push("A");
483 ty.print(self)?;
484 self.print_const(len)?;
485 }
486 ty::Slice(ty) => {
487 self.push("S");
488 ty.print(self)?;
489 }
490
491 ty::Tuple(tys) => {
492 self.push("T");
493 for ty in tys.iter() {
494 ty.print(self)?;
495 }
496 self.push("E");
497 }
498
499 ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), args)
501 | ty::FnDef(def_id, args)
502 | ty::Closure(def_id, args)
503 | ty::CoroutineClosure(def_id, args)
504 | ty::Coroutine(def_id, args) => {
505 self.print_def_path(def_id, args)?;
506 }
507
508 ty::Alias(ty::Projection, ty::AliasTy { def_id, args, .. }) => {
511 self.print_def_path(def_id, args)?;
512 }
513
514 ty::Foreign(def_id) => {
515 self.print_def_path(def_id, &[])?;
516 }
517
518 ty::FnPtr(sig_tys, hdr) => {
519 let sig = sig_tys.with(hdr);
520 self.push("F");
521 self.wrap_binder(&sig, |cx, sig| {
522 if sig.safety.is_unsafe() {
523 cx.push("U");
524 }
525 match sig.abi {
526 ExternAbi::Rust => {}
527 ExternAbi::C { unwind: false } => cx.push("KC"),
528 abi => {
529 cx.push("K");
530 let name = abi.as_str();
531 if name.contains('-') {
532 cx.push_ident(&name.replace('-', "_"));
533 } else {
534 cx.push_ident(name);
535 }
536 }
537 }
538 for &ty in sig.inputs() {
539 ty.print(cx)?;
540 }
541 if sig.c_variadic {
542 cx.push("v");
543 }
544 cx.push("E");
545 sig.output().print(cx)
546 })?;
547 }
548
549 ty::UnsafeBinder(..) => todo!(),
551
552 ty::Dynamic(predicates, r, kind) => {
553 self.push(match kind {
554 ty::Dyn => "D",
555 ty::DynStar => "D*",
557 });
558 self.print_dyn_existential(predicates)?;
559 r.print(self)?;
560 }
561
562 ty::Alias(..) => bug!("symbol_names: unexpected alias"),
563 ty::CoroutineWitness(..) => bug!("symbol_names: unexpected `CoroutineWitness`"),
564 }
565
566 if !ty.has_escaping_bound_vars() {
569 self.types.insert(ty, start);
570 }
571 Ok(())
572 }
573
574 fn print_dyn_existential(
575 &mut self,
576 predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
577 ) -> Result<(), PrintError> {
578 self.wrap_binder(&predicates[0], |cx, _| {
605 for predicate in predicates.iter() {
606 match predicate.as_ref().skip_binder() {
611 ty::ExistentialPredicate::Trait(trait_ref) => {
612 let dummy_self = Ty::new_fresh(cx.tcx, 0);
614 let trait_ref = trait_ref.with_self_ty(cx.tcx, dummy_self);
615 cx.print_def_path(trait_ref.def_id, trait_ref.args)?;
616 }
617 ty::ExistentialPredicate::Projection(projection) => {
618 let name = cx.tcx.associated_item(projection.def_id).name;
619 cx.push("p");
620 cx.push_ident(name.as_str());
621 match projection.term.unpack() {
622 ty::TermKind::Ty(ty) => ty.print(cx),
623 ty::TermKind::Const(c) => c.print(cx),
624 }?;
625 }
626 ty::ExistentialPredicate::AutoTrait(def_id) => {
627 cx.print_def_path(*def_id, &[])?;
628 }
629 }
630 }
631 Ok(())
632 })?;
633
634 self.push("E");
635 Ok(())
636 }
637
638 fn print_const(&mut self, ct: ty::Const<'tcx>) -> Result<(), PrintError> {
639 let cv = match ct.kind() {
641 ty::ConstKind::Value(cv) => cv,
642
643 ty::ConstKind::Param(_) => {
646 self.push("p");
648 return Ok(());
649 }
650
651 ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, args, .. }) => {
654 return self.print_def_path(def, args);
655 }
656
657 ty::ConstKind::Expr(_)
658 | ty::ConstKind::Infer(_)
659 | ty::ConstKind::Bound(..)
660 | ty::ConstKind::Placeholder(_)
661 | ty::ConstKind::Error(_) => bug!(),
662 };
663
664 if let Some(&i) = self.consts.get(&ct) {
665 self.print_backref(i)?;
666 return Ok(());
667 }
668
669 let ty::Value { ty: ct_ty, valtree } = cv;
670 let start = self.out.len();
671
672 match ct_ty.kind() {
673 ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Char => {
674 ct_ty.print(self)?;
675
676 let mut bits = cv
677 .try_to_bits(self.tcx, ty::TypingEnv::fully_monomorphized())
678 .expect("expected const to be monomorphic");
679
680 if let ty::Int(ity) = ct_ty.kind() {
682 let val =
683 Integer::from_int_ty(&self.tcx, *ity).size().sign_extend(bits) as i128;
684 if val < 0 {
685 self.push("n");
686 }
687 bits = val.unsigned_abs();
688 }
689
690 let _ = write!(self.out, "{bits:x}_");
691 }
692
693 ty::Str => {
695 let tcx = self.tcx();
696 let ref_ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, ct_ty);
699 let cv = ty::Value { ty: ref_ty, valtree };
700 let slice = cv.try_to_raw_bytes(tcx).unwrap_or_else(|| {
701 bug!("expected to get raw bytes from valtree {:?} for type {:}", valtree, ct_ty)
702 });
703 let s = std::str::from_utf8(slice).expect("non utf8 str from MIR interpreter");
704
705 self.push("e");
707
708 for byte in s.bytes() {
710 let _ = write!(self.out, "{byte:02x}");
711 }
712
713 self.push("_");
714 }
715
716 ty::Ref(_, _, mutbl) => {
719 self.push(match mutbl {
720 hir::Mutability::Not => "R",
721 hir::Mutability::Mut => "Q",
722 });
723
724 let pointee_ty =
725 ct_ty.builtin_deref(true).expect("tried to dereference on non-ptr type");
726 let dereferenced_const = ty::Const::new_value(self.tcx, valtree, pointee_ty);
727 dereferenced_const.print(self)?;
728 }
729
730 ty::Array(..) | ty::Tuple(..) | ty::Adt(..) | ty::Slice(_) => {
731 let contents = self.tcx.destructure_const(ct);
732 let fields = contents.fields.iter().copied();
733
734 let print_field_list = |this: &mut Self| {
735 for field in fields.clone() {
736 field.print(this)?;
737 }
738 this.push("E");
739 Ok(())
740 };
741
742 match *ct_ty.kind() {
743 ty::Array(..) | ty::Slice(_) => {
744 self.push("A");
745 print_field_list(self)?;
746 }
747 ty::Tuple(..) => {
748 self.push("T");
749 print_field_list(self)?;
750 }
751 ty::Adt(def, args) => {
752 let variant_idx =
753 contents.variant.expect("destructed const of adt without variant idx");
754 let variant_def = &def.variant(variant_idx);
755
756 self.push("V");
757 self.print_def_path(variant_def.def_id, args)?;
758
759 match variant_def.ctor_kind() {
760 Some(CtorKind::Const) => {
761 self.push("U");
762 }
763 Some(CtorKind::Fn) => {
764 self.push("T");
765 print_field_list(self)?;
766 }
767 None => {
768 self.push("S");
769 for (field_def, field) in iter::zip(&variant_def.fields, fields) {
770 let disambiguated_field =
774 self.tcx.def_key(field_def.did).disambiguated_data;
775 let field_name = disambiguated_field.data.get_opt_name();
776 self.push_disambiguator(
777 disambiguated_field.disambiguator as u64,
778 );
779 self.push_ident(field_name.unwrap_or(kw::Empty).as_str());
780
781 field.print(self)?;
782 }
783 self.push("E");
784 }
785 }
786 }
787 _ => unreachable!(),
788 }
789 }
790 _ => {
791 bug!("symbol_names: unsupported constant of type `{}` ({:?})", ct_ty, ct);
792 }
793 }
794
795 if !ct.has_escaping_bound_vars() {
798 self.consts.insert(ct, start);
799 }
800 Ok(())
801 }
802
803 fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
804 self.push("C");
805 let stable_crate_id = self.tcx.def_path_hash(cnum.as_def_id()).stable_crate_id();
806 self.push_disambiguator(stable_crate_id.as_u64());
807 let name = self.tcx.crate_name(cnum);
808 self.push_ident(name.as_str());
809 Ok(())
810 }
811
812 fn path_qualified(
813 &mut self,
814 self_ty: Ty<'tcx>,
815 trait_ref: Option<ty::TraitRef<'tcx>>,
816 ) -> Result<(), PrintError> {
817 assert!(trait_ref.is_some());
818 let trait_ref = trait_ref.unwrap();
819
820 self.push("Y");
821 self_ty.print(self)?;
822 self.print_def_path(trait_ref.def_id, trait_ref.args)
823 }
824
825 fn path_append_impl(
826 &mut self,
827 _: impl FnOnce(&mut Self) -> Result<(), PrintError>,
828 _: &DisambiguatedDefPathData,
829 _: Ty<'tcx>,
830 _: Option<ty::TraitRef<'tcx>>,
831 ) -> Result<(), PrintError> {
832 unreachable!()
834 }
835
836 fn path_append(
837 &mut self,
838 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
839 disambiguated_data: &DisambiguatedDefPathData,
840 ) -> Result<(), PrintError> {
841 let ns = match disambiguated_data.data {
842 DefPathData::ForeignMod => return print_prefix(self),
845
846 DefPathData::TypeNs(_) => 't',
848 DefPathData::ValueNs(_) => 'v',
849 DefPathData::Closure => 'C',
850 DefPathData::Ctor => 'c',
851 DefPathData::AnonConst => 'k',
852 DefPathData::OpaqueTy => 'i',
853
854 DefPathData::CrateRoot
856 | DefPathData::Use
857 | DefPathData::GlobalAsm
858 | DefPathData::Impl
859 | DefPathData::MacroNs(_)
860 | DefPathData::LifetimeNs(_) => {
861 bug!("symbol_names: unexpected DefPathData: {:?}", disambiguated_data.data)
862 }
863 };
864
865 let name = disambiguated_data.data.get_opt_name();
866
867 self.path_append_ns(
868 print_prefix,
869 ns,
870 disambiguated_data.disambiguator as u64,
871 name.unwrap_or(kw::Empty).as_str(),
872 )
873 }
874
875 fn path_generic_args(
876 &mut self,
877 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
878 args: &[GenericArg<'tcx>],
879 ) -> Result<(), PrintError> {
880 let print_regions = args.iter().any(|arg| match arg.unpack() {
882 GenericArgKind::Lifetime(r) => !r.is_erased(),
883 _ => false,
884 });
885 let args = args.iter().cloned().filter(|arg| match arg.unpack() {
886 GenericArgKind::Lifetime(_) => print_regions,
887 _ => true,
888 });
889
890 if args.clone().next().is_none() {
891 return print_prefix(self);
892 }
893
894 self.push("I");
895 print_prefix(self)?;
896 for arg in args {
897 match arg.unpack() {
898 GenericArgKind::Lifetime(lt) => {
899 lt.print(self)?;
900 }
901 GenericArgKind::Type(ty) => {
902 ty.print(self)?;
903 }
904 GenericArgKind::Const(c) => {
905 self.push("K");
906 c.print(self)?;
907 }
908 }
909 }
910 self.push("E");
911
912 Ok(())
913 }
914}
915pub(crate) fn push_integer_62(x: u64, output: &mut String) {
921 if let Some(x) = x.checked_sub(1) {
922 output.push_str(&x.to_base(62));
923 }
924 output.push('_');
925}
926
927pub(crate) fn encode_integer_62(x: u64) -> String {
928 let mut output = String::new();
929 push_integer_62(x, &mut output);
930 output
931}
932
933pub(crate) fn push_ident(ident: &str, output: &mut String) {
934 let mut use_punycode = false;
935 for b in ident.bytes() {
936 match b {
937 b'_' | b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' => {}
938 0x80..=0xff => use_punycode = true,
939 _ => bug!("symbol_names: bad byte {} in ident {:?}", b, ident),
940 }
941 }
942
943 let punycode_string;
944 let ident = if use_punycode {
945 output.push('u');
946
947 let mut punycode_bytes = match punycode::encode(ident) {
949 Ok(s) => s.into_bytes(),
950 Err(()) => bug!("symbol_names: punycode encoding failed for ident {:?}", ident),
951 };
952
953 if let Some(c) = punycode_bytes.iter_mut().rfind(|&&mut c| c == b'-') {
955 *c = b'_';
956 }
957
958 punycode_string = String::from_utf8(punycode_bytes).unwrap();
960 &punycode_string
961 } else {
962 ident
963 };
964
965 let _ = write!(output, "{}", ident.len());
966
967 if let Some('_' | '0'..='9') = ident.chars().next() {
969 output.push('_');
970 }
971
972 output.push_str(ident);
973}