Skip to content

Commit 16a286b

Browse files
committed
Simplify cs_fold.
`cs_fold` has four distinct cases, covered by three different function arguments: - first field - combine current field with previous results - no fields - non-matching enum variants This commit clarifies things by replacing the three function arguments with one that takes a new `CsFold` type with four slightly different) cases - single field - combine result for current field with results for previous fields - no fields - non-matching enum variants This makes the code shorter and clearer.
1 parent 559398f commit 16a286b

File tree

4 files changed

+114
-162
lines changed

4 files changed

+114
-162
lines changed

compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs

+28-47
Original file line numberDiff line numberDiff line change
@@ -55,57 +55,38 @@ pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> Bl
5555
// foldr nests the if-elses correctly, leaving the first field
5656
// as the outermost one, and the last as the innermost.
5757
false,
58-
|cx, span, old, self_expr, other_selflike_exprs| {
59-
// match new {
60-
// ::core::cmp::Ordering::Equal => old,
61-
// cmp => cmp
62-
// }
63-
let new = {
64-
let [other_expr] = other_selflike_exprs else {
65-
cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`");
66-
};
58+
cx,
59+
span,
60+
substr,
61+
|cx, fold| match fold {
62+
CsFold::Single(field) => {
63+
let [other_expr] = &field.other_selflike_exprs[..] else {
64+
cx.span_bug(field.span, "not exactly 2 arguments in `derive(Ord)`");
65+
};
6766
let args = vec![
68-
cx.expr_addr_of(span, self_expr),
69-
cx.expr_addr_of(span, other_expr.clone()),
67+
cx.expr_addr_of(field.span, field.self_expr.clone()),
68+
cx.expr_addr_of(field.span, other_expr.clone()),
7069
];
71-
cx.expr_call_global(span, cmp_path.clone(), args)
72-
};
73-
74-
let eq_arm = cx.arm(span, cx.pat_path(span, equal_path.clone()), old);
75-
let neq_arm = cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id));
76-
77-
cx.expr_match(span, new, vec![eq_arm, neq_arm])
78-
},
79-
|cx, args| match args {
80-
Some((span, self_expr, other_selflike_exprs)) => {
81-
let new = {
82-
let [other_expr] = other_selflike_exprs else {
83-
cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`");
84-
};
85-
let args = vec![
86-
cx.expr_addr_of(span, self_expr),
87-
cx.expr_addr_of(span, other_expr.clone()),
88-
];
89-
cx.expr_call_global(span, cmp_path.clone(), args)
90-
};
91-
92-
new
70+
cx.expr_call_global(field.span, cmp_path.clone(), args)
9371
}
94-
None => cx.expr_path(equal_path.clone()),
95-
},
96-
Box::new(|cx, span, tag_tuple| {
97-
if tag_tuple.len() != 2 {
98-
cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`")
99-
} else {
100-
let lft = cx.expr_addr_of(span, cx.expr_ident(span, tag_tuple[0]));
101-
let rgt = cx.expr_addr_of(span, cx.expr_ident(span, tag_tuple[1]));
102-
let fn_cmp_path = cx.std_path(&[sym::cmp, sym::Ord, sym::cmp]);
103-
cx.expr_call_global(span, fn_cmp_path, vec![lft, rgt])
72+
CsFold::Combine(span, expr1, expr2) => {
73+
let eq_arm = cx.arm(span, cx.pat_path(span, equal_path.clone()), expr1);
74+
let neq_arm =
75+
cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id));
76+
cx.expr_match(span, expr2, vec![eq_arm, neq_arm])
10477
}
105-
}),
106-
cx,
107-
span,
108-
substr,
78+
CsFold::Fieldless => cx.expr_path(equal_path.clone()),
79+
CsFold::EnumNonMatching(span, tag_tuple) => {
80+
if tag_tuple.len() != 2 {
81+
cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`")
82+
} else {
83+
let lft = cx.expr_addr_of(span, cx.expr_ident(span, tag_tuple[0]));
84+
let rgt = cx.expr_addr_of(span, cx.expr_ident(span, tag_tuple[1]));
85+
let fn_cmp_path = cx.std_path(&[sym::cmp, sym::Ord, sym::cmp]);
86+
cx.expr_call_global(span, fn_cmp_path, vec![lft, rgt])
87+
}
88+
}
89+
},
10990
);
11091
BlockOrExpr::new_expr(expr)
11192
}

compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs

+12-25
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ use crate::deriving::generic::ty::*;
22
use crate::deriving::generic::*;
33
use crate::deriving::{path_local, path_std};
44

5-
use rustc_ast::ptr::P;
6-
use rustc_ast::{BinOpKind, Expr, MetaItem};
5+
use rustc_ast::{BinOpKind, MetaItem};
76
use rustc_expand::base::{Annotatable, ExtCtxt};
87
use rustc_span::symbol::sym;
98
use rustc_span::Span;
@@ -23,34 +22,22 @@ pub fn expand_deriving_partial_eq(
2322
combiner: BinOpKind,
2423
base: bool,
2524
) -> BlockOrExpr {
26-
let op = |cx: &mut ExtCtxt<'_>,
27-
span: Span,
28-
self_expr: P<Expr>,
29-
other_selflike_exprs: &[P<Expr>]| {
30-
let [other_expr] = other_selflike_exprs else {
31-
cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`");
32-
};
33-
34-
cx.expr_binary(span, op, self_expr, other_expr.clone())
35-
};
36-
3725
let expr = cs_fold(
3826
true, // use foldl
39-
|cx, span, old, self_expr, other_selflike_exprs| {
40-
let eq = op(cx, span, self_expr, other_selflike_exprs);
41-
cx.expr_binary(span, combiner, old, eq)
42-
},
43-
|cx, args| match args {
44-
Some((span, self_expr, other_selflike_exprs)) => {
45-
// Special-case the base case to generate cleaner code.
46-
op(cx, span, self_expr, other_selflike_exprs)
47-
}
48-
None => cx.expr_bool(span, base),
49-
},
50-
Box::new(|cx, span, _| cx.expr_bool(span, !base)),
5127
cx,
5228
span,
5329
substr,
30+
|cx, fold| match fold {
31+
CsFold::Single(field) => {
32+
let [other_expr] = &field.other_selflike_exprs[..] else {
33+
cx.span_bug(field.span, "not exactly 2 arguments in `derive(PartialEq)`");
34+
};
35+
cx.expr_binary(field.span, op, field.self_expr.clone(), other_expr.clone())
36+
}
37+
CsFold::Combine(span, expr1, expr2) => cx.expr_binary(span, combiner, expr1, expr2),
38+
CsFold::Fieldless => cx.expr_bool(span, base),
39+
CsFold::EnumNonMatching(span, _tag_tuple) => cx.expr_bool(span, !base),
40+
},
5441
);
5542
BlockOrExpr::new_expr(expr)
5643
}

compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs

+30-51
Original file line numberDiff line numberDiff line change
@@ -63,61 +63,40 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_
6363
// foldr nests the if-elses correctly, leaving the first field
6464
// as the outermost one, and the last as the innermost.
6565
false,
66-
|cx, span, old, self_expr, other_selflike_exprs| {
67-
// match new {
68-
// Some(::core::cmp::Ordering::Equal) => old,
69-
// cmp => cmp
70-
// }
71-
let new = {
72-
let [other_expr] = other_selflike_exprs else {
73-
cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`");
74-
};
75-
66+
cx,
67+
span,
68+
substr,
69+
|cx, fold| match fold {
70+
CsFold::Single(field) => {
71+
let [other_expr] = &field.other_selflike_exprs[..] else {
72+
cx.span_bug(field.span, "not exactly 2 arguments in `derive(Ord)`");
73+
};
7674
let args = vec![
77-
cx.expr_addr_of(span, self_expr),
78-
cx.expr_addr_of(span, other_expr.clone()),
75+
cx.expr_addr_of(field.span, field.self_expr.clone()),
76+
cx.expr_addr_of(field.span, other_expr.clone()),
7977
];
80-
81-
cx.expr_call_global(span, partial_cmp_path.clone(), args)
82-
};
83-
84-
let eq_arm =
85-
cx.arm(span, cx.pat_some(span, cx.pat_path(span, equal_path.clone())), old);
86-
let neq_arm = cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id));
87-
88-
cx.expr_match(span, new, vec![eq_arm, neq_arm])
89-
},
90-
|cx, args| match args {
91-
Some((span, self_expr, other_selflike_exprs)) => {
92-
let new = {
93-
let [other_expr] = other_selflike_exprs else {
94-
cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`");
95-
};
96-
let args = vec![
97-
cx.expr_addr_of(span, self_expr),
98-
cx.expr_addr_of(span, other_expr.clone()),
99-
];
100-
cx.expr_call_global(span, partial_cmp_path.clone(), args)
101-
};
102-
103-
new
78+
cx.expr_call_global(field.span, partial_cmp_path.clone(), args)
10479
}
105-
None => cx.expr_some(span, cx.expr_path(equal_path.clone())),
106-
},
107-
Box::new(|cx, span, tag_tuple| {
108-
if tag_tuple.len() != 2 {
109-
cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`")
110-
} else {
111-
let lft = cx.expr_addr_of(span, cx.expr_ident(span, tag_tuple[0]));
112-
let rgt = cx.expr_addr_of(span, cx.expr_ident(span, tag_tuple[1]));
113-
let fn_partial_cmp_path =
114-
cx.std_path(&[sym::cmp, sym::PartialOrd, sym::partial_cmp]);
115-
cx.expr_call_global(span, fn_partial_cmp_path, vec![lft, rgt])
80+
CsFold::Combine(span, expr1, expr2) => {
81+
let eq_arm =
82+
cx.arm(span, cx.pat_some(span, cx.pat_path(span, equal_path.clone())), expr1);
83+
let neq_arm =
84+
cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id));
85+
cx.expr_match(span, expr2, vec![eq_arm, neq_arm])
11686
}
117-
}),
118-
cx,
119-
span,
120-
substr,
87+
CsFold::Fieldless => cx.expr_some(span, cx.expr_path(equal_path.clone())),
88+
CsFold::EnumNonMatching(span, tag_tuple) => {
89+
if tag_tuple.len() != 2 {
90+
cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`")
91+
} else {
92+
let lft = cx.expr_addr_of(span, cx.expr_ident(span, tag_tuple[0]));
93+
let rgt = cx.expr_addr_of(span, cx.expr_ident(span, tag_tuple[1]));
94+
let fn_partial_cmp_path =
95+
cx.std_path(&[sym::cmp, sym::PartialOrd, sym::partial_cmp]);
96+
cx.expr_call_global(span, fn_partial_cmp_path, vec![lft, rgt])
97+
}
98+
}
99+
},
121100
);
122101
BlockOrExpr::new_expr(expr)
123102
}

compiler/rustc_builtin_macros/src/deriving/generic/mod.rs

+44-39
Original file line numberDiff line numberDiff line change
@@ -296,11 +296,6 @@ pub enum SubstructureFields<'a> {
296296
pub type CombineSubstructureFunc<'a> =
297297
Box<dyn FnMut(&mut ExtCtxt<'_>, Span, &Substructure<'_>) -> BlockOrExpr + 'a>;
298298

299-
/// Deal with non-matching enum variants. The slice is the identifiers holding
300-
/// the variant index value for each of the `Self` arguments.
301-
pub type EnumNonMatchCollapsedFunc<'a> =
302-
Box<dyn FnMut(&mut ExtCtxt<'_>, Span, &[Ident]) -> P<Expr> + 'a>;
303-
304299
pub fn combine_substructure(
305300
f: CombineSubstructureFunc<'_>,
306301
) -> RefCell<CombineSubstructureFunc<'_>> {
@@ -1601,55 +1596,65 @@ impl<'a> TraitDef<'a> {
16011596
}
16021597
}
16031598

1604-
/// Function to fold over fields, with three cases, to generate more efficient and concise code.
1605-
/// When the `substructure` has grouped fields, there are two cases:
1606-
/// Zero fields: call the base case function with `None` (like the usual base case of `cs_fold`).
1607-
/// One or more fields: call the base case function on the first value (which depends on
1608-
/// `use_fold`), and use that as the base case. Then perform `cs_fold` on the remainder of the
1609-
/// fields.
1610-
/// When the `substructure` is an `EnumNonMatchingCollapsed`, the result of `enum_nonmatch_f`
1611-
/// is returned. Statics may not be folded over.
1612-
pub fn cs_fold<F, B>(
1599+
/// The function passed to `cs_fold` is called repeatedly with a value of this
1600+
/// type. It describes one part of the code generation. The result is always an
1601+
/// expression.
1602+
pub enum CsFold<'a> {
1603+
/// The basic case: a field expression for one or more selflike args. E.g.
1604+
/// for `PartialEq::eq` this is something like `self.x == other.x`.
1605+
Single(&'a FieldInfo),
1606+
1607+
/// The combination of two field expressions. E.g. for `PartialEq::eq` this
1608+
/// is something like `<field1 equality> && <field2 equality>`.
1609+
Combine(Span, P<Expr>, P<Expr>),
1610+
1611+
// The fallback case for a struct or enum variant with no fields.
1612+
Fieldless,
1613+
1614+
/// The fallback case for non-matching enum variants. The slice is the
1615+
/// identifiers holding the variant index value for each of the `Self`
1616+
/// arguments.
1617+
EnumNonMatching(Span, &'a [Ident]),
1618+
}
1619+
1620+
/// Folds over fields, combining the expressions for each field in a sequence.
1621+
/// Statics may not be folded over.
1622+
pub fn cs_fold<F>(
16131623
use_foldl: bool,
1614-
mut f: F,
1615-
mut b: B,
1616-
mut enum_nonmatch_f: EnumNonMatchCollapsedFunc<'_>,
16171624
cx: &mut ExtCtxt<'_>,
16181625
trait_span: Span,
16191626
substructure: &Substructure<'_>,
1627+
mut f: F,
16201628
) -> P<Expr>
16211629
where
1622-
F: FnMut(&mut ExtCtxt<'_>, Span, P<Expr>, P<Expr>, &[P<Expr>]) -> P<Expr>,
1623-
B: FnMut(&mut ExtCtxt<'_>, Option<(Span, P<Expr>, &[P<Expr>])>) -> P<Expr>,
1630+
F: FnMut(&mut ExtCtxt<'_>, CsFold<'_>) -> P<Expr>,
16241631
{
16251632
match *substructure.fields {
16261633
EnumMatching(.., ref all_fields) | Struct(_, ref all_fields) => {
1627-
let (base, rest) = match (all_fields.is_empty(), use_foldl) {
1628-
(false, true) => {
1629-
let (first, rest) = all_fields.split_first().unwrap();
1630-
let args =
1631-
(first.span, first.self_expr.clone(), &first.other_selflike_exprs[..]);
1632-
(b(cx, Some(args)), rest)
1633-
}
1634-
(false, false) => {
1635-
let (last, rest) = all_fields.split_last().unwrap();
1636-
let args = (last.span, last.self_expr.clone(), &last.other_selflike_exprs[..]);
1637-
(b(cx, Some(args)), rest)
1638-
}
1639-
(true, _) => (b(cx, None), &all_fields[..]),
1634+
if all_fields.is_empty() {
1635+
return f(cx, CsFold::Fieldless);
1636+
}
1637+
1638+
let (base_field, rest) = if use_foldl {
1639+
all_fields.split_first().unwrap()
1640+
} else {
1641+
all_fields.split_last().unwrap()
1642+
};
1643+
1644+
let base_expr = f(cx, CsFold::Single(base_field));
1645+
1646+
let op = |old, field: &FieldInfo| {
1647+
let new = f(cx, CsFold::Single(field));
1648+
f(cx, CsFold::Combine(field.span, old, new))
16401649
};
16411650

16421651
if use_foldl {
1643-
rest.iter().fold(base, |old, field| {
1644-
f(cx, field.span, old, field.self_expr.clone(), &field.other_selflike_exprs)
1645-
})
1652+
rest.iter().fold(base_expr, op)
16461653
} else {
1647-
rest.iter().rev().fold(base, |old, field| {
1648-
f(cx, field.span, old, field.self_expr.clone(), &field.other_selflike_exprs)
1649-
})
1654+
rest.iter().rfold(base_expr, op)
16501655
}
16511656
}
1652-
EnumNonMatchingCollapsed(tuple) => enum_nonmatch_f(cx, trait_span, tuple),
1657+
EnumNonMatchingCollapsed(tuple) => f(cx, CsFold::EnumNonMatching(trait_span, tuple)),
16531658
StaticEnum(..) | StaticStruct(..) => cx.span_bug(trait_span, "static function in `derive`"),
16541659
}
16551660
}

0 commit comments

Comments
 (0)