1- use rustc_ast:: { ExprKind , ItemKind , MetaItem , PatKind , Safety } ;
1+ use rustc_ast:: { ExprKind , ItemKind , MetaItem , PatKind , Safety , ast } ;
22use rustc_expand:: base:: { Annotatable , ExtCtxt } ;
33use rustc_span:: { Ident , Span , sym} ;
4- use thin_vec:: thin_vec;
4+ use thin_vec:: { ThinVec , thin_vec} ;
55
66use crate :: deriving:: generic:: ty:: * ;
77use crate :: deriving:: generic:: * ;
@@ -41,6 +41,45 @@ pub(crate) fn expand_deriving_partial_ord(
4141 } else {
4242 true
4343 } ;
44+
45+ let container_id = cx. current_expansion . id . expn_data ( ) . parent . expect_local ( ) ;
46+ let has_derive_ord = cx. resolver . has_derive_ord ( container_id) ;
47+ let is_simple_candidate = |params : & ThinVec < ast:: GenericParam > | -> bool {
48+ has_derive_ord
49+ && !params. iter ( ) . any ( |param| matches ! ( param. kind, ast:: GenericParamKind :: Type { .. } ) )
50+ } ;
51+
52+ let default_substructure = combine_substructure ( Box :: new ( |cx, span, substr| {
53+ cs_partial_cmp ( cx, span, substr, discr_then_data)
54+ } ) ) ;
55+ let simple_substructure = combine_substructure ( Box :: new ( |cx, span, _| {
56+ cs_partial_cmp_simple ( cx, span, cx. expr_ident ( span, Ident :: new ( sym:: other, span) ) )
57+ } ) ) ;
58+ let ( is_simple, substructure) = match item {
59+ Annotatable :: Item ( annitem) => match & annitem. kind {
60+ // For unit structs/zero-variant enums, the default generated code is better.
61+ ItemKind :: Struct ( .., ast:: VariantData :: Unit ( ..) ) => ( false , default_substructure) ,
62+ // Also for single fieldless variant enum
63+ ItemKind :: Enum ( .., enum_def) if enum_def. variants . is_empty ( ) => {
64+ ( false , default_substructure)
65+ }
66+ ItemKind :: Enum ( .., enum_def)
67+ if enum_def. variants . len ( ) == 1
68+ && matches ! ( enum_def. variants[ 0 ] . data, ast:: VariantData :: Unit ( ..) ) =>
69+ {
70+ ( false , default_substructure)
71+ }
72+ ItemKind :: Struct ( _, ast:: Generics { params, .. } , _)
73+ | ItemKind :: Enum ( _, ast:: Generics { params, .. } , _)
74+ if is_simple_candidate ( params) =>
75+ {
76+ ( true , simple_substructure)
77+ }
78+ _ => ( false , default_substructure) ,
79+ } ,
80+ _ => ( false , default_substructure) ,
81+ } ;
82+
4483 let partial_cmp_def = MethodDef {
4584 name : sym:: partial_cmp,
4685 generics : Bounds :: empty ( ) ,
@@ -49,9 +88,7 @@ pub(crate) fn expand_deriving_partial_ord(
4988 ret_ty,
5089 attributes : thin_vec ! [ cx. attr_word( sym:: inline, span) ] ,
5190 fieldless_variants_strategy : FieldlessVariantsStrategy :: Unify ,
52- combine_substructure : combine_substructure ( Box :: new ( |cx, span, substr| {
53- cs_partial_cmp ( cx, span, substr, discr_then_data)
54- } ) ) ,
91+ combine_substructure : substructure,
5592 } ;
5693
5794 let trait_def = TraitDef {
@@ -68,7 +105,18 @@ pub(crate) fn expand_deriving_partial_ord(
68105 safety : Safety :: Default ,
69106 document : true ,
70107 } ;
71- trait_def. expand ( cx, mitem, item, push)
108+ trait_def. expand_ext ( cx, mitem, item, push, is_simple)
109+ }
110+
111+ // Special case for the type deriving both `PartialOrd` and `Ord`. Builds:
112+ // ```
113+ // Some(::core::cmp::Ord::cmp(self, other))
114+ // ```
115+ fn cs_partial_cmp_simple ( cx : & ExtCtxt < ' _ > , span : Span , other_expr : Box < ast:: Expr > ) -> BlockOrExpr {
116+ let ord_cmp_path = cx. std_path ( & [ sym:: cmp, sym:: Ord , sym:: cmp] ) ;
117+ let cmp_expr =
118+ cx. expr_call_global ( span, ord_cmp_path, thin_vec ! [ cx. expr_self( span) , other_expr] ) ;
119+ BlockOrExpr :: new_expr ( cx. expr_some ( span, cmp_expr) )
72120}
73121
74122fn cs_partial_cmp (
@@ -98,7 +146,8 @@ fn cs_partial_cmp(
98146 |cx, fold| match fold {
99147 CsFold :: Single ( field) => {
100148 let [ other_expr] = & field. other_selflike_exprs [ ..] else {
101- cx. dcx ( ) . span_bug ( field. span , "not exactly 2 arguments in `derive(Ord)`" ) ;
149+ cx. dcx ( )
150+ . span_bug ( field. span , "not exactly 2 arguments in `derive(PartialOrd)`" ) ;
102151 } ;
103152 let args = thin_vec ! [ field. self_expr. clone( ) , other_expr. clone( ) ] ;
104153 cx. expr_call_global ( field. span , partial_cmp_path. clone ( ) , args)
0 commit comments