Skip to content

Commit c8ae446

Browse files
committed
O(n*k) code-size deriving on enums (better than previous O(n^k)).
In the above formulas, `n` is the number of variants, and `k` is the number of self-args fed into deriving. In the particular case of interest (namely `PartialOrd` and `Ord`), `k` is always 2, so we are basically comparing `O(n)` versus `O(n^2)`. Also, the stage is set for having *all* enum deriving codes go through `build_enum_match_tuple` and getting rid of `build_enum_match`. Also, seriously attempted to clean up the code itself. Added a bunch of comments attempting to document what I learned as I worked through the original code and adapted it to this new strategy.
1 parent 5d1bdc3 commit c8ae446

File tree

8 files changed

+455
-43
lines changed

8 files changed

+455
-43
lines changed

src/libsyntax/ext/deriving/clone.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ fn cs_clone(
6969
ctor_ident = variant.node.name;
7070
all_fields = af;
7171
},
72-
EnumNonMatching(..) => {
72+
EnumNonMatching(..) | EnumNonMatchingCollapsed (..) => {
7373
cx.span_bug(trait_span,
7474
format!("non-matching enum variants in \
7575
`deriving({})`",

src/libsyntax/ext/deriving/cmp/eq.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,12 @@ pub fn expand_deriving_eq(cx: &mut ExtCtxt,
2727
// any fields are not equal or if the enum variants are different
2828
fn cs_eq(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> Gc<Expr> {
2929
cs_and(|cx, span, _, _| cx.expr_bool(span, false),
30-
cx, span, substr)
30+
|cx, span, _, _| cx.expr_bool(span, false),
31+
cx, span, substr)
3132
}
3233
fn cs_ne(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> Gc<Expr> {
3334
cs_or(|cx, span, _, _| cx.expr_bool(span, true),
35+
|cx, span, _, _| cx.expr_bool(span, true),
3436
cx, span, substr)
3537
}
3638

src/libsyntax/ext/deriving/cmp/ord.rs

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ pub fn expand_deriving_ord(cx: &mut ExtCtxt,
3535
args: vec!(borrowed_self()),
3636
ret_ty: Literal(Path::new(vec!("bool"))),
3737
attributes: attrs,
38-
on_nonmatching: NonMatchesExplode,
38+
on_nonmatching: NonMatchesCollapseWithTags,
3939
combine_substructure: combine_substructure(|cx, span, substr| {
4040
cs_op($op, $equal, cx, span, substr)
4141
})
@@ -59,7 +59,7 @@ pub fn expand_deriving_ord(cx: &mut ExtCtxt,
5959
args: vec![borrowed_self()],
6060
ret_ty: ret_ty,
6161
attributes: attrs,
62-
on_nonmatching: NonMatchesExplode,
62+
on_nonmatching: NonMatchesCollapseWithTags,
6363
combine_substructure: combine_substructure(|cx, span, substr| {
6464
cs_partial_cmp(cx, span, substr)
6565
})
@@ -96,6 +96,24 @@ pub fn some_ordering_const(cx: &mut ExtCtxt, span: Span, cnst: Ordering) -> Gc<a
9696
cx.expr_some(span, ordering)
9797
}
9898

99+
pub enum OrderingOp {
100+
PartialCmpOp, LtOp, LeOp, GtOp, GeOp,
101+
}
102+
103+
pub fn some_ordering_collapsed(cx: &mut ExtCtxt,
104+
span: Span,
105+
op: OrderingOp,
106+
self_arg_tags: &[ast::Ident]) -> Gc<ast::Expr> {
107+
let lft = cx.expr_ident(span, self_arg_tags[0]);
108+
let rgt = cx.expr_addr_of(span, cx.expr_ident(span, self_arg_tags[1]));
109+
let op_str = match op {
110+
PartialCmpOp => "partial_cmp",
111+
LtOp => "lt", LeOp => "le",
112+
GtOp => "gt", GeOp => "ge",
113+
};
114+
cx.expr_method_call(span, lft, cx.ident_of(op_str), vec![rgt])
115+
}
116+
99117
pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span,
100118
substr: &Substructure) -> Gc<Expr> {
101119
let test_id = cx.ident_of("__test");
@@ -147,7 +165,14 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span,
147165
// later one.
148166
[(self_var, _, _), (other_var, _, _)] =>
149167
some_ordering_const(cx, span, self_var.cmp(&other_var)),
150-
_ => cx.span_bug(span, "not exactly 2 arguments in `deriving(Ord)`")
168+
_ => cx.span_bug(span, "not exactly 2 arguments in `deriving(Ord)`"),
169+
}
170+
},
171+
|cx, span, (self_args, tag_tuple), _non_self_args| {
172+
if self_args.len() != 2 {
173+
cx.span_bug(span, "not exactly 2 arguments in `deriving(Ord)`")
174+
} else {
175+
some_ordering_collapsed(cx, span, PartialCmpOp, tag_tuple)
151176
}
152177
},
153178
cx, span, substr)
@@ -206,5 +231,16 @@ fn cs_op(less: bool, equal: bool, cx: &mut ExtCtxt, span: Span,
206231
_ => cx.span_bug(span, "not exactly 2 arguments in `deriving(Ord)`")
207232
}
208233
},
234+
|cx, span, (self_args, tag_tuple), _non_self_args| {
235+
if self_args.len() != 2 {
236+
cx.span_bug(span, "not exactly 2 arguments in `deriving(Ord)`")
237+
} else {
238+
let op = match (less, equal) {
239+
(true, true) => LeOp, (true, false) => LtOp,
240+
(false, true) => GeOp, (false, false) => GtOp,
241+
};
242+
some_ordering_collapsed(cx, span, op, tag_tuple)
243+
}
244+
},
209245
cx, span, substr)
210246
}

src/libsyntax/ext/deriving/cmp/totaleq.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ pub fn expand_deriving_totaleq(cx: &mut ExtCtxt,
3232
let block = cx.block(span, stmts, None);
3333
cx.expr_block(block)
3434
},
35+
|cx, sp, _, _| cx.span_bug(sp, "non matching enums in deriving(Eq)?"),
3536
|cx, sp, _, _| cx.span_bug(sp, "non matching enums in deriving(Eq)?"),
3637
cx,
3738
span,

src/libsyntax/ext/deriving/cmp/totalord.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ pub fn expand_deriving_totalord(cx: &mut ExtCtxt,
4141
args: vec!(borrowed_self()),
4242
ret_ty: Literal(Path::new(vec!("std", "cmp", "Ordering"))),
4343
attributes: attrs,
44-
on_nonmatching: NonMatchesExplode,
44+
on_nonmatching: NonMatchesCollapseWithTags,
4545
combine_substructure: combine_substructure(|a, b, c| {
4646
cs_cmp(a, b, c)
4747
}),
@@ -65,6 +65,14 @@ pub fn ordering_const(cx: &mut ExtCtxt, span: Span, cnst: Ordering) -> ast::Path
6565
cx.ident_of(cnst)))
6666
}
6767

