@@ -829,6 +829,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
829
829
err. note ( & format ! (
830
830
"the following trait bounds were not satisfied:\n {bound_list}"
831
831
) ) ;
832
+ self . suggest_derive ( & mut err, & unsatisfied_predicates) ;
833
+
832
834
unsatisfied_bounds = true ;
833
835
}
834
836
}
@@ -971,6 +973,85 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
971
973
None
972
974
}
973
975
976
+ fn suggest_derive (
977
+ & self ,
978
+ err : & mut DiagnosticBuilder < ' _ > ,
979
+ unsatisfied_predicates : & Vec < ( ty:: Predicate < ' tcx > , Option < ty:: Predicate < ' tcx > > ) > ,
980
+ ) {
981
+ let derivables = [
982
+ sym:: Eq ,
983
+ sym:: PartialEq ,
984
+ sym:: Ord ,
985
+ sym:: PartialOrd ,
986
+ sym:: Clone ,
987
+ sym:: Copy ,
988
+ sym:: Hash ,
989
+ sym:: Default ,
990
+ sym:: debug_trait,
991
+ ] ;
992
+ let mut derives = unsatisfied_predicates
993
+ . iter ( )
994
+ . filter_map ( |( pred, _) | {
995
+ let trait_pred =
996
+ if let ty:: PredicateKind :: Trait ( trait_pred) = pred. kind ( ) . skip_binder ( ) {
997
+ trait_pred
998
+ } else {
999
+ return None ;
1000
+ } ;
1001
+ let trait_ref = trait_pred. trait_ref ;
1002
+ let adt_def = if let ty:: Adt ( adt_def, _) = trait_ref. self_ty ( ) . kind ( ) {
1003
+ adt_def
1004
+ } else {
1005
+ return None ;
1006
+ } ;
1007
+ if adt_def. did . is_local ( ) {
1008
+ let diagnostic_items = self . tcx . diagnostic_items ( trait_ref. def_id . krate ) ;
1009
+ return derivables. iter ( ) . find_map ( |trait_derivable| {
1010
+ let item_def_id =
1011
+ if let Some ( item_def_id) = diagnostic_items. get ( trait_derivable) {
1012
+ item_def_id
1013
+ } else {
1014
+ return None ;
1015
+ } ;
1016
+ if item_def_id == & trait_pred. trait_ref . def_id
1017
+ && !( adt_def. is_enum ( ) && * trait_derivable == sym:: Default )
1018
+ {
1019
+ return Some ( (
1020
+ format ! ( "{}" , trait_ref. self_ty( ) ) ,
1021
+ self . tcx . def_span ( adt_def. did ) ,
1022
+ format ! ( "{}" , trait_ref. print_only_trait_path( ) ) ,
1023
+ ) ) ;
1024
+ }
1025
+ None
1026
+ } ) ;
1027
+ }
1028
+ None
1029
+ } )
1030
+ . collect :: < Vec < ( String , Span , String ) > > ( ) ;
1031
+ derives. sort ( ) ;
1032
+ let derives_grouped = derives. into_iter ( ) . fold (
1033
+ Vec :: < ( String , Span , String ) > :: new ( ) ,
1034
+ |mut acc, ( self_name, self_span, trait_name) | {
1035
+ if let Some ( ( acc_self_name, _, ref mut traits) ) = acc. last_mut ( ) {
1036
+ if acc_self_name == & self_name {
1037
+ traits. push_str ( format ! ( ", {}" , trait_name) . as_str ( ) ) ;
1038
+ return acc;
1039
+ }
1040
+ }
1041
+ acc. push ( ( self_name, self_span, trait_name) ) ;
1042
+ acc
1043
+ } ,
1044
+ ) ;
1045
+ for ( self_name, self_span, traits) in & derives_grouped {
1046
+ err. span_suggestion_verbose (
1047
+ self_span. shrink_to_lo ( ) ,
1048
+ & format ! ( "consider annotating `{}` with `#[derive({})]`" , self_name, traits) ,
1049
+ format ! ( "#[derive({})]\n " , traits) ,
1050
+ Applicability :: MaybeIncorrect ,
1051
+ ) ;
1052
+ }
1053
+ }
1054
+
974
1055
/// Print out the type for use in value namespace.
975
1056
fn ty_to_value_string ( & self , ty : Ty < ' tcx > ) -> String {
976
1057
match ty. kind ( ) {
0 commit comments