@@ -721,51 +721,42 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
721
721
/// emit a generic note suggesting using a `where` clause to constraint instead.
722
722
pub ( crate ) fn check_for_required_assoc_tys (
723
723
& self ,
724
- associated_types : FxIndexMap < Span , FxIndexSet < DefId > > ,
724
+ principal_span : Span ,
725
+ missing_assoc_types : FxIndexSet < ( DefId , ty:: PolyTraitRef < ' tcx > ) > ,
725
726
potential_assoc_types : Vec < usize > ,
726
727
trait_bounds : & [ hir:: PolyTraitRef < ' _ > ] ,
727
728
) -> Result < ( ) , ErrorGuaranteed > {
728
- if associated_types . values ( ) . all ( |v| v . is_empty ( ) ) {
729
+ if missing_assoc_types . is_empty ( ) {
729
730
return Ok ( ( ) ) ;
730
731
}
731
732
732
733
let tcx = self . tcx ( ) ;
733
- // FIXME: Marked `mut` so that we can replace the spans further below with a more
734
- // appropriate one, but this should be handled earlier in the span assignment.
735
- let associated_types: FxIndexMap < Span , Vec < _ > > = associated_types
734
+ // FIXME: This logic needs some more care w.r.t handling of conflicts
735
+ let missing_assoc_types: Vec < _ > = missing_assoc_types
736
736
. into_iter ( )
737
- . map ( |( span, def_ids) | {
738
- ( span, def_ids. into_iter ( ) . map ( |did| tcx. associated_item ( did) ) . collect ( ) )
739
- } )
737
+ . map ( |( def_id, trait_ref) | ( tcx. associated_item ( def_id) , trait_ref) )
740
738
. collect ( ) ;
741
- let mut names: FxIndexMap < String , Vec < Symbol > > = Default :: default ( ) ;
739
+ let mut names: FxIndexMap < _ , Vec < Symbol > > = Default :: default ( ) ;
742
740
let mut names_len = 0 ;
743
741
744
742
// Account for things like `dyn Foo + 'a`, like in tests `issue-22434.rs` and
745
743
// `issue-22560.rs`.
746
- let mut trait_bound_spans: Vec < Span > = vec ! [ ] ;
747
744
let mut dyn_compatibility_violations = Ok ( ( ) ) ;
748
- for ( span, items) in & associated_types {
749
- if !items. is_empty ( ) {
750
- trait_bound_spans. push ( * span) ;
751
- }
752
- for assoc_item in items {
753
- let trait_def_id = assoc_item. container_id ( tcx) ;
754
- names. entry ( tcx. def_path_str ( trait_def_id) ) . or_default ( ) . push ( assoc_item. name ) ;
755
- names_len += 1 ;
756
-
757
- let violations =
758
- dyn_compatibility_violations_for_assoc_item ( tcx, trait_def_id, * assoc_item) ;
759
- if !violations. is_empty ( ) {
760
- dyn_compatibility_violations = Err ( report_dyn_incompatibility (
761
- tcx,
762
- * span,
763
- None ,
764
- trait_def_id,
765
- & violations,
766
- )
767
- . emit ( ) ) ;
768
- }
745
+ for ( assoc_item, trait_ref) in & missing_assoc_types {
746
+ names. entry ( trait_ref) . or_default ( ) . push ( assoc_item. name ) ;
747
+ names_len += 1 ;
748
+
749
+ let violations =
750
+ dyn_compatibility_violations_for_assoc_item ( tcx, trait_ref. def_id ( ) , * assoc_item) ;
751
+ if !violations. is_empty ( ) {
752
+ dyn_compatibility_violations = Err ( report_dyn_incompatibility (
753
+ tcx,
754
+ principal_span,
755
+ None ,
756
+ trait_ref. def_id ( ) ,
757
+ & violations,
758
+ )
759
+ . emit ( ) ) ;
769
760
}
770
761
}
771
762
@@ -813,6 +804,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
813
804
. into_iter ( )
814
805
. map ( |( trait_, mut assocs) | {
815
806
assocs. sort ( ) ;
807
+ let trait_ = trait_. print_trait_sugared ( ) ;
816
808
format ! ( "{} in `{trait_}`" , match & assocs[ ..] {
817
809
[ ] => String :: new( ) ,
818
810
[ only] => format!( "`{only}`" ) ,
@@ -826,10 +818,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
826
818
names. sort ( ) ;
827
819
let names = names. join ( ", " ) ;
828
820
829
- trait_bound_spans. sort ( ) ;
830
821
let mut err = struct_span_code_err ! (
831
822
self . dcx( ) ,
832
- trait_bound_spans ,
823
+ principal_span ,
833
824
E0191 ,
834
825
"the value of the associated type{} {} must be specified" ,
835
826
pluralize!( names_len) ,
@@ -839,81 +830,83 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
839
830
let mut types_count = 0 ;
840
831
let mut where_constraints = vec ! [ ] ;
841
832
let mut already_has_generics_args_suggestion = false ;
842
- for ( span, assoc_items) in & associated_types {
843
- let mut names: UnordMap < _ , usize > = Default :: default ( ) ;
844
- for item in assoc_items {
845
- types_count += 1 ;
846
- * names. entry ( item. name ) . or_insert ( 0 ) += 1 ;
847
- }
848
- let mut dupes = false ;
849
- let mut shadows = false ;
850
- for item in assoc_items {
851
- let prefix = if names[ & item. name ] > 1 {
852
- let trait_def_id = item. container_id ( tcx) ;
853
- dupes = true ;
854
- format ! ( "{}::" , tcx. def_path_str( trait_def_id) )
855
- } else if bound_names. get ( & item. name ) . is_some_and ( |x| x != & item) {
856
- let trait_def_id = item. container_id ( tcx) ;
857
- shadows = true ;
858
- format ! ( "{}::" , tcx. def_path_str( trait_def_id) )
859
- } else {
860
- String :: new ( )
861
- } ;
862
833
863
- let mut is_shadowed = false ;
864
-
865
- if let Some ( assoc_item) = bound_names. get ( & item. name )
866
- && assoc_item != & item
867
- {
868
- is_shadowed = true ;
834
+ let mut names: UnordMap < _ , usize > = Default :: default ( ) ;
835
+ for ( item, _) in & missing_assoc_types {
836
+ types_count += 1 ;
837
+ * names. entry ( item. name ) . or_insert ( 0 ) += 1 ;
838
+ }
839
+ let mut dupes = false ;
840
+ let mut shadows = false ;
841
+ for ( item, trait_ref) in & missing_assoc_types {
842
+ let prefix = if names[ & item. name ] > 1 {
843
+ let trait_def_id = trait_ref. def_id ( ) ;
844
+ dupes = true ;
845
+ format ! ( "{}::" , tcx. def_path_str( trait_def_id) )
846
+ } else if bound_names. get ( & item. name ) . is_some_and ( |x| * x != item) {
847
+ let trait_def_id = trait_ref. def_id ( ) ;
848
+ shadows = true ;
849
+ format ! ( "{}::" , tcx. def_path_str( trait_def_id) )
850
+ } else {
851
+ String :: new ( )
852
+ } ;
869
853
870
- let rename_message =
871
- if assoc_item. def_id . is_local ( ) { ", consider renaming it" } else { "" } ;
872
- err. span_label (
873
- tcx. def_span ( assoc_item. def_id ) ,
874
- format ! ( "`{}{}` shadowed here{}" , prefix, item. name, rename_message) ,
875
- ) ;
876
- }
854
+ let mut is_shadowed = false ;
877
855
878
- let rename_message = if is_shadowed { ", consider renaming it" } else { "" } ;
856
+ if let Some ( assoc_item) = bound_names. get ( & item. name )
857
+ && * assoc_item != item
858
+ {
859
+ is_shadowed = true ;
879
860
880
- if let Some ( sp ) = tcx . hir ( ) . span_if_local ( item . def_id ) {
881
- err . span_label (
882
- sp ,
883
- format ! ( "`{}{}` defined here{}" , prefix , item . name , rename_message ) ,
884
- ) ;
885
- }
861
+ let rename_message =
862
+ if assoc_item . def_id . is_local ( ) { ", consider renaming it" } else { "" } ;
863
+ err . span_label (
864
+ tcx . def_span ( assoc_item . def_id ) ,
865
+ format ! ( "`{}{}` shadowed here{}" , prefix , item . name , rename_message ) ,
866
+ ) ;
886
867
}
887
- if potential_assoc_types. len ( ) == assoc_items. len ( ) {
888
- // When the amount of missing associated types equals the number of
889
- // extra type arguments present. A suggesting to replace the generic args with
890
- // associated types is already emitted.
891
- already_has_generics_args_suggestion = true ;
892
- } else if let ( Ok ( snippet) , false , false ) =
893
- ( tcx. sess . source_map ( ) . span_to_snippet ( * span) , dupes, shadows)
894
- {
895
- let types: Vec < _ > =
896
- assoc_items. iter ( ) . map ( |item| format ! ( "{} = Type" , item. name) ) . collect ( ) ;
897
- let code = if snippet. ends_with ( '>' ) {
898
- // The user wrote `Trait<'a>` or similar and we don't have a type we can
899
- // suggest, but at least we can clue them to the correct syntax
900
- // `Trait<'a, Item = Type>` while accounting for the `<'a>` in the
901
- // suggestion.
902
- format ! ( "{}, {}>" , & snippet[ ..snippet. len( ) - 1 ] , types. join( ", " ) )
903
- } else if in_expr_or_pat {
904
- // The user wrote `Iterator`, so we don't have a type we can suggest, but at
905
- // least we can clue them to the correct syntax `Iterator::<Item = Type>`.
906
- format ! ( "{}::<{}>" , snippet, types. join( ", " ) )
907
- } else {
908
- // The user wrote `Iterator`, so we don't have a type we can suggest, but at
909
- // least we can clue them to the correct syntax `Iterator<Item = Type>`.
910
- format ! ( "{}<{}>" , snippet, types. join( ", " ) )
911
- } ;
912
- suggestions. push ( ( * span, code) ) ;
913
- } else if dupes {
914
- where_constraints. push ( * span) ;
868
+
869
+ let rename_message = if is_shadowed { ", consider renaming it" } else { "" } ;
870
+
871
+ if let Some ( sp) = tcx. hir ( ) . span_if_local ( item. def_id ) {
872
+ err. span_label (
873
+ sp,
874
+ format ! ( "`{}{}` defined here{}" , prefix, item. name, rename_message) ,
875
+ ) ;
915
876
}
916
877
}
878
+ if potential_assoc_types. len ( ) == missing_assoc_types. len ( ) {
879
+ // When the amount of missing associated types equals the number of
880
+ // extra type arguments present. A suggesting to replace the generic args with
881
+ // associated types is already emitted.
882
+ already_has_generics_args_suggestion = true ;
883
+ } else if let ( Ok ( snippet) , false , false ) =
884
+ ( tcx. sess . source_map ( ) . span_to_snippet ( principal_span) , dupes, shadows)
885
+ {
886
+ let types: Vec < _ > = missing_assoc_types
887
+ . iter ( )
888
+ . map ( |( item, _) | format ! ( "{} = Type" , item. name) )
889
+ . collect ( ) ;
890
+ let code = if snippet. ends_with ( '>' ) {
891
+ // The user wrote `Trait<'a>` or similar and we don't have a type we can
892
+ // suggest, but at least we can clue them to the correct syntax
893
+ // `Trait<'a, Item = Type>` while accounting for the `<'a>` in the
894
+ // suggestion.
895
+ format ! ( "{}, {}>" , & snippet[ ..snippet. len( ) - 1 ] , types. join( ", " ) )
896
+ } else if in_expr_or_pat {
897
+ // The user wrote `Iterator`, so we don't have a type we can suggest, but at
898
+ // least we can clue them to the correct syntax `Iterator::<Item = Type>`.
899
+ format ! ( "{}::<{}>" , snippet, types. join( ", " ) )
900
+ } else {
901
+ // The user wrote `Iterator`, so we don't have a type we can suggest, but at
902
+ // least we can clue them to the correct syntax `Iterator<Item = Type>`.
903
+ format ! ( "{}<{}>" , snippet, types. join( ", " ) )
904
+ } ;
905
+ suggestions. push ( ( principal_span, code) ) ;
906
+ } else if dupes {
907
+ where_constraints. push ( principal_span) ;
908
+ }
909
+
917
910
let where_msg = "consider introducing a new type parameter, adding `where` constraints \
918
911
using the fully-qualified path to the associated types";
919
912
if !where_constraints. is_empty ( ) && suggestions. is_empty ( ) {
@@ -924,32 +917,29 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
924
917
}
925
918
if suggestions. len ( ) != 1 || already_has_generics_args_suggestion {
926
919
// We don't need this label if there's an inline suggestion, show otherwise.
927
- for ( span, assoc_items) in & associated_types {
928
- let mut names: FxIndexMap < _ , usize > = FxIndexMap :: default ( ) ;
929
- for item in assoc_items {
930
- types_count += 1 ;
931
- * names. entry ( item. name ) . or_insert ( 0 ) += 1 ;
932
- }
933
- let mut label = vec ! [ ] ;
934
- for item in assoc_items {
935
- let postfix = if names[ & item. name ] > 1 {
936
- let trait_def_id = item. container_id ( tcx) ;
937
- format ! ( " (from trait `{}`)" , tcx. def_path_str( trait_def_id) )
938
- } else {
939
- String :: new ( )
940
- } ;
941
- label. push ( format ! ( "`{}`{}" , item. name, postfix) ) ;
942
- }
943
- if !label. is_empty ( ) {
944
- err. span_label (
945
- * span,
946
- format ! (
947
- "associated type{} {} must be specified" ,
948
- pluralize!( label. len( ) ) ,
949
- label. join( ", " ) ,
950
- ) ,
951
- ) ;
952
- }
920
+ let mut names: FxIndexMap < _ , usize > = FxIndexMap :: default ( ) ;
921
+ for ( item, _) in & missing_assoc_types {
922
+ types_count += 1 ;
923
+ * names. entry ( item. name ) . or_insert ( 0 ) += 1 ;
924
+ }
925
+ let mut label = vec ! [ ] ;
926
+ for ( item, trait_ref) in & missing_assoc_types {
927
+ let postfix = if names[ & item. name ] > 1 {
928
+ format ! ( " (from trait `{}`)" , trait_ref. print_trait_sugared( ) )
929
+ } else {
930
+ String :: new ( )
931
+ } ;
932
+ label. push ( format ! ( "`{}`{}" , item. name, postfix) ) ;
933
+ }
934
+ if !label. is_empty ( ) {
935
+ err. span_label (
936
+ principal_span,
937
+ format ! (
938
+ "associated type{} {} must be specified" ,
939
+ pluralize!( label. len( ) ) ,
940
+ label. join( ", " ) ,
941
+ ) ,
942
+ ) ;
953
943
}
954
944
}
955
945
suggestions. sort_by_key ( |& ( span, _) | span) ;
0 commit comments