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