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, e.g. the `Ord` instance
25 //! requires an explicit `PartialEq` bound at the
26 //! moment. (`TraitDef.additional_bounds`)
28 //! Unsupported: FIXME #6257: calling methods on reference fields,
29 //! e.g. derive Eq/Ord/Clone don't work on `struct A(&int)`,
30 //! because of how the auto-dereferencing happens.
32 //! The most important thing for implementers is the `Substructure` and
33 //! `SubstructureFields` objects. The latter groups 5 possibilities of the
36 //! - `Struct`, when `Self` is a struct (including tuple structs, e.g
37 //! `struct T(int, char)`).
38 //! - `EnumMatching`, when `Self` is an enum and all the arguments are the
39 //! same variant of the enum (e.g. `Some(1)`, `Some(3)` and `Some(4)`)
40 //! - `EnumNonMatchingCollapsed` when `Self` is an enum and the arguments
41 //! are not the same variant (e.g. `None`, `Some(1)` and `None`).
42 //! - `StaticEnum` and `StaticStruct` for static methods, where the type
43 //! being derived upon is either an enum or struct respectively. (Any
44 //! argument with type Self is just grouped among the non-self
47 //! In the first two cases, the values from the corresponding fields in
48 //! all the arguments are grouped together. For `EnumNonMatchingCollapsed`
49 //! this isn't possible (different variants have different fields), so the
50 //! fields are inaccessible. (Previous versions of the deriving infrastructure
51 //! had a way to expand into code that could access them, at the cost of
52 //! generating exponential amounts of code; see issue #15375). There are no
53 //! fields with values in the static cases, so these are treated entirely
56 //! The non-static cases have `Option<ident>` in several places associated
57 //! with field `expr`s. This represents the name of the field it is
58 //! associated with. It is only not `None` when the associated field has
59 //! an identifier in the source code. For example, the `x`s in the
63 //! struct A { x : int }
73 //! The `int`s in `B` and `C0` don't have an identifier, so the
74 //! `Option<ident>`s would be `None` for them.
76 //! In the static cases, the structure is summarised, either into the just
77 //! spans of the fields or a list of spans and the field idents (for tuple
78 //! structs and record structs, respectively), or a list of these, for
79 //! enums (one for each variant). For empty struct and empty enum
80 //! variants, it is represented as a count of 0.
84 //! The following simplified `PartialEq` is used for in-code examples:
88 //! fn eq(&self, other: &Self);
90 //! impl PartialEq for int {
91 //! fn eq(&self, other: &int) -> bool {
97 //! Some examples of the values of `SubstructureFields` follow, using the
98 //! above `PartialEq`, `A`, `B` and `C`.
102 //! When generating the `expr` for the `A` impl, the `SubstructureFields` is
105 //! Struct(~[FieldInfo {
106 //! span: <span of x>
107 //! name: Some(<ident of x>),
108 //! self_: <expr for &self.x>,
109 //! other: ~[<expr for &other.x]
113 //! For the `B` impl, called with `B(a)` and `B(b)`,
116 //! Struct(~[FieldInfo {
117 //! span: <span of `int`>,
126 //! When generating the `expr` for a call with `self == C0(a)` and `other
127 //! == C0(b)`, the SubstructureFields is
130 //! EnumMatching(0, <ast::Variant for C0>,
132 //! span: <span of int>
134 //! self_: <expr for &a>,
135 //! other: ~[<expr for &b>]
139 //! For `C1 {x}` and `C1 {x}`,
142 //! EnumMatching(1, <ast::Variant for C1>,
144 //! span: <span of x>
145 //! name: Some(<ident of x>),
146 //! self_: <expr for &self.x>,
147 //! other: ~[<expr for &other.x>]
151 //! For `C0(a)` and `C1 {x}` ,
154 //! EnumNonMatchingCollapsed(
155 //! ~[<ident of self>, <ident of __arg_1>],
156 //! &[<ast::Variant for C0>, <ast::Variant for C1>],
157 //! &[<ident for self index value>, <ident of __arg_1 index value>])
160 //! It is the same for when the arguments are flipped to `C1 {x}` and
161 //! `C0(a)`; the only difference is what the values of the identifiers
162 //! <ident for self index value> and <ident of __arg_1 index value> will
163 //! be in the generated code.
165 //! `EnumNonMatchingCollapsed` deliberately provides far less information
166 //! than is generally available for a given pair of variants; see #15375
171 //! A static method on the above would result in,
174 //! StaticStruct(<ast::StructDef of A>, Named(~[(<ident of x>, <span of x>)]))
176 //! StaticStruct(<ast::StructDef of B>, Unnamed(~[<span of x>]))
178 //! StaticEnum(<ast::EnumDef of C>, ~[(<ident of C0>, <span of C0>, Unnamed(~[<span of int>])),
179 //! (<ident of C1>, <span of C1>,
180 //! Named(~[(<ident of x>, <span of x>)]))])
183 pub use self::StaticFields::*;
184 pub use self::SubstructureFields::*;
185 use self::StructType::*;
187 use std::cell::RefCell;
193 use ast::{EnumDef, Expr, Ident, Generics, StructDef};
196 use attr::AttrMetaMethods;
197 use ext::base::ExtCtxt;
198 use ext::build::AstBuilder;
199 use codemap::{self, DUMMY_SP};
202 use owned_slice::OwnedSlice;
203 use parse::token::InternedString;
204 use parse::token::special_idents;
207 use self::ty::{LifetimeBounds, Path, Ptr, PtrTy, Self, Ty};
211 pub struct TraitDef<'a> {
212 /// The span for the current #[derive(Foo)] header.
215 pub attributes: Vec<ast::Attribute>,
217 /// Path of the trait, including any type parameters
220 /// Additional bounds required of any type parameters of the type,
221 /// other than the current trait
222 pub additional_bounds: Vec<Ty<'a>>,
224 /// Any extra lifetimes and/or bounds, e.g. `D: serialize::Decoder`
225 pub generics: LifetimeBounds<'a>,
227 pub methods: Vec<MethodDef<'a>>,
231 pub struct MethodDef<'a> {
232 /// name of the method
234 /// List of generics, e.g. `R: rand::Rng`
235 pub generics: LifetimeBounds<'a>,
237 /// Whether there is a self argument (outer Option) i.e. whether
238 /// this is a static function, and whether it is a pointer (inner
240 pub explicit_self: Option<Option<PtrTy<'a>>>,
242 /// Arguments other than the self argument
243 pub args: Vec<Ty<'a>>,
248 pub attributes: Vec<ast::Attribute>,
250 pub combine_substructure: RefCell<CombineSubstructureFunc<'a>>,
253 /// All the data about the data structure/method being derived upon.
254 pub struct Substructure<'a> {
256 pub type_ident: Ident,
257 /// ident of the method
258 pub method_ident: Ident,
259 /// dereferenced access to any `Self` or `Ptr(Self, _)` arguments
260 pub self_args: &'a [P<Expr>],
261 /// verbatim access to any other arguments
262 pub nonself_args: &'a [P<Expr>],
263 pub fields: &'a SubstructureFields<'a>
266 /// Summary of the relevant parts of a struct/enum field.
267 pub struct FieldInfo {
269 /// None for tuple structs/normal enum variants, Some for normal
270 /// structs/struct enum variants.
271 pub name: Option<Ident>,
272 /// The expression corresponding to this field of `self`
273 /// (specifically, a reference to it).
275 /// The expressions corresponding to references to this field in
276 /// the other `Self` arguments.
277 pub other: Vec<P<Expr>>,
280 /// Fields for a static method
281 pub enum StaticFields {
282 /// Tuple structs/enum variants like this.
284 /// Normal structs/struct variants.
285 Named(Vec<(Ident, Span)>),
288 /// A summary of the possible sets of fields.
289 pub enum SubstructureFields<'a> {
290 Struct(Vec<FieldInfo>),
291 /// Matching variants of the enum: variant index, ast::Variant,
292 /// fields: the field name is only non-`None` in the case of a struct
294 EnumMatching(uint, &'a ast::Variant, Vec<FieldInfo>),
296 /// Non-matching variants of the enum, but with all state hidden from
297 /// the consequent code. The first component holds `Ident`s for all of
298 /// the `Self` arguments; the second component is a slice of all of the
299 /// variants for the enum itself, and the third component is a list of
300 /// `Ident`s bound to the variant index values for each of the actual
301 /// input `Self` arguments.
302 EnumNonMatchingCollapsed(Vec<Ident>, &'a [P<ast::Variant>], &'a [Ident]),
304 /// A static method where `Self` is a struct.
305 StaticStruct(&'a ast::StructDef, StaticFields),
306 /// A static method where `Self` is an enum.
307 StaticEnum(&'a ast::EnumDef, Vec<(Ident, Span, StaticFields)>),
312 /// Combine the values of all the fields together. The last argument is
313 /// all the fields of all the structures.
314 pub type CombineSubstructureFunc<'a> =
315 Box<FnMut(&mut ExtCtxt, Span, &Substructure) -> P<Expr> + 'a>;
317 /// Deal with non-matching enum variants. The tuple is a list of
318 /// identifiers (one for each `Self` argument, which could be any of the
319 /// variants since they have been collapsed together) and the identifiers
320 /// holding the variant index value for each of the `Self` arguments. The
321 /// last argument is all the non-`Self` args of the method being derived.
322 pub type EnumNonMatchCollapsedFunc<'a> =
323 Box<FnMut(&mut ExtCtxt, Span, (&[Ident], &[Ident]), &[P<Expr>]) -> P<Expr> + 'a>;
325 pub fn combine_substructure<'a>(f: CombineSubstructureFunc<'a>)
326 -> RefCell<CombineSubstructureFunc<'a>> {
331 impl<'a> TraitDef<'a> {
332 pub fn expand<F>(&self,
334 mitem: &ast::MetaItem,
337 F: FnOnce(P<ast::Item>),
339 let newitem = match item.node {
340 ast::ItemStruct(ref struct_def, ref generics) => {
341 self.expand_struct_def(cx,
346 ast::ItemEnum(ref enum_def, ref generics) => {
347 self.expand_enum_def(cx,
353 cx.span_err(mitem.span, "`derive` may only be applied to structs and enums");
357 // Keep the lint attributes of the previous item to control how the
358 // generated implementations are linted
359 let mut attrs = newitem.attrs.clone();
360 attrs.extend(item.attrs.iter().filter(|a| {
361 match a.name().get() {
362 "allow" | "warn" | "deny" | "forbid" => true,
365 }).map(|a| a.clone()));
372 /// Given that we are deriving a trait `Tr` for a type `T<'a, ...,
373 /// 'z, A, ..., Z>`, creates an impl like:
376 /// impl<'a, ..., 'z, A:Tr B1 B2, ..., Z: Tr B1 B2> Tr for T<A, ..., Z> { ... }
379 /// where B1, B2, ... are the bounds given by `bounds_paths`.'
380 fn create_derived_impl(&self,
384 methods: Vec<P<ast::Method>>) -> P<ast::Item> {
385 let trait_path = self.path.to_path(cx, self.span, type_ident, generics);
387 let Generics { mut lifetimes, ty_params, mut where_clause } =
388 self.generics.to_generics(cx, self.span, type_ident, generics);
389 let mut ty_params = ty_params.into_vec();
391 // Copy the lifetimes
392 lifetimes.extend(generics.lifetimes.iter().map(|l| (*l).clone()));
394 // Create the type parameters.
395 ty_params.extend(generics.ty_params.iter().map(|ty_param| {
396 // I don't think this can be moved out of the loop, since
397 // a TyParamBound requires an ast id
398 let mut bounds: Vec<_> =
399 // extra restrictions on the generics parameters to the type being derived upon
400 self.additional_bounds.iter().map(|p| {
401 cx.typarambound(p.to_path(cx, self.span,
402 type_ident, generics))
405 // require the current trait
406 bounds.push(cx.typarambound(trait_path.clone()));
408 // also add in any bounds from the declaration
409 for declared_bound in ty_param.bounds.iter() {
410 bounds.push((*declared_bound).clone());
413 cx.typaram(self.span,
415 OwnedSlice::from_vec(bounds),
419 // and similarly for where clauses
420 where_clause.predicates.extend(generics.where_clause.predicates.iter().map(|clause| {
422 ast::WherePredicate::BoundPredicate(ref wb) => {
423 ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
425 bounded_ty: wb.bounded_ty.clone(),
426 bounds: OwnedSlice::from_vec(wb.bounds.iter().map(|b| b.clone()).collect())
429 ast::WherePredicate::RegionPredicate(ref rb) => {
430 ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
432 lifetime: rb.lifetime,
433 bounds: rb.bounds.iter().map(|b| b.clone()).collect()
436 ast::WherePredicate::EqPredicate(ref we) => {
437 ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
438 id: ast::DUMMY_NODE_ID,
440 path: we.path.clone(),
447 let trait_generics = Generics {
448 lifetimes: lifetimes,
449 ty_params: OwnedSlice::from_vec(ty_params),
450 where_clause: where_clause
453 // Create the reference to the trait.
454 let trait_ref = cx.trait_ref(trait_path);
456 // Create the type parameters on the `self` path.
457 let self_ty_params = generics.ty_params.map(|ty_param| {
458 cx.ty_ident(self.span, ty_param.ident)
461 let self_lifetimes: Vec<ast::Lifetime> =
464 .map(|ld| ld.lifetime)
467 // Create the type of `self`.
468 let self_type = cx.ty_path(
469 cx.path_all(self.span, false, vec!( type_ident ), self_lifetimes,
470 self_ty_params.into_vec(), Vec::new()));
472 let attr = cx.attribute(
474 cx.meta_word(self.span,
475 InternedString::new("automatically_derived")));
476 // Just mark it now since we know that it'll end up used downstream
477 attr::mark_used(&attr);
478 let opt_trait_ref = Some(trait_ref);
479 let ident = ast_util::impl_pretty_name(&opt_trait_ref, &*self_type);
480 let mut a = vec![attr];
481 a.extend(self.attributes.iter().map(|a| a.clone()));
486 ast::ItemImpl(ast::Unsafety::Normal,
487 ast::ImplPolarity::Positive,
493 ast::MethodImplItem(method)
497 fn expand_struct_def(&self,
499 struct_def: &StructDef,
501 generics: &Generics) -> P<ast::Item> {
502 let methods = self.methods.iter().map(|method_def| {
503 let (explicit_self, self_args, nonself_args, tys) =
504 method_def.split_self_nonself_args(
505 cx, self, type_ident, generics);
507 let body = if method_def.is_static() {
508 method_def.expand_static_struct_method_body(
513 self_args.index(&FullRange),
514 nonself_args.index(&FullRange))
516 method_def.expand_struct_method_body(cx,
520 self_args.index(&FullRange),
521 nonself_args.index(&FullRange))
524 method_def.create_method(cx,
534 self.create_derived_impl(cx, type_ident, generics, methods)
537 fn expand_enum_def(&self,
541 generics: &Generics) -> P<ast::Item> {
542 let methods = self.methods.iter().map(|method_def| {
543 let (explicit_self, self_args, nonself_args, tys) =
544 method_def.split_self_nonself_args(cx, self,
545 type_ident, generics);
547 let body = if method_def.is_static() {
548 method_def.expand_static_enum_method_body(
553 self_args.index(&FullRange),
554 nonself_args.index(&FullRange))
556 method_def.expand_enum_method_body(cx,
561 nonself_args.index(&FullRange))
564 method_def.create_method(cx,
574 self.create_derived_impl(cx, type_ident, generics, methods)
578 fn variant_to_pat(cx: &mut ExtCtxt, sp: Span, enum_ident: ast::Ident, variant: &ast::Variant)
580 let path = cx.path(sp, vec![enum_ident, variant.node.name]);
581 cx.pat(sp, match variant.node.kind {
582 ast::TupleVariantKind(..) => ast::PatEnum(path, None),
583 ast::StructVariantKind(..) => ast::PatStruct(path, Vec::new(), true),
587 impl<'a> MethodDef<'a> {
588 fn call_substructure_method(&self,
592 self_args: &[P<Expr>],
593 nonself_args: &[P<Expr>],
594 fields: &SubstructureFields)
596 let substructure = Substructure {
597 type_ident: type_ident,
598 method_ident: cx.ident_of(self.name),
599 self_args: self_args,
600 nonself_args: nonself_args,
603 let mut f = self.combine_substructure.borrow_mut();
604 let f: &mut CombineSubstructureFunc = &mut *f;
605 f(cx, trait_.span, &substructure)
614 self.ret_ty.to_ty(cx, trait_.span, type_ident, generics)
617 fn is_static(&self) -> bool {
618 self.explicit_self.is_none()
621 fn split_self_nonself_args(&self,
626 -> (ast::ExplicitSelf, Vec<P<Expr>>, Vec<P<Expr>>, Vec<(Ident, P<ast::Ty>)>) {
628 let mut self_args = Vec::new();
629 let mut nonself_args = Vec::new();
630 let mut arg_tys = Vec::new();
631 let mut nonstatic = false;
633 let ast_explicit_self = match self.explicit_self {
634 Some(ref self_ptr) => {
635 let (self_expr, explicit_self) =
636 ty::get_explicit_self(cx, trait_.span, self_ptr);
638 self_args.push(self_expr);
643 None => codemap::respan(trait_.span, ast::SelfStatic),
646 for (i, ty) in self.args.iter().enumerate() {
647 let ast_ty = ty.to_ty(cx, trait_.span, type_ident, generics);
648 let ident = cx.ident_of(format!("__arg_{}", i).index(&FullRange));
649 arg_tys.push((ident, ast_ty));
651 let arg_expr = cx.expr_ident(trait_.span, ident);
654 // for static methods, just treat any Self
655 // arguments as a normal arg
656 Self if nonstatic => {
657 self_args.push(arg_expr);
659 Ptr(box Self, _) if nonstatic => {
660 self_args.push(cx.expr_deref(trait_.span, arg_expr))
663 nonself_args.push(arg_expr);
668 (ast_explicit_self, self_args, nonself_args, arg_tys)
671 fn create_method(&self,
677 explicit_self: ast::ExplicitSelf,
678 arg_types: Vec<(Ident, P<ast::Ty>)> ,
679 body: P<Expr>) -> P<ast::Method> {
680 // create the generics that aren't for Self
681 let fn_generics = self.generics.to_generics(cx, trait_.span, type_ident, generics);
683 let self_arg = match explicit_self.node {
684 ast::SelfStatic => None,
685 // creating fresh self id
686 _ => Some(ast::Arg::new_self(trait_.span, ast::MutImmutable, special_idents::self_))
689 let args = arg_types.into_iter().map(|(name, ty)| {
690 cx.arg(trait_.span, name, ty)
692 self_arg.into_iter().chain(args).collect()
695 let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident);
697 let method_ident = cx.ident_of(self.name);
698 let fn_decl = cx.fn_decl(args, ret_type);
699 let body_block = cx.block_expr(body);
701 // Create the method.
703 attrs: self.attributes.clone(),
704 id: ast::DUMMY_NODE_ID,
706 node: ast::MethDecl(method_ident,
710 ast::Unsafety::Normal,
718 /// #[derive(PartialEq)]
719 /// struct A { x: int, y: int }
721 /// // equivalent to:
722 /// impl PartialEq for A {
723 /// fn eq(&self, __arg_1: &A) -> bool {
725 /// A {x: ref __self_0_0, y: ref __self_0_1} => {
727 /// A {x: ref __self_1_0, y: ref __self_1_1} => {
728 /// __self_0_0.eq(__self_1_0) && __self_0_1.eq(__self_1_1)
736 fn expand_struct_method_body(&self,
739 struct_def: &StructDef,
741 self_args: &[P<Expr>],
742 nonself_args: &[P<Expr>])
745 let mut raw_fields = Vec::new(); // ~[[fields of self],
746 // [fields of next Self arg], [etc]]
747 let mut patterns = Vec::new();
748 for i in range(0u, self_args.len()) {
749 let struct_path= cx.path(DUMMY_SP, vec!( type_ident ));
750 let (pat, ident_expr) =
751 trait_.create_struct_pattern(cx,
755 i).index(&FullRange),
758 raw_fields.push(ident_expr);
761 // transpose raw_fields
762 let fields = if raw_fields.len() > 0 {
763 let mut raw_fields = raw_fields.into_iter().map(|v| v.into_iter());
764 let first_field = raw_fields.next().unwrap();
765 let mut other_fields: Vec<vec::IntoIter<(Span, Option<Ident>, P<Expr>)>>
766 = raw_fields.collect();
767 first_field.map(|(span, opt_id, field)| {
772 other: other_fields.iter_mut().map(|l| {
773 match l.next().unwrap() {
780 cx.span_bug(trait_.span,
781 "no self arguments to non-static method in generic \
785 // body of the inner most destructuring match
786 let mut body = self.call_substructure_method(
794 // make a series of nested matches, to destructure the
795 // structs. This is actually right-to-left, but it shouldn't
797 for (arg_expr, pat) in self_args.iter().zip(patterns.iter()) {
798 body = cx.expr_match(trait_.span, arg_expr.clone(),
799 vec!( cx.arm(trait_.span, vec!(pat.clone()), body) ))
804 fn expand_static_struct_method_body(&self,
807 struct_def: &StructDef,
809 self_args: &[P<Expr>],
810 nonself_args: &[P<Expr>])
812 let summary = trait_.summarise_struct(cx, struct_def);
814 self.call_substructure_method(cx,
817 self_args, nonself_args,
818 &StaticStruct(struct_def, summary))
822 /// #[derive(PartialEq)]
828 /// // is equivalent to
830 /// impl PartialEq for A {
831 /// fn eq(&self, __arg_1: &A) -> ::bool {
832 /// match (&*self, &*__arg_1) {
833 /// (&A1, &A1) => true,
834 /// (&A2(ref __self_0),
835 /// &A2(ref __arg_1_0)) => (*__self_0).eq(&(*__arg_1_0)),
837 /// let __self_vi = match *self { A1(..) => 0u, A2(..) => 1u };
838 /// let __arg_1_vi = match *__arg_1 { A1(..) => 0u, A2(..) => 1u };
846 /// (Of course `__self_vi` and `__arg_1_vi` are unused for
847 /// `PartialEq`, and those subcomputations will hopefully be removed
848 /// as their results are unused. The point of `__self_vi` and
849 /// `__arg_1_vi` is for `PartialOrd`; see #15503.)
850 fn expand_enum_method_body(&self,
855 self_args: Vec<P<Expr>>,
856 nonself_args: &[P<Expr>])
858 self.build_enum_match_tuple(
859 cx, trait_, enum_def, type_ident, self_args, nonself_args)
863 /// Creates a match for a tuple of all `self_args`, where either all
864 /// variants match, or it falls into a catch-all for when one variant
867 /// There are N + 1 cases because is a case for each of the N
868 /// variants where all of the variants match, and one catch-all for
869 /// when one does not match.
871 /// The catch-all handler is provided access the variant index values
872 /// for each of the self-args, carried in precomputed variables. (Nota
873 /// bene: the variant index values are not necessarily the
874 /// discriminant values. See issue #15523.)
877 /// match (this, that, ...) {
878 /// (Variant1, Variant1, Variant1) => ... // delegate Matching on Variant1
879 /// (Variant2, Variant2, Variant2) => ... // delegate Matching on Variant2
882 /// let __this_vi = match this { Variant1 => 0u, Variant2 => 1u, ... };
883 /// let __that_vi = match that { Variant1 => 0u, Variant2 => 1u, ... };
884 /// ... // catch-all remainder can inspect above variant index values.
888 fn build_enum_match_tuple(
894 self_args: Vec<P<Expr>>,
895 nonself_args: &[P<Expr>]) -> P<Expr> {
897 let sp = trait_.span;
898 let variants = &enum_def.variants;
900 let self_arg_names = self_args.iter().enumerate()
901 .map(|(arg_count, _self_arg)| {
905 format!("__arg_{}", arg_count)
908 .collect::<Vec<String>>();
910 let self_arg_idents = self_arg_names.iter()
911 .map(|name|cx.ident_of(name.index(&FullRange)))
912 .collect::<Vec<ast::Ident>>();
914 // The `vi_idents` will be bound, solely in the catch-all, to
915 // a series of let statements mapping each self_arg to a uint
916 // corresponding to its variant index.
917 let vi_idents: Vec<ast::Ident> = self_arg_names.iter()
918 .map(|name| { let vi_suffix = format!("{}_vi", name.index(&FullRange));
919 cx.ident_of(vi_suffix.index(&FullRange)) })
920 .collect::<Vec<ast::Ident>>();
922 // Builds, via callback to call_substructure_method, the
923 // delegated expression that handles the catch-all case,
924 // using `__variants_tuple` to drive logic if necessary.
925 let catch_all_substructure = EnumNonMatchingCollapsed(
926 self_arg_idents, variants.index(&FullRange), vi_idents.index(&FullRange));
928 // These arms are of the form:
929 // (Variant1, Variant1, ...) => Body1
930 // (Variant2, Variant2, ...) => Body2
932 // where each tuple has length = self_args.len()
933 let mut match_arms: Vec<ast::Arm> = variants.iter().enumerate()
934 .map(|(index, variant)| {
935 let mk_self_pat = |&: cx: &mut ExtCtxt, self_arg_name: &str| {
936 let (p, idents) = trait_.create_enum_variant_pattern(cx, type_ident,
940 (cx.pat(sp, ast::PatRegion(p, ast::MutImmutable)), idents)
943 // A single arm has form (&VariantK, &VariantK, ...) => BodyK
944 // (see "Final wrinkle" note below for why.)
945 let mut subpats = Vec::with_capacity(self_arg_names.len());
946 let mut self_pats_idents = Vec::with_capacity(self_arg_names.len() - 1);
947 let first_self_pat_idents = {
948 let (p, idents) = mk_self_pat(cx, self_arg_names[0].index(&FullRange));
952 for self_arg_name in self_arg_names.tail().iter() {
953 let (p, idents) = mk_self_pat(cx, self_arg_name.index(&FullRange));
955 self_pats_idents.push(idents);
958 // Here is the pat = `(&VariantK, &VariantK, ...)`
959 let single_pat = cx.pat_tuple(sp, subpats);
961 // For the BodyK, we need to delegate to our caller,
962 // passing it an EnumMatching to indicate which case
965 // All of the Self args have the same variant in these
966 // cases. So we transpose the info in self_pats_idents
967 // to gather the getter expressions together, in the
968 // form that EnumMatching expects.
970 // The transposition is driven by walking across the
971 // arg fields of the variant for the first self pat.
972 let field_tuples = first_self_pat_idents.into_iter().enumerate()
973 // For each arg field of self, pull out its getter expr ...
974 .map(|(field_index, (sp, opt_ident, self_getter_expr))| {
975 // ... but FieldInfo also wants getter expr
976 // for matching other arguments of Self type;
977 // so walk across the *other* self_pats_idents
978 // and pull out getter for same field in each
979 // of them (using `field_index` tracked above).
980 // That is the heart of the transposition.
981 let others = self_pats_idents.iter().map(|fields| {
982 let (_, _opt_ident, ref other_getter_expr) =
985 // All Self args have same variant, so
986 // opt_idents are the same. (Assert
987 // here to make it self-evident that
988 // it is okay to ignore `_opt_ident`.)
989 assert!(opt_ident == _opt_ident);
991 other_getter_expr.clone()
992 }).collect::<Vec<P<Expr>>>();
994 FieldInfo { span: sp,
996 self_: self_getter_expr,
999 }).collect::<Vec<FieldInfo>>();
1001 // Now, for some given VariantK, we have built up
1002 // expressions for referencing every field of every
1003 // Self arg, assuming all are instances of VariantK.
1004 // Build up code associated with such a case.
1005 let substructure = EnumMatching(index,
1008 let arm_expr = self.call_substructure_method(
1009 cx, trait_, type_ident, self_args.index(&FullRange), nonself_args,
1012 cx.arm(sp, vec![single_pat], arm_expr)
1015 // We will usually need the catch-all after matching the
1016 // tuples `(VariantK, VariantK, ...)` for each VariantK of the
1019 // * when there is only one Self arg, the arms above suffice
1020 // (and the deriving we call back into may not be prepared to
1021 // handle EnumNonMatchCollapsed), and,
1023 // * when the enum has only one variant, the single arm that
1024 // is already present always suffices.
1026 // * In either of the two cases above, if we *did* add a
1027 // catch-all `_` match, it would trigger the
1028 // unreachable-pattern error.
1030 if variants.len() > 1 && self_args.len() > 1 {
1031 let arms: Vec<ast::Arm> = variants.iter().enumerate()
1032 .map(|(index, variant)| {
1033 let pat = variant_to_pat(cx, sp, type_ident, &**variant);
1034 let lit = ast::LitInt(index as u64, ast::UnsignedIntLit(ast::TyUs));
1035 cx.arm(sp, vec![pat], cx.expr_lit(sp, lit))
1038 // Build a series of let statements mapping each self_arg
1039 // to a uint corresponding to its variant index.
1040 // i.e. for `enum E<T> { A, B(1), C(T, T) }`, and a deriving
1041 // with three Self args, builds three statements:
1044 // let __self0_vi = match self {
1045 // A => 0u, B(..) => 1u, C(..) => 2u
1047 // let __self1_vi = match __arg1 {
1048 // A => 0u, B(..) => 1u, C(..) => 2u
1050 // let __self2_vi = match __arg2 {
1051 // A => 0u, B(..) => 1u, C(..) => 2u
1054 let mut index_let_stmts: Vec<P<ast::Stmt>> = Vec::new();
1055 for (&ident, self_arg) in vi_idents.iter().zip(self_args.iter()) {
1056 let variant_idx = cx.expr_match(sp, self_arg.clone(), arms.clone());
1057 let let_stmt = cx.stmt_let(sp, false, ident, variant_idx);
1058 index_let_stmts.push(let_stmt);
1061 let arm_expr = self.call_substructure_method(
1062 cx, trait_, type_ident, self_args.index(&FullRange), nonself_args,
1063 &catch_all_substructure);
1065 // Builds the expression:
1067 // let __self0_vi = ...;
1068 // let __self1_vi = ...;
1070 // <delegated expression referring to __self0_vi, et al.>
1072 let arm_expr = cx.expr_block(
1073 cx.block_all(sp, Vec::new(), index_let_stmts, Some(arm_expr)));
1076 // _ => { let __self0_vi = ...;
1077 // let __self1_vi = ...;
1079 // <delegated expression as above> }
1080 let catch_all_match_arm =
1081 cx.arm(sp, vec![cx.pat_wild(sp)], arm_expr);
1083 match_arms.push(catch_all_match_arm);
1085 } else if variants.len() == 0 {
1086 // As an additional wrinkle, For a zero-variant enum A,
1087 // currently the compiler
1088 // will accept `fn (a: &Self) { match *a { } }`
1089 // but rejects `fn (a: &Self) { match (&*a,) { } }`
1090 // as well as `fn (a: &Self) { match ( *a,) { } }`
1092 // This means that the strategy of building up a tuple of
1093 // all Self arguments fails when Self is a zero variant
1094 // enum: rustc rejects the expanded program, even though
1095 // the actual code tends to be impossible to execute (at
1096 // least safely), according to the type system.
1098 // The most expedient fix for this is to just let the
1099 // code fall through to the catch-all. But even this is
1100 // error-prone, since the catch-all as defined above would
1101 // generate code like this:
1103 // _ => { let __self0 = match *self { };
1104 // let __self1 = match *__arg_0 { };
1105 // <catch-all-expr> }
1107 // Which is yields bindings for variables which type
1108 // inference cannot resolve to unique types.
1110 // One option to the above might be to add explicit type
1111 // annotations. But the *only* reason to go down that path
1112 // would be to try to make the expanded output consistent
1113 // with the case when the number of enum variants >= 1.
1115 // That just isn't worth it. In fact, trying to generate
1116 // sensible code for *any* deriving on a zero-variant enum
1117 // does not make sense. But at the same time, for now, we
1118 // do not want to cause a compile failure just because the
1119 // user happened to attach a deriving to their
1120 // zero-variant enum.
1122 // Instead, just generate a failing expression for the
1123 // zero variant case, skipping matches and also skipping
1124 // delegating back to the end user code entirely.
1126 // (See also #4499 and #12609; note that some of the
1127 // discussions there influence what choice we make here;
1128 // e.g. if we feature-gate `match x { ... }` when x refers
1129 // to an uninhabited type (e.g. a zero-variant enum or a
1130 // type holding such an enum), but do not feature-gate
1131 // zero-variant enums themselves, then attempting to
1132 // derive Show on such a type could here generate code
1133 // that needs the feature gate enabled.)
1135 return cx.expr_unreachable(sp);
1138 // Final wrinkle: the self_args are expressions that deref
1139 // down to desired l-values, but we cannot actually deref
1140 // them when they are fed as r-values into a tuple
1141 // expression; here add a layer of borrowing, turning
1142 // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
1143 let borrowed_self_args = self_args.move_map(|self_arg| cx.expr_addr_of(sp, self_arg));
1144 let match_arg = cx.expr(sp, ast::ExprTup(borrowed_self_args));
1145 cx.expr_match(sp, match_arg, match_arms)
1148 fn expand_static_enum_method_body(&self,
1153 self_args: &[P<Expr>],
1154 nonself_args: &[P<Expr>])
1156 let summary = enum_def.variants.iter().map(|v| {
1157 let ident = v.node.name;
1158 let summary = match v.node.kind {
1159 ast::TupleVariantKind(ref args) => {
1160 Unnamed(args.iter().map(|va| trait_.set_expn_info(cx, va.ty.span)).collect())
1162 ast::StructVariantKind(ref struct_def) => {
1163 trait_.summarise_struct(cx, &**struct_def)
1166 (ident, v.span, summary)
1168 self.call_substructure_method(cx, trait_, type_ident,
1169 self_args, nonself_args,
1170 &StaticEnum(enum_def, summary))
1174 #[derive(PartialEq)] // dogfooding!
1176 Unknown, Record, Tuple
1179 // general helper methods.
1180 impl<'a> TraitDef<'a> {
1181 fn set_expn_info(&self,
1183 mut to_set: Span) -> Span {
1184 let trait_name = match self.path.path.last() {
1185 None => cx.span_bug(self.span, "trait with empty path in generic `derive`"),
1188 to_set.expn_id = cx.codemap().record_expansion(codemap::ExpnInfo {
1190 callee: codemap::NameAndSpan {
1191 name: format!("deriving({})", trait_name),
1192 format: codemap::MacroAttribute,
1193 span: Some(self.span)
1199 fn summarise_struct(&self,
1201 struct_def: &StructDef) -> StaticFields {
1202 let mut named_idents = Vec::new();
1203 let mut just_spans = Vec::new();
1204 for field in struct_def.fields.iter(){
1205 let sp = self.set_expn_info(cx, field.span);
1206 match field.node.kind {
1207 ast::NamedField(ident, _) => named_idents.push((ident, sp)),
1208 ast::UnnamedField(..) => just_spans.push(sp),
1212 match (just_spans.is_empty(), named_idents.is_empty()) {
1213 (false, false) => cx.span_bug(self.span,
1214 "a struct with named and unnamed \
1215 fields in generic `derive`"),
1217 (_, false) => Named(named_idents),
1218 // tuple structs (includes empty structs)
1219 (_, _) => Unnamed(just_spans)
1223 fn create_subpatterns(&self,
1225 field_paths: Vec<ast::SpannedIdent> ,
1226 mutbl: ast::Mutability)
1227 -> Vec<P<ast::Pat>> {
1228 field_paths.iter().map(|path| {
1230 ast::PatIdent(ast::BindByRef(mutbl), (*path).clone(), None))
1234 fn create_struct_pattern(&self,
1236 struct_path: ast::Path,
1237 struct_def: &StructDef,
1239 mutbl: ast::Mutability)
1240 -> (P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>) {
1241 if struct_def.fields.is_empty() {
1242 return (cx.pat_enum(self.span, struct_path, vec![]), vec![]);
1245 let mut paths = Vec::new();
1246 let mut ident_expr = Vec::new();
1247 let mut struct_type = Unknown;
1249 for (i, struct_field) in struct_def.fields.iter().enumerate() {
1250 let sp = self.set_expn_info(cx, struct_field.span);
1251 let opt_id = match struct_field.node.kind {
1252 ast::NamedField(ident, _) if (struct_type == Unknown ||
1253 struct_type == Record) => {
1254 struct_type = Record;
1257 ast::UnnamedField(..) if (struct_type == Unknown ||
1258 struct_type == Tuple) => {
1259 struct_type = Tuple;
1263 cx.span_bug(sp, "a struct with named and unnamed fields in `derive`");
1266 let ident = cx.ident_of(format!("{}_{}", prefix, i).index(&FullRange));
1267 paths.push(codemap::Spanned{span: sp, node: ident});
1269 sp, ast::ExprParen(cx.expr_deref(sp, cx.expr_path(cx.path_ident(sp,ident)))));
1270 ident_expr.push((sp, opt_id, val));
1273 let subpats = self.create_subpatterns(cx, paths, mutbl);
1275 // struct_type is definitely not Unknown, since struct_def.fields
1276 // must be nonempty to reach here
1277 let pattern = if struct_type == Record {
1278 let field_pats = subpats.into_iter().zip(ident_expr.iter()).map(|(pat, &(_, id, _))| {
1279 // id is guaranteed to be Some
1282 node: ast::FieldPat { ident: id.unwrap(), pat: pat, is_shorthand: false },
1285 cx.pat_struct(self.span, struct_path, field_pats)
1287 cx.pat_enum(self.span, struct_path, subpats)
1290 (pattern, ident_expr)
1293 fn create_enum_variant_pattern(&self,
1295 enum_ident: ast::Ident,
1296 variant: &ast::Variant,
1298 mutbl: ast::Mutability)
1299 -> (P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>) {
1300 let variant_ident = variant.node.name;
1301 let variant_path = cx.path(variant.span, vec![enum_ident, variant_ident]);
1302 match variant.node.kind {
1303 ast::TupleVariantKind(ref variant_args) => {
1304 if variant_args.is_empty() {
1305 return (cx.pat_enum(variant.span, variant_path, vec![]), vec![]);
1308 let mut paths = Vec::new();
1309 let mut ident_expr = Vec::new();
1310 for (i, va) in variant_args.iter().enumerate() {
1311 let sp = self.set_expn_info(cx, va.ty.span);
1312 let ident = cx.ident_of(format!("{}_{}", prefix, i).index(&FullRange));
1313 let path1 = codemap::Spanned{span: sp, node: ident};
1315 let expr_path = cx.expr_path(cx.path_ident(sp, ident));
1316 let val = cx.expr(sp, ast::ExprParen(cx.expr_deref(sp, expr_path)));
1317 ident_expr.push((sp, None, val));
1320 let subpats = self.create_subpatterns(cx, paths, mutbl);
1322 (cx.pat_enum(variant.span, variant_path, subpats),
1325 ast::StructVariantKind(ref struct_def) => {
1326 self.create_struct_pattern(cx, variant_path, &**struct_def,
1333 /* helpful premade recipes */
1335 /// Fold the fields. `use_foldl` controls whether this is done
1336 /// left-to-right (`true`) or right-to-left (`false`).
1337 pub fn cs_fold<F>(use_foldl: bool,
1340 mut enum_nonmatch_f: EnumNonMatchCollapsedFunc,
1343 substructure: &Substructure)
1345 F: FnMut(&mut ExtCtxt, Span, P<Expr>, P<Expr>, &[P<Expr>]) -> P<Expr>,
1347 match *substructure.fields {
1348 EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => {
1350 all_fields.iter().fold(base, |old, field| {
1354 field.self_.clone(),
1355 field.other.index(&FullRange))
1358 all_fields.iter().rev().fold(base, |old, field| {
1362 field.self_.clone(),
1363 field.other.index(&FullRange))
1367 EnumNonMatchingCollapsed(ref all_args, _, tuple) =>
1368 enum_nonmatch_f(cx, trait_span, (all_args.index(&FullRange), tuple),
1369 substructure.nonself_args),
1370 StaticEnum(..) | StaticStruct(..) => {
1371 cx.span_bug(trait_span, "static function in `derive`")
1377 /// Call the method that is being derived on all the fields, and then
1378 /// process the collected results. i.e.
1381 /// f(cx, span, ~[self_1.method(__arg_1_1, __arg_2_1),
1382 /// self_2.method(__arg_1_2, __arg_2_2)])
1385 pub fn cs_same_method<F>(f: F,
1386 mut enum_nonmatch_f: EnumNonMatchCollapsedFunc,
1389 substructure: &Substructure)
1391 F: FnOnce(&mut ExtCtxt, Span, Vec<P<Expr>>) -> P<Expr>,
1393 match *substructure.fields {
1394 EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => {
1395 // call self_n.method(other_1_n, other_2_n, ...)
1396 let called = all_fields.iter().map(|field| {
1397 cx.expr_method_call(field.span,
1398 field.self_.clone(),
1399 substructure.method_ident,
1401 .map(|e| cx.expr_addr_of(field.span, e.clone()))
1405 f(cx, trait_span, called)
1407 EnumNonMatchingCollapsed(ref all_self_args, _, tuple) =>
1408 enum_nonmatch_f(cx, trait_span, (all_self_args.index(&FullRange), tuple),
1409 substructure.nonself_args),
1410 StaticEnum(..) | StaticStruct(..) => {
1411 cx.span_bug(trait_span, "static function in `derive`")
1416 /// Fold together the results of calling the derived method on all the
1417 /// fields. `use_foldl` controls whether this is done left-to-right
1418 /// (`true`) or right-to-left (`false`).
1420 pub fn cs_same_method_fold<F>(use_foldl: bool,
1423 enum_nonmatch_f: EnumNonMatchCollapsedFunc,
1426 substructure: &Substructure)
1428 F: FnMut(&mut ExtCtxt, Span, P<Expr>, P<Expr>) -> P<Expr>,
1433 vals.into_iter().fold(base.clone(), |old, new| {
1434 f(cx, span, old, new)
1437 vals.into_iter().rev().fold(base.clone(), |old, new| {
1438 f(cx, span, old, new)
1443 cx, trait_span, substructure)
1446 /// Use a given binop to combine the result of calling the derived method
1447 /// on all the fields.
1449 pub fn cs_binop(binop: ast::BinOp, base: P<Expr>,
1450 enum_nonmatch_f: EnumNonMatchCollapsedFunc,
1451 cx: &mut ExtCtxt, trait_span: Span,
1452 substructure: &Substructure) -> P<Expr> {
1453 cs_same_method_fold(
1454 true, // foldl is good enough
1455 |cx, span, old, new| {
1456 cx.expr_binary(span,
1463 cx, trait_span, substructure)
1466 /// cs_binop with binop == or
1468 pub fn cs_or(enum_nonmatch_f: EnumNonMatchCollapsedFunc,
1469 cx: &mut ExtCtxt, span: Span,
1470 substructure: &Substructure) -> P<Expr> {
1471 cs_binop(ast::BiOr, cx.expr_bool(span, false),
1473 cx, span, substructure)
1476 /// cs_binop with binop == and
1478 pub fn cs_and(enum_nonmatch_f: EnumNonMatchCollapsedFunc,
1479 cx: &mut ExtCtxt, span: Span,
1480 substructure: &Substructure) -> P<Expr> {
1481 cs_binop(ast::BiAnd, cx.expr_bool(span, true),
1483 cx, span, substructure)