@@ -12,9 +12,14 @@ use std::assert_matches::debug_assert_matches;
1212
1313use min_specialization:: check_min_specialization;
1414use rustc_data_structures:: fx:: FxHashSet ;
15+ use rustc_errors:: Applicability ;
1516use rustc_errors:: codes:: * ;
1617use rustc_hir:: def:: DefKind ;
1718use rustc_hir:: def_id:: LocalDefId ;
19+ use rustc_hir:: {
20+ GenericParam , GenericParamKind , LifetimeParamKind , Path , PredicateOrigin , QPath , Ty , TyKind ,
21+ WhereBoundPredicate , WherePredicateKind ,
22+ } ;
1823use rustc_middle:: ty:: { self , TyCtxt , TypeVisitableExt } ;
1924use rustc_span:: ErrorGuaranteed ;
2025
@@ -121,6 +126,14 @@ fn enforce_impl_params_are_constrained(
121126 } )
122127 . collect ( ) ;
123128
129+ let node = tcx. hir ( ) . get_if_local ( impl_def_id. into ( ) ) . expect ( "cannot get `Node`" ) ;
130+ let hir_impl = if let rustc_hir:: Node :: Item ( item) = node {
131+ if let rustc_hir:: ItemKind :: Impl ( imp) = item. kind { Some ( imp) } else { None }
132+ } else {
133+ None
134+ }
135+ . expect ( "cannot take `Impl` in a impl block" ) ;
136+
124137 let mut res = Ok ( ( ) ) ;
125138 for param in & impl_generics. own_params {
126139 let err = match param. kind {
@@ -149,6 +162,79 @@ fn enforce_impl_params_are_constrained(
149162 const_param_note2 : const_param_note,
150163 } ) ;
151164 diag. code ( E0207 ) ;
165+
166+ let ( index, hir_param) = hir_impl
167+ . generics
168+ . params
169+ . iter ( )
170+ . enumerate ( )
171+ . find ( |( _, par) | par. name . ident ( ) . name == param. name )
172+ . unwrap ( ) ;
173+ let mut suggestions = vec ! [ ] ;
174+
175+ let is_impl_generic = |par : & & GenericParam < ' _ > | match par. kind {
176+ GenericParamKind :: Type { .. }
177+ | GenericParamKind :: Const { .. }
178+ | GenericParamKind :: Lifetime { kind : LifetimeParamKind :: Explicit } => true ,
179+ _ => false ,
180+ } ;
181+ // Suggestion for removing the type parameter.
182+ suggestions. push ( vec ! [ (
183+ // Find the span of the type parameter.
184+ if let Some ( prev) = hir_impl. generics. params[ ..index] . iter( ) . rfind( is_impl_generic)
185+ {
186+ let mut span = prev. span;
187+
188+ // Consider the span of the bounds with the generic parameter when there is.
189+ if let Some ( predicate) = hir_impl. generics. predicates. iter( ) . find( |pred| {
190+ if let WherePredicateKind :: BoundPredicate ( WhereBoundPredicate {
191+ origin: PredicateOrigin :: GenericParam ,
192+ bounded_ty,
193+ ..
194+ } ) = pred. kind
195+ {
196+ bounded_ty. span == prev. span
197+ } else {
198+ false
199+ }
200+ } ) {
201+ span = span. to( predicate. span)
202+ } ;
203+
204+ span. shrink_to_hi( ) . to( hir_param. span)
205+ } else if let Some ( next) =
206+ hir_impl. generics. params[ index + 1 ..] . iter( ) . find( is_impl_generic)
207+ {
208+ hir_param. span. until( next. span)
209+ } else {
210+ // Remove also angle brackets <> when there is just ONE generic parameter.
211+ hir_impl. generics. span
212+ } ,
213+ String :: new( ) ,
214+ ) ] ) ;
215+
216+ // Suggestion for making use of the type parameter.
217+ if let Some ( path) = extract_ty_as_path ( hir_impl. self_ty ) {
218+ let seg = path. segments . last ( ) . unwrap ( ) ;
219+ if let Some ( args) = seg. args {
220+ suggestions. push ( vec ! [ (
221+ args. span( ) . unwrap( ) . shrink_to_hi( ) ,
222+ format!( ", {}" , param. name) ,
223+ ) ] ) ;
224+ } else {
225+ suggestions
226+ . push ( vec ! [ ( seg. ident. span. shrink_to_hi( ) , format!( "<{}>" , param. name) ) ] ) ;
227+ }
228+ }
229+
230+ diag. multipart_suggestions (
231+ format ! (
232+ "either remove the type parameter {}, or make use of it, for example" ,
233+ param. name
234+ ) ,
235+ suggestions,
236+ Applicability :: MaybeIncorrect ,
237+ ) ;
152238 res = Err ( diag. emit ( ) ) ;
153239 }
154240 }
@@ -173,3 +259,12 @@ fn enforce_impl_params_are_constrained(
173259 // associated types. I believe this is sound, because lifetimes
174260 // used elsewhere are not projected back out.
175261}
262+
263+ fn extract_ty_as_path < ' hir > ( ty : & Ty < ' hir > ) -> Option < & ' hir Path < ' hir > > {
264+ match ty. kind {
265+ TyKind :: Path ( QPath :: Resolved ( _, path) ) => Some ( path) ,
266+ TyKind :: Slice ( ty) | TyKind :: Array ( ty, _) => extract_ty_as_path ( ty) ,
267+ TyKind :: Ptr ( ty) | TyKind :: Ref ( _, ty) => extract_ty_as_path ( ty. ty ) ,
268+ _ => None ,
269+ }
270+ }
0 commit comments