@@ -39,6 +39,7 @@ use syntax::ast;
39
39
use syntax:: symbol:: { sym, kw} ;
40
40
use syntax_pos:: { DUMMY_SP , Span , ExpnKind , MultiSpan } ;
41
41
use rustc:: hir:: def_id:: LOCAL_CRATE ;
42
+ use syntax_pos:: source_map:: SourceMap ;
42
43
43
44
use rustc_error_codes:: * ;
44
45
@@ -1091,7 +1092,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
1091
1092
}
1092
1093
fn suggest_restricting_param_bound(
1093
1094
& self ,
1094
- err : & mut DiagnosticBuilder < ' _ > ,
1095
+ mut err : & mut DiagnosticBuilder < ' _ > ,
1095
1096
trait_ref : & ty:: PolyTraitRef < ' _ > ,
1096
1097
body_id : hir:: HirId ,
1097
1098
) {
@@ -1102,7 +1103,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
1102
1103
_ => return ,
1103
1104
} ;
1104
1105
1105
- let mut suggest_restriction = |generics : & hir:: Generics , msg| {
1106
+ let suggest_restriction = |
1107
+ generics : & hir:: Generics ,
1108
+ msg,
1109
+ err : & mut DiagnosticBuilder < ' _ > ,
1110
+ | {
1106
1111
let span = generics. where_clause. span_for_predicates_or_empty_place( ) ;
1107
1112
if !span. from_expansion( ) && span. desugaring_kind( ) . is_none( ) {
1108
1113
err. span_suggestion(
@@ -1132,7 +1137,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
1132
1137
kind : hir:: TraitItemKind :: Method ( ..) , ..
1133
1138
} ) if param_ty && self_ty == self . tcx. types. self_param => {
1134
1139
// Restricting `Self` for a single method.
1135
- suggest_restriction ( & generics, "`Self`" ) ;
1140
+ suggest_restriction( & generics, "`Self`" , err ) ;
1136
1141
return ;
1137
1142
}
1138
1143
@@ -1154,7 +1159,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
1154
1159
kind : hir:: ItemKind :: Impl ( _, _, _, generics, ..) , ..
1155
1160
} ) if projection. is_some( ) => {
1156
1161
// Missing associated type bound.
1157
- suggest_restriction ( & generics, "the associated type" ) ;
1162
+ suggest_restriction( & generics, "the associated type" , err ) ;
1158
1163
return ;
1159
1164
}
1160
1165
@@ -1183,68 +1188,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
1183
1188
hir:: Node :: ImplItem ( hir:: ImplItem { generics, span, .. } )
1184
1189
if param_ty => {
1185
1190
// Missing generic type parameter bound.
1186
- let restrict_msg = "consider further restricting this bound" ;
1187
1191
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
+ ) {
1248
1201
return ;
1249
1202
}
1250
1203
}
@@ -2546,3 +2499,76 @@ impl ArgKind {
2546
2499
}
2547
2500
}
2548
2501
}
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