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