@@ -722,51 +722,40 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
722722 /// emit a generic note suggesting using a `where` clause to constraint instead.
723723 pub ( crate ) fn check_for_required_assoc_tys (
724724 & self ,
725- associated_types : FxIndexMap < Span , FxIndexSet < DefId > > ,
725+ principal_span : Span ,
726+ missing_assoc_types : FxIndexSet < DefId > ,
726727 potential_assoc_types : Vec < usize > ,
727728 trait_bounds : & [ hir:: PolyTraitRef < ' _ > ] ,
728729 ) -> Result < ( ) , ErrorGuaranteed > {
729- if associated_types . values ( ) . all ( |v| v . is_empty ( ) ) {
730+ if missing_assoc_types . is_empty ( ) {
730731 return Ok ( ( ) ) ;
731732 }
732733
733734 let tcx = self . tcx ( ) ;
734- // FIXME: Marked `mut` so that we can replace the spans further below with a more
735- // appropriate one, but this should be handled earlier in the span assignment.
736- let associated_types: FxIndexMap < Span , Vec < _ > > = associated_types
737- . into_iter ( )
738- . map ( |( span, def_ids) | {
739- ( span, def_ids. into_iter ( ) . map ( |did| tcx. associated_item ( did) ) . collect ( ) )
740- } )
741- . collect ( ) ;
735+ let missing_assoc_types: Vec < _ > =
736+ missing_assoc_types. into_iter ( ) . map ( |def_id| tcx. associated_item ( def_id) ) . collect ( ) ;
742737 let mut names: FxIndexMap < String , Vec < Symbol > > = Default :: default ( ) ;
743738 let mut names_len = 0 ;
744739
745740 // Account for things like `dyn Foo + 'a`, like in tests `issue-22434.rs` and
746741 // `issue-22560.rs`.
747- let mut trait_bound_spans: Vec < Span > = vec ! [ ] ;
748742 let mut dyn_compatibility_violations = Ok ( ( ) ) ;
749- for ( span, items) in & associated_types {
750- if !items. is_empty ( ) {
751- trait_bound_spans. push ( * span) ;
752- }
753- for assoc_item in items {
754- let trait_def_id = assoc_item. container_id ( tcx) ;
755- names. entry ( tcx. def_path_str ( trait_def_id) ) . or_default ( ) . push ( assoc_item. name ) ;
756- names_len += 1 ;
757-
758- let violations =
759- dyn_compatibility_violations_for_assoc_item ( tcx, trait_def_id, * assoc_item) ;
760- if !violations. is_empty ( ) {
761- dyn_compatibility_violations = Err ( report_dyn_incompatibility (
762- tcx,
763- * span,
764- None ,
765- trait_def_id,
766- & violations,
767- )
768- . emit ( ) ) ;
769- }
743+ for assoc_item in & missing_assoc_types {
744+ let trait_def_id = assoc_item. container_id ( tcx) ;
745+ names. entry ( tcx. def_path_str ( trait_def_id) ) . or_default ( ) . push ( assoc_item. name ) ;
746+ names_len += 1 ;
747+
748+ let violations =
749+ dyn_compatibility_violations_for_assoc_item ( tcx, trait_def_id, * assoc_item) ;
750+ if !violations. is_empty ( ) {
751+ dyn_compatibility_violations = Err ( report_dyn_incompatibility (
752+ tcx,
753+ principal_span,
754+ None ,
755+ trait_def_id,
756+ & violations,
757+ )
758+ . emit ( ) ) ;
770759 }
771760 }
772761
@@ -827,10 +816,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
827816 names. sort ( ) ;
828817 let names = names. join ( ", " ) ;
829818
830- trait_bound_spans. sort ( ) ;
831819 let mut err = struct_span_code_err ! (
832820 self . dcx( ) ,
833- trait_bound_spans ,
821+ principal_span ,
834822 E0191 ,
835823 "the value of the associated type{} {} must be specified" ,
836824 pluralize!( names_len) ,
@@ -840,81 +828,81 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
840828 let mut types_count = 0 ;
841829 let mut where_constraints = vec ! [ ] ;
842830 let mut already_has_generics_args_suggestion = false ;
843- for ( span, assoc_items) in & associated_types {
844- let mut names: UnordMap < _ , usize > = Default :: default ( ) ;
845- for item in assoc_items {
846- types_count += 1 ;
847- * names. entry ( item. name ) . or_insert ( 0 ) += 1 ;
848- }
849- let mut dupes = false ;
850- let mut shadows = false ;
851- for item in assoc_items {
852- let prefix = if names[ & item. name ] > 1 {
853- let trait_def_id = item. container_id ( tcx) ;
854- dupes = true ;
855- format ! ( "{}::" , tcx. def_path_str( trait_def_id) )
856- } else if bound_names. get ( & item. name ) . is_some_and ( |x| x != & item) {
857- let trait_def_id = item. container_id ( tcx) ;
858- shadows = true ;
859- format ! ( "{}::" , tcx. def_path_str( trait_def_id) )
860- } else {
861- String :: new ( )
862- } ;
863831
864- let mut is_shadowed = false ;
865-
866- if let Some ( assoc_item) = bound_names. get ( & item. name )
867- && assoc_item != & item
868- {
869- is_shadowed = true ;
832+ let mut names: UnordMap < _ , usize > = Default :: default ( ) ;
833+ for item in & missing_assoc_types {
834+ types_count += 1 ;
835+ * names. entry ( item. name ) . or_insert ( 0 ) += 1 ;
836+ }
837+ let mut dupes = false ;
838+ let mut shadows = false ;
839+ for item in & missing_assoc_types {
840+ let prefix = if names[ & item. name ] > 1 {
841+ let trait_def_id = item. container_id ( tcx) ;
842+ dupes = true ;
843+ format ! ( "{}::" , tcx. def_path_str( trait_def_id) )
844+ } else if bound_names. get ( & item. name ) . is_some_and ( |x| * x != item) {
845+ let trait_def_id = item. container_id ( tcx) ;
846+ shadows = true ;
847+ format ! ( "{}::" , tcx. def_path_str( trait_def_id) )
848+ } else {
849+ String :: new ( )
850+ } ;
870851
871- let rename_message =
872- if assoc_item. def_id . is_local ( ) { ", consider renaming it" } else { "" } ;
873- err. span_label (
874- tcx. def_span ( assoc_item. def_id ) ,
875- format ! ( "`{}{}` shadowed here{}" , prefix, item. name, rename_message) ,
876- ) ;
877- }
852+ let mut is_shadowed = false ;
878853
879- let rename_message = if is_shadowed { ", consider renaming it" } else { "" } ;
854+ if let Some ( assoc_item) = bound_names. get ( & item. name )
855+ && * assoc_item != item
856+ {
857+ is_shadowed = true ;
880858
881- if let Some ( sp ) = tcx . hir ( ) . span_if_local ( item . def_id ) {
882- err . span_label (
883- sp ,
884- format ! ( "`{}{}` defined here{}" , prefix , item . name , rename_message ) ,
885- ) ;
886- }
859+ let rename_message =
860+ if assoc_item . def_id . is_local ( ) { ", consider renaming it" } else { "" } ;
861+ err . span_label (
862+ tcx . def_span ( assoc_item . def_id ) ,
863+ format ! ( "`{}{}` shadowed here{}" , prefix , item . name , rename_message ) ,
864+ ) ;
887865 }
888- if potential_assoc_types. len ( ) == assoc_items. len ( ) {
889- // When the amount of missing associated types equals the number of
890- // extra type arguments present. A suggesting to replace the generic args with
891- // associated types is already emitted.
892- already_has_generics_args_suggestion = true ;
893- } else if let ( Ok ( snippet) , false , false ) =
894- ( tcx. sess . source_map ( ) . span_to_snippet ( * span) , dupes, shadows)
895- {
896- let types: Vec < _ > =
897- assoc_items. iter ( ) . map ( |item| format ! ( "{} = Type" , item. name) ) . collect ( ) ;
898- let code = if snippet. ends_with ( '>' ) {
899- // The user wrote `Trait<'a>` or similar and we don't have a type we can
900- // suggest, but at least we can clue them to the correct syntax
901- // `Trait<'a, Item = Type>` while accounting for the `<'a>` in the
902- // suggestion.
903- format ! ( "{}, {}>" , & snippet[ ..snippet. len( ) - 1 ] , types. join( ", " ) )
904- } else if in_expr_or_pat {
905- // The user wrote `Iterator`, so we don't have a type we can suggest, but at
906- // least we can clue them to the correct syntax `Iterator::<Item = Type>`.
907- format ! ( "{}::<{}>" , snippet, types. join( ", " ) )
908- } else {
909- // The user wrote `Iterator`, so we don't have a type we can suggest, but at
910- // least we can clue them to the correct syntax `Iterator<Item = Type>`.
911- format ! ( "{}<{}>" , snippet, types. join( ", " ) )
912- } ;
913- suggestions. push ( ( * span, code) ) ;
914- } else if dupes {
915- where_constraints. push ( * span) ;
866+
867+ let rename_message = if is_shadowed { ", consider renaming it" } else { "" } ;
868+
869+ if let Some ( sp) = tcx. hir ( ) . span_if_local ( item. def_id ) {
870+ err. span_label (
871+ sp,
872+ format ! ( "`{}{}` defined here{}" , prefix, item. name, rename_message) ,
873+ ) ;
916874 }
917875 }
876+ if potential_assoc_types. len ( ) == missing_assoc_types. len ( ) {
877+ // When the amount of missing associated types equals the number of
878+ // extra type arguments present. A suggesting to replace the generic args with
879+ // associated types is already emitted.
880+ already_has_generics_args_suggestion = true ;
881+ } else if let ( Ok ( snippet) , false , false ) =
882+ ( tcx. sess . source_map ( ) . span_to_snippet ( principal_span) , dupes, shadows)
883+ {
884+ let types: Vec < _ > =
885+ missing_assoc_types. iter ( ) . map ( |item| format ! ( "{} = Type" , item. name) ) . collect ( ) ;
886+ let code = if snippet. ends_with ( '>' ) {
887+ // The user wrote `Trait<'a>` or similar and we don't have a type we can
888+ // suggest, but at least we can clue them to the correct syntax
889+ // `Trait<'a, Item = Type>` while accounting for the `<'a>` in the
890+ // suggestion.
891+ format ! ( "{}, {}>" , & snippet[ ..snippet. len( ) - 1 ] , types. join( ", " ) )
892+ } else if in_expr_or_pat {
893+ // The user wrote `Iterator`, so we don't have a type we can suggest, but at
894+ // least we can clue them to the correct syntax `Iterator::<Item = Type>`.
895+ format ! ( "{}::<{}>" , snippet, types. join( ", " ) )
896+ } else {
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+ } ;
901+ suggestions. push ( ( principal_span, code) ) ;
902+ } else if dupes {
903+ where_constraints. push ( principal_span) ;
904+ }
905+
918906 let where_msg = "consider introducing a new type parameter, adding `where` constraints \
919907 using the fully-qualified path to the associated types";
920908 if !where_constraints. is_empty ( ) && suggestions. is_empty ( ) {
@@ -925,32 +913,30 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
925913 }
926914 if suggestions. len ( ) != 1 || already_has_generics_args_suggestion {
927915 // We don't need this label if there's an inline suggestion, show otherwise.
928- for ( span, assoc_items) in & associated_types {
929- let mut names: FxIndexMap < _ , usize > = FxIndexMap :: default ( ) ;
930- for item in assoc_items {
931- types_count += 1 ;
932- * names. entry ( item. name ) . or_insert ( 0 ) += 1 ;
933- }
934- let mut label = vec ! [ ] ;
935- for item in assoc_items {
936- let postfix = if names[ & item. name ] > 1 {
937- let trait_def_id = item. container_id ( tcx) ;
938- format ! ( " (from trait `{}`)" , tcx. def_path_str( trait_def_id) )
939- } else {
940- String :: new ( )
941- } ;
942- label. push ( format ! ( "`{}`{}" , item. name, postfix) ) ;
943- }
944- if !label. is_empty ( ) {
945- err. span_label (
946- * span,
947- format ! (
948- "associated type{} {} must be specified" ,
949- pluralize!( label. len( ) ) ,
950- label. join( ", " ) ,
951- ) ,
952- ) ;
953- }
916+ let mut names: FxIndexMap < _ , usize > = FxIndexMap :: default ( ) ;
917+ for item in & missing_assoc_types {
918+ types_count += 1 ;
919+ * names. entry ( item. name ) . or_insert ( 0 ) += 1 ;
920+ }
921+ let mut label = vec ! [ ] ;
922+ for item in & missing_assoc_types {
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+ principal_span,
934+ format ! (
935+ "associated type{} {} must be specified" ,
936+ pluralize!( label. len( ) ) ,
937+ label. join( ", " ) ,
938+ ) ,
939+ ) ;
954940 }
955941 }
956942 suggestions. sort_by_key ( |& ( span, _) | span) ;
0 commit comments