11
11
// within the brackets).
12
12
// * `"` is treated as the start of a string.
13
13
14
- use rustc_data_structures:: fx:: FxHashSet ;
14
+ use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
15
15
use rustc_data_structures:: stable_hasher:: { HashStable , StableHasher } ;
16
16
use rustc_hir as hir;
17
17
use rustc_hir:: def_id:: DefId ;
@@ -33,12 +33,18 @@ pub fn compute_debuginfo_type_name<'tcx>(
33
33
tcx : TyCtxt < ' tcx > ,
34
34
t : Ty < ' tcx > ,
35
35
qualified : bool ,
36
+ type_name_cache : & mut FxHashMap < ( Ty < ' tcx > , bool ) , String > ,
36
37
) -> String {
37
38
let _prof = tcx. prof . generic_activity ( "compute_debuginfo_type_name" ) ;
38
39
40
+ // Check if we have seen this type and qualifier before.
41
+ if let Some ( type_name) = type_name_cache. get ( & ( & t, qualified) ) {
42
+ return type_name. clone ( ) ;
43
+ }
44
+
39
45
let mut result = String :: with_capacity ( 64 ) ;
40
46
let mut visited = FxHashSet :: default ( ) ;
41
- push_debuginfo_type_name ( tcx, t, qualified, & mut result, & mut visited) ;
47
+ push_debuginfo_type_name ( tcx, t, qualified, & mut result, & mut visited, type_name_cache ) ;
42
48
result
43
49
}
44
50
@@ -50,6 +56,7 @@ fn push_debuginfo_type_name<'tcx>(
50
56
qualified : bool ,
51
57
output : & mut String ,
52
58
visited : & mut FxHashSet < Ty < ' tcx > > ,
59
+ type_name_cache : & mut FxHashMap < ( Ty < ' tcx > , bool ) , String > ,
53
60
) {
54
61
// When targeting MSVC, emit C++ style type names for compatibility with
55
62
// .natvis visualizers (and perhaps other existing native debuggers?)
@@ -72,10 +79,10 @@ fn push_debuginfo_type_name<'tcx>(
72
79
ty:: Foreign ( def_id) => push_item_name ( tcx, def_id, qualified, output) ,
73
80
ty:: Adt ( def, substs) => {
74
81
if def. is_enum ( ) && cpp_like_names {
75
- msvc_enum_fallback ( tcx, t, def, substs, output, visited) ;
82
+ msvc_enum_fallback ( tcx, t, def, substs, output, visited, type_name_cache ) ;
76
83
} else {
77
84
push_item_name ( tcx, def. did , qualified, output) ;
78
- push_generic_params_internal ( tcx, substs, output, visited) ;
85
+ push_generic_params_internal ( tcx, substs, output, visited, type_name_cache ) ;
79
86
}
80
87
}
81
88
ty:: Tuple ( component_types) => {
@@ -86,7 +93,14 @@ fn push_debuginfo_type_name<'tcx>(
86
93
}
87
94
88
95
for component_type in component_types {
89
- push_debuginfo_type_name ( tcx, component_type. expect_ty ( ) , true , output, visited) ;
96
+ push_debuginfo_type_name (
97
+ tcx,
98
+ component_type. expect_ty ( ) ,
99
+ true ,
100
+ output,
101
+ visited,
102
+ type_name_cache,
103
+ ) ;
90
104
push_arg_separator ( cpp_like_names, output) ;
91
105
}
92
106
if !component_types. is_empty ( ) {
@@ -113,7 +127,7 @@ fn push_debuginfo_type_name<'tcx>(
113
127
}
114
128
}
115
129
116
- push_debuginfo_type_name ( tcx, inner_type, qualified, output, visited) ;
130
+ push_debuginfo_type_name ( tcx, inner_type, qualified, output, visited, type_name_cache ) ;
117
131
118
132
if cpp_like_names {
119
133
push_close_angle_bracket ( cpp_like_names, output) ;
@@ -139,7 +153,7 @@ fn push_debuginfo_type_name<'tcx>(
139
153
}
140
154
}
141
155
142
- push_debuginfo_type_name ( tcx, inner_type, qualified, output, visited) ;
156
+ push_debuginfo_type_name ( tcx, inner_type, qualified, output, visited, type_name_cache ) ;
143
157
144
158
if cpp_like_names && !is_slice_or_str {
145
159
push_close_angle_bracket ( cpp_like_names, output) ;
@@ -148,15 +162,15 @@ fn push_debuginfo_type_name<'tcx>(
148
162
ty:: Array ( inner_type, len) => {
149
163
if cpp_like_names {
150
164
output. push_str ( "array$<" ) ;
151
- push_debuginfo_type_name ( tcx, inner_type, true , output, visited) ;
165
+ push_debuginfo_type_name ( tcx, inner_type, true , output, visited, type_name_cache ) ;
152
166
match len. val {
153
167
ty:: ConstKind :: Param ( param) => write ! ( output, ",{}>" , param. name) . unwrap ( ) ,
154
168
_ => write ! ( output, ",{}>" , len. eval_usize( tcx, ty:: ParamEnv :: reveal_all( ) ) )
155
169
. unwrap ( ) ,
156
170
}
157
171
} else {
158
172
output. push ( '[' ) ;
159
- push_debuginfo_type_name ( tcx, inner_type, true , output, visited) ;
173
+ push_debuginfo_type_name ( tcx, inner_type, true , output, visited, type_name_cache ) ;
160
174
match len. val {
161
175
ty:: ConstKind :: Param ( param) => write ! ( output, "; {}]" , param. name) . unwrap ( ) ,
162
176
_ => write ! ( output, "; {}]" , len. eval_usize( tcx, ty:: ParamEnv :: reveal_all( ) ) )
@@ -171,7 +185,7 @@ fn push_debuginfo_type_name<'tcx>(
171
185
output. push ( '[' ) ;
172
186
}
173
187
174
- push_debuginfo_type_name ( tcx, inner_type, true , output, visited) ;
188
+ push_debuginfo_type_name ( tcx, inner_type, true , output, visited, type_name_cache ) ;
175
189
176
190
if cpp_like_names {
177
191
push_close_angle_bracket ( cpp_like_names, output) ;
@@ -200,8 +214,13 @@ fn push_debuginfo_type_name<'tcx>(
200
214
let principal =
201
215
tcx. normalize_erasing_late_bound_regions ( ty:: ParamEnv :: reveal_all ( ) , principal) ;
202
216
push_item_name ( tcx, principal. def_id , qualified, output) ;
203
- let principal_has_generic_params =
204
- push_generic_params_internal ( tcx, principal. substs , output, visited) ;
217
+ let principal_has_generic_params = push_generic_params_internal (
218
+ tcx,
219
+ principal. substs ,
220
+ output,
221
+ visited,
222
+ type_name_cache,
223
+ ) ;
205
224
206
225
let projection_bounds: SmallVec < [ _ ; 4 ] > = trait_data
207
226
. projection_bounds ( )
@@ -225,12 +244,26 @@ fn push_debuginfo_type_name<'tcx>(
225
244
output. push_str ( "assoc$<" ) ;
226
245
push_item_name ( tcx, item_def_id, false , output) ;
227
246
push_arg_separator ( cpp_like_names, output) ;
228
- push_debuginfo_type_name ( tcx, ty, true , output, visited) ;
247
+ push_debuginfo_type_name (
248
+ tcx,
249
+ ty,
250
+ true ,
251
+ output,
252
+ visited,
253
+ type_name_cache,
254
+ ) ;
229
255
push_close_angle_bracket ( cpp_like_names, output) ;
230
256
} else {
231
257
push_item_name ( tcx, item_def_id, false , output) ;
232
258
output. push ( '=' ) ;
233
- push_debuginfo_type_name ( tcx, ty, true , output, visited) ;
259
+ push_debuginfo_type_name (
260
+ tcx,
261
+ ty,
262
+ true ,
263
+ output,
264
+ visited,
265
+ type_name_cache,
266
+ ) ;
234
267
}
235
268
}
236
269
@@ -298,7 +331,14 @@ fn push_debuginfo_type_name<'tcx>(
298
331
if sig. output ( ) . is_unit ( ) {
299
332
output. push_str ( "void" ) ;
300
333
} else {
301
- push_debuginfo_type_name ( tcx, sig. output ( ) , true , output, visited) ;
334
+ push_debuginfo_type_name (
335
+ tcx,
336
+ sig. output ( ) ,
337
+ true ,
338
+ output,
339
+ visited,
340
+ type_name_cache,
341
+ ) ;
302
342
}
303
343
output. push_str ( " (*)(" ) ;
304
344
} else {
@@ -315,7 +355,14 @@ fn push_debuginfo_type_name<'tcx>(
315
355
316
356
if !sig. inputs ( ) . is_empty ( ) {
317
357
for & parameter_type in sig. inputs ( ) {
318
- push_debuginfo_type_name ( tcx, parameter_type, true , output, visited) ;
358
+ push_debuginfo_type_name (
359
+ tcx,
360
+ parameter_type,
361
+ true ,
362
+ output,
363
+ visited,
364
+ type_name_cache,
365
+ ) ;
319
366
push_arg_separator ( cpp_like_names, output) ;
320
367
}
321
368
pop_arg_separator ( output) ;
@@ -333,7 +380,7 @@ fn push_debuginfo_type_name<'tcx>(
333
380
334
381
if !cpp_like_names && !sig. output ( ) . is_unit ( ) {
335
382
output. push_str ( " -> " ) ;
336
- push_debuginfo_type_name ( tcx, sig. output ( ) , true , output, visited) ;
383
+ push_debuginfo_type_name ( tcx, sig. output ( ) , true , output, visited, type_name_cache ) ;
337
384
}
338
385
339
386
// We only keep the type in 'visited'
@@ -375,6 +422,10 @@ fn push_debuginfo_type_name<'tcx>(
375
422
}
376
423
}
377
424
425
+ if type_name_cache. insert ( ( & t, qualified) , output. clone ( ) ) . is_some ( ) {
426
+ bug ! ( "type name is already in the type name cache!" ) ;
427
+ }
428
+
378
429
/// MSVC names enums differently than other platforms so that the debugging visualization
379
430
// format (natvis) is able to understand enums and render the active variant correctly in the
380
431
// debugger. For more information, look in `src/etc/natvis/intrinsic.natvis` and
@@ -386,12 +437,13 @@ fn push_debuginfo_type_name<'tcx>(
386
437
substs : SubstsRef < ' tcx > ,
387
438
output : & mut String ,
388
439
visited : & mut FxHashSet < Ty < ' tcx > > ,
440
+ type_name_cache : & mut FxHashMap < ( Ty < ' tcx > , bool ) , String > ,
389
441
) {
390
442
let layout = tcx. layout_of ( tcx. param_env ( def. did ) . and ( ty) ) . expect ( "layout error" ) ;
391
443
392
444
output. push_str ( "enum$<" ) ;
393
445
push_item_name ( tcx, def. did , true , output) ;
394
- push_generic_params_internal ( tcx, substs, output, visited) ;
446
+ push_generic_params_internal ( tcx, substs, output, visited, type_name_cache ) ;
395
447
396
448
if let Variants :: Multiple {
397
449
tag_encoding : TagEncoding :: Niche { dataful_variant, .. } ,
@@ -503,6 +555,7 @@ fn push_generic_params_internal<'tcx>(
503
555
substs : SubstsRef < ' tcx > ,
504
556
output : & mut String ,
505
557
visited : & mut FxHashSet < Ty < ' tcx > > ,
558
+ type_name_cache : & mut FxHashMap < ( Ty < ' tcx > , bool ) , String > ,
506
559
) -> bool {
507
560
if substs. non_erasable_generics ( ) . next ( ) . is_none ( ) {
508
561
return false ;
@@ -517,7 +570,14 @@ fn push_generic_params_internal<'tcx>(
517
570
for type_parameter in substs. non_erasable_generics ( ) {
518
571
match type_parameter {
519
572
GenericArgKind :: Type ( type_parameter) => {
520
- push_debuginfo_type_name ( tcx, type_parameter, true , output, visited) ;
573
+ push_debuginfo_type_name (
574
+ tcx,
575
+ type_parameter,
576
+ true ,
577
+ output,
578
+ visited,
579
+ type_name_cache,
580
+ ) ;
521
581
}
522
582
GenericArgKind :: Const ( ct) => {
523
583
push_const_param ( tcx, ct, output) ;
@@ -578,10 +638,15 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: &'tcx ty::Const<'tcx>, output:
578
638
. unwrap ( ) ;
579
639
}
580
640
581
- pub fn push_generic_params < ' tcx > ( tcx : TyCtxt < ' tcx > , substs : SubstsRef < ' tcx > , output : & mut String ) {
641
+ pub fn push_generic_params < ' tcx > (
642
+ tcx : TyCtxt < ' tcx > ,
643
+ substs : SubstsRef < ' tcx > ,
644
+ output : & mut String ,
645
+ type_name_cache : & mut FxHashMap < ( Ty < ' tcx > , bool ) , String > ,
646
+ ) {
582
647
let _prof = tcx. prof . generic_activity ( "compute_debuginfo_type_name" ) ;
583
648
let mut visited = FxHashSet :: default ( ) ;
584
- push_generic_params_internal ( tcx, substs, output, & mut visited) ;
649
+ push_generic_params_internal ( tcx, substs, output, & mut visited, type_name_cache ) ;
585
650
}
586
651
587
652
fn push_close_angle_bracket ( cpp_like_names : bool , output : & mut String ) {
0 commit comments