@@ -9,7 +9,7 @@ use crate::Expectation;
99use crate :: FnCtxt ;
1010use rustc_ast:: ast:: Mutability ;
1111use rustc_attr:: parse_confusables;
12- use rustc_data_structures:: fx:: { FxIndexMap , FxIndexSet } ;
12+ use rustc_data_structures:: fx:: { FxHashMap , FxIndexMap , FxIndexSet } ;
1313use rustc_data_structures:: unord:: UnordSet ;
1414use rustc_errors:: StashKey ;
1515use rustc_errors:: {
@@ -547,7 +547,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
547547 ) ;
548548 }
549549
550- let mut bound_spans = vec ! [ ] ;
550+ let mut bound_spans: FxHashMap < Span , Vec < String > > = Default :: default ( ) ;
551551 let mut restrict_type_params = false ;
552552 let mut unsatisfied_bounds = false ;
553553 if item_name. name == sym:: count && self . is_slice_ty ( rcvr_ty, span) {
@@ -642,28 +642,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
642642 false
643643 } ;
644644 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 } ) ;
649646 match & self_ty. kind ( ) {
650647 // 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+ }
652651 // Point at the trait object that couldn't satisfy the bound.
653652 ty:: Dynamic ( preds, _, _) => {
654653 for pred in preds. iter ( ) {
655654 match pred. skip_binder ( ) {
656655 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 ( ) ) ;
658660 }
659661 ty:: ExistentialPredicate :: Projection ( _)
660662 | ty:: ExistentialPredicate :: AutoTrait ( _) => { }
661663 }
662664 }
663665 }
664666 // 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+ }
667673 _ => { }
668674 }
669675 } ;
@@ -1170,9 +1176,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11701176
11711177 self . suggest_unwrapping_inner_self ( & mut err, source, rcvr_ty, item_name) ;
11721178
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+ } ;
11761198 err. span_label ( span, msg) ;
11771199 }
11781200
0 commit comments