@@ -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;
@@ -13,6 +14,7 @@ use rustc_session::parse::feature_err;
1314use rustc_span:: edit_distance:: find_best_match_for_name;
1415use rustc_span:: symbol:: { sym, Ident } ;
1516use rustc_span:: { Span , Symbol , DUMMY_SP } ;
17+ use rustc_trait_selection:: traits:: object_safety_violations_for_assoc_item;
1618
1719use std:: collections:: BTreeSet ;
1820
@@ -520,24 +522,33 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
520522 ( span, def_ids. into_iter ( ) . map ( |did| tcx. associated_item ( did) ) . collect ( ) )
521523 } )
522524 . collect ( ) ;
523- let mut names = vec ! [ ] ;
525+ let mut names: FxHashMap < String , Vec < Symbol > > = Default :: default ( ) ;
526+ let mut names_len = 0 ;
524527
525528 // Account for things like `dyn Foo + 'a`, like in tests `issue-22434.rs` and
526529 // `issue-22560.rs`.
527530 let mut trait_bound_spans: Vec < Span > = vec ! [ ] ;
531+ let mut object_safety_violations = false ;
528532 for ( span, items) in & associated_types {
529533 if !items. is_empty ( ) {
530534 trait_bound_spans. push ( * span) ;
531535 }
532536 for assoc_item in items {
533537 let trait_def_id = assoc_item. container_id ( tcx) ;
534- names. push ( format ! (
535- "`{}` (from trait `{}`)" ,
536- assoc_item. name,
537- tcx. def_path_str( trait_def_id) ,
538- ) ) ;
538+ names. entry ( tcx. def_path_str ( trait_def_id) ) . or_default ( ) . push ( assoc_item. name ) ;
539+ names_len += 1 ;
540+
541+ let violations =
542+ object_safety_violations_for_assoc_item ( tcx, trait_def_id, * assoc_item) ;
543+ if !violations. is_empty ( ) {
544+ report_object_safety_error ( tcx, * span, trait_def_id, & violations) . emit ( ) ;
545+ object_safety_violations = true ;
546+ }
539547 }
540548 }
549+ if object_safety_violations {
550+ return ;
551+ }
541552 if let ( [ ] , [ bound] ) = ( & potential_assoc_types[ ..] , & trait_bounds) {
542553 match bound. trait_ref . path . segments {
543554 // FIXME: `trait_ref.path.span` can point to a full path with multiple
@@ -573,15 +584,33 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
573584 _ => { }
574585 }
575586 }
576- names. sort ( ) ;
587+
588+ let names = names
589+ . into_iter ( )
590+ . map ( |( trait_, assocs) | {
591+ format ! (
592+ "{} in `{trait_}`" ,
593+ match & assocs[ ..] {
594+ [ ] => String :: new( ) ,
595+ [ only] => format!( "`{only}`" ) ,
596+ [ assocs @ .., last] => format!(
597+ "{} and `{last}`" ,
598+ assocs. iter( ) . map( |a| format!( "`{a}`" ) ) . collect:: <Vec <_>>( ) . join( ", " )
599+ ) ,
600+ }
601+ )
602+ } )
603+ . collect :: < Vec < String > > ( )
604+ . join ( ", " ) ;
605+
577606 trait_bound_spans. sort ( ) ;
578607 let mut err = struct_span_err ! (
579608 tcx. sess,
580609 trait_bound_spans,
581610 E0191 ,
582611 "the value of the associated type{} {} must be specified" ,
583- pluralize!( names . len ( ) ) ,
584- names. join ( ", " ) ,
612+ pluralize!( names_len ) ,
613+ names,
585614 ) ;
586615 let mut suggestions = vec ! [ ] ;
587616 let mut types_count = 0 ;
0 commit comments