@@ -12,9 +12,14 @@ use std::assert_matches::debug_assert_matches;
12
12
13
13
use min_specialization:: check_min_specialization;
14
14
use rustc_data_structures:: fx:: FxHashSet ;
15
+ use rustc_errors:: Applicability ;
15
16
use rustc_errors:: codes:: * ;
16
17
use rustc_hir:: def:: DefKind ;
17
18
use rustc_hir:: def_id:: LocalDefId ;
19
+ use rustc_hir:: {
20
+ GenericParam , GenericParamKind , LifetimeParamKind , Path , PredicateOrigin , QPath , Ty , TyKind ,
21
+ WhereBoundPredicate , WherePredicateKind ,
22
+ } ;
18
23
use rustc_middle:: ty:: { self , TyCtxt , TypeVisitableExt } ;
19
24
use rustc_span:: ErrorGuaranteed ;
20
25
@@ -121,6 +126,14 @@ fn enforce_impl_params_are_constrained(
121
126
} )
122
127
. collect ( ) ;
123
128
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
+
124
137
let mut res = Ok ( ( ) ) ;
125
138
for param in & impl_generics. own_params {
126
139
let err = match param. kind {
@@ -149,6 +162,79 @@ fn enforce_impl_params_are_constrained(
149
162
const_param_note2 : const_param_note,
150
163
} ) ;
151
164
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
+ ) ;
152
238
res = Err ( diag. emit ( ) ) ;
153
239
}
154
240
}
@@ -173,3 +259,12 @@ fn enforce_impl_params_are_constrained(
173
259
// associated types. I believe this is sound, because lifetimes
174
260
// used elsewhere are not projected back out.
175
261
}
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