@@ -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 ) {
@@ -2651,6 +2658,68 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
2651
2658
_ => { }
2652
2659
}
2653
2660
}
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
+ }
2654
2723
}
2655
2724
2656
2725
/// Collect all the returned expressions within the input expression.
0 commit comments