@@ -19,8 +19,9 @@ use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathD
19
19
use rustc_middle:: ich:: NodeIdHashingMode ;
20
20
use rustc_middle:: ty:: layout:: IntegerExt ;
21
21
use rustc_middle:: ty:: subst:: { GenericArgKind , SubstsRef } ;
22
- use rustc_middle:: ty:: { self , AdtDef , Ty , TyCtxt } ;
22
+ use rustc_middle:: ty:: { self , AdtDef , ExistentialProjection , Ty , TyCtxt } ;
23
23
use rustc_target:: abi:: { Integer , TagEncoding , Variants } ;
24
+ use smallvec:: SmallVec ;
24
25
25
26
use std:: fmt:: Write ;
26
27
@@ -33,6 +34,8 @@ pub fn compute_debuginfo_type_name<'tcx>(
33
34
t : Ty < ' tcx > ,
34
35
qualified : bool ,
35
36
) -> String {
37
+ let _prof = tcx. prof . generic_activity ( "compute_debuginfo_type_name" ) ;
38
+
36
39
let mut result = String :: with_capacity ( 64 ) ;
37
40
let mut visited = FxHashSet :: default ( ) ;
38
41
push_debuginfo_type_name ( tcx, t, qualified, & mut result, & mut visited) ;
@@ -41,7 +44,7 @@ pub fn compute_debuginfo_type_name<'tcx>(
41
44
42
45
// Pushes the name of the type as it should be stored in debuginfo on the
43
46
// `output` String. See also compute_debuginfo_type_name().
44
- pub fn push_debuginfo_type_name < ' tcx > (
47
+ fn push_debuginfo_type_name < ' tcx > (
45
48
tcx : TyCtxt < ' tcx > ,
46
49
t : Ty < ' tcx > ,
47
50
qualified : bool ,
@@ -84,25 +87,14 @@ pub fn push_debuginfo_type_name<'tcx>(
84
87
85
88
for component_type in component_types {
86
89
push_debuginfo_type_name ( tcx, component_type. expect_ty ( ) , true , output, visited) ;
87
- output. push ( ',' ) ;
88
-
89
- // Natvis does not always like having spaces between parts of the type name
90
- // and this causes issues when we need to write a typename in natvis, for example
91
- // as part of a cast like the `HashMap` visualizer does.
92
- if !cpp_like_names {
93
- output. push ( ' ' ) ;
94
- }
90
+ push_arg_separator ( cpp_like_names, output) ;
95
91
}
96
92
if !component_types. is_empty ( ) {
97
- output. pop ( ) ;
98
-
99
- if !cpp_like_names {
100
- output. pop ( ) ;
101
- }
93
+ pop_arg_separator ( output) ;
102
94
}
103
95
104
96
if cpp_like_names {
105
- push_close_angle_bracket ( tcx , output) ;
97
+ push_close_angle_bracket ( cpp_like_names , output) ;
106
98
} else {
107
99
output. push ( ')' ) ;
108
100
}
@@ -124,7 +116,7 @@ pub fn push_debuginfo_type_name<'tcx>(
124
116
push_debuginfo_type_name ( tcx, inner_type, qualified, output, visited) ;
125
117
126
118
if cpp_like_names {
127
- push_close_angle_bracket ( tcx , output) ;
119
+ push_close_angle_bracket ( cpp_like_names , output) ;
128
120
}
129
121
}
130
122
ty:: Ref ( _, inner_type, mutbl) => {
@@ -150,7 +142,7 @@ pub fn push_debuginfo_type_name<'tcx>(
150
142
push_debuginfo_type_name ( tcx, inner_type, qualified, output, visited) ;
151
143
152
144
if cpp_like_names && !is_slice_or_str {
153
- push_close_angle_bracket ( tcx , output) ;
145
+ push_close_angle_bracket ( cpp_like_names , output) ;
154
146
}
155
147
}
156
148
ty:: Array ( inner_type, len) => {
@@ -182,69 +174,97 @@ pub fn push_debuginfo_type_name<'tcx>(
182
174
push_debuginfo_type_name ( tcx, inner_type, true , output, visited) ;
183
175
184
176
if cpp_like_names {
185
- push_close_angle_bracket ( tcx , output) ;
177
+ push_close_angle_bracket ( cpp_like_names , output) ;
186
178
} else {
187
179
output. push ( ']' ) ;
188
180
}
189
181
}
190
182
ty:: Dynamic ( ref trait_data, ..) => {
191
- if cpp_like_names {
183
+ let auto_traits: SmallVec < [ DefId ; 4 ] > = trait_data. auto_traits ( ) . collect ( ) ;
184
+
185
+ let has_enclosing_parens = if cpp_like_names {
192
186
output. push_str ( "dyn$<" ) ;
187
+ false
193
188
} else {
194
- output. push_str ( "dyn " ) ;
195
- }
189
+ if trait_data. len ( ) > 1 && auto_traits. len ( ) != 0 {
190
+ // We need enclosing parens because there is more than one trait
191
+ output. push_str ( "(dyn " ) ;
192
+ true
193
+ } else {
194
+ output. push_str ( "dyn " ) ;
195
+ false
196
+ }
197
+ } ;
196
198
197
199
if let Some ( principal) = trait_data. principal ( ) {
198
200
let principal =
199
201
tcx. normalize_erasing_late_bound_regions ( ty:: ParamEnv :: reveal_all ( ) , principal) ;
200
202
push_item_name ( tcx, principal. def_id , qualified, output) ;
201
- push_generic_params_internal ( tcx, principal. substs , output, visited) ;
202
- } else {
203
- // The auto traits come ordered by `DefPathHash`, which guarantees stability if the
204
- // environment is stable (e.g., incremental builds) but not otherwise (e.g.,
205
- // updated compiler version, different target).
206
- //
207
- // To avoid that causing instabilities in test output, sort the auto-traits
208
- // alphabetically.
209
- let mut auto_traits: Vec < _ > = trait_data
210
- . iter ( )
211
- . filter_map ( |predicate| {
212
- match tcx. normalize_erasing_late_bound_regions (
213
- ty:: ParamEnv :: reveal_all ( ) ,
214
- predicate,
215
- ) {
216
- ty:: ExistentialPredicate :: AutoTrait ( def_id) => {
217
- let mut name = String :: new ( ) ;
218
- push_item_name ( tcx, def_id, true , & mut name) ;
219
- Some ( name)
220
- }
221
- _ => None ,
222
- }
203
+ let principal_has_generic_params =
204
+ push_generic_params_internal ( tcx, principal. substs , output, visited) ;
205
+
206
+ let projection_bounds: SmallVec < [ _ ; 4 ] > = trait_data
207
+ . projection_bounds ( )
208
+ . map ( |bound| {
209
+ let ExistentialProjection { item_def_id, ty, .. } = bound. skip_binder ( ) ;
210
+ ( item_def_id, ty)
223
211
} )
224
212
. collect ( ) ;
225
- auto_traits. sort ( ) ;
226
213
227
- for name in auto_traits {
228
- output. push_str ( & name) ;
214
+ if projection_bounds. len ( ) != 0 {
215
+ if principal_has_generic_params {
216
+ // push_generic_params_internal() above added a `>` but we actually
217
+ // want to add more items to that list, so remove that again.
218
+ pop_close_angle_bracket ( output) ;
219
+ }
229
220
230
- if cpp_like_names {
231
- output. push_str ( ", " ) ;
232
- } else {
233
- output. push_str ( " + " ) ;
221
+ for ( item_def_id, ty) in projection_bounds {
222
+ push_arg_separator ( cpp_like_names, output) ;
223
+
224
+ if cpp_like_names {
225
+ output. push_str ( "assoc$<" ) ;
226
+ push_item_name ( tcx, item_def_id, false , output) ;
227
+ push_arg_separator ( cpp_like_names, output) ;
228
+ push_debuginfo_type_name ( tcx, ty, true , output, visited) ;
229
+ push_close_angle_bracket ( cpp_like_names, output) ;
230
+ } else {
231
+ push_item_name ( tcx, item_def_id, false , output) ;
232
+ output. push ( '=' ) ;
233
+ push_debuginfo_type_name ( tcx, ty, true , output, visited) ;
234
+ }
234
235
}
236
+
237
+ push_close_angle_bracket ( cpp_like_names, output) ;
235
238
}
236
239
237
- // Remove the trailing joining characters. For cpp_like_names
238
- // this is `, ` otherwise ` + `.
239
- output. pop ( ) ;
240
- output. pop ( ) ;
241
- if !cpp_like_names {
242
- output. pop ( ) ;
240
+ if auto_traits. len ( ) != 0 {
241
+ push_auto_trait_separator ( cpp_like_names, output) ;
243
242
}
244
243
}
245
244
245
+ if auto_traits. len ( ) != 0 {
246
+ let mut auto_traits: SmallVec < [ String ; 4 ] > = auto_traits
247
+ . into_iter ( )
248
+ . map ( |def_id| {
249
+ let mut name = String :: with_capacity ( 20 ) ;
250
+ push_item_name ( tcx, def_id, true , & mut name) ;
251
+ name
252
+ } )
253
+ . collect ( ) ;
254
+ auto_traits. sort_unstable ( ) ;
255
+
256
+ for auto_trait in auto_traits {
257
+ output. push_str ( & auto_trait) ;
258
+ push_auto_trait_separator ( cpp_like_names, output) ;
259
+ }
260
+
261
+ pop_auto_trait_separator ( output) ;
262
+ }
263
+
246
264
if cpp_like_names {
247
- push_close_angle_bracket ( tcx, output) ;
265
+ push_close_angle_bracket ( cpp_like_names, output) ;
266
+ } else if has_enclosing_parens {
267
+ output. push ( ')' ) ;
248
268
}
249
269
}
250
270
ty:: FnDef ( ..) | ty:: FnPtr ( _) => {
@@ -296,10 +316,9 @@ pub fn push_debuginfo_type_name<'tcx>(
296
316
if !sig. inputs ( ) . is_empty ( ) {
297
317
for & parameter_type in sig. inputs ( ) {
298
318
push_debuginfo_type_name ( tcx, parameter_type, true , output, visited) ;
299
- output . push_str ( ", " ) ;
319
+ push_arg_separator ( cpp_like_names , output ) ;
300
320
}
301
- output. pop ( ) ;
302
- output. pop ( ) ;
321
+ pop_arg_separator ( output) ;
303
322
}
304
323
305
324
if sig. c_variadic {
@@ -405,7 +424,25 @@ pub fn push_debuginfo_type_name<'tcx>(
405
424
output. push_str ( & format ! ( ", {}" , variant) ) ;
406
425
}
407
426
}
408
- push_close_angle_bracket ( tcx, output) ;
427
+ push_close_angle_bracket ( true , output) ;
428
+ }
429
+
430
+ const NON_CPP_AUTO_TRAIT_SEPARATOR : & str = " + " ;
431
+
432
+ fn push_auto_trait_separator ( cpp_like_names : bool , output : & mut String ) {
433
+ if cpp_like_names {
434
+ push_arg_separator ( cpp_like_names, output) ;
435
+ } else {
436
+ output. push_str ( NON_CPP_AUTO_TRAIT_SEPARATOR ) ;
437
+ }
438
+ }
439
+
440
+ fn pop_auto_trait_separator ( output : & mut String ) {
441
+ if output. ends_with ( NON_CPP_AUTO_TRAIT_SEPARATOR ) {
442
+ output. truncate ( output. len ( ) - NON_CPP_AUTO_TRAIT_SEPARATOR . len ( ) ) ;
443
+ } else {
444
+ pop_arg_separator ( output) ;
445
+ }
409
446
}
410
447
}
411
448
@@ -466,13 +503,15 @@ fn push_generic_params_internal<'tcx>(
466
503
substs : SubstsRef < ' tcx > ,
467
504
output : & mut String ,
468
505
visited : & mut FxHashSet < Ty < ' tcx > > ,
469
- ) {
506
+ ) -> bool {
470
507
if substs. non_erasable_generics ( ) . next ( ) . is_none ( ) {
471
- return ;
508
+ return false ;
472
509
}
473
510
474
511
debug_assert_eq ! ( substs, tcx. normalize_erasing_regions( ty:: ParamEnv :: reveal_all( ) , substs) ) ;
475
512
513
+ let cpp_like_names = cpp_like_names ( tcx) ;
514
+
476
515
output. push ( '<' ) ;
477
516
478
517
for type_parameter in substs. non_erasable_generics ( ) {
@@ -486,13 +525,12 @@ fn push_generic_params_internal<'tcx>(
486
525
other => bug ! ( "Unexpected non-erasable generic: {:?}" , other) ,
487
526
}
488
527
489
- output . push_str ( ", " ) ;
528
+ push_arg_separator ( cpp_like_names , output ) ;
490
529
}
530
+ pop_arg_separator ( output) ;
531
+ push_close_angle_bracket ( cpp_like_names, output) ;
491
532
492
- output. pop ( ) ;
493
- output. pop ( ) ;
494
-
495
- push_close_angle_bracket ( tcx, output) ;
533
+ true
496
534
}
497
535
498
536
fn push_const_param < ' tcx > ( tcx : TyCtxt < ' tcx > , ct : & ' tcx ty:: Const < ' tcx > , output : & mut String ) {
@@ -541,20 +579,50 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: &'tcx ty::Const<'tcx>, output:
541
579
}
542
580
543
581
pub fn push_generic_params < ' tcx > ( tcx : TyCtxt < ' tcx > , substs : SubstsRef < ' tcx > , output : & mut String ) {
582
+ let _prof = tcx. prof . generic_activity ( "compute_debuginfo_type_name" ) ;
544
583
let mut visited = FxHashSet :: default ( ) ;
545
584
push_generic_params_internal ( tcx, substs, output, & mut visited) ;
546
585
}
547
586
548
- fn push_close_angle_bracket < ' tcx > ( tcx : TyCtxt < ' tcx > , output : & mut String ) {
587
+ fn push_close_angle_bracket ( cpp_like_names : bool , output : & mut String ) {
549
588
// MSVC debugger always treats `>>` as a shift, even when parsing templates,
550
589
// so add a space to avoid confusion.
551
- if cpp_like_names ( tcx ) && output. ends_with ( '>' ) {
590
+ if cpp_like_names && output. ends_with ( '>' ) {
552
591
output. push ( ' ' )
553
592
} ;
554
593
555
594
output. push ( '>' ) ;
556
595
}
557
596
597
+ fn pop_close_angle_bracket ( output : & mut String ) {
598
+ assert ! ( output. ends_with( '>' ) , "'output' does not end with '>': {}" , output) ;
599
+ output. pop ( ) ;
600
+ if output. ends_with ( ' ' ) {
601
+ output. pop ( ) ;
602
+ }
603
+ }
604
+
605
+ fn push_arg_separator ( cpp_like_names : bool , output : & mut String ) {
606
+ // Natvis does not always like having spaces between parts of the type name
607
+ // and this causes issues when we need to write a typename in natvis, for example
608
+ // as part of a cast like the `HashMap` visualizer does.
609
+ if cpp_like_names {
610
+ output. push ( ',' ) ;
611
+ } else {
612
+ output. push_str ( ", " ) ;
613
+ } ;
614
+ }
615
+
616
+ fn pop_arg_separator ( output : & mut String ) {
617
+ if output. ends_with ( ' ' ) {
618
+ output. pop ( ) ;
619
+ }
620
+
621
+ assert ! ( output. ends_with( ',' ) ) ;
622
+
623
+ output. pop ( ) ;
624
+ }
625
+
558
626
fn cpp_like_names ( tcx : TyCtxt < ' _ > ) -> bool {
559
627
tcx. sess . target . is_like_msvc
560
628
}
0 commit comments