@@ -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 } ;
@@ -513,6 +513,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
513
513
if associated_types. values ( ) . all ( |v| v. is_empty ( ) ) {
514
514
return ;
515
515
}
516
+
516
517
let tcx = self . tcx ( ) ;
517
518
// FIXME: Marked `mut` so that we can replace the spans further below with a more
518
519
// appropriate one, but this should be handled earlier in the span assignment.
@@ -585,6 +586,35 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
585
586
}
586
587
}
587
588
589
+ // We get all the associated items that _are_ set,
590
+ // so that we can check if any of their names match one of the ones we are missing.
591
+ // This would mean that they are shadowing the associated type we are missing,
592
+ // and we can then use their span to indicate this to the user.
593
+ let bound_names = trait_bounds
594
+ . iter ( )
595
+ . filter_map ( |poly_trait_ref| {
596
+ poly_trait_ref. trait_ref . path . segments . last ( ) . and_then ( |path| {
597
+ let args = path. args ?;
598
+ Some ( ( path, args) )
599
+ } )
600
+ } )
601
+ . flat_map ( |( path, args) | {
602
+ args. bindings . iter ( ) . map ( |binding| {
603
+ let ident = binding. ident ;
604
+ let trait_def = path. res . opt_def_id ( ) ;
605
+ let assoc_item = trait_def. and_then ( |did| {
606
+ tcx. associated_items ( did) . find_by_name_and_kinds (
607
+ tcx,
608
+ ident,
609
+ & [ AssocKind :: Fn , AssocKind :: Type , AssocKind :: Const ] ,
610
+ did,
611
+ )
612
+ } ) ;
613
+ ( ident. name , assoc_item)
614
+ } )
615
+ } )
616
+ . collect :: < FxHashMap < Symbol , Option < & AssocItem > > > ( ) ;
617
+
588
618
let mut names = names
589
619
. into_iter ( )
590
620
. map ( |( trait_, mut assocs) | {
@@ -614,6 +644,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
614
644
pluralize!( names_len) ,
615
645
names,
616
646
) ;
647
+ let mut rename_suggestions = vec ! [ ] ;
617
648
let mut suggestions = vec ! [ ] ;
618
649
let mut types_count = 0 ;
619
650
let mut where_constraints = vec ! [ ] ;
@@ -625,23 +656,47 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
625
656
* names. entry ( item. name ) . or_insert ( 0 ) += 1 ;
626
657
}
627
658
let mut dupes = false ;
659
+ let mut shadows = false ;
628
660
for item in assoc_items {
629
661
let prefix = if names[ & item. name ] > 1 {
630
662
let trait_def_id = item. container_id ( tcx) ;
631
663
dupes = true ;
632
664
format ! ( "{}::" , tcx. def_path_str( trait_def_id) )
665
+ } else if bound_names. contains_key ( & item. name ) {
666
+ let trait_def_id = item. container_id ( tcx) ;
667
+ shadows = true ;
668
+ format ! ( "{}::" , tcx. def_path_str( trait_def_id) )
633
669
} else {
634
670
String :: new ( )
635
671
} ;
636
672
if let Some ( sp) = tcx. hir ( ) . span_if_local ( item. def_id ) {
637
673
err. span_label ( sp, format ! ( "`{}{}` defined here" , prefix, item. name) ) ;
638
674
}
675
+
676
+ if let Some ( Some ( assoc_item) ) = bound_names. get ( & item. name ) {
677
+ err. span_label (
678
+ tcx. def_span ( assoc_item. def_id ) ,
679
+ format ! ( "`{}{}` shadowed here" , prefix, item. name) ,
680
+ ) ;
681
+ }
639
682
}
640
683
if potential_assoc_types. len ( ) == assoc_items. len ( ) {
641
684
// When the amount of missing associated types equals the number of
642
685
// extra type arguments present. A suggesting to replace the generic args with
643
686
// associated types is already emitted.
644
687
already_has_generics_args_suggestion = true ;
688
+ } else if shadows {
689
+ for item in assoc_items {
690
+ if let Some ( Some ( assoc_item) ) = bound_names. get ( & item. name ) {
691
+ if let Some ( sp) = tcx. hir ( ) . span_if_local ( item. def_id ) {
692
+ rename_suggestions. push ( sp) ;
693
+ }
694
+
695
+ if let Some ( sp) = tcx. hir ( ) . span_if_local ( assoc_item. def_id ) {
696
+ rename_suggestions. push ( sp) ;
697
+ }
698
+ }
699
+ }
645
700
} else if let ( Ok ( snippet) , false ) =
646
701
( tcx. sess . source_map ( ) . span_to_snippet ( * span) , dupes)
647
702
{
@@ -725,6 +780,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
725
780
err. span_help ( where_constraints, where_msg) ;
726
781
}
727
782
}
783
+
784
+ for span in rename_suggestions {
785
+ err. span_help ( span, "consider renaming this associated type" ) ;
786
+ }
728
787
err. emit ( ) ;
729
788
}
730
789
}
0 commit comments