@@ -13,9 +13,11 @@ use std::assert_matches::debug_assert_matches;
1313use min_specialization:: check_min_specialization;
1414use rustc_data_structures:: fx:: FxHashSet ;
1515use rustc_errors:: codes:: * ;
16+ use rustc_errors:: { Applicability , Diag } ;
1617use rustc_hir:: def:: DefKind ;
1718use 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 } ;
1921use rustc_span:: ErrorGuaranteed ;
2022
2123use crate :: constrained_generic_params as cgp;
@@ -128,6 +130,21 @@ pub(crate) fn enforce_impl_lifetime_params_are_constrained(
128130 for param in & impl_generics. own_params {
129131 match param. kind {
130132 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+ }
131148 // This is a horrible concession to reality. I think it'd be
132149 // better to just ban unconstrained lifetimes outright, but in
133150 // practice people do non-hygienic macros like:
@@ -158,6 +175,7 @@ pub(crate) fn enforce_impl_lifetime_params_are_constrained(
158175 const_param_note2 : false ,
159176 } ) ;
160177 diag. code ( E0207 ) ;
178+ suggest_to_remove_or_use_generic ( tcx, & mut diag, impl_def_id, param) ;
161179 res = Err ( diag. emit ( ) ) ;
162180 }
163181 }
@@ -229,8 +247,60 @@ pub(crate) fn enforce_impl_non_lifetime_params_are_constrained(
229247 const_param_note2 : const_param_note,
230248 } ) ;
231249 diag. code ( E0207 ) ;
250+ suggest_to_remove_or_use_generic ( tcx, & mut diag, impl_def_id, & param) ;
232251 res = Err ( diag. emit ( ) ) ;
233252 }
234253 }
235254 res
236255}
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