68+
pub fn ordering_collapsed(cx: &mut ExtCtxt,
69+
span: Span,
70+
self_arg_tags: &[ast::Ident]) -> Gc<ast::Expr> {
71+
let lft = cx.expr_ident(span, self_arg_tags[0]);
72+
let rgt = cx.expr_addr_of(span, cx.expr_ident(span, self_arg_tags[1]));
73+
cx.expr_method_call(span, lft, cx.ident_of("cmp"), vec![rgt])
74+
}
75+
6876
pub fn cs_cmp(cx: &mut ExtCtxt, span: Span,
6977
substr: &Substructure) -> Gc<Expr> {
7078
let test_id = cx.ident_of("__test");
@@ -122,5 +130,12 @@ pub fn cs_cmp(cx: &mut ExtCtxt, span: Span,
122130
_ => cx.span_bug(span, "not exactly 2 arguments in `deriving(Ord)`")
123131
}
124132
},
133+
|cx, span, (self_args, tag_tuple), _non_self_args| {
134+
if self_args.len() != 2 {
135+
cx.span_bug(span, "not exactly 2 arguments in `deriving(TotalOrd)`")
136+
} else {
137+
ordering_collapsed(cx, span, tag_tuple)
138+
}
139+
},
125140
cx, span, substr)
126141
}

0 commit comments

Comments
 (0)