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 //! `deriving` 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. deriving 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 use std::cell::RefCell;
184 use std::gc::{Gc, GC};
187 use ast::{P, EnumDef, Expr, Ident, Generics, StructDef};
190 use attr::AttrMetaMethods;
191 use ext::base::ExtCtxt;
192 use ext::build::AstBuilder;
195 use owned_slice::OwnedSlice;
196 use parse::token::InternedString;
197 use parse::token::special_idents;
203 pub struct TraitDef<'a> {
204 /// The span for the current #[deriving(Foo)] header.
207 pub attributes: Vec<ast::Attribute>,
209 /// Path of the trait, including any type parameters
212 /// Additional bounds required of any type parameters of the type,
213 /// other than the current trait
214 pub additional_bounds: Vec<Ty<'a>>,
216 /// Any extra lifetimes and/or bounds, e.g. `D: serialize::Decoder`
217 pub generics: LifetimeBounds<'a>,
219 pub methods: Vec<MethodDef<'a>>,
223 pub struct MethodDef<'a> {
224 /// name of the method
226 /// List of generics, e.g. `R: rand::Rng`
227 pub generics: LifetimeBounds<'a>,
229 /// Whether there is a self argument (outer Option) i.e. whether
230 /// this is a static function, and whether it is a pointer (inner
232 pub explicit_self: Option<Option<PtrTy<'a>>>,
234 /// Arguments other than the self argument
235 pub args: Vec<Ty<'a>>,
240 pub attributes: Vec<ast::Attribute>,
242 pub combine_substructure: RefCell<CombineSubstructureFunc<'a>>,
245 /// All the data about the data structure/method being derived upon.
246 pub struct Substructure<'a> {
248 pub type_ident: Ident,
249 /// ident of the method
250 pub method_ident: Ident,
251 /// dereferenced access to any Self or Ptr(Self, _) arguments
252 pub self_args: &'a [Gc<Expr>],
253 /// verbatim access to any other arguments
254 pub nonself_args: &'a [Gc<Expr>],
255 pub fields: &'a SubstructureFields<'a>
258 /// Summary of the relevant parts of a struct/enum field.
259 pub struct FieldInfo {
261 /// None for tuple structs/normal enum variants, Some for normal
262 /// structs/struct enum variants.
263 pub name: Option<Ident>,
264 /// The expression corresponding to this field of `self`
265 /// (specifically, a reference to it).
267 /// The expressions corresponding to references to this field in
268 /// the other Self arguments.
269 pub other: Vec<Gc<Expr>>,
272 /// Fields for a static method
273 pub enum StaticFields {
274 /// Tuple structs/enum variants like this
276 /// Normal structs/struct variants.
277 Named(Vec<(Ident, Span)>),
280 /// A summary of the possible sets of fields. See above for details
282 pub enum SubstructureFields<'a> {
283 Struct(Vec<FieldInfo>),
285 Matching variants of the enum: variant index, ast::Variant,
286 fields: the field name is only non-`None` in the case of a struct
289 EnumMatching(uint, &'a ast::Variant, Vec<FieldInfo>),
292 non-matching variants of the enum, but with all state hidden from
293 the consequent code. The first component holds Idents for all of
294 the Self arguments; the second component is a slice of all of the
295 variants for the enum itself, and the third component is a list of
296 Idents bound to the variant index values for each of the actual
297 input Self arguments.
299 EnumNonMatchingCollapsed(Vec<Ident>, &'a [Gc<ast::Variant>], &'a [Ident]),
301 /// A static method where Self is a struct.
302 StaticStruct(&'a ast::StructDef, StaticFields),
303 /// A static method where Self is an enum.
304 StaticEnum(&'a ast::EnumDef, Vec<(Ident, Span, StaticFields)>),
310 Combine the values of all the fields together. The last argument is
311 all the fields of all the structures, see above for details.
313 pub type CombineSubstructureFunc<'a> =
314 |&mut ExtCtxt, Span, &Substructure|: 'a -> Gc<Expr>;
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.
323 pub type EnumNonMatchCollapsedFunc<'a> =
326 (&[Ident], &[Ident]),
330 pub fn combine_substructure<'a>(f: CombineSubstructureFunc<'a>)
331 -> RefCell<CombineSubstructureFunc<'a>> {
336 impl<'a> TraitDef<'a> {
339 _mitem: Gc<ast::MetaItem>,
341 push: |Gc<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,
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()));
366 push(box(GC) ast::Item {
374 * Given that we are deriving a trait `Tr` for a type `T<'a, ...,
375 * 'z, A, ..., Z>`, creates an impl like:
378 * impl<'a, ..., 'z, A:Tr B1 B2, ..., Z: Tr B1 B2> Tr for T<A, ..., Z> { ... }
381 * where B1, B2, ... are the bounds given by `bounds_paths`.'
384 fn create_derived_impl(&self,
388 methods: Vec<Gc<ast::Method>> ) -> Gc<ast::Item> {
389 let trait_path = self.path.to_path(cx, self.span, type_ident, generics);
391 let Generics { mut lifetimes, ty_params } =
392 self.generics.to_generics(cx, self.span, type_ident, generics);
393 let mut ty_params = ty_params.into_vec();
395 // Copy the lifetimes
396 lifetimes.extend(generics.lifetimes.iter().map(|l| *l));
398 // Create the type parameters.
399 ty_params.extend(generics.ty_params.iter().map(|ty_param| {
400 // I don't think this can be moved out of the loop, since
401 // a TyParamBound requires an ast id
402 let mut bounds: Vec<_> =
403 // extra restrictions on the generics parameters to the type being derived upon
404 self.additional_bounds.iter().map(|p| {
405 cx.typarambound(p.to_path(cx, self.span,
406 type_ident, generics))
408 // require the current trait
409 bounds.push(cx.typarambound(trait_path.clone()));
411 cx.typaram(self.span,
413 OwnedSlice::from_vec(bounds),
414 ty_param.unbound.clone(),
417 let trait_generics = Generics {
418 lifetimes: lifetimes,
419 ty_params: OwnedSlice::from_vec(ty_params)
422 // Create the reference to the trait.
423 let trait_ref = cx.trait_ref(trait_path);
425 // Create the type parameters on the `self` path.
426 let self_ty_params = generics.ty_params.map(|ty_param| {
427 cx.ty_ident(self.span, ty_param.ident)
430 let self_lifetimes = generics.lifetimes.clone();
432 // Create the type of `self`.
433 let self_type = cx.ty_path(
434 cx.path_all(self.span, false, vec!( type_ident ), self_lifetimes,
435 self_ty_params.into_vec()), None);
437 let attr = cx.attribute(
439 cx.meta_word(self.span,
440 InternedString::new("automatically_derived")));
441 // Just mark it now since we know that it'll end up used downstream
442 attr::mark_used(&attr);
443 let opt_trait_ref = Some(trait_ref);
444 let ident = ast_util::impl_pretty_name(&opt_trait_ref, &*self_type);
448 (vec!(attr)).append(self.attributes.as_slice()),
449 ast::ItemImpl(trait_generics, opt_trait_ref,
453 fn expand_struct_def(&self,
455 struct_def: &StructDef,
457 generics: &Generics) -> Gc<ast::Item> {
458 let methods = self.methods.iter().map(|method_def| {
459 let (explicit_self, self_args, nonself_args, tys) =
460 method_def.split_self_nonself_args(
461 cx, self, type_ident, generics);
463 let body = if method_def.is_static() {
464 method_def.expand_static_struct_method_body(
469 self_args.as_slice(),
470 nonself_args.as_slice())
472 method_def.expand_struct_method_body(cx,
476 self_args.as_slice(),
477 nonself_args.as_slice())
480 method_def.create_method(cx, self,
481 type_ident, generics,
486 self.create_derived_impl(cx, type_ident, generics, methods)
489 fn expand_enum_def(&self,
493 generics: &Generics) -> Gc<ast::Item> {
494 let methods = self.methods.iter().map(|method_def| {
495 let (explicit_self, self_args, nonself_args, tys) =
496 method_def.split_self_nonself_args(cx, self,
497 type_ident, generics);
499 let body = if method_def.is_static() {
500 method_def.expand_static_enum_method_body(
505 self_args.as_slice(),
506 nonself_args.as_slice())
508 method_def.expand_enum_method_body(cx,
512 self_args.as_slice(),
513 nonself_args.as_slice())
516 method_def.create_method(cx, self,
517 type_ident, generics,
522 self.create_derived_impl(cx, type_ident, generics, methods)
526 fn variant_to_pat(cx: &mut ExtCtxt, sp: Span, variant: &ast::Variant)
528 let ident = cx.path_ident(sp, variant.node.name);
529 cx.pat(sp, match variant.node.kind {
530 ast::TupleVariantKind(..) => ast::PatEnum(ident, None),
531 ast::StructVariantKind(..) => ast::PatStruct(ident, Vec::new(), true),
535 impl<'a> MethodDef<'a> {
536 fn call_substructure_method(&self,
540 self_args: &[Gc<Expr>],
541 nonself_args: &[Gc<Expr>],
542 fields: &SubstructureFields)
544 let substructure = Substructure {
545 type_ident: type_ident,
546 method_ident: cx.ident_of(self.name),
547 self_args: self_args,
548 nonself_args: nonself_args,
551 let mut f = self.combine_substructure.borrow_mut();
552 let f: &mut CombineSubstructureFunc = &mut *f;
553 (*f)(cx, trait_.span, &substructure)
562 self.ret_ty.to_ty(cx, trait_.span, type_ident, generics)
565 fn is_static(&self) -> bool {
566 self.explicit_self.is_none()
569 fn split_self_nonself_args(&self,
574 -> (ast::ExplicitSelf, Vec<Gc<Expr>>, Vec<Gc<Expr>>,
575 Vec<(Ident, P<ast::Ty>)>) {
577 let mut self_args = Vec::new();
578 let mut nonself_args = Vec::new();
579 let mut arg_tys = Vec::new();
580 let mut nonstatic = false;
582 let ast_explicit_self = match self.explicit_self {
583 Some(ref self_ptr) => {
584 let (self_expr, explicit_self) =
585 ty::get_explicit_self(cx, trait_.span, self_ptr);
587 self_args.push(self_expr);
592 None => codemap::respan(trait_.span, ast::SelfStatic),
595 for (i, ty) in self.args.iter().enumerate() {
596 let ast_ty = ty.to_ty(cx, trait_.span, type_ident, generics);
597 let ident = cx.ident_of(format!("__arg_{}", i).as_slice());
598 arg_tys.push((ident, ast_ty));
600 let arg_expr = cx.expr_ident(trait_.span, ident);
603 // for static methods, just treat any Self
604 // arguments as a normal arg
605 Self if nonstatic => {
606 self_args.push(arg_expr);
608 Ptr(box Self, _) if nonstatic => {
609 self_args.push(cx.expr_deref(trait_.span, arg_expr))
612 nonself_args.push(arg_expr);
617 (ast_explicit_self, self_args, nonself_args, arg_tys)
620 fn create_method(&self,
625 explicit_self: ast::ExplicitSelf,
626 arg_types: Vec<(Ident, P<ast::Ty>)> ,
627 body: Gc<Expr>) -> Gc<ast::Method> {
628 // create the generics that aren't for Self
629 let fn_generics = self.generics.to_generics(cx, trait_.span, type_ident, generics);
631 let self_arg = match explicit_self.node {
632 ast::SelfStatic => None,
633 // creating fresh self id
634 _ => Some(ast::Arg::new_self(trait_.span, ast::MutImmutable, special_idents::self_))
637 let args = arg_types.move_iter().map(|(name, ty)| {
638 cx.arg(trait_.span, name, ty)
640 self_arg.move_iter().chain(args).collect()
643 let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident);
645 let method_ident = cx.ident_of(self.name);
646 let fn_decl = cx.fn_decl(args, ret_type);
647 let body_block = cx.block_expr(body);
649 // Create the method.
650 box(GC) ast::Method {
651 attrs: self.attributes.clone(),
652 id: ast::DUMMY_NODE_ID,
654 node: ast::MethDecl(method_ident,
666 #[deriving(PartialEq)]
667 struct A { x: int, y: int }
670 impl PartialEq for A {
671 fn eq(&self, __arg_1: &A) -> bool {
673 A {x: ref __self_0_0, y: ref __self_0_1} => {
675 A {x: ref __self_1_0, y: ref __self_1_1} => {
676 __self_0_0.eq(__self_1_0) && __self_0_1.eq(__self_1_1)
685 fn expand_struct_method_body(&self,
688 struct_def: &StructDef,
690 self_args: &[Gc<Expr>],
691 nonself_args: &[Gc<Expr>])
694 let mut raw_fields = Vec::new(); // ~[[fields of self],
695 // [fields of next Self arg], [etc]]
696 let mut patterns = Vec::new();
697 for i in range(0u, self_args.len()) {
698 let (pat, ident_expr) =
699 trait_.create_struct_pattern(cx,
706 raw_fields.push(ident_expr);
709 // transpose raw_fields
710 let fields = if raw_fields.len() > 0 {
714 .map(|(i, &(span, opt_id, field))| {
715 let other_fields = raw_fields.tail().iter().map(|l| {
728 cx.span_bug(trait_.span,
729 "no self arguments to non-static method in generic \
733 // body of the inner most destructuring match
734 let mut body = self.call_substructure_method(
742 // make a series of nested matches, to destructure the
743 // structs. This is actually right-to-left, but it shouldn't
745 for (&arg_expr, &pat) in self_args.iter().zip(patterns.iter()) {
746 body = cx.expr_match(trait_.span, arg_expr,
747 vec!( cx.arm(trait_.span, vec!(pat), body) ))
752 fn expand_static_struct_method_body(&self,
755 struct_def: &StructDef,
757 self_args: &[Gc<Expr>],
758 nonself_args: &[Gc<Expr>])
760 let summary = trait_.summarise_struct(cx, struct_def);
762 self.call_substructure_method(cx,
765 self_args, nonself_args,
766 &StaticStruct(struct_def, summary))
771 #[deriving(PartialEq)]
779 impl PartialEq for A {
780 fn eq(&self, __arg_1: &A) -> ::bool {
781 match (&*self, &*__arg_1) {
784 &A2(ref __arg_1_0)) => (*__self_0).eq(&(*__arg_1_0)),
786 let __self_vi = match *self { A1(..) => 0u, A2(..) => 1u };
787 let __arg_1_vi = match *__arg_1 { A1(..) => 0u, A2(..) => 1u };
795 (Of course `__self_vi` and `__arg_1_vi` are unused for
796 `PartialEq`, and those subcomputations will hopefully be removed
797 as their results are unused. The point of `__self_vi` and
798 `__arg_1_vi` is for `PartialOrd`; see #15503.)
800 fn expand_enum_method_body(&self,
805 self_args: &[Gc<Expr>],
806 nonself_args: &[Gc<Expr>])
808 self.build_enum_match_tuple(
809 cx, trait_, enum_def, type_ident, self_args, nonself_args)
814 Creates a match for a tuple of all `self_args`, where either all
815 variants match, or it falls into a catch-all for when one variant
818 There are N + 1 cases because is a case for each of the N
819 variants where all of the variants match, and one catch-all for
820 when one does not match.
822 The catch-all handler is provided access the variant index values
823 for each of the self-args, carried in precomputed variables. (Nota
824 bene: the variant index values are not necessarily the
825 discriminant values. See issue #15523.)
828 match (this, that, ...) {
829 (Variant1, Variant1, Variant1) => ... // delegate Matching on Variant1
830 (Variant2, Variant2, Variant2) => ... // delegate Matching on Variant2
833 let __this_vi = match this { Variant1 => 0u, Variant2 => 1u, ... };
834 let __that_vi = match that { Variant1 => 0u, Variant2 => 1u, ... };
835 ... // catch-all remainder can inspect above variant index values.
840 fn build_enum_match_tuple(
846 self_args: &[Gc<Expr>],
847 nonself_args: &[Gc<Expr>]) -> Gc<Expr> {
849 let sp = trait_.span;
850 let variants = &enum_def.variants;
852 let self_arg_names = self_args.iter().enumerate()
853 .map(|(arg_count, _self_arg)| {
857 format!("__arg_{}", arg_count)
860 .collect::<Vec<String>>();
862 let self_arg_idents = self_arg_names.iter()
863 .map(|name|cx.ident_of(name.as_slice()))
864 .collect::<Vec<ast::Ident>>();
866 // The `vi_idents` will be bound, solely in the catch-all, to
867 // a series of let statements mapping each self_arg to a uint
868 // corresponding to its variant index.
869 let vi_idents : Vec<ast::Ident> = self_arg_names.iter()
870 .map(|name| { let vi_suffix = format!("{:s}_vi", name.as_slice());
871 cx.ident_of(vi_suffix.as_slice()) })
872 .collect::<Vec<ast::Ident>>();
874 // Builds, via callback to call_substructure_method, the
875 // delegated expression that handles the catch-all case,
876 // using `__variants_tuple` to drive logic if necessary.
877 let catch_all_substructure = EnumNonMatchingCollapsed(
878 self_arg_idents, variants.as_slice(), vi_idents.as_slice());
880 // These arms are of the form:
881 // (Variant1, Variant1, ...) => Body1
882 // (Variant2, Variant2, ...) => Body2
884 // where each tuple has length = self_args.len()
885 let mut match_arms : Vec<ast::Arm> = variants.iter().enumerate()
886 .map(|(index, &variant)| {
888 // These self_pats have form Variant1, Variant2, ...
889 let self_pats : Vec<(Gc<ast::Pat>,
890 Vec<(Span, Option<Ident>, Gc<Expr>)>)>;
891 self_pats = self_arg_names.iter()
893 trait_.create_enum_variant_pattern(
894 cx, &*variant, self_arg_name.as_slice(),
898 // A single arm has form (&VariantK, &VariantK, ...) => BodyK
899 // (see "Final wrinkle" note below for why.)
900 let subpats = self_pats.iter()
901 .map(|&(p, ref _idents)| cx.pat(sp, ast::PatRegion(p)))
902 .collect::<Vec<Gc<ast::Pat>>>();
904 // Here is the pat = `(&VariantK, &VariantK, ...)`
905 let single_pat = cx.pat(sp, ast::PatTup(subpats));
907 // For the BodyK, we need to delegate to our caller,
908 // passing it an EnumMatching to indicate which case
911 // All of the Self args have the same variant in these
912 // cases. So we transpose the info in self_pats to
913 // gather the getter expressions together, in the form
914 // that EnumMatching expects.
916 // The transposition is driven by walking across the
917 // arg fields of the variant for the first self pat.
918 let &(_, ref self_arg_fields) = self_pats.get(0);
920 let field_tuples : Vec<FieldInfo>;
922 field_tuples = self_arg_fields.iter().enumerate()
923 // For each arg field of self, pull out its getter expr ...
924 .map(|(field_index, &(sp, opt_ident, self_getter_expr))| {
925 // ... but FieldInfo also wants getter expr
926 // for matching other arguments of Self type;
927 // so walk across the *other* self_pats and
928 // pull out getter for same field in each of
929 // them (using `field_index` tracked above).
930 // That is the heart of the transposition.
931 let others = self_pats.tail().iter()
932 .map(|&(_pat, ref fields)| {
934 let &(_, _opt_ident, other_getter_expr) =
935 fields.get(field_index);
937 // All Self args have same variant, so
938 // opt_idents are the same. (Assert
939 // here to make it self-evident that
940 // it is okay to ignore `_opt_ident`.)
941 assert!(opt_ident == _opt_ident);
944 }).collect::<Vec<Gc<Expr>>>();
946 FieldInfo { span: sp,
948 self_: self_getter_expr,
951 }).collect::<Vec<FieldInfo>>();
953 // Now, for some given VariantK, we have built up
954 // expressions for referencing every field of every
955 // Self arg, assuming all are instances of VariantK.
956 // Build up code associated with such a case.
957 let substructure = EnumMatching(index, variant, field_tuples);
958 let arm_expr = self.call_substructure_method(
959 cx, trait_, type_ident, self_args, nonself_args,
962 cx.arm(sp, vec![single_pat], arm_expr)
965 // We will usually need the catch-all after matching the
966 // tuples `(VariantK, VariantK, ...)` for each VariantK of the
969 // * when there is only one Self arg, the arms above suffice
970 // (and the deriving we call back into may not be prepared to
971 // handle EnumNonMatchCollapsed), and,
973 // * when the enum has only one variant, the single arm that
974 // is already present always suffices.
976 // * In either of the two cases above, if we *did* add a
977 // catch-all `_` match, it would trigger the
978 // unreachable-pattern error.
980 if variants.len() > 1 && self_args.len() > 1 {
981 let arms : Vec<ast::Arm> = variants.iter().enumerate()
982 .map(|(index, &variant)| {
983 let pat = variant_to_pat(cx, sp, &*variant);
984 let lit = ast::LitUint(index as u64, ast::TyU);
985 cx.arm(sp, vec![pat], cx.expr_lit(sp, lit))
988 // Build a series of let statements mapping each self_arg
989 // to a uint corresponding to its variant index.
990 // i.e. for `enum E<T> { A, B(1), C(T, T) }`, and a deriving
991 // with three Self args, builds three statements:
994 // let __self0_vi = match self {
995 // A => 0u, B(..) => 1u, C(..) => 2u
997 // let __self1_vi = match __arg1 {
998 // A => 0u, B(..) => 1u, C(..) => 2u
1000 // let __self2_vi = match __arg2 {
1001 // A => 0u, B(..) => 1u, C(..) => 2u
1004 let mut index_let_stmts : Vec<Gc<ast::Stmt>> = Vec::new();
1005 for (&ident, &self_arg) in vi_idents.iter().zip(self_args.iter()) {
1006 let variant_idx = cx.expr_match(sp, self_arg, arms.clone());
1007 let let_stmt = cx.stmt_let(sp, false, ident, variant_idx);
1008 index_let_stmts.push(let_stmt);
1011 let arm_expr = self.call_substructure_method(
1012 cx, trait_, type_ident, self_args, nonself_args,
1013 &catch_all_substructure);
1015 // Builds the expression:
1017 // let __self0_vi = ...;
1018 // let __self1_vi = ...;
1020 // <delegated expression referring to __self0_vi, et al.>
1022 let arm_expr = cx.expr_block(
1023 cx.block_all(sp, Vec::new(), index_let_stmts, Some(arm_expr)));
1026 // _ => { let __self0_vi = ...;
1027 // let __self1_vi = ...;
1029 // <delegated expression as above> }
1030 let catch_all_match_arm =
1031 cx.arm(sp, vec![cx.pat_wild(sp)], arm_expr);
1033 match_arms.push(catch_all_match_arm);
1035 } else if variants.len() == 0 {
1036 // As an additional wrinkle, For a zero-variant enum A,
1037 // currently the compiler
1038 // will accept `fn (a: &Self) { match *a { } }`
1039 // but rejects `fn (a: &Self) { match (&*a,) { } }`
1040 // as well as `fn (a: &Self) { match ( *a,) { } }`
1042 // This means that the strategy of building up a tuple of
1043 // all Self arguments fails when Self is a zero variant
1044 // enum: rustc rejects the expanded program, even though
1045 // the actual code tends to be impossible to execute (at
1046 // least safely), according to the type system.
1048 // The most expedient fix for this is to just let the
1049 // code fall through to the catch-all. But even this is
1050 // error-prone, since the catch-all as defined above would
1051 // generate code like this:
1053 // _ => { let __self0 = match *self { };
1054 // let __self1 = match *__arg_0 { };
1055 // <catch-all-expr> }
1057 // Which is yields bindings for variables which type
1058 // inference cannot resolve to unique types.
1060 // One option to the above might be to add explicit type
1061 // annotations. But the *only* reason to go down that path
1062 // would be to try to make the expanded output consistent
1063 // with the case when the number of enum variants >= 1.
1065 // That just isn't worth it. In fact, trying to generate
1066 // sensible code for *any* deriving on a zero-variant enum
1067 // does not make sense. But at the same time, for now, we
1068 // do not want to cause a compile failure just because the
1069 // user happened to attach a deriving to their
1070 // zero-variant enum.
1072 // Instead, just generate a failing expression for the
1073 // zero variant case, skipping matches and also skipping
1074 // delegating back to the end user code entirely.
1076 // (See also #4499 and #12609; note that some of the
1077 // discussions there influence what choice we make here;
1078 // e.g. if we feature-gate `match x { ... }` when x refers
1079 // to an uninhabited type (e.g. a zero-variant enum or a
1080 // type holding such an enum), but do not feature-gate
1081 // zero-variant enums themselves, then attempting to
1082 // derive Show on such a type could here generate code
1083 // that needs the feature gate enabled.)
1085 return cx.expr_unreachable(sp);
1088 // Final wrinkle: the self_args are expressions that deref
1089 // down to desired l-values, but we cannot actually deref
1090 // them when they are fed as r-values into a tuple
1091 // expression; here add a layer of borrowing, turning
1092 // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
1093 let borrowed_self_args = self_args.iter()
1094 .map(|&self_arg| cx.expr_addr_of(sp, self_arg))
1095 .collect::<Vec<Gc<ast::Expr>>>();
1096 let match_arg = cx.expr(sp, ast::ExprTup(borrowed_self_args));
1097 cx.expr_match(sp, match_arg, match_arms)
1100 fn expand_static_enum_method_body(&self,
1105 self_args: &[Gc<Expr>],
1106 nonself_args: &[Gc<Expr>])
1108 let summary = enum_def.variants.iter().map(|v| {
1109 let ident = v.node.name;
1110 let summary = match v.node.kind {
1111 ast::TupleVariantKind(ref args) => {
1112 Unnamed(args.iter().map(|va| trait_.set_expn_info(cx, va.ty.span)).collect())
1114 ast::StructVariantKind(ref struct_def) => {
1115 trait_.summarise_struct(cx, &**struct_def)
1118 (ident, v.span, summary)
1120 self.call_substructure_method(cx, trait_, type_ident,
1121 self_args, nonself_args,
1122 &StaticEnum(enum_def, summary))
1126 #[deriving(PartialEq)] // dogfooding!
1128 Unknown, Record, Tuple
1131 // general helper methods.
1132 impl<'a> TraitDef<'a> {
1133 fn set_expn_info(&self,
1135 mut to_set: Span) -> Span {
1136 let trait_name = match self.path.path.last() {
1137 None => cx.span_bug(self.span, "trait with empty path in generic `deriving`"),
1140 to_set.expn_info = Some(box(GC) codemap::ExpnInfo {
1142 callee: codemap::NameAndSpan {
1143 name: format!("deriving({})", trait_name),
1144 format: codemap::MacroAttribute,
1145 span: Some(self.span)
1151 fn summarise_struct(&self,
1153 struct_def: &StructDef) -> StaticFields {
1154 let mut named_idents = Vec::new();
1155 let mut just_spans = Vec::new();
1156 for field in struct_def.fields.iter(){
1157 let sp = self.set_expn_info(cx, field.span);
1158 match field.node.kind {
1159 ast::NamedField(ident, _) => named_idents.push((ident, sp)),
1160 ast::UnnamedField(..) => just_spans.push(sp),
1164 match (just_spans.is_empty(), named_idents.is_empty()) {
1165 (false, false) => cx.span_bug(self.span,
1166 "a struct with named and unnamed \
1167 fields in generic `deriving`"),
1169 (_, false) => Named(named_idents),
1170 // tuple structs (includes empty structs)
1171 (_, _) => Unnamed(just_spans)
1175 fn create_subpatterns(&self,
1177 field_paths: Vec<ast::SpannedIdent> ,
1178 mutbl: ast::Mutability)
1179 -> Vec<Gc<ast::Pat>> {
1180 field_paths.iter().map(|path| {
1182 ast::PatIdent(ast::BindByRef(mutbl), (*path).clone(), None))
1186 fn create_struct_pattern(&self,
1188 struct_ident: Ident,
1189 struct_def: &StructDef,
1191 mutbl: ast::Mutability)
1192 -> (Gc<ast::Pat>, Vec<(Span, Option<Ident>, Gc<Expr>)>) {
1193 if struct_def.fields.is_empty() {
1195 cx.pat_ident_binding_mode(
1196 self.span, struct_ident, ast::BindByValue(ast::MutImmutable)),
1200 let matching_path = cx.path(self.span, vec!( struct_ident ));
1202 let mut paths = Vec::new();
1203 let mut ident_expr = Vec::new();
1204 let mut struct_type = Unknown;
1206 for (i, struct_field) in struct_def.fields.iter().enumerate() {
1207 let sp = self.set_expn_info(cx, struct_field.span);
1208 let opt_id = match struct_field.node.kind {
1209 ast::NamedField(ident, _) if (struct_type == Unknown ||
1210 struct_type == Record) => {
1211 struct_type = Record;
1214 ast::UnnamedField(..) if (struct_type == Unknown ||
1215 struct_type == Tuple) => {
1216 struct_type = Tuple;
1220 cx.span_bug(sp, "a struct with named and unnamed fields in `deriving`");
1223 let ident = cx.ident_of(format!("{}_{}", prefix, i).as_slice());
1224 paths.push(codemap::Spanned{span: sp, node: ident});
1226 sp, ast::ExprParen(cx.expr_deref(sp, cx.expr_path(cx.path_ident(sp,ident)))));
1227 ident_expr.push((sp, opt_id, val));
1230 let subpats = self.create_subpatterns(cx, paths, mutbl);
1232 // struct_type is definitely not Unknown, since struct_def.fields
1233 // must be nonempty to reach here
1234 let pattern = if struct_type == Record {
1235 let field_pats = subpats.iter().zip(ident_expr.iter()).map(|(&pat, &(_, id, _))| {
1236 // id is guaranteed to be Some
1237 ast::FieldPat { ident: id.unwrap(), pat: pat }
1239 cx.pat_struct(self.span, matching_path, field_pats)
1241 cx.pat_enum(self.span, matching_path, subpats)
1244 (pattern, ident_expr)
1247 fn create_enum_variant_pattern(&self,
1249 variant: &ast::Variant,
1251 mutbl: ast::Mutability)
1252 -> (Gc<ast::Pat>, Vec<(Span, Option<Ident>, Gc<Expr>)> ) {
1253 let variant_ident = variant.node.name;
1254 match variant.node.kind {
1255 ast::TupleVariantKind(ref variant_args) => {
1256 if variant_args.is_empty() {
1257 return (cx.pat_ident_binding_mode(variant.span, variant_ident,
1258 ast::BindByValue(ast::MutImmutable)),
1262 let matching_path = cx.path_ident(variant.span, variant_ident);
1264 let mut paths = Vec::new();
1265 let mut ident_expr = Vec::new();
1266 for (i, va) in variant_args.iter().enumerate() {
1267 let sp = self.set_expn_info(cx, va.ty.span);
1268 let ident = cx.ident_of(format!("{}_{}", prefix, i).as_slice());
1269 let path1 = codemap::Spanned{span: sp, node: ident};
1271 let expr_path = cx.expr_path(cx.path_ident(sp, ident));
1272 let val = cx.expr(sp, ast::ExprParen(cx.expr_deref(sp, expr_path)));
1273 ident_expr.push((sp, None, val));
1276 let subpats = self.create_subpatterns(cx, paths, mutbl);
1278 (cx.pat_enum(variant.span, matching_path, subpats),
1281 ast::StructVariantKind(ref struct_def) => {
1282 self.create_struct_pattern(cx, variant_ident, &**struct_def,
1289 /* helpful premade recipes */
1292 Fold the fields. `use_foldl` controls whether this is done
1293 left-to-right (`true`) or right-to-left (`false`).
1295 pub fn cs_fold(use_foldl: bool,
1296 f: |&mut ExtCtxt, Span, Gc<Expr>, Gc<Expr>, &[Gc<Expr>]| -> Gc<Expr>,
1298 enum_nonmatch_f: EnumNonMatchCollapsedFunc,
1301 substructure: &Substructure)
1303 match *substructure.fields {
1304 EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => {
1306 all_fields.iter().fold(base, |old, field| {
1311 field.other.as_slice())
1314 all_fields.iter().rev().fold(base, |old, field| {
1319 field.other.as_slice())
1323 EnumNonMatchingCollapsed(ref all_args, _, tuple) =>
1324 enum_nonmatch_f(cx, trait_span, (all_args.as_slice(), tuple),
1325 substructure.nonself_args),
1326 StaticEnum(..) | StaticStruct(..) => {
1327 cx.span_bug(trait_span, "static function in `deriving`")
1334 Call the method that is being derived on all the fields, and then
1335 process the collected results. i.e.
1338 f(cx, span, ~[self_1.method(__arg_1_1, __arg_2_1),
1339 self_2.method(__arg_1_2, __arg_2_2)])
1343 pub fn cs_same_method(f: |&mut ExtCtxt, Span, Vec<Gc<Expr>>| -> Gc<Expr>,
1344 enum_nonmatch_f: EnumNonMatchCollapsedFunc,
1347 substructure: &Substructure)
1349 match *substructure.fields {
1350 EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => {
1351 // call self_n.method(other_1_n, other_2_n, ...)
1352 let called = all_fields.iter().map(|field| {
1353 cx.expr_method_call(field.span,
1355 substructure.method_ident,
1357 .map(|e| cx.expr_addr_of(field.span, *e))
1361 f(cx, trait_span, called)
1363 EnumNonMatchingCollapsed(ref all_self_args, _, tuple) =>
1364 enum_nonmatch_f(cx, trait_span, (all_self_args.as_slice(), tuple),
1365 substructure.nonself_args),
1366 StaticEnum(..) | StaticStruct(..) => {
1367 cx.span_bug(trait_span, "static function in `deriving`")
1373 Fold together the results of calling the derived method on all the
1374 fields. `use_foldl` controls whether this is done left-to-right
1375 (`true`) or right-to-left (`false`).
1378 pub fn cs_same_method_fold(use_foldl: bool,
1379 f: |&mut ExtCtxt, Span, Gc<Expr>, Gc<Expr>| -> Gc<Expr>,
1381 enum_nonmatch_f: EnumNonMatchCollapsedFunc,
1384 substructure: &Substructure)
1389 vals.iter().fold(base, |old, &new| {
1390 f(cx, span, old, new)
1393 vals.iter().rev().fold(base, |old, &new| {
1394 f(cx, span, old, new)
1399 cx, trait_span, substructure)
1403 Use a given binop to combine the result of calling the derived method
1407 pub fn cs_binop(binop: ast::BinOp, base: Gc<Expr>,
1408 enum_nonmatch_f: EnumNonMatchCollapsedFunc,
1409 cx: &mut ExtCtxt, trait_span: Span,
1410 substructure: &Substructure) -> Gc<Expr> {
1411 cs_same_method_fold(
1412 true, // foldl is good enough
1413 |cx, span, old, new| {
1414 cx.expr_binary(span,
1421 cx, trait_span, substructure)
1424 /// cs_binop with binop == or
1426 pub fn cs_or(enum_nonmatch_f: EnumNonMatchCollapsedFunc,
1427 cx: &mut ExtCtxt, span: Span,
1428 substructure: &Substructure) -> Gc<Expr> {
1429 cs_binop(ast::BiOr, cx.expr_bool(span, false),
1431 cx, span, substructure)
1434 /// cs_binop with binop == and
1436 pub fn cs_and(enum_nonmatch_f: EnumNonMatchCollapsedFunc,
1437 cx: &mut ExtCtxt, span: Span,
1438 substructure: &Substructure) -> Gc<Expr> {
1439 cs_binop(ast::BiAnd, cx.expr_bool(span, true),
1441 cx, span, substructure)