@@ -6,10 +6,9 @@ use crate::errors::{
6
6
use rustc_data_structures:: fx:: FxHashMap ;
7
7
use rustc_errors:: { pluralize, struct_span_err, Applicability , Diagnostic , ErrorGuaranteed } ;
8
8
use rustc_hir as hir;
9
- use rustc_hir:: def_id:: DefId ;
9
+ use rustc_hir:: def_id:: { DefId , LocalDefId } ;
10
10
use rustc_infer:: traits:: FulfillmentError ;
11
- use rustc_middle:: ty:: TyCtxt ;
12
- use rustc_middle:: ty:: { self , Ty } ;
11
+ use rustc_middle:: ty:: { self , suggest_constraining_type_param, Ty , TyCtxt } ;
13
12
use rustc_session:: parse:: feature_err;
14
13
use rustc_span:: edit_distance:: find_best_match_for_name;
15
14
use rustc_span:: symbol:: { sym, Ident } ;
@@ -102,6 +101,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
102
101
& self ,
103
102
all_candidates : impl Fn ( ) -> I ,
104
103
ty_param_name : & str ,
104
+ ty_param_def_id : Option < LocalDefId > ,
105
105
assoc_name : Ident ,
106
106
span : Span ,
107
107
) -> ErrorGuaranteed
@@ -190,13 +190,61 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
190
190
} )
191
191
. collect :: < Vec < _ > > ( ) [ ..]
192
192
{
193
+ let trait_name = self . tcx ( ) . def_path_str ( * best_trait) ;
194
+ let an = if suggested_name != assoc_name. name { "a similarly named" } else { "an" } ;
193
195
err. span_label (
194
196
assoc_name. span ,
195
197
format ! (
196
- "there is a similarly named associated type `{suggested_name}` in the trait `{}`" ,
197
- self . tcx ( ) . def_path_str ( * best_trait )
198
+ "there is {an} associated type `{suggested_name}` in the \
199
+ trait `{trait_name}`" ,
198
200
) ,
199
201
) ;
202
+ let hir = self . tcx ( ) . hir ( ) ;
203
+ if let Some ( def_id) = ty_param_def_id
204
+ && let parent = hir. get_parent_item ( hir. local_def_id_to_hir_id ( def_id) )
205
+ && let Some ( generics) = hir. get_generics ( parent. def_id )
206
+ {
207
+ if generics. bounds_for_param ( def_id)
208
+ . flat_map ( |pred| pred. bounds . iter ( ) )
209
+ . any ( |b| match b {
210
+ hir:: GenericBound :: Trait ( t, ..) => {
211
+ t. trait_ref . trait_def_id ( ) . as_ref ( ) == Some ( best_trait)
212
+ }
213
+ _ => false ,
214
+ } )
215
+ {
216
+ // The type param already has a bound for `trait_name`, we just need to
217
+ // change the associated type.
218
+ err. span_suggestion_verbose (
219
+ assoc_name. span ,
220
+ format ! (
221
+ "change the associated type name to use `{suggested_name}` from \
222
+ `{trait_name}`",
223
+ ) ,
224
+ suggested_name. to_string ( ) ,
225
+ Applicability :: MaybeIncorrect ,
226
+ ) ;
227
+ } else if suggest_constraining_type_param (
228
+ self . tcx ( ) ,
229
+ generics,
230
+ & mut err,
231
+ & ty_param_name,
232
+ & trait_name,
233
+ None ,
234
+ None ,
235
+ )
236
+ && suggested_name != assoc_name. name
237
+ {
238
+ // We suggested constraining a type parameter, but the associated type on it
239
+ // was also not an exact match, so we also suggest changing it.
240
+ err. span_suggestion_verbose (
241
+ assoc_name. span ,
242
+ "and also change the associated type name" ,
243
+ suggested_name. to_string ( ) ,
244
+ Applicability :: MaybeIncorrect ,
245
+ ) ;
246
+ }
247
+ }
200
248
return err. emit ( ) ;
201
249
}
202
250
}
0 commit comments