1 // Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! Some code that abstracts away much of the boilerplate of writing
12 //! `deriving` instances for traits. Among other things it manages getting
13 //! access to the fields of the 4 different sorts of structs and enum
14 //! variants, as well as creating the method and impl ast instances.
16 //! Supported features (fairly exhaustive):
18 //! - Methods taking any number of parameters of any type, and returning
19 //! any type, other than vectors, bottom and closures.
20 //! - Generating `impl`s for types with type parameters and lifetimes
21 //! (e.g. `Option<T>`), the parameters are automatically given the
22 //! current trait as a bound. (This includes separate type parameters
23 //! and lifetimes for methods.)
24 //! - Additional bounds on the type parameters, e.g. the `Ord` instance
25 //! requires an explicit `PartialEq` bound at the
26 //! moment. (`TraitDef.additional_bounds`)
28 //! Unsupported: FIXME #6257: calling methods on reference fields,
29 //! e.g. deriving Eq/Ord/Clone don't work on `struct A(&int)`,
30 //! because of how the auto-dereferencing happens.
32 //! The most important thing for implementers is the `Substructure` and
33 //! `SubstructureFields` objects. The latter groups 5 possibilities of the
36 //! - `Struct`, when `Self` is a struct (including tuple structs, e.g
37 //! `struct T(int, char)`).
38 //! - `EnumMatching`, when `Self` is an enum and all the arguments are the
39 //! same variant of the enum (e.g. `Some(1)`, `Some(3)` and `Some(4)`)
40 //! - `EnumNonMatching` when `Self` is an enum and the arguments are not
41 //! the same variant (e.g. `None`, `Some(1)` and `None`). If
42 //! `const_nonmatching` is true, this will contain an empty list.
43 //! - `StaticEnum` and `StaticStruct` for static methods, where the type
44 //! being derived upon is either an enum or struct respectively. (Any
45 //! argument with type Self is just grouped among the non-self
48 //! In the first two cases, the values from the corresponding fields in
49 //! all the arguments are grouped together. In the `EnumNonMatching` case
50 //! this isn't possible (different variants have different fields), so the
51 //! fields are grouped by which argument they come from. There are no
52 //! fields with values in the static cases, so these are treated entirely
55 //! The non-static cases have `Option<ident>` in several places associated
56 //! with field `expr`s. This represents the name of the field it is
57 //! associated with. It is only not `None` when the associated field has
58 //! an identifier in the source code. For example, the `x`s in the
62 //! struct A { x : int }
72 //! The `int`s in `B` and `C0` don't have an identifier, so the
73 //! `Option<ident>`s would be `None` for them.
75 //! In the static cases, the structure is summarised, either into the just
76 //! spans of the fields or a list of spans and the field idents (for tuple
77 //! structs and record structs, respectively), or a list of these, for
78 //! enums (one for each variant). For empty struct and empty enum
79 //! variants, it is represented as a count of 0.
83 //! The following simplified `PartialEq` is used for in-code examples:
87 //! fn eq(&self, other: &Self);
89 //! impl PartialEq for int {
90 //! fn eq(&self, other: &int) -> bool {
96 //! Some examples of the values of `SubstructureFields` follow, using the
97 //! above `PartialEq`, `A`, `B` and `C`.
101 //! When generating the `expr` for the `A` impl, the `SubstructureFields` is
104 //! Struct(~[FieldInfo {
105 //! span: <span of x>
106 //! name: Some(<ident of x>),
107 //! self_: <expr for &self.x>,
108 //! other: ~[<expr for &other.x]
112 //! For the `B` impl, called with `B(a)` and `B(b)`,
115 //! Struct(~[FieldInfo {
116 //! span: <span of `int`>,
125 //! When generating the `expr` for a call with `self == C0(a)` and `other
126 //! == C0(b)`, the SubstructureFields is
129 //! EnumMatching(0, <ast::Variant for C0>,
131 //! span: <span of int>
133 //! self_: <expr for &a>,
134 //! other: ~[<expr for &b>]
138 //! For `C1 {x}` and `C1 {x}`,
141 //! EnumMatching(1, <ast::Variant for C1>,
143 //! span: <span of x>
144 //! name: Some(<ident of x>),
145 //! self_: <expr for &self.x>,
146 //! other: ~[<expr for &other.x>]
150 //! For `C0(a)` and `C1 {x}` ,
153 //! EnumNonMatching(~[(0, <ast::Variant for B0>,
154 //! ~[(<span of int>, None, <expr for &a>)]),
155 //! (1, <ast::Variant for B1>,
156 //! ~[(<span of x>, Some(<ident of x>),
157 //! <expr for &other.x>)])])
160 //! (and vice versa, but with the order of the outermost list flipped.)
164 //! A static method on the above would result in,
167 //! StaticStruct(<ast::StructDef of A>, Named(~[(<ident of x>, <span of x>)]))
169 //! StaticStruct(<ast::StructDef of B>, Unnamed(~[<span of x>]))
171 //! StaticEnum(<ast::EnumDef of C>, ~[(<ident of C0>, <span of C0>, Unnamed(~[<span of int>])),
172 //! (<ident of C1>, <span of C1>,
173 //! Named(~[(<ident of x>, <span of x>)]))])
176 use std::cell::RefCell;
177 use std::gc::{Gc, GC};
180 use ast::{P, EnumDef, Expr, Ident, Generics, StructDef};
183 use attr::AttrMetaMethods;
184 use ext::base::ExtCtxt;
185 use ext::build::AstBuilder;
188 use owned_slice::OwnedSlice;
189 use parse::token::InternedString;
190 use parse::token::special_idents;
196 pub struct TraitDef<'a> {
197 /// The span for the current #[deriving(Foo)] header.
200 pub attributes: Vec<ast::Attribute>,
202 /// Path of the trait, including any type parameters
205 /// Additional bounds required of any type parameters of the type,
206 /// other than the current trait
207 pub additional_bounds: Vec<Ty<'a>>,
209 /// Any extra lifetimes and/or bounds, e.g. `D: serialize::Decoder`
210 pub generics: LifetimeBounds<'a>,
212 pub methods: Vec<MethodDef<'a>>,
216 pub struct MethodDef<'a> {
217 /// name of the method
219 /// List of generics, e.g. `R: rand::Rng`
220 pub generics: LifetimeBounds<'a>,
222 /// Whether there is a self argument (outer Option) i.e. whether
223 /// this is a static function, and whether it is a pointer (inner
225 pub explicit_self: Option<Option<PtrTy<'a>>>,
227 /// Arguments other than the self argument
228 pub args: Vec<Ty<'a>>,
233 pub attributes: Vec<ast::Attribute>,
235 /// if the value of the nonmatching enums is independent of the
236 /// actual enum variants, i.e. can use _ => .. match.
237 pub const_nonmatching: bool,
239 pub combine_substructure: RefCell<CombineSubstructureFunc<'a>>,
242 /// All the data about the data structure/method being derived upon.
243 pub struct Substructure<'a> {
245 pub type_ident: Ident,
246 /// ident of the method
247 pub method_ident: Ident,
248 /// dereferenced access to any Self or Ptr(Self, _) arguments
249 pub self_args: &'a [Gc<Expr>],
250 /// verbatim access to any other arguments
251 pub nonself_args: &'a [Gc<Expr>],
252 pub fields: &'a SubstructureFields<'a>
255 /// Summary of the relevant parts of a struct/enum field.
256 pub struct FieldInfo {
258 /// None for tuple structs/normal enum variants, Some for normal
259 /// structs/struct enum variants.
260 pub name: Option<Ident>,
261 /// The expression corresponding to this field of `self`
262 /// (specifically, a reference to it).
264 /// The expressions corresponding to references to this field in
265 /// the other Self arguments.
266 pub other: Vec<Gc<Expr>>,
269 /// Fields for a static method
270 pub enum StaticFields {
271 /// Tuple structs/enum variants like this
273 /// Normal structs/struct variants.
274 Named(Vec<(Ident, Span)>),
277 /// A summary of the possible sets of fields. See above for details
279 pub enum SubstructureFields<'a> {
280 Struct(Vec<FieldInfo>),
282 Matching variants of the enum: variant index, ast::Variant,
283 fields: the field name is only non-`None` in the case of a struct
286 EnumMatching(uint, &'a ast::Variant, Vec<FieldInfo>),
289 non-matching variants of the enum, [(variant index, ast::Variant,
290 [field span, field ident, fields])] \(i.e. all fields for self are in the
291 first tuple, for other1 are in the second tuple, etc.)
293 EnumNonMatching(&'a [(uint, P<ast::Variant>,
294 Vec<(Span, Option<Ident>, Gc<Expr>)>)]),
296 /// A static method where Self is a struct.
297 StaticStruct(&'a ast::StructDef, StaticFields),
298 /// A static method where Self is an enum.
299 StaticEnum(&'a ast::EnumDef, Vec<(Ident, Span, StaticFields)>),
305 Combine the values of all the fields together. The last argument is
306 all the fields of all the structures, see above for details.
308 pub type CombineSubstructureFunc<'a> =
309 |&mut ExtCtxt, Span, &Substructure|: 'a -> Gc<Expr>;
312 Deal with non-matching enum variants, the arguments are a list
313 representing each variant: (variant index, ast::Variant instance,
314 [variant fields]), and a list of the nonself args of the type
316 pub type EnumNonMatchFunc<'a> =
319 &[(uint, P<ast::Variant>, Vec<(Span, Option<Ident>, Gc<Expr>)>)],
323 pub fn combine_substructure<'a>(f: CombineSubstructureFunc<'a>)
324 -> RefCell<CombineSubstructureFunc<'a>> {
329 impl<'a> TraitDef<'a> {
332 _mitem: Gc<ast::MetaItem>,
334 push: |Gc<ast::Item>|) {
335 let newitem = match item.node {
336 ast::ItemStruct(ref struct_def, ref generics) => {
337 self.expand_struct_def(cx,
342 ast::ItemEnum(ref enum_def, ref generics) => {
343 self.expand_enum_def(cx,
350 // Keep the lint attributes of the previous item to control how the
351 // generated implementations are linted
352 let mut attrs = newitem.attrs.clone();
353 attrs.extend(item.attrs.iter().filter(|a| {
354 match a.name().get() {
355 "allow" | "warn" | "deny" | "forbid" => true,
358 }).map(|a| a.clone()));
359 push(box(GC) ast::Item {
367 * Given that we are deriving a trait `Tr` for a type `T<'a, ...,
368 * 'z, A, ..., Z>`, creates an impl like:
371 * impl<'a, ..., 'z, A:Tr B1 B2, ..., Z: Tr B1 B2> Tr for T<A, ..., Z> { ... }
374 * where B1, B2, ... are the bounds given by `bounds_paths`.'
377 fn create_derived_impl(&self,
381 methods: Vec<Gc<ast::Method>> ) -> Gc<ast::Item> {
382 let trait_path = self.path.to_path(cx, self.span, type_ident, generics);
384 let Generics { mut lifetimes, ty_params } =
385 self.generics.to_generics(cx, self.span, type_ident, generics);
386 let mut ty_params = ty_params.into_vec();
388 // Copy the lifetimes
389 lifetimes.extend(generics.lifetimes.iter().map(|l| *l));
391 // Create the type parameters.
392 ty_params.extend(generics.ty_params.iter().map(|ty_param| {
393 // I don't think this can be moved out of the loop, since
394 // a TyParamBound requires an ast id
395 let mut bounds: Vec<_> =
396 // extra restrictions on the generics parameters to the type being derived upon
397 self.additional_bounds.iter().map(|p| {
398 cx.typarambound(p.to_path(cx, self.span,
399 type_ident, generics))
401 // require the current trait
402 bounds.push(cx.typarambound(trait_path.clone()));
404 cx.typaram(self.span,
406 OwnedSlice::from_vec(bounds),
407 ty_param.unbound.clone(),
410 let trait_generics = Generics {
411 lifetimes: lifetimes,
412 ty_params: OwnedSlice::from_vec(ty_params)
415 // Create the reference to the trait.
416 let trait_ref = cx.trait_ref(trait_path);
418 // Create the type parameters on the `self` path.
419 let self_ty_params = generics.ty_params.map(|ty_param| {
420 cx.ty_ident(self.span, ty_param.ident)
423 let self_lifetimes = generics.lifetimes.clone();
425 // Create the type of `self`.
426 let self_type = cx.ty_path(
427 cx.path_all(self.span, false, vec!( type_ident ), self_lifetimes,
428 self_ty_params.into_vec()), None);
430 let attr = cx.attribute(
432 cx.meta_word(self.span,
433 InternedString::new("automatically_derived")));
434 // Just mark it now since we know that it'll end up used downstream
435 attr::mark_used(&attr);
436 let opt_trait_ref = Some(trait_ref);
437 let ident = ast_util::impl_pretty_name(&opt_trait_ref, &*self_type);
441 (vec!(attr)).append(self.attributes.as_slice()),
442 ast::ItemImpl(trait_generics, opt_trait_ref,
446 fn expand_struct_def(&self,
448 struct_def: &StructDef,
450 generics: &Generics) -> Gc<ast::Item> {
451 let methods = self.methods.iter().map(|method_def| {
452 let (explicit_self, self_args, nonself_args, tys) =
453 method_def.split_self_nonself_args(
454 cx, self, type_ident, generics);
456 let body = if method_def.is_static() {
457 method_def.expand_static_struct_method_body(
462 self_args.as_slice(),
463 nonself_args.as_slice())
465 method_def.expand_struct_method_body(cx,
469 self_args.as_slice(),
470 nonself_args.as_slice())
473 method_def.create_method(cx, self,
474 type_ident, generics,
479 self.create_derived_impl(cx, type_ident, generics, methods)
482 fn expand_enum_def(&self,
486 generics: &Generics) -> Gc<ast::Item> {
487 let methods = self.methods.iter().map(|method_def| {
488 let (explicit_self, self_args, nonself_args, tys) =
489 method_def.split_self_nonself_args(cx, self,
490 type_ident, generics);
492 let body = if method_def.is_static() {
493 method_def.expand_static_enum_method_body(
498 self_args.as_slice(),
499 nonself_args.as_slice())
501 method_def.expand_enum_method_body(cx,
505 self_args.as_slice(),
506 nonself_args.as_slice())
509 method_def.create_method(cx, self,
510 type_ident, generics,
515 self.create_derived_impl(cx, type_ident, generics, methods)
519 impl<'a> MethodDef<'a> {
520 fn call_substructure_method(&self,
524 self_args: &[Gc<Expr>],
525 nonself_args: &[Gc<Expr>],
526 fields: &SubstructureFields)
528 let substructure = Substructure {
529 type_ident: type_ident,
530 method_ident: cx.ident_of(self.name),
531 self_args: self_args,
532 nonself_args: nonself_args,
535 let mut f = self.combine_substructure.borrow_mut();
536 let f: &mut CombineSubstructureFunc = &mut *f;
537 (*f)(cx, trait_.span, &substructure)
546 self.ret_ty.to_ty(cx, trait_.span, type_ident, generics)
549 fn is_static(&self) -> bool {
550 self.explicit_self.is_none()
553 fn split_self_nonself_args(&self,
558 -> (ast::ExplicitSelf, Vec<Gc<Expr>>, Vec<Gc<Expr>>,
559 Vec<(Ident, P<ast::Ty>)>) {
561 let mut self_args = Vec::new();
562 let mut nonself_args = Vec::new();
563 let mut arg_tys = Vec::new();
564 let mut nonstatic = false;
566 let ast_explicit_self = match self.explicit_self {
567 Some(ref self_ptr) => {
568 let (self_expr, explicit_self) =
569 ty::get_explicit_self(cx, trait_.span, self_ptr);
571 self_args.push(self_expr);
576 None => codemap::respan(trait_.span, ast::SelfStatic),
579 for (i, ty) in self.args.iter().enumerate() {
580 let ast_ty = ty.to_ty(cx, trait_.span, type_ident, generics);
581 let ident = cx.ident_of(format!("__arg_{}", i).as_slice());
582 arg_tys.push((ident, ast_ty));
584 let arg_expr = cx.expr_ident(trait_.span, ident);
587 // for static methods, just treat any Self
588 // arguments as a normal arg
589 Self if nonstatic => {
590 self_args.push(arg_expr);
592 Ptr(box Self, _) if nonstatic => {
593 self_args.push(cx.expr_deref(trait_.span, arg_expr))
596 nonself_args.push(arg_expr);
601 (ast_explicit_self, self_args, nonself_args, arg_tys)
604 fn create_method(&self,
609 explicit_self: ast::ExplicitSelf,
610 arg_types: Vec<(Ident, P<ast::Ty>)> ,
611 body: Gc<Expr>) -> Gc<ast::Method> {
612 // create the generics that aren't for Self
613 let fn_generics = self.generics.to_generics(cx, trait_.span, type_ident, generics);
615 let self_arg = match explicit_self.node {
616 ast::SelfStatic => None,
617 // creating fresh self id
618 _ => Some(ast::Arg::new_self(trait_.span, ast::MutImmutable, special_idents::self_))
621 let args = arg_types.move_iter().map(|(name, ty)| {
622 cx.arg(trait_.span, name, ty)
624 self_arg.move_iter().chain(args).collect()
627 let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident);
629 let method_ident = cx.ident_of(self.name);
630 let fn_decl = cx.fn_decl(args, ret_type);
631 let body_block = cx.block_expr(body);
633 // Create the method.
634 box(GC) ast::Method {
636 attrs: self.attributes.clone(),
637 generics: fn_generics,
638 explicit_self: explicit_self,
639 fn_style: ast::NormalFn,
642 id: ast::DUMMY_NODE_ID,
650 #[deriving(PartialEq)]
651 struct A { x: int, y: int }
654 impl PartialEq for A {
655 fn eq(&self, __arg_1: &A) -> bool {
657 A {x: ref __self_0_0, y: ref __self_0_1} => {
659 A {x: ref __self_1_0, y: ref __self_1_1} => {
660 __self_0_0.eq(__self_1_0) && __self_0_1.eq(__self_1_1)
669 fn expand_struct_method_body(&self,
672 struct_def: &StructDef,
674 self_args: &[Gc<Expr>],
675 nonself_args: &[Gc<Expr>])
678 let mut raw_fields = Vec::new(); // ~[[fields of self],
679 // [fields of next Self arg], [etc]]
680 let mut patterns = Vec::new();
681 for i in range(0u, self_args.len()) {
682 let (pat, ident_expr) =
683 trait_.create_struct_pattern(cx,
690 raw_fields.push(ident_expr);
693 // transpose raw_fields
694 let fields = if raw_fields.len() > 0 {
698 .map(|(i, &(span, opt_id, field))| {
699 let other_fields = raw_fields.tail().iter().map(|l| {
712 cx.span_bug(trait_.span,
713 "no self arguments to non-static method in generic \
717 // body of the inner most destructuring match
718 let mut body = self.call_substructure_method(
726 // make a series of nested matches, to destructure the
727 // structs. This is actually right-to-left, but it shouldn't
729 for (&arg_expr, &pat) in self_args.iter().zip(patterns.iter()) {
730 body = cx.expr_match(trait_.span, arg_expr,
731 vec!( cx.arm(trait_.span, vec!(pat), body) ))
736 fn expand_static_struct_method_body(&self,
739 struct_def: &StructDef,
741 self_args: &[Gc<Expr>],
742 nonself_args: &[Gc<Expr>])
744 let summary = trait_.summarise_struct(cx, struct_def);
746 self.call_substructure_method(cx,
749 self_args, nonself_args,
750 &StaticStruct(struct_def, summary))
755 #[deriving(PartialEq)]
761 // is equivalent to (with const_nonmatching == false)
763 impl PartialEq for A {
764 fn eq(&self, __arg_1: &A) {
766 A1 => match *__arg_1 {
768 A2(ref __arg_1_1) => false
770 A2(self_1) => match *__arg_1 {
772 A2(ref __arg_1_1) => self_1.eq(__arg_1_1)
779 fn expand_enum_method_body(&self,
784 self_args: &[Gc<Expr>],
785 nonself_args: &[Gc<Expr>])
787 let mut matches = Vec::new();
788 self.build_enum_match(cx, trait_, enum_def, type_ident,
789 self_args, nonself_args,
790 None, &mut matches, 0)
795 Creates the nested matches for an enum definition recursively, i.e.
799 Variant1 => match other { Variant1 => matching, Variant2 => nonmatching, ... },
800 Variant2 => match other { Variant1 => nonmatching, Variant2 => matching, ... },
805 It acts in the most naive way, so every branch (and subbranch,
806 subsubbranch, etc) exists, not just the ones where all the variants in
807 the tree are the same. Hopefully the optimisers get rid of any
808 repetition, otherwise derived methods with many Self arguments will be
811 `matching` is Some(n) if all branches in the tree above the
812 current position are variant `n`, `None` otherwise (including on
815 fn build_enum_match(&self,
820 self_args: &[Gc<Expr>],
821 nonself_args: &[Gc<Expr>],
822 matching: Option<uint>,
823 matches_so_far: &mut Vec<(uint, P<ast::Variant>,
824 Vec<(Span, Option<Ident>, Gc<Expr>)>)> ,
825 match_count: uint) -> Gc<Expr> {
826 if match_count == self_args.len() {
827 // we've matched against all arguments, so make the final
828 // expression at the bottom of the match tree
829 if matches_so_far.len() == 0 {
830 cx.span_bug(trait_.span,
831 "no self match on an enum in \
832 generic `deriving`");
835 // `ref` inside let matches is buggy. Causes havoc with rusc.
836 // let (variant_index, ref self_vec) = matches_so_far[0];
837 let (variant, self_vec) = match matches_so_far.get(0) {
838 &(_, v, ref s) => (v, s)
841 // we currently have a vec of vecs, where each
842 // subvec is the fields of one of the arguments,
843 // but if the variants all match, we want this as
844 // vec of tuples, where each tuple represents a
847 // most arms don't have matching variants, so do a
848 // quick check to see if they match (even though
849 // this means iterating twice) instead of being
850 // optimistic and doing a pile of allocations etc.
851 let substructure = match matching {
852 Some(variant_index) => {
853 let mut enum_matching_fields = Vec::from_elem(self_vec.len(), Vec::new());
855 for triple in matches_so_far.tail().iter() {
857 &(_, _, ref other_fields) => {
858 for (i, &(_, _, e)) in other_fields.iter().enumerate() {
859 enum_matching_fields.get_mut(i).push(e);
866 .zip(enum_matching_fields.iter())
867 .map(|(&(span, id, self_f), other)| {
872 other: (*other).clone()
875 EnumMatching(variant_index, &*variant, field_tuples)
878 EnumNonMatching(matches_so_far.as_slice())
881 self.call_substructure_method(cx, trait_, type_ident,
882 self_args, nonself_args,
885 } else { // there are still matches to create
886 let current_match_str = if match_count == 0 {
889 format!("__arg_{}", match_count)
892 let mut arms = Vec::new();
894 // the code for nonmatching variants only matters when
895 // we've seen at least one other variant already
896 if self.const_nonmatching && match_count > 0 {
897 // make a matching-variant match, and a _ match.
898 let index = match matching {
900 None => cx.span_bug(trait_.span,
901 "non-matching variants when required to \
902 be matching in generic `deriving`")
905 // matching-variant match
906 let variant = *enum_def.variants.get(index);
907 let (pattern, idents) = trait_.create_enum_variant_pattern(
910 current_match_str.as_slice(),
913 matches_so_far.push((index, variant, idents));
914 let arm_expr = self.build_enum_match(cx,
918 self_args, nonself_args,
922 matches_so_far.pop().unwrap();
923 arms.push(cx.arm(trait_.span, vec!( pattern ), arm_expr));
925 if enum_def.variants.len() > 1 {
926 let e = &EnumNonMatching(&[]);
927 let wild_expr = self.call_substructure_method(cx, trait_, type_ident,
928 self_args, nonself_args,
930 let wild_arm = cx.arm(
932 vec!( cx.pat_wild(trait_.span) ),
937 // create an arm matching on each variant
938 for (index, &variant) in enum_def.variants.iter().enumerate() {
939 let (pattern, idents) =
940 trait_.create_enum_variant_pattern(
943 current_match_str.as_slice(),
946 matches_so_far.push((index, variant, idents));
949 _ if match_count == 0 => Some(index),
950 Some(i) if index == i => Some(i),
953 let arm_expr = self.build_enum_match(cx,
957 self_args, nonself_args,
961 matches_so_far.pop().unwrap();
963 let arm = cx.arm(trait_.span, vec!( pattern ), arm_expr);
968 // match foo { arm, arm, arm, ... }
969 cx.expr_match(trait_.span, self_args[match_count], arms)
973 fn expand_static_enum_method_body(&self,
978 self_args: &[Gc<Expr>],
979 nonself_args: &[Gc<Expr>])
981 let summary = enum_def.variants.iter().map(|v| {
982 let ident = v.node.name;
983 let summary = match v.node.kind {
984 ast::TupleVariantKind(ref args) => {
985 Unnamed(args.iter().map(|va| trait_.set_expn_info(cx, va.ty.span)).collect())
987 ast::StructVariantKind(ref struct_def) => {
988 trait_.summarise_struct(cx, &**struct_def)
991 (ident, v.span, summary)
993 self.call_substructure_method(cx, trait_, type_ident,
994 self_args, nonself_args,
995 &StaticEnum(enum_def, summary))
999 #[deriving(PartialEq)] // dogfooding!
1001 Unknown, Record, Tuple
1004 // general helper methods.
1005 impl<'a> TraitDef<'a> {
1006 fn set_expn_info(&self,
1008 mut to_set: Span) -> Span {
1009 let trait_name = match self.path.path.last() {
1010 None => cx.span_bug(self.span, "trait with empty path in generic `deriving`"),
1013 to_set.expn_info = Some(box(GC) codemap::ExpnInfo {
1015 callee: codemap::NameAndSpan {
1016 name: format!("deriving({})", trait_name),
1017 format: codemap::MacroAttribute,
1018 span: Some(self.span)
1024 fn summarise_struct(&self,
1026 struct_def: &StructDef) -> StaticFields {
1027 let mut named_idents = Vec::new();
1028 let mut just_spans = Vec::new();
1029 for field in struct_def.fields.iter(){
1030 let sp = self.set_expn_info(cx, field.span);
1031 match field.node.kind {
1032 ast::NamedField(ident, _) => named_idents.push((ident, sp)),
1033 ast::UnnamedField(..) => just_spans.push(sp),
1037 match (just_spans.is_empty(), named_idents.is_empty()) {
1038 (false, false) => cx.span_bug(self.span,
1039 "a struct with named and unnamed \
1040 fields in generic `deriving`"),
1042 (_, false) => Named(named_idents),
1043 // tuple structs (includes empty structs)
1044 (_, _) => Unnamed(just_spans)
1048 fn create_subpatterns(&self,
1050 field_paths: Vec<ast::SpannedIdent> ,
1051 mutbl: ast::Mutability)
1052 -> Vec<Gc<ast::Pat>> {
1053 field_paths.iter().map(|path| {
1055 ast::PatIdent(ast::BindByRef(mutbl), (*path).clone(), None))
1059 fn create_struct_pattern(&self,
1061 struct_ident: Ident,
1062 struct_def: &StructDef,
1064 mutbl: ast::Mutability)
1065 -> (Gc<ast::Pat>, Vec<(Span, Option<Ident>, Gc<Expr>)>) {
1066 if struct_def.fields.is_empty() {
1068 cx.pat_ident_binding_mode(
1069 self.span, struct_ident, ast::BindByValue(ast::MutImmutable)),
1073 let matching_path = cx.path(self.span, vec!( struct_ident ));
1075 let mut paths = Vec::new();
1076 let mut ident_expr = Vec::new();
1077 let mut struct_type = Unknown;
1079 for (i, struct_field) in struct_def.fields.iter().enumerate() {
1080 let sp = self.set_expn_info(cx, struct_field.span);
1081 let opt_id = match struct_field.node.kind {
1082 ast::NamedField(ident, _) if (struct_type == Unknown ||
1083 struct_type == Record) => {
1084 struct_type = Record;
1087 ast::UnnamedField(..) if (struct_type == Unknown ||
1088 struct_type == Tuple) => {
1089 struct_type = Tuple;
1093 cx.span_bug(sp, "a struct with named and unnamed fields in `deriving`");
1096 let ident = cx.ident_of(format!("{}_{}", prefix, i).as_slice());
1097 paths.push(codemap::Spanned{span: sp, node: ident});
1099 sp, ast::ExprParen(cx.expr_deref(sp, cx.expr_path(cx.path_ident(sp,ident)))));
1100 ident_expr.push((sp, opt_id, val));
1103 let subpats = self.create_subpatterns(cx, paths, mutbl);
1105 // struct_type is definitely not Unknown, since struct_def.fields
1106 // must be nonempty to reach here
1107 let pattern = if struct_type == Record {
1108 let field_pats = subpats.iter().zip(ident_expr.iter()).map(|(&pat, &(_, id, _))| {
1109 // id is guaranteed to be Some
1110 ast::FieldPat { ident: id.unwrap(), pat: pat }
1112 cx.pat_struct(self.span, matching_path, field_pats)
1114 cx.pat_enum(self.span, matching_path, subpats)
1117 (pattern, ident_expr)
1120 fn create_enum_variant_pattern(&self,
1122 variant: &ast::Variant,
1124 mutbl: ast::Mutability)
1125 -> (Gc<ast::Pat>, Vec<(Span, Option<Ident>, Gc<Expr>)> ) {
1126 let variant_ident = variant.node.name;
1127 match variant.node.kind {
1128 ast::TupleVariantKind(ref variant_args) => {
1129 if variant_args.is_empty() {
1130 return (cx.pat_ident_binding_mode(variant.span, variant_ident,
1131 ast::BindByValue(ast::MutImmutable)),
1135 let matching_path = cx.path_ident(variant.span, variant_ident);
1137 let mut paths = Vec::new();
1138 let mut ident_expr = Vec::new();
1139 for (i, va) in variant_args.iter().enumerate() {
1140 let sp = self.set_expn_info(cx, va.ty.span);
1141 let ident = cx.ident_of(format!("{}_{}", prefix, i).as_slice());
1142 let path1 = codemap::Spanned{span: sp, node: ident};
1144 let expr_path = cx.expr_path(cx.path_ident(sp, ident));
1145 let val = cx.expr(sp, ast::ExprParen(cx.expr_deref(sp, expr_path)));
1146 ident_expr.push((sp, None, val));
1149 let subpats = self.create_subpatterns(cx, paths, mutbl);
1151 (cx.pat_enum(variant.span, matching_path, subpats),
1154 ast::StructVariantKind(ref struct_def) => {
1155 self.create_struct_pattern(cx, variant_ident, &**struct_def,
1162 /* helpful premade recipes */
1165 Fold the fields. `use_foldl` controls whether this is done
1166 left-to-right (`true`) or right-to-left (`false`).
1168 pub fn cs_fold(use_foldl: bool,
1169 f: |&mut ExtCtxt, Span, Gc<Expr>, Gc<Expr>, &[Gc<Expr>]| -> Gc<Expr>,
1171 enum_nonmatch_f: EnumNonMatchFunc,
1174 substructure: &Substructure)
1176 match *substructure.fields {
1177 EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => {
1179 all_fields.iter().fold(base, |old, field| {
1184 field.other.as_slice())
1187 all_fields.iter().rev().fold(base, |old, field| {
1192 field.other.as_slice())
1196 EnumNonMatching(ref all_enums) => enum_nonmatch_f(cx, trait_span,
1198 substructure.nonself_args),
1199 StaticEnum(..) | StaticStruct(..) => {
1200 cx.span_bug(trait_span, "static function in `deriving`")
1207 Call the method that is being derived on all the fields, and then
1208 process the collected results. i.e.
1211 f(cx, span, ~[self_1.method(__arg_1_1, __arg_2_1),
1212 self_2.method(__arg_1_2, __arg_2_2)])
1216 pub fn cs_same_method(f: |&mut ExtCtxt, Span, Vec<Gc<Expr>>| -> Gc<Expr>,
1217 enum_nonmatch_f: EnumNonMatchFunc,
1220 substructure: &Substructure)
1222 match *substructure.fields {
1223 EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => {
1224 // call self_n.method(other_1_n, other_2_n, ...)
1225 let called = all_fields.iter().map(|field| {
1226 cx.expr_method_call(field.span,
1228 substructure.method_ident,
1230 .map(|e| cx.expr_addr_of(field.span, *e))
1234 f(cx, trait_span, called)
1236 EnumNonMatching(ref all_enums) => enum_nonmatch_f(cx, trait_span,
1238 substructure.nonself_args),
1239 StaticEnum(..) | StaticStruct(..) => {
1240 cx.span_bug(trait_span, "static function in `deriving`")
1246 Fold together the results of calling the derived method on all the
1247 fields. `use_foldl` controls whether this is done left-to-right
1248 (`true`) or right-to-left (`false`).
1251 pub fn cs_same_method_fold(use_foldl: bool,
1252 f: |&mut ExtCtxt, Span, Gc<Expr>, Gc<Expr>| -> Gc<Expr>,
1254 enum_nonmatch_f: EnumNonMatchFunc,
1257 substructure: &Substructure)
1262 vals.iter().fold(base, |old, &new| {
1263 f(cx, span, old, new)
1266 vals.iter().rev().fold(base, |old, &new| {
1267 f(cx, span, old, new)
1272 cx, trait_span, substructure)
1276 Use a given binop to combine the result of calling the derived method
1280 pub fn cs_binop(binop: ast::BinOp, base: Gc<Expr>,
1281 enum_nonmatch_f: EnumNonMatchFunc,
1282 cx: &mut ExtCtxt, trait_span: Span,
1283 substructure: &Substructure) -> Gc<Expr> {
1284 cs_same_method_fold(
1285 true, // foldl is good enough
1286 |cx, span, old, new| {
1287 cx.expr_binary(span,
1294 cx, trait_span, substructure)
1297 /// cs_binop with binop == or
1299 pub fn cs_or(enum_nonmatch_f: EnumNonMatchFunc,
1300 cx: &mut ExtCtxt, span: Span,
1301 substructure: &Substructure) -> Gc<Expr> {
1302 cs_binop(ast::BiOr, cx.expr_bool(span, false),
1304 cx, span, substructure)
1307 /// cs_binop with binop == and
1309 pub fn cs_and(enum_nonmatch_f: EnumNonMatchFunc,
1310 cx: &mut ExtCtxt, span: Span,
1311 substructure: &Substructure) -> Gc<Expr> {
1312 cs_binop(ast::BiAnd, cx.expr_bool(span, true),
1314 cx, span, substructure)