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.
13 Some code that abstracts away much of the boilerplate of writing
14 `deriving` instances for traits. Among other things it manages getting
15 access to the fields of the 4 different sorts of structs and enum
16 variants, as well as creating the method and impl ast instances.
18 Supported features (fairly exhaustive):
20 - Methods taking any number of parameters of any type, and returning
21 any type, other than vectors, bottom and closures.
22 - Generating `impl`s for types with type parameters and lifetimes
23 (e.g. `Option<T>`), the parameters are automatically given the
24 current trait as a bound. (This includes separate type parameters
25 and lifetimes for methods.)
26 - Additional bounds on the type parameters, e.g. the `Ord` instance
27 requires an explicit `Eq` bound at the
28 moment. (`TraitDef.additional_bounds`)
30 Unsupported: FIXME #6257: calling methods on reference fields,
31 e.g. deriving TotalEq/TotalOrd/Clone don't work on `struct A(&int)`,
32 because of how the auto-dereferencing happens.
34 The most important thing for implementers is the `Substructure` and
35 `SubstructureFields` objects. The latter groups 5 possibilities of the
38 - `Struct`, when `Self` is a struct (including tuple structs, e.g
39 `struct T(int, char)`).
40 - `EnumMatching`, when `Self` is an enum and all the arguments are the
41 same variant of the enum (e.g. `Some(1)`, `Some(3)` and `Some(4)`)
42 - `EnumNonMatching` when `Self` is an enum and the arguments are not
43 the same variant (e.g. `None`, `Some(1)` and `None`). If
44 `const_nonmatching` is true, this will contain an empty list.
45 - `StaticEnum` and `StaticStruct` for static methods, where the type
46 being derived upon is either an enum or struct respectively. (Any
47 argument with type Self is just grouped among the non-self
50 In the first two cases, the values from the corresponding fields in
51 all the arguments are grouped together. In the `EnumNonMatching` case
52 this isn't possible (different variants have different fields), so the
53 fields are grouped by which argument they come from. There are no
54 fields with values in the static cases, so these are treated entirely
57 The non-static cases have `Option<ident>` in several places associated
58 with field `expr`s. This represents the name of the field it is
59 associated with. It is only not `None` when the associated field has
60 an identifier in the source code. For example, the `x`s in the
74 The `int`s in `B` and `C0` don't have an identifier, so the
75 `Option<ident>`s would be `None` for them.
77 In the static cases, the structure is summarised, either into the just
78 spans of the fields or a list of spans and the field idents (for tuple
79 structs and record structs, respectively), or a list of these, for
80 enums (one for each variant). For empty struct and empty enum
81 variants, it is represented as a count of 0.
85 The following simplified `Eq` is used for in-code examples:
89 fn eq(&self, other: &Self);
92 fn eq(&self, other: &int) -> bool {
98 Some examples of the values of `SubstructureFields` follow, using the
99 above `Eq`, `A`, `B` and `C`.
103 When generating the `expr` for the `A` impl, the `SubstructureFields` is
108 name: Some(<ident of x>),
109 self_: <expr for &self.x>,
110 other: ~[<expr for &other.x]
114 For the `B` impl, called with `B(a)` and `B(b)`,
118 span: <span of `int`>,
127 When generating the `expr` for a call with `self == C0(a)` and `other
128 == C0(b)`, the SubstructureFields is
131 EnumMatching(0, <ast::Variant for C0>,
135 self_: <expr for &a>,
136 other: ~[<expr for &b>]
140 For `C1 {x}` and `C1 {x}`,
143 EnumMatching(1, <ast::Variant for C1>,
146 name: Some(<ident of x>),
147 self_: <expr for &self.x>,
148 other: ~[<expr for &other.x>]
152 For `C0(a)` and `C1 {x}` ,
155 EnumNonMatching(~[(0, <ast::Variant for B0>,
156 ~[(<span of int>, None, <expr for &a>)]),
157 (1, <ast::Variant for B1>,
158 ~[(<span of x>, Some(<ident of x>),
159 <expr for &other.x>)])])
162 (and vice versa, but with the order of the outermost list flipped.)
166 A static method on the above would result in,
169 StaticStruct(<ast::StructDef of A>, Named(~[(<ident of x>, <span of x>)]))
171 StaticStruct(<ast::StructDef of B>, Unnamed(~[<span of x>]))
173 StaticEnum(<ast::EnumDef of C>, ~[(<ident of C0>, <span of C0>, Unnamed(~[<span of int>])),
174 (<ident of C1>, <span of C1>,
175 Named(~[(<ident of x>, <span of x>)]))])
180 use std::cell::RefCell;
183 use ast::{P, EnumDef, Expr, Ident, Generics, StructDef};
185 use ext::base::ExtCtxt;
186 use ext::build::AstBuilder;
189 use owned_slice::OwnedSlice;
190 use parse::token::InternedString;
195 pub struct TraitDef<'a> {
196 /// The span for the current #[deriving(Foo)] header.
199 pub attributes: Vec<ast::Attribute>,
201 /// Path of the trait, including any type parameters
204 /// Additional bounds required of any type parameters of the type,
205 /// other than the current trait
206 pub additional_bounds: Vec<Ty<'a>>,
208 /// Any extra lifetimes and/or bounds, e.g. `D: serialize::Decoder`
209 pub generics: LifetimeBounds<'a>,
211 pub methods: Vec<MethodDef<'a>>,
215 pub struct MethodDef<'a> {
216 /// name of the method
218 /// List of generics, e.g. `R: rand::Rng`
219 pub generics: LifetimeBounds<'a>,
221 /// Whether there is a self argument (outer Option) i.e. whether
222 /// this is a static function, and whether it is a pointer (inner
224 pub explicit_self: Option<Option<PtrTy<'a>>>,
226 /// Arguments other than the self argument
227 pub args: Vec<Ty<'a>>,
232 pub attributes: Vec<ast::Attribute>,
234 /// if the value of the nonmatching enums is independent of the
235 /// actual enum variants, i.e. can use _ => .. match.
236 pub const_nonmatching: bool,
238 pub combine_substructure: RefCell<CombineSubstructureFunc<'a>>,
241 /// All the data about the data structure/method being derived upon.
242 pub struct Substructure<'a> {
244 pub type_ident: Ident,
245 /// ident of the method
246 pub method_ident: Ident,
247 /// dereferenced access to any Self or Ptr(Self, _) arguments
248 pub self_args: &'a [@Expr],
249 /// verbatim access to any other arguments
250 pub nonself_args: &'a [@Expr],
251 pub fields: &'a SubstructureFields<'a>
254 /// Summary of the relevant parts of a struct/enum field.
255 pub struct FieldInfo {
257 /// None for tuple structs/normal enum variants, Some for normal
258 /// structs/struct enum variants.
259 pub name: Option<Ident>,
260 /// The expression corresponding to this field of `self`
261 /// (specifically, a reference to it).
263 /// The expressions corresponding to references to this field in
264 /// the other Self arguments.
265 pub other: Vec<@Expr>,
268 /// Fields for a static method
269 pub enum StaticFields {
270 /// Tuple structs/enum variants like this
272 /// Normal structs/struct variants.
273 Named(Vec<(Ident, Span)> )
276 /// A summary of the possible sets of fields. See above for details
278 pub enum SubstructureFields<'a> {
279 Struct(Vec<FieldInfo> ),
281 Matching variants of the enum: variant index, ast::Variant,
282 fields: the field name is only non-`None` in the case of a struct
285 EnumMatching(uint, &'a ast::Variant, Vec<FieldInfo> ),
288 non-matching variants of the enum, [(variant index, ast::Variant,
289 [field span, field ident, fields])] (i.e. all fields for self are in the
290 first tuple, for other1 are in the second tuple, etc.)
292 EnumNonMatching(&'a [(uint, P<ast::Variant>, Vec<(Span, Option<Ident>, @Expr)> )]),
294 /// A static method where Self is a struct.
295 StaticStruct(&'a ast::StructDef, StaticFields),
296 /// A static method where Self is an enum.
297 StaticEnum(&'a ast::EnumDef, Vec<(Ident, Span, StaticFields)> )
303 Combine the values of all the fields together. The last argument is
304 all the fields of all the structures, see above for details.
306 pub type CombineSubstructureFunc<'a> =
307 |&mut ExtCtxt, Span, &Substructure|: 'a -> @Expr;
310 Deal with non-matching enum variants, the arguments are a list
311 representing each variant: (variant index, ast::Variant instance,
312 [variant fields]), and a list of the nonself args of the type
314 pub type EnumNonMatchFunc<'a> =
317 &[(uint, P<ast::Variant>, Vec<(Span, Option<Ident>, @Expr)> )],
321 pub fn combine_substructure<'a>(f: CombineSubstructureFunc<'a>)
322 -> RefCell<CombineSubstructureFunc<'a>> {
327 impl<'a> TraitDef<'a> {
330 _mitem: @ast::MetaItem,
332 push: |@ast::Item|) {
334 ast::ItemStruct(struct_def, ref generics) => {
335 push(self.expand_struct_def(cx,
340 ast::ItemEnum(ref enum_def, ref generics) => {
341 push(self.expand_enum_def(cx,
352 * Given that we are deriving a trait `Tr` for a type `T<'a, ...,
353 * 'z, A, ..., Z>`, creates an impl like:
356 * impl<'a, ..., 'z, A:Tr B1 B2, ..., Z: Tr B1 B2> Tr for T<A, ..., Z> { ... }
359 * where B1, B2, ... are the bounds given by `bounds_paths`.'
362 fn create_derived_impl(&self,
366 methods: Vec<@ast::Method> ) -> @ast::Item {
367 let trait_path = self.path.to_path(cx, self.span, type_ident, generics);
369 let Generics { mut lifetimes, ty_params } =
370 self.generics.to_generics(cx, self.span, type_ident, generics);
371 let mut ty_params = ty_params.into_vec();
373 // Copy the lifetimes
374 lifetimes.extend(generics.lifetimes.iter().map(|l| *l));
376 // Create the type parameters.
377 ty_params.extend(generics.ty_params.iter().map(|ty_param| {
378 // I don't think this can be moved out of the loop, since
379 // a TyParamBound requires an ast id
380 let mut bounds: Vec<_> =
381 // extra restrictions on the generics parameters to the type being derived upon
382 self.additional_bounds.iter().map(|p| {
383 cx.typarambound(p.to_path(cx, self.span,
384 type_ident, generics))
386 // require the current trait
387 bounds.push(cx.typarambound(trait_path.clone()));
389 cx.typaram(self.span,
392 OwnedSlice::from_vec(bounds),
395 let trait_generics = Generics {
396 lifetimes: lifetimes,
397 ty_params: OwnedSlice::from_vec(ty_params)
400 // Create the reference to the trait.
401 let trait_ref = cx.trait_ref(trait_path);
403 // Create the type parameters on the `self` path.
404 let self_ty_params = generics.ty_params.map(|ty_param| {
405 cx.ty_ident(self.span, ty_param.ident)
408 let self_lifetimes = generics.lifetimes.clone();
410 // Create the type of `self`.
411 let self_type = cx.ty_path(
412 cx.path_all(self.span, false, vec!( type_ident ), self_lifetimes,
413 self_ty_params.into_vec()), None);
415 let attr = cx.attribute(
417 cx.meta_word(self.span,
418 InternedString::new("automatically_derived")));
419 let opt_trait_ref = Some(trait_ref);
420 let ident = ast_util::impl_pretty_name(&opt_trait_ref, self_type);
424 (vec!(attr)).append(self.attributes.as_slice()),
425 ast::ItemImpl(trait_generics, opt_trait_ref,
429 fn expand_struct_def(&self,
431 struct_def: &StructDef,
433 generics: &Generics) -> @ast::Item {
434 let methods = self.methods.iter().map(|method_def| {
435 let (explicit_self, self_args, nonself_args, tys) =
436 method_def.split_self_nonself_args(
437 cx, self, type_ident, generics);
439 let body = if method_def.is_static() {
440 method_def.expand_static_struct_method_body(
445 self_args.as_slice(),
446 nonself_args.as_slice())
448 method_def.expand_struct_method_body(cx,
452 self_args.as_slice(),
453 nonself_args.as_slice())
456 method_def.create_method(cx, self,
457 type_ident, generics,
462 self.create_derived_impl(cx, type_ident, generics, methods)
465 fn expand_enum_def(&self,
469 generics: &Generics) -> @ast::Item {
470 let methods = self.methods.iter().map(|method_def| {
471 let (explicit_self, self_args, nonself_args, tys) =
472 method_def.split_self_nonself_args(cx, self,
473 type_ident, generics);
475 let body = if method_def.is_static() {
476 method_def.expand_static_enum_method_body(
481 self_args.as_slice(),
482 nonself_args.as_slice())
484 method_def.expand_enum_method_body(cx,
488 self_args.as_slice(),
489 nonself_args.as_slice())
492 method_def.create_method(cx, self,
493 type_ident, generics,
498 self.create_derived_impl(cx, type_ident, generics, methods)
502 impl<'a> MethodDef<'a> {
503 fn call_substructure_method(&self,
508 nonself_args: &[@Expr],
509 fields: &SubstructureFields)
511 let substructure = Substructure {
512 type_ident: type_ident,
513 method_ident: cx.ident_of(self.name),
514 self_args: self_args,
515 nonself_args: nonself_args,
518 let mut f = self.combine_substructure.borrow_mut();
519 let f: &mut CombineSubstructureFunc = &mut *f;
520 (*f)(cx, trait_.span, &substructure)
529 self.ret_ty.to_ty(cx, trait_.span, type_ident, generics)
532 fn is_static(&self) -> bool {
533 self.explicit_self.is_none()
536 fn split_self_nonself_args(&self,
541 -> (ast::ExplicitSelf, Vec<@Expr> , Vec<@Expr> , Vec<(Ident, P<ast::Ty>)> ) {
543 let mut self_args = Vec::new();
544 let mut nonself_args = Vec::new();
545 let mut arg_tys = Vec::new();
546 let mut nonstatic = false;
548 let ast_explicit_self = match self.explicit_self {
549 Some(ref self_ptr) => {
550 let (self_expr, explicit_self) =
551 ty::get_explicit_self(cx, trait_.span, self_ptr);
553 self_args.push(self_expr);
558 None => codemap::respan(trait_.span, ast::SelfStatic),
561 for (i, ty) in self.args.iter().enumerate() {
562 let ast_ty = ty.to_ty(cx, trait_.span, type_ident, generics);
563 let ident = cx.ident_of(format!("__arg_{}", i));
564 arg_tys.push((ident, ast_ty));
566 let arg_expr = cx.expr_ident(trait_.span, ident);
569 // for static methods, just treat any Self
570 // arguments as a normal arg
571 Self if nonstatic => {
572 self_args.push(arg_expr);
574 Ptr(~Self, _) if nonstatic => {
575 self_args.push(cx.expr_deref(trait_.span, arg_expr))
578 nonself_args.push(arg_expr);
583 (ast_explicit_self, self_args, nonself_args, arg_tys)
586 fn create_method(&self,
591 explicit_self: ast::ExplicitSelf,
592 arg_types: Vec<(Ident, P<ast::Ty>)> ,
593 body: @Expr) -> @ast::Method {
594 // create the generics that aren't for Self
595 let fn_generics = self.generics.to_generics(cx, trait_.span, type_ident, generics);
597 let self_arg = match explicit_self.node {
598 ast::SelfStatic => None,
599 _ => Some(ast::Arg::new_self(trait_.span, ast::MutImmutable))
602 let args = arg_types.move_iter().map(|(name, ty)| {
603 cx.arg(trait_.span, name, ty)
605 self_arg.move_iter().chain(args).collect()
608 let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident);
610 let method_ident = cx.ident_of(self.name);
611 let fn_decl = cx.fn_decl(args, ret_type);
612 let body_block = cx.block_expr(body);
614 // Create the method.
617 attrs: self.attributes.clone(),
618 generics: fn_generics,
619 explicit_self: explicit_self,
620 fn_style: ast::NormalFn,
623 id: ast::DUMMY_NODE_ID,
632 struct A { x: int, y: int }
636 fn eq(&self, __arg_1: &A) -> bool {
638 A {x: ref __self_0_0, y: ref __self_0_1} => {
640 A {x: ref __self_1_0, y: ref __self_1_1} => {
641 __self_0_0.eq(__self_1_0) && __self_0_1.eq(__self_1_1)
650 fn expand_struct_method_body(&self,
653 struct_def: &StructDef,
656 nonself_args: &[@Expr])
659 let mut raw_fields = Vec::new(); // ~[[fields of self],
660 // [fields of next Self arg], [etc]]
661 let mut patterns = Vec::new();
662 for i in range(0u, self_args.len()) {
663 let (pat, ident_expr) = trait_.create_struct_pattern(cx, type_ident, struct_def,
664 format!("__self_{}", i),
667 raw_fields.push(ident_expr);
670 // transpose raw_fields
671 let fields = if raw_fields.len() > 0 {
675 .map(|(i, &(span, opt_id, field))| {
676 let other_fields = raw_fields.tail().iter().map(|l| {
689 cx.span_bug(trait_.span,
690 "no self arguments to non-static method in generic \
694 // body of the inner most destructuring match
695 let mut body = self.call_substructure_method(
703 // make a series of nested matches, to destructure the
704 // structs. This is actually right-to-left, but it shoudn't
706 for (&arg_expr, &pat) in self_args.iter().zip(patterns.iter()) {
707 body = cx.expr_match(trait_.span, arg_expr,
708 vec!( cx.arm(trait_.span, vec!(pat), body) ))
713 fn expand_static_struct_method_body(&self,
716 struct_def: &StructDef,
719 nonself_args: &[@Expr])
721 let summary = trait_.summarise_struct(cx, struct_def);
723 self.call_substructure_method(cx,
726 self_args, nonself_args,
727 &StaticStruct(struct_def, summary))
738 // is equivalent to (with const_nonmatching == false)
741 fn eq(&self, __arg_1: &A) {
743 A1 => match *__arg_1 {
745 A2(ref __arg_1_1) => false
747 A2(self_1) => match *__arg_1 {
749 A2(ref __arg_1_1) => self_1.eq(__arg_1_1)
756 fn expand_enum_method_body(&self,
762 nonself_args: &[@Expr])
764 let mut matches = Vec::new();
765 self.build_enum_match(cx, trait_, enum_def, type_ident,
766 self_args, nonself_args,
767 None, &mut matches, 0)
772 Creates the nested matches for an enum definition recursively, i.e.
776 Variant1 => match other { Variant1 => matching, Variant2 => nonmatching, ... },
777 Variant2 => match other { Variant1 => nonmatching, Variant2 => matching, ... },
782 It acts in the most naive way, so every branch (and subbranch,
783 subsubbranch, etc) exists, not just the ones where all the variants in
784 the tree are the same. Hopefully the optimisers get rid of any
785 repetition, otherwise derived methods with many Self arguments will be
788 `matching` is Some(n) if all branches in the tree above the
789 current position are variant `n`, `None` otherwise (including on
792 fn build_enum_match(&self,
798 nonself_args: &[@Expr],
799 matching: Option<uint>,
800 matches_so_far: &mut Vec<(uint, P<ast::Variant>,
801 Vec<(Span, Option<Ident>, @Expr)> )> ,
802 match_count: uint) -> @Expr {
803 if match_count == self_args.len() {
804 // we've matched against all arguments, so make the final
805 // expression at the bottom of the match tree
806 if matches_so_far.len() == 0 {
807 cx.span_bug(trait_.span,
808 "no self match on an enum in \
809 generic `deriving`");
812 // `ref` inside let matches is buggy. Causes havoc wih rusc.
813 // let (variant_index, ref self_vec) = matches_so_far[0];
814 let (variant, self_vec) = match matches_so_far.get(0) {
815 &(_, v, ref s) => (v, s)
818 // we currently have a vec of vecs, where each
819 // subvec is the fields of one of the arguments,
820 // but if the variants all match, we want this as
821 // vec of tuples, where each tuple represents a
824 // most arms don't have matching variants, so do a
825 // quick check to see if they match (even though
826 // this means iterating twice) instead of being
827 // optimistic and doing a pile of allocations etc.
828 let substructure = match matching {
829 Some(variant_index) => {
830 let mut enum_matching_fields = Vec::from_elem(self_vec.len(), Vec::new());
832 for triple in matches_so_far.tail().iter() {
834 &(_, _, ref other_fields) => {
835 for (i, &(_, _, e)) in other_fields.iter().enumerate() {
836 enum_matching_fields.get_mut(i).push(e);
843 .zip(enum_matching_fields.iter())
844 .map(|(&(span, id, self_f), other)| {
849 other: (*other).clone()
852 EnumMatching(variant_index, variant, field_tuples)
855 EnumNonMatching(matches_so_far.as_slice())
858 self.call_substructure_method(cx, trait_, type_ident,
859 self_args, nonself_args,
862 } else { // there are still matches to create
863 let current_match_str = if match_count == 0 {
866 format!("__arg_{}", match_count)
869 let mut arms = Vec::new();
871 // the code for nonmatching variants only matters when
872 // we've seen at least one other variant already
873 if self.const_nonmatching && match_count > 0 {
874 // make a matching-variant match, and a _ match.
875 let index = match matching {
877 None => cx.span_bug(trait_.span,
878 "non-matching variants when required to \
879 be matching in generic `deriving`")
882 // matching-variant match
883 let variant = *enum_def.variants.get(index);
884 let (pattern, idents) = trait_.create_enum_variant_pattern(cx,
889 matches_so_far.push((index, variant, idents));
890 let arm_expr = self.build_enum_match(cx,
894 self_args, nonself_args,
898 matches_so_far.pop().unwrap();
899 arms.push(cx.arm(trait_.span, vec!( pattern ), arm_expr));
901 if enum_def.variants.len() > 1 {
902 let e = &EnumNonMatching(&[]);
903 let wild_expr = self.call_substructure_method(cx, trait_, type_ident,
904 self_args, nonself_args,
906 let wild_arm = cx.arm(
908 vec!( cx.pat_wild(trait_.span) ),
913 // create an arm matching on each variant
914 for (index, &variant) in enum_def.variants.iter().enumerate() {
915 let (pattern, idents) = trait_.create_enum_variant_pattern(cx,
920 matches_so_far.push((index, variant, idents));
923 _ if match_count == 0 => Some(index),
924 Some(i) if index == i => Some(i),
927 let arm_expr = self.build_enum_match(cx,
931 self_args, nonself_args,
935 matches_so_far.pop().unwrap();
937 let arm = cx.arm(trait_.span, vec!( pattern ), arm_expr);
942 // match foo { arm, arm, arm, ... }
943 cx.expr_match(trait_.span, self_args[match_count], arms)
947 fn expand_static_enum_method_body(&self,
953 nonself_args: &[@Expr])
955 let summary = enum_def.variants.iter().map(|v| {
956 let ident = v.node.name;
957 let summary = match v.node.kind {
958 ast::TupleVariantKind(ref args) => {
959 Unnamed(args.iter().map(|va| trait_.set_expn_info(cx, va.ty.span)).collect())
961 ast::StructVariantKind(struct_def) => {
962 trait_.summarise_struct(cx, struct_def)
965 (ident, v.span, summary)
967 self.call_substructure_method(cx, trait_, type_ident,
968 self_args, nonself_args,
969 &StaticEnum(enum_def, summary))
973 #[deriving(Eq)] // dogfooding!
975 Unknown, Record, Tuple
978 // general helper methods.
979 impl<'a> TraitDef<'a> {
980 fn set_expn_info(&self,
982 mut to_set: Span) -> Span {
983 let trait_name = match self.path.path.last() {
984 None => cx.span_bug(self.span, "trait with empty path in generic `deriving`"),
987 to_set.expn_info = Some(@codemap::ExpnInfo {
989 callee: codemap::NameAndSpan {
990 name: format!("deriving({})", trait_name),
991 format: codemap::MacroAttribute,
992 span: Some(self.span)
998 fn summarise_struct(&self,
1000 struct_def: &StructDef) -> StaticFields {
1001 let mut named_idents = Vec::new();
1002 let mut just_spans = Vec::new();
1003 for field in struct_def.fields.iter(){
1004 let sp = self.set_expn_info(cx, field.span);
1005 match field.node.kind {
1006 ast::NamedField(ident, _) => named_idents.push((ident, sp)),
1007 ast::UnnamedField(..) => just_spans.push(sp),
1011 match (just_spans.is_empty(), named_idents.is_empty()) {
1012 (false, false) => cx.span_bug(self.span,
1013 "a struct with named and unnamed \
1014 fields in generic `deriving`"),
1016 (_, false) => Named(named_idents),
1017 // tuple structs (includes empty structs)
1018 (_, _) => Unnamed(just_spans)
1022 fn create_subpatterns(&self,
1024 field_paths: Vec<ast::Path> ,
1025 mutbl: ast::Mutability)
1027 field_paths.iter().map(|path| {
1029 ast::PatIdent(ast::BindByRef(mutbl), (*path).clone(), None))
1033 fn create_struct_pattern(&self,
1035 struct_ident: Ident,
1036 struct_def: &StructDef,
1038 mutbl: ast::Mutability)
1039 -> (@ast::Pat, Vec<(Span, Option<Ident>, @Expr)> ) {
1040 if struct_def.fields.is_empty() {
1042 cx.pat_ident_binding_mode(
1043 self.span, struct_ident, ast::BindByValue(ast::MutImmutable)),
1047 let matching_path = cx.path(self.span, vec!( struct_ident ));
1049 let mut paths = Vec::new();
1050 let mut ident_expr = Vec::new();
1051 let mut struct_type = Unknown;
1053 for (i, struct_field) in struct_def.fields.iter().enumerate() {
1054 let sp = self.set_expn_info(cx, struct_field.span);
1055 let opt_id = match struct_field.node.kind {
1056 ast::NamedField(ident, _) if (struct_type == Unknown ||
1057 struct_type == Record) => {
1058 struct_type = Record;
1061 ast::UnnamedField(..) if (struct_type == Unknown ||
1062 struct_type == Tuple) => {
1063 struct_type = Tuple;
1067 cx.span_bug(sp, "a struct with named and unnamed fields in `deriving`");
1070 let path = cx.path_ident(sp, cx.ident_of(format!("{}_{}", prefix, i)));
1071 paths.push(path.clone());
1074 cx.expr_deref(sp, cx.expr_path(path))));
1075 ident_expr.push((sp, opt_id, val));
1078 let subpats = self.create_subpatterns(cx, paths, mutbl);
1080 // struct_type is definitely not Unknown, since struct_def.fields
1081 // must be nonempty to reach here
1082 let pattern = if struct_type == Record {
1083 let field_pats = subpats.iter().zip(ident_expr.iter()).map(|(&pat, &(_, id, _))| {
1084 // id is guaranteed to be Some
1085 ast::FieldPat { ident: id.unwrap(), pat: pat }
1087 cx.pat_struct(self.span, matching_path, field_pats)
1089 cx.pat_enum(self.span, matching_path, subpats)
1092 (pattern, ident_expr)
1095 fn create_enum_variant_pattern(&self,
1097 variant: &ast::Variant,
1099 mutbl: ast::Mutability)
1100 -> (@ast::Pat, Vec<(Span, Option<Ident>, @Expr)> ) {
1101 let variant_ident = variant.node.name;
1102 match variant.node.kind {
1103 ast::TupleVariantKind(ref variant_args) => {
1104 if variant_args.is_empty() {
1105 return (cx.pat_ident_binding_mode(variant.span, variant_ident,
1106 ast::BindByValue(ast::MutImmutable)),
1110 let matching_path = cx.path_ident(variant.span, variant_ident);
1112 let mut paths = Vec::new();
1113 let mut ident_expr = Vec::new();
1114 for (i, va) in variant_args.iter().enumerate() {
1115 let sp = self.set_expn_info(cx, va.ty.span);
1116 let path = cx.path_ident(sp, cx.ident_of(format!("{}_{}", prefix, i)));
1118 paths.push(path.clone());
1120 sp, ast::ExprParen(cx.expr_deref(sp, cx.expr_path(path))));
1121 ident_expr.push((sp, None, val));
1124 let subpats = self.create_subpatterns(cx, paths, mutbl);
1126 (cx.pat_enum(variant.span, matching_path, subpats),
1129 ast::StructVariantKind(struct_def) => {
1130 self.create_struct_pattern(cx, variant_ident, struct_def,
1137 /* helpful premade recipes */
1140 Fold the fields. `use_foldl` controls whether this is done
1141 left-to-right (`true`) or right-to-left (`false`).
1143 pub fn cs_fold(use_foldl: bool,
1144 f: |&mut ExtCtxt, Span, @Expr, @Expr, &[@Expr]| -> @Expr,
1146 enum_nonmatch_f: EnumNonMatchFunc,
1149 substructure: &Substructure)
1151 match *substructure.fields {
1152 EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => {
1154 all_fields.iter().fold(base, |old, field| {
1159 field.other.as_slice())
1162 all_fields.iter().rev().fold(base, |old, field| {
1167 field.other.as_slice())
1171 EnumNonMatching(ref all_enums) => enum_nonmatch_f(cx, trait_span,
1173 substructure.nonself_args),
1174 StaticEnum(..) | StaticStruct(..) => {
1175 cx.span_bug(trait_span, "static function in `deriving`")
1182 Call the method that is being derived on all the fields, and then
1183 process the collected results. i.e.
1186 f(cx, span, ~[self_1.method(__arg_1_1, __arg_2_1),
1187 self_2.method(__arg_1_2, __arg_2_2)])
1191 pub fn cs_same_method(f: |&mut ExtCtxt, Span, Vec<@Expr> | -> @Expr,
1192 enum_nonmatch_f: EnumNonMatchFunc,
1195 substructure: &Substructure)
1197 match *substructure.fields {
1198 EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => {
1199 // call self_n.method(other_1_n, other_2_n, ...)
1200 let called = all_fields.iter().map(|field| {
1201 cx.expr_method_call(field.span,
1203 substructure.method_ident,
1205 .map(|e| cx.expr_addr_of(field.span, *e))
1209 f(cx, trait_span, called)
1211 EnumNonMatching(ref all_enums) => enum_nonmatch_f(cx, trait_span,
1213 substructure.nonself_args),
1214 StaticEnum(..) | StaticStruct(..) => {
1215 cx.span_bug(trait_span, "static function in `deriving`")
1221 Fold together the results of calling the derived method on all the
1222 fields. `use_foldl` controls whether this is done left-to-right
1223 (`true`) or right-to-left (`false`).
1226 pub fn cs_same_method_fold(use_foldl: bool,
1227 f: |&mut ExtCtxt, Span, @Expr, @Expr| -> @Expr,
1229 enum_nonmatch_f: EnumNonMatchFunc,
1232 substructure: &Substructure)
1237 vals.iter().fold(base, |old, &new| {
1238 f(cx, span, old, new)
1241 vals.iter().rev().fold(base, |old, &new| {
1242 f(cx, span, old, new)
1247 cx, trait_span, substructure)
1251 Use a given binop to combine the result of calling the derived method
1255 pub fn cs_binop(binop: ast::BinOp, base: @Expr,
1256 enum_nonmatch_f: EnumNonMatchFunc,
1257 cx: &mut ExtCtxt, trait_span: Span,
1258 substructure: &Substructure) -> @Expr {
1259 cs_same_method_fold(
1260 true, // foldl is good enough
1261 |cx, span, old, new| {
1262 cx.expr_binary(span,
1269 cx, trait_span, substructure)
1272 /// cs_binop with binop == or
1274 pub fn cs_or(enum_nonmatch_f: EnumNonMatchFunc,
1275 cx: &mut ExtCtxt, span: Span,
1276 substructure: &Substructure) -> @Expr {
1277 cs_binop(ast::BiOr, cx.expr_bool(span, false),
1279 cx, span, substructure)
1282 /// cs_binop with binop == and
1284 pub fn cs_and(enum_nonmatch_f: EnumNonMatchFunc,
1285 cx: &mut ExtCtxt, span: Span,
1286 substructure: &Substructure) -> @Expr {
1287 cs_binop(ast::BiAnd, cx.expr_bool(span, true),
1289 cx, span, substructure)