@@ -7,7 +7,7 @@ use rustc::hir::map as hir_map;
7
7
use rustc:: hir:: map:: Map ;
8
8
use rustc:: ty:: print:: with_crate_prefix;
9
9
use rustc:: ty:: { self , ToPolyTraitRef , ToPredicate , Ty , TyCtxt , TypeFoldable , WithConstness } ;
10
- use rustc_data_structures:: fx:: FxHashSet ;
10
+ use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
11
11
use rustc_errors:: { pluralize, struct_span_err, Applicability , DiagnosticBuilder } ;
12
12
use rustc_hir as hir;
13
13
use rustc_hir:: def:: { DefKind , Namespace , Res } ;
@@ -537,10 +537,43 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
537
537
if !unsatisfied_predicates. is_empty ( ) {
538
538
let def_span =
539
539
|def_id| self . tcx . sess . source_map ( ) . def_span ( self . tcx . def_span ( def_id) ) ;
540
+ let mut type_params = FxHashMap :: default ( ) ;
540
541
let mut bound_spans = vec ! [ ] ;
542
+ let mut collect_type_param_suggestions =
543
+ |self_ty : Ty < ' _ > , parent_pred : & ty:: Predicate < ' _ > , obligation : & str | {
544
+ if let ( ty:: Param ( _) , ty:: Predicate :: Trait ( p, _) ) =
545
+ ( & self_ty. kind , parent_pred)
546
+ {
547
+ if let ty:: Adt ( def, _) = p. skip_binder ( ) . trait_ref . self_ty ( ) . kind {
548
+ let id = self . tcx . hir ( ) . as_local_hir_id ( def. did ) . unwrap ( ) ;
549
+ let node = self . tcx . hir ( ) . get ( id) ;
550
+ match node {
551
+ hir:: Node :: Item ( hir:: Item { kind, .. } ) => {
552
+ if let Some ( g) = kind. generics ( ) {
553
+ let key = match & g. where_clause . predicates [ ..] {
554
+ [ .., pred] => {
555
+ ( pred. span ( ) . shrink_to_hi ( ) , false )
556
+ }
557
+ [ ] => (
558
+ g. where_clause
559
+ . span_for_predicates_or_empty_place ( ) ,
560
+ true ,
561
+ ) ,
562
+ } ;
563
+ type_params
564
+ . entry ( key)
565
+ . or_insert_with ( FxHashSet :: default)
566
+ . insert ( obligation. to_owned ( ) ) ;
567
+ }
568
+ }
569
+ _ => { }
570
+ }
571
+ }
572
+ }
573
+ } ;
541
574
let mut bound_span_label = |self_ty : Ty < ' _ > , obligation : & str , quiet : & str | {
542
575
let msg = format ! (
543
- "doesn't satisfy {} " ,
576
+ "doesn't satisfy `{}` " ,
544
577
if obligation. len( ) > 50 { quiet } else { obligation }
545
578
) ;
546
579
match & self_ty. kind {
@@ -560,7 +593,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
560
593
}
561
594
// Point at the closure that couldn't satisfy the bound.
562
595
ty:: Closure ( def_id, _) => bound_spans
563
- . push ( ( def_span ( * def_id) , format ! ( "doesn't satisfy {} " , quiet) ) ) ,
596
+ . push ( ( def_span ( * def_id) , format ! ( "doesn't satisfy `{}` " , quiet) ) ) ,
564
597
_ => { }
565
598
}
566
599
} ;
@@ -574,43 +607,60 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
574
607
. tcx
575
608
. associated_item ( pred. skip_binder ( ) . projection_ty . item_def_id ) ;
576
609
let ty = pred. skip_binder ( ) . ty ;
577
- let obligation =
578
- format ! ( "`{}::{} = {}`" , trait_ref, assoc. ident, ty) ;
610
+ let obligation = format ! ( "{}::{} = {}" , trait_ref, assoc. ident, ty) ;
579
611
let quiet = format ! (
580
- "` <_ as {}>::{} = {}` " ,
612
+ "<_ as {}>::{} = {}" ,
581
613
trait_ref. print_only_trait_path( ) ,
582
614
assoc. ident,
583
615
ty
584
616
) ;
585
617
bound_span_label ( trait_ref. self_ty ( ) , & obligation, & quiet) ;
586
- Some ( obligation)
618
+ Some ( ( obligation, trait_ref . self_ty ( ) ) )
587
619
}
588
620
ty:: Predicate :: Trait ( poly_trait_ref, _) => {
589
621
let p = poly_trait_ref. skip_binder ( ) . trait_ref ;
590
622
let self_ty = p. self_ty ( ) ;
591
623
let path = p. print_only_trait_path ( ) ;
592
- let obligation = format ! ( "` {}: {}` " , self_ty, path) ;
593
- let quiet = format ! ( "` _: {}` " , path) ;
624
+ let obligation = format ! ( "{}: {}" , self_ty, path) ;
625
+ let quiet = format ! ( "_: {}" , path) ;
594
626
bound_span_label ( self_ty, & obligation, & quiet) ;
595
- Some ( obligation)
627
+ Some ( ( obligation, self_ty ) )
596
628
}
597
629
_ => None ,
598
630
}
599
631
} ;
600
632
let mut bound_list = unsatisfied_predicates
601
633
. iter ( )
602
634
. filter_map ( |( pred, parent_pred) | {
603
- format_pred ( * pred) . map ( |pred | match parent_pred {
604
- None => pred ,
635
+ format_pred ( * pred) . map ( |( p , self_ty ) | match parent_pred {
636
+ None => format ! ( "`{}`" , p ) ,
605
637
Some ( parent_pred) => match format_pred ( * parent_pred) {
606
- None => pred,
607
- Some ( parent_pred) => {
608
- format ! ( "{} which is required by {}" , pred, parent_pred)
638
+ None => format ! ( "`{}`" , p) ,
639
+ Some ( ( parent_p, _) ) => {
640
+ collect_type_param_suggestions ( self_ty, parent_pred, & p) ;
641
+ format ! ( "`{}` which is required by `{}`" , p, parent_p)
609
642
}
610
643
} ,
611
644
} )
612
645
} )
613
646
. collect :: < Vec < String > > ( ) ;
647
+ for ( ( span, empty_where) , obligations) in type_params. into_iter ( ) {
648
+ err. span_suggestion_verbose (
649
+ span,
650
+ & format ! (
651
+ "consider restricting the type parameter{s} to satisfy the \
652
+ obligation{s}",
653
+ s = pluralize!( obligations. len( ) )
654
+ ) ,
655
+ format ! (
656
+ "{} {}" ,
657
+ if empty_where { " where" } else { "," } ,
658
+ obligations. into_iter( ) . collect:: <Vec <_>>( ) . join( ", " )
659
+ ) ,
660
+ Applicability :: MaybeIncorrect ,
661
+ ) ;
662
+ }
663
+
614
664
bound_list. sort ( ) ;
615
665
bound_list. dedup ( ) ; // #35677
616
666
bound_spans. sort ( ) ;
0 commit comments