@@ -716,51 +716,40 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
716716 /// emit a generic note suggesting using a `where` clause to constraint instead.
717717 pub ( crate ) fn check_for_required_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 ) -> Result < ( ) , ErrorGuaranteed > {
723- if associated_types . values ( ) . all ( |v| v . is_empty ( ) ) {
724+ if missing_assoc_types . is_empty ( ) {
724725 return Ok ( ( ) ) ;
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 = Ok ( ( ) ) ;
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- dyn_compatibility_violations = Err ( report_dyn_incompatibility (
756- tcx,
757- * span,
758- None ,
759- trait_def_id,
760- & violations,
761- )
762- . emit ( ) ) ;
763- }
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+ dyn_compatibility_violations = Err ( report_dyn_incompatibility (
746+ tcx,
747+ principal_span,
748+ None ,
749+ trait_def_id,
750+ & violations,
751+ )
752+ . emit ( ) ) ;
764753 }
765754 }
766755
@@ -821,10 +810,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
821810 names. sort ( ) ;
822811 let names = names. join ( ", " ) ;
823812
824- trait_bound_spans. sort ( ) ;
825813 let mut err = struct_span_code_err ! (
826814 self . dcx( ) ,
827- trait_bound_spans ,
815+ principal_span ,
828816 E0191 ,
829817 "the value of the associated type{} {} must be specified" ,
830818 pluralize!( names_len) ,
@@ -834,81 +822,81 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
834822 let mut types_count = 0 ;
835823 let mut where_constraints = vec ! [ ] ;
836824 let mut already_has_generics_args_suggestion = false ;
837- for ( span, assoc_items) in & associated_types {
838- let mut names: UnordMap < _ , usize > = Default :: default ( ) ;
839- for item in assoc_items {
840- types_count += 1 ;
841- * names. entry ( item. name ) . or_insert ( 0 ) += 1 ;
842- }
843- let mut dupes = false ;
844- let mut shadows = false ;
845- for item in assoc_items {
846- let prefix = if names[ & item. name ] > 1 {
847- let trait_def_id = item. container_id ( tcx) ;
848- dupes = true ;
849- format ! ( "{}::" , tcx. def_path_str( trait_def_id) )
850- } else if bound_names. get ( & item. name ) . is_some_and ( |x| x != & item) {
851- let trait_def_id = item. container_id ( tcx) ;
852- shadows = true ;
853- format ! ( "{}::" , tcx. def_path_str( trait_def_id) )
854- } else {
855- String :: new ( )
856- } ;
857825
858- let mut is_shadowed = false ;
859-
860- if let Some ( assoc_item) = bound_names. get ( & item. name )
861- && assoc_item != & item
862- {
863- is_shadowed = true ;
826+ let mut names: UnordMap < _ , usize > = Default :: default ( ) ;
827+ for item in & missing_assoc_types {
828+ types_count += 1 ;
829+ * names. entry ( item. name ) . or_insert ( 0 ) += 1 ;
830+ }
831+ let mut dupes = false ;
832+ let mut shadows = false ;
833+ for item in & missing_assoc_types {
834+ let prefix = if names[ & item. name ] > 1 {
835+ let trait_def_id = item. container_id ( tcx) ;
836+ dupes = true ;
837+ format ! ( "{}::" , tcx. def_path_str( trait_def_id) )
838+ } else if bound_names. get ( & item. name ) . is_some_and ( |x| * x != item) {
839+ let trait_def_id = item. container_id ( tcx) ;
840+ shadows = true ;
841+ format ! ( "{}::" , tcx. def_path_str( trait_def_id) )
842+ } else {
843+ String :: new ( )
844+ } ;
864845
865- let rename_message =
866- if assoc_item. def_id . is_local ( ) { ", consider renaming it" } else { "" } ;
867- err. span_label (
868- tcx. def_span ( assoc_item. def_id ) ,
869- format ! ( "`{}{}` shadowed here{}" , prefix, item. name, rename_message) ,
870- ) ;
871- }
846+ let mut is_shadowed = false ;
872847
873- let rename_message = if is_shadowed { ", consider renaming it" } else { "" } ;
848+ if let Some ( assoc_item) = bound_names. get ( & item. name )
849+ && * assoc_item != item
850+ {
851+ is_shadowed = true ;
874852
875- if let Some ( sp ) = tcx . hir ( ) . span_if_local ( item . def_id ) {
876- err . span_label (
877- sp ,
878- format ! ( "`{}{}` defined here{}" , prefix , item . name , rename_message ) ,
879- ) ;
880- }
853+ let rename_message =
854+ if assoc_item . def_id . is_local ( ) { ", consider renaming it" } else { "" } ;
855+ err . span_label (
856+ tcx . def_span ( assoc_item . def_id ) ,
857+ format ! ( "`{}{}` shadowed here{}" , prefix , item . name , rename_message ) ,
858+ ) ;
881859 }
882- if potential_assoc_types. len ( ) == assoc_items. len ( ) {
883- // When the amount of missing associated types equals the number of
884- // extra type arguments present. A suggesting to replace the generic args with
885- // associated types is already emitted.
886- already_has_generics_args_suggestion = true ;
887- } else if let ( Ok ( snippet) , false , false ) =
888- ( tcx. sess . source_map ( ) . span_to_snippet ( * span) , dupes, shadows)
889- {
890- let types: Vec < _ > =
891- assoc_items. iter ( ) . map ( |item| format ! ( "{} = Type" , item. name) ) . collect ( ) ;
892- let code = if snippet. ends_with ( '>' ) {
893- // The user wrote `Trait<'a>` or similar and we don't have a type we can
894- // suggest, but at least we can clue them to the correct syntax
895- // `Trait<'a, Item = Type>` while accounting for the `<'a>` in the
896- // suggestion.
897- format ! ( "{}, {}>" , & snippet[ ..snippet. len( ) - 1 ] , types. join( ", " ) )
898- } else if in_expr_or_pat {
899- // The user wrote `Iterator`, so we don't have a type we can suggest, but at
900- // least we can clue them to the correct syntax `Iterator::<Item = Type>`.
901- format ! ( "{}::<{}>" , snippet, types. join( ", " ) )
902- } else {
903- // The user wrote `Iterator`, so we don't have a type we can suggest, but at
904- // least we can clue them to the correct syntax `Iterator<Item = Type>`.
905- format ! ( "{}<{}>" , snippet, types. join( ", " ) )
906- } ;
907- suggestions. push ( ( * span, code) ) ;
908- } else if dupes {
909- where_constraints. push ( * span) ;
860+
861+ let rename_message = if is_shadowed { ", consider renaming it" } else { "" } ;
862+
863+ if let Some ( sp) = tcx. hir ( ) . span_if_local ( item. def_id ) {
864+ err. span_label (
865+ sp,
866+ format ! ( "`{}{}` defined here{}" , prefix, item. name, rename_message) ,
867+ ) ;
910868 }
911869 }
870+ if potential_assoc_types. len ( ) == missing_assoc_types. len ( ) {
871+ // When the amount of missing associated types equals the number of
872+ // extra type arguments present. A suggesting to replace the generic args with
873+ // associated types is already emitted.
874+ already_has_generics_args_suggestion = true ;
875+ } else if let ( Ok ( snippet) , false , false ) =
876+ ( tcx. sess . source_map ( ) . span_to_snippet ( principal_span) , dupes, shadows)
877+ {
878+ let types: Vec < _ > =
879+ missing_assoc_types. iter ( ) . map ( |item| format ! ( "{} = Type" , item. name) ) . collect ( ) ;
880+ let code = if snippet. ends_with ( '>' ) {
881+ // The user wrote `Trait<'a>` or similar and we don't have a type we can
882+ // suggest, but at least we can clue them to the correct syntax
883+ // `Trait<'a, Item = Type>` while accounting for the `<'a>` in the
884+ // suggestion.
885+ format ! ( "{}, {}>" , & snippet[ ..snippet. len( ) - 1 ] , types. join( ", " ) )
886+ } else if in_expr_or_pat {
887+ // The user wrote `Iterator`, so we don't have a type we can suggest, but at
888+ // least we can clue them to the correct syntax `Iterator::<Item = Type>`.
889+ format ! ( "{}::<{}>" , snippet, types. join( ", " ) )
890+ } else {
891+ // The user wrote `Iterator`, so we don't have a type we can suggest, but at
892+ // least we can clue them to the correct syntax `Iterator<Item = Type>`.
893+ format ! ( "{}<{}>" , snippet, types. join( ", " ) )
894+ } ;
895+ suggestions. push ( ( principal_span, code) ) ;
896+ } else if dupes {
897+ where_constraints. push ( principal_span) ;
898+ }
899+
912900 let where_msg = "consider introducing a new type parameter, adding `where` constraints \
913901 using the fully-qualified path to the associated types";
914902 if !where_constraints. is_empty ( ) && suggestions. is_empty ( ) {
@@ -919,32 +907,30 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
919907 }
920908 if suggestions. len ( ) != 1 || already_has_generics_args_suggestion {
921909 // We don't need this label if there's an inline suggestion, show otherwise.
922- for ( span, assoc_items) in & associated_types {
923- let mut names: FxIndexMap < _ , usize > = FxIndexMap :: default ( ) ;
924- for item in assoc_items {
925- types_count += 1 ;
926- * names. entry ( item. name ) . or_insert ( 0 ) += 1 ;
927- }
928- let mut label = vec ! [ ] ;
929- for item in assoc_items {
930- let postfix = if names[ & item. name ] > 1 {
931- let trait_def_id = item. container_id ( tcx) ;
932- format ! ( " (from trait `{}`)" , tcx. def_path_str( trait_def_id) )
933- } else {
934- String :: new ( )
935- } ;
936- label. push ( format ! ( "`{}`{}" , item. name, postfix) ) ;
937- }
938- if !label. is_empty ( ) {
939- err. span_label (
940- * span,
941- format ! (
942- "associated type{} {} must be specified" ,
943- pluralize!( label. len( ) ) ,
944- label. join( ", " ) ,
945- ) ,
946- ) ;
947- }
910+ let mut names: FxIndexMap < _ , usize > = FxIndexMap :: default ( ) ;
911+ for item in & missing_assoc_types {
912+ types_count += 1 ;
913+ * names. entry ( item. name ) . or_insert ( 0 ) += 1 ;
914+ }
915+ let mut label = vec ! [ ] ;
916+ for item in & missing_assoc_types {
917+ let postfix = if names[ & item. name ] > 1 {
918+ let trait_def_id = item. container_id ( tcx) ;
919+ format ! ( " (from trait `{}`)" , tcx. def_path_str( trait_def_id) )
920+ } else {
921+ String :: new ( )
922+ } ;
923+ label. push ( format ! ( "`{}`{}" , item. name, postfix) ) ;
924+ }
925+ if !label. is_empty ( ) {
926+ err. span_label (
927+ principal_span,
928+ format ! (
929+ "associated type{} {} must be specified" ,
930+ pluralize!( label. len( ) ) ,
931+ label. join( ", " ) ,
932+ ) ,
933+ ) ;
948934 }
949935 }
950936 suggestions. sort_by_key ( |& ( span, _) | span) ;
0 commit comments