Skip to content

Commit 7906c55

Browse files
committed
libsyntax: derive Clone, Eq, TotalEq, Ord, TotalOrd with the new generic deriving code.
Closes #4269, #5588 and #5589.
1 parent 85b82c7 commit 7906c55

File tree

7 files changed

+411
-761
lines changed

7 files changed

+411
-761
lines changed

src/libsyntax/ext/deriving/clone.rs

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

11-
use core::prelude::*;
12-
13-
use ast;
14-
use ast::*;
11+
use ast::{meta_item, item, expr};
12+
use codemap::span;
1513
use ext::base::ext_ctxt;
1614
use ext::build;
17-
use ext::deriving::*;
18-
use codemap::{span, spanned};
19-
use ast_util;
20-
use opt_vec;
15+
use ext::deriving::generic::*;
16+
use core::option::{None,Some};
2117

22-
use core::uint;
2318

2419
pub fn expand_deriving_clone(cx: @ext_ctxt,
2520
span: span,
26-
_: @meta_item,
21+
mitem: @meta_item,
2722
in_items: ~[@item])
2823
-> ~[@item] {
29-
expand_deriving(cx,
30-
span,
31-
in_items,
32-
expand_deriving_clone_struct_def,
33-
expand_deriving_clone_enum_def)
24+
let trait_def = TraitDef {
25+
path: ~[~"core", ~"clone", ~"Clone"],
26+
additional_bounds: ~[],
27+
methods: ~[
28+
MethodDef {
29+
name: ~"clone",
30+
nargs: 0,
31+
output_type: None, // return Self
32+
combine_substructure: cs_clone
33+
}
34+
]
35+
};
36+
37+
expand_deriving_generic(cx, span,
38+
mitem, in_items,
39+
&trait_def)
3440
}
3541

