@@ -984,84 +984,66 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
984984 }
985985 } ;
986986
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`.
9871006 let mut hir_id = body_id;
9881007 while let Some ( node) = self . tcx . hir ( ) . find ( hir_id) {
989- debug ! ( "suggest_restricting_param_bound node={:?}" , node) ;
9901008 match node {
9911009 hir:: Node :: Item ( hir:: Item {
992- kind : hir:: ItemKind :: Fn ( decl , _, generics, _) , ..
1010+ kind : hir:: ItemKind :: Fn ( _ , _, generics, _) , ..
9931011 } ) |
9941012 hir:: Node :: TraitItem ( hir:: TraitItem {
9951013 generics,
996- kind : hir:: TraitItemKind :: Method ( hir :: MethodSig { decl , .. } , _ ) , ..
1014+ kind : hir:: TraitItemKind :: Method ( .. ) , ..
9971015 } ) |
9981016 hir:: Node :: ImplItem ( hir:: ImplItem {
9991017 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`" ) ;
10171022 return ;
10181023 }
1024+
10191025 hir:: Node :: Item ( hir:: Item {
1020- kind : hir:: ItemKind :: Fn ( decl , _, generics, _) , ..
1026+ kind : hir:: ItemKind :: Fn ( _ , _, generics, _) , ..
10211027 } ) |
10221028 hir:: Node :: TraitItem ( hir:: TraitItem {
10231029 generics,
1024- kind : hir:: TraitItemKind :: Method ( hir :: MethodSig { decl , .. } , _ ) , ..
1030+ kind : hir:: TraitItemKind :: Method ( .. ) , ..
10251031 } ) |
10261032 hir:: Node :: ImplItem ( hir:: ImplItem {
10271033 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+ } ) |
10471039 hir:: Node :: Item ( hir:: Item {
10481040 kind : hir:: ItemKind :: Impl ( _, _, _, generics, ..) , ..
10491041 } ) 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" ) ;
10631044 return ;
10641045 }
1046+
10651047 hir:: Node :: Item ( hir:: Item { kind : hir:: ItemKind :: Struct ( _, generics) , span, .. } ) |
10661048 hir:: Node :: Item ( hir:: Item { kind : hir:: ItemKind :: Enum ( _, generics) , span, .. } ) |
10671049 hir:: Node :: Item ( hir:: Item { kind : hir:: ItemKind :: Union ( _, generics) , span, .. } ) |
@@ -1086,73 +1068,82 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
10861068 hir:: Node :: TraitItem ( hir:: TraitItem { generics, span, .. } ) |
10871069 hir:: Node :: ImplItem ( hir:: ImplItem { generics, span, .. } )
10881070 if param_ty. is_some ( ) => {
1071+ // Missing generic type parameter bound.
10891072 let restrict_msg = "consider further restricting this bound" ;
10901073 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) {}`
10941094 err. span_suggestion (
10951095 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( ) ) ,
10991111 Applicability :: MachineApplicable ,
11001112 ) ;
11011113 } 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 ) ;
11211128 } 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+ ) ) ;
11381133 }
11391134 }
1140- return ;
11411135 }
1136+ return ;
11421137 }
11431138 }
1139+
11441140 hir:: Node :: Crate => return ,
1141+
11451142 _ => { }
11461143 }
11471144
11481145 hir_id = self . tcx . hir ( ) . get_parent_item ( hir_id) ;
11491146 }
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( ) ) ) ;
11561147 }
11571148
11581149 /// When encountering an assignment of an unsized trait, like `let x = ""[..];`, provide a
0 commit comments