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