@@ -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+ mut 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 mut 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 {
@@ -794,11 +784,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
794784 // | ^^^^^^^^^^^^^ help: specify the associated type:
795785 // | `BitXor::bitor<Output = Type>`
796786 [ segment] if segment. args . is_none ( ) => {
797- trait_bound_spans = vec ! [ segment. ident. span] ;
798- associated_types = associated_types
799- . into_values ( )
800- . map ( |items| ( segment. ident . span , items) )
801- . collect ( ) ;
787+ principal_span = segment. ident . span ;
802788 }
803789 _ => { }
804790 }
@@ -847,10 +833,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
847833 names. sort ( ) ;
848834 let names = names. join ( ", " ) ;
849835
850- trait_bound_spans. sort ( ) ;
851836 let mut err = struct_span_code_err ! (
852837 self . dcx( ) ,
853- trait_bound_spans ,
838+ principal_span ,
854839 E0191 ,
855840 "the value of the associated type{} {} must be specified" ,
856841 pluralize!( names_len) ,
@@ -860,81 +845,81 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
860845 let mut types_count = 0 ;
861846 let mut where_constraints = vec ! [ ] ;
862847 let mut already_has_generics_args_suggestion = false ;
863- for ( span, assoc_items) in & associated_types {
864- let mut names: UnordMap < _ , usize > = Default :: default ( ) ;
865- for item in assoc_items {
866- types_count += 1 ;
867- * names. entry ( item. name ) . or_insert ( 0 ) += 1 ;
868- }
869- let mut dupes = false ;
870- let mut shadows = false ;
871- for item in assoc_items {
872- let prefix = if names[ & item. name ] > 1 {
873- let trait_def_id = item. container_id ( tcx) ;
874- dupes = true ;
875- format ! ( "{}::" , tcx. def_path_str( trait_def_id) )
876- } else if bound_names. get ( & item. name ) . is_some_and ( |x| x != & item) {
877- let trait_def_id = item. container_id ( tcx) ;
878- shadows = true ;
879- format ! ( "{}::" , tcx. def_path_str( trait_def_id) )
880- } else {
881- String :: new ( )
882- } ;
883-
884- let mut is_shadowed = false ;
885848
886- if let Some ( assoc_item) = bound_names. get ( & item. name )
887- && assoc_item != & item
888- {
889- is_shadowed = true ;
849+ let mut names: UnordMap < _ , usize > = Default :: default ( ) ;
850+ for item in & missing_assoc_types {
851+ types_count += 1 ;
852+ * names. entry ( item. name ) . or_insert ( 0 ) += 1 ;
853+ }
854+ let mut dupes = false ;
855+ let mut shadows = false ;
856+ for item in & missing_assoc_types {
857+ let prefix = if names[ & item. name ] > 1 {
858+ let trait_def_id = item. container_id ( tcx) ;
859+ dupes = true ;
860+ format ! ( "{}::" , tcx. def_path_str( trait_def_id) )
861+ } else if bound_names. get ( & item. name ) . is_some_and ( |x| * x != item) {
862+ let trait_def_id = item. container_id ( tcx) ;
863+ shadows = true ;
864+ format ! ( "{}::" , tcx. def_path_str( trait_def_id) )
865+ } else {
866+ String :: new ( )
867+ } ;
890868
891- let rename_message =
892- if assoc_item. def_id . is_local ( ) { ", consider renaming it" } else { "" } ;
893- err. span_label (
894- tcx. def_span ( assoc_item. def_id ) ,
895- format ! ( "`{}{}` shadowed here{}" , prefix, item. name, rename_message) ,
896- ) ;
897- }
869+ let mut is_shadowed = false ;
898870
899- let rename_message = if is_shadowed { ", consider renaming it" } else { "" } ;
871+ if let Some ( assoc_item) = bound_names. get ( & item. name )
872+ && * assoc_item != item
873+ {
874+ is_shadowed = true ;
900875
901- if let Some ( sp ) = tcx . hir ( ) . span_if_local ( item . def_id ) {
902- err . span_label (
903- sp ,
904- format ! ( "`{}{}` defined here{}" , prefix , item . name , rename_message ) ,
905- ) ;
906- }
876+ let rename_message =
877+ if assoc_item . def_id . is_local ( ) { ", consider renaming it" } else { "" } ;
878+ err . span_label (
879+ tcx . def_span ( assoc_item . def_id ) ,
880+ format ! ( "`{}{}` shadowed here{}" , prefix , item . name , rename_message ) ,
881+ ) ;
907882 }
908- if potential_assoc_types. len ( ) == assoc_items. len ( ) {
909- // When the amount of missing associated types equals the number of
910- // extra type arguments present. A suggesting to replace the generic args with
911- // associated types is already emitted.
912- already_has_generics_args_suggestion = true ;
913- } else if let ( Ok ( snippet) , false , false ) =
914- ( tcx. sess . source_map ( ) . span_to_snippet ( * span) , dupes, shadows)
915- {
916- let types: Vec < _ > =
917- assoc_items. iter ( ) . map ( |item| format ! ( "{} = Type" , item. name) ) . collect ( ) ;
918- let code = if snippet. ends_with ( '>' ) {
919- // The user wrote `Trait<'a>` or similar and we don't have a type we can
920- // suggest, but at least we can clue them to the correct syntax
921- // `Trait<'a, Item = Type>` while accounting for the `<'a>` in the
922- // suggestion.
923- format ! ( "{}, {}>" , & snippet[ ..snippet. len( ) - 1 ] , types. join( ", " ) )
924- } else if in_expr_or_pat {
925- // The user wrote `Iterator`, so we don't have a type we can suggest, but at
926- // least we can clue them to the correct syntax `Iterator::<Item = Type>`.
927- format ! ( "{}::<{}>" , snippet, types. join( ", " ) )
928- } else {
929- // The user wrote `Iterator`, so we don't have a type we can suggest, but at
930- // least we can clue them to the correct syntax `Iterator<Item = Type>`.
931- format ! ( "{}<{}>" , snippet, types. join( ", " ) )
932- } ;
933- suggestions. push ( ( * span, code) ) ;
934- } else if dupes {
935- where_constraints. push ( * span) ;
883+
884+ let rename_message = if is_shadowed { ", consider renaming it" } else { "" } ;
885+
886+ if let Some ( sp) = tcx. hir ( ) . span_if_local ( item. def_id ) {
887+ err. span_label (
888+ sp,
889+ format ! ( "`{}{}` defined here{}" , prefix, item. name, rename_message) ,
890+ ) ;
936891 }
937892 }
893+ if potential_assoc_types. len ( ) == missing_assoc_types. len ( ) {
894+ // When the amount of missing associated types equals the number of
895+ // extra type arguments present. A suggesting to replace the generic args with
896+ // associated types is already emitted.
897+ already_has_generics_args_suggestion = true ;
898+ } else if let ( Ok ( snippet) , false , false ) =
899+ ( tcx. sess . source_map ( ) . span_to_snippet ( principal_span) , dupes, shadows)
900+ {
901+ let types: Vec < _ > =
902+ missing_assoc_types. iter ( ) . map ( |item| format ! ( "{} = Type" , item. name) ) . collect ( ) ;
903+ let code = if snippet. ends_with ( '>' ) {
904+ // The user wrote `Trait<'a>` or similar and we don't have a type we can
905+ // suggest, but at least we can clue them to the correct syntax
906+ // `Trait<'a, Item = Type>` while accounting for the `<'a>` in the
907+ // suggestion.
908+ format ! ( "{}, {}>" , & snippet[ ..snippet. len( ) - 1 ] , types. join( ", " ) )
909+ } else if in_expr_or_pat {
910+ // The user wrote `Iterator`, so we don't have a type we can suggest, but at
911+ // least we can clue them to the correct syntax `Iterator::<Item = Type>`.
912+ format ! ( "{}::<{}>" , snippet, types. join( ", " ) )
913+ } else {
914+ // The user wrote `Iterator`, so we don't have a type we can suggest, but at
915+ // least we can clue them to the correct syntax `Iterator<Item = Type>`.
916+ format ! ( "{}<{}>" , snippet, types. join( ", " ) )
917+ } ;
918+ suggestions. push ( ( principal_span, code) ) ;
919+ } else if dupes {
920+ where_constraints. push ( principal_span) ;
921+ }
922+
938923 let where_msg = "consider introducing a new type parameter, adding `where` constraints \
939924 using the fully-qualified path to the associated types";
940925 if !where_constraints. is_empty ( ) && suggestions. is_empty ( ) {
@@ -945,32 +930,30 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
945930 }
946931 if suggestions. len ( ) != 1 || already_has_generics_args_suggestion {
947932 // We don't need this label if there's an inline suggestion, show otherwise.
948- for ( span, assoc_items) in & associated_types {
949- let mut names: FxIndexMap < _ , usize > = FxIndexMap :: default ( ) ;
950- for item in assoc_items {
951- types_count += 1 ;
952- * names. entry ( item. name ) . or_insert ( 0 ) += 1 ;
953- }
954- let mut label = vec ! [ ] ;
955- for item in assoc_items {
956- let postfix = if names[ & item. name ] > 1 {
957- let trait_def_id = item. container_id ( tcx) ;
958- format ! ( " (from trait `{}`)" , tcx. def_path_str( trait_def_id) )
959- } else {
960- String :: new ( )
961- } ;
962- label. push ( format ! ( "`{}`{}" , item. name, postfix) ) ;
963- }
964- if !label. is_empty ( ) {
965- err. span_label (
966- * span,
967- format ! (
968- "associated type{} {} must be specified" ,
969- pluralize!( label. len( ) ) ,
970- label. join( ", " ) ,
971- ) ,
972- ) ;
973- }
933+ let mut names: FxIndexMap < _ , usize > = FxIndexMap :: default ( ) ;
934+ for item in & missing_assoc_types {
935+ types_count += 1 ;
936+ * names. entry ( item. name ) . or_insert ( 0 ) += 1 ;
937+ }
938+ let mut label = vec ! [ ] ;
939+ for item in & missing_assoc_types {
940+ let postfix = if names[ & item. name ] > 1 {
941+ let trait_def_id = item. container_id ( tcx) ;
942+ format ! ( " (from trait `{}`)" , tcx. def_path_str( trait_def_id) )
943+ } else {
944+ String :: new ( )
945+ } ;
946+ label. push ( format ! ( "`{}`{}" , item. name, postfix) ) ;
947+ }
948+ if !label. is_empty ( ) {
949+ err. span_label (
950+ principal_span,
951+ format ! (
952+ "associated type{} {} must be specified" ,
953+ pluralize!( label. len( ) ) ,
954+ label. join( ", " ) ,
955+ ) ,
956+ ) ;
974957 }
975958 }
976959 suggestions. sort_by_key ( |& ( span, _) | span) ;
0 commit comments