@@ -715,8 +715,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
715
715
// these notes will often be of the form
716
716
// "the type `T` can't be frobnicated"
717
717
// which is somewhat confusing.
718
- err. help ( & format ! ( "consider adding a `where {}` bound" ,
719
- trait_ref. to_predicate( ) ) ) ;
718
+ self . suggest_restricting_param_bound (
719
+ & mut err,
720
+ & trait_ref,
721
+ obligation. cause . body_id ,
722
+ ) ;
720
723
} else {
721
724
if !have_alt_message {
722
725
// Can't show anything else useful, try to find similar impls.
@@ -960,6 +963,175 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
960
963
err. emit ( ) ;
961
964
}
962
965
966
+ fn suggest_restricting_param_bound (
967
+ & self ,
968
+ err : & mut DiagnosticBuilder < ' _ > ,
969
+ trait_ref : & ty:: PolyTraitRef < ' _ > ,
970
+ body_id : hir:: HirId ,
971
+ ) {
972
+ let self_ty = trait_ref. self_ty ( ) ;
973
+ let ( param_ty, projection) = match & self_ty. kind {
974
+ ty:: Param ( _) => ( true , None ) ,
975
+ ty:: Projection ( projection) => ( false , Some ( projection) ) ,
976
+ _ => return ,
977
+ } ;
978
+
979
+ let mut suggest_restriction = |generics : & hir:: Generics , msg| {
980
+ let span = generics. where_clause . span_for_predicates_or_empty_place ( ) ;
981
+ if !span. from_expansion ( ) && span. desugaring_kind ( ) . is_none ( ) {
982
+ err. span_suggestion (
983
+ generics. where_clause . span_for_predicates_or_empty_place ( ) . shrink_to_hi ( ) ,
984
+ & format ! ( "consider further restricting {}" , msg) ,
985
+ format ! (
986
+ "{} {} " ,
987
+ if !generics. where_clause. predicates. is_empty( ) {
988
+ ","
989
+ } else {
990
+ " where"
991
+ } ,
992
+ trait_ref. to_predicate( ) ,
993
+ ) ,
994
+ Applicability :: MachineApplicable ,
995
+ ) ;
996
+ }
997
+ } ;
998
+
999
+ // FIXME: Add check for trait bound that is already present, particularly `?Sized` so we
1000
+ // don't suggest `T: Sized + ?Sized`.
1001
+ let mut hir_id = body_id;
1002
+ while let Some ( node) = self . tcx . hir ( ) . find ( hir_id) {
1003
+ match node {
1004
+ hir:: Node :: TraitItem ( hir:: TraitItem {
1005
+ generics,
1006
+ kind : hir:: TraitItemKind :: Method ( ..) , ..
1007
+ } ) if param_ty && self_ty == self . tcx . types . self_param => {
1008
+ // Restricting `Self` for a single method.
1009
+ suggest_restriction ( & generics, "`Self`" ) ;
1010
+ return ;
1011
+ }
1012
+
1013
+ hir:: Node :: Item ( hir:: Item {
1014
+ kind : hir:: ItemKind :: Fn ( _, _, generics, _) , ..
1015
+ } ) |
1016
+ hir:: Node :: TraitItem ( hir:: TraitItem {
1017
+ generics,
1018
+ kind : hir:: TraitItemKind :: Method ( ..) , ..
1019
+ } ) |
1020
+ hir:: Node :: ImplItem ( hir:: ImplItem {
1021
+ generics,
1022
+ kind : hir:: ImplItemKind :: Method ( ..) , ..
1023
+ } ) |
1024
+ hir:: Node :: Item ( hir:: Item {
1025
+ kind : hir:: ItemKind :: Trait ( _, _, generics, _, _) , ..
1026
+ } ) |
1027
+ hir:: Node :: Item ( hir:: Item {
1028
+ kind : hir:: ItemKind :: Impl ( _, _, _, generics, ..) , ..
1029
+ } ) if projection. is_some ( ) => {
1030
+ // Missing associated type bound.
1031
+ suggest_restriction ( & generics, "the associated type" ) ;
1032
+ return ;
1033
+ }
1034
+
1035
+ hir:: Node :: Item ( hir:: Item { kind : hir:: ItemKind :: Struct ( _, generics) , span, .. } ) |
1036
+ hir:: Node :: Item ( hir:: Item { kind : hir:: ItemKind :: Enum ( _, generics) , span, .. } ) |
1037
+ hir:: Node :: Item ( hir:: Item { kind : hir:: ItemKind :: Union ( _, generics) , span, .. } ) |
1038
+ hir:: Node :: Item ( hir:: Item {
1039
+ kind : hir:: ItemKind :: Trait ( _, _, generics, ..) , span, ..
1040
+ } ) |
1041
+ hir:: Node :: Item ( hir:: Item {
1042
+ kind : hir:: ItemKind :: Impl ( _, _, _, generics, ..) , span, ..
1043
+ } ) |
1044
+ hir:: Node :: Item ( hir:: Item {
1045
+ kind : hir:: ItemKind :: Fn ( _, _, generics, _) , span, ..
1046
+ } ) |
1047
+ hir:: Node :: Item ( hir:: Item {
1048
+ kind : hir:: ItemKind :: TyAlias ( _, generics) , span, ..
1049
+ } ) |
1050
+ hir:: Node :: Item ( hir:: Item {
1051
+ kind : hir:: ItemKind :: TraitAlias ( generics, _) , span, ..
1052
+ } ) |
1053
+ hir:: Node :: Item ( hir:: Item {
1054
+ kind : hir:: ItemKind :: OpaqueTy ( hir:: OpaqueTy { generics, .. } ) , span, ..
1055
+ } ) |
1056
+ hir:: Node :: TraitItem ( hir:: TraitItem { generics, span, .. } ) |
1057
+ hir:: Node :: ImplItem ( hir:: ImplItem { generics, span, .. } )
1058
+ if param_ty => {
1059
+ // Missing generic type parameter bound.
1060
+ let restrict_msg = "consider further restricting this bound" ;
1061
+ let param_name = self_ty. to_string ( ) ;
1062
+ for param in generics. params . iter ( ) . filter ( |p| {
1063
+ & param_name == std:: convert:: AsRef :: < str > :: as_ref ( & p. name . ident ( ) . as_str ( ) )
1064
+ } ) {
1065
+ if param_name. starts_with ( "impl " ) {
1066
+ // `impl Trait` in argument:
1067
+ // `fn foo(x: impl Trait) {}` → `fn foo(t: impl Trait + Trait2) {}`
1068
+ err. span_suggestion (
1069
+ param. span ,
1070
+ restrict_msg,
1071
+ // `impl CurrentTrait + MissingTrait`
1072
+ format ! ( "{} + {}" , param. name. ident( ) , trait_ref) ,
1073
+ Applicability :: MachineApplicable ,
1074
+ ) ;
1075
+ } else if generics. where_clause . predicates . is_empty ( ) &&
1076
+ param. bounds . is_empty ( )
1077
+ {
1078
+ // If there are no bounds whatsoever, suggest adding a constraint
1079
+ // to the type parameter:
1080
+ // `fn foo<T>(t: T) {}` → `fn foo<T: Trait>(t: T) {}`
1081
+ err. span_suggestion (
1082
+ param. span ,
1083
+ "consider restricting this bound" ,
1084
+ format ! ( "{}" , trait_ref. to_predicate( ) ) ,
1085
+ Applicability :: MachineApplicable ,
1086
+ ) ;
1087
+ } else if !generics. where_clause . predicates . is_empty ( ) {
1088
+ // There is a `where` clause, so suggest expanding it:
1089
+ // `fn foo<T>(t: T) where T: Debug {}` →
1090
+ // `fn foo<T>(t: T) where T: Debug, T: Trait {}`
1091
+ err. span_suggestion (
1092
+ generics. where_clause . span ( ) . unwrap ( ) . shrink_to_hi ( ) ,
1093
+ & format ! (
1094
+ "consider further restricting type parameter `{}`" ,
1095
+ param_name,
1096
+ ) ,
1097
+ format ! ( ", {}" , trait_ref. to_predicate( ) ) ,
1098
+ Applicability :: MachineApplicable ,
1099
+ ) ;
1100
+ } else {
1101
+ // If there is no `where` clause lean towards constraining to the
1102
+ // type parameter:
1103
+ // `fn foo<X: Bar, T>(t: T, x: X) {}` → `fn foo<T: Trait>(t: T) {}`
1104
+ // `fn foo<T: Bar>(t: T) {}` → `fn foo<T: Bar + Trait>(t: T) {}`
1105
+ let sp = param. span . with_hi ( span. hi ( ) ) ;
1106
+ let span = self . tcx . sess . source_map ( )
1107
+ . span_through_char ( sp, ':' ) ;
1108
+ if sp != param. span && sp != span {
1109
+ // Only suggest if we have high certainty that the span
1110
+ // covers the colon in `foo<T: Trait>`.
1111
+ err. span_suggestion ( span, restrict_msg, format ! (
1112
+ "{} + " ,
1113
+ trait_ref. to_predicate( ) ,
1114
+ ) , Applicability :: MachineApplicable ) ;
1115
+ } else {
1116
+ err. span_label ( param. span , & format ! (
1117
+ "consider adding a `where {}` bound" ,
1118
+ trait_ref. to_predicate( ) ,
1119
+ ) ) ;
1120
+ }
1121
+ }
1122
+ return ;
1123
+ }
1124
+ }
1125
+
1126
+ hir:: Node :: Crate => return ,
1127
+
1128
+ _ => { }
1129
+ }
1130
+
1131
+ hir_id = self . tcx . hir ( ) . get_parent_item ( hir_id) ;
1132
+ }
1133
+ }
1134
+
963
1135
/// When encountering an assignment of an unsized trait, like `let x = ""[..];`, provide a
964
1136
/// suggestion to borrow the initializer in order to use have a slice instead.
965
1137
fn suggest_borrow_on_unsized_slice (
0 commit comments