@@ -7,7 +7,7 @@ use rustc::hir::map as hir_map;
77use rustc:: hir:: map:: Map ;
88use rustc:: ty:: print:: with_crate_prefix;
99use rustc:: ty:: { self , ToPolyTraitRef , ToPredicate , Ty , TyCtxt , TypeFoldable , WithConstness } ;
10- use rustc_data_structures:: fx:: FxHashSet ;
10+ use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
1111use rustc_errors:: { pluralize, struct_span_err, Applicability , DiagnosticBuilder } ;
1212use rustc_hir as hir;
1313use rustc_hir:: def:: { DefKind , Namespace , Res } ;
@@ -537,10 +537,43 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
537537 if !unsatisfied_predicates. is_empty ( ) {
538538 let def_span =
539539 |def_id| self . tcx . sess . source_map ( ) . def_span ( self . tcx . def_span ( def_id) ) ;
540+ let mut type_params = FxHashMap :: default ( ) ;
540541 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+ } ;
541574 let mut bound_span_label = |self_ty : Ty < ' _ > , obligation : & str , quiet : & str | {
542575 let msg = format ! (
543- "doesn't satisfy {} " ,
576+ "doesn't satisfy `{}` " ,
544577 if obligation. len( ) > 50 { quiet } else { obligation }
545578 ) ;
546579 match & self_ty. kind {
@@ -560,7 +593,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
560593 }
561594 // Point at the closure that couldn't satisfy the bound.
562595 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) ) ) ,
564597 _ => { }
565598 }
566599 } ;
@@ -574,43 +607,60 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
574607 . tcx
575608 . associated_item ( pred. skip_binder ( ) . projection_ty . item_def_id ) ;
576609 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) ;
579611 let quiet = format ! (
580- "` <_ as {}>::{} = {}` " ,
612+ "<_ as {}>::{} = {}" ,
581613 trait_ref. print_only_trait_path( ) ,
582614 assoc. ident,
583615 ty
584616 ) ;
585617 bound_span_label ( trait_ref. self_ty ( ) , & obligation, & quiet) ;
586- Some ( obligation)
618+ Some ( ( obligation, trait_ref . self_ty ( ) ) )
587619 }
588620 ty:: Predicate :: Trait ( poly_trait_ref, _) => {
589621 let p = poly_trait_ref. skip_binder ( ) . trait_ref ;
590622 let self_ty = p. self_ty ( ) ;
591623 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) ;
594626 bound_span_label ( self_ty, & obligation, & quiet) ;
595- Some ( obligation)
627+ Some ( ( obligation, self_ty ) )
596628 }
597629 _ => None ,
598630 }
599631 } ;
600632 let mut bound_list = unsatisfied_predicates
601633 . iter ( )
602634 . 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 ) ,
605637 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)
609642 }
610643 } ,
611644 } )
612645 } )
613646 . 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+
614664 bound_list. sort ( ) ;
615665 bound_list. dedup ( ) ; // #35677
616666 bound_spans. sort ( ) ;
0 commit comments