@@ -9,7 +9,7 @@ use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, ErrorG
9
9
use rustc_hir as hir;
10
10
use rustc_hir:: def_id:: { DefId , LocalDefId } ;
11
11
use 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 } ;
13
13
use rustc_session:: parse:: feature_err;
14
14
use rustc_span:: edit_distance:: find_best_match_for_name;
15
15
use rustc_span:: symbol:: { sym, Ident } ;
@@ -509,6 +509,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
509
509
if associated_types. values ( ) . all ( |v| v. is_empty ( ) ) {
510
510
return ;
511
511
}
512
+
512
513
let tcx = self . tcx ( ) ;
513
514
// FIXME: Marked `mut` so that we can replace the spans further below with a more
514
515
// appropriate one, but this should be handled earlier in the span assignment.
@@ -581,6 +582,32 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
581
582
}
582
583
}
583
584
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
+
584
611
let mut names = names
585
612
. into_iter ( )
586
613
. map ( |( trait_, mut assocs) | {
@@ -610,6 +637,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
610
637
pluralize!( names_len) ,
611
638
names,
612
639
) ;
640
+ let mut rename_count = 0 ;
613
641
let mut suggestions = vec ! [ ] ;
614
642
let mut types_count = 0 ;
615
643
let mut where_constraints = vec ! [ ] ;
@@ -621,23 +649,65 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
621
649
* names. entry ( item. name ) . or_insert ( 0 ) += 1 ;
622
650
}
623
651
let mut dupes = false ;
652
+ let mut shadows = false ;
624
653
for item in assoc_items {
625
654
let prefix = if names[ & item. name ] > 1 {
626
655
let trait_def_id = item. container_id ( tcx) ;
627
656
dupes = true ;
628
657
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) )
629
662
} else {
630
663
String :: new ( )
631
664
} ;
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
+
632
684
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
+ ) ;
634
696
}
635
697
}
636
698
if potential_assoc_types. len ( ) == assoc_items. len ( ) {
637
699
// When the amount of missing associated types equals the number of
638
700
// extra type arguments present. A suggesting to replace the generic args with
639
701
// associated types is already emitted.
640
702
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) ;
641
711
} else if let ( Ok ( snippet) , false ) =
642
712
( tcx. sess . source_map ( ) . span_to_snippet ( * span) , dupes)
643
713
{
@@ -721,6 +791,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
721
791
err. span_help ( where_constraints, where_msg) ;
722
792
}
723
793
}
794
+
724
795
err. emit ( ) ;
725
796
}
726
797
}
0 commit comments