@@ -3281,6 +3281,63 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
32813281 }
32823282 }
32833283
3284+ /// Checks if we can suggest a derive macro for the unmet trait bound.
3285+ /// Returns Some(list_of_derives) if possible, or None if not.
3286+ fn consider_suggesting_derives_for_ty (
3287+ & self ,
3288+ trait_pred : ty:: TraitPredicate < ' tcx > ,
3289+ adt : ty:: AdtDef < ' tcx > ,
3290+ ) -> Option < Vec < ( String , Span , Symbol ) > > {
3291+ let diagnostic_name = self . tcx . get_diagnostic_name ( trait_pred. def_id ( ) ) ?;
3292+
3293+ let can_derive = match diagnostic_name {
3294+ sym:: Default
3295+ | sym:: Eq
3296+ | sym:: PartialEq
3297+ | sym:: Ord
3298+ | sym:: PartialOrd
3299+ | sym:: Clone
3300+ | sym:: Copy
3301+ | sym:: Hash
3302+ | sym:: Debug => true ,
3303+ _ => false ,
3304+ } ;
3305+
3306+ if !can_derive {
3307+ return None ;
3308+ }
3309+
3310+ let trait_def_id = trait_pred. def_id ( ) ;
3311+ let self_ty = trait_pred. self_ty ( ) ;
3312+
3313+ // We need to check if there is already a manual implementation of the trait
3314+ // for this specific ADT to avoid suggesting `#[derive(..)]` that would conflict.
3315+ if self . tcx . non_blanket_impls_for_ty ( trait_def_id, self_ty) . any ( |impl_def_id| {
3316+ self . tcx
3317+ . type_of ( impl_def_id)
3318+ . instantiate_identity ( )
3319+ . ty_adt_def ( )
3320+ . is_some_and ( |def| def. did ( ) == adt. did ( ) )
3321+ } ) {
3322+ return None ;
3323+ }
3324+
3325+ let mut derives = Vec :: new ( ) ;
3326+ let self_name = self_ty. to_string ( ) ;
3327+ let self_span = self . tcx . def_span ( adt. did ( ) ) ;
3328+
3329+ for super_trait in supertraits ( self . tcx , ty:: Binder :: dummy ( trait_pred. trait_ref ) ) {
3330+ if let Some ( parent_diagnostic_name) = self . tcx . get_diagnostic_name ( super_trait. def_id ( ) )
3331+ {
3332+ derives. push ( ( self_name. clone ( ) , self_span, parent_diagnostic_name) ) ;
3333+ }
3334+ }
3335+
3336+ derives. push ( ( self_name, self_span, diagnostic_name) ) ;
3337+
3338+ Some ( derives)
3339+ }
3340+
32843341 fn note_predicate_source_and_get_derives (
32853342 & self ,
32863343 err : & mut Diag < ' _ > ,
@@ -3298,35 +3355,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
32983355 Some ( adt) if adt. did ( ) . is_local ( ) => adt,
32993356 _ => continue ,
33003357 } ;
3301- if let Some ( diagnostic_name) = self . tcx . get_diagnostic_name ( trait_pred. def_id ( ) ) {
3302- let can_derive = match diagnostic_name {
3303- sym:: Default
3304- | sym:: Eq
3305- | sym:: PartialEq
3306- | sym:: Ord
3307- | sym:: PartialOrd
3308- | sym:: Clone
3309- | sym:: Copy
3310- | sym:: Hash
3311- | sym:: Debug => true ,
3312- _ => false ,
3313- } ;
3314- if can_derive {
3315- let self_name = trait_pred. self_ty ( ) . to_string ( ) ;
3316- let self_span = self . tcx . def_span ( adt. did ( ) ) ;
3317- for super_trait in
3318- supertraits ( self . tcx , ty:: Binder :: dummy ( trait_pred. trait_ref ) )
3319- {
3320- if let Some ( parent_diagnostic_name) =
3321- self . tcx . get_diagnostic_name ( super_trait. def_id ( ) )
3322- {
3323- derives. push ( ( self_name. clone ( ) , self_span, parent_diagnostic_name) ) ;
3324- }
3325- }
3326- derives. push ( ( self_name, self_span, diagnostic_name) ) ;
3327- } else {
3328- traits. push ( trait_pred. def_id ( ) ) ;
3329- }
3358+ if let Some ( new_derives) = self . consider_suggesting_derives_for_ty ( trait_pred, adt) {
3359+ derives. extend ( new_derives) ;
33303360 } else {
33313361 traits. push ( trait_pred. def_id ( ) ) ;
33323362 }
0 commit comments