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