]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/ext/deriving/generic/mod.rs
auto merge of #15483 : AlisdairO/rust/master, r=alexcrichton
[rust.git] / src / libsyntax / ext / deriving / generic / mod.rs
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.
4 //
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.
10
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.
15 //!
16 //! Supported features (fairly exhaustive):
17 //!
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`)
27 //!
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.
31 //!
32 //! The most important thing for implementers is the `Substructure` and
33 //! `SubstructureFields` objects. The latter groups 5 possibilities of the
34 //! arguments:
35 //!
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
46 //!   arguments.)
47 //!
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
53 //! differently.
54 //!
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
59 //! following snippet
60 //!
61 //! ```rust
62 //! struct A { x : int }
63 //!
64 //! struct B(int);
65 //!
66 //! enum C {
67 //!     C0(int),
68 //!     C1 { x: int }
69 //! }
70 //! ```
71 //!
72 //! The `int`s in `B` and `C0` don't have an identifier, so the
73 //! `Option<ident>`s would be `None` for them.
74 //!
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.
80 //!
81 //! # Examples
82 //!
83 //! The following simplified `PartialEq` is used for in-code examples:
84 //!
85 //! ```rust
86 //! trait PartialEq {
87 //!     fn eq(&self, other: &Self);
88 //! }
89 //! impl PartialEq for int {
90 //!     fn eq(&self, other: &int) -> bool {
91 //!         *self == *other
92 //!     }
93 //! }
94 //! ```
95 //!
96 //! Some examples of the values of `SubstructureFields` follow, using the
97 //! above `PartialEq`, `A`, `B` and `C`.
98 //!
99 //! ## Structs
100 //!
101 //! When generating the `expr` for the `A` impl, the `SubstructureFields` is
102 //!
103 //! ~~~text
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]
109 //!          }])
110 //! ~~~
111 //!
112 //! For the `B` impl, called with `B(a)` and `B(b)`,
113 //!
114 //! ~~~text
115 //! Struct(~[FieldInfo {
116 //!           span: <span of `int`>,
117 //!           name: None,
118 //!           <expr for &a>
119 //!           ~[<expr for &b>]
120 //!          }])
121 //! ~~~
122 //!
123 //! ## Enums
124 //!
125 //! When generating the `expr` for a call with `self == C0(a)` and `other
126 //! == C0(b)`, the SubstructureFields is
127 //!
128 //! ~~~text
129 //! EnumMatching(0, <ast::Variant for C0>,
130 //!              ~[FieldInfo {
131 //!                 span: <span of int>
132 //!                 name: None,
133 //!                 self_: <expr for &a>,
134 //!                 other: ~[<expr for &b>]
135 //!               }])
136 //! ~~~
137 //!
138 //! For `C1 {x}` and `C1 {x}`,
139 //!
140 //! ~~~text
141 //! EnumMatching(1, <ast::Variant for C1>,
142 //!              ~[FieldInfo {
143 //!                 span: <span of x>
144 //!                 name: Some(<ident of x>),
145 //!                 self_: <expr for &self.x>,
146 //!                 other: ~[<expr for &other.x>]
147 //!                }])
148 //! ~~~
149 //!
150 //! For `C0(a)` and `C1 {x}` ,
151 //!
152 //! ~~~text
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>)])])
158 //! ~~~
159 //!
160 //! (and vice versa, but with the order of the outermost list flipped.)
161 //!
162 //! ## Static
163 //!
164 //! A static method on the above would result in,
165 //!
166 //! ~~~text
167 //! StaticStruct(<ast::StructDef of A>, Named(~[(<ident of x>, <span of x>)]))
168 //!
169 //! StaticStruct(<ast::StructDef of B>, Unnamed(~[<span of x>]))
170 //!
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>)]))])
174 //! ~~~
175
176 use std::cell::RefCell;
177 use std::gc::{Gc, GC};
178
179 use ast;
180 use ast::{P, EnumDef, Expr, Ident, Generics, StructDef};
181 use ast_util;
182 use attr;
183 use attr::AttrMetaMethods;
184 use ext::base::ExtCtxt;
185 use ext::build::AstBuilder;
186 use codemap;
187 use codemap::Span;
188 use owned_slice::OwnedSlice;
189 use parse::token::InternedString;
190 use parse::token::special_idents;
191
192 use self::ty::*;
193
194 pub mod ty;
195
196 pub struct TraitDef<'a> {
197     /// The span for the current #[deriving(Foo)] header.
198     pub span: Span,
199
200     pub attributes: Vec<ast::Attribute>,
201
202     /// Path of the trait, including any type parameters
203     pub path: Path<'a>,
204
205     /// Additional bounds required of any type parameters of the type,
206     /// other than the current trait
207     pub additional_bounds: Vec<Ty<'a>>,
208
209     /// Any extra lifetimes and/or bounds, e.g. `D: serialize::Decoder`
210     pub generics: LifetimeBounds<'a>,
211
212     pub methods: Vec<MethodDef<'a>>,
213 }
214
215
216 pub struct MethodDef<'a> {
217     /// name of the method
218     pub name: &'a str,
219     /// List of generics, e.g. `R: rand::Rng`
220     pub generics: LifetimeBounds<'a>,
221
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
224     /// Option)
225     pub explicit_self: Option<Option<PtrTy<'a>>>,
226
227     /// Arguments other than the self argument
228     pub args: Vec<Ty<'a>>,
229
230     /// Return type
231     pub ret_ty: Ty<'a>,
232
233     pub attributes: Vec<ast::Attribute>,
234
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,
238
239     pub combine_substructure: RefCell<CombineSubstructureFunc<'a>>,
240 }
241
242 /// All the data about the data structure/method being derived upon.
243 pub struct Substructure<'a> {
244     /// ident of self
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>
253 }
254
255 /// Summary of the relevant parts of a struct/enum field.
256 pub struct FieldInfo {
257     pub span: Span,
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).
263     pub self_: Gc<Expr>,
264     /// The expressions corresponding to references to this field in
265     /// the other Self arguments.
266     pub other: Vec<Gc<Expr>>,
267 }
268
269 /// Fields for a static method
270 pub enum StaticFields {
271     /// Tuple structs/enum variants like this
272     Unnamed(Vec<Span>),
273     /// Normal structs/struct variants.
274     Named(Vec<(Ident, Span)>),
275 }
276
277 /// A summary of the possible sets of fields. See above for details
278 /// and examples
279 pub enum SubstructureFields<'a> {
280     Struct(Vec<FieldInfo>),
281     /**
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
284     variant.
285     */
286     EnumMatching(uint, &'a ast::Variant, Vec<FieldInfo>),
287
288     /**
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.)
292     */
293     EnumNonMatching(&'a [(uint, P<ast::Variant>,
294                           Vec<(Span, Option<Ident>, Gc<Expr>)>)]),
295
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)>),
300 }
301
302
303
304 /**
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.
307 */
308 pub type CombineSubstructureFunc<'a> =
309     |&mut ExtCtxt, Span, &Substructure|: 'a -> Gc<Expr>;
310
311 /**
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
315 */
316 pub type EnumNonMatchFunc<'a> =
317     |&mut ExtCtxt,
318            Span,
319            &[(uint, P<ast::Variant>, Vec<(Span, Option<Ident>, Gc<Expr>)>)],
320            &[Gc<Expr>]|: 'a
321            -> Gc<Expr>;
322
323 pub fn combine_substructure<'a>(f: CombineSubstructureFunc<'a>)
324     -> RefCell<CombineSubstructureFunc<'a>> {
325     RefCell::new(f)
326 }
327
328
329 impl<'a> TraitDef<'a> {
330     pub fn expand(&self,
331                   cx: &mut ExtCtxt,
332                   _mitem: Gc<ast::MetaItem>,
333                   item: Gc<ast::Item>,
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,
338                                        &**struct_def,
339                                        item.ident,
340                                        generics)
341             }
342             ast::ItemEnum(ref enum_def, ref generics) => {
343                 self.expand_enum_def(cx,
344                                      enum_def,
345                                      item.ident,
346                                      generics)
347             }
348             _ => return
349         };
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,
356                 _ => false,
357             }
358         }).map(|a| a.clone()));
359         push(box(GC) ast::Item {
360             attrs: attrs,
361             ..(*newitem).clone()
362         })
363     }
364
365     /**
366      *
367      * Given that we are deriving a trait `Tr` for a type `T<'a, ...,
368      * 'z, A, ..., Z>`, creates an impl like:
369      *
370      * ```ignore
371      *      impl<'a, ..., 'z, A:Tr B1 B2, ..., Z: Tr B1 B2> Tr for T<A, ..., Z> { ... }
372      * ```
373      *
374      * where B1, B2, ... are the bounds given by `bounds_paths`.'
375      *
376      */
377     fn create_derived_impl(&self,
378                            cx: &mut ExtCtxt,
379                            type_ident: Ident,
380                            generics: &Generics,
381                            methods: Vec<Gc<ast::Method>> ) -> Gc<ast::Item> {
382         let trait_path = self.path.to_path(cx, self.span, type_ident, generics);
383
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();
387
388         // Copy the lifetimes
389         lifetimes.extend(generics.lifetimes.iter().map(|l| *l));
390
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))
400                 }).collect();
401             // require the current trait
402             bounds.push(cx.typarambound(trait_path.clone()));
403
404             cx.typaram(self.span,
405                        ty_param.ident,
406                        OwnedSlice::from_vec(bounds),
407                        ty_param.unbound.clone(),
408                        None)
409         }));
410         let trait_generics = Generics {
411             lifetimes: lifetimes,
412             ty_params: OwnedSlice::from_vec(ty_params)
413         };
414
415         // Create the reference to the trait.
416         let trait_ref = cx.trait_ref(trait_path);
417
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)
421         });
422
423         let self_lifetimes = generics.lifetimes.clone();
424
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);
429
430         let attr = cx.attribute(
431             self.span,
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);
438         cx.item(
439             self.span,
440             ident,
441             (vec!(attr)).append(self.attributes.as_slice()),
442             ast::ItemImpl(trait_generics, opt_trait_ref,
443                           self_type, methods))
444     }
445
446     fn expand_struct_def(&self,
447                          cx: &mut ExtCtxt,
448                          struct_def: &StructDef,
449                          type_ident: Ident,
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);
455
456             let body = if method_def.is_static() {
457                 method_def.expand_static_struct_method_body(
458                     cx,
459                     self,
460                     struct_def,
461                     type_ident,
462                     self_args.as_slice(),
463                     nonself_args.as_slice())
464             } else {
465                 method_def.expand_struct_method_body(cx,
466                                                      self,
467                                                      struct_def,
468                                                      type_ident,
469                                                      self_args.as_slice(),
470                                                      nonself_args.as_slice())
471             };
472
473             method_def.create_method(cx, self,
474                                      type_ident, generics,
475                                      explicit_self, tys,
476                                      body)
477         }).collect();
478
479         self.create_derived_impl(cx, type_ident, generics, methods)
480     }
481
482     fn expand_enum_def(&self,
483                        cx: &mut ExtCtxt,
484                        enum_def: &EnumDef,
485                        type_ident: Ident,
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);
491
492             let body = if method_def.is_static() {
493                 method_def.expand_static_enum_method_body(
494                     cx,
495                     self,
496                     enum_def,
497                     type_ident,
498                     self_args.as_slice(),
499                     nonself_args.as_slice())
500             } else {
501                 method_def.expand_enum_method_body(cx,
502                                                    self,
503                                                    enum_def,
504                                                    type_ident,
505                                                    self_args.as_slice(),
506                                                    nonself_args.as_slice())
507             };
508
509             method_def.create_method(cx, self,
510                                      type_ident, generics,
511                                      explicit_self, tys,
512                                      body)
513         }).collect();
514
515         self.create_derived_impl(cx, type_ident, generics, methods)
516     }
517 }
518
519 impl<'a> MethodDef<'a> {
520     fn call_substructure_method(&self,
521                                 cx: &mut ExtCtxt,
522                                 trait_: &TraitDef,
523                                 type_ident: Ident,
524                                 self_args: &[Gc<Expr>],
525                                 nonself_args: &[Gc<Expr>],
526                                 fields: &SubstructureFields)
527         -> Gc<Expr> {
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,
533             fields: fields
534         };
535         let mut f = self.combine_substructure.borrow_mut();
536         let f: &mut CombineSubstructureFunc = &mut *f;
537         (*f)(cx, trait_.span, &substructure)
538     }
539
540     fn get_ret_ty(&self,
541                   cx: &mut ExtCtxt,
542                   trait_: &TraitDef,
543                   generics: &Generics,
544                   type_ident: Ident)
545                   -> P<ast::Ty> {
546         self.ret_ty.to_ty(cx, trait_.span, type_ident, generics)
547     }
548
549     fn is_static(&self) -> bool {
550         self.explicit_self.is_none()
551     }
552
553     fn split_self_nonself_args(&self,
554                                cx: &mut ExtCtxt,
555                                trait_: &TraitDef,
556                                type_ident: Ident,
557                                generics: &Generics)
558         -> (ast::ExplicitSelf, Vec<Gc<Expr>>, Vec<Gc<Expr>>,
559             Vec<(Ident, P<ast::Ty>)>) {
560
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;
565
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);
570
571                 self_args.push(self_expr);
572                 nonstatic = true;
573
574                 explicit_self
575             }
576             None => codemap::respan(trait_.span, ast::SelfStatic),
577         };
578
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));
583
584             let arg_expr = cx.expr_ident(trait_.span, ident);
585
586             match *ty {
587                 // for static methods, just treat any Self
588                 // arguments as a normal arg
589                 Self if nonstatic  => {
590                     self_args.push(arg_expr);
591                 }
592                 Ptr(box Self, _) if nonstatic => {
593                     self_args.push(cx.expr_deref(trait_.span, arg_expr))
594                 }
595                 _ => {
596                     nonself_args.push(arg_expr);
597                 }
598             }
599         }
600
601         (ast_explicit_self, self_args, nonself_args, arg_tys)
602     }
603
604     fn create_method(&self,
605                      cx: &mut ExtCtxt,
606                      trait_: &TraitDef,
607                      type_ident: Ident,
608                      generics: &Generics,
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);
614
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_))
619         };
620         let args = {
621             let args = arg_types.move_iter().map(|(name, ty)| {
622                     cx.arg(trait_.span, name, ty)
623                 });
624             self_arg.move_iter().chain(args).collect()
625         };
626
627         let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident);
628
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);
632
633         // Create the method.
634         box(GC) ast::Method {
635             ident: method_ident,
636             attrs: self.attributes.clone(),
637             generics: fn_generics,
638             explicit_self: explicit_self,
639             fn_style: ast::NormalFn,
640             decl: fn_decl,
641             body: body_block,
642             id: ast::DUMMY_NODE_ID,
643             span: trait_.span,
644             vis: ast::Inherited,
645         }
646     }
647
648     /**
649    ~~~
650     #[deriving(PartialEq)]
651     struct A { x: int, y: int }
652
653     // equivalent to:
654     impl PartialEq for A {
655         fn eq(&self, __arg_1: &A) -> bool {
656             match *self {
657                 A {x: ref __self_0_0, y: ref __self_0_1} => {
658                     match *__arg_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)
661                         }
662                     }
663                 }
664             }
665         }
666     }
667    ~~~
668     */
669     fn expand_struct_method_body(&self,
670                                  cx: &mut ExtCtxt,
671                                  trait_: &TraitDef,
672                                  struct_def: &StructDef,
673                                  type_ident: Ident,
674                                  self_args: &[Gc<Expr>],
675                                  nonself_args: &[Gc<Expr>])
676         -> Gc<Expr> {
677
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,
684                                              type_ident,
685                                              struct_def,
686                                              format!("__self_{}",
687                                                      i).as_slice(),
688                                              ast::MutImmutable);
689             patterns.push(pat);
690             raw_fields.push(ident_expr);
691         }
692
693         // transpose raw_fields
694         let fields = if raw_fields.len() > 0 {
695             raw_fields.get(0)
696                       .iter()
697                       .enumerate()
698                       .map(|(i, &(span, opt_id, field))| {
699                 let other_fields = raw_fields.tail().iter().map(|l| {
700                     match l.get(i) {
701                         &(_, _, ex) => ex
702                     }
703                 }).collect();
704                 FieldInfo {
705                     span: span,
706                     name: opt_id,
707                     self_: field,
708                     other: other_fields
709                 }
710             }).collect()
711         } else {
712             cx.span_bug(trait_.span,
713                         "no self arguments to non-static method in generic \
714                          `deriving`")
715         };
716
717         // body of the inner most destructuring match
718         let mut body = self.call_substructure_method(
719             cx,
720             trait_,
721             type_ident,
722             self_args,
723             nonself_args,
724             &Struct(fields));
725
726         // make a series of nested matches, to destructure the
727         // structs. This is actually right-to-left, but it shouldn't
728         // matter.
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) ))
732         }
733         body
734     }
735
736     fn expand_static_struct_method_body(&self,
737                                         cx: &mut ExtCtxt,
738                                         trait_: &TraitDef,
739                                         struct_def: &StructDef,
740                                         type_ident: Ident,
741                                         self_args: &[Gc<Expr>],
742                                         nonself_args: &[Gc<Expr>])
743         -> Gc<Expr> {
744         let summary = trait_.summarise_struct(cx, struct_def);
745
746         self.call_substructure_method(cx,
747                                       trait_,
748                                       type_ident,
749                                       self_args, nonself_args,
750                                       &StaticStruct(struct_def, summary))
751     }
752
753     /**
754    ~~~
755     #[deriving(PartialEq)]
756     enum A {
757         A1
758         A2(int)
759     }
760
761     // is equivalent to (with const_nonmatching == false)
762
763     impl PartialEq for A {
764         fn eq(&self, __arg_1: &A) {
765             match *self {
766                 A1 => match *__arg_1 {
767                     A1 => true
768                     A2(ref __arg_1_1) => false
769                 },
770                 A2(self_1) => match *__arg_1 {
771                     A1 => false,
772                     A2(ref __arg_1_1) => self_1.eq(__arg_1_1)
773                 }
774             }
775         }
776     }
777    ~~~
778     */
779     fn expand_enum_method_body(&self,
780                                cx: &mut ExtCtxt,
781                                trait_: &TraitDef,
782                                enum_def: &EnumDef,
783                                type_ident: Ident,
784                                self_args: &[Gc<Expr>],
785                                nonself_args: &[Gc<Expr>])
786                                -> 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)
791     }
792
793
794     /**
795     Creates the nested matches for an enum definition recursively, i.e.
796
797    ~~~text
798     match self {
799        Variant1 => match other { Variant1 => matching, Variant2 => nonmatching, ... },
800        Variant2 => match other { Variant1 => nonmatching, Variant2 => matching, ... },
801        ...
802     }
803    ~~~
804
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
809     exponentially large.
810
811     `matching` is Some(n) if all branches in the tree above the
812     current position are variant `n`, `None` otherwise (including on
813     the first call).
814     */
815     fn build_enum_match(&self,
816                         cx: &mut ExtCtxt,
817                         trait_: &TraitDef,
818                         enum_def: &EnumDef,
819                         type_ident: Ident,
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`");
833             }
834
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)
839             };
840
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
845             // field.
846
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());
854
855                     for triple in matches_so_far.tail().iter() {
856                         match triple {
857                             &(_, _, ref other_fields) => {
858                                 for (i, &(_, _, e)) in other_fields.iter().enumerate() {
859                                     enum_matching_fields.get_mut(i).push(e);
860                                 }
861                             }
862                         }
863                     }
864                     let field_tuples =
865                         self_vec.iter()
866                                 .zip(enum_matching_fields.iter())
867                                 .map(|(&(span, id, self_f), other)| {
868                         FieldInfo {
869                             span: span,
870                             name: id,
871                             self_: self_f,
872                             other: (*other).clone()
873                         }
874                     }).collect();
875                     EnumMatching(variant_index, &*variant, field_tuples)
876                 }
877                 None => {
878                     EnumNonMatching(matches_so_far.as_slice())
879                 }
880             };
881             self.call_substructure_method(cx, trait_, type_ident,
882                                           self_args, nonself_args,
883                                           &substructure)
884
885         } else {  // there are still matches to create
886             let current_match_str = if match_count == 0 {
887                 "__self".to_string()
888             } else {
889                 format!("__arg_{}", match_count)
890             };
891
892             let mut arms = Vec::new();
893
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 {
899                     Some(i) => i,
900                     None => cx.span_bug(trait_.span,
901                                         "non-matching variants when required to \
902                                         be matching in generic `deriving`")
903                 };
904
905                 // matching-variant match
906                 let variant = *enum_def.variants.get(index);
907                 let (pattern, idents) = trait_.create_enum_variant_pattern(
908                     cx,
909                     &*variant,
910                     current_match_str.as_slice(),
911                     ast::MutImmutable);
912
913                 matches_so_far.push((index, variant, idents));
914                 let arm_expr = self.build_enum_match(cx,
915                                                      trait_,
916                                                      enum_def,
917                                                      type_ident,
918                                                      self_args, nonself_args,
919                                                      matching,
920                                                      matches_so_far,
921                                                      match_count + 1);
922                 matches_so_far.pop().unwrap();
923                 arms.push(cx.arm(trait_.span, vec!( pattern ), arm_expr));
924
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,
929                                                                   e);
930                     let wild_arm = cx.arm(
931                         trait_.span,
932                         vec!( cx.pat_wild(trait_.span) ),
933                         wild_expr);
934                     arms.push(wild_arm);
935                 }
936             } else {
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(
941                             cx,
942                             &*variant,
943                             current_match_str.as_slice(),
944                             ast::MutImmutable);
945
946                     matches_so_far.push((index, variant, idents));
947                     let new_matching =
948                         match matching {
949                             _ if match_count == 0 => Some(index),
950                             Some(i) if index == i => Some(i),
951                             _ => None
952                         };
953                     let arm_expr = self.build_enum_match(cx,
954                                                          trait_,
955                                                          enum_def,
956                                                          type_ident,
957                                                          self_args, nonself_args,
958                                                          new_matching,
959                                                          matches_so_far,
960                                                          match_count + 1);
961                     matches_so_far.pop().unwrap();
962
963                     let arm = cx.arm(trait_.span, vec!( pattern ), arm_expr);
964                     arms.push(arm);
965                 }
966             }
967
968             // match foo { arm, arm, arm, ... }
969             cx.expr_match(trait_.span, self_args[match_count], arms)
970         }
971     }
972
973     fn expand_static_enum_method_body(&self,
974                                       cx: &mut ExtCtxt,
975                                       trait_: &TraitDef,
976                                       enum_def: &EnumDef,
977                                       type_ident: Ident,
978                                       self_args: &[Gc<Expr>],
979                                       nonself_args: &[Gc<Expr>])
980         -> 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())
986                 }
987                 ast::StructVariantKind(ref struct_def) => {
988                     trait_.summarise_struct(cx, &**struct_def)
989                 }
990             };
991             (ident, v.span, summary)
992         }).collect();
993         self.call_substructure_method(cx, trait_, type_ident,
994                                       self_args, nonself_args,
995                                       &StaticEnum(enum_def, summary))
996     }
997 }
998
999 #[deriving(PartialEq)] // dogfooding!
1000 enum StructType {
1001     Unknown, Record, Tuple
1002 }
1003
1004 // general helper methods.
1005 impl<'a> TraitDef<'a> {
1006     fn set_expn_info(&self,
1007                      cx: &mut ExtCtxt,
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`"),
1011             Some(name) => *name
1012         };
1013         to_set.expn_info = Some(box(GC) codemap::ExpnInfo {
1014             call_site: to_set,
1015             callee: codemap::NameAndSpan {
1016                 name: format!("deriving({})", trait_name),
1017                 format: codemap::MacroAttribute,
1018                 span: Some(self.span)
1019             }
1020         });
1021         to_set
1022     }
1023
1024     fn summarise_struct(&self,
1025                         cx: &mut ExtCtxt,
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),
1034             }
1035         }
1036
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`"),
1041             // named fields
1042             (_, false) => Named(named_idents),
1043             // tuple structs (includes empty structs)
1044             (_, _)     => Unnamed(just_spans)
1045         }
1046     }
1047
1048     fn create_subpatterns(&self,
1049                           cx: &mut ExtCtxt,
1050                           field_paths: Vec<ast::SpannedIdent> ,
1051                           mutbl: ast::Mutability)
1052                           -> Vec<Gc<ast::Pat>> {
1053         field_paths.iter().map(|path| {
1054             cx.pat(path.span,
1055                         ast::PatIdent(ast::BindByRef(mutbl), (*path).clone(), None))
1056             }).collect()
1057     }
1058
1059     fn create_struct_pattern(&self,
1060                              cx: &mut ExtCtxt,
1061                              struct_ident: Ident,
1062                              struct_def: &StructDef,
1063                              prefix: &str,
1064                              mutbl: ast::Mutability)
1065                              -> (Gc<ast::Pat>, Vec<(Span, Option<Ident>, Gc<Expr>)>) {
1066         if struct_def.fields.is_empty() {
1067             return (
1068                 cx.pat_ident_binding_mode(
1069                     self.span, struct_ident, ast::BindByValue(ast::MutImmutable)),
1070                 Vec::new());
1071         }
1072
1073         let matching_path = cx.path(self.span, vec!( struct_ident ));
1074
1075         let mut paths = Vec::new();
1076         let mut ident_expr = Vec::new();
1077         let mut struct_type = Unknown;
1078
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;
1085                     Some(ident)
1086                 }
1087                 ast::UnnamedField(..) if (struct_type == Unknown ||
1088                                           struct_type == Tuple) => {
1089                     struct_type = Tuple;
1090                     None
1091                 }
1092                 _ => {
1093                     cx.span_bug(sp, "a struct with named and unnamed fields in `deriving`");
1094                 }
1095             };
1096             let ident = cx.ident_of(format!("{}_{}", prefix, i).as_slice());
1097             paths.push(codemap::Spanned{span: sp, node: ident});
1098             let val = cx.expr(
1099                 sp, ast::ExprParen(cx.expr_deref(sp, cx.expr_path(cx.path_ident(sp,ident)))));
1100             ident_expr.push((sp, opt_id, val));
1101         }
1102
1103         let subpats = self.create_subpatterns(cx, paths, mutbl);
1104
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 }
1111             }).collect();
1112             cx.pat_struct(self.span, matching_path, field_pats)
1113         } else {
1114             cx.pat_enum(self.span, matching_path, subpats)
1115         };
1116
1117         (pattern, ident_expr)
1118     }
1119
1120     fn create_enum_variant_pattern(&self,
1121                                    cx: &mut ExtCtxt,
1122                                    variant: &ast::Variant,
1123                                    prefix: &str,
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)),
1132                             Vec::new());
1133                 }
1134
1135                 let matching_path = cx.path_ident(variant.span, variant_ident);
1136
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};
1143                     paths.push(path1);
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));
1147                 }
1148
1149                 let subpats = self.create_subpatterns(cx, paths, mutbl);
1150
1151                 (cx.pat_enum(variant.span, matching_path, subpats),
1152                  ident_expr)
1153             }
1154             ast::StructVariantKind(ref struct_def) => {
1155                 self.create_struct_pattern(cx, variant_ident, &**struct_def,
1156                                            prefix, mutbl)
1157             }
1158         }
1159     }
1160 }
1161
1162 /* helpful premade recipes */
1163
1164 /**
1165 Fold the fields. `use_foldl` controls whether this is done
1166 left-to-right (`true`) or right-to-left (`false`).
1167 */
1168 pub fn cs_fold(use_foldl: bool,
1169                f: |&mut ExtCtxt, Span, Gc<Expr>, Gc<Expr>, &[Gc<Expr>]| -> Gc<Expr>,
1170                base: Gc<Expr>,
1171                enum_nonmatch_f: EnumNonMatchFunc,
1172                cx: &mut ExtCtxt,
1173                trait_span: Span,
1174                substructure: &Substructure)
1175                -> Gc<Expr> {
1176     match *substructure.fields {
1177         EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => {
1178             if use_foldl {
1179                 all_fields.iter().fold(base, |old, field| {
1180                     f(cx,
1181                       field.span,
1182                       old,
1183                       field.self_,
1184                       field.other.as_slice())
1185                 })
1186             } else {
1187                 all_fields.iter().rev().fold(base, |old, field| {
1188                     f(cx,
1189                       field.span,
1190                       old,
1191                       field.self_,
1192                       field.other.as_slice())
1193                 })
1194             }
1195         },
1196         EnumNonMatching(ref all_enums) => enum_nonmatch_f(cx, trait_span,
1197                                                           *all_enums,
1198                                                           substructure.nonself_args),
1199         StaticEnum(..) | StaticStruct(..) => {
1200             cx.span_bug(trait_span, "static function in `deriving`")
1201         }
1202     }
1203 }
1204
1205
1206 /**
1207 Call the method that is being derived on all the fields, and then
1208 process the collected results. i.e.
1209
1210 ~~~
1211 f(cx, span, ~[self_1.method(__arg_1_1, __arg_2_1),
1212               self_2.method(__arg_1_2, __arg_2_2)])
1213 ~~~
1214 */
1215 #[inline]
1216 pub fn cs_same_method(f: |&mut ExtCtxt, Span, Vec<Gc<Expr>>| -> Gc<Expr>,
1217                       enum_nonmatch_f: EnumNonMatchFunc,
1218                       cx: &mut ExtCtxt,
1219                       trait_span: Span,
1220                       substructure: &Substructure)
1221                       -> Gc<Expr> {
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,
1227                                     field.self_,
1228                                     substructure.method_ident,
1229                                     field.other.iter()
1230                                                .map(|e| cx.expr_addr_of(field.span, *e))
1231                                                .collect())
1232             }).collect();
1233
1234             f(cx, trait_span, called)
1235         },
1236         EnumNonMatching(ref all_enums) => enum_nonmatch_f(cx, trait_span,
1237                                                           *all_enums,
1238                                                           substructure.nonself_args),
1239         StaticEnum(..) | StaticStruct(..) => {
1240             cx.span_bug(trait_span, "static function in `deriving`")
1241         }
1242     }
1243 }
1244
1245 /**
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`).
1249 */
1250 #[inline]
1251 pub fn cs_same_method_fold(use_foldl: bool,
1252                            f: |&mut ExtCtxt, Span, Gc<Expr>, Gc<Expr>| -> Gc<Expr>,
1253                            base: Gc<Expr>,
1254                            enum_nonmatch_f: EnumNonMatchFunc,
1255                            cx: &mut ExtCtxt,
1256                            trait_span: Span,
1257                            substructure: &Substructure)
1258                            -> Gc<Expr> {
1259     cs_same_method(
1260         |cx, span, vals| {
1261             if use_foldl {
1262                 vals.iter().fold(base, |old, &new| {
1263                     f(cx, span, old, new)
1264                 })
1265             } else {
1266                 vals.iter().rev().fold(base, |old, &new| {
1267                     f(cx, span, old, new)
1268                 })
1269             }
1270         },
1271         enum_nonmatch_f,
1272         cx, trait_span, substructure)
1273 }
1274
1275 /**
1276 Use a given binop to combine the result of calling the derived method
1277 on all the fields.
1278 */
1279 #[inline]
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,
1288                            binop,
1289                            old, new)
1290
1291         },
1292         base,
1293         enum_nonmatch_f,
1294         cx, trait_span, substructure)
1295 }
1296
1297 /// cs_binop with binop == or
1298 #[inline]
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),
1303              enum_nonmatch_f,
1304              cx, span, substructure)
1305 }
1306
1307 /// cs_binop with binop == and
1308 #[inline]
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),
1313              enum_nonmatch_f,
1314              cx, span, substructure)
1315 }