@@ -716,45 +716,35 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
716716 /// emit a generic note suggesting using a `where` clause to constraint instead.
717717 pub ( crate ) fn complain_about_missing_assoc_tys (
718718 & self ,
719- associated_types : FxIndexMap < Span , FxIndexSet < DefId > > ,
719+ principal_span : Span ,
720+ missing_assoc_types : FxIndexSet < DefId > ,
720721 potential_assoc_types : Vec < usize > ,
721722 trait_bounds : & [ hir:: PolyTraitRef < ' _ > ] ,
722723 ) {
723- if associated_types . values ( ) . all ( |v| v . is_empty ( ) ) {
724+ if missing_assoc_types . is_empty ( ) {
724725 return ;
725726 }
726727
727728 let tcx = self . tcx ( ) ;
728- // FIXME: Marked `mut` so that we can replace the spans further below with a more
729- // appropriate one, but this should be handled earlier in the span assignment.
730- let associated_types: FxIndexMap < Span , Vec < _ > > = associated_types
731- . into_iter ( )
732- . map ( |( span, def_ids) | {
733- ( span, def_ids. into_iter ( ) . map ( |did| tcx. associated_item ( did) ) . collect ( ) )
734- } )
735- . collect ( ) ;
729+ let missing_assoc_types: Vec < _ > =
730+ missing_assoc_types. into_iter ( ) . map ( |def_id| tcx. associated_item ( def_id) ) . collect ( ) ;
736731 let mut names: FxIndexMap < String , Vec < Symbol > > = Default :: default ( ) ;
737732 let mut names_len = 0 ;
738733
739734 // Account for things like `dyn Foo + 'a`, like in tests `issue-22434.rs` and
740735 // `issue-22560.rs`.
741- let mut trait_bound_spans: Vec < Span > = vec ! [ ] ;
742736 let mut dyn_compatibility_violations = false ;
743- for ( span, items) in & associated_types {
744- if !items. is_empty ( ) {
745- trait_bound_spans. push ( * span) ;
746- }
747- for assoc_item in items {
748- let trait_def_id = assoc_item. container_id ( tcx) ;
749- names. entry ( tcx. def_path_str ( trait_def_id) ) . or_default ( ) . push ( assoc_item. name ) ;
750- names_len += 1 ;
751-
752- let violations =
753- dyn_compatibility_violations_for_assoc_item ( tcx, trait_def_id, * assoc_item) ;
754- if !violations. is_empty ( ) {
755- report_dyn_incompatibility ( tcx, * span, None , trait_def_id, & violations) . emit ( ) ;
756- dyn_compatibility_violations = true ;
757- }
737+ for assoc_item in & missing_assoc_types {
738+ let trait_def_id = assoc_item. container_id ( tcx) ;
739+ names. entry ( tcx. def_path_str ( trait_def_id) ) . or_default ( ) . push ( assoc_item. name ) ;
740+ names_len += 1 ;
741+
742+ let violations =
743+ dyn_compatibility_violations_for_assoc_item ( tcx, trait_def_id, * assoc_item) ;
744+ if !violations. is_empty ( ) {
745+ report_dyn_incompatibility ( tcx, principal_span, None , trait_def_id, & violations)
746+ . emit ( ) ;
747+ dyn_compatibility_violations = true ;
758748 }
759749 }
760750 if dyn_compatibility_violations {
@@ -814,10 +804,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
814804 names. sort ( ) ;
815805 let names = names. join ( ", " ) ;
816806
817- trait_bound_spans. sort ( ) ;
818807 let mut err = struct_span_code_err ! (
819808 self . dcx( ) ,
820- trait_bound_spans ,
809+ principal_span ,
821810 E0191 ,
822811 "the value of the associated type{} {} must be specified" ,
823812 pluralize!( names_len) ,
@@ -827,81 +816,81 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
827816 let mut types_count = 0 ;
828817 let mut where_constraints = vec ! [ ] ;
829818 let mut already_has_generics_args_suggestion = false ;
830- for ( span, assoc_items) in & associated_types {
831- let mut names: UnordMap < _ , usize > = Default :: default ( ) ;
832- for item in assoc_items {
833- types_count += 1 ;
834- * names. entry ( item. name ) . or_insert ( 0 ) += 1 ;
835- }
836- let mut dupes = false ;
837- let mut shadows = false ;
838- for item in assoc_items {
839- let prefix = if names[ & item. name ] > 1 {
840- let trait_def_id = item. container_id ( tcx) ;
841- dupes = true ;
842- format ! ( "{}::" , tcx. def_path_str( trait_def_id) )
843- } else if bound_names. get ( & item. name ) . is_some_and ( |x| x != & item) {
844- let trait_def_id = item. container_id ( tcx) ;
845- shadows = true ;
846- format ! ( "{}::" , tcx. def_path_str( trait_def_id) )
847- } else {
848- String :: new ( )
849- } ;
850-
851- let mut is_shadowed = false ;
852819
853- if let Some ( assoc_item) = bound_names. get ( & item. name )
854- && assoc_item != & item
855- {
856- is_shadowed = true ;
820+ let mut names: UnordMap < _ , usize > = Default :: default ( ) ;
821+ for item in & missing_assoc_types {
822+ types_count += 1 ;
823+ * names. entry ( item. name ) . or_insert ( 0 ) += 1 ;
824+ }
825+ let mut dupes = false ;
826+ let mut shadows = false ;
827+ for item in & missing_assoc_types {
828+ let prefix = if names[ & item. name ] > 1 {
829+ let trait_def_id = item. container_id ( tcx) ;
830+ dupes = true ;
831+ format ! ( "{}::" , tcx. def_path_str( trait_def_id) )
832+ } else if bound_names. get ( & item. name ) . is_some_and ( |x| * x != item) {
833+ let trait_def_id = item. container_id ( tcx) ;
834+ shadows = true ;
835+ format ! ( "{}::" , tcx. def_path_str( trait_def_id) )
836+ } else {
837+ String :: new ( )
838+ } ;
857839
858- let rename_message =
859- if assoc_item. def_id . is_local ( ) { ", consider renaming it" } else { "" } ;
860- err. span_label (
861- tcx. def_span ( assoc_item. def_id ) ,
862- format ! ( "`{}{}` shadowed here{}" , prefix, item. name, rename_message) ,
863- ) ;
864- }
840+ let mut is_shadowed = false ;
865841
866- let rename_message = if is_shadowed { ", consider renaming it" } else { "" } ;
842+ if let Some ( assoc_item) = bound_names. get ( & item. name )
843+ && * assoc_item != item
844+ {
845+ is_shadowed = true ;
867846
868- if let Some ( sp ) = tcx . hir ( ) . span_if_local ( item . def_id ) {
869- err . span_label (
870- sp ,
871- format ! ( "`{}{}` defined here{}" , prefix , item . name , rename_message ) ,
872- ) ;
873- }
847+ let rename_message =
848+ if assoc_item . def_id . is_local ( ) { ", consider renaming it" } else { "" } ;
849+ err . span_label (
850+ tcx . def_span ( assoc_item . def_id ) ,
851+ format ! ( "`{}{}` shadowed here{}" , prefix , item . name , rename_message ) ,
852+ ) ;
874853 }
875- if potential_assoc_types. len ( ) == assoc_items. len ( ) {
876- // When the amount of missing associated types equals the number of
877- // extra type arguments present. A suggesting to replace the generic args with
878- // associated types is already emitted.
879- already_has_generics_args_suggestion = true ;
880- } else if let ( Ok ( snippet) , false , false ) =
881- ( tcx. sess . source_map ( ) . span_to_snippet ( * span) , dupes, shadows)
882- {
883- let types: Vec < _ > =
884- assoc_items. iter ( ) . map ( |item| format ! ( "{} = Type" , item. name) ) . collect ( ) ;
885- let code = if snippet. ends_with ( '>' ) {
886- // The user wrote `Trait<'a>` or similar and we don't have a type we can
887- // suggest, but at least we can clue them to the correct syntax
888- // `Trait<'a, Item = Type>` while accounting for the `<'a>` in the
889- // suggestion.
890- format ! ( "{}, {}>" , & snippet[ ..snippet. len( ) - 1 ] , types. join( ", " ) )
891- } else if in_expr_or_pat {
892- // The user wrote `Iterator`, so we don't have a type we can suggest, but at
893- // least we can clue them to the correct syntax `Iterator::<Item = Type>`.
894- format ! ( "{}::<{}>" , snippet, types. join( ", " ) )
895- } else {
896- // The user wrote `Iterator`, so we don't have a type we can suggest, but at
897- // least we can clue them to the correct syntax `Iterator<Item = Type>`.
898- format ! ( "{}<{}>" , snippet, types. join( ", " ) )
899- } ;
900- suggestions. push ( ( * span, code) ) ;
901- } else if dupes {
902- where_constraints. push ( * span) ;
854+
855+ let rename_message = if is_shadowed { ", consider renaming it" } else { "" } ;
856+
857+ if let Some ( sp) = tcx. hir ( ) . span_if_local ( item. def_id ) {
858+ err. span_label (
859+ sp,
860+ format ! ( "`{}{}` defined here{}" , prefix, item. name, rename_message) ,
861+ ) ;
903862 }
904863 }
864+ if potential_assoc_types. len ( ) == missing_assoc_types. len ( ) {
865+ // When the amount of missing associated types equals the number of
866+ // extra type arguments present. A suggesting to replace the generic args with
867+ // associated types is already emitted.
868+ already_has_generics_args_suggestion = true ;
869+ } else if let ( Ok ( snippet) , false , false ) =
870+ ( tcx. sess . source_map ( ) . span_to_snippet ( principal_span) , dupes, shadows)
871+ {
872+ let types: Vec < _ > =
873+ missing_assoc_types. iter ( ) . map ( |item| format ! ( "{} = Type" , item. name) ) . collect ( ) ;
874+ let code = if snippet. ends_with ( '>' ) {
875+ // The user wrote `Trait<'a>` or similar and we don't have a type we can
876+ // suggest, but at least we can clue them to the correct syntax
877+ // `Trait<'a, Item = Type>` while accounting for the `<'a>` in the
878+ // suggestion.
879+ format ! ( "{}, {}>" , & snippet[ ..snippet. len( ) - 1 ] , types. join( ", " ) )
880+ } else if in_expr_or_pat {
881+ // The user wrote `Iterator`, so we don't have a type we can suggest, but at
882+ // least we can clue them to the correct syntax `Iterator::<Item = Type>`.
883+ format ! ( "{}::<{}>" , snippet, types. join( ", " ) )
884+ } else {
885+ // The user wrote `Iterator`, so we don't have a type we can suggest, but at
886+ // least we can clue them to the correct syntax `Iterator<Item = Type>`.
887+ format ! ( "{}<{}>" , snippet, types. join( ", " ) )
888+ } ;
889+ suggestions. push ( ( principal_span, code) ) ;
890+ } else if dupes {
891+ where_constraints. push ( principal_span) ;
892+ }
893+
905894 let where_msg = "consider introducing a new type parameter, adding `where` constraints \
906895 using the fully-qualified path to the associated types";
907896 if !where_constraints. is_empty ( ) && suggestions. is_empty ( ) {
@@ -912,32 +901,30 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
912901 }
913902 if suggestions. len ( ) != 1 || already_has_generics_args_suggestion {
914903 // We don't need this label if there's an inline suggestion, show otherwise.
915- for ( span, assoc_items) in & associated_types {
916- let mut names: FxIndexMap < _ , usize > = FxIndexMap :: default ( ) ;
917- for item in assoc_items {
918- types_count += 1 ;
919- * names. entry ( item. name ) . or_insert ( 0 ) += 1 ;
920- }
921- let mut label = vec ! [ ] ;
922- for item in assoc_items {
923- let postfix = if names[ & item. name ] > 1 {
924- let trait_def_id = item. container_id ( tcx) ;
925- format ! ( " (from trait `{}`)" , tcx. def_path_str( trait_def_id) )
926- } else {
927- String :: new ( )
928- } ;
929- label. push ( format ! ( "`{}`{}" , item. name, postfix) ) ;
930- }
931- if !label. is_empty ( ) {
932- err. span_label (
933- * span,
934- format ! (
935- "associated type{} {} must be specified" ,
936- pluralize!( label. len( ) ) ,
937- label. join( ", " ) ,
938- ) ,
939- ) ;
940- }
904+ let mut names: FxIndexMap < _ , usize > = FxIndexMap :: default ( ) ;
905+ for item in & missing_assoc_types {
906+ types_count += 1 ;
907+ * names. entry ( item. name ) . or_insert ( 0 ) += 1 ;
908+ }
909+ let mut label = vec ! [ ] ;
910+ for item in & missing_assoc_types {
911+ let postfix = if names[ & item. name ] > 1 {
912+ let trait_def_id = item. container_id ( tcx) ;
913+ format ! ( " (from trait `{}`)" , tcx. def_path_str( trait_def_id) )
914+ } else {
915+ String :: new ( )
916+ } ;
917+ label. push ( format ! ( "`{}`{}" , item. name, postfix) ) ;
918+ }
919+ if !label. is_empty ( ) {
920+ err. span_label (
921+ principal_span,
922+ format ! (
923+ "associated type{} {} must be specified" ,
924+ pluralize!( label. len( ) ) ,
925+ label. join( ", " ) ,
926+ ) ,
927+ ) ;
941928 }
942929 }
943930 suggestions. sort_by_key ( |& ( span, _) | span) ;
0 commit comments