@@ -984,84 +984,66 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
984
984
}
985
985
} ;
986
986
987
+ let mut suggest_restriction = |generics : & hir:: Generics , msg| {
988
+ err. span_suggestion (
989
+ generics. where_clause . span_for_predicates_or_empty_place ( ) . shrink_to_hi ( ) ,
990
+ & format ! ( "consider further restricting {}" , msg) ,
991
+ format ! (
992
+ "{} {} " ,
993
+ if !generics. where_clause. predicates. is_empty( ) {
994
+ ","
995
+ } else {
996
+ " where"
997
+ } ,
998
+ trait_ref. to_predicate( ) ,
999
+ ) ,
1000
+ Applicability :: MachineApplicable ,
1001
+ ) ;
1002
+ } ;
1003
+
1004
+ // FIXME: Add check for trait bound that is already present, particularly `?Sized` so we
1005
+ // don't suggest `T: Sized + ?Sized`.
987
1006
let mut hir_id = body_id;
988
1007
while let Some ( node) = self . tcx . hir ( ) . find ( hir_id) {
989
- debug ! ( "suggest_restricting_param_bound node={:?}" , node) ;
990
1008
match node {
991
1009
hir:: Node :: Item ( hir:: Item {
992
- kind : hir:: ItemKind :: Fn ( decl , _, generics, _) , ..
1010
+ kind : hir:: ItemKind :: Fn ( _ , _, generics, _) , ..
993
1011
} ) |
994
1012
hir:: Node :: TraitItem ( hir:: TraitItem {
995
1013
generics,
996
- kind : hir:: TraitItemKind :: Method ( hir :: MethodSig { decl , .. } , _ ) , ..
1014
+ kind : hir:: TraitItemKind :: Method ( .. ) , ..
997
1015
} ) |
998
1016
hir:: Node :: ImplItem ( hir:: ImplItem {
999
1017
generics,
1000
- kind : hir:: ImplItemKind :: Method ( hir:: MethodSig { decl, .. } , _) , ..
1001
- } ) if param_ty. map ( |p| p. name . as_str ( ) == "Self" ) . unwrap_or ( false ) => {
1002
- if !generics. where_clause . predicates . is_empty ( ) {
1003
- err. span_suggestion (
1004
- generics. where_clause . span ( ) . unwrap ( ) . shrink_to_hi ( ) ,
1005
- "consider further restricting `Self`" ,
1006
- format ! ( ", {}" , trait_ref. to_predicate( ) ) ,
1007
- Applicability :: MachineApplicable ,
1008
- ) ;
1009
- } else {
1010
- err. span_suggestion (
1011
- decl. output . span ( ) . shrink_to_hi ( ) ,
1012
- "consider further restricting `Self`" ,
1013
- format ! ( " where {}" , trait_ref. to_predicate( ) ) ,
1014
- Applicability :: MachineApplicable ,
1015
- ) ;
1016
- }
1018
+ kind : hir:: ImplItemKind :: Method ( ..) , ..
1019
+ } ) if param_ty. map_or ( false , |p| p. name . as_str ( ) == "Self" ) => {
1020
+ // Restricting `Self` for a single method.
1021
+ suggest_restriction ( & generics, "`Self`" ) ;
1017
1022
return ;
1018
1023
}
1024
+
1019
1025
hir:: Node :: Item ( hir:: Item {
1020
- kind : hir:: ItemKind :: Fn ( decl , _, generics, _) , ..
1026
+ kind : hir:: ItemKind :: Fn ( _ , _, generics, _) , ..
1021
1027
} ) |
1022
1028
hir:: Node :: TraitItem ( hir:: TraitItem {
1023
1029
generics,
1024
- kind : hir:: TraitItemKind :: Method ( hir :: MethodSig { decl , .. } , _ ) , ..
1030
+ kind : hir:: TraitItemKind :: Method ( .. ) , ..
1025
1031
} ) |
1026
1032
hir:: Node :: ImplItem ( hir:: ImplItem {
1027
1033
generics,
1028
- kind : hir:: ImplItemKind :: Method ( hir:: MethodSig { decl, .. } , _) , ..
1029
- } ) if projection. is_some ( ) => {
1030
- if !generics. where_clause . predicates . is_empty ( ) {
1031
- err. span_suggestion (
1032
- generics. where_clause . span ( ) . unwrap ( ) . shrink_to_hi ( ) ,
1033
- "consider further restricting the associated type" ,
1034
- format ! ( ", {}" , trait_ref. to_predicate( ) ) ,
1035
- Applicability :: MachineApplicable ,
1036
- ) ;
1037
- } else {
1038
- err. span_suggestion (
1039
- decl. output . span ( ) . shrink_to_hi ( ) ,
1040
- "consider further restricting the associated type" ,
1041
- format ! ( " where {}" , trait_ref. to_predicate( ) ) ,
1042
- Applicability :: MachineApplicable ,
1043
- ) ;
1044
- }
1045
- return ;
1046
- }
1034
+ kind : hir:: ImplItemKind :: Method ( ..) , ..
1035
+ } ) |
1036
+ hir:: Node :: Item ( hir:: Item {
1037
+ kind : hir:: ItemKind :: Trait ( _, _, generics, _, _) , ..
1038
+ } ) |
1047
1039
hir:: Node :: Item ( hir:: Item {
1048
1040
kind : hir:: ItemKind :: Impl ( _, _, _, generics, ..) , ..
1049
1041
} ) if projection. is_some ( ) => {
1050
- err. span_suggestion (
1051
- generics. where_clause . span_for_predicates_or_empty_place ( ) . shrink_to_hi ( ) ,
1052
- "consider further restricting the associated type" ,
1053
- format ! (
1054
- "{} {}" , if generics. where_clause. predicates. is_empty( ) {
1055
- " where"
1056
- } else {
1057
- " ,"
1058
- } ,
1059
- trait_ref. to_predicate( ) ,
1060
- ) ,
1061
- Applicability :: MachineApplicable ,
1062
- ) ;
1042
+ // Missing associated type bound.
1043
+ suggest_restriction ( & generics, "the associated type" ) ;
1063
1044
return ;
1064
1045
}
1046
+
1065
1047
hir:: Node :: Item ( hir:: Item { kind : hir:: ItemKind :: Struct ( _, generics) , span, .. } ) |
1066
1048
hir:: Node :: Item ( hir:: Item { kind : hir:: ItemKind :: Enum ( _, generics) , span, .. } ) |
1067
1049
hir:: Node :: Item ( hir:: Item { kind : hir:: ItemKind :: Union ( _, generics) , span, .. } ) |
@@ -1086,73 +1068,82 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
1086
1068
hir:: Node :: TraitItem ( hir:: TraitItem { generics, span, .. } ) |
1087
1069
hir:: Node :: ImplItem ( hir:: ImplItem { generics, span, .. } )
1088
1070
if param_ty. is_some ( ) => {
1071
+ // Missing generic type parameter bound.
1089
1072
let restrict_msg = "consider further restricting this bound" ;
1090
1073
let param_name = param_ty. unwrap ( ) . name . as_str ( ) ;
1091
- for param in & generics. params {
1092
- if param_name == param. name . ident ( ) . as_str ( ) {
1093
- if param_name. starts_with ( "impl " ) {
1074
+ for param in generics. params . iter ( ) . filter ( |p| {
1075
+ param_name == p. name . ident ( ) . as_str ( )
1076
+ } ) {
1077
+ if param_name. starts_with ( "impl " ) {
1078
+ // `impl Trait` in argument:
1079
+ // `fn foo(x: impl Trait) {}` → `fn foo(t: impl Trait + Trait2) {}`
1080
+ err. span_suggestion (
1081
+ param. span ,
1082
+ restrict_msg,
1083
+ // `impl CurrentTrait + MissingTrait`
1084
+ format ! ( "{} + {}" , param. name. ident( ) , trait_ref) ,
1085
+ Applicability :: MachineApplicable ,
1086
+ ) ;
1087
+ } else {
1088
+ if generics. where_clause . predicates . is_empty ( ) &&
1089
+ param. bounds . is_empty ( )
1090
+ {
1091
+ // If there are no bounds whatsoever, suggest adding a constraint
1092
+ // to the type parameter:
1093
+ // `fn foo<T>(t: T) {}` → `fn foo<T: Trait>(t: T) {}`
1094
1094
err. span_suggestion (
1095
1095
param. span ,
1096
- restrict_msg,
1097
- // `impl CurrentTrait + MissingTrait`
1098
- format ! ( "{} + {}" , param. name. ident( ) , trait_ref) ,
1096
+ "consider restricting this bound" ,
1097
+ format ! ( "{}" , trait_ref. to_predicate( ) ) ,
1098
+ Applicability :: MachineApplicable ,
1099
+ ) ;
1100
+ } else if !generics. where_clause . predicates . is_empty ( ) {
1101
+ // There is a `where` clause, so suggest expanding it:
1102
+ // `fn foo<T>(t: T) where T: Debug {}` →
1103
+ // `fn foo<T(t: T) where T: Debug, Trait {}`
1104
+ err. span_suggestion (
1105
+ generics. where_clause . span ( ) . unwrap ( ) . shrink_to_hi ( ) ,
1106
+ & format ! (
1107
+ "consider further restricting type parameter `{}`" ,
1108
+ param_name,
1109
+ ) ,
1110
+ format ! ( ", {}" , trait_ref. to_predicate( ) ) ,
1099
1111
Applicability :: MachineApplicable ,
1100
1112
) ;
1101
1113
} else {
1102
- if generics. where_clause . predicates . is_empty ( ) &&
1103
- param. bounds . is_empty ( )
1104
- {
1105
- err. span_suggestion (
1106
- param. span ,
1107
- "consider restricting this bound" ,
1108
- format ! ( "{}" , trait_ref. to_predicate( ) ) ,
1109
- Applicability :: MachineApplicable ,
1110
- ) ;
1111
- } else if !generics. where_clause . predicates . is_empty ( ) {
1112
- err. span_suggestion (
1113
- generics. where_clause . span ( ) . unwrap ( ) . shrink_to_hi ( ) ,
1114
- & format ! (
1115
- "consider further restricting type parameter `{}`" ,
1116
- param_name,
1117
- ) ,
1118
- format ! ( ", {}" , trait_ref. to_predicate( ) ) ,
1119
- Applicability :: MachineApplicable ,
1120
- ) ;
1114
+ // If there is no `where` clause lean towards constraining to the
1115
+ // type parameter:
1116
+ // `fn foo<X: Bar, T>(t: T, x: X) {}` → `fn foo<T: Trait>(t: T) {}`
1117
+ // `fn foo<T: Bar>(t: T) {}` → `fn foo<T: Bar + Trait>(t: T) {}`
1118
+ let sp = param. span . with_hi ( span. hi ( ) ) ;
1119
+ let span = self . tcx . sess . source_map ( )
1120
+ . span_through_char ( sp, ':' ) ;
1121
+ if sp != param. span && sp != span {
1122
+ // Only suggest if we have high certainty that the span
1123
+ // covers the colon in `foo<T: Trait>`.
1124
+ err. span_suggestion ( span, restrict_msg, format ! (
1125
+ "{} + " ,
1126
+ trait_ref. to_predicate( ) ,
1127
+ ) , Applicability :: MachineApplicable ) ;
1121
1128
} else {
1122
- let sp = param. span . with_hi ( span. hi ( ) ) ;
1123
- let span = self . tcx . sess . source_map ( )
1124
- . span_through_char ( sp, ':' ) ;
1125
- if sp != param. span && sp != span {
1126
- // Only suggest if we have high certainty that the span
1127
- // covers the colon in `foo<T: Trait>`.
1128
- err. span_suggestion ( span, restrict_msg, format ! (
1129
- "{} + " ,
1130
- trait_ref. to_predicate( ) ,
1131
- ) , Applicability :: MachineApplicable ) ;
1132
- } else {
1133
- err. span_label ( param. span , & format ! (
1134
- "consider adding a `where {}` bound" ,
1135
- trait_ref. to_predicate( ) ,
1136
- ) ) ;
1137
- }
1129
+ err. span_label ( param. span , & format ! (
1130
+ "consider adding a `where {}` bound" ,
1131
+ trait_ref. to_predicate( ) ,
1132
+ ) ) ;
1138
1133
}
1139
1134
}
1140
- return ;
1141
1135
}
1136
+ return ;
1142
1137
}
1143
1138
}
1139
+
1144
1140
hir:: Node :: Crate => return ,
1141
+
1145
1142
_ => { }
1146
1143
}
1147
1144
1148
1145
hir_id = self . tcx . hir ( ) . get_parent_item ( hir_id) ;
1149
1146
}
1150
- // FIXME: Add special check for `?Sized` so we don't suggest `T: Sized + ?Sized`.
1151
-
1152
- // Fallback in case we didn't find the type argument. Can happen on associated types
1153
- // bounds and when `Self` needs to be restricted, like in the ui test
1154
- // `associated-types-projection-to-unrelated-trait-in-method-without-default.rs`.
1155
- err. help ( & format ! ( "consider adding a `where {}` bound" , trait_ref. to_predicate( ) ) ) ;
1156
1147
}
1157
1148
1158
1149
/// When encountering an assignment of an unsized trait, like `let x = ""[..];`, provide a
0 commit comments