]>
Commit | Line | Data |
---|---|---|
dc9dc135 XL |
1 | use rustc::hir; |
2 | use rustc::hir::def_id::{CrateNum, DefId}; | |
3 | use rustc::hir::map::{DefPathData, DisambiguatedDefPathData}; | |
4 | use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, Instance}; | |
5 | use rustc::ty::print::{Printer, Print}; | |
e74abb32 | 6 | use rustc::ty::subst::{GenericArg, Subst, GenericArgKind}; |
dc9dc135 XL |
7 | use rustc_data_structures::base_n; |
8 | use rustc_data_structures::fx::{FxHashMap, FxHashSet}; | |
9 | use rustc_target::spec::abi::Abi; | |
10 | use syntax::ast::{IntTy, UintTy, FloatTy}; | |
11 | ||
12 | use std::fmt::Write; | |
13 | use std::ops::Range; | |
14 | ||
15 | pub(super) fn mangle( | |
16 | tcx: TyCtxt<'tcx>, | |
17 | instance: Instance<'tcx>, | |
18 | instantiating_crate: Option<CrateNum>, | |
19 | ) -> String { | |
20 | let def_id = instance.def_id(); | |
21 | // FIXME(eddyb) this should ideally not be needed. | |
22 | let substs = | |
23 | tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), instance.substs); | |
24 | ||
25 | let prefix = "_R"; | |
26 | let mut cx = SymbolMangler { | |
27 | tcx, | |
28 | compress: Some(Box::new(CompressionCaches { | |
29 | start_offset: prefix.len(), | |
30 | ||
31 | paths: FxHashMap::default(), | |
32 | types: FxHashMap::default(), | |
33 | consts: FxHashMap::default(), | |
34 | })), | |
35 | binders: vec![], | |
36 | out: String::from(prefix), | |
37 | }; | |
38 | cx = if instance.is_vtable_shim() { | |
39 | cx.path_append_ns( | |
40 | |cx| cx.print_def_path(def_id, substs), | |
41 | 'S', | |
42 | 0, | |
43 | "", | |
44 | ).unwrap() | |
45 | } else { | |
46 | cx.print_def_path(def_id, substs).unwrap() | |
47 | }; | |
48 | if let Some(instantiating_crate) = instantiating_crate { | |
49 | cx = cx.print_def_path(instantiating_crate.as_def_id(), &[]).unwrap(); | |
50 | } | |
51 | cx.out | |
52 | } | |
53 | ||
54 | struct CompressionCaches<'tcx> { | |
55 | // The length of the prefix in `out` (e.g. 2 for `_R`). | |
56 | start_offset: usize, | |
57 | ||
58 | // The values are start positions in `out`, in bytes. | |
e74abb32 | 59 | paths: FxHashMap<(DefId, &'tcx [GenericArg<'tcx>]), usize>, |
dc9dc135 XL |
60 | types: FxHashMap<Ty<'tcx>, usize>, |
61 | consts: FxHashMap<&'tcx ty::Const<'tcx>, usize>, | |
62 | } | |
63 | ||
64 | struct BinderLevel { | |
65 | /// The range of distances from the root of what's | |
66 | /// being printed, to the lifetimes in a binder. | |
67 | /// Specifically, a `BrAnon(i)` lifetime has depth | |
68 | /// `lifetime_depths.start + i`, going away from the | |
69 | /// the root and towards its use site, as `i` increases. | |
70 | /// This is used to flatten rustc's pairing of `BrAnon` | |
71 | /// (intra-binder disambiguation) with a `DebruijnIndex` | |
72 | /// (binder addressing), to "true" de Bruijn indices, | |
73 | /// by subtracting the depth of a certain lifetime, from | |
74 | /// the innermost depth at its use site. | |
75 | lifetime_depths: Range<u32>, | |
76 | } | |
77 | ||
78 | struct SymbolMangler<'tcx> { | |
79 | tcx: TyCtxt<'tcx>, | |
80 | compress: Option<Box<CompressionCaches<'tcx>>>, | |
81 | binders: Vec<BinderLevel>, | |
82 | out: String, | |
83 | } | |
84 | ||
85 | impl SymbolMangler<'tcx> { | |
86 | fn push(&mut self, s: &str) { | |
87 | self.out.push_str(s); | |
88 | } | |
89 | ||
90 | /// Push a `_`-terminated base 62 integer, using the format | |
91 | /// specified in the RFC as `<base-62-number>`, that is: | |
92 | /// * `x = 0` is encoded as just the `"_"` terminator | |
93 | /// * `x > 0` is encoded as `x - 1` in base 62, followed by `"_"`, | |
94 | /// e.g. `1` becomes `"0_"`, `62` becomes `"Z_"`, etc. | |
95 | fn push_integer_62(&mut self, x: u64) { | |
96 | if let Some(x) = x.checked_sub(1) { | |
97 | base_n::push_str(x as u128, 62, &mut self.out); | |
98 | } | |
99 | self.push("_"); | |
100 | } | |
101 | ||
102 | /// Push a `tag`-prefixed base 62 integer, when larger than `0`, that is: | |
103 | /// * `x = 0` is encoded as `""` (nothing) | |
104 | /// * `x > 0` is encoded as the `tag` followed by `push_integer_62(x - 1)` | |
105 | /// e.g. `1` becomes `tag + "_"`, `2` becomes `tag + "0_"`, etc. | |
106 | fn push_opt_integer_62(&mut self, tag: &str, x: u64) { | |
107 | if let Some(x) = x.checked_sub(1) { | |
108 | self.push(tag); | |
109 | self.push_integer_62(x); | |
110 | } | |
111 | } | |
112 | ||
113 | fn push_disambiguator(&mut self, dis: u64) { | |
114 | self.push_opt_integer_62("s", dis); | |
115 | } | |
116 | ||
117 | fn push_ident(&mut self, ident: &str) { | |
118 | let mut use_punycode = false; | |
119 | for b in ident.bytes() { | |
120 | match b { | |
121 | b'_' | b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' => {} | |
122 | 0x80..=0xff => use_punycode = true, | |
123 | _ => bug!("symbol_names: bad byte {} in ident {:?}", b, ident), | |
124 | } | |
125 | } | |
126 | ||
127 | let punycode_string; | |
128 | let ident = if use_punycode { | |
129 | self.push("u"); | |
130 | ||
131 | // FIXME(eddyb) we should probably roll our own punycode implementation. | |
132 | let mut punycode_bytes = match ::punycode::encode(ident) { | |
133 | Ok(s) => s.into_bytes(), | |
134 | Err(()) => bug!("symbol_names: punycode encoding failed for ident {:?}", ident), | |
135 | }; | |
136 | ||
137 | // Replace `-` with `_`. | |
138 | if let Some(c) = punycode_bytes.iter_mut().rfind(|&&mut c| c == b'-') { | |
139 | *c = b'_'; | |
140 | } | |
141 | ||
142 | // FIXME(eddyb) avoid rechecking UTF-8 validity. | |
143 | punycode_string = String::from_utf8(punycode_bytes).unwrap(); | |
144 | &punycode_string | |
145 | } else { | |
146 | ident | |
147 | }; | |
148 | ||
149 | let _ = write!(self.out, "{}", ident.len()); | |
150 | ||
151 | // Write a separating `_` if necessary (leading digit or `_`). | |
152 | match ident.chars().next() { | |
153 | Some('_') | Some('0'..='9') => { | |
154 | self.push("_"); | |
155 | } | |
156 | _ => {} | |
157 | } | |
158 | ||
159 | self.push(ident); | |
160 | } | |
161 | ||
162 | fn path_append_ns( | |
163 | mut self, | |
164 | print_prefix: impl FnOnce(Self) -> Result<Self, !>, | |
165 | ns: char, | |
166 | disambiguator: u64, | |
167 | name: &str, | |
168 | ) -> Result<Self, !> { | |
169 | self.push("N"); | |
170 | self.out.push(ns); | |
171 | self = print_prefix(self)?; | |
172 | self.push_disambiguator(disambiguator as u64); | |
173 | self.push_ident(name); | |
174 | Ok(self) | |
175 | } | |
176 | ||
177 | fn print_backref(mut self, i: usize) -> Result<Self, !> { | |
178 | self.push("B"); | |
179 | self.push_integer_62((i - self.compress.as_ref().unwrap().start_offset) as u64); | |
180 | Ok(self) | |
181 | } | |
182 | ||
183 | fn in_binder<T>( | |
184 | mut self, | |
185 | value: &ty::Binder<T>, | |
186 | print_value: impl FnOnce(Self, &T) -> Result<Self, !> | |
187 | ) -> Result<Self, !> | |
188 | where T: TypeFoldable<'tcx> | |
189 | { | |
190 | let regions = if value.has_late_bound_regions() { | |
191 | self.tcx.collect_referenced_late_bound_regions(value) | |
192 | } else { | |
193 | FxHashSet::default() | |
194 | }; | |
195 | ||
196 | let mut lifetime_depths = | |
197 | self.binders.last().map(|b| b.lifetime_depths.end).map_or(0..0, |i| i..i); | |
198 | ||
199 | let lifetimes = regions.into_iter().map(|br| { | |
200 | match br { | |
e1599b0c XL |
201 | ty::BrAnon(i) => { |
202 | // FIXME(eddyb) for some reason, `anonymize_late_bound_regions` starts at `1`. | |
203 | assert_ne!(i, 0); | |
204 | i - 1 | |
205 | }, | |
dc9dc135 XL |
206 | _ => bug!("symbol_names: non-anonymized region `{:?}` in `{:?}`", br, value), |
207 | } | |
e1599b0c | 208 | }).max().map_or(0, |max| max + 1); |
dc9dc135 XL |
209 | |
210 | self.push_opt_integer_62("G", lifetimes as u64); | |
211 | lifetime_depths.end += lifetimes; | |
212 | ||
213 | self.binders.push(BinderLevel { lifetime_depths }); | |
214 | self = print_value(self, value.skip_binder())?; | |
215 | self.binders.pop(); | |
216 | ||
217 | Ok(self) | |
218 | } | |
219 | } | |
220 | ||
221 | impl Printer<'tcx> for SymbolMangler<'tcx> { | |
222 | type Error = !; | |
223 | ||
224 | type Path = Self; | |
225 | type Region = Self; | |
226 | type Type = Self; | |
227 | type DynExistential = Self; | |
228 | type Const = Self; | |
229 | ||
230 | fn tcx(&self) -> TyCtxt<'tcx> { | |
231 | self.tcx | |
232 | } | |
233 | ||
234 | fn print_def_path( | |
235 | mut self, | |
236 | def_id: DefId, | |
e74abb32 | 237 | substs: &'tcx [GenericArg<'tcx>], |
dc9dc135 XL |
238 | ) -> Result<Self::Path, Self::Error> { |
239 | if let Some(&i) = self.compress.as_ref().and_then(|c| c.paths.get(&(def_id, substs))) { | |
240 | return self.print_backref(i); | |
241 | } | |
242 | let start = self.out.len(); | |
243 | ||
244 | self = self.default_print_def_path(def_id, substs)?; | |
245 | ||
246 | // Only cache paths that do not refer to an enclosing | |
247 | // binder (which would change depending on context). | |
248 | if !substs.iter().any(|k| k.has_escaping_bound_vars()) { | |
249 | if let Some(c) = &mut self.compress { | |
250 | c.paths.insert((def_id, substs), start); | |
251 | } | |
252 | } | |
253 | Ok(self) | |
254 | } | |
255 | ||
256 | fn print_impl_path( | |
257 | self, | |
258 | impl_def_id: DefId, | |
e74abb32 | 259 | substs: &'tcx [GenericArg<'tcx>], |
dc9dc135 XL |
260 | mut self_ty: Ty<'tcx>, |
261 | mut impl_trait_ref: Option<ty::TraitRef<'tcx>>, | |
262 | ) -> Result<Self::Path, Self::Error> { | |
263 | let key = self.tcx.def_key(impl_def_id); | |
264 | let parent_def_id = DefId { index: key.parent.unwrap(), ..impl_def_id }; | |
265 | ||
266 | let mut param_env = self.tcx.param_env(impl_def_id) | |
267 | .with_reveal_all(); | |
268 | if !substs.is_empty() { | |
269 | param_env = param_env.subst(self.tcx, substs); | |
270 | } | |
271 | ||
272 | match &mut impl_trait_ref { | |
273 | Some(impl_trait_ref) => { | |
274 | assert_eq!(impl_trait_ref.self_ty(), self_ty); | |
275 | *impl_trait_ref = | |
276 | self.tcx.normalize_erasing_regions(param_env, *impl_trait_ref); | |
277 | self_ty = impl_trait_ref.self_ty(); | |
278 | } | |
279 | None => { | |
280 | self_ty = self.tcx.normalize_erasing_regions(param_env, self_ty); | |
281 | } | |
282 | } | |
283 | ||
284 | self.path_append_impl( | |
285 | |cx| cx.print_def_path(parent_def_id, &[]), | |
286 | &key.disambiguated_data, | |
287 | self_ty, | |
288 | impl_trait_ref, | |
289 | ) | |
290 | } | |
291 | ||
292 | fn print_region( | |
293 | mut self, | |
294 | region: ty::Region<'_>, | |
295 | ) -> Result<Self::Region, Self::Error> { | |
296 | let i = match *region { | |
297 | // Erased lifetimes use the index 0, for a | |
298 | // shorter mangling of `L_`. | |
299 | ty::ReErased => 0, | |
300 | ||
301 | // Late-bound lifetimes use indices starting at 1, | |
302 | // see `BinderLevel` for more details. | |
303 | ty::ReLateBound(debruijn, ty::BrAnon(i)) => { | |
e1599b0c XL |
304 | // FIXME(eddyb) for some reason, `anonymize_late_bound_regions` starts at `1`. |
305 | assert_ne!(i, 0); | |
306 | let i = i - 1; | |
307 | ||
dc9dc135 XL |
308 | let binder = &self.binders[self.binders.len() - 1 - debruijn.index()]; |
309 | let depth = binder.lifetime_depths.start + i; | |
310 | ||
311 | 1 + (self.binders.last().unwrap().lifetime_depths.end - 1 - depth) | |
312 | } | |
313 | ||
314 | _ => bug!("symbol_names: non-erased region `{:?}`", region), | |
315 | }; | |
316 | self.push("L"); | |
317 | self.push_integer_62(i as u64); | |
318 | Ok(self) | |
319 | } | |
320 | ||
321 | fn print_type( | |
322 | mut self, | |
323 | ty: Ty<'tcx>, | |
324 | ) -> Result<Self::Type, Self::Error> { | |
325 | // Basic types, never cached (single-character). | |
e74abb32 | 326 | let basic_type = match ty.kind { |
dc9dc135 XL |
327 | ty::Bool => "b", |
328 | ty::Char => "c", | |
329 | ty::Str => "e", | |
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", | |
345 | ty::Never => "z", | |
346 | ||
347 | // Placeholders (should be demangled as `_`). | |
348 | ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | | |
349 | ty::Infer(_) | ty::Error => "p", | |
350 | ||
351 | _ => "", | |
352 | }; | |
353 | if !basic_type.is_empty() { | |
354 | self.push(basic_type); | |
355 | return Ok(self); | |
356 | } | |
357 | ||
358 | if let Some(&i) = self.compress.as_ref().and_then(|c| c.types.get(&ty)) { | |
359 | return self.print_backref(i); | |
360 | } | |
361 | let start = self.out.len(); | |
362 | ||
e74abb32 | 363 | match ty.kind { |
dc9dc135 XL |
364 | // Basic types, handled above. |
365 | ty::Bool | ty::Char | ty::Str | | |
366 | ty::Int(_) | ty::Uint(_) | ty::Float(_) | | |
367 | ty::Never => unreachable!(), | |
368 | ty::Tuple(_) if ty.is_unit() => unreachable!(), | |
369 | ||
370 | // Placeholders, also handled as part of basic types. | |
371 | ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | | |
372 | ty::Infer(_) | ty::Error => unreachable!(), | |
373 | ||
374 | ty::Ref(r, ty, mutbl) => { | |
375 | self.push(match mutbl { | |
60c5eb7d XL |
376 | hir::Mutability::Immutable => "R", |
377 | hir::Mutability::Mutable => "Q", | |
dc9dc135 XL |
378 | }); |
379 | if *r != ty::ReErased { | |
380 | self = r.print(self)?; | |
381 | } | |
382 | self = ty.print(self)?; | |
383 | } | |
384 | ||
385 | ty::RawPtr(mt) => { | |
386 | self.push(match mt.mutbl { | |
60c5eb7d XL |
387 | hir::Mutability::Immutable => "P", |
388 | hir::Mutability::Mutable => "O", | |
dc9dc135 XL |
389 | }); |
390 | self = mt.ty.print(self)?; | |
391 | } | |
392 | ||
393 | ty::Array(ty, len) => { | |
394 | self.push("A"); | |
395 | self = ty.print(self)?; | |
396 | self = self.print_const(len)?; | |
397 | } | |
398 | ty::Slice(ty) => { | |
399 | self.push("S"); | |
400 | self = ty.print(self)?; | |
401 | } | |
402 | ||
403 | ty::Tuple(tys) => { | |
404 | self.push("T"); | |
405 | for ty in tys.iter().map(|k| k.expect_ty()) { | |
406 | self = ty.print(self)?; | |
407 | } | |
408 | self.push("E"); | |
409 | } | |
410 | ||
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 }) | | |
e74abb32 XL |
417 | ty::Closure(def_id, substs) | |
418 | ty::Generator(def_id, substs, _) => { | |
dc9dc135 XL |
419 | self = self.print_def_path(def_id, substs)?; |
420 | } | |
421 | ty::Foreign(def_id) => { | |
422 | self = self.print_def_path(def_id, &[])?; | |
423 | } | |
424 | ||
425 | ty::FnPtr(sig) => { | |
426 | self.push("F"); | |
427 | self = self.in_binder(&sig, |mut cx, sig| { | |
428 | if sig.unsafety == hir::Unsafety::Unsafe { | |
429 | cx.push("U"); | |
430 | } | |
431 | match sig.abi { | |
432 | Abi::Rust => {} | |
433 | Abi::C => cx.push("KC"), | |
434 | abi => { | |
435 | cx.push("K"); | |
436 | let name = abi.name(); | |
437 | if name.contains('-') { | |
438 | cx.push_ident(&name.replace('-', "_")); | |
439 | } else { | |
440 | cx.push_ident(name); | |
441 | } | |
442 | } | |
443 | } | |
444 | for &ty in sig.inputs() { | |
445 | cx = ty.print(cx)?; | |
446 | } | |
447 | if sig.c_variadic { | |
448 | cx.push("v"); | |
449 | } | |
450 | cx.push("E"); | |
451 | sig.output().print(cx) | |
452 | })?; | |
453 | } | |
454 | ||
455 | ty::Dynamic(predicates, r) => { | |
456 | self.push("D"); | |
457 | self = self.in_binder(&predicates, |cx, predicates| { | |
458 | cx.print_dyn_existential(predicates) | |
459 | })?; | |
460 | self = r.print(self)?; | |
461 | } | |
462 | ||
463 | ty::GeneratorWitness(_) => { | |
464 | bug!("symbol_names: unexpected `GeneratorWitness`") | |
465 | } | |
466 | } | |
467 | ||
468 | // Only cache types that do not refer to an enclosing | |
469 | // binder (which would change depending on context). | |
470 | if !ty.has_escaping_bound_vars() { | |
471 | if let Some(c) = &mut self.compress { | |
472 | c.types.insert(ty, start); | |
473 | } | |
474 | } | |
475 | Ok(self) | |
476 | } | |
477 | ||
478 | fn print_dyn_existential( | |
479 | mut self, | |
480 | predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>, | |
481 | ) -> Result<Self::DynExistential, Self::Error> { | |
482 | for predicate in predicates { | |
483 | match *predicate { | |
484 | ty::ExistentialPredicate::Trait(trait_ref) => { | |
485 | // Use a type that can't appear in defaults of type parameters. | |
486 | let dummy_self = self.tcx.mk_ty_infer(ty::FreshTy(0)); | |
487 | let trait_ref = trait_ref.with_self_ty(self.tcx, dummy_self); | |
488 | self = self.print_def_path(trait_ref.def_id, trait_ref.substs)?; | |
489 | } | |
490 | ty::ExistentialPredicate::Projection(projection) => { | |
491 | let name = self.tcx.associated_item(projection.item_def_id).ident; | |
492 | self.push("p"); | |
493 | self.push_ident(&name.as_str()); | |
494 | self = projection.ty.print(self)?; | |
495 | } | |
496 | ty::ExistentialPredicate::AutoTrait(def_id) => { | |
497 | self = self.print_def_path(def_id, &[])?; | |
498 | } | |
499 | } | |
500 | } | |
501 | self.push("E"); | |
502 | Ok(self) | |
503 | } | |
504 | ||
505 | fn print_const( | |
506 | mut self, | |
507 | ct: &'tcx ty::Const<'tcx>, | |
508 | ) -> Result<Self::Const, Self::Error> { | |
509 | if let Some(&i) = self.compress.as_ref().and_then(|c| c.consts.get(&ct)) { | |
510 | return self.print_backref(i); | |
511 | } | |
512 | let start = self.out.len(); | |
513 | ||
e74abb32 | 514 | match ct.ty.kind { |
dc9dc135 XL |
515 | ty::Uint(_) => {} |
516 | _ => { | |
517 | bug!("symbol_names: unsupported constant of type `{}` ({:?})", | |
518 | ct.ty, ct); | |
519 | } | |
520 | } | |
521 | self = ct.ty.print(self)?; | |
522 | ||
416331ca | 523 | if let Some(bits) = ct.try_eval_bits(self.tcx, ty::ParamEnv::reveal_all(), ct.ty) { |
dc9dc135 XL |
524 | let _ = write!(self.out, "{:x}_", bits); |
525 | } else { | |
526 | // NOTE(eddyb) despite having the path, we need to | |
527 | // encode a placeholder, as the path could refer | |
528 | // back to e.g. an `impl` using the constant. | |
529 | self.push("p"); | |
530 | } | |
531 | ||
532 | // Only cache consts that do not refer to an enclosing | |
533 | // binder (which would change depending on context). | |
534 | if !ct.has_escaping_bound_vars() { | |
535 | if let Some(c) = &mut self.compress { | |
536 | c.consts.insert(ct, start); | |
537 | } | |
538 | } | |
539 | Ok(self) | |
540 | } | |
541 | ||
542 | fn path_crate( | |
543 | mut self, | |
544 | cnum: CrateNum, | |
545 | ) -> Result<Self::Path, Self::Error> { | |
546 | self.push("C"); | |
547 | let fingerprint = self.tcx.crate_disambiguator(cnum).to_fingerprint(); | |
548 | self.push_disambiguator(fingerprint.to_smaller_hash()); | |
549 | let name = self.tcx.original_crate_name(cnum).as_str(); | |
550 | self.push_ident(&name); | |
551 | Ok(self) | |
552 | } | |
553 | fn path_qualified( | |
554 | mut self, | |
555 | self_ty: Ty<'tcx>, | |
556 | trait_ref: Option<ty::TraitRef<'tcx>>, | |
557 | ) -> Result<Self::Path, Self::Error> { | |
558 | assert!(trait_ref.is_some()); | |
559 | let trait_ref = trait_ref.unwrap(); | |
560 | ||
561 | self.push("Y"); | |
562 | self = self_ty.print(self)?; | |
563 | self.print_def_path(trait_ref.def_id, trait_ref.substs) | |
564 | } | |
565 | ||
566 | fn path_append_impl( | |
567 | mut self, | |
568 | print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, | |
569 | disambiguated_data: &DisambiguatedDefPathData, | |
570 | self_ty: Ty<'tcx>, | |
571 | trait_ref: Option<ty::TraitRef<'tcx>>, | |
572 | ) -> Result<Self::Path, Self::Error> { | |
573 | self.push(match trait_ref { | |
574 | Some(_) => "X", | |
575 | None => "M", | |
576 | }); | |
577 | self.push_disambiguator(disambiguated_data.disambiguator as u64); | |
578 | self = print_prefix(self)?; | |
579 | self = self_ty.print(self)?; | |
580 | if let Some(trait_ref) = trait_ref { | |
581 | self = self.print_def_path(trait_ref.def_id, trait_ref.substs)?; | |
582 | } | |
583 | Ok(self) | |
584 | } | |
585 | fn path_append( | |
586 | self, | |
587 | print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, | |
588 | disambiguated_data: &DisambiguatedDefPathData, | |
589 | ) -> Result<Self::Path, Self::Error> { | |
590 | let ns = match disambiguated_data.data { | |
591 | // Uppercase categories are more stable than lowercase ones. | |
592 | DefPathData::TypeNs(_) => 't', | |
593 | DefPathData::ValueNs(_) => 'v', | |
594 | DefPathData::ClosureExpr => 'C', | |
595 | DefPathData::Ctor => 'c', | |
596 | DefPathData::AnonConst => 'k', | |
597 | DefPathData::ImplTrait => 'i', | |
598 | ||
599 | // These should never show up as `path_append` arguments. | |
600 | DefPathData::CrateRoot | |
601 | | DefPathData::Misc | |
602 | | DefPathData::Impl | |
603 | | DefPathData::MacroNs(_) | |
60c5eb7d | 604 | | DefPathData::LifetimeNs(_) => { |
dc9dc135 XL |
605 | bug!("symbol_names: unexpected DefPathData: {:?}", disambiguated_data.data) |
606 | } | |
607 | }; | |
608 | ||
609 | let name = disambiguated_data.data.get_opt_name().map(|s| s.as_str()); | |
610 | ||
611 | self.path_append_ns( | |
612 | print_prefix, | |
613 | ns, | |
614 | disambiguated_data.disambiguator as u64, | |
615 | name.as_ref().map_or("", |s| &s[..]) | |
616 | ) | |
617 | } | |
618 | fn path_generic_args( | |
619 | mut self, | |
620 | print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, | |
e74abb32 | 621 | args: &[GenericArg<'tcx>], |
dc9dc135 XL |
622 | ) -> Result<Self::Path, Self::Error> { |
623 | // Don't print any regions if they're all erased. | |
624 | let print_regions = args.iter().any(|arg| { | |
625 | match arg.unpack() { | |
e74abb32 | 626 | GenericArgKind::Lifetime(r) => *r != ty::ReErased, |
dc9dc135 XL |
627 | _ => false, |
628 | } | |
629 | }); | |
630 | let args = args.iter().cloned().filter(|arg| { | |
631 | match arg.unpack() { | |
e74abb32 | 632 | GenericArgKind::Lifetime(_) => print_regions, |
dc9dc135 XL |
633 | _ => true, |
634 | } | |
635 | }); | |
636 | ||
637 | if args.clone().next().is_none() { | |
638 | return print_prefix(self); | |
639 | } | |
640 | ||
641 | self.push("I"); | |
642 | self = print_prefix(self)?; | |
643 | for arg in args { | |
644 | match arg.unpack() { | |
e74abb32 | 645 | GenericArgKind::Lifetime(lt) => { |
dc9dc135 XL |
646 | self = lt.print(self)?; |
647 | } | |
e74abb32 | 648 | GenericArgKind::Type(ty) => { |
dc9dc135 XL |
649 | self = ty.print(self)?; |
650 | } | |
e74abb32 | 651 | GenericArgKind::Const(c) => { |
dc9dc135 XL |
652 | self.push("K"); |
653 | // FIXME(const_generics) implement `ty::print::Print` on `ty::Const`. | |
654 | // self = c.print(self)?; | |
655 | self = self.print_const(c)?; | |
656 | } | |
657 | } | |
658 | } | |
659 | self.push("E"); | |
660 | ||
661 | Ok(self) | |
662 | } | |
663 | } |