@@ -461,22 +461,24 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
461
461
return err. emit ( ) ;
462
462
}
463
463
464
- let mut bound_spans = Vec :: new ( ) ;
464
+ let mut bound_spans: FxHashMap < Span , Vec < String > > = Default :: default ( ) ;
465
465
466
466
let mut bound_span_label = |self_ty : Ty < ' _ > , obligation : & str , quiet : & str | {
467
- let msg = format ! (
468
- "doesn't satisfy `{}`" ,
469
- if obligation. len( ) > 50 { quiet } else { obligation }
470
- ) ;
467
+ let msg = format ! ( "`{}`" , if obligation. len( ) > 50 { quiet } else { obligation } ) ;
471
468
match & self_ty. kind ( ) {
472
469
// Point at the type that couldn't satisfy the bound.
473
- ty:: Adt ( def, _) => bound_spans. push ( ( tcx. def_span ( def. did ( ) ) , msg) ) ,
470
+ ty:: Adt ( def, _) => {
471
+ bound_spans. entry ( tcx. def_span ( def. did ( ) ) ) . or_default ( ) . push ( msg)
472
+ }
474
473
// Point at the trait object that couldn't satisfy the bound.
475
474
ty:: Dynamic ( preds, _, _) => {
476
475
for pred in preds. iter ( ) {
477
476
match pred. skip_binder ( ) {
478
477
ty:: ExistentialPredicate :: Trait ( tr) => {
479
- bound_spans. push ( ( tcx. def_span ( tr. def_id ) , msg. clone ( ) ) )
478
+ bound_spans
479
+ . entry ( tcx. def_span ( tr. def_id ) )
480
+ . or_default ( )
481
+ . push ( msg. clone ( ) ) ;
480
482
}
481
483
ty:: ExistentialPredicate :: Projection ( _)
482
484
| ty:: ExistentialPredicate :: AutoTrait ( _) => { }
@@ -485,7 +487,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
485
487
}
486
488
// Point at the closure that couldn't satisfy the bound.
487
489
ty:: Closure ( def_id, _) => {
488
- bound_spans. push ( ( tcx. def_span ( * def_id) , format ! ( "doesn't satisfy `{quiet}`" ) ) )
490
+ bound_spans
491
+ . entry ( tcx. def_span ( * def_id) )
492
+ . or_default ( )
493
+ . push ( format ! ( "`{quiet}`" ) ) ;
489
494
}
490
495
_ => { }
491
496
}
@@ -554,12 +559,24 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
554
559
format ! ( "associated type cannot be referenced on `{self_ty}` due to unsatisfied trait bounds" )
555
560
) ;
556
561
557
- bound_spans. sort ( ) ;
558
- bound_spans. dedup ( ) ;
559
- for ( span, msg) in bound_spans {
562
+ let mut bound_spans: Vec < ( Span , Vec < String > ) > = bound_spans
563
+ . into_iter ( )
564
+ . map ( |( span, mut bounds) | {
565
+ bounds. sort ( ) ;
566
+ bounds. dedup ( ) ;
567
+ ( span, bounds)
568
+ } )
569
+ . collect ( ) ;
570
+ bound_spans. sort_by_key ( |( span, _) | * span) ;
571
+ for ( span, bounds) in bound_spans {
560
572
if !tcx. sess . source_map ( ) . is_span_accessible ( span) {
561
573
continue ;
562
574
}
575
+ let msg = match & bounds[ ..] {
576
+ [ bound] => format ! ( "doesn't satisfy {bound}" ) ,
577
+ [ bounds @ .., last] => format ! ( "doesn't satisfy {} or {last}" , bounds. join( ", " ) ) ,
578
+ [ ] => unreachable ! ( ) ,
579
+ } ;
563
580
err. span_label ( span, msg) ;
564
581
}
565
582
add_def_label ( & mut err) ;
0 commit comments