@@ -19,8 +19,9 @@ use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathD
1919use rustc_middle:: ich:: NodeIdHashingMode ;
2020use rustc_middle:: ty:: layout:: IntegerExt ;
2121use 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 } ;
2323use rustc_target:: abi:: { Integer , TagEncoding , Variants } ;
24+ use smallvec:: SmallVec ;
2425
2526use std:: fmt:: Write ;
2627
@@ -33,6 +34,8 @@ pub fn compute_debuginfo_type_name<'tcx>(
3334 t : Ty < ' tcx > ,
3435 qualified : bool ,
3536) -> String {
37+ let _prof = tcx. prof . generic_activity ( "compute_debuginfo_type_name" ) ;
38+
3639 let mut result = String :: with_capacity ( 64 ) ;
3740 let mut visited = FxHashSet :: default ( ) ;
3841 push_debuginfo_type_name ( tcx, t, qualified, & mut result, & mut visited) ;
@@ -41,7 +44,7 @@ pub fn compute_debuginfo_type_name<'tcx>(
4144
4245// Pushes the name of the type as it should be stored in debuginfo on the
4346// `output` String. See also compute_debuginfo_type_name().
44- pub fn push_debuginfo_type_name < ' tcx > (
47+ fn push_debuginfo_type_name < ' tcx > (
4548 tcx : TyCtxt < ' tcx > ,
4649 t : Ty < ' tcx > ,
4750 qualified : bool ,
@@ -84,25 +87,14 @@ pub fn push_debuginfo_type_name<'tcx>(
8487
8588 for component_type in component_types {
8689 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) ;
9591 }
9692 if !component_types. is_empty ( ) {
97- output. pop ( ) ;
98-
99- if !cpp_like_names {
100- output. pop ( ) ;
101- }
93+ pop_arg_separator ( output) ;
10294 }
10395
10496 if cpp_like_names {
105- push_close_angle_bracket ( tcx , output) ;
97+ push_close_angle_bracket ( cpp_like_names , output) ;
10698 } else {
10799 output. push ( ')' ) ;
108100 }
@@ -124,7 +116,7 @@ pub fn push_debuginfo_type_name<'tcx>(
124116 push_debuginfo_type_name ( tcx, inner_type, qualified, output, visited) ;
125117
126118 if cpp_like_names {
127- push_close_angle_bracket ( tcx , output) ;
119+ push_close_angle_bracket ( cpp_like_names , output) ;
128120 }
129121 }
130122 ty:: Ref ( _, inner_type, mutbl) => {
@@ -150,7 +142,7 @@ pub fn push_debuginfo_type_name<'tcx>(
150142 push_debuginfo_type_name ( tcx, inner_type, qualified, output, visited) ;
151143
152144 if cpp_like_names && !is_slice_or_str {
153- push_close_angle_bracket ( tcx , output) ;
145+ push_close_angle_bracket ( cpp_like_names , output) ;
154146 }
155147 }
156148 ty:: Array ( inner_type, len) => {
@@ -182,69 +174,97 @@ pub fn push_debuginfo_type_name<'tcx>(
182174 push_debuginfo_type_name ( tcx, inner_type, true , output, visited) ;
183175
184176 if cpp_like_names {
185- push_close_angle_bracket ( tcx , output) ;
177+ push_close_angle_bracket ( cpp_like_names , output) ;
186178 } else {
187179 output. push ( ']' ) ;
188180 }
189181 }
190182 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 {
192186 output. push_str ( "dyn$<" ) ;
187+ false
193188 } 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+ } ;
196198
197199 if let Some ( principal) = trait_data. principal ( ) {
198200 let principal =
199201 tcx. normalize_erasing_late_bound_regions ( ty:: ParamEnv :: reveal_all ( ) , principal) ;
200202 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)
223211 } )
224212 . collect ( ) ;
225- auto_traits. sort ( ) ;
226213
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+ }
229220
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+ }
234235 }
236+
237+ push_close_angle_bracket ( cpp_like_names, output) ;
235238 }
236239
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) ;
243242 }
244243 }
245244
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+
246264 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 ( ')' ) ;
248268 }
249269 }
250270 ty:: FnDef ( ..) | ty:: FnPtr ( _) => {
@@ -296,10 +316,9 @@ pub fn push_debuginfo_type_name<'tcx>(
296316 if !sig. inputs ( ) . is_empty ( ) {
297317 for & parameter_type in sig. inputs ( ) {
298318 push_debuginfo_type_name ( tcx, parameter_type, true , output, visited) ;
299- output . push_str ( ", " ) ;
319+ push_arg_separator ( cpp_like_names , output ) ;
300320 }
301- output. pop ( ) ;
302- output. pop ( ) ;
321+ pop_arg_separator ( output) ;
303322 }
304323
305324 if sig. c_variadic {
@@ -405,7 +424,25 @@ pub fn push_debuginfo_type_name<'tcx>(
405424 output. push_str ( & format ! ( ", {}" , variant) ) ;
406425 }
407426 }
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+ }
409446 }
410447}
411448
@@ -466,13 +503,15 @@ fn push_generic_params_internal<'tcx>(
466503 substs : SubstsRef < ' tcx > ,
467504 output : & mut String ,
468505 visited : & mut FxHashSet < Ty < ' tcx > > ,
469- ) {
506+ ) -> bool {
470507 if substs. non_erasable_generics ( ) . next ( ) . is_none ( ) {
471- return ;
508+ return false ;
472509 }
473510
474511 debug_assert_eq ! ( substs, tcx. normalize_erasing_regions( ty:: ParamEnv :: reveal_all( ) , substs) ) ;
475512
513+ let cpp_like_names = cpp_like_names ( tcx) ;
514+
476515 output. push ( '<' ) ;
477516
478517 for type_parameter in substs. non_erasable_generics ( ) {
@@ -486,13 +525,12 @@ fn push_generic_params_internal<'tcx>(
486525 other => bug ! ( "Unexpected non-erasable generic: {:?}" , other) ,
487526 }
488527
489- output . push_str ( ", " ) ;
528+ push_arg_separator ( cpp_like_names , output ) ;
490529 }
530+ pop_arg_separator ( output) ;
531+ push_close_angle_bracket ( cpp_like_names, output) ;
491532
492- output. pop ( ) ;
493- output. pop ( ) ;
494-
495- push_close_angle_bracket ( tcx, output) ;
533+ true
496534}
497535
498536fn 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:
541579}
542580
543581pub 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" ) ;
544583 let mut visited = FxHashSet :: default ( ) ;
545584 push_generic_params_internal ( tcx, substs, output, & mut visited) ;
546585}
547586
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 ) {
549588 // MSVC debugger always treats `>>` as a shift, even when parsing templates,
550589 // so add a space to avoid confusion.
551- if cpp_like_names ( tcx ) && output. ends_with ( '>' ) {
590+ if cpp_like_names && output. ends_with ( '>' ) {
552591 output. push ( ' ' )
553592 } ;
554593
555594 output. push ( '>' ) ;
556595}
557596
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+
558626fn cpp_like_names ( tcx : TyCtxt < ' _ > ) -> bool {
559627 tcx. sess . target . is_like_msvc
560628}
0 commit comments