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.
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.
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.
16 //! Supported features (fairly exhaustive):
18 //! - Methods taking any number of parameters of any type, and returning
19 //! any type, other than vectors, bottom and closures.
20 //! - Generating `impl`s for types with type parameters and lifetimes
21 //! (e.g. `Option<T>`), the parameters are automatically given the
22 //! current trait as a bound. (This includes separate type parameters
23 //! and lifetimes for methods.)
24 //! - Additional bounds on the type parameters (`TraitDef.additional_bounds`)
26 //! The most important thing for implementers is the `Substructure` and
27 //! `SubstructureFields` objects. The latter groups 5 possibilities of the
30 //! - `Struct`, when `Self` is a struct (including tuple structs, e.g
31 //! `struct T(int, char)`).
32 //! - `EnumMatching`, when `Self` is an enum and all the arguments are the
33 //! same variant of the enum (e.g. `Some(1)`, `Some(3)` and `Some(4)`)
34 //! - `EnumNonMatchingCollapsed` when `Self` is an enum and the arguments
35 //! are not the same variant (e.g. `None`, `Some(1)` and `None`).
36 //! - `StaticEnum` and `StaticStruct` for static methods, where the type
37 //! being derived upon is either an enum or struct respectively. (Any
38 //! argument with type Self is just grouped among the non-self
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
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
57 //! struct A { x : int }
67 //! The `int`s in `B` and `C0` don't have an identifier, so the
68 //! `Option<ident>`s would be `None` for them.
70 //! In the static cases, the structure is summarised, either into the just
71 //! spans of the fields or a list of spans and the field idents (for tuple
72 //! structs and record structs, respectively), or a list of these, for
73 //! enums (one for each variant). For empty struct and empty enum
74 //! variants, it is represented as a count of 0.
76 //! # "`cs`" functions
78 //! The `cs_...` functions ("combine substructure) are designed to
79 //! make life easier by providing some pre-made recipes for common
80 //! tasks; mostly calling the function being derived on all the
81 //! arguments and then combining them back together in some way (or
82 //! letting the user chose that). They are not meant to be the only
83 //! way to handle the structures that this code creates.
87 //! The following simplified `PartialEq` is used for in-code examples:
91 //! fn eq(&self, other: &Self);
93 //! impl PartialEq for int {
94 //! fn eq(&self, other: &int) -> bool {
100 //! Some examples of the values of `SubstructureFields` follow, using the
101 //! above `PartialEq`, `A`, `B` and `C`.
105 //! When generating the `expr` for the `A` impl, the `SubstructureFields` is
108 //! Struct(vec![FieldInfo {
109 //! span: <span of x>
110 //! name: Some(<ident of x>),
111 //! self_: <expr for &self.x>,
112 //! other: vec![<expr for &other.x]
116 //! For the `B` impl, called with `B(a)` and `B(b)`,
119 //! Struct(vec![FieldInfo {
120 //! span: <span of `int`>,
122 //! self_: <expr for &a>
123 //! other: vec![<expr for &b>]
129 //! When generating the `expr` for a call with `self == C0(a)` and `other
130 //! == C0(b)`, the SubstructureFields is
133 //! EnumMatching(0, <ast::Variant for C0>,
135 //! span: <span of int>
137 //! self_: <expr for &a>,
138 //! other: vec![<expr for &b>]
142 //! For `C1 {x}` and `C1 {x}`,
145 //! EnumMatching(1, <ast::Variant for C1>,
147 //! span: <span of x>
148 //! name: Some(<ident of x>),
149 //! self_: <expr for &self.x>,
150 //! other: vec![<expr for &other.x>]
154 //! For `C0(a)` and `C1 {x}` ,
157 //! EnumNonMatchingCollapsed(
158 //! vec![<ident of self>, <ident of __arg_1>],
159 //! &[<ast::Variant for C0>, <ast::Variant for C1>],
160 //! &[<ident for self index value>, <ident of __arg_1 index value>])
163 //! It is the same for when the arguments are flipped to `C1 {x}` and
164 //! `C0(a)`; the only difference is what the values of the identifiers
165 //! <ident for self index value> and <ident of __arg_1 index value> will
166 //! be in the generated code.
168 //! `EnumNonMatchingCollapsed` deliberately provides far less information
169 //! than is generally available for a given pair of variants; see #15375
174 //! A static method on the types above would result in,
177 //! StaticStruct(<ast::StructDef of A>, Named(vec![(<ident of x>, <span of x>)]))
179 //! StaticStruct(<ast::StructDef of B>, Unnamed(vec![<span of x>]))
181 //! StaticEnum(<ast::EnumDef of C>,
182 //! vec![(<ident of C0>, <span of C0>, Unnamed(vec![<span of int>])),
183 //! (<ident of C1>, <span of C1>, Named(vec![(<ident of x>, <span of x>)]))])
186 pub use self::StaticFields::*;
187 pub use self::SubstructureFields::*;
188 use self::StructType::*;
190 use std::cell::RefCell;
196 use ast::{EnumDef, Expr, Ident, Generics, StructDef};
199 use attr::AttrMetaMethods;
200 use ext::base::ExtCtxt;
201 use ext::build::AstBuilder;
202 use codemap::{self, DUMMY_SP};
205 use owned_slice::OwnedSlice;
206 use parse::token::InternedString;
207 use parse::token::special_idents;
210 use self::ty::{LifetimeBounds, Path, Ptr, PtrTy, Self, Ty};
214 pub struct TraitDef<'a> {
215 /// The span for the current #[derive(Foo)] header.
218 pub attributes: Vec<ast::Attribute>,
220 /// Path of the trait, including any type parameters
223 /// Additional bounds required of any type parameters of the type,
224 /// other than the current trait
225 pub additional_bounds: Vec<Ty<'a>>,
227 /// Any extra lifetimes and/or bounds, e.g. `D: serialize::Decoder`
228 pub generics: LifetimeBounds<'a>,
230 pub methods: Vec<MethodDef<'a>>,
234 pub struct MethodDef<'a> {
235 /// name of the method
237 /// List of generics, e.g. `R: rand::Rng`
238 pub generics: LifetimeBounds<'a>,
240 /// Whether there is a self argument (outer Option) i.e. whether
241 /// this is a static function, and whether it is a pointer (inner
243 pub explicit_self: Option<Option<PtrTy<'a>>>,
245 /// Arguments other than the self argument
246 pub args: Vec<Ty<'a>>,
251 pub attributes: Vec<ast::Attribute>,
253 pub combine_substructure: RefCell<CombineSubstructureFunc<'a>>,
256 /// All the data about the data structure/method being derived upon.
257 pub struct Substructure<'a> {
259 pub type_ident: Ident,
260 /// ident of the method
261 pub method_ident: Ident,
262 /// dereferenced access to any `Self` or `Ptr(Self, _)` arguments
263 pub self_args: &'a [P<Expr>],
264 /// verbatim access to any other arguments
265 pub nonself_args: &'a [P<Expr>],
266 pub fields: &'a SubstructureFields<'a>
269 /// Summary of the relevant parts of a struct/enum field.
270 pub struct FieldInfo {
272 /// None for tuple structs/normal enum variants, Some for normal
273 /// structs/struct enum variants.
274 pub name: Option<Ident>,
275 /// The expression corresponding to this field of `self`
276 /// (specifically, a reference to it).
278 /// The expressions corresponding to references to this field in
279 /// the other `Self` arguments.
280 pub other: Vec<P<Expr>>,
283 /// Fields for a static method
284 pub enum StaticFields {
285 /// Tuple structs/enum variants like this.
287 /// Normal structs/struct variants.
288 Named(Vec<(Ident, Span)>),
291 /// A summary of the possible sets of fields.
292 pub enum SubstructureFields<'a> {
293 Struct(Vec<FieldInfo>),
294 /// Matching variants of the enum: variant index, ast::Variant,
295 /// fields: the field name is only non-`None` in the case of a struct
297 EnumMatching(uint, &'a ast::Variant, Vec<FieldInfo>),
299 /// Non-matching variants of the enum, but with all state hidden from
300 /// the consequent code. The first component holds `Ident`s for all of
301 /// the `Self` arguments; the second component is a slice of all of the
302 /// variants for the enum itself, and the third component is a list of
303 /// `Ident`s bound to the variant index values for each of the actual
304 /// input `Self` arguments.
305 EnumNonMatchingCollapsed(Vec<Ident>, &'a [P<ast::Variant>], &'a [Ident]),
307 /// A static method where `Self` is a struct.
308 StaticStruct(&'a ast::StructDef, StaticFields),
309 /// A static method where `Self` is an enum.
310 StaticEnum(&'a ast::EnumDef, Vec<(Ident, Span, StaticFields)>),
315 /// Combine the values of all the fields together. The last argument is
316 /// all the fields of all the structures.
317 pub type CombineSubstructureFunc<'a> =
318 Box<FnMut(&mut ExtCtxt, Span, &Substructure) -> P<Expr> + 'a>;
320 /// Deal with non-matching enum variants. The tuple is a list of
321 /// identifiers (one for each `Self` argument, which could be any of the
322 /// variants since they have been collapsed together) and the identifiers
323 /// holding the variant index value for each of the `Self` arguments. The
324 /// last argument is all the non-`Self` args of the method being derived.
325 pub type EnumNonMatchCollapsedFunc<'a> =
326 Box<FnMut(&mut ExtCtxt, Span, (&[Ident], &[Ident]), &[P<Expr>]) -> P<Expr> + 'a>;
328 pub fn combine_substructure<'a>(f: CombineSubstructureFunc<'a>)
329 -> RefCell<CombineSubstructureFunc<'a>> {
334 impl<'a> TraitDef<'a> {
335 pub fn expand<F>(&self,
337 mitem: &ast::MetaItem,
340 F: FnOnce(P<ast::Item>),
342 let newitem = match item.node {
343 ast::ItemStruct(ref struct_def, ref generics) => {
344 self.expand_struct_def(cx,
349 ast::ItemEnum(ref enum_def, ref generics) => {
350 self.expand_enum_def(cx,
356 cx.span_err(mitem.span, "`derive` may only be applied to structs and enums");
360 // Keep the lint attributes of the previous item to control how the
361 // generated implementations are linted
362 let mut attrs = newitem.attrs.clone();
363 attrs.extend(item.attrs.iter().filter(|a| {
364 match a.name().get() {
365 "allow" | "warn" | "deny" | "forbid" => true,
368 }).map(|a| a.clone()));
375 /// Given that we are deriving a trait `Tr` for a type `T<'a, ...,
376 /// 'z, A, ..., Z>`, creates an impl like:
379 /// impl<'a, ..., 'z, A:Tr B1 B2, ..., Z: Tr B1 B2> Tr for T<A, ..., Z> { ... }
382 /// where B1, B2, ... are the bounds given by `bounds_paths`.'
383 fn create_derived_impl(&self,
387 methods: Vec<P<ast::Method>>) -> P<ast::Item> {
388 let trait_path = self.path.to_path(cx, self.span, type_ident, generics);
390 let Generics { mut lifetimes, ty_params, mut where_clause } =
391 self.generics.to_generics(cx, self.span, type_ident, generics);
392 let mut ty_params = ty_params.into_vec();
394 // Copy the lifetimes
395 lifetimes.extend(generics.lifetimes.iter().map(|l| (*l).clone()));
397 // Create the type parameters.
398 ty_params.extend(generics.ty_params.iter().map(|ty_param| {
399 // I don't think this can be moved out of the loop, since
400 // a TyParamBound requires an ast id
401 let mut bounds: Vec<_> =
402 // extra restrictions on the generics parameters to the type being derived upon
403 self.additional_bounds.iter().map(|p| {
404 cx.typarambound(p.to_path(cx, self.span,
405 type_ident, generics))
408 // require the current trait
409 bounds.push(cx.typarambound(trait_path.clone()));
411 // also add in any bounds from the declaration
412 for declared_bound in ty_param.bounds.iter() {
413 bounds.push((*declared_bound).clone());
416 cx.typaram(self.span,
418 OwnedSlice::from_vec(bounds),
422 // and similarly for where clauses
423 where_clause.predicates.extend(generics.where_clause.predicates.iter().map(|clause| {
425 ast::WherePredicate::BoundPredicate(ref wb) => {
426 ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
428 bounded_ty: wb.bounded_ty.clone(),
429 bounds: OwnedSlice::from_vec(wb.bounds.iter().map(|b| b.clone()).collect())
432 ast::WherePredicate::RegionPredicate(ref rb) => {
433 ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
435 lifetime: rb.lifetime,
436 bounds: rb.bounds.iter().map(|b| b.clone()).collect()
439 ast::WherePredicate::EqPredicate(ref we) => {
440 ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
441 id: ast::DUMMY_NODE_ID,
443 path: we.path.clone(),
450 let trait_generics = Generics {
451 lifetimes: lifetimes,
452 ty_params: OwnedSlice::from_vec(ty_params),
453 where_clause: where_clause
456 // Create the reference to the trait.
457 let trait_ref = cx.trait_ref(trait_path);
459 // Create the type parameters on the `self` path.
460 let self_ty_params = generics.ty_params.map(|ty_param| {
461 cx.ty_ident(self.span, ty_param.ident)
464 let self_lifetimes: Vec<ast::Lifetime> =
467 .map(|ld| ld.lifetime)
470 // Create the type of `self`.
471 let self_type = cx.ty_path(
472 cx.path_all(self.span, false, vec!( type_ident ), self_lifetimes,
473 self_ty_params.into_vec(), Vec::new()));
475 let attr = cx.attribute(
477 cx.meta_word(self.span,
478 InternedString::new("automatically_derived")));
479 // Just mark it now since we know that it'll end up used downstream
480 attr::mark_used(&attr);
481 let opt_trait_ref = Some(trait_ref);
482 let ident = ast_util::impl_pretty_name(&opt_trait_ref, &*self_type);
483 let mut a = vec![attr];
484 a.extend(self.attributes.iter().map(|a| a.clone()));
489 ast::ItemImpl(ast::Unsafety::Normal,
490 ast::ImplPolarity::Positive,
496 ast::MethodImplItem(method)
500 fn expand_struct_def(&self,
502 struct_def: &StructDef,
504 generics: &Generics) -> P<ast::Item> {
505 let methods = self.methods.iter().map(|method_def| {
506 let (explicit_self, self_args, nonself_args, tys) =
507 method_def.split_self_nonself_args(
508 cx, self, type_ident, generics);
510 let body = if method_def.is_static() {
511 method_def.expand_static_struct_method_body(
519 method_def.expand_struct_method_body(cx,
527 method_def.create_method(cx,
537 self.create_derived_impl(cx, type_ident, generics, methods)
540 fn expand_enum_def(&self,
544 generics: &Generics) -> P<ast::Item> {
545 let methods = self.methods.iter().map(|method_def| {
546 let (explicit_self, self_args, nonself_args, tys) =
547 method_def.split_self_nonself_args(cx, self,
548 type_ident, generics);
550 let body = if method_def.is_static() {
551 method_def.expand_static_enum_method_body(
559 method_def.expand_enum_method_body(cx,
567 method_def.create_method(cx,
577 self.create_derived_impl(cx, type_ident, generics, methods)
581 fn variant_to_pat(cx: &mut ExtCtxt, sp: Span, enum_ident: ast::Ident, variant: &ast::Variant)
583 let path = cx.path(sp, vec![enum_ident, variant.node.name]);
584 cx.pat(sp, match variant.node.kind {
585 ast::TupleVariantKind(..) => ast::PatEnum(path, None),
586 ast::StructVariantKind(..) => ast::PatStruct(path, Vec::new(), true),
590 impl<'a> MethodDef<'a> {
591 fn call_substructure_method(&self,
595 self_args: &[P<Expr>],
596 nonself_args: &[P<Expr>],
597 fields: &SubstructureFields)
599 let substructure = Substructure {
600 type_ident: type_ident,
601 method_ident: cx.ident_of(self.name),
602 self_args: self_args,
603 nonself_args: nonself_args,
606 let mut f = self.combine_substructure.borrow_mut();
607 let f: &mut CombineSubstructureFunc = &mut *f;
608 f(cx, trait_.span, &substructure)
617 self.ret_ty.to_ty(cx, trait_.span, type_ident, generics)
620 fn is_static(&self) -> bool {
621 self.explicit_self.is_none()
624 fn split_self_nonself_args(&self,
629 -> (ast::ExplicitSelf, Vec<P<Expr>>, Vec<P<Expr>>, Vec<(Ident, P<ast::Ty>)>) {
631 let mut self_args = Vec::new();
632 let mut nonself_args = Vec::new();
633 let mut arg_tys = Vec::new();
634 let mut nonstatic = false;
636 let ast_explicit_self = match self.explicit_self {
637 Some(ref self_ptr) => {
638 let (self_expr, explicit_self) =
639 ty::get_explicit_self(cx, trait_.span, self_ptr);
641 self_args.push(self_expr);
646 None => codemap::respan(trait_.span, ast::SelfStatic),
649 for (i, ty) in self.args.iter().enumerate() {
650 let ast_ty = ty.to_ty(cx, trait_.span, type_ident, generics);
651 let ident = cx.ident_of(&format!("__arg_{}", i)[]);
652 arg_tys.push((ident, ast_ty));
654 let arg_expr = cx.expr_ident(trait_.span, ident);
657 // for static methods, just treat any Self
658 // arguments as a normal arg
659 Self if nonstatic => {
660 self_args.push(arg_expr);
662 Ptr(box Self, _) if nonstatic => {
663 self_args.push(cx.expr_deref(trait_.span, arg_expr))
666 nonself_args.push(arg_expr);
671 (ast_explicit_self, self_args, nonself_args, arg_tys)
674 fn create_method(&self,
680 explicit_self: ast::ExplicitSelf,
681 arg_types: Vec<(Ident, P<ast::Ty>)> ,
682 body: P<Expr>) -> P<ast::Method> {
683 // create the generics that aren't for Self
684 let fn_generics = self.generics.to_generics(cx, trait_.span, type_ident, generics);
686 let self_arg = match explicit_self.node {
687 ast::SelfStatic => None,
688 // creating fresh self id
689 _ => Some(ast::Arg::new_self(trait_.span, ast::MutImmutable, special_idents::self_))
692 let args = arg_types.into_iter().map(|(name, ty)| {
693 cx.arg(trait_.span, name, ty)
695 self_arg.into_iter().chain(args).collect()
698 let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident);
700 let method_ident = cx.ident_of(self.name);
701 let fn_decl = cx.fn_decl(args, ret_type);
702 let body_block = cx.block_expr(body);
704 // Create the method.
706 attrs: self.attributes.clone(),
707 id: ast::DUMMY_NODE_ID,
709 node: ast::MethDecl(method_ident,
713 ast::Unsafety::Normal,
721 /// #[derive(PartialEq)]
722 /// struct A { x: int, y: int }
724 /// // equivalent to:
725 /// impl PartialEq for A {
726 /// fn eq(&self, __arg_1: &A) -> bool {
728 /// A {x: ref __self_0_0, y: ref __self_0_1} => {
730 /// A {x: ref __self_1_0, y: ref __self_1_1} => {
731 /// __self_0_0.eq(__self_1_0) && __self_0_1.eq(__self_1_1)
739 fn expand_struct_method_body(&self,
742 struct_def: &StructDef,
744 self_args: &[P<Expr>],
745 nonself_args: &[P<Expr>])
748 let mut raw_fields = Vec::new(); // ~[[fields of self],
749 // [fields of next Self arg], [etc]]
750 let mut patterns = Vec::new();
751 for i in range(0u, self_args.len()) {
752 let struct_path= cx.path(DUMMY_SP, vec!( type_ident ));
753 let (pat, ident_expr) =
754 trait_.create_struct_pattern(cx,
757 &format!("__self_{}",
761 raw_fields.push(ident_expr);
764 // transpose raw_fields
765 let fields = if raw_fields.len() > 0 {
766 let mut raw_fields = raw_fields.into_iter().map(|v| v.into_iter());
767 let first_field = raw_fields.next().unwrap();
768 let mut other_fields: Vec<vec::IntoIter<(Span, Option<Ident>, P<Expr>)>>
769 = raw_fields.collect();
770 first_field.map(|(span, opt_id, field)| {
775 other: other_fields.iter_mut().map(|l| {
776 match l.next().unwrap() {
783 cx.span_bug(trait_.span,
784 "no self arguments to non-static method in generic \
788 // body of the inner most destructuring match
789 let mut body = self.call_substructure_method(
797 // make a series of nested matches, to destructure the
798 // structs. This is actually right-to-left, but it shouldn't
800 for (arg_expr, pat) in self_args.iter().zip(patterns.iter()) {
801 body = cx.expr_match(trait_.span, arg_expr.clone(),
802 vec!( cx.arm(trait_.span, vec!(pat.clone()), body) ))
807 fn expand_static_struct_method_body(&self,
810 struct_def: &StructDef,
812 self_args: &[P<Expr>],
813 nonself_args: &[P<Expr>])
815 let summary = trait_.summarise_struct(cx, struct_def);
817 self.call_substructure_method(cx,
820 self_args, nonself_args,
821 &StaticStruct(struct_def, summary))
825 /// #[derive(PartialEq)]
831 /// // is equivalent to
833 /// impl PartialEq for A {
834 /// fn eq(&self, __arg_1: &A) -> ::bool {
835 /// match (&*self, &*__arg_1) {
836 /// (&A1, &A1) => true,
837 /// (&A2(ref __self_0),
838 /// &A2(ref __arg_1_0)) => (*__self_0).eq(&(*__arg_1_0)),
840 /// let __self_vi = match *self { A1(..) => 0u, A2(..) => 1u };
841 /// let __arg_1_vi = match *__arg_1 { A1(..) => 0u, A2(..) => 1u };
849 /// (Of course `__self_vi` and `__arg_1_vi` are unused for
850 /// `PartialEq`, and those subcomputations will hopefully be removed
851 /// as their results are unused. The point of `__self_vi` and
852 /// `__arg_1_vi` is for `PartialOrd`; see #15503.)
853 fn expand_enum_method_body(&self,
858 self_args: Vec<P<Expr>>,
859 nonself_args: &[P<Expr>])
861 self.build_enum_match_tuple(
862 cx, trait_, enum_def, type_ident, self_args, nonself_args)
866 /// Creates a match for a tuple of all `self_args`, where either all
867 /// variants match, or it falls into a catch-all for when one variant
870 /// There are N + 1 cases because is a case for each of the N
871 /// variants where all of the variants match, and one catch-all for
872 /// when one does not match.
874 /// The catch-all handler is provided access the variant index values
875 /// for each of the self-args, carried in precomputed variables. (Nota
876 /// bene: the variant index values are not necessarily the
877 /// discriminant values. See issue #15523.)
880 /// match (this, that, ...) {
881 /// (Variant1, Variant1, Variant1) => ... // delegate Matching on Variant1
882 /// (Variant2, Variant2, Variant2) => ... // delegate Matching on Variant2
885 /// let __this_vi = match this { Variant1 => 0u, Variant2 => 1u, ... };
886 /// let __that_vi = match that { Variant1 => 0u, Variant2 => 1u, ... };
887 /// ... // catch-all remainder can inspect above variant index values.
891 fn build_enum_match_tuple(
897 self_args: Vec<P<Expr>>,
898 nonself_args: &[P<Expr>]) -> P<Expr> {
900 let sp = trait_.span;
901 let variants = &enum_def.variants;
903 let self_arg_names = self_args.iter().enumerate()
904 .map(|(arg_count, _self_arg)| {
908 format!("__arg_{}", arg_count)
911 .collect::<Vec<String>>();
913 let self_arg_idents = self_arg_names.iter()
914 .map(|name|cx.ident_of(&name[]))
915 .collect::<Vec<ast::Ident>>();
917 // The `vi_idents` will be bound, solely in the catch-all, to
918 // a series of let statements mapping each self_arg to a uint
919 // corresponding to its variant index.
920 let vi_idents: Vec<ast::Ident> = self_arg_names.iter()
921 .map(|name| { let vi_suffix = format!("{}_vi", &name[]);
922 cx.ident_of(&vi_suffix[]) })
923 .collect::<Vec<ast::Ident>>();
925 // Builds, via callback to call_substructure_method, the
926 // delegated expression that handles the catch-all case,
927 // using `__variants_tuple` to drive logic if necessary.
928 let catch_all_substructure = EnumNonMatchingCollapsed(
929 self_arg_idents, &variants[], &vi_idents[]);
931 // These arms are of the form:
932 // (Variant1, Variant1, ...) => Body1
933 // (Variant2, Variant2, ...) => Body2
935 // where each tuple has length = self_args.len()
936 let mut match_arms: Vec<ast::Arm> = variants.iter().enumerate()
937 .map(|(index, variant)| {
938 let mk_self_pat = |&: cx: &mut ExtCtxt, self_arg_name: &str| {
939 let (p, idents) = trait_.create_enum_variant_pattern(cx, type_ident,
943 (cx.pat(sp, ast::PatRegion(p, ast::MutImmutable)), idents)
946 // A single arm has form (&VariantK, &VariantK, ...) => BodyK
947 // (see "Final wrinkle" note below for why.)
948 let mut subpats = Vec::with_capacity(self_arg_names.len());
949 let mut self_pats_idents = Vec::with_capacity(self_arg_names.len() - 1);
950 let first_self_pat_idents = {
951 let (p, idents) = mk_self_pat(cx, &self_arg_names[0][]);
955 for self_arg_name in self_arg_names.tail().iter() {
956 let (p, idents) = mk_self_pat(cx, &self_arg_name[]);
958 self_pats_idents.push(idents);
961 // Here is the pat = `(&VariantK, &VariantK, ...)`
962 let single_pat = cx.pat_tuple(sp, subpats);
964 // For the BodyK, we need to delegate to our caller,
965 // passing it an EnumMatching to indicate which case
968 // All of the Self args have the same variant in these
969 // cases. So we transpose the info in self_pats_idents
970 // to gather the getter expressions together, in the
971 // form that EnumMatching expects.
973 // The transposition is driven by walking across the
974 // arg fields of the variant for the first self pat.
975 let field_tuples = first_self_pat_idents.into_iter().enumerate()
976 // For each arg field of self, pull out its getter expr ...
977 .map(|(field_index, (sp, opt_ident, self_getter_expr))| {
978 // ... but FieldInfo also wants getter expr
979 // for matching other arguments of Self type;
980 // so walk across the *other* self_pats_idents
981 // and pull out getter for same field in each
982 // of them (using `field_index` tracked above).
983 // That is the heart of the transposition.
984 let others = self_pats_idents.iter().map(|fields| {
985 let (_, _opt_ident, ref other_getter_expr) =
988 // All Self args have same variant, so
989 // opt_idents are the same. (Assert
990 // here to make it self-evident that
991 // it is okay to ignore `_opt_ident`.)
992 assert!(opt_ident == _opt_ident);
994 other_getter_expr.clone()
995 }).collect::<Vec<P<Expr>>>();
997 FieldInfo { span: sp,
999 self_: self_getter_expr,
1002 }).collect::<Vec<FieldInfo>>();
1004 // Now, for some given VariantK, we have built up
1005 // expressions for referencing every field of every
1006 // Self arg, assuming all are instances of VariantK.
1007 // Build up code associated with such a case.
1008 let substructure = EnumMatching(index,
1011 let arm_expr = self.call_substructure_method(
1012 cx, trait_, type_ident, &self_args[], nonself_args,
1015 cx.arm(sp, vec![single_pat], arm_expr)
1018 // We will usually need the catch-all after matching the
1019 // tuples `(VariantK, VariantK, ...)` for each VariantK of the
1022 // * when there is only one Self arg, the arms above suffice
1023 // (and the deriving we call back into may not be prepared to
1024 // handle EnumNonMatchCollapsed), and,
1026 // * when the enum has only one variant, the single arm that
1027 // is already present always suffices.
1029 // * In either of the two cases above, if we *did* add a
1030 // catch-all `_` match, it would trigger the
1031 // unreachable-pattern error.
1033 if variants.len() > 1 && self_args.len() > 1 {
1034 let arms: Vec<ast::Arm> = variants.iter().enumerate()
1035 .map(|(index, variant)| {
1036 let pat = variant_to_pat(cx, sp, type_ident, &**variant);
1037 let lit = ast::LitInt(index as u64, ast::UnsignedIntLit(ast::TyUs(false)));
1038 cx.arm(sp, vec![pat], cx.expr_lit(sp, lit))
1041 // Build a series of let statements mapping each self_arg
1042 // to a uint corresponding to its variant index.
1043 // i.e. for `enum E<T> { A, B(1), C(T, T) }`, and a deriving
1044 // with three Self args, builds three statements:
1047 // let __self0_vi = match self {
1048 // A => 0u, B(..) => 1u, C(..) => 2u
1050 // let __self1_vi = match __arg1 {
1051 // A => 0u, B(..) => 1u, C(..) => 2u
1053 // let __self2_vi = match __arg2 {
1054 // A => 0u, B(..) => 1u, C(..) => 2u
1057 let mut index_let_stmts: Vec<P<ast::Stmt>> = Vec::new();
1058 for (&ident, self_arg) in vi_idents.iter().zip(self_args.iter()) {
1059 let variant_idx = cx.expr_match(sp, self_arg.clone(), arms.clone());
1060 let let_stmt = cx.stmt_let(sp, false, ident, variant_idx);
1061 index_let_stmts.push(let_stmt);
1064 let arm_expr = self.call_substructure_method(
1065 cx, trait_, type_ident, &self_args[], nonself_args,
1066 &catch_all_substructure);
1068 // Builds the expression:
1070 // let __self0_vi = ...;
1071 // let __self1_vi = ...;
1073 // <delegated expression referring to __self0_vi, et al.>
1075 let arm_expr = cx.expr_block(
1076 cx.block_all(sp, Vec::new(), index_let_stmts, Some(arm_expr)));
1079 // _ => { let __self0_vi = ...;
1080 // let __self1_vi = ...;
1082 // <delegated expression as above> }
1083 let catch_all_match_arm =
1084 cx.arm(sp, vec![cx.pat_wild(sp)], arm_expr);
1086 match_arms.push(catch_all_match_arm);
1088 } else if variants.len() == 0 {
1089 // As an additional wrinkle, For a zero-variant enum A,
1090 // currently the compiler
1091 // will accept `fn (a: &Self) { match *a { } }`
1092 // but rejects `fn (a: &Self) { match (&*a,) { } }`
1093 // as well as `fn (a: &Self) { match ( *a,) { } }`
1095 // This means that the strategy of building up a tuple of
1096 // all Self arguments fails when Self is a zero variant
1097 // enum: rustc rejects the expanded program, even though
1098 // the actual code tends to be impossible to execute (at
1099 // least safely), according to the type system.
1101 // The most expedient fix for this is to just let the
1102 // code fall through to the catch-all. But even this is
1103 // error-prone, since the catch-all as defined above would
1104 // generate code like this:
1106 // _ => { let __self0 = match *self { };
1107 // let __self1 = match *__arg_0 { };
1108 // <catch-all-expr> }
1110 // Which is yields bindings for variables which type
1111 // inference cannot resolve to unique types.
1113 // One option to the above might be to add explicit type
1114 // annotations. But the *only* reason to go down that path
1115 // would be to try to make the expanded output consistent
1116 // with the case when the number of enum variants >= 1.
1118 // That just isn't worth it. In fact, trying to generate
1119 // sensible code for *any* deriving on a zero-variant enum
1120 // does not make sense. But at the same time, for now, we
1121 // do not want to cause a compile failure just because the
1122 // user happened to attach a deriving to their
1123 // zero-variant enum.
1125 // Instead, just generate a failing expression for the
1126 // zero variant case, skipping matches and also skipping
1127 // delegating back to the end user code entirely.
1129 // (See also #4499 and #12609; note that some of the
1130 // discussions there influence what choice we make here;
1131 // e.g. if we feature-gate `match x { ... }` when x refers
1132 // to an uninhabited type (e.g. a zero-variant enum or a
1133 // type holding such an enum), but do not feature-gate
1134 // zero-variant enums themselves, then attempting to
1135 // derive Show on such a type could here generate code
1136 // that needs the feature gate enabled.)
1138 return cx.expr_unreachable(sp);
1141 // Final wrinkle: the self_args are expressions that deref
1142 // down to desired l-values, but we cannot actually deref
1143 // them when they are fed as r-values into a tuple
1144 // expression; here add a layer of borrowing, turning
1145 // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
1146 let borrowed_self_args = self_args.move_map(|self_arg| cx.expr_addr_of(sp, self_arg));
1147 let match_arg = cx.expr(sp, ast::ExprTup(borrowed_self_args));
1148 cx.expr_match(sp, match_arg, match_arms)
1151 fn expand_static_enum_method_body(&self,
1156 self_args: &[P<Expr>],
1157 nonself_args: &[P<Expr>])
1159 let summary = enum_def.variants.iter().map(|v| {
1160 let ident = v.node.name;
1161 let summary = match v.node.kind {
1162 ast::TupleVariantKind(ref args) => {
1163 Unnamed(args.iter().map(|va| trait_.set_expn_info(cx, va.ty.span)).collect())
1165 ast::StructVariantKind(ref struct_def) => {
1166 trait_.summarise_struct(cx, &**struct_def)
1169 (ident, v.span, summary)
1171 self.call_substructure_method(cx, trait_, type_ident,
1172 self_args, nonself_args,
1173 &StaticEnum(enum_def, summary))
1177 #[derive(PartialEq)] // dogfooding!
1179 Unknown, Record, Tuple
1182 // general helper methods.
1183 impl<'a> TraitDef<'a> {
1184 fn set_expn_info(&self,
1186 mut to_set: Span) -> Span {
1187 let trait_name = match self.path.path.last() {
1188 None => cx.span_bug(self.span, "trait with empty path in generic `derive`"),
1191 to_set.expn_id = cx.codemap().record_expansion(codemap::ExpnInfo {
1193 callee: codemap::NameAndSpan {
1194 name: format!("derive({})", trait_name),
1195 format: codemap::MacroAttribute,
1196 span: Some(self.span)
1202 fn summarise_struct(&self,
1204 struct_def: &StructDef) -> StaticFields {
1205 let mut named_idents = Vec::new();
1206 let mut just_spans = Vec::new();
1207 for field in struct_def.fields.iter(){
1208 let sp = self.set_expn_info(cx, field.span);
1209 match field.node.kind {
1210 ast::NamedField(ident, _) => named_idents.push((ident, sp)),
1211 ast::UnnamedField(..) => just_spans.push(sp),
1215 match (just_spans.is_empty(), named_idents.is_empty()) {
1216 (false, false) => cx.span_bug(self.span,
1217 "a struct with named and unnamed \
1218 fields in generic `derive`"),
1220 (_, false) => Named(named_idents),
1221 // tuple structs (includes empty structs)
1222 (_, _) => Unnamed(just_spans)
1226 fn create_subpatterns(&self,
1228 field_paths: Vec<ast::SpannedIdent> ,
1229 mutbl: ast::Mutability)
1230 -> Vec<P<ast::Pat>> {
1231 field_paths.iter().map(|path| {
1233 ast::PatIdent(ast::BindByRef(mutbl), (*path).clone(), None))
1237 fn create_struct_pattern(&self,
1239 struct_path: ast::Path,
1240 struct_def: &StructDef,
1242 mutbl: ast::Mutability)
1243 -> (P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>) {
1244 if struct_def.fields.is_empty() {
1245 return (cx.pat_enum(self.span, struct_path, vec![]), vec![]);
1248 let mut paths = Vec::new();
1249 let mut ident_expr = Vec::new();
1250 let mut struct_type = Unknown;
1252 for (i, struct_field) in struct_def.fields.iter().enumerate() {
1253 let sp = self.set_expn_info(cx, struct_field.span);
1254 let opt_id = match struct_field.node.kind {
1255 ast::NamedField(ident, _) if (struct_type == Unknown ||
1256 struct_type == Record) => {
1257 struct_type = Record;
1260 ast::UnnamedField(..) if (struct_type == Unknown ||
1261 struct_type == Tuple) => {
1262 struct_type = Tuple;
1266 cx.span_bug(sp, "a struct with named and unnamed fields in `derive`");
1269 let ident = cx.ident_of(&format!("{}_{}", prefix, i)[]);
1270 paths.push(codemap::Spanned{span: sp, node: ident});
1272 sp, ast::ExprParen(cx.expr_deref(sp, cx.expr_path(cx.path_ident(sp,ident)))));
1273 ident_expr.push((sp, opt_id, val));
1276 let subpats = self.create_subpatterns(cx, paths, mutbl);
1278 // struct_type is definitely not Unknown, since struct_def.fields
1279 // must be nonempty to reach here
1280 let pattern = if struct_type == Record {
1281 let field_pats = subpats.into_iter().zip(ident_expr.iter()).map(|(pat, &(_, id, _))| {
1282 // id is guaranteed to be Some
1285 node: ast::FieldPat { ident: id.unwrap(), pat: pat, is_shorthand: false },
1288 cx.pat_struct(self.span, struct_path, field_pats)
1290 cx.pat_enum(self.span, struct_path, subpats)
1293 (pattern, ident_expr)
1296 fn create_enum_variant_pattern(&self,
1298 enum_ident: ast::Ident,
1299 variant: &ast::Variant,
1301 mutbl: ast::Mutability)
1302 -> (P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>) {
1303 let variant_ident = variant.node.name;
1304 let variant_path = cx.path(variant.span, vec![enum_ident, variant_ident]);
1305 match variant.node.kind {
1306 ast::TupleVariantKind(ref variant_args) => {
1307 if variant_args.is_empty() {
1308 return (cx.pat_enum(variant.span, variant_path, vec![]), vec![]);
1311 let mut paths = Vec::new();
1312 let mut ident_expr = Vec::new();
1313 for (i, va) in variant_args.iter().enumerate() {
1314 let sp = self.set_expn_info(cx, va.ty.span);
1315 let ident = cx.ident_of(&format!("{}_{}", prefix, i)[]);
1316 let path1 = codemap::Spanned{span: sp, node: ident};
1318 let expr_path = cx.expr_path(cx.path_ident(sp, ident));
1319 let val = cx.expr(sp, ast::ExprParen(cx.expr_deref(sp, expr_path)));
1320 ident_expr.push((sp, None, val));
1323 let subpats = self.create_subpatterns(cx, paths, mutbl);
1325 (cx.pat_enum(variant.span, variant_path, subpats),
1328 ast::StructVariantKind(ref struct_def) => {
1329 self.create_struct_pattern(cx, variant_path, &**struct_def,
1336 /* helpful premade recipes */
1338 /// Fold the fields. `use_foldl` controls whether this is done
1339 /// left-to-right (`true`) or right-to-left (`false`).
1340 pub fn cs_fold<F>(use_foldl: bool,
1343 mut enum_nonmatch_f: EnumNonMatchCollapsedFunc,
1346 substructure: &Substructure)
1348 F: FnMut(&mut ExtCtxt, Span, P<Expr>, P<Expr>, &[P<Expr>]) -> P<Expr>,
1350 match *substructure.fields {
1351 EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => {
1353 all_fields.iter().fold(base, |old, field| {
1357 field.self_.clone(),
1361 all_fields.iter().rev().fold(base, |old, field| {
1365 field.self_.clone(),
1370 EnumNonMatchingCollapsed(ref all_args, _, tuple) =>
1371 enum_nonmatch_f(cx, trait_span, (&all_args[], tuple),
1372 substructure.nonself_args),
1373 StaticEnum(..) | StaticStruct(..) => {
1374 cx.span_bug(trait_span, "static function in `derive`")
1380 /// Call the method that is being derived on all the fields, and then
1381 /// process the collected results. i.e.
1384 /// f(cx, span, vec![self_1.method(__arg_1_1, __arg_2_1),
1385 /// self_2.method(__arg_1_2, __arg_2_2)])
1388 pub fn cs_same_method<F>(f: F,
1389 mut enum_nonmatch_f: EnumNonMatchCollapsedFunc,
1392 substructure: &Substructure)
1394 F: FnOnce(&mut ExtCtxt, Span, Vec<P<Expr>>) -> P<Expr>,
1396 match *substructure.fields {
1397 EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => {
1398 // call self_n.method(other_1_n, other_2_n, ...)
1399 let called = all_fields.iter().map(|field| {
1400 cx.expr_method_call(field.span,
1401 field.self_.clone(),
1402 substructure.method_ident,
1404 .map(|e| cx.expr_addr_of(field.span, e.clone()))
1408 f(cx, trait_span, called)
1410 EnumNonMatchingCollapsed(ref all_self_args, _, tuple) =>
1411 enum_nonmatch_f(cx, trait_span, (&all_self_args[], tuple),
1412 substructure.nonself_args),
1413 StaticEnum(..) | StaticStruct(..) => {
1414 cx.span_bug(trait_span, "static function in `derive`")
1419 /// Fold together the results of calling the derived method on all the
1420 /// fields. `use_foldl` controls whether this is done left-to-right
1421 /// (`true`) or right-to-left (`false`).
1423 pub fn cs_same_method_fold<F>(use_foldl: bool,
1426 enum_nonmatch_f: EnumNonMatchCollapsedFunc,
1429 substructure: &Substructure)
1431 F: FnMut(&mut ExtCtxt, Span, P<Expr>, P<Expr>) -> P<Expr>,
1436 vals.into_iter().fold(base.clone(), |old, new| {
1437 f(cx, span, old, new)
1440 vals.into_iter().rev().fold(base.clone(), |old, new| {
1441 f(cx, span, old, new)
1446 cx, trait_span, substructure)
1449 /// Use a given binop to combine the result of calling the derived method
1450 /// on all the fields.
1452 pub fn cs_binop(binop: ast::BinOp, base: P<Expr>,
1453 enum_nonmatch_f: EnumNonMatchCollapsedFunc,
1454 cx: &mut ExtCtxt, trait_span: Span,
1455 substructure: &Substructure) -> P<Expr> {
1456 cs_same_method_fold(
1457 true, // foldl is good enough
1458 |cx, span, old, new| {
1459 cx.expr_binary(span,
1466 cx, trait_span, substructure)
1469 /// cs_binop with binop == or
1471 pub fn cs_or(enum_nonmatch_f: EnumNonMatchCollapsedFunc,
1472 cx: &mut ExtCtxt, span: Span,
1473 substructure: &Substructure) -> P<Expr> {
1474 cs_binop(ast::BiOr, cx.expr_bool(span, false),
1476 cx, span, substructure)
1479 /// cs_binop with binop == and
1481 pub fn cs_and(enum_nonmatch_f: EnumNonMatchCollapsedFunc,
1482 cx: &mut ExtCtxt, span: Span,
1483 substructure: &Substructure) -> P<Expr> {
1484 cs_binop(ast::BiAnd, cx.expr_bool(span, true),
1486 cx, span, substructure)