Skip to content

Commit b20eb97

Browse files
committed
libsyntax: extend generic deriving code to handle almost all possible traits.
This adds support for static methods, and arguments of most types, traits with type parameters, methods with type parameters (and lifetimes for both), as well as making the code more robust to support deriving on types with lifetimes (i.e. 'self).
1 parent 6e6a4be commit b20eb97

File tree

11 files changed

+936
-554
lines changed

11 files changed

+936
-554
lines changed

src/libsyntax/ext/build.rs

Lines changed: 59 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -54,43 +54,52 @@ pub fn mk_binary(cx: @ext_ctxt, sp: span, op: ast::binop,
5454
cx.next_id(); // see ast_util::op_expr_callee_id
5555
mk_expr(cx, sp, ast::expr_binary(op, lhs, rhs))
5656
}
57+
58+
pub fn mk_deref(cx: @ext_ctxt, sp: span, e: @ast::expr) -> @ast::expr {
59+
mk_unary(cx, sp, ast::deref, e)
60+
}
5761
pub fn mk_unary(cx: @ext_ctxt, sp: span, op: ast::unop, e: @ast::expr)
5862
-> @ast::expr {
5963
cx.next_id(); // see ast_util::op_expr_callee_id
6064
mk_expr(cx, sp, ast::expr_unary(op, e))
6165
}
6266
pub fn mk_raw_path(sp: span, idents: ~[ast::ident]) -> @ast::Path {
63-
mk_raw_path_(sp, idents, ~[])
67+
mk_raw_path_(sp, idents, None, ~[])
6468
}
6569
pub fn mk_raw_path_(sp: span,
6670
idents: ~[ast::ident],
71+
rp: Option<@ast::Lifetime>,
6772
types: ~[@ast::Ty])
6873
-> @ast::Path {
6974
@ast::Path { span: sp,
7075
global: false,
7176
idents: idents,
72-
rp: None,
77+
rp: rp,
7378
types: types }
7479
}
7580
pub fn mk_raw_path_global(sp: span, idents: ~[ast::ident]) -> @ast::Path {
76-
mk_raw_path_global_(sp, idents, ~[])
81+
mk_raw_path_global_(sp, idents, None, ~[])
7782
}
7883
pub fn mk_raw_path_global_(sp: span,
7984
idents: ~[ast::ident],
85+
rp: Option<@ast::Lifetime>,
8086
types: ~[@ast::Ty]) -> @ast::Path {
8187
@ast::Path { span: sp,
8288
global: true,
8389
idents: idents,
84-
rp: None,
90+
rp: rp,
8591
types: types }
8692
}
93+
pub fn mk_path_raw(cx: @ext_ctxt, sp: span, path: @ast::Path)-> @ast::expr {
94+
mk_expr(cx, sp, ast::expr_path(path))
95+
}
8796
pub fn mk_path(cx: @ext_ctxt, sp: span, idents: ~[ast::ident])
8897
-> @ast::expr {
89-
mk_expr(cx, sp, ast::expr_path(mk_raw_path(sp, idents)))
98+
mk_path_raw(cx, sp, mk_raw_path(sp, idents))
9099
}
91100
pub fn mk_path_global(cx: @ext_ctxt, sp: span, idents: ~[ast::ident])
92101
-> @ast::expr {
93-
mk_expr(cx, sp, ast::expr_path(mk_raw_path_global(sp, idents)))
102+
mk_path_raw(cx, sp, mk_raw_path_global(sp, idents))
94103
}
95104
pub fn mk_access_(cx: @ext_ctxt, sp: span, p: @ast::expr, m: ast::ident)
96105
-> @ast::expr {
@@ -354,44 +363,69 @@ pub fn mk_stmt(cx: @ext_ctxt, span: span, expr: @ast::expr) -> @ast::stmt {
354363
let stmt_ = ast::stmt_semi(expr, cx.next_id());
355364
@codemap::spanned { node: stmt_, span: span }
356365
}
366+
367+
pub fn mk_ty_mt(ty: @ast::Ty, mutbl: ast::mutability) -> ast::mt {
368+
ast::mt {
369+
ty: ty,
370+
mutbl: mutbl
371+
}
372+
}
373+
374+
pub fn mk_ty(cx: @ext_ctxt,
375+
span: span,
376+
ty: ast::ty_) -> @ast::Ty {
377+
@ast::Ty {
378+
id: cx.next_id(),
379+
span: span,
380+
node: ty
381+
}
382+
}
383+
357384
pub fn mk_ty_path(cx: @ext_ctxt,
358385
span: span,
359386
idents: ~[ ast::ident ])
360387
-> @ast::Ty {
361388
let ty = build::mk_raw_path(span, idents);
362-
let ty = ast::ty_path(ty, cx.next_id());
363-
let ty = @ast::Ty { id: cx.next_id(), node: ty, span: span };
364-
ty
389+
mk_ty_path_path(cx, span, ty)
365390
}
391+
366392
pub fn mk_ty_path_global(cx: @ext_ctxt,
367393
span: span,
368394
idents: ~[ ast::ident ])
369395
-> @ast::Ty {
370396
let ty = build::mk_raw_path_global(span, idents);
371-
let ty = ast::ty_path(ty, cx.next_id());
372-
let ty = @ast::Ty { id: cx.next_id(), node: ty, span: span };
373-
ty
397+
mk_ty_path_path(cx, span, ty)
374398
}
399+
400+
pub fn mk_ty_path_path(cx: @ext_ctxt,
401+
span: span,
402+
path: @ast::Path)
403+
-> @ast::Ty {
404+
let ty = ast::ty_path(path, cx.next_id());
405+
mk_ty(cx, span, ty)
406+
}
407+
375408
pub fn mk_ty_rptr(cx: @ext_ctxt,
376409
span: span,
377410
ty: @ast::Ty,
411+
lifetime: Option<@ast::Lifetime>,
378412
mutbl: ast::mutability)
379413
-> @ast::Ty {
380-
@ast::Ty {
381-
id: cx.next_id(),
382-
span: span,
383-
node: ast::ty_rptr(
384-
None,
385-
ast::mt { ty: ty, mutbl: mutbl }
386-
),
387-
}
414+
mk_ty(cx, span,
415+
ast::ty_rptr(lifetime, mk_ty_mt(ty, mutbl)))
416+
}
417+
pub fn mk_ty_uniq(cx: @ext_ctxt, span: span, ty: @ast::Ty) -> @ast::Ty {
418+
mk_ty(cx, span, ast::ty_uniq(mk_ty_mt(ty, ast::m_imm)))
388419
}
420+
pub fn mk_ty_box(cx: @ext_ctxt, span: span,
421+
ty: @ast::Ty, mutbl: ast::mutability) -> @ast::Ty {
422+
mk_ty(cx, span, ast::ty_box(mk_ty_mt(ty, mutbl)))
423+
}
424+
425+
426+
389427
pub fn mk_ty_infer(cx: @ext_ctxt, span: span) -> @ast::Ty {
390-
@ast::Ty {
391-
id: cx.next_id(),
392-
node: ast::ty_infer,
393-
span: span,
394-
}
428+
mk_ty(cx, span, ast::ty_infer)
395429
}
396430
pub fn mk_trait_ref_global(cx: @ext_ctxt,
397431
span: span,

src/libsyntax/ext/deriving/clone.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ use codemap::span;
1313
use ext::base::ext_ctxt;
1414
use ext::build;
1515
use ext::deriving::generic::*;
16-
use core::option::{None,Some};
1716

1817

1918
pub fn expand_deriving_clone(cx: @ext_ctxt,
@@ -22,13 +21,16 @@ pub fn expand_deriving_clone(cx: @ext_ctxt,
2221
in_items: ~[@item])
2322
-> ~[@item] {
2423
let trait_def = TraitDef {
25-
path: ~[~"core", ~"clone", ~"Clone"],
24+
path: Path::new(~[~"core", ~"clone", ~"Clone"]),
2625
additional_bounds: ~[],
26+
generics: LifetimeBounds::empty(),
2727
methods: ~[
2828
MethodDef {
2929
name: ~"clone",
30-
nargs: 0,
31-
output_type: None, // return Self
30+
generics: LifetimeBounds::empty(),
31+
self_ty: borrowed_explicit_self(),
32+
args: ~[],
33+
ret_ty: Self,
3234
const_nonmatching: false,
3335
combine_substructure: cs_clone
3436
}
@@ -66,7 +68,8 @@ fn cs_clone(cx: @ext_ctxt, span: span,
6668
ctor_ident = ~[ variant.node.name ];
6769
all_fields = af;
6870
},
69-
EnumNonMatching(*) => cx.bug("Non-matching enum variants in `deriving(Clone)`")
71+
EnumNonMatching(*) => cx.span_bug(span, "Non-matching enum variants in `deriving(Clone)`"),
72+
StaticEnum(*) | StaticStruct(*) => cx.span_bug(span, "Static method in `deriving(Clone)`")
7073
}
7174

7275
match all_fields {

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

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,44 +8,45 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
1211
use ast::{meta_item, item, expr};
1312
use codemap::span;
1413
use ext::base::ext_ctxt;
1514
use ext::build;
1615
use ext::deriving::generic::*;
1716

18-
use core::option::Some;
19-
2017
pub fn expand_deriving_eq(cx: @ext_ctxt,
2118
span: span,
2219
mitem: @meta_item,
2320
in_items: ~[@item]) -> ~[@item] {
2421
// structures are equal if all fields are equal, and non equal, if
2522
// any fields are not equal or if the enum variants are different
2623
fn cs_eq(cx: @ext_ctxt, span: span, substr: &Substructure) -> @expr {
27-
cs_and(|cx, span, _| build::mk_bool(cx, span, false),
24+
cs_and(|cx, span, _, _| build::mk_bool(cx, span, false),
2825
cx, span, substr)
2926
}
3027
fn cs_ne(cx: @ext_ctxt, span: span, substr: &Substructure) -> @expr {
31-
cs_or(|cx, span, _| build::mk_bool(cx, span, true),
28+
cs_or(|cx, span, _, _| build::mk_bool(cx, span, true),
3229
cx, span, substr)
3330
}
31+
3432
macro_rules! md (
3533
($name:expr, $f:ident) => {
3634
MethodDef {
3735
name: $name,
38-
output_type: Some(~[~"bool"]),
39-
nargs: 1,
36+
generics: LifetimeBounds::empty(),
37+
self_ty: borrowed_explicit_self(),
38+
args: ~[borrowed_self()],
39+
ret_ty: Literal(Path::new(~[~"bool"])),
4040
const_nonmatching: true,
4141
combine_substructure: $f
4242
},
4343
}
44-
)
44+
);
4545

4646
let trait_def = TraitDef {
47-
path: ~[~"core", ~"cmp", ~"Eq"],
47+
path: Path::new(~[~"core", ~"cmp", ~"Eq"]),
4848
additional_bounds: ~[],
49+
generics: LifetimeBounds::empty(),
4950
methods: ~[
5051
md!(~"eq", cs_eq),
5152
md!(~"ne", cs_ne)

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

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,29 +14,33 @@ use codemap::span;
1414
use ext::base::ext_ctxt;
1515
use ext::build;
1616
use ext::deriving::generic::*;
17-
use core::option::Some;
18-
19-
macro_rules! md {
20-
($name:expr, $less:expr, $equal:expr) => {
21-
MethodDef {
22-
name: $name,
23-
output_type: Some(~[~"bool"]),
24-
nargs: 1,
25-
const_nonmatching: false,
26-
combine_substructure: |cx, span, substr|
27-
cs_ord($less, $equal, cx, span, substr)
28-
}
29-
}
30-
}
3117

3218
pub fn expand_deriving_ord(cx: @ext_ctxt,
3319
span: span,
3420
mitem: @meta_item,
3521
in_items: ~[@item]) -> ~[@item] {
22+
macro_rules! md (
23+
($name:expr, $less:expr, $equal:expr) => {
24+
MethodDef {
25+
name: $name,
26+
generics: LifetimeBounds::empty(),
27+
self_ty: borrowed_explicit_self(),
28+
args: ~[borrowed_self()],
29+
ret_ty: Literal(Path::new(~[~"bool"])),
30+
const_nonmatching: false,
31+
combine_substructure: |cx, span, substr|
32+
cs_ord($less, $equal, cx, span, substr)
33+
}
34+
}
35+
);
36+
37+
38+
3639
let trait_def = TraitDef {
37-
path: ~[~"core", ~"cmp", ~"Ord"],
40+
path: Path::new(~[~"core", ~"cmp", ~"Ord"]),
3841
// XXX: Ord doesn't imply Eq yet
39-
additional_bounds: ~[~[~"core", ~"cmp", ~"Eq"]],
42+
additional_bounds: ~[Literal(Path::new(~[~"core", ~"cmp", ~"Eq"]))],
43+
generics: LifetimeBounds::empty(),
4044
methods: ~[
4145
md!(~"lt", true, false),
4246
md!(~"le", true, true),
@@ -97,19 +101,19 @@ fn cs_ord(less: bool, equal: bool,
97101
}
98102

99103
let cmp = build::mk_method_call(cx, span,
100-
self_f, cx.ident_of(~"eq"), other_fs);
104+
self_f, cx.ident_of(~"eq"), other_fs.to_owned());
101105
let subexpr = build::mk_simple_block(cx, span, subexpr);
102106
let elseif = expr_if(cmp, subexpr, Some(false_blk_expr));
103107
let elseif = build::mk_expr(cx, span, elseif);
104108
105109
let cmp = build::mk_method_call(cx, span,
106-
self_f, binop, other_fs);
110+
self_f, binop, other_fs.to_owned());
107111
let if_ = expr_if(cmp, true_blk, Some(elseif));
108112
109113
build::mk_expr(cx, span, if_)
110114
},
111115
base,
112-
|cx, span, args| {
116+
|cx, span, args, _| {
113117
// nonmatching enums, order by the order the variants are
114118
// written
115119
match args {

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

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,27 @@ use ext::base::ext_ctxt;
1515
use ext::build;
1616
use ext::deriving::generic::*;
1717

18-
use core::option::Some;
19-
2018
pub fn expand_deriving_totaleq(cx: @ext_ctxt,
2119
span: span,
2220
mitem: @meta_item,
2321
in_items: ~[@item]) -> ~[@item] {
2422

2523
fn cs_equals(cx: @ext_ctxt, span: span, substr: &Substructure) -> @expr {
26-
cs_and(|cx, span, _| build::mk_bool(cx, span, false),
24+
cs_and(|cx, span, _, _| build::mk_bool(cx, span, false),
2725
cx, span, substr)
2826
}
2927

3028
let trait_def = TraitDef {
31-
path: ~[~"core", ~"cmp", ~"TotalEq"],
29+
path: Path::new(~[~"core", ~"cmp", ~"TotalEq"]),
3230
additional_bounds: ~[],
31+
generics: LifetimeBounds::empty(),
3332
methods: ~[
3433
MethodDef {
3534
name: ~"equals",
36-
output_type: Some(~[~"bool"]),
37-
nargs: 1,
35+
generics: LifetimeBounds::empty(),
36+
self_ty: borrowed_explicit_self(),
37+
args: ~[borrowed_self()],
38+
ret_ty: Literal(Path::new(~[~"bool"])),
3839
const_nonmatching: true,
3940
combine_substructure: cs_equals
4041
}

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

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,22 @@ use ext::base::ext_ctxt;
1414
use ext::build;
1515
use ext::deriving::generic::*;
1616
use core::cmp::{Ordering, Equal, Less, Greater};
17-
use core::option::Some;
1817

1918
pub fn expand_deriving_totalord(cx: @ext_ctxt,
2019
span: span,
2120
mitem: @meta_item,
2221
in_items: ~[@item]) -> ~[@item] {
2322
let trait_def = TraitDef {
24-
path: ~[~"core", ~"cmp", ~"TotalOrd"],
23+
path: Path::new(~[~"core", ~"cmp", ~"TotalOrd"]),
2524
additional_bounds: ~[],
25+
generics: LifetimeBounds::empty(),
2626
methods: ~[
2727
MethodDef {
2828
name: ~"cmp",
29-
output_type: Some(~[~"core", ~"cmp", ~"Ordering"]),
30-
nargs: 1,
29+
generics: LifetimeBounds::empty(),
30+
self_ty: borrowed_explicit_self(),
31+
args: ~[borrowed_self()],
32+
ret_ty: Literal(Path::new(~[~"core", ~"cmp", ~"Ordering"])),
3133
const_nonmatching: false,
3234
combine_substructure: cs_cmp
3335
}
@@ -64,7 +66,7 @@ pub fn cs_cmp(cx: @ext_ctxt, span: span,
6466
build::mk_call_global(cx, span, lexical_ord, ~[old, new])
6567
},
6668
ordering_const(cx, span, Equal),
67-
|cx, span, list| {
69+
|cx, span, list, _| {
6870
match list {
6971
// an earlier nonmatching variant is Less than a
7072
// later one

0 commit comments

Comments
 (0)