@@ -13,9 +13,11 @@ use std::assert_matches::debug_assert_matches;
13
13
use min_specialization:: check_min_specialization;
14
14
use rustc_data_structures:: fx:: FxHashSet ;
15
15
use rustc_errors:: codes:: * ;
16
+ use rustc_errors:: { Applicability , Diag } ;
16
17
use rustc_hir:: def:: DefKind ;
17
18
use rustc_hir:: def_id:: LocalDefId ;
18
- use rustc_middle:: ty:: { self , TyCtxt , TypeVisitableExt } ;
19
+ use rustc_hir:: { Path , QPath , Ty , TyKind } ;
20
+ use rustc_middle:: ty:: { self , GenericParamDef , TyCtxt , TypeVisitableExt } ;
19
21
use rustc_span:: ErrorGuaranteed ;
20
22
21
23
use crate :: constrained_generic_params as cgp;
@@ -128,6 +130,21 @@ pub(crate) fn enforce_impl_lifetime_params_are_constrained(
128
130
for param in & impl_generics. own_params {
129
131
match param. kind {
130
132
ty:: GenericParamDefKind :: Lifetime => {
133
+ let param_lt = cgp:: Parameter :: from ( param. to_early_bound_region_data ( ) ) ;
134
+ if lifetimes_in_associated_types. contains ( & param_lt) // (*)
135
+ && !input_parameters. contains ( & param_lt)
136
+ {
137
+ let mut diag = tcx. dcx ( ) . create_err ( UnconstrainedGenericParameter {
138
+ span : tcx. def_span ( param. def_id ) ,
139
+ param_name : param. name ,
140
+ param_def_kind : tcx. def_descr ( param. def_id ) ,
141
+ const_param_note : false ,
142
+ const_param_note2 : false ,
143
+ } ) ;
144
+ diag. code ( E0207 ) ;
145
+ suggest_to_remove_or_use_generic ( tcx, & mut diag, impl_def_id, param) ;
146
+ res = Err ( diag. emit ( ) ) ;
147
+ }
131
148
// This is a horrible concession to reality. I think it'd be
132
149
// better to just ban unconstrained lifetimes outright, but in
133
150
// practice people do non-hygienic macros like:
@@ -158,6 +175,7 @@ pub(crate) fn enforce_impl_lifetime_params_are_constrained(
158
175
const_param_note2 : false ,
159
176
} ) ;
160
177
diag. code ( E0207 ) ;
178
+ suggest_to_remove_or_use_generic ( tcx, & mut diag, impl_def_id, param) ;
161
179
res = Err ( diag. emit ( ) ) ;
162
180
}
163
181
}
@@ -229,8 +247,60 @@ pub(crate) fn enforce_impl_non_lifetime_params_are_constrained(
229
247
const_param_note2 : const_param_note,
230
248
} ) ;
231
249
diag. code ( E0207 ) ;
250
+ suggest_to_remove_or_use_generic ( tcx, & mut diag, impl_def_id, & param) ;
232
251
res = Err ( diag. emit ( ) ) ;
233
252
}
234
253
}
235
254
res
236
255
}
256
+
257
+ fn suggest_to_remove_or_use_generic (
258
+ tcx : TyCtxt < ' _ > ,
259
+ diag : & mut Diag < ' _ > ,
260
+ impl_def_id : LocalDefId ,
261
+ param : & GenericParamDef ,
262
+ ) {
263
+ let node = tcx. hir_node_by_def_id ( impl_def_id) ;
264
+ let hir_impl = node. expect_item ( ) . expect_impl ( ) ;
265
+
266
+ let Some ( ( index, _) ) = hir_impl
267
+ . generics
268
+ . params
269
+ . iter ( )
270
+ . enumerate ( )
271
+ . find ( |( _, par) | par. def_id . to_def_id ( ) == param. def_id )
272
+ else {
273
+ return ;
274
+ } ;
275
+
276
+ let mut suggestions = vec ! [ ] ;
277
+
278
+ // Suggestion for removing the type parameter.
279
+ suggestions. push ( vec ! [ ( hir_impl. generics. span_for_param_removal( index) , String :: new( ) ) ] ) ;
280
+
281
+ // Suggestion for making use of the type parameter.
282
+ if let Some ( path) = extract_ty_as_path ( hir_impl. self_ty ) {
283
+ let seg = path. segments . last ( ) . unwrap ( ) ;
284
+ if let Some ( args) = seg. args {
285
+ suggestions
286
+ . push ( vec ! [ ( args. span( ) . unwrap( ) . shrink_to_hi( ) , format!( ", {}" , param. name) ) ] ) ;
287
+ } else {
288
+ suggestions. push ( vec ! [ ( seg. ident. span. shrink_to_hi( ) , format!( "<{}>" , param. name) ) ] ) ;
289
+ }
290
+ }
291
+
292
+ diag. multipart_suggestions (
293
+ format ! ( "either remove the type parameter {}, or make use of it, for example" , param. name) ,
294
+ suggestions,
295
+ Applicability :: MaybeIncorrect ,
296
+ ) ;
297
+ }
298
+
299
+ fn extract_ty_as_path < ' hir > ( ty : & Ty < ' hir > ) -> Option < & ' hir Path < ' hir > > {
300
+ match ty. kind {
301
+ TyKind :: Path ( QPath :: Resolved ( _, path) ) => Some ( path) ,
302
+ TyKind :: Slice ( ty) | TyKind :: Array ( ty, _) => extract_ty_as_path ( ty) ,
303
+ TyKind :: Ptr ( ty) | TyKind :: Ref ( _, ty) => extract_ty_as_path ( ty. ty ) ,
304
+ _ => None ,
305
+ }
306
+ }
0 commit comments