@@ -829,6 +829,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
829829 err. note ( & format ! (
830830 "the following trait bounds were not satisfied:\n {bound_list}"
831831 ) ) ;
832+ self . suggest_derive ( & mut err, & unsatisfied_predicates) ;
833+
832834 unsatisfied_bounds = true ;
833835 }
834836 }
@@ -971,6 +973,85 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
971973 None
972974 }
973975
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+
9741055 /// Print out the type for use in value namespace.
9751056 fn ty_to_value_string ( & self , ty : Ty < ' tcx > ) -> String {
9761057 match ty. kind ( ) {
0 commit comments