@@ -189,6 +189,13 @@ pub trait InferCtxtExt<'tcx> {
189189 err : & mut Diagnostic ,
190190 trait_ref : & ty:: PolyTraitRef < ' tcx > ,
191191 ) ;
192+
193+ fn suggest_derive (
194+ & self ,
195+ obligation : & PredicateObligation < ' tcx > ,
196+ err : & mut Diagnostic ,
197+ trait_pred : ty:: PolyTraitPredicate < ' tcx > ,
198+ ) ;
192199}
193200
194201fn predicate_constraint ( generics : & hir:: Generics < ' _ > , pred : String ) -> ( Span , String ) {
@@ -2651,6 +2658,68 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
26512658 _ => { }
26522659 }
26532660 }
2661+
2662+ fn suggest_derive (
2663+ & self ,
2664+ obligation : & PredicateObligation < ' tcx > ,
2665+ err : & mut Diagnostic ,
2666+ trait_pred : ty:: PolyTraitPredicate < ' tcx > ,
2667+ ) {
2668+ let Some ( diagnostic_name) = self . tcx . get_diagnostic_name ( trait_pred. def_id ( ) ) else {
2669+ return ;
2670+ } ;
2671+ let ( adt, substs) = match trait_pred. skip_binder ( ) . self_ty ( ) . kind ( ) {
2672+ ty:: Adt ( adt, substs) if adt. did ( ) . is_local ( ) => ( adt, substs) ,
2673+ _ => return ,
2674+ } ;
2675+ let can_derive = {
2676+ let is_derivable_trait = match diagnostic_name {
2677+ sym:: Default => !adt. is_enum ( ) ,
2678+ sym:: PartialEq | sym:: PartialOrd => {
2679+ let rhs_ty = trait_pred. skip_binder ( ) . trait_ref . substs . type_at ( 1 ) ;
2680+ trait_pred. skip_binder ( ) . self_ty ( ) == rhs_ty
2681+ }
2682+ sym:: Eq | sym:: Ord | sym:: Clone | sym:: Copy | sym:: Hash | sym:: Debug => true ,
2683+ _ => false ,
2684+ } ;
2685+ is_derivable_trait &&
2686+ // Ensure all fields impl the trait.
2687+ adt. all_fields ( ) . all ( |field| {
2688+ let field_ty = field. ty ( self . tcx , substs) ;
2689+ let trait_substs = match diagnostic_name {
2690+ sym:: PartialEq | sym:: PartialOrd => {
2691+ self . tcx . mk_substs_trait ( field_ty, & [ field_ty. into ( ) ] )
2692+ }
2693+ _ => self . tcx . mk_substs_trait ( field_ty, & [ ] ) ,
2694+ } ;
2695+ let trait_pred = trait_pred. map_bound_ref ( |tr| ty:: TraitPredicate {
2696+ trait_ref : ty:: TraitRef {
2697+ substs : trait_substs,
2698+ ..trait_pred. skip_binder ( ) . trait_ref
2699+ } ,
2700+ ..* tr
2701+ } ) ;
2702+ let field_obl = Obligation :: new (
2703+ obligation. cause . clone ( ) ,
2704+ obligation. param_env ,
2705+ trait_pred. to_predicate ( self . tcx ) ,
2706+ ) ;
2707+ self . predicate_must_hold_modulo_regions ( & field_obl)
2708+ } )
2709+ } ;
2710+ if can_derive {
2711+ err. span_suggestion_verbose (
2712+ self . tcx . def_span ( adt. did ( ) ) . shrink_to_lo ( ) ,
2713+ & format ! (
2714+ "consider annotating `{}` with `#[derive({})]`" ,
2715+ trait_pred. skip_binder( ) . self_ty( ) ,
2716+ diagnostic_name. to_string( ) ,
2717+ ) ,
2718+ format ! ( "#[derive({})]\n " , diagnostic_name. to_string( ) ) ,
2719+ Applicability :: MaybeIncorrect ,
2720+ ) ;
2721+ }
2722+ }
26542723}
26552724
26562725/// Collect all the returned expressions within the input expression.
0 commit comments