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