3642
pub fn expand_deriving_obsolete(cx: @ext_ctxt,
@@ -42,252 +48,52 @@ pub fn expand_deriving_obsolete(cx: @ext_ctxt,
4248
in_items
4349
}
4450

45-
fn create_derived_clone_impl(cx: @ext_ctxt,
46-
span: span,
47-
type_ident: ident,
48-
generics: &Generics,
49-
method: @method)
50-
-> @item {
51-
let methods = [ method ];
52-
let trait_path = ~[
53-
cx.ident_of(~"core"),
54-
cx.ident_of(~"clone"),
55-
cx.ident_of(~"Clone"),
56-
];
57-
let trait_path = build::mk_raw_path_global(span, trait_path);
58-
create_derived_impl(cx, span, type_ident, generics, methods, trait_path,
59-
opt_vec::Empty, opt_vec::Empty)
60-
}
61-
// Creates a method from the given expression conforming to the signature of
62-
// the `clone` method.
63-
fn create_clone_method(cx: @ext_ctxt,
64-
span: span,
65-
+type_ident: ast::ident,
66-
generics: &Generics,
67-
expr: @ast::expr)
68-
-> @method {
69-
// Create the type parameters of the return value.
70-
let mut output_ty_params = ~[];
71-
for generics.ty_params.each |ty_param| {
72-
let path = build::mk_ty_path(cx, span, ~[ ty_param.ident ]);
73-
output_ty_params.push(path);
74-
}
75-
76-
// Create the type of the return value.
77-
let output_type_path = build::mk_raw_path_(span,
78-
~[ type_ident ],
79-
output_ty_params);
80-
let output_type = ast::ty_path(output_type_path, cx.next_id());
81-
let output_type = @ast::Ty {
82-
id: cx.next_id(),
83-
node: output_type,
84-
span: span
85-
};
86-
87-
// Create the function declaration.
88-
let fn_decl = build::mk_fn_decl(~[], output_type);
89-
90-
// Create the body block.
91-
let body_block = build::mk_simple_block(cx, span, expr);
92-
93-
// Create the self type and method identifier.
94-
let self_ty = spanned { node: sty_region(None, m_imm), span: span };
95-
let method_ident = cx.ident_of(~"clone");
96-
97-
// Create the method.
98-
@ast::method {
99-
ident: method_ident,
100-
attrs: ~[],
101-
generics: ast_util::empty_generics(),
102-
self_ty: self_ty,
103-
purity: impure_fn,
104-
decl: fn_decl,
105-
body: body_block,
106-
id: cx.next_id(),
107-
span: span,
108-
self_id: cx.next_id(),
109-
vis: public,
51+
fn cs_clone(cx: @ext_ctxt, span: span,
52+
substr: &Substructure) -> @expr {
53+
let clone_ident = substr.method_ident;
54+
let ctor_ident;
55+
let all_fields;
56+
let subcall = |field|
57+
build::mk_method_call(cx, span, field, clone_ident, ~[]);
58+
59+
match *substr.fields {
60+
Struct(af) => {
61+
ctor_ident = ~[ substr.type_ident ];
62+
all_fields = af;
63+
}
64+
EnumMatching(_, variant, af) => {
65+
ctor_ident = ~[ variant.node.name ];
66+
all_fields = af;
67+
},
68+
EnumNonMatching(*) => cx.bug("Non-matching enum variants in `deriving(Clone)`")
11069
}
111-
}
112-
113-
fn call_substructure_clone_method(cx: @ext_ctxt,
114-
span: span,
115-
self_field: @expr)
116-
-> @expr {
117-
// Call the substructure method.
118-
let clone_ident = cx.ident_of(~"clone");
119-
build::mk_method_call(cx, span,
120-
self_field, clone_ident,
121-
~[])
122-
}
123-
124-
fn expand_deriving_clone_struct_def(cx: @ext_ctxt,
125-
span: span,
126-
struct_def: &struct_def,
127-
type_ident: ident,
128-
generics: &Generics)
129-
-> @item {
130-
// Create the method.
131-
let method = if !is_struct_tuple(struct_def) {
132-
expand_deriving_clone_struct_method(cx,
133-
span,
134-
struct_def,
135-
type_ident,
136-
generics)
137-
} else {
138-
expand_deriving_clone_tuple_struct_method(cx,
139-
span,
140-
struct_def,
141-
type_ident,
142-
generics)
143-
};
144-
145-
// Create the implementation.
146-
create_derived_clone_impl(cx, span, type_ident, generics, method)
147-
}
148-
149-
fn expand_deriving_clone_enum_def(cx: @ext_ctxt,
150-
span: span,
151-
enum_definition: &enum_def,
152-
type_ident: ident,
153-
generics: &Generics)
154-
-> @item {
155-
// Create the method.
156-
let method = expand_deriving_clone_enum_method(cx,
157-
span,
158-
enum_definition,
159-
type_ident,
160-
generics);
161-
162-
// Create the implementation.
163-
create_derived_clone_impl(cx, span, type_ident, generics, method)
164-
}
165-
166-
fn expand_deriving_clone_struct_method(cx: @ext_ctxt,
167-
span: span,
168-
struct_def: &struct_def,
169-
type_ident: ident,
170-
generics: &Generics)
171-
-> @method {
172-
let self_ident = cx.ident_of(~"self");
173-
174-
// Create the new fields.
175-
let mut fields = ~[];
176-
for struct_def.fields.each |struct_field| {
177-
match struct_field.node.kind {
178-
named_field(ident, _, _) => {
179-
// Create the accessor for this field.
180-
let self_field = build::mk_access(cx,
181-
span,
182-
~[ self_ident ],
183-
ident);
18470

185-
// Call the substructure method.
186-
let call = call_substructure_clone_method(cx,
187-
span,
188-
self_field);
189-
190-
let field = build::Field { ident: ident, ex: call };
191-
fields.push(field);
192-
}
193-
unnamed_field => {
194-
cx.span_bug(span, ~"unnamed fields in `deriving(Clone)`");
71+
match all_fields {
72+
[(None, _, _), .. _] => {
73+
// enum-like
74+
let subcalls = all_fields.map(|&(_, self_f, _)| subcall(self_f));
75+
build::mk_call(cx, span, ctor_ident, subcalls)
76+
},
77+
_ => {
78+
// struct-like
79+
let fields = do all_fields.map |&(o_id, self_f, _)| {
80+
let ident = match o_id {
81+
Some(i) => i,
82+
None => cx.span_bug(span,
83+
~"unnamed field in normal struct \
84+
in `deriving(Clone)`")
85+
};
86+
build::Field { ident: ident, ex: subcall(self_f) }
87+
};
88+
89+
if fields.is_empty() {
90+
// no fields, so construct like `None`
91+
build::mk_path(cx, span, ctor_ident)
92+
} else {
93+
build::mk_struct_e(cx, span,
94+
ctor_ident,
95+
fields)
19596
}
19697
}
19798
}
198-
199-
// Create the struct literal.
200-
let struct_literal = build::mk_struct_e(cx,
201-
span,
202-
~[ type_ident ],
203-
fields);
204-
create_clone_method(cx, span, type_ident, generics, struct_literal)
205-
}
206-
207-
fn expand_deriving_clone_tuple_struct_method(cx: @ext_ctxt,
208-
span: span,
209-
struct_def: &struct_def,
210-
type_ident: ident,
211-
generics: &Generics)
212-
-> @method {
213-
// Create the pattern for the match.
214-
let matching_path = build::mk_raw_path(span, ~[ type_ident ]);
215-
let field_count = struct_def.fields.len();
216-
let subpats = create_subpatterns(cx, span, ~"__self", field_count);
217-
let pat = build::mk_pat_enum(cx, span, matching_path, subpats);
218-
219-
// Create the new fields.
220-
let mut subcalls = ~[];
221-
for uint::range(0, struct_def.fields.len()) |i| {
222-
// Create the expression for this field.
223-
let field_ident = cx.ident_of(~"__self_" + i.to_str());
224-
let field = build::mk_path(cx, span, ~[ field_ident ]);
225-
226-
// Call the substructure method.
227-
let subcall = call_substructure_clone_method(cx, span, field);
228-
subcalls.push(subcall);
229-
}
230-
231-
// Create the call to the struct constructor.
232-
let call = build::mk_call(cx, span, ~[ type_ident ], subcalls);
233-
234-
// Create the pattern body.
235-
let match_body_block = build::mk_simple_block(cx, span, call);
236-
237-
// Create the arm.
238-
let arm = ast::arm {
239-
pats: ~[ pat ],
240-
guard: None,
241-
body: match_body_block
242-
};
243-
244-
// Create the method body.
245-
let self_match_expr = expand_enum_or_struct_match(cx, span, ~[ arm ]);
246-
247-
// Create the method.
248-
create_clone_method(cx, span, type_ident, generics, self_match_expr)
249-
}
250-
251-
fn expand_deriving_clone_enum_method(cx: @ext_ctxt,
252-
span: span,
253-
enum_definition: &enum_def,
254-
type_ident: ident,
255-
generics: &Generics)
256-
-> @method {
257-
// Create the arms of the match in the method body.
258-
let arms = do enum_definition.variants.map |variant| {
259-
// Create the matching pattern.
260-
let pat = create_enum_variant_pattern(cx, span, variant, ~"__self");
261-
262-
// Iterate over the variant arguments, creating the subcalls.
263-
let mut subcalls = ~[];
264-
for uint::range(0, variant_arg_count(cx, span, variant)) |j| {
265-
// Create the expression for this field.
266-
let field_ident = cx.ident_of(~"__self_" + j.to_str());
267-
let field = build::mk_path(cx, span, ~[ field_ident ]);
268-
269-
// Call the substructure method.
270-
let subcall = call_substructure_clone_method(cx, span, field);
271-
subcalls.push(subcall);
272-
}
273-
274-
// Create the call to the enum variant (if necessary).
275-
let call = if subcalls.len() > 0 {
276-
build::mk_call(cx, span, ~[ variant.node.name ], subcalls)
277-
} else {
278-
build::mk_path(cx, span, ~[ variant.node.name ])
279-
};
280-
281-
// Create the pattern body.
282-
let match_body_block = build::mk_simple_block(cx, span, call);
283-
284-
// Create the arm.
285-
ast::arm { pats: ~[ pat ], guard: None, body: match_body_block }
286-
};
287-
288-
// Create the method body.
289-
let self_match_expr = expand_enum_or_struct_match(cx, span, arms);
290-
291-
// Create the method.
292-
create_clone_method(cx, span, type_ident, generics, self_match_expr)
29399
}

0 commit comments

Comments
 (0)