@@ -3,6 +3,7 @@ use crate::errors::{
33 AssocTypeBindingNotAllowed , ManualImplementation , MissingTypeParams ,
44 ParenthesizedFnTraitExpansion ,
55} ;
6+ use crate :: traits:: error_reporting:: report_object_safety_error;
67use rustc_data_structures:: fx:: FxHashMap ;
78use rustc_errors:: { pluralize, struct_span_err, Applicability , Diagnostic , ErrorGuaranteed } ;
89use rustc_hir as hir;
@@ -14,6 +15,7 @@ use rustc_session::parse::feature_err;
1415use rustc_span:: edit_distance:: find_best_match_for_name;
1516use rustc_span:: symbol:: { sym, Ident } ;
1617use rustc_span:: { Span , Symbol , DUMMY_SP } ;
18+ use rustc_trait_selection:: traits:: object_safety_violation_for_assoc_item;
1719
1820use std:: collections:: BTreeSet ;
1921
@@ -472,24 +474,33 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
472474 ( span, def_ids. into_iter ( ) . map ( |did| tcx. associated_item ( did) ) . collect ( ) )
473475 } )
474476 . collect ( ) ;
475- let mut names = vec ! [ ] ;
477+ let mut names: FxHashMap < String , Vec < Symbol > > = Default :: default ( ) ;
478+ let mut names_len = 0 ;
476479
477480 // Account for things like `dyn Foo + 'a`, like in tests `issue-22434.rs` and
478481 // `issue-22560.rs`.
479482 let mut trait_bound_spans: Vec < Span > = vec ! [ ] ;
483+ let mut object_safety_violations = false ;
480484 for ( span, items) in & associated_types {
481485 if !items. is_empty ( ) {
482486 trait_bound_spans. push ( * span) ;
483487 }
484488 for assoc_item in items {
485489 let trait_def_id = assoc_item. container_id ( tcx) ;
486- names. push ( format ! (
487- "`{}` (from trait `{}`)" ,
488- assoc_item. name,
489- tcx. def_path_str( trait_def_id) ,
490- ) ) ;
490+ names. entry ( tcx. def_path_str ( trait_def_id) ) . or_default ( ) . push ( assoc_item. name ) ;
491+ names_len += 1 ;
492+
493+ if let Some ( violation) =
494+ object_safety_violation_for_assoc_item ( tcx, trait_def_id, * assoc_item)
495+ {
496+ report_object_safety_error ( tcx, * span, trait_def_id, & [ violation] ) . emit ( ) ;
497+ object_safety_violations = true ;
498+ }
491499 }
492500 }
501+ if object_safety_violations {
502+ return ;
503+ }
493504 if let ( [ ] , [ bound] ) = ( & potential_assoc_types[ ..] , & trait_bounds) {
494505 match bound. trait_ref . path . segments {
495506 // FIXME: `trait_ref.path.span` can point to a full path with multiple
@@ -525,15 +536,33 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
525536 _ => { }
526537 }
527538 }
528- names. sort ( ) ;
539+
540+ let names = names
541+ . into_iter ( )
542+ . map ( |( trait_, assocs) | {
543+ format ! (
544+ "{} in `{trait_}`" ,
545+ match & assocs[ ..] {
546+ [ ] => String :: new( ) ,
547+ [ only] => format!( "`{only}`" ) ,
548+ [ assocs @ .., last] => format!(
549+ "{} and `{last}`" ,
550+ assocs. iter( ) . map( |a| format!( "`{a}`" ) ) . collect:: <Vec <_>>( ) . join( ", " )
551+ ) ,
552+ }
553+ )
554+ } )
555+ . collect :: < Vec < String > > ( )
556+ . join ( ", " ) ;
557+
529558 trait_bound_spans. sort ( ) ;
530559 let mut err = struct_span_err ! (
531560 tcx. sess,
532561 trait_bound_spans,
533562 E0191 ,
534563 "the value of the associated type{} {} must be specified" ,
535- pluralize!( names . len ( ) ) ,
536- names. join ( ", " ) ,
564+ pluralize!( names_len ) ,
565+ names,
537566 ) ;
538567 let mut suggestions = vec ! [ ] ;
539568 let mut types_count = 0 ;
0 commit comments