Avoid the unnecessary innermost match in partial_cmp
/cmp
.
We currently do a match on the comparison of every field in a struct or enum variant. But the last field has a degenerate match like this: ``` match ::core::cmp::Ord::cmp(&self.y, &other.y) { ::core::cmp::Ordering::Equal => ::core::cmp::Ordering::Equal, cmp => cmp, }, ``` This commit changes it to this: ``` ::core::cmp::Ord::cmp(&self.y, &other.y), ``` This is fairly straightforward thanks to the existing `cs_fold1` function. The commit also removes the `cs_fold` function which is no longer used. (Note: there is some repetition now in `cs_cmp` and `cs_partial_cmp`. I will remove that in a follow-up PR.)
This commit is contained in:
parent
2c911dc16f
commit
0ee79f2c5a
4 changed files with 57 additions and 139 deletions
|
@ -70,7 +70,7 @@ pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> Bl
|
|||
// cmp => cmp
|
||||
// }
|
||||
//
|
||||
let expr = cs_fold(
|
||||
let expr = cs_fold1(
|
||||
// foldr nests the if-elses correctly, leaving the first field
|
||||
// as the outermost one, and the last as the innermost.
|
||||
false,
|
||||
|
@ -79,15 +79,12 @@ pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> Bl
|
|||
// ::std::cmp::Ordering::Equal => old,
|
||||
// cmp => cmp
|
||||
// }
|
||||
|
||||
let new = {
|
||||
let [other_f] = other_fs else {
|
||||
cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`");
|
||||
};
|
||||
|
||||
let args =
|
||||
vec![cx.expr_addr_of(span, self_f), cx.expr_addr_of(span, other_f.clone())];
|
||||
|
||||
cx.expr_call_global(span, cmp_path.clone(), args)
|
||||
};
|
||||
|
||||
|
@ -96,7 +93,21 @@ pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> Bl
|
|||
|
||||
cx.expr_match(span, new, vec![eq_arm, neq_arm])
|
||||
},
|
||||
cx.expr_path(equals_path.clone()),
|
||||
|cx, args| match args {
|
||||
Some((span, self_f, other_fs)) => {
|
||||
let new = {
|
||||
let [other_f] = other_fs else {
|
||||
cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`");
|
||||
};
|
||||
let args =
|
||||
vec![cx.expr_addr_of(span, self_f), cx.expr_addr_of(span, other_f.clone())];
|
||||
cx.expr_call_global(span, cmp_path.clone(), args)
|
||||
};
|
||||
|
||||
new
|
||||
}
|
||||
None => cx.expr_path(equals_path.clone()),
|
||||
},
|
||||
Box::new(|cx, span, tag_tuple| {
|
||||
if tag_tuple.len() != 2 {
|
||||
cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`")
|
||||
|
|
|
@ -2,7 +2,8 @@ use crate::deriving::generic::ty::*;
|
|||
use crate::deriving::generic::*;
|
||||
use crate::deriving::{path_std, pathvec_std};
|
||||
|
||||
use rustc_ast::MetaItem;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::{Expr, MetaItem};
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_span::symbol::{sym, Ident};
|
||||
use rustc_span::Span;
|
||||
|
@ -51,7 +52,6 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_
|
|||
let test_id = Ident::new(sym::cmp, span);
|
||||
let ordering = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal]));
|
||||
let ordering_expr = cx.expr_path(ordering.clone());
|
||||
let equals_expr = cx.expr_some(span, ordering_expr);
|
||||
|
||||
let partial_cmp_path = cx.std_path(&[sym::cmp, sym::PartialOrd, sym::partial_cmp]);
|
||||
|
||||
|
@ -68,7 +68,7 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_
|
|||
// cmp => cmp
|
||||
// }
|
||||
//
|
||||
let expr = cs_fold(
|
||||
let expr = cs_fold1(
|
||||
// foldr nests the if-elses correctly, leaving the first field
|
||||
// as the outermost one, and the last as the innermost.
|
||||
false,
|
||||
|
@ -94,7 +94,21 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_
|
|||
|
||||
cx.expr_match(span, new, vec![eq_arm, neq_arm])
|
||||
},
|
||||
equals_expr,
|
||||
|cx: &mut ExtCtxt<'_>, args: Option<(Span, P<Expr>, &[P<Expr>])>| match args {
|
||||
Some((span, self_f, other_fs)) => {
|
||||
let new = {
|
||||
let [other_f] = other_fs else {
|
||||
cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`");
|
||||
};
|
||||
let args =
|
||||
vec![cx.expr_addr_of(span, self_f), cx.expr_addr_of(span, other_f.clone())];
|
||||
cx.expr_call_global(span, partial_cmp_path.clone(), args)
|
||||
};
|
||||
|
||||
new
|
||||
}
|
||||
None => cx.expr_some(span, ordering_expr.clone()),
|
||||
},
|
||||
Box::new(|cx, span, tag_tuple| {
|
||||
if tag_tuple.len() != 2 {
|
||||
cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`")
|
||||
|
|
|
@ -1694,31 +1694,6 @@ fn cs_fold_static(cx: &mut ExtCtxt<'_>, trait_span: Span) -> P<Expr> {
|
|||
cx.span_bug(trait_span, "static function in `derive`")
|
||||
}
|
||||
|
||||
/// Fold the fields. `use_foldl` controls whether this is done
|
||||
/// left-to-right (`true`) or right-to-left (`false`).
|
||||
pub fn cs_fold<F>(
|
||||
use_foldl: bool,
|
||||
f: F,
|
||||
base: P<Expr>,
|
||||
enum_nonmatch_f: EnumNonMatchCollapsedFunc<'_>,
|
||||
cx: &mut ExtCtxt<'_>,
|
||||
trait_span: Span,
|
||||
substructure: &Substructure<'_>,
|
||||
) -> P<Expr>
|
||||
where
|
||||
F: FnMut(&mut ExtCtxt<'_>, Span, P<Expr>, P<Expr>, &[P<Expr>]) -> P<Expr>,
|
||||
{
|
||||
match *substructure.fields {
|
||||
EnumMatching(.., ref all_fields) | Struct(_, ref all_fields) => {
|
||||
cs_fold_fields(use_foldl, f, base, cx, all_fields)
|
||||
}
|
||||
EnumNonMatchingCollapsed(..) => {
|
||||
cs_fold_enumnonmatch(enum_nonmatch_f, cx, trait_span, substructure)
|
||||
}
|
||||
StaticEnum(..) | StaticStruct(..) => cs_fold_static(cx, trait_span),
|
||||
}
|
||||
}
|
||||
|
||||
/// Function to fold over fields, with three cases, to generate more efficient and concise code.
|
||||
/// When the `substructure` has grouped fields, there are two cases:
|
||||
/// Zero fields: call the base case function with `None` (like the usual base case of `cs_fold`).
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue