@@ -9,7 +9,7 @@ use crate::Expectation;
9
9
use crate :: FnCtxt ;
10
10
use rustc_ast:: ast:: Mutability ;
11
11
use rustc_attr:: parse_confusables;
12
- use rustc_data_structures:: fx:: { FxIndexMap , FxIndexSet } ;
12
+ use rustc_data_structures:: fx:: { FxHashMap , FxIndexMap , FxIndexSet } ;
13
13
use rustc_data_structures:: unord:: UnordSet ;
14
14
use rustc_errors:: StashKey ;
15
15
use rustc_errors:: {
@@ -547,7 +547,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
547
547
) ;
548
548
}
549
549
550
- let mut bound_spans = vec ! [ ] ;
550
+ let mut bound_spans: FxHashMap < Span , Vec < String > > = Default :: default ( ) ;
551
551
let mut restrict_type_params = false ;
552
552
let mut unsatisfied_bounds = false ;
553
553
if item_name. name == sym:: count && self . is_slice_ty ( rcvr_ty, span) {
@@ -653,28 +653,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
653
653
false
654
654
} ;
655
655
let mut bound_span_label = |self_ty : Ty < ' _ > , obligation : & str , quiet : & str | {
656
- let msg = format ! (
657
- "doesn't satisfy `{}`" ,
658
- if obligation. len( ) > 50 { quiet } else { obligation }
659
- ) ;
656
+ let msg = format ! ( "`{}`" , if obligation. len( ) > 50 { quiet } else { obligation } ) ;
660
657
match & self_ty. kind ( ) {
661
658
// Point at the type that couldn't satisfy the bound.
662
- ty:: Adt ( def, _) => bound_spans. push ( ( self . tcx . def_span ( def. did ( ) ) , msg) ) ,
659
+ ty:: Adt ( def, _) => {
660
+ bound_spans. entry ( tcx. def_span ( def. did ( ) ) ) . or_default ( ) . push ( msg)
661
+ }
663
662
// Point at the trait object that couldn't satisfy the bound.
664
663
ty:: Dynamic ( preds, _, _) => {
665
664
for pred in preds. iter ( ) {
666
665
match pred. skip_binder ( ) {
667
666
ty:: ExistentialPredicate :: Trait ( tr) => {
668
- bound_spans. push ( ( self . tcx . def_span ( tr. def_id ) , msg. clone ( ) ) )
667
+ bound_spans
668
+ . entry ( tcx. def_span ( tr. def_id ) )
669
+ . or_default ( )
670
+ . push ( msg. clone ( ) ) ;
669
671
}
670
672
ty:: ExistentialPredicate :: Projection ( _)
671
673
| ty:: ExistentialPredicate :: AutoTrait ( _) => { }
672
674
}
673
675
}
674
676
}
675
677
// Point at the closure that couldn't satisfy the bound.
676
- ty:: Closure ( def_id, _) => bound_spans
677
- . push ( ( tcx. def_span ( * def_id) , format ! ( "doesn't satisfy `{quiet}`" ) ) ) ,
678
+ ty:: Closure ( def_id, _) => {
679
+ bound_spans
680
+ . entry ( tcx. def_span ( * def_id) )
681
+ . or_default ( )
682
+ . push ( format ! ( "`{quiet}`" ) ) ;
683
+ }
678
684
_ => { }
679
685
}
680
686
} ;
@@ -1181,9 +1187,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1181
1187
1182
1188
self . suggest_unwrapping_inner_self ( & mut err, source, rcvr_ty, item_name) ;
1183
1189
1184
- bound_spans. sort ( ) ;
1185
- bound_spans. dedup ( ) ;
1186
- for ( span, msg) in bound_spans. into_iter ( ) {
1190
+ #[ allow( rustc:: potential_query_instability) ] // We immediately sort the resulting Vec.
1191
+ let mut bound_spans: Vec < ( Span , Vec < String > ) > = bound_spans
1192
+ . into_iter ( )
1193
+ . map ( |( span, mut bounds) | {
1194
+ bounds. sort ( ) ;
1195
+ bounds. dedup ( ) ;
1196
+ ( span, bounds)
1197
+ } )
1198
+ . collect ( ) ;
1199
+ bound_spans. sort_by_key ( |( span, _) | * span) ;
1200
+ for ( span, bounds) in bound_spans {
1201
+ if !tcx. sess . source_map ( ) . is_span_accessible ( span) {
1202
+ continue ;
1203
+ }
1204
+ let msg = match & bounds[ ..] {
1205
+ [ bound] => format ! ( "doesn't satisfy {bound}" ) ,
1206
+ [ bounds @ .., last] => format ! ( "doesn't satisfy {} or {last}" , bounds. join( ", " ) ) ,
1207
+ [ ] => unreachable ! ( ) ,
1208
+ } ;
1187
1209
err. span_label ( span, msg) ;
1188
1210
}
1189
1211
0 commit comments