@@ -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
@@ -188,63 +189,86 @@ pub fn push_debuginfo_type_name<'tcx>(
188189 }
189190 }
190191 ty:: Dynamic ( ref trait_data, ..) => {
191- if cpp_like_names {
192+ let auto_traits: SmallVec < [ DefId ; 4 ] > = trait_data. auto_traits ( ) . collect ( ) ;
193+
194+ let has_enclosing_parens = if cpp_like_names {
192195 output. push_str ( "dyn$<" ) ;
196+ false
193197 } else {
194- output. push_str ( "dyn " ) ;
195- }
198+ if trait_data. len ( ) > 1 && auto_traits. len ( ) != 0 {
199+ // We need enclosing parens
200+ output. push_str ( "(dyn " ) ;
201+ true
202+ } else {
203+ output. push_str ( "dyn " ) ;
204+ false
205+ }
206+ } ;
196207
197208 if let Some ( principal) = trait_data. principal ( ) {
198209 let principal =
199210 tcx. normalize_erasing_late_bound_regions ( ty:: ParamEnv :: reveal_all ( ) , principal) ;
200211 push_item_name ( tcx, principal. def_id , qualified, output) ;
201212 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- }
213+
214+ let projection_bounds: SmallVec < [ _ ; 4 ] > = trait_data
215+ . projection_bounds ( )
216+ . map ( |bound| {
217+ let ExistentialProjection { item_def_id, ty, .. } = bound. skip_binder ( ) ;
218+ ( item_def_id, ty)
223219 } )
224220 . collect ( ) ;
225- auto_traits. sort ( ) ;
226221
227- for name in auto_traits {
228- output . push_str ( & name ) ;
222+ if projection_bounds . len ( ) != 0 {
223+ pop_close_angle_bracket ( output ) ;
229224
230- if cpp_like_names {
225+ for ( item_def_id , ty ) in projection_bounds {
231226 output. push_str ( ", " ) ;
232- } else {
233- output. push_str ( " + " ) ;
227+
228+ if cpp_like_names {
229+ output. push_str ( "assoc$<" ) ;
230+ push_item_name ( tcx, item_def_id, false , output) ;
231+ output. push_str ( ", " ) ;
232+ push_debuginfo_type_name ( tcx, ty, true , output, visited) ;
233+ push_close_angle_bracket ( tcx, output) ;
234+ } else {
235+ push_item_name ( tcx, item_def_id, false , output) ;
236+ output. push ( '=' ) ;
237+ push_debuginfo_type_name ( tcx, ty, true , output, visited) ;
238+ }
234239 }
240+
241+ push_close_angle_bracket ( tcx, output) ;
235242 }
236243
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 ( ) ;
244+ if auto_traits. len ( ) != 0 {
245+ push_auto_trait_separator ( cpp_like_names, output) ;
246+ }
247+ }
248+
249+ if auto_traits. len ( ) != 0 {
250+ let mut auto_traits: SmallVec < [ String ; 4 ] > = auto_traits
251+ . into_iter ( )
252+ . map ( |def_id| {
253+ let mut name = String :: with_capacity ( 20 ) ;
254+ push_item_name ( tcx, def_id, true , & mut name) ;
255+ name
256+ } )
257+ . collect ( ) ;
258+ auto_traits. sort_unstable ( ) ;
259+
260+ for auto_trait in auto_traits {
261+ output. push_str ( & auto_trait) ;
262+ push_auto_trait_separator ( cpp_like_names, output) ;
243263 }
264+
265+ pop_auto_trait_separator ( cpp_like_names, output) ;
244266 }
245267
246268 if cpp_like_names {
247269 push_close_angle_bracket ( tcx, output) ;
270+ } else if has_enclosing_parens {
271+ output. push ( ')' ) ;
248272 }
249273 }
250274 ty:: FnDef ( ..) | ty:: FnPtr ( _) => {
@@ -407,6 +431,20 @@ pub fn push_debuginfo_type_name<'tcx>(
407431 }
408432 push_close_angle_bracket ( tcx, output) ;
409433 }
434+
435+ fn auto_trait_separator ( cpp_like_names : bool ) -> & ' static str {
436+ if cpp_like_names { ", " } else { " + " }
437+ }
438+
439+ fn push_auto_trait_separator ( cpp_like_names : bool , output : & mut String ) {
440+ output. push_str ( auto_trait_separator ( cpp_like_names) ) ;
441+ }
442+
443+ fn pop_auto_trait_separator ( cpp_like_names : bool , output : & mut String ) {
444+ let sep = auto_trait_separator ( cpp_like_names) ;
445+ assert ! ( output. ends_with( sep) ) ;
446+ output. truncate ( output. len ( ) - sep. len ( ) ) ;
447+ }
410448}
411449
412450pub fn push_item_name ( tcx : TyCtxt < ' tcx > , def_id : DefId , qualified : bool , output : & mut String ) {
@@ -555,6 +593,14 @@ fn push_close_angle_bracket<'tcx>(tcx: TyCtxt<'tcx>, output: &mut String) {
555593 output. push ( '>' ) ;
556594}
557595
596+ fn pop_close_angle_bracket ( output : & mut String ) {
597+ assert ! ( output. ends_with( '>' ) ) ;
598+ output. pop ( ) ;
599+ if output. ends_with ( ' ' ) {
600+ output. pop ( ) ;
601+ }
602+ }
603+
558604fn cpp_like_names ( tcx : TyCtxt < ' _ > ) -> bool {
559605 tcx. sess . target . is_like_msvc
560606}
0 commit comments