@@ -721,51 +721,42 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
721721 /// emit a generic note suggesting using a `where` clause to constraint instead.
722722 pub ( crate ) fn check_for_required_assoc_tys (
723723 & self ,
724- associated_types : FxIndexMap < Span , FxIndexSet < DefId > > ,
724+ principal_span : Span ,
725+ missing_assoc_types : FxIndexSet < ( DefId , ty:: PolyTraitRef < ' tcx > ) > ,
725726 potential_assoc_types : Vec < usize > ,
726727 trait_bounds : & [ hir:: PolyTraitRef < ' _ > ] ,
727728 ) -> Result < ( ) , ErrorGuaranteed > {
728- if associated_types . values ( ) . all ( |v| v . is_empty ( ) ) {
729+ if missing_assoc_types . is_empty ( ) {
729730 return Ok ( ( ) ) ;
730731 }
731732
732733 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
736736 . 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) )
740738 . collect ( ) ;
741- let mut names: FxIndexMap < String , Vec < Symbol > > = Default :: default ( ) ;
739+ let mut names: FxIndexMap < _ , Vec < Symbol > > = Default :: default ( ) ;
742740 let mut names_len = 0 ;
743741
744742 // Account for things like `dyn Foo + 'a`, like in tests `issue-22434.rs` and
745743 // `issue-22560.rs`.
746- let mut trait_bound_spans: Vec < Span > = vec ! [ ] ;
747744 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 ( ) ) ;
769760 }
770761 }
771762
@@ -813,6 +804,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
813804 . into_iter ( )
814805 . map ( |( trait_, mut assocs) | {
815806 assocs. sort ( ) ;
807+ let trait_ = trait_. print_trait_sugared ( ) ;
816808 format ! ( "{} in `{trait_}`" , match & assocs[ ..] {
817809 [ ] => String :: new( ) ,
818810 [ only] => format!( "`{only}`" ) ,
@@ -826,10 +818,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
826818 names. sort ( ) ;
827819 let names = names. join ( ", " ) ;
828820
829- trait_bound_spans. sort ( ) ;
830821 let mut err = struct_span_code_err ! (
831822 self . dcx( ) ,
832- trait_bound_spans ,
823+ principal_span ,
833824 E0191 ,
834825 "the value of the associated type{} {} must be specified" ,
835826 pluralize!( names_len) ,
@@ -839,81 +830,83 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
839830 let mut types_count = 0 ;
840831 let mut where_constraints = vec ! [ ] ;
841832 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- } ;
862833
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+ } ;
869853
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 ;
877855
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 ;
879860
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+ ) ;
886867 }
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+ ) ;
915876 }
916877 }
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+
917910 let where_msg = "consider introducing a new type parameter, adding `where` constraints \
918911 using the fully-qualified path to the associated types";
919912 if !where_constraints. is_empty ( ) && suggestions. is_empty ( ) {
@@ -924,32 +917,29 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
924917 }
925918 if suggestions. len ( ) != 1 || already_has_generics_args_suggestion {
926919 // 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+ ) ;
953943 }
954944 }
955945 suggestions. sort_by_key ( |& ( span, _) | span) ;
0 commit comments