]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/ext/deriving/generic/mod.rs
auto merge of #15586 : aturon/rust/stability-dashboard, 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 //! - `EnumNonMatchingCollapsed` when `Self` is an enum and the arguments
41 //!   are not the same variant (e.g. `None`, `Some(1)` and `None`).
42 //! - `StaticEnum` and `StaticStruct` for static methods, where the type
43 //!   being derived upon is either an enum or struct respectively. (Any
44 //!   argument with type Self is just grouped among the non-self
45 //!   arguments.)
46 //!
47 //! In the first two cases, the values from the corresponding fields in
48 //! all the arguments are grouped together. For `EnumNonMatchingCollapsed`
49 //! this isn't possible (different variants have different fields), so the
50 //! fields are inaccessible. (Previous versions of the deriving infrastructure
51 //! had a way to expand into code that could access them, at the cost of
52 //! generating exponential amounts of code; see issue #15375). There are no
53 //! fields with values in the static cases, so these are treated entirely
54 //! differently.
55 //!
56 //! The non-static cases have `Option<ident>` in several places associated
57 //! with field `expr`s. This represents the name of the field it is
58 //! associated with. It is only not `None` when the associated field has
59 //! an identifier in the source code. For example, the `x`s in the
60 //! following snippet
61 //!
62 //! ```rust
63 //! struct A { x : int }
64 //!
65 //! struct B(int);
66 //!
67 //! enum C {
68 //!     C0(int),
69 //!     C1 { x: int }
70 //! }
71 //! ```
72 //!
73 //! The `int`s in `B` and `C0` don't have an identifier, so the
74 //! `Option<ident>`s would be `None` for them.
75 //!
76 //! In the static cases, the structure is summarised, either into the just
77 //! spans of the fields or a list of spans and the field idents (for tuple
78 //! structs and record structs, respectively), or a list of these, for
79 //! enums (one for each variant). For empty struct and empty enum
80 //! variants, it is represented as a count of 0.
81 //!
82 //! # Examples
83 //!
84 //! The following simplified `PartialEq` is used for in-code examples:
85 //!
86 //! ```rust
87 //! trait PartialEq {
88 //!     fn eq(&self, other: &Self);
89 //! }
90 //! impl PartialEq for int {
91 //!     fn eq(&self, other: &int) -> bool {
92 //!         *self == *other
93 //!     }
94 //! }
95 //! ```
96 //!
97 //! Some examples of the values of `SubstructureFields` follow, using the
98 //! above `PartialEq`, `A`, `B` and `C`.
99 //!
100 //! ## Structs
101 //!
102 //! When generating the `expr` for the `A` impl, the `SubstructureFields` is
103 //!
104 //! ~~~text
105 //! Struct(~[FieldInfo {
106 //!            span: <span of x>
107 //!            name: Some(<ident of x>),
108 //!            self_: <expr for &self.x>,
109 //!            other: ~[<expr for &other.x]
110 //!          }])
111 //! ~~~
112 //!
113 //! For the `B` impl, called with `B(a)` and `B(b)`,
114 //!
115 //! ~~~text
116 //! Struct(~[FieldInfo {
117 //!           span: <span of `int`>,
118 //!           name: None,
119 //!           <expr for &a>
120 //!           ~[<expr for &b>]
121 //!          }])
122 //! ~~~
123 //!
124 //! ## Enums
125 //!
126 //! When generating the `expr` for a call with `self == C0(a)` and `other
127 //! == C0(b)`, the SubstructureFields is
128 //!
129 //! ~~~text
130 //! EnumMatching(0, <ast::Variant for C0>,
131 //!              ~[FieldInfo {
132 //!                 span: <span of int>
133 //!                 name: None,
134 //!                 self_: <expr for &a>,
135 //!                 other: ~[<expr for &b>]
136 //!               }])
137 //! ~~~
138 //!
139 //! For `C1 {x}` and `C1 {x}`,
140 //!
141 //! ~~~text
142 //! EnumMatching(1, <ast::Variant for C1>,
143 //!              ~[FieldInfo {
144 //!                 span: <span of x>
145 //!                 name: Some(<ident of x>),
146 //!                 self_: <expr for &self.x>,
147 //!                 other: ~[<expr for &other.x>]
148 //!                }])
149 //! ~~~
150 //!
151 //! For `C0(a)` and `C1 {x}` ,
152 //!
153 //! ~~~text
154 //! EnumNonMatchingCollapsed(
155 //!     ~[<ident of self>, <ident of __arg_1>],
156 //!     &[<ast::Variant for C0>, <ast::Variant for C1>],
157 //!     &[<ident for self index value>, <ident of __arg_1 index value>])
158 //! ~~~
159 //!
160 //! It is the same for when the arguments are flipped to `C1 {x}` and
161 //! `C0(a)`; the only difference is what the values of the identifiers
162 //! <ident for self index value> and <ident of __arg_1 index value> will
163 //! be in the generated code.
164 //!
165 //! `EnumNonMatchingCollapsed` deliberately provides far less information
166 //! than is generally available for a given pair of variants; see #15375
167 //! for discussion.
168 //!
169 //! ## Static
170 //!
171 //! A static method on the above would result in,
172 //!
173 //! ~~~text
174 //! StaticStruct(<ast::StructDef of A>, Named(~[(<ident of x>, <span of x>)]))
175 //!
176 //! StaticStruct(<ast::StructDef of B>, Unnamed(~[<span of x>]))
177 //!
178 //! StaticEnum(<ast::EnumDef of C>, ~[(<ident of C0>, <span of C0>, Unnamed(~[<span of int>])),
179 //!                                   (<ident of C1>, <span of C1>,
180 //!                                    Named(~[(<ident of x>, <span of x>)]))])
181 //! ~~~
182
183 use std::cell::RefCell;
184 use std::gc::{Gc, GC};
185
186 use ast;
187 use ast::{P, EnumDef, Expr, Ident, Generics, StructDef};
188 use ast_util;
189 use attr;
190 use attr::AttrMetaMethods;
191 use ext::base::ExtCtxt;
192 use ext::build::AstBuilder;
193 use codemap;
194 use codemap::Span;
195 use owned_slice::OwnedSlice;
196 use parse::token::InternedString;
197 use parse::token::special_idents;
198
199 use self::ty::*;
200
201 pub mod ty;
202
203 pub struct TraitDef<'a> {
204     /// The span for the current #[deriving(Foo)] header.
205     pub span: Span,
206
207     pub attributes: Vec<ast::Attribute>,
208
209     /// Path of the trait, including any type parameters
210     pub path: Path<'a>,
211
212     /// Additional bounds required of any type parameters of the type,
213     /// other than the current trait
214     pub additional_bounds: Vec<Ty<'a>>,
215
216     /// Any extra lifetimes and/or bounds, e.g. `D: serialize::Decoder`
217     pub generics: LifetimeBounds<'a>,
218
219     pub methods: Vec<MethodDef<'a>>,
220 }
221
222
223 pub struct MethodDef<'a> {
224     /// name of the method
225     pub name: &'a str,
226     /// List of generics, e.g. `R: rand::Rng`
227     pub generics: LifetimeBounds<'a>,
228
229     /// Whether there is a self argument (outer Option) i.e. whether
230     /// this is a static function, and whether it is a pointer (inner
231     /// Option)
232     pub explicit_self: Option<Option<PtrTy<'a>>>,
233
234     /// Arguments other than the self argument
235     pub args: Vec<Ty<'a>>,
236
237     /// Return type
238     pub ret_ty: Ty<'a>,
239
240     pub attributes: Vec<ast::Attribute>,
241
242     pub combine_substructure: RefCell<CombineSubstructureFunc<'a>>,
243 }
244
245 /// All the data about the data structure/method being derived upon.
246 pub struct Substructure<'a> {
247     /// ident of self
248     pub type_ident: Ident,
249     /// ident of the method
250     pub method_ident: Ident,
251     /// dereferenced access to any Self or Ptr(Self, _) arguments
252     pub self_args: &'a [Gc<Expr>],
253     /// verbatim access to any other arguments
254     pub nonself_args: &'a [Gc<Expr>],
255     pub fields: &'a SubstructureFields<'a>
256 }
257
258 /// Summary of the relevant parts of a struct/enum field.
259 pub struct FieldInfo {
260     pub span: Span,
261     /// None for tuple structs/normal enum variants, Some for normal
262     /// structs/struct enum variants.
263     pub name: Option<Ident>,
264     /// The expression corresponding to this field of `self`
265     /// (specifically, a reference to it).
266     pub self_: Gc<Expr>,
267     /// The expressions corresponding to references to this field in
268     /// the other Self arguments.
269     pub other: Vec<Gc<Expr>>,
270 }
271
272 /// Fields for a static method
273 pub enum StaticFields {
274     /// Tuple structs/enum variants like this
275     Unnamed(Vec<Span>),
276     /// Normal structs/struct variants.
277     Named(Vec<(Ident, Span)>),
278 }
279
280 /// A summary of the possible sets of fields. See above for details
281 /// and examples
282 pub enum SubstructureFields<'a> {
283     Struct(Vec<FieldInfo>),
284     /**
285     Matching variants of the enum: variant index, ast::Variant,
286     fields: the field name is only non-`None` in the case of a struct
287     variant.
288     */
289     EnumMatching(uint, &'a ast::Variant, Vec<FieldInfo>),
290
291     /**
292     non-matching variants of the enum, but with all state hidden from
293     the consequent code.  The first component holds Idents for all of
294     the Self arguments; the second component is a slice of all of the
295     variants for the enum itself, and the third component is a list of
296     Idents bound to the variant index values for each of the actual
297     input Self arguments.
298     */
299     EnumNonMatchingCollapsed(Vec<Ident>, &'a [Gc<ast::Variant>], &'a [Ident]),
300
301     /// A static method where Self is a struct.
302     StaticStruct(&'a ast::StructDef, StaticFields),
303     /// A static method where Self is an enum.
304     StaticEnum(&'a ast::EnumDef, Vec<(Ident, Span, StaticFields)>),
305 }
306
307
308
309 /**
310 Combine the values of all the fields together. The last argument is
311 all the fields of all the structures, see above for details.
312 */
313 pub type CombineSubstructureFunc<'a> =
314     |&mut ExtCtxt, Span, &Substructure|: 'a -> Gc<Expr>;
315
316 /**
317 Deal with non-matching enum variants.  The tuple is a list of
318 identifiers (one for each Self argument, which could be any of the
319 variants since they have been collapsed together) and the identifiers
320 holding the variant index value for each of the Self arguments.  The
321 last argument is all the non-Self args of the method being derived.
322 */
323 pub type EnumNonMatchCollapsedFunc<'a> =
324     |&mut ExtCtxt,
325            Span,
326            (&[Ident], &[Ident]),
327            &[Gc<Expr>]|: 'a
328            -> Gc<Expr>;
329
330 pub fn combine_substructure<'a>(f: CombineSubstructureFunc<'a>)
331     -> RefCell<CombineSubstructureFunc<'a>> {
332     RefCell::new(f)
333 }
334
335
336 impl<'a> TraitDef<'a> {
337     pub fn expand(&self,
338                   cx: &mut ExtCtxt,
339                   _mitem: Gc<ast::MetaItem>,
340                   item: Gc<ast::Item>,
341                   push: |Gc<ast::Item>|) {
342         let newitem = match item.node {
343             ast::ItemStruct(ref struct_def, ref generics) => {
344                 self.expand_struct_def(cx,
345                                        &**struct_def,
346                                        item.ident,
347                                        generics)
348             }
349             ast::ItemEnum(ref enum_def, ref generics) => {
350                 self.expand_enum_def(cx,
351                                      enum_def,
352                                      item.ident,
353                                      generics)
354             }
355             _ => return
356         };
357         // Keep the lint attributes of the previous item to control how the
358         // generated implementations are linted
359         let mut attrs = newitem.attrs.clone();
360         attrs.extend(item.attrs.iter().filter(|a| {
361             match a.name().get() {
362                 "allow" | "warn" | "deny" | "forbid" => true,
363                 _ => false,
364             }
365         }).map(|a| a.clone()));
366         push(box(GC) ast::Item {
367             attrs: attrs,
368             ..(*newitem).clone()
369         })
370     }
371
372     /**
373      *
374      * Given that we are deriving a trait `Tr` for a type `T<'a, ...,
375      * 'z, A, ..., Z>`, creates an impl like:
376      *
377      * ```ignore
378      *      impl<'a, ..., 'z, A:Tr B1 B2, ..., Z: Tr B1 B2> Tr for T<A, ..., Z> { ... }
379      * ```
380      *
381      * where B1, B2, ... are the bounds given by `bounds_paths`.'
382      *
383      */
384     fn create_derived_impl(&self,
385                            cx: &mut ExtCtxt,
386                            type_ident: Ident,
387                            generics: &Generics,
388                            methods: Vec<Gc<ast::Method>> ) -> Gc<ast::Item> {
389         let trait_path = self.path.to_path(cx, self.span, type_ident, generics);
390
391         let Generics { mut lifetimes, ty_params } =
392             self.generics.to_generics(cx, self.span, type_ident, generics);
393         let mut ty_params = ty_params.into_vec();
394
395         // Copy the lifetimes
396         lifetimes.extend(generics.lifetimes.iter().map(|l| *l));
397
398         // Create the type parameters.
399         ty_params.extend(generics.ty_params.iter().map(|ty_param| {
400             // I don't think this can be moved out of the loop, since
401             // a TyParamBound requires an ast id
402             let mut bounds: Vec<_> =
403                 // extra restrictions on the generics parameters to the type being derived upon
404                 self.additional_bounds.iter().map(|p| {
405                     cx.typarambound(p.to_path(cx, self.span,
406                                                   type_ident, generics))
407                 }).collect();
408             // require the current trait
409             bounds.push(cx.typarambound(trait_path.clone()));
410
411             cx.typaram(self.span,
412                        ty_param.ident,
413                        OwnedSlice::from_vec(bounds),
414                        ty_param.unbound.clone(),
415                        None)
416         }));
417         let trait_generics = Generics {
418             lifetimes: lifetimes,
419             ty_params: OwnedSlice::from_vec(ty_params)
420         };
421
422         // Create the reference to the trait.
423         let trait_ref = cx.trait_ref(trait_path);
424
425         // Create the type parameters on the `self` path.
426         let self_ty_params = generics.ty_params.map(|ty_param| {
427             cx.ty_ident(self.span, ty_param.ident)
428         });
429
430         let self_lifetimes = generics.lifetimes.clone();
431
432         // Create the type of `self`.
433         let self_type = cx.ty_path(
434             cx.path_all(self.span, false, vec!( type_ident ), self_lifetimes,
435                         self_ty_params.into_vec()), None);
436
437         let attr = cx.attribute(
438             self.span,
439             cx.meta_word(self.span,
440                          InternedString::new("automatically_derived")));
441         // Just mark it now since we know that it'll end up used downstream
442         attr::mark_used(&attr);
443         let opt_trait_ref = Some(trait_ref);
444         let ident = ast_util::impl_pretty_name(&opt_trait_ref, &*self_type);
445         cx.item(
446             self.span,
447             ident,
448             (vec!(attr)).append(self.attributes.as_slice()),
449             ast::ItemImpl(trait_generics, opt_trait_ref,
450                           self_type, methods))
451     }
452
453     fn expand_struct_def(&self,
454                          cx: &mut ExtCtxt,
455                          struct_def: &StructDef,
456                          type_ident: Ident,
457                          generics: &Generics) -> Gc<ast::Item> {
458         let methods = self.methods.iter().map(|method_def| {
459             let (explicit_self, self_args, nonself_args, tys) =
460                 method_def.split_self_nonself_args(
461                     cx, self, type_ident, generics);
462
463             let body = if method_def.is_static() {
464                 method_def.expand_static_struct_method_body(
465                     cx,
466                     self,
467                     struct_def,
468                     type_ident,
469                     self_args.as_slice(),
470                     nonself_args.as_slice())
471             } else {
472                 method_def.expand_struct_method_body(cx,
473                                                      self,
474                                                      struct_def,
475                                                      type_ident,
476                                                      self_args.as_slice(),
477                                                      nonself_args.as_slice())
478             };
479
480             method_def.create_method(cx, self,
481                                      type_ident, generics,
482                                      explicit_self, tys,
483                                      body)
484         }).collect();
485
486         self.create_derived_impl(cx, type_ident, generics, methods)
487     }
488
489     fn expand_enum_def(&self,
490                        cx: &mut ExtCtxt,
491                        enum_def: &EnumDef,
492                        type_ident: Ident,
493                        generics: &Generics) -> Gc<ast::Item> {
494         let methods = self.methods.iter().map(|method_def| {
495             let (explicit_self, self_args, nonself_args, tys) =
496                 method_def.split_self_nonself_args(cx, self,
497                                                    type_ident, generics);
498
499             let body = if method_def.is_static() {
500                 method_def.expand_static_enum_method_body(
501                     cx,
502                     self,
503                     enum_def,
504                     type_ident,
505                     self_args.as_slice(),
506                     nonself_args.as_slice())
507             } else {
508                 method_def.expand_enum_method_body(cx,
509                                                    self,
510                                                    enum_def,
511                                                    type_ident,
512                                                    self_args.as_slice(),
513                                                    nonself_args.as_slice())
514             };
515
516             method_def.create_method(cx, self,
517                                      type_ident, generics,
518                                      explicit_self, tys,
519                                      body)
520         }).collect();
521
522         self.create_derived_impl(cx, type_ident, generics, methods)
523     }
524 }
525
526 fn variant_to_pat(cx: &mut ExtCtxt, sp: Span, variant: &ast::Variant)
527                   -> Gc<ast::Pat> {
528     let ident = cx.path_ident(sp, variant.node.name);
529     cx.pat(sp, match variant.node.kind {
530         ast::TupleVariantKind(..) => ast::PatEnum(ident, None),
531         ast::StructVariantKind(..) => ast::PatStruct(ident, Vec::new(), true),
532     })
533 }
534
535 impl<'a> MethodDef<'a> {
536     fn call_substructure_method(&self,
537                                 cx: &mut ExtCtxt,
538                                 trait_: &TraitDef,
539                                 type_ident: Ident,
540                                 self_args: &[Gc<Expr>],
541                                 nonself_args: &[Gc<Expr>],
542                                 fields: &SubstructureFields)
543         -> Gc<Expr> {
544         let substructure = Substructure {
545             type_ident: type_ident,
546             method_ident: cx.ident_of(self.name),
547             self_args: self_args,
548             nonself_args: nonself_args,
549             fields: fields
550         };
551         let mut f = self.combine_substructure.borrow_mut();
552         let f: &mut CombineSubstructureFunc = &mut *f;
553         (*f)(cx, trait_.span, &substructure)
554     }
555
556     fn get_ret_ty(&self,
557                   cx: &mut ExtCtxt,
558                   trait_: &TraitDef,
559                   generics: &Generics,
560                   type_ident: Ident)
561                   -> P<ast::Ty> {
562         self.ret_ty.to_ty(cx, trait_.span, type_ident, generics)
563     }
564
565     fn is_static(&self) -> bool {
566         self.explicit_self.is_none()
567     }
568
569     fn split_self_nonself_args(&self,
570                                cx: &mut ExtCtxt,
571                                trait_: &TraitDef,
572                                type_ident: Ident,
573                                generics: &Generics)
574         -> (ast::ExplicitSelf, Vec<Gc<Expr>>, Vec<Gc<Expr>>,
575             Vec<(Ident, P<ast::Ty>)>) {
576
577         let mut self_args = Vec::new();
578         let mut nonself_args = Vec::new();
579         let mut arg_tys = Vec::new();
580         let mut nonstatic = false;
581
582         let ast_explicit_self = match self.explicit_self {
583             Some(ref self_ptr) => {
584                 let (self_expr, explicit_self) =
585                     ty::get_explicit_self(cx, trait_.span, self_ptr);
586
587                 self_args.push(self_expr);
588                 nonstatic = true;
589
590                 explicit_self
591             }
592             None => codemap::respan(trait_.span, ast::SelfStatic),
593         };
594
595         for (i, ty) in self.args.iter().enumerate() {
596             let ast_ty = ty.to_ty(cx, trait_.span, type_ident, generics);
597             let ident = cx.ident_of(format!("__arg_{}", i).as_slice());
598             arg_tys.push((ident, ast_ty));
599
600             let arg_expr = cx.expr_ident(trait_.span, ident);
601
602             match *ty {
603                 // for static methods, just treat any Self
604                 // arguments as a normal arg
605                 Self if nonstatic  => {
606                     self_args.push(arg_expr);
607                 }
608                 Ptr(box Self, _) if nonstatic => {
609                     self_args.push(cx.expr_deref(trait_.span, arg_expr))
610                 }
611                 _ => {
612                     nonself_args.push(arg_expr);
613                 }
614             }
615         }
616
617         (ast_explicit_self, self_args, nonself_args, arg_tys)
618     }
619
620     fn create_method(&self,
621                      cx: &mut ExtCtxt,
622                      trait_: &TraitDef,
623                      type_ident: Ident,
624                      generics: &Generics,
625                      explicit_self: ast::ExplicitSelf,
626                      arg_types: Vec<(Ident, P<ast::Ty>)> ,
627                      body: Gc<Expr>) -> Gc<ast::Method> {
628         // create the generics that aren't for Self
629         let fn_generics = self.generics.to_generics(cx, trait_.span, type_ident, generics);
630
631         let self_arg = match explicit_self.node {
632             ast::SelfStatic => None,
633             // creating fresh self id
634             _ => Some(ast::Arg::new_self(trait_.span, ast::MutImmutable, special_idents::self_))
635         };
636         let args = {
637             let args = arg_types.move_iter().map(|(name, ty)| {
638                     cx.arg(trait_.span, name, ty)
639                 });
640             self_arg.move_iter().chain(args).collect()
641         };
642
643         let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident);
644
645         let method_ident = cx.ident_of(self.name);
646         let fn_decl = cx.fn_decl(args, ret_type);
647         let body_block = cx.block_expr(body);
648
649         // Create the method.
650         box(GC) ast::Method {
651             ident: method_ident,
652             attrs: self.attributes.clone(),
653             generics: fn_generics,
654             explicit_self: explicit_self,
655             fn_style: ast::NormalFn,
656             decl: fn_decl,
657             body: body_block,
658             id: ast::DUMMY_NODE_ID,
659             span: trait_.span,
660             vis: ast::Inherited,
661         }
662     }
663
664     /**
665    ~~~
666     #[deriving(PartialEq)]
667     struct A { x: int, y: int }
668
669     // equivalent to:
670     impl PartialEq for A {
671         fn eq(&self, __arg_1: &A) -> bool {
672             match *self {
673                 A {x: ref __self_0_0, y: ref __self_0_1} => {
674                     match *__arg_1 {
675                         A {x: ref __self_1_0, y: ref __self_1_1} => {
676                             __self_0_0.eq(__self_1_0) && __self_0_1.eq(__self_1_1)
677                         }
678                     }
679                 }
680             }
681         }
682     }
683    ~~~
684     */
685     fn expand_struct_method_body(&self,
686                                  cx: &mut ExtCtxt,
687                                  trait_: &TraitDef,
688                                  struct_def: &StructDef,
689                                  type_ident: Ident,
690                                  self_args: &[Gc<Expr>],
691                                  nonself_args: &[Gc<Expr>])
692         -> Gc<Expr> {
693
694         let mut raw_fields = Vec::new(); // ~[[fields of self],
695                                  // [fields of next Self arg], [etc]]
696         let mut patterns = Vec::new();
697         for i in range(0u, self_args.len()) {
698             let (pat, ident_expr) =
699                 trait_.create_struct_pattern(cx,
700                                              type_ident,
701                                              struct_def,
702                                              format!("__self_{}",
703                                                      i).as_slice(),
704                                              ast::MutImmutable);
705             patterns.push(pat);
706             raw_fields.push(ident_expr);
707         }
708
709         // transpose raw_fields
710         let fields = if raw_fields.len() > 0 {
711             raw_fields.get(0)
712                       .iter()
713                       .enumerate()
714                       .map(|(i, &(span, opt_id, field))| {
715                 let other_fields = raw_fields.tail().iter().map(|l| {
716                     match l.get(i) {
717                         &(_, _, ex) => ex
718                     }
719                 }).collect();
720                 FieldInfo {
721                     span: span,
722                     name: opt_id,
723                     self_: field,
724                     other: other_fields
725                 }
726             }).collect()
727         } else {
728             cx.span_bug(trait_.span,
729                         "no self arguments to non-static method in generic \
730                          `deriving`")
731         };
732
733         // body of the inner most destructuring match
734         let mut body = self.call_substructure_method(
735             cx,
736             trait_,
737             type_ident,
738             self_args,
739             nonself_args,
740             &Struct(fields));
741
742         // make a series of nested matches, to destructure the
743         // structs. This is actually right-to-left, but it shouldn't
744         // matter.
745         for (&arg_expr, &pat) in self_args.iter().zip(patterns.iter()) {
746             body = cx.expr_match(trait_.span, arg_expr,
747                                      vec!( cx.arm(trait_.span, vec!(pat), body) ))
748         }
749         body
750     }
751
752     fn expand_static_struct_method_body(&self,
753                                         cx: &mut ExtCtxt,
754                                         trait_: &TraitDef,
755                                         struct_def: &StructDef,
756                                         type_ident: Ident,
757                                         self_args: &[Gc<Expr>],
758                                         nonself_args: &[Gc<Expr>])
759         -> Gc<Expr> {
760         let summary = trait_.summarise_struct(cx, struct_def);
761
762         self.call_substructure_method(cx,
763                                       trait_,
764                                       type_ident,
765                                       self_args, nonself_args,
766                                       &StaticStruct(struct_def, summary))
767     }
768
769     /**
770    ~~~
771     #[deriving(PartialEq)]
772     enum A {
773         A1,
774         A2(int)
775     }
776
777     // is equivalent to
778
779     impl PartialEq for A {
780         fn eq(&self, __arg_1: &A) -> ::bool {
781             match (&*self, &*__arg_1) {
782                 (&A1, &A1) => true,
783                 (&A2(ref __self_0),
784                  &A2(ref __arg_1_0)) => (*__self_0).eq(&(*__arg_1_0)),
785                 _ => {
786                     let __self_vi = match *self { A1(..) => 0u, A2(..) => 1u };
787                     let __arg_1_vi = match *__arg_1 { A1(..) => 0u, A2(..) => 1u };
788                     false
789                 }
790             }
791         }
792     }
793    ~~~
794
795     (Of course `__self_vi` and `__arg_1_vi` are unused for
796      `PartialEq`, and those subcomputations will hopefully be removed
797      as their results are unused.  The point of `__self_vi` and
798      `__arg_1_vi` is for `PartialOrd`; see #15503.)
799     */
800     fn expand_enum_method_body(&self,
801                                cx: &mut ExtCtxt,
802                                trait_: &TraitDef,
803                                enum_def: &EnumDef,
804                                type_ident: Ident,
805                                self_args: &[Gc<Expr>],
806                                nonself_args: &[Gc<Expr>])
807                                -> Gc<Expr> {
808         self.build_enum_match_tuple(
809             cx, trait_, enum_def, type_ident, self_args, nonself_args)
810     }
811
812
813     /**
814     Creates a match for a tuple of all `self_args`, where either all
815     variants match, or it falls into a catch-all for when one variant
816     does not match.
817
818     There are N + 1 cases because is a case for each of the N
819     variants where all of the variants match, and one catch-all for
820     when one does not match.
821
822     The catch-all handler is provided access the variant index values
823     for each of the self-args, carried in precomputed variables. (Nota
824     bene: the variant index values are not necessarily the
825     discriminant values.  See issue #15523.)
826
827     ~~~text
828     match (this, that, ...) {
829       (Variant1, Variant1, Variant1) => ... // delegate Matching on Variant1
830       (Variant2, Variant2, Variant2) => ... // delegate Matching on Variant2
831       ...
832       _ => {
833         let __this_vi = match this { Variant1 => 0u, Variant2 => 1u, ... };
834         let __that_vi = match that { Variant1 => 0u, Variant2 => 1u, ... };
835         ... // catch-all remainder can inspect above variant index values.
836       }
837     }
838     ~~~
839     */
840     fn build_enum_match_tuple(
841         &self,
842         cx: &mut ExtCtxt,
843         trait_: &TraitDef,
844         enum_def: &EnumDef,
845         type_ident: Ident,
846         self_args: &[Gc<Expr>],
847         nonself_args: &[Gc<Expr>]) -> Gc<Expr> {
848
849         let sp = trait_.span;
850         let variants = &enum_def.variants;
851
852         let self_arg_names = self_args.iter().enumerate()
853             .map(|(arg_count, _self_arg)| {
854                 if arg_count == 0 {
855                     "__self".to_string()
856                 } else {
857                     format!("__arg_{}", arg_count)
858                 }
859             })
860             .collect::<Vec<String>>();
861
862         let self_arg_idents = self_arg_names.iter()
863             .map(|name|cx.ident_of(name.as_slice()))
864             .collect::<Vec<ast::Ident>>();
865
866         // The `vi_idents` will be bound, solely in the catch-all, to
867         // a series of let statements mapping each self_arg to a uint
868         // corresponding to its variant index.
869         let vi_idents : Vec<ast::Ident> = self_arg_names.iter()
870             .map(|name| { let vi_suffix = format!("{:s}_vi", name.as_slice());
871                           cx.ident_of(vi_suffix.as_slice()) })
872             .collect::<Vec<ast::Ident>>();
873
874         // Builds, via callback to call_substructure_method, the
875         // delegated expression that handles the catch-all case,
876         // using `__variants_tuple` to drive logic if necessary.
877         let catch_all_substructure = EnumNonMatchingCollapsed(
878             self_arg_idents, variants.as_slice(), vi_idents.as_slice());
879
880         // These arms are of the form:
881         // (Variant1, Variant1, ...) => Body1
882         // (Variant2, Variant2, ...) => Body2
883         // ...
884         // where each tuple has length = self_args.len()
885         let mut match_arms : Vec<ast::Arm> = variants.iter().enumerate()
886             .map(|(index, &variant)| {
887
888                 // These self_pats have form Variant1, Variant2, ...
889                 let self_pats : Vec<(Gc<ast::Pat>,
890                                      Vec<(Span, Option<Ident>, Gc<Expr>)>)>;
891                 self_pats = self_arg_names.iter()
892                     .map(|self_arg_name|
893                          trait_.create_enum_variant_pattern(
894                              cx, &*variant, self_arg_name.as_slice(),
895                              ast::MutImmutable))
896                     .collect();
897
898                 // A single arm has form (&VariantK, &VariantK, ...) => BodyK
899                 // (see "Final wrinkle" note below for why.)
900                 let subpats = self_pats.iter()
901                     .map(|&(p, ref _idents)| cx.pat(sp, ast::PatRegion(p)))
902                     .collect::<Vec<Gc<ast::Pat>>>();
903
904                 // Here is the pat = `(&VariantK, &VariantK, ...)`
905                 let single_pat = cx.pat(sp, ast::PatTup(subpats));
906
907                 // For the BodyK, we need to delegate to our caller,
908                 // passing it an EnumMatching to indicate which case
909                 // we are in.
910
911                 // All of the Self args have the same variant in these
912                 // cases.  So we transpose the info in self_pats to
913                 // gather the getter expressions together, in the form
914                 // that EnumMatching expects.
915
916                 // The transposition is driven by walking across the
917                 // arg fields of the variant for the first self pat.
918                 let &(_, ref self_arg_fields) = self_pats.get(0);
919
920                 let field_tuples : Vec<FieldInfo>;
921
922                 field_tuples = self_arg_fields.iter().enumerate()
923                     // For each arg field of self, pull out its getter expr ...
924                     .map(|(field_index, &(sp, opt_ident, self_getter_expr))| {
925                         // ... but FieldInfo also wants getter expr
926                         // for matching other arguments of Self type;
927                         // so walk across the *other* self_pats and
928                         // pull out getter for same field in each of
929                         // them (using `field_index` tracked above).
930                         // That is the heart of the transposition.
931                         let others = self_pats.tail().iter()
932                             .map(|&(_pat, ref fields)| {
933
934                                 let &(_, _opt_ident, other_getter_expr) =
935                                     fields.get(field_index);
936
937                                 // All Self args have same variant, so
938                                 // opt_idents are the same.  (Assert
939                                 // here to make it self-evident that
940                                 // it is okay to ignore `_opt_ident`.)
941                                 assert!(opt_ident == _opt_ident);
942
943                                 other_getter_expr
944                             }).collect::<Vec<Gc<Expr>>>();
945
946                         FieldInfo { span: sp,
947                                     name: opt_ident,
948                                     self_: self_getter_expr,
949                                     other: others,
950                         }
951                     }).collect::<Vec<FieldInfo>>();
952
953                 // Now, for some given VariantK, we have built up
954                 // expressions for referencing every field of every
955                 // Self arg, assuming all are instances of VariantK.
956                 // Build up code associated with such a case.
957                 let substructure = EnumMatching(index, variant, field_tuples);
958                 let arm_expr = self.call_substructure_method(
959                     cx, trait_, type_ident, self_args, nonself_args,
960                     &substructure);
961
962                 cx.arm(sp, vec![single_pat], arm_expr)
963             }).collect();
964
965         // We will usually need the catch-all after matching the
966         // tuples `(VariantK, VariantK, ...)` for each VariantK of the
967         // enum.  But:
968         //
969         // * when there is only one Self arg, the arms above suffice
970         // (and the deriving we call back into may not be prepared to
971         // handle EnumNonMatchCollapsed), and,
972         //
973         // * when the enum has only one variant, the single arm that
974         // is already present always suffices.
975         //
976         // * In either of the two cases above, if we *did* add a
977         //   catch-all `_` match, it would trigger the
978         //   unreachable-pattern error.
979         //
980         if variants.len() > 1 && self_args.len() > 1 {
981             let arms : Vec<ast::Arm> = variants.iter().enumerate()
982                 .map(|(index, &variant)| {
983                     let pat = variant_to_pat(cx, sp, &*variant);
984                     let lit = ast::LitUint(index as u64, ast::TyU);
985                     cx.arm(sp, vec![pat], cx.expr_lit(sp, lit))
986                 }).collect();
987
988             // Build a series of let statements mapping each self_arg
989             // to a uint corresponding to its variant index.
990             // i.e. for `enum E<T> { A, B(1), C(T, T) }`, and a deriving
991             // with three Self args, builds three statements:
992             //
993             // ```
994             // let __self0_vi = match   self {
995             //     A => 0u, B(..) => 1u, C(..) => 2u
996             // };
997             // let __self1_vi = match __arg1 {
998             //     A => 0u, B(..) => 1u, C(..) => 2u
999             // };
1000             // let __self2_vi = match __arg2 {
1001             //     A => 0u, B(..) => 1u, C(..) => 2u
1002             // };
1003             // ```
1004             let mut index_let_stmts : Vec<Gc<ast::Stmt>> = Vec::new();
1005             for (&ident, &self_arg) in vi_idents.iter().zip(self_args.iter()) {
1006                 let variant_idx = cx.expr_match(sp, self_arg, arms.clone());
1007                 let let_stmt = cx.stmt_let(sp, false, ident, variant_idx);
1008                 index_let_stmts.push(let_stmt);
1009             }
1010
1011             let arm_expr = self.call_substructure_method(
1012                 cx, trait_, type_ident, self_args, nonself_args,
1013                 &catch_all_substructure);
1014
1015             // Builds the expression:
1016             // {
1017             //   let __self0_vi = ...;
1018             //   let __self1_vi = ...;
1019             //   ...
1020             //   <delegated expression referring to __self0_vi, et al.>
1021             // }
1022             let arm_expr = cx.expr_block(
1023                 cx.block_all(sp, Vec::new(), index_let_stmts, Some(arm_expr)));
1024
1025             // Builds arm:
1026             // _ => { let __self0_vi = ...;
1027             //        let __self1_vi = ...;
1028             //        ...
1029             //        <delegated expression as above> }
1030             let catch_all_match_arm =
1031                 cx.arm(sp, vec![cx.pat_wild(sp)], arm_expr);
1032
1033             match_arms.push(catch_all_match_arm);
1034
1035         } else if variants.len() == 0 {
1036             // As an additional wrinkle, For a zero-variant enum A,
1037             // currently the compiler
1038             // will accept `fn (a: &Self) { match   *a   { } }`
1039             // but rejects `fn (a: &Self) { match (&*a,) { } }`
1040             // as well as  `fn (a: &Self) { match ( *a,) { } }`
1041             //
1042             // This means that the strategy of building up a tuple of
1043             // all Self arguments fails when Self is a zero variant
1044             // enum: rustc rejects the expanded program, even though
1045             // the actual code tends to be impossible to execute (at
1046             // least safely), according to the type system.
1047             //
1048             // The most expedient fix for this is to just let the
1049             // code fall through to the catch-all.  But even this is
1050             // error-prone, since the catch-all as defined above would
1051             // generate code like this:
1052             //
1053             //     _ => { let __self0 = match *self { };
1054             //            let __self1 = match *__arg_0 { };
1055             //            <catch-all-expr> }
1056             //
1057             // Which is yields bindings for variables which type
1058             // inference cannot resolve to unique types.
1059             //
1060             // One option to the above might be to add explicit type
1061             // annotations.  But the *only* reason to go down that path
1062             // would be to try to make the expanded output consistent
1063             // with the case when the number of enum variants >= 1.
1064             //
1065             // That just isn't worth it.  In fact, trying to generate
1066             // sensible code for *any* deriving on a zero-variant enum
1067             // does not make sense.  But at the same time, for now, we
1068             // do not want to cause a compile failure just because the
1069             // user happened to attach a deriving to their
1070             // zero-variant enum.
1071             //
1072             // Instead, just generate a failing expression for the
1073             // zero variant case, skipping matches and also skipping
1074             // delegating back to the end user code entirely.
1075             //
1076             // (See also #4499 and #12609; note that some of the
1077             // discussions there influence what choice we make here;
1078             // e.g. if we feature-gate `match x { ... }` when x refers
1079             // to an uninhabited type (e.g. a zero-variant enum or a
1080             // type holding such an enum), but do not feature-gate
1081             // zero-variant enums themselves, then attempting to
1082             // derive Show on such a type could here generate code
1083             // that needs the feature gate enabled.)
1084
1085             return cx.expr_unreachable(sp);
1086         }
1087
1088         // Final wrinkle: the self_args are expressions that deref
1089         // down to desired l-values, but we cannot actually deref
1090         // them when they are fed as r-values into a tuple
1091         // expression; here add a layer of borrowing, turning
1092         // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
1093         let borrowed_self_args = self_args.iter()
1094             .map(|&self_arg| cx.expr_addr_of(sp, self_arg))
1095             .collect::<Vec<Gc<ast::Expr>>>();
1096         let match_arg = cx.expr(sp, ast::ExprTup(borrowed_self_args));
1097         cx.expr_match(sp, match_arg, match_arms)
1098     }
1099
1100     fn expand_static_enum_method_body(&self,
1101                                       cx: &mut ExtCtxt,
1102                                       trait_: &TraitDef,
1103                                       enum_def: &EnumDef,
1104                                       type_ident: Ident,
1105                                       self_args: &[Gc<Expr>],
1106                                       nonself_args: &[Gc<Expr>])
1107         -> Gc<Expr> {
1108         let summary = enum_def.variants.iter().map(|v| {
1109             let ident = v.node.name;
1110             let summary = match v.node.kind {
1111                 ast::TupleVariantKind(ref args) => {
1112                     Unnamed(args.iter().map(|va| trait_.set_expn_info(cx, va.ty.span)).collect())
1113                 }
1114                 ast::StructVariantKind(ref struct_def) => {
1115                     trait_.summarise_struct(cx, &**struct_def)
1116                 }
1117             };
1118             (ident, v.span, summary)
1119         }).collect();
1120         self.call_substructure_method(cx, trait_, type_ident,
1121                                       self_args, nonself_args,
1122                                       &StaticEnum(enum_def, summary))
1123     }
1124 }
1125
1126 #[deriving(PartialEq)] // dogfooding!
1127 enum StructType {
1128     Unknown, Record, Tuple
1129 }
1130
1131 // general helper methods.
1132 impl<'a> TraitDef<'a> {
1133     fn set_expn_info(&self,
1134                      cx: &mut ExtCtxt,
1135                      mut to_set: Span) -> Span {
1136         let trait_name = match self.path.path.last() {
1137             None => cx.span_bug(self.span, "trait with empty path in generic `deriving`"),
1138             Some(name) => *name
1139         };
1140         to_set.expn_info = Some(box(GC) codemap::ExpnInfo {
1141             call_site: to_set,
1142             callee: codemap::NameAndSpan {
1143                 name: format!("deriving({})", trait_name),
1144                 format: codemap::MacroAttribute,
1145                 span: Some(self.span)
1146             }
1147         });
1148         to_set
1149     }
1150
1151     fn summarise_struct(&self,
1152                         cx: &mut ExtCtxt,
1153                         struct_def: &StructDef) -> StaticFields {
1154         let mut named_idents = Vec::new();
1155         let mut just_spans = Vec::new();
1156         for field in struct_def.fields.iter(){
1157             let sp = self.set_expn_info(cx, field.span);
1158             match field.node.kind {
1159                 ast::NamedField(ident, _) => named_idents.push((ident, sp)),
1160                 ast::UnnamedField(..) => just_spans.push(sp),
1161             }
1162         }
1163
1164         match (just_spans.is_empty(), named_idents.is_empty()) {
1165             (false, false) => cx.span_bug(self.span,
1166                                           "a struct with named and unnamed \
1167                                           fields in generic `deriving`"),
1168             // named fields
1169             (_, false) => Named(named_idents),
1170             // tuple structs (includes empty structs)
1171             (_, _)     => Unnamed(just_spans)
1172         }
1173     }
1174
1175     fn create_subpatterns(&self,
1176                           cx: &mut ExtCtxt,
1177                           field_paths: Vec<ast::SpannedIdent> ,
1178                           mutbl: ast::Mutability)
1179                           -> Vec<Gc<ast::Pat>> {
1180         field_paths.iter().map(|path| {
1181             cx.pat(path.span,
1182                         ast::PatIdent(ast::BindByRef(mutbl), (*path).clone(), None))
1183             }).collect()
1184     }
1185
1186     fn create_struct_pattern(&self,
1187                              cx: &mut ExtCtxt,
1188                              struct_ident: Ident,
1189                              struct_def: &StructDef,
1190                              prefix: &str,
1191                              mutbl: ast::Mutability)
1192                              -> (Gc<ast::Pat>, Vec<(Span, Option<Ident>, Gc<Expr>)>) {
1193         if struct_def.fields.is_empty() {
1194             return (
1195                 cx.pat_ident_binding_mode(
1196                     self.span, struct_ident, ast::BindByValue(ast::MutImmutable)),
1197                 Vec::new());
1198         }
1199
1200         let matching_path = cx.path(self.span, vec!( struct_ident ));
1201
1202         let mut paths = Vec::new();
1203         let mut ident_expr = Vec::new();
1204         let mut struct_type = Unknown;
1205
1206         for (i, struct_field) in struct_def.fields.iter().enumerate() {
1207             let sp = self.set_expn_info(cx, struct_field.span);
1208             let opt_id = match struct_field.node.kind {
1209                 ast::NamedField(ident, _) if (struct_type == Unknown ||
1210                                               struct_type == Record) => {
1211                     struct_type = Record;
1212                     Some(ident)
1213                 }
1214                 ast::UnnamedField(..) if (struct_type == Unknown ||
1215                                           struct_type == Tuple) => {
1216                     struct_type = Tuple;
1217                     None
1218                 }
1219                 _ => {
1220                     cx.span_bug(sp, "a struct with named and unnamed fields in `deriving`");
1221                 }
1222             };
1223             let ident = cx.ident_of(format!("{}_{}", prefix, i).as_slice());
1224             paths.push(codemap::Spanned{span: sp, node: ident});
1225             let val = cx.expr(
1226                 sp, ast::ExprParen(cx.expr_deref(sp, cx.expr_path(cx.path_ident(sp,ident)))));
1227             ident_expr.push((sp, opt_id, val));
1228         }
1229
1230         let subpats = self.create_subpatterns(cx, paths, mutbl);
1231
1232         // struct_type is definitely not Unknown, since struct_def.fields
1233         // must be nonempty to reach here
1234         let pattern = if struct_type == Record {
1235             let field_pats = subpats.iter().zip(ident_expr.iter()).map(|(&pat, &(_, id, _))| {
1236                 // id is guaranteed to be Some
1237                 ast::FieldPat { ident: id.unwrap(), pat: pat }
1238             }).collect();
1239             cx.pat_struct(self.span, matching_path, field_pats)
1240         } else {
1241             cx.pat_enum(self.span, matching_path, subpats)
1242         };
1243
1244         (pattern, ident_expr)
1245     }
1246
1247     fn create_enum_variant_pattern(&self,
1248                                    cx: &mut ExtCtxt,
1249                                    variant: &ast::Variant,
1250                                    prefix: &str,
1251                                    mutbl: ast::Mutability)
1252         -> (Gc<ast::Pat>, Vec<(Span, Option<Ident>, Gc<Expr>)> ) {
1253         let variant_ident = variant.node.name;
1254         match variant.node.kind {
1255             ast::TupleVariantKind(ref variant_args) => {
1256                 if variant_args.is_empty() {
1257                     return (cx.pat_ident_binding_mode(variant.span, variant_ident,
1258                                                           ast::BindByValue(ast::MutImmutable)),
1259                             Vec::new());
1260                 }
1261
1262                 let matching_path = cx.path_ident(variant.span, variant_ident);
1263
1264                 let mut paths = Vec::new();
1265                 let mut ident_expr = Vec::new();
1266                 for (i, va) in variant_args.iter().enumerate() {
1267                     let sp = self.set_expn_info(cx, va.ty.span);
1268                     let ident = cx.ident_of(format!("{}_{}", prefix, i).as_slice());
1269                     let path1 = codemap::Spanned{span: sp, node: ident};
1270                     paths.push(path1);
1271                     let expr_path = cx.expr_path(cx.path_ident(sp, ident));
1272                     let val = cx.expr(sp, ast::ExprParen(cx.expr_deref(sp, expr_path)));
1273                     ident_expr.push((sp, None, val));
1274                 }
1275
1276                 let subpats = self.create_subpatterns(cx, paths, mutbl);
1277
1278                 (cx.pat_enum(variant.span, matching_path, subpats),
1279                  ident_expr)
1280             }
1281             ast::StructVariantKind(ref struct_def) => {
1282                 self.create_struct_pattern(cx, variant_ident, &**struct_def,
1283                                            prefix, mutbl)
1284             }
1285         }
1286     }
1287 }
1288
1289 /* helpful premade recipes */
1290
1291 /**
1292 Fold the fields. `use_foldl` controls whether this is done
1293 left-to-right (`true`) or right-to-left (`false`).
1294 */
1295 pub fn cs_fold(use_foldl: bool,
1296                f: |&mut ExtCtxt, Span, Gc<Expr>, Gc<Expr>, &[Gc<Expr>]| -> Gc<Expr>,
1297                base: Gc<Expr>,
1298                enum_nonmatch_f: EnumNonMatchCollapsedFunc,
1299                cx: &mut ExtCtxt,
1300                trait_span: Span,
1301                substructure: &Substructure)
1302                -> Gc<Expr> {
1303     match *substructure.fields {
1304         EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => {
1305             if use_foldl {
1306                 all_fields.iter().fold(base, |old, field| {
1307                     f(cx,
1308                       field.span,
1309                       old,
1310                       field.self_,
1311                       field.other.as_slice())
1312                 })
1313             } else {
1314                 all_fields.iter().rev().fold(base, |old, field| {
1315                     f(cx,
1316                       field.span,
1317                       old,
1318                       field.self_,
1319                       field.other.as_slice())
1320                 })
1321             }
1322         },
1323         EnumNonMatchingCollapsed(ref all_args, _, tuple) =>
1324             enum_nonmatch_f(cx, trait_span, (all_args.as_slice(), tuple),
1325                             substructure.nonself_args),
1326         StaticEnum(..) | StaticStruct(..) => {
1327             cx.span_bug(trait_span, "static function in `deriving`")
1328         }
1329     }
1330 }
1331
1332
1333 /**
1334 Call the method that is being derived on all the fields, and then
1335 process the collected results. i.e.
1336
1337 ~~~
1338 f(cx, span, ~[self_1.method(__arg_1_1, __arg_2_1),
1339               self_2.method(__arg_1_2, __arg_2_2)])
1340 ~~~
1341 */
1342 #[inline]
1343 pub fn cs_same_method(f: |&mut ExtCtxt, Span, Vec<Gc<Expr>>| -> Gc<Expr>,
1344                       enum_nonmatch_f: EnumNonMatchCollapsedFunc,
1345                       cx: &mut ExtCtxt,
1346                       trait_span: Span,
1347                       substructure: &Substructure)
1348                       -> Gc<Expr> {
1349     match *substructure.fields {
1350         EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => {
1351             // call self_n.method(other_1_n, other_2_n, ...)
1352             let called = all_fields.iter().map(|field| {
1353                 cx.expr_method_call(field.span,
1354                                     field.self_,
1355                                     substructure.method_ident,
1356                                     field.other.iter()
1357                                                .map(|e| cx.expr_addr_of(field.span, *e))
1358                                                .collect())
1359             }).collect();
1360
1361             f(cx, trait_span, called)
1362         },
1363         EnumNonMatchingCollapsed(ref all_self_args, _, tuple) =>
1364             enum_nonmatch_f(cx, trait_span, (all_self_args.as_slice(), tuple),
1365                             substructure.nonself_args),
1366         StaticEnum(..) | StaticStruct(..) => {
1367             cx.span_bug(trait_span, "static function in `deriving`")
1368         }
1369     }
1370 }
1371
1372 /**
1373 Fold together the results of calling the derived method on all the
1374 fields. `use_foldl` controls whether this is done left-to-right
1375 (`true`) or right-to-left (`false`).
1376 */
1377 #[inline]
1378 pub fn cs_same_method_fold(use_foldl: bool,
1379                            f: |&mut ExtCtxt, Span, Gc<Expr>, Gc<Expr>| -> Gc<Expr>,
1380                            base: Gc<Expr>,
1381                            enum_nonmatch_f: EnumNonMatchCollapsedFunc,
1382                            cx: &mut ExtCtxt,
1383                            trait_span: Span,
1384                            substructure: &Substructure)
1385                            -> Gc<Expr> {
1386     cs_same_method(
1387         |cx, span, vals| {
1388             if use_foldl {
1389                 vals.iter().fold(base, |old, &new| {
1390                     f(cx, span, old, new)
1391                 })
1392             } else {
1393                 vals.iter().rev().fold(base, |old, &new| {
1394                     f(cx, span, old, new)
1395                 })
1396             }
1397         },
1398         enum_nonmatch_f,
1399         cx, trait_span, substructure)
1400 }
1401
1402 /**
1403 Use a given binop to combine the result of calling the derived method
1404 on all the fields.
1405 */
1406 #[inline]
1407 pub fn cs_binop(binop: ast::BinOp, base: Gc<Expr>,
1408                 enum_nonmatch_f: EnumNonMatchCollapsedFunc,
1409                 cx: &mut ExtCtxt, trait_span: Span,
1410                 substructure: &Substructure) -> Gc<Expr> {
1411     cs_same_method_fold(
1412         true, // foldl is good enough
1413         |cx, span, old, new| {
1414             cx.expr_binary(span,
1415                            binop,
1416                            old, new)
1417
1418         },
1419         base,
1420         enum_nonmatch_f,
1421         cx, trait_span, substructure)
1422 }
1423
1424 /// cs_binop with binop == or
1425 #[inline]
1426 pub fn cs_or(enum_nonmatch_f: EnumNonMatchCollapsedFunc,
1427              cx: &mut ExtCtxt, span: Span,
1428              substructure: &Substructure) -> Gc<Expr> {
1429     cs_binop(ast::BiOr, cx.expr_bool(span, false),
1430              enum_nonmatch_f,
1431              cx, span, substructure)
1432 }
1433
1434 /// cs_binop with binop == and
1435 #[inline]
1436 pub fn cs_and(enum_nonmatch_f: EnumNonMatchCollapsedFunc,
1437               cx: &mut ExtCtxt, span: Span,
1438               substructure: &Substructure) -> Gc<Expr> {
1439     cs_binop(ast::BiAnd, cx.expr_bool(span, true),
1440              enum_nonmatch_f,
1441              cx, span, substructure)
1442 }