@@ -9,7 +9,7 @@ use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, ErrorG
99use rustc_hir as hir;
1010use rustc_hir:: def_id:: { DefId , LocalDefId } ;
1111use rustc_infer:: traits:: FulfillmentError ;
12- use rustc_middle:: ty:: { self , suggest_constraining_type_param, Ty , TyCtxt } ;
12+ use rustc_middle:: ty:: { self , suggest_constraining_type_param, AssocItem , AssocKind , Ty , TyCtxt } ;
1313use rustc_session:: parse:: feature_err;
1414use rustc_span:: edit_distance:: find_best_match_for_name;
1515use rustc_span:: symbol:: { sym, Ident } ;
@@ -509,6 +509,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
509509 if associated_types. values ( ) . all ( |v| v. is_empty ( ) ) {
510510 return ;
511511 }
512+
512513 let tcx = self . tcx ( ) ;
513514 // FIXME: Marked `mut` so that we can replace the spans further below with a more
514515 // appropriate one, but this should be handled earlier in the span assignment.
@@ -581,6 +582,32 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
581582 }
582583 }
583584
585+ // We get all the associated items that _are_ set,
586+ // so that we can check if any of their names match one of the ones we are missing.
587+ // This would mean that they are shadowing the associated type we are missing,
588+ // and we can then use their span to indicate this to the user.
589+ let bound_names = trait_bounds
590+ . iter ( )
591+ . filter_map ( |poly_trait_ref| {
592+ let path = poly_trait_ref. trait_ref . path . segments . last ( ) ?;
593+ let args = path. args ?;
594+
595+ Some ( args. bindings . iter ( ) . filter_map ( |binding| {
596+ let ident = binding. ident ;
597+ let trait_def = path. res . def_id ( ) ;
598+ let assoc_item = tcx. associated_items ( trait_def) . find_by_name_and_kind (
599+ tcx,
600+ ident,
601+ AssocKind :: Type ,
602+ trait_def,
603+ ) ;
604+
605+ Some ( ( ident. name , assoc_item?) )
606+ } ) )
607+ } )
608+ . flatten ( )
609+ . collect :: < FxHashMap < Symbol , & AssocItem > > ( ) ;
610+
584611 let mut names = names
585612 . into_iter ( )
586613 . map ( |( trait_, mut assocs) | {
@@ -610,6 +637,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
610637 pluralize!( names_len) ,
611638 names,
612639 ) ;
640+ let mut rename_count = 0 ;
613641 let mut suggestions = vec ! [ ] ;
614642 let mut types_count = 0 ;
615643 let mut where_constraints = vec ! [ ] ;
@@ -621,23 +649,65 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
621649 * names. entry ( item. name ) . or_insert ( 0 ) += 1 ;
622650 }
623651 let mut dupes = false ;
652+ let mut shadows = false ;
624653 for item in assoc_items {
625654 let prefix = if names[ & item. name ] > 1 {
626655 let trait_def_id = item. container_id ( tcx) ;
627656 dupes = true ;
628657 format ! ( "{}::" , tcx. def_path_str( trait_def_id) )
658+ } else if bound_names. get ( & item. name ) . is_some_and ( |x| x != & item) {
659+ let trait_def_id = item. container_id ( tcx) ;
660+ shadows = true ;
661+ format ! ( "{}::" , tcx. def_path_str( trait_def_id) )
629662 } else {
630663 String :: new ( )
631664 } ;
665+
666+ let mut is_shadowed = false ;
667+
668+ if let Some ( assoc_item) = bound_names. get ( & item. name )
669+ && assoc_item != & item
670+ {
671+ is_shadowed = true ;
672+ if let Some ( sp) = tcx. hir ( ) . span_if_local ( assoc_item. def_id ) {
673+ err. span_label (
674+ sp,
675+ format ! (
676+ "`{}{}` shadowed here, consider renaming it" ,
677+ prefix, item. name
678+ ) ,
679+ ) ;
680+ rename_count += 1 ;
681+ }
682+ }
683+
632684 if let Some ( sp) = tcx. hir ( ) . span_if_local ( item. def_id ) {
633- err. span_label ( sp, format ! ( "`{}{}` defined here" , prefix, item. name) ) ;
685+ let rename_message = if is_shadowed {
686+ rename_count += 1 ;
687+ ", consider renaming it"
688+ } else {
689+ ""
690+ } ;
691+
692+ err. span_label (
693+ sp,
694+ format ! ( "`{}{}` defined here{}" , prefix, item. name, rename_message) ,
695+ ) ;
634696 }
635697 }
636698 if potential_assoc_types. len ( ) == assoc_items. len ( ) {
637699 // When the amount of missing associated types equals the number of
638700 // extra type arguments present. A suggesting to replace the generic args with
639701 // associated types is already emitted.
640702 already_has_generics_args_suggestion = true ;
703+ } else if shadows {
704+ let message = if rename_count > 1 {
705+ "consider renaming one of the associated types"
706+ } else {
707+ "consider renaming the associated type"
708+ } ;
709+
710+ err. help ( message) ;
641711 } else if let ( Ok ( snippet) , false ) =
642712 ( tcx. sess . source_map ( ) . span_to_snippet ( * span) , dupes)
643713 {
@@ -721,6 +791,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
721791 err. span_help ( where_constraints, where_msg) ;
722792 }
723793 }
794+
724795 err. emit ( ) ;
725796 }
726797}
0 commit comments