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