Skip to content

Commit 43e52e4

Browse files
committed
syntax: move functions from deriving/mod to deriving/generic.
These are now only called in generic and can be private. This includes manually inlining/merging some that are called once.
1 parent 4abd83b commit 43e52e4

File tree

2 files changed

+199
-277
lines changed

2 files changed

+199
-277
lines changed

src/libsyntax/ext/deriving/generic.rs

Lines changed: 198 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,6 @@ use ast::{enum_def, expr, ident, Generics, struct_def};
169169

170170
use ext::base::ExtCtxt;
171171
use ext::build::AstBuilder;
172-
use ext::deriving::*;
173172
use codemap::{span,respan};
174173
use opt_vec;
175174

@@ -184,18 +183,28 @@ pub fn expand_deriving_generic(cx: @ExtCtxt,
184183
_mitem: @ast::meta_item,
185184
in_items: ~[@ast::item],
186185
trait_def: &TraitDef) -> ~[@ast::item] {
187-
let expand_enum: ExpandDerivingEnumDefFn =
188-
|cx, span, enum_def, type_ident, generics| {
189-
trait_def.expand_enum_def(cx, span, enum_def, type_ident, generics)
190-
};
191-
let expand_struct: ExpandDerivingStructDefFn =
192-
|cx, span, struct_def, type_ident, generics| {
193-
trait_def.expand_struct_def(cx, span, struct_def, type_ident, generics)
194-
};
195-
196-
expand_deriving(cx, span, in_items,
197-
expand_struct,
198-
expand_enum)
186+
let mut result = ~[];
187+
for in_items.each |item| {
188+
result.push(*item);
189+
match item.node {
190+
ast::item_struct(struct_def, ref generics) => {
191+
result.push(trait_def.expand_struct_def(cx,
192+
span,
193+
struct_def,
194+
item.ident,
195+
generics));
196+
}
197+
ast::item_enum(ref enum_definition, ref generics) => {
198+
result.push(trait_def.expand_enum_def(cx,
199+
span,
200+
enum_definition,
201+
item.ident,
202+
generics));
203+
}
204+
_ => ()
205+
}
206+
}
207+
result
199208
}
200209

201210
pub struct TraitDef<'self> {
@@ -301,23 +310,71 @@ pub type EnumNonMatchFunc<'self> =
301310

302311

303312
impl<'self> TraitDef<'self> {
313+
/**
314+
*
315+
* Given that we are deriving a trait `Tr` for a type `T<'a, ...,
316+
* 'z, A, ..., Z>`, creates an impl like:
317+
*
318+
* impl<'a, ..., 'z, A:Tr B1 B2, ..., Z: Tr B1 B2> Tr for T<A, ..., Z> { ... }
319+
*
320+
* where B1, B2, ... are the bounds given by `bounds_paths`.'
321+
*
322+
*/
304323
fn create_derived_impl(&self, cx: @ExtCtxt, span: span,
305324
type_ident: ident, generics: &Generics,
306325
methods: ~[@ast::method]) -> @ast::item {
307326
let trait_path = self.path.to_path(cx, span, type_ident, generics);
308327

309-
let trait_generics = self.generics.to_generics(cx, span, type_ident, generics);
328+
let mut trait_generics = self.generics.to_generics(cx, span, type_ident, generics);
329+
// Copy the lifetimes
330+
for generics.lifetimes.each |l| {
331+
trait_generics.lifetimes.push(copy *l)
332+
};
333+
// Create the type parameters.
334+
for generics.ty_params.each |ty_param| {
335+
// I don't think this can be moved out of the loop, since
336+
// a TyParamBound requires an ast id
337+
let mut bounds = opt_vec::from(
338+
// extra restrictions on the generics parameters to the type being derived upon
339+
do self.additional_bounds.map |p| {
340+
cx.typarambound(p.to_path(cx, span, type_ident, generics))
341+
});
342+
// require the current trait
343+
bounds.push(cx.typarambound(trait_path));
344+
345+
trait_generics.ty_params.push(cx.typaram(ty_param.ident, @bounds));
346+
}
347+
348+
// Create the reference to the trait.
349+
let trait_ref = cx.trait_ref(trait_path);
310350

311-
let additional_bounds = opt_vec::from(
312-
do self.additional_bounds.map |p| {
313-
p.to_path(cx, span, type_ident, generics)
314-
});
351+
// Create the type parameters on the `self` path.
352+
let self_ty_params = do generics.ty_params.map |ty_param| {
353+
cx.ty_ident(span, ty_param.ident)
354+
};
315355

316-
create_derived_impl(cx, span,
317-
type_ident, generics,
318-
methods, trait_path,
319-
trait_generics,
320-
additional_bounds)
356+
let self_lifetime = if generics.lifetimes.is_empty() {
357+
None
358+
} else {
359+
Some(@*generics.lifetimes.get(0))
360+
};
361+
362+
// Create the type of `self`.
363+
let self_type = cx.ty_path(cx.path_all(span, false, ~[ type_ident ], self_lifetime,
364+
opt_vec::take_vec(self_ty_params)));
365+
366+
let doc_attr = cx.attribute(
367+
span,
368+
cx.meta_name_value(span,
369+
~"doc", ast::lit_str(@~"Automatically derived.")));
370+
cx.item(
371+
span,
372+
::parse::token::special_idents::clownshoes_extensions,
373+
~[doc_attr],
374+
ast::item_impl(trait_generics,
375+
Some(trait_ref),
376+
self_type,
377+
methods.map(|x| *x)))
321378
}
322379

323380
fn expand_struct_def(&self, cx: @ExtCtxt,
@@ -834,6 +891,124 @@ fn summarise_struct(cx: @ExtCtxt, span: span,
834891
}
835892
}
836893

894+
pub fn create_subpatterns(cx: @ExtCtxt,
895+
span: span,
896+
field_paths: ~[@ast::Path],
897+
mutbl: ast::mutability)
898+
-> ~[@ast::pat] {
899+
do field_paths.map |&path| {
900+
cx.pat(span, ast::pat_ident(ast::bind_by_ref(mutbl), path, None))
901+
}
902+
}
903+
904+
#[deriving(Eq)] // dogfooding!
905+
enum StructType {
906+
Unknown, Record, Tuple
907+
}
908+
909+
fn create_struct_pattern(cx: @ExtCtxt,
910+
span: span,
911+
struct_ident: ident,
912+
struct_def: &struct_def,
913+
prefix: &str,
914+
mutbl: ast::mutability)
915+
-> (@ast::pat, ~[(Option<ident>, @expr)]) {
916+
if struct_def.fields.is_empty() {
917+
return (
918+
cx.pat_ident_binding_mode(
919+
span, struct_ident, ast::bind_infer),
920+
~[]);
921+
}
922+
923+
let matching_path = cx.path(span, ~[ struct_ident ]);
924+
925+
let mut paths = ~[];
926+
let mut ident_expr = ~[];
927+
let mut struct_type = Unknown;
928+
929+
for struct_def.fields.eachi |i, struct_field| {
930+
let opt_id = match struct_field.node.kind {
931+
ast::named_field(ident, _) if (struct_type == Unknown ||
932+
struct_type == Record) => {
933+
struct_type = Record;
934+
Some(ident)
935+
}
936+
ast::unnamed_field if (struct_type == Unknown ||
937+
struct_type == Tuple) => {
938+
struct_type = Tuple;
939+
None
940+
}
941+
_ => {
942+
cx.span_bug(span, "A struct with named and unnamed fields in `deriving`");
943+
}
944+
};
945+
let path = cx.path_ident(span,
946+
cx.ident_of(fmt!("%s_%u", prefix, i)));
947+
paths.push(path);
948+
ident_expr.push((opt_id, cx.expr_path(path)));
949+
}
950+
951+
let subpats = create_subpatterns(cx, span, paths, mutbl);
952+
953+
// struct_type is definitely not Unknown, since struct_def.fields
954+
// must be nonempty to reach here
955+
let pattern = if struct_type == Record {
956+
let field_pats = do vec::build |push| {
957+
for vec::each2(subpats, ident_expr) |&pat, &(id, _)| {
958+
// id is guaranteed to be Some
959+
push(ast::field_pat { ident: id.get(), pat: pat })
960+
}
961+
};
962+
cx.pat_struct(span, matching_path, field_pats)
963+
} else {
964+
cx.pat_enum(span, matching_path, subpats)
965+
};
966+
967+
(pattern, ident_expr)
968+
}
969+
970+
fn create_enum_variant_pattern(cx: @ExtCtxt,
971+
span: span,
972+
variant: &ast::variant,
973+
prefix: &str,
974+
mutbl: ast::mutability)
975+
-> (@ast::pat, ~[(Option<ident>, @expr)]) {
976+
977+
let variant_ident = variant.node.name;
978+
match variant.node.kind {
979+
ast::tuple_variant_kind(ref variant_args) => {
980+
if variant_args.is_empty() {
981+
return (cx.pat_ident_binding_mode(
982+
span, variant_ident, ast::bind_infer), ~[]);
983+
}
984+
985+
let matching_path = cx.path_ident(span, variant_ident);
986+
987+
let mut paths = ~[];
988+
let mut ident_expr = ~[];
989+
for uint::range(0, variant_args.len()) |i| {
990+
let path = cx.path_ident(span,
991+
cx.ident_of(fmt!("%s_%u", prefix, i)));
992+
993+
paths.push(path);
994+
ident_expr.push((None, cx.expr_path(path)));
995+
}
996+
997+
let subpats = create_subpatterns(cx, span, paths, mutbl);
998+
999+
(cx.pat_enum(span, matching_path, subpats),
1000+
ident_expr)
1001+
}
1002+
ast::struct_variant_kind(struct_def) => {
1003+
create_struct_pattern(cx, span,
1004+
variant_ident, struct_def,
1005+
prefix,
1006+
mutbl)
1007+
}
1008+
}
1009+
}
1010+
1011+
8371012

8381013
/* helpful premade recipes */
8391014

0 commit comments

Comments
 (0)