@@ -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) {
@@ -642,28 +642,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
642
642
false
643
643
} ;
644
644
let mut bound_span_label = |self_ty : Ty < ' _ > , obligation : & str , quiet : & str | {
645
- let msg = format ! (
646
- "doesn't satisfy `{}`" ,
647
- if obligation. len( ) > 50 { quiet } else { obligation }
648
- ) ;
645
+ let msg = format ! ( "`{}`" , if obligation. len( ) > 50 { quiet } else { obligation } ) ;
649
646
match & self_ty. kind ( ) {
650
647
// Point at the type that couldn't satisfy the bound.
651
- ty:: Adt ( def, _) => bound_spans. push ( ( self . tcx . def_span ( def. did ( ) ) , msg) ) ,
648
+ ty:: Adt ( def, _) => {
649
+ bound_spans. entry ( tcx. def_span ( def. did ( ) ) ) . or_default ( ) . push ( msg)
650
+ }
652
651
// Point at the trait object that couldn't satisfy the bound.
653
652
ty:: Dynamic ( preds, _, _) => {
654
653
for pred in preds. iter ( ) {
655
654
match pred. skip_binder ( ) {
656
655
ty:: ExistentialPredicate :: Trait ( tr) => {
657
- bound_spans. push ( ( self . tcx . def_span ( tr. def_id ) , msg. clone ( ) ) )
656
+ bound_spans
657
+ . entry ( tcx. def_span ( tr. def_id ) )
658
+ . or_default ( )
659
+ . push ( msg. clone ( ) ) ;
658
660
}
659
661
ty:: ExistentialPredicate :: Projection ( _)
660
662
| ty:: ExistentialPredicate :: AutoTrait ( _) => { }
661
663
}
662
664
}
663
665
}
664
666
// Point at the closure that couldn't satisfy the bound.
665
- ty:: Closure ( def_id, _) => bound_spans
666
- . push ( ( tcx. def_span ( * def_id) , format ! ( "doesn't satisfy `{quiet}`" ) ) ) ,
667
+ ty:: Closure ( def_id, _) => {
668
+ bound_spans
669
+ . entry ( tcx. def_span ( * def_id) )
670
+ . or_default ( )
671
+ . push ( format ! ( "`{quiet}`" ) ) ;
672
+ }
667
673
_ => { }
668
674
}
669
675
} ;
@@ -1170,9 +1176,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1170
1176
1171
1177
self . suggest_unwrapping_inner_self ( & mut err, source, rcvr_ty, item_name) ;
1172
1178
1173
- bound_spans. sort ( ) ;
1174
- bound_spans. dedup ( ) ;
1175
- for ( span, msg) in bound_spans. into_iter ( ) {
1179
+ #[ allow( rustc:: potential_query_instability) ] // We immediately sort the resulting Vec.
1180
+ let mut bound_spans: Vec < ( Span , Vec < String > ) > = bound_spans
1181
+ . into_iter ( )
1182
+ . map ( |( span, mut bounds) | {
1183
+ bounds. sort ( ) ;
1184
+ bounds. dedup ( ) ;
1185
+ ( span, bounds)
1186
+ } )
1187
+ . collect ( ) ;
1188
+ bound_spans. sort_by_key ( |( span, _) | * span) ;
1189
+ for ( span, bounds) in bound_spans {
1190
+ if !tcx. sess . source_map ( ) . is_span_accessible ( span) {
1191
+ continue ;
1192
+ }
1193
+ let msg = match & bounds[ ..] {
1194
+ [ bound] => format ! ( "doesn't satisfy {bound}" ) ,
1195
+ [ bounds @ .., last] => format ! ( "doesn't satisfy {} or {last}" , bounds. join( ", " ) ) ,
1196
+ [ ] => unreachable ! ( ) ,
1197
+ } ;
1176
1198
err. span_label ( span, msg) ;
1177
1199
}
1178
1200
0 commit comments