@@ -6,10 +6,9 @@ use crate::errors::{
66use rustc_data_structures:: fx:: FxHashMap ;
77use rustc_errors:: { pluralize, struct_span_err, Applicability , Diagnostic , ErrorGuaranteed } ;
88use rustc_hir as hir;
9- use rustc_hir:: def_id:: DefId ;
9+ use rustc_hir:: def_id:: { DefId , LocalDefId } ;
1010use 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 } ;
1312use rustc_session:: parse:: feature_err;
1413use rustc_span:: edit_distance:: find_best_match_for_name;
1514use rustc_span:: symbol:: { sym, Ident } ;
@@ -102,6 +101,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
102101 & self ,
103102 all_candidates : impl Fn ( ) -> I ,
104103 ty_param_name : & str ,
104+ ty_param_def_id : Option < LocalDefId > ,
105105 assoc_name : Ident ,
106106 span : Span ,
107107 ) -> ErrorGuaranteed
@@ -190,13 +190,61 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
190190 } )
191191 . collect :: < Vec < _ > > ( ) [ ..]
192192 {
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" } ;
193195 err. span_label (
194196 assoc_name. span ,
195197 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}`" ,
198200 ) ,
199201 ) ;
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+ }
200248 return err. emit ( ) ;
201249 }
202250 }
0 commit comments