@@ -39,6 +39,7 @@ use syntax::ast;
3939use syntax:: symbol:: { sym, kw} ;
4040use syntax_pos:: { DUMMY_SP , Span , ExpnKind , MultiSpan } ;
4141use rustc:: hir:: def_id:: LOCAL_CRATE ;
42+ use syntax_pos:: source_map:: SourceMap ;
4243
4344use rustc_error_codes:: * ;
4445
@@ -1091,7 +1092,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
10911092 }
10921093 fn suggest_restricting_param_bound(
10931094 & self ,
1094- err : & mut DiagnosticBuilder < ' _ > ,
1095+ mut err : & mut DiagnosticBuilder < ' _ > ,
10951096 trait_ref : & ty:: PolyTraitRef < ' _ > ,
10961097 body_id : hir:: HirId ,
10971098 ) {
@@ -1102,7 +1103,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
11021103 _ => return ,
11031104 } ;
11041105
1105- let mut suggest_restriction = |generics : & hir:: Generics , msg| {
1106+ let suggest_restriction = |
1107+ generics : & hir:: Generics ,
1108+ msg,
1109+ err : & mut DiagnosticBuilder < ' _ > ,
1110+ | {
11061111 let span = generics. where_clause. span_for_predicates_or_empty_place( ) ;
11071112 if !span. from_expansion( ) && span. desugaring_kind( ) . is_none( ) {
11081113 err. span_suggestion(
@@ -1132,7 +1137,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
11321137 kind : hir:: TraitItemKind :: Method ( ..) , ..
11331138 } ) if param_ty && self_ty == self . tcx. types. self_param => {
11341139 // Restricting `Self` for a single method.
1135- suggest_restriction ( & generics, "`Self`" ) ;
1140+ suggest_restriction( & generics, "`Self`" , err ) ;
11361141 return ;
11371142 }
11381143
@@ -1154,7 +1159,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
11541159 kind : hir:: ItemKind :: Impl ( _, _, _, generics, ..) , ..
11551160 } ) if projection. is_some( ) => {
11561161 // Missing associated type bound.
1157- suggest_restriction ( & generics, "the associated type" ) ;
1162+ suggest_restriction( & generics, "the associated type" , err ) ;
11581163 return ;
11591164 }
11601165
@@ -1183,68 +1188,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
11831188 hir:: Node :: ImplItem ( hir:: ImplItem { generics, span, .. } )
11841189 if param_ty => {
11851190 // Missing generic type parameter bound.
1186- let restrict_msg = "consider further restricting this bound" ;
11871191 let param_name = self_ty. to_string ( ) ;
1188- for param in generics. params . iter ( ) . filter ( |p| {
1189- p. name . ident ( ) . as_str ( ) == param_name
1190- } ) {
1191- if param_name. starts_with ( "impl " ) {
1192- // `impl Trait` in argument:
1193- // `fn foo(x: impl Trait) {}` → `fn foo(t: impl Trait + Trait2) {}`
1194- err. span_suggestion (
1195- param. span ,
1196- restrict_msg,
1197- // `impl CurrentTrait + MissingTrait`
1198- format ! ( "{} + {}" , param. name. ident( ) , trait_ref) ,
1199- Applicability :: MachineApplicable ,
1200- ) ;
1201- } else if generics. where_clause . predicates . is_empty ( ) &&
1202- param. bounds . is_empty ( )
1203- {
1204- // If there are no bounds whatsoever, suggest adding a constraint
1205- // to the type parameter:
1206- // `fn foo<T>(t: T) {}` → `fn foo<T: Trait>(t: T) {}`
1207- err. span_suggestion (
1208- param. span ,
1209- "consider restricting this bound" ,
1210- format ! ( "{}" , trait_ref. to_predicate( ) ) ,
1211- Applicability :: MachineApplicable ,
1212- ) ;
1213- } else if !generics. where_clause . predicates . is_empty ( ) {
1214- // There is a `where` clause, so suggest expanding it:
1215- // `fn foo<T>(t: T) where T: Debug {}` →
1216- // `fn foo<T>(t: T) where T: Debug, T: Trait {}`
1217- err. span_suggestion (
1218- generics. where_clause . span ( ) . unwrap ( ) . shrink_to_hi ( ) ,
1219- & format ! (
1220- "consider further restricting type parameter `{}`" ,
1221- param_name,
1222- ) ,
1223- format ! ( ", {}" , trait_ref. to_predicate( ) ) ,
1224- Applicability :: MachineApplicable ,
1225- ) ;
1226- } else {
1227- // If there is no `where` clause lean towards constraining to the
1228- // type parameter:
1229- // `fn foo<X: Bar, T>(t: T, x: X) {}` → `fn foo<T: Trait>(t: T) {}`
1230- // `fn foo<T: Bar>(t: T) {}` → `fn foo<T: Bar + Trait>(t: T) {}`
1231- let sp = param. span . with_hi ( span. hi ( ) ) ;
1232- let span = self . tcx . sess . source_map ( )
1233- . span_through_char ( sp, ':' ) ;
1234- if sp != param. span && sp != span {
1235- // Only suggest if we have high certainty that the span
1236- // covers the colon in `foo<T: Trait>`.
1237- err. span_suggestion ( span, restrict_msg, format ! (
1238- "{} + " ,
1239- trait_ref. to_predicate( ) ,
1240- ) , Applicability :: MachineApplicable ) ;
1241- } else {
1242- err. span_label ( param. span , & format ! (
1243- "consider adding a `where {}` bound" ,
1244- trait_ref. to_predicate( ) ,
1245- ) ) ;
1246- }
1247- }
1192+ let constraint = trait_ref. to_string ( ) ;
1193+ if suggest_constraining_type_param (
1194+ generics,
1195+ & mut err,
1196+ & param_name,
1197+ & constraint,
1198+ self . tcx . sess . source_map ( ) ,
1199+ * span,
1200+ ) {
12481201 return ;
12491202 }
12501203 }
@@ -2546,3 +2499,76 @@ impl ArgKind {
25462499 }
25472500 }
25482501}
2502+
2503+ /// Suggest restricting a type param with a new bound.
2504+ pub fn suggest_constraining_type_param (
2505+ generics : & hir:: Generics ,
2506+ err : & mut DiagnosticBuilder < ' _ > ,
2507+ param_name : & str ,
2508+ constraint : & str ,
2509+ source_map : & SourceMap ,
2510+ span : Span ,
2511+ ) -> bool {
2512+ let restrict_msg = "consider further restricting this bound" ;
2513+ if let Some ( param) = generics. params . iter ( ) . filter ( |p| {
2514+ p. name . ident ( ) . as_str ( ) == param_name
2515+ } ) . next ( ) {
2516+ if param_name. starts_with ( "impl " ) {
2517+ // `impl Trait` in argument:
2518+ // `fn foo(x: impl Trait) {}` → `fn foo(t: impl Trait + Trait2) {}`
2519+ err. span_suggestion (
2520+ param. span ,
2521+ restrict_msg,
2522+ // `impl CurrentTrait + MissingTrait`
2523+ format ! ( "{} + {}" , param_name, constraint) ,
2524+ Applicability :: MachineApplicable ,
2525+ ) ;
2526+ } else if generics. where_clause . predicates . is_empty ( ) &&
2527+ param. bounds . is_empty ( )
2528+ {
2529+ // If there are no bounds whatsoever, suggest adding a constraint
2530+ // to the type parameter:
2531+ // `fn foo<T>(t: T) {}` → `fn foo<T: Trait>(t: T) {}`
2532+ err. span_suggestion (
2533+ param. span ,
2534+ "consider restricting this bound" ,
2535+ format ! ( "{}: {}" , param_name, constraint) ,
2536+ Applicability :: MachineApplicable ,
2537+ ) ;
2538+ } else if !generics. where_clause . predicates . is_empty ( ) {
2539+ // There is a `where` clause, so suggest expanding it:
2540+ // `fn foo<T>(t: T) where T: Debug {}` →
2541+ // `fn foo<T>(t: T) where T: Debug, T: Trait {}`
2542+ err. span_suggestion (
2543+ generics. where_clause . span ( ) . unwrap ( ) . shrink_to_hi ( ) ,
2544+ & format ! ( "consider further restricting type parameter `{}`" , param_name) ,
2545+ format ! ( ", {}: {}" , param_name, constraint) ,
2546+ Applicability :: MachineApplicable ,
2547+ ) ;
2548+ } else {
2549+ // If there is no `where` clause lean towards constraining to the
2550+ // type parameter:
2551+ // `fn foo<X: Bar, T>(t: T, x: X) {}` → `fn foo<T: Trait>(t: T) {}`
2552+ // `fn foo<T: Bar>(t: T) {}` → `fn foo<T: Bar + Trait>(t: T) {}`
2553+ let sp = param. span . with_hi ( span. hi ( ) ) ;
2554+ let span = source_map. span_through_char ( sp, ':' ) ;
2555+ if sp != param. span && sp != span {
2556+ // Only suggest if we have high certainty that the span
2557+ // covers the colon in `foo<T: Trait>`.
2558+ err. span_suggestion (
2559+ span,
2560+ restrict_msg,
2561+ format ! ( "{}: {} + " , param_name, constraint) ,
2562+ Applicability :: MachineApplicable ,
2563+ ) ;
2564+ } else {
2565+ err. span_label (
2566+ param. span ,
2567+ & format ! ( "consider adding a `where {}: {}` bound" , param_name, constraint) ,
2568+ ) ;
2569+ }
2570+ }
2571+ return true ;
2572+ }
2573+ false
2574+ }
0 commit comments