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>)]))])
181 use ast::{P, EnumDef, Expr, Ident, Generics, StructDef};
183 use ext::base::ExtCtxt;
184 use ext::build::AstBuilder;
187 use owned_slice::OwnedSlice;
188 use parse::token::InternedString;
193 pub struct TraitDef<'a> {
194 /// The span for the current #[deriving(Foo)] header.
197 pub attributes: Vec<ast::Attribute>,
199 /// Path of the trait, including any type parameters
202 /// Additional bounds required of any type parameters of the type,
203 /// other than the current trait
204 pub additional_bounds: Vec<Ty<'a>>,
206 /// Any extra lifetimes and/or bounds, e.g. `D: serialize::Decoder`
207 pub generics: LifetimeBounds<'a>,
209 pub methods: Vec<MethodDef<'a>>,
213 pub struct MethodDef<'a> {
214 /// name of the method
216 /// List of generics, e.g. `R: rand::Rng`
217 pub generics: LifetimeBounds<'a>,
219 /// Whether there is a self argument (outer Option) i.e. whether
220 /// this is a static function, and whether it is a pointer (inner
222 pub explicit_self: Option<Option<PtrTy<'a>>>,
224 /// Arguments other than the self argument
225 pub args: Vec<Ty<'a>>,
230 pub attributes: Vec<ast::Attribute>,
232 /// if the value of the nonmatching enums is independent of the
233 /// actual enum variants, i.e. can use _ => .. match.
234 pub const_nonmatching: bool,
236 pub combine_substructure: CombineSubstructureFunc<'a>,
239 /// All the data about the data structure/method being derived upon.
240 pub struct Substructure<'a> {
242 pub type_ident: Ident,
243 /// ident of the method
244 pub method_ident: Ident,
245 /// dereferenced access to any Self or Ptr(Self, _) arguments
246 pub self_args: &'a [@Expr],
247 /// verbatim access to any other arguments
248 pub nonself_args: &'a [@Expr],
249 pub fields: &'a SubstructureFields<'a>
252 /// Summary of the relevant parts of a struct/enum field.
253 pub struct FieldInfo {
255 /// None for tuple structs/normal enum variants, Some for normal
256 /// structs/struct enum variants.
257 pub name: Option<Ident>,
258 /// The expression corresponding to this field of `self`
259 /// (specifically, a reference to it).
261 /// The expressions corresponding to references to this field in
262 /// the other Self arguments.
263 pub other: Vec<@Expr>,
266 /// Fields for a static method
267 pub enum StaticFields {
268 /// Tuple structs/enum variants like this
270 /// Normal structs/struct variants.
271 Named(Vec<(Ident, Span)> )
274 /// A summary of the possible sets of fields. See above for details
276 pub enum SubstructureFields<'a> {
277 Struct(Vec<FieldInfo> ),
279 Matching variants of the enum: variant index, ast::Variant,
280 fields: the field name is only non-`None` in the case of a struct
283 EnumMatching(uint, &'a ast::Variant, Vec<FieldInfo> ),
286 non-matching variants of the enum, [(variant index, ast::Variant,
287 [field span, field ident, fields])] (i.e. all fields for self are in the
288 first tuple, for other1 are in the second tuple, etc.)
290 EnumNonMatching(&'a [(uint, P<ast::Variant>, Vec<(Span, Option<Ident>, @Expr)> )]),
292 /// A static method where Self is a struct.
293 StaticStruct(&'a ast::StructDef, StaticFields),
294 /// A static method where Self is an enum.
295 StaticEnum(&'a ast::EnumDef, Vec<(Ident, Span, StaticFields)> )
301 Combine the values of all the fields together. The last argument is
302 all the fields of all the structures, see above for details.
304 pub type CombineSubstructureFunc<'a> =
305 |&mut ExtCtxt, Span, &Substructure|: 'a -> @Expr;
308 Deal with non-matching enum variants, the arguments are a list
309 representing each variant: (variant index, ast::Variant instance,
310 [variant fields]), and a list of the nonself args of the type
312 pub type EnumNonMatchFunc<'a> =
315 &[(uint, P<ast::Variant>, Vec<(Span, Option<Ident>, @Expr)> )],
320 impl<'a> TraitDef<'a> {
323 _mitem: @ast::MetaItem,
325 push: |@ast::Item|) {
327 ast::ItemStruct(struct_def, ref generics) => {
328 push(self.expand_struct_def(cx,
333 ast::ItemEnum(ref enum_def, ref generics) => {
334 push(self.expand_enum_def(cx,
345 * Given that we are deriving a trait `Tr` for a type `T<'a, ...,
346 * 'z, A, ..., Z>`, creates an impl like:
349 * impl<'a, ..., 'z, A:Tr B1 B2, ..., Z: Tr B1 B2> Tr for T<A, ..., Z> { ... }
352 * where B1, B2, ... are the bounds given by `bounds_paths`.'
355 fn create_derived_impl(&self,
359 methods: Vec<@ast::Method> ) -> @ast::Item {
360 let trait_path = self.path.to_path(cx, self.span, type_ident, generics);
362 let Generics { mut lifetimes, ty_params } =
363 self.generics.to_generics(cx, self.span, type_ident, generics);
364 let mut ty_params = ty_params.into_vec();
366 // Copy the lifetimes
367 lifetimes.extend(generics.lifetimes.iter().map(|l| *l));
369 // Create the type parameters.
370 ty_params.extend(generics.ty_params.iter().map(|ty_param| {
371 // I don't think this can be moved out of the loop, since
372 // a TyParamBound requires an ast id
373 let mut bounds: Vec<_> =
374 // extra restrictions on the generics parameters to the type being derived upon
375 self.additional_bounds.iter().map(|p| {
376 cx.typarambound(p.to_path(cx, self.span,
377 type_ident, generics))
379 // require the current trait
380 bounds.push(cx.typarambound(trait_path.clone()));
382 cx.typaram(self.span,
385 OwnedSlice::from_vec(bounds),
388 let trait_generics = Generics {
389 lifetimes: lifetimes,
390 ty_params: OwnedSlice::from_vec(ty_params)
393 // Create the reference to the trait.
394 let trait_ref = cx.trait_ref(trait_path);
396 // Create the type parameters on the `self` path.
397 let self_ty_params = generics.ty_params.map(|ty_param| {
398 cx.ty_ident(self.span, ty_param.ident)
401 let self_lifetimes = generics.lifetimes.clone();
403 // Create the type of `self`.
404 let self_type = cx.ty_path(
405 cx.path_all(self.span, false, vec!( type_ident ), self_lifetimes,
406 self_ty_params.into_vec()), None);
408 let attr = cx.attribute(
410 cx.meta_word(self.span,
411 InternedString::new("automatically_derived")));
412 let opt_trait_ref = Some(trait_ref);
413 let ident = ast_util::impl_pretty_name(&opt_trait_ref, self_type);
417 (vec!(attr)).append(self.attributes.as_slice()),
418 ast::ItemImpl(trait_generics, opt_trait_ref,
422 fn expand_struct_def(&self,
424 struct_def: &StructDef,
426 generics: &Generics) -> @ast::Item {
427 let methods = self.methods.iter().map(|method_def| {
428 let (explicit_self, self_args, nonself_args, tys) =
429 method_def.split_self_nonself_args(
430 cx, self, type_ident, generics);
432 let body = if method_def.is_static() {
433 method_def.expand_static_struct_method_body(
438 self_args.as_slice(),
439 nonself_args.as_slice())
441 method_def.expand_struct_method_body(cx,
445 self_args.as_slice(),
446 nonself_args.as_slice())
449 method_def.create_method(cx, self,
450 type_ident, generics,
455 self.create_derived_impl(cx, type_ident, generics, methods)
458 fn expand_enum_def(&self,
462 generics: &Generics) -> @ast::Item {
463 let methods = self.methods.iter().map(|method_def| {
464 let (explicit_self, self_args, nonself_args, tys) =
465 method_def.split_self_nonself_args(cx, self,
466 type_ident, generics);
468 let body = if method_def.is_static() {
469 method_def.expand_static_enum_method_body(
474 self_args.as_slice(),
475 nonself_args.as_slice())
477 method_def.expand_enum_method_body(cx,
481 self_args.as_slice(),
482 nonself_args.as_slice())
485 method_def.create_method(cx, self,
486 type_ident, generics,
491 self.create_derived_impl(cx, type_ident, generics, methods)
495 impl<'a> MethodDef<'a> {
496 fn call_substructure_method(&self,
501 nonself_args: &[@Expr],
502 fields: &SubstructureFields)
504 let substructure = Substructure {
505 type_ident: type_ident,
506 method_ident: cx.ident_of(self.name),
507 self_args: self_args,
508 nonself_args: nonself_args,
511 (self.combine_substructure)(cx, trait_.span,
521 self.ret_ty.to_ty(cx, trait_.span, type_ident, generics)
524 fn is_static(&self) -> bool {
525 self.explicit_self.is_none()
528 fn split_self_nonself_args(&self,
533 -> (ast::ExplicitSelf, Vec<@Expr> , Vec<@Expr> , Vec<(Ident, P<ast::Ty>)> ) {
535 let mut self_args = Vec::new();
536 let mut nonself_args = Vec::new();
537 let mut arg_tys = Vec::new();
538 let mut nonstatic = false;
540 let ast_explicit_self = match self.explicit_self {
541 Some(ref self_ptr) => {
542 let (self_expr, explicit_self) =
543 ty::get_explicit_self(cx, trait_.span, self_ptr);
545 self_args.push(self_expr);
550 None => codemap::respan(trait_.span, ast::SelfStatic),
553 for (i, ty) in self.args.iter().enumerate() {
554 let ast_ty = ty.to_ty(cx, trait_.span, type_ident, generics);
555 let ident = cx.ident_of(format!("__arg_{}", i));
556 arg_tys.push((ident, ast_ty));
558 let arg_expr = cx.expr_ident(trait_.span, ident);
561 // for static methods, just treat any Self
562 // arguments as a normal arg
563 Self if nonstatic => {
564 self_args.push(arg_expr);
566 Ptr(~Self, _) if nonstatic => {
567 self_args.push(cx.expr_deref(trait_.span, arg_expr))
570 nonself_args.push(arg_expr);
575 (ast_explicit_self, self_args, nonself_args, arg_tys)
578 fn create_method(&self,
583 explicit_self: ast::ExplicitSelf,
584 arg_types: Vec<(Ident, P<ast::Ty>)> ,
585 body: @Expr) -> @ast::Method {
586 // create the generics that aren't for Self
587 let fn_generics = self.generics.to_generics(cx, trait_.span, type_ident, generics);
589 let self_arg = match explicit_self.node {
590 ast::SelfStatic => None,
591 _ => Some(ast::Arg::new_self(trait_.span, ast::MutImmutable))
594 let args = arg_types.move_iter().map(|(name, ty)| {
595 cx.arg(trait_.span, name, ty)
597 self_arg.move_iter().chain(args).collect()
600 let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident);
602 let method_ident = cx.ident_of(self.name);
603 let fn_decl = cx.fn_decl(args, ret_type);
604 let body_block = cx.block_expr(body);
606 // Create the method.
609 attrs: self.attributes.clone(),
610 generics: fn_generics,
611 explicit_self: explicit_self,
612 fn_style: ast::NormalFn,
615 id: ast::DUMMY_NODE_ID,
624 struct A { x: int, y: int }
628 fn eq(&self, __arg_1: &A) -> bool {
630 A {x: ref __self_0_0, y: ref __self_0_1} => {
632 A {x: ref __self_1_0, y: ref __self_1_1} => {
633 __self_0_0.eq(__self_1_0) && __self_0_1.eq(__self_1_1)
642 fn expand_struct_method_body(&self,
645 struct_def: &StructDef,
648 nonself_args: &[@Expr])
651 let mut raw_fields = Vec::new(); // ~[[fields of self],
652 // [fields of next Self arg], [etc]]
653 let mut patterns = Vec::new();
654 for i in range(0u, self_args.len()) {
655 let (pat, ident_expr) = trait_.create_struct_pattern(cx, type_ident, struct_def,
656 format!("__self_{}", i),
659 raw_fields.push(ident_expr);
662 // transpose raw_fields
663 let fields = if raw_fields.len() > 0 {
667 .map(|(i, &(span, opt_id, field))| {
668 let other_fields = raw_fields.tail().iter().map(|l| {
681 cx.span_bug(trait_.span,
682 "no self arguments to non-static method in generic \
686 // body of the inner most destructuring match
687 let mut body = self.call_substructure_method(
695 // make a series of nested matches, to destructure the
696 // structs. This is actually right-to-left, but it shoudn't
698 for (&arg_expr, &pat) in self_args.iter().zip(patterns.iter()) {
699 body = cx.expr_match(trait_.span, arg_expr,
700 vec!( cx.arm(trait_.span, vec!(pat), body) ))
705 fn expand_static_struct_method_body(&self,
708 struct_def: &StructDef,
711 nonself_args: &[@Expr])
713 let summary = trait_.summarise_struct(cx, struct_def);
715 self.call_substructure_method(cx,
718 self_args, nonself_args,
719 &StaticStruct(struct_def, summary))
730 // is equivalent to (with const_nonmatching == false)
733 fn eq(&self, __arg_1: &A) {
735 A1 => match *__arg_1 {
737 A2(ref __arg_1_1) => false
739 A2(self_1) => match *__arg_1 {
741 A2(ref __arg_1_1) => self_1.eq(__arg_1_1)
748 fn expand_enum_method_body(&self,
754 nonself_args: &[@Expr])
756 let mut matches = Vec::new();
757 self.build_enum_match(cx, trait_, enum_def, type_ident,
758 self_args, nonself_args,
759 None, &mut matches, 0)
764 Creates the nested matches for an enum definition recursively, i.e.
768 Variant1 => match other { Variant1 => matching, Variant2 => nonmatching, ... },
769 Variant2 => match other { Variant1 => nonmatching, Variant2 => matching, ... },
774 It acts in the most naive way, so every branch (and subbranch,
775 subsubbranch, etc) exists, not just the ones where all the variants in
776 the tree are the same. Hopefully the optimisers get rid of any
777 repetition, otherwise derived methods with many Self arguments will be
780 `matching` is Some(n) if all branches in the tree above the
781 current position are variant `n`, `None` otherwise (including on
784 fn build_enum_match(&self,
790 nonself_args: &[@Expr],
791 matching: Option<uint>,
792 matches_so_far: &mut Vec<(uint, P<ast::Variant>,
793 Vec<(Span, Option<Ident>, @Expr)> )> ,
794 match_count: uint) -> @Expr {
795 if match_count == self_args.len() {
796 // we've matched against all arguments, so make the final
797 // expression at the bottom of the match tree
798 if matches_so_far.len() == 0 {
799 cx.span_bug(trait_.span,
800 "no self match on an enum in \
801 generic `deriving`");
803 // we currently have a vec of vecs, where each
804 // subvec is the fields of one of the arguments,
805 // but if the variants all match, we want this as
806 // vec of tuples, where each tuple represents a
811 // most arms don't have matching variants, so do a
812 // quick check to see if they match (even though
813 // this means iterating twice) instead of being
814 // optimistic and doing a pile of allocations etc.
816 Some(variant_index) => {
817 // `ref` inside let matches is buggy. Causes havoc wih rusc.
818 // let (variant_index, ref self_vec) = matches_so_far[0];
819 let (variant, self_vec) = match matches_so_far.get(0) {
820 &(_, v, ref s) => (v, s)
823 let mut enum_matching_fields = Vec::from_elem(self_vec.len(), Vec::new());
825 for triple in matches_so_far.tail().iter() {
827 &(_, _, ref other_fields) => {
828 for (i, &(_, _, e)) in other_fields.iter().enumerate() {
829 enum_matching_fields.get_mut(i).push(e);
836 .zip(enum_matching_fields.iter())
837 .map(|(&(span, id, self_f), other)| {
842 other: (*other).clone()
845 substructure = EnumMatching(variant_index, variant, field_tuples);
848 substructure = EnumNonMatching(matches_so_far.as_slice());
851 self.call_substructure_method(cx, trait_, type_ident,
852 self_args, nonself_args,
855 } else { // there are still matches to create
856 let current_match_str = if match_count == 0 {
859 format!("__arg_{}", match_count)
862 let mut arms = Vec::new();
864 // the code for nonmatching variants only matters when
865 // we've seen at least one other variant already
866 if self.const_nonmatching && match_count > 0 {
867 // make a matching-variant match, and a _ match.
868 let index = match matching {
870 None => cx.span_bug(trait_.span,
871 "non-matching variants when required to \
872 be matching in generic `deriving`")
875 // matching-variant match
876 let variant = *enum_def.variants.get(index);
877 let (pattern, idents) = trait_.create_enum_variant_pattern(cx,
882 matches_so_far.push((index, variant, idents));
883 let arm_expr = self.build_enum_match(cx,
887 self_args, nonself_args,
891 matches_so_far.pop().unwrap();
892 arms.push(cx.arm(trait_.span, vec!( pattern ), arm_expr));
894 if enum_def.variants.len() > 1 {
895 let e = &EnumNonMatching(&[]);
896 let wild_expr = self.call_substructure_method(cx, trait_, type_ident,
897 self_args, nonself_args,
899 let wild_arm = cx.arm(
901 vec!( cx.pat_wild(trait_.span) ),
906 // create an arm matching on each variant
907 for (index, &variant) in enum_def.variants.iter().enumerate() {
908 let (pattern, idents) = trait_.create_enum_variant_pattern(cx,
913 matches_so_far.push((index, variant, idents));
916 _ if match_count == 0 => Some(index),
917 Some(i) if index == i => Some(i),
920 let arm_expr = self.build_enum_match(cx,
924 self_args, nonself_args,
928 matches_so_far.pop().unwrap();
930 let arm = cx.arm(trait_.span, vec!( pattern ), arm_expr);
935 // match foo { arm, arm, arm, ... }
936 cx.expr_match(trait_.span, self_args[match_count], arms)
940 fn expand_static_enum_method_body(&self,
946 nonself_args: &[@Expr])
948 let summary = enum_def.variants.iter().map(|v| {
949 let ident = v.node.name;
950 let summary = match v.node.kind {
951 ast::TupleVariantKind(ref args) => {
952 Unnamed(args.iter().map(|va| trait_.set_expn_info(cx, va.ty.span)).collect())
954 ast::StructVariantKind(struct_def) => {
955 trait_.summarise_struct(cx, struct_def)
958 (ident, v.span, summary)
960 self.call_substructure_method(cx, trait_, type_ident,
961 self_args, nonself_args,
962 &StaticEnum(enum_def, summary))
966 #[deriving(Eq)] // dogfooding!
968 Unknown, Record, Tuple
971 // general helper methods.
972 impl<'a> TraitDef<'a> {
973 fn set_expn_info(&self,
975 mut to_set: Span) -> Span {
976 let trait_name = match self.path.path.last() {
977 None => cx.span_bug(self.span, "trait with empty path in generic `deriving`"),
980 to_set.expn_info = Some(@codemap::ExpnInfo {
982 callee: codemap::NameAndSpan {
983 name: format!("deriving({})", trait_name),
984 format: codemap::MacroAttribute,
985 span: Some(self.span)
991 fn summarise_struct(&self,
993 struct_def: &StructDef) -> StaticFields {
994 let mut named_idents = Vec::new();
995 let mut just_spans = Vec::new();
996 for field in struct_def.fields.iter(){
997 let sp = self.set_expn_info(cx, field.span);
998 match field.node.kind {
999 ast::NamedField(ident, _) => named_idents.push((ident, sp)),
1000 ast::UnnamedField(..) => just_spans.push(sp),
1004 match (just_spans.is_empty(), named_idents.is_empty()) {
1005 (false, false) => cx.span_bug(self.span,
1006 "a struct with named and unnamed \
1007 fields in generic `deriving`"),
1009 (_, false) => Named(named_idents),
1010 // tuple structs (includes empty structs)
1011 (_, _) => Unnamed(just_spans)
1015 fn create_subpatterns(&self,
1017 field_paths: Vec<ast::Path> ,
1018 mutbl: ast::Mutability)
1020 field_paths.iter().map(|path| {
1022 ast::PatIdent(ast::BindByRef(mutbl), (*path).clone(), None))
1026 fn create_struct_pattern(&self,
1028 struct_ident: Ident,
1029 struct_def: &StructDef,
1031 mutbl: ast::Mutability)
1032 -> (@ast::Pat, Vec<(Span, Option<Ident>, @Expr)> ) {
1033 if struct_def.fields.is_empty() {
1035 cx.pat_ident_binding_mode(
1036 self.span, struct_ident, ast::BindByValue(ast::MutImmutable)),
1040 let matching_path = cx.path(self.span, vec!( struct_ident ));
1042 let mut paths = Vec::new();
1043 let mut ident_expr = Vec::new();
1044 let mut struct_type = Unknown;
1046 for (i, struct_field) in struct_def.fields.iter().enumerate() {
1047 let sp = self.set_expn_info(cx, struct_field.span);
1048 let opt_id = match struct_field.node.kind {
1049 ast::NamedField(ident, _) if (struct_type == Unknown ||
1050 struct_type == Record) => {
1051 struct_type = Record;
1054 ast::UnnamedField(..) if (struct_type == Unknown ||
1055 struct_type == Tuple) => {
1056 struct_type = Tuple;
1060 cx.span_bug(sp, "a struct with named and unnamed fields in `deriving`");
1063 let path = cx.path_ident(sp, cx.ident_of(format!("{}_{}", prefix, i)));
1064 paths.push(path.clone());
1067 cx.expr_deref(sp, cx.expr_path(path))));
1068 ident_expr.push((sp, opt_id, val));
1071 let subpats = self.create_subpatterns(cx, paths, mutbl);
1073 // struct_type is definitely not Unknown, since struct_def.fields
1074 // must be nonempty to reach here
1075 let pattern = if struct_type == Record {
1076 let field_pats = subpats.iter().zip(ident_expr.iter()).map(|(&pat, &(_, id, _))| {
1077 // id is guaranteed to be Some
1078 ast::FieldPat { ident: id.unwrap(), pat: pat }
1080 cx.pat_struct(self.span, matching_path, field_pats)
1082 cx.pat_enum(self.span, matching_path, subpats)
1085 (pattern, ident_expr)
1088 fn create_enum_variant_pattern(&self,
1090 variant: &ast::Variant,
1092 mutbl: ast::Mutability)
1093 -> (@ast::Pat, Vec<(Span, Option<Ident>, @Expr)> ) {
1094 let variant_ident = variant.node.name;
1095 match variant.node.kind {
1096 ast::TupleVariantKind(ref variant_args) => {
1097 if variant_args.is_empty() {
1098 return (cx.pat_ident_binding_mode(variant.span, variant_ident,
1099 ast::BindByValue(ast::MutImmutable)),
1103 let matching_path = cx.path_ident(variant.span, variant_ident);
1105 let mut paths = Vec::new();
1106 let mut ident_expr = Vec::new();
1107 for (i, va) in variant_args.iter().enumerate() {
1108 let sp = self.set_expn_info(cx, va.ty.span);
1109 let path = cx.path_ident(sp, cx.ident_of(format!("{}_{}", prefix, i)));
1111 paths.push(path.clone());
1113 sp, ast::ExprParen(cx.expr_deref(sp, cx.expr_path(path))));
1114 ident_expr.push((sp, None, val));
1117 let subpats = self.create_subpatterns(cx, paths, mutbl);
1119 (cx.pat_enum(variant.span, matching_path, subpats),
1122 ast::StructVariantKind(struct_def) => {
1123 self.create_struct_pattern(cx, variant_ident, struct_def,
1130 /* helpful premade recipes */
1133 Fold the fields. `use_foldl` controls whether this is done
1134 left-to-right (`true`) or right-to-left (`false`).
1136 pub fn cs_fold(use_foldl: bool,
1137 f: |&mut ExtCtxt, Span, @Expr, @Expr, &[@Expr]| -> @Expr,
1139 enum_nonmatch_f: EnumNonMatchFunc,
1142 substructure: &Substructure)
1144 match *substructure.fields {
1145 EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => {
1147 all_fields.iter().fold(base, |old, field| {
1152 field.other.as_slice())
1155 all_fields.iter().rev().fold(base, |old, field| {
1160 field.other.as_slice())
1164 EnumNonMatching(ref all_enums) => enum_nonmatch_f(cx, trait_span,
1166 substructure.nonself_args),
1167 StaticEnum(..) | StaticStruct(..) => {
1168 cx.span_bug(trait_span, "static function in `deriving`")
1175 Call the method that is being derived on all the fields, and then
1176 process the collected results. i.e.
1179 f(cx, span, ~[self_1.method(__arg_1_1, __arg_2_1),
1180 self_2.method(__arg_1_2, __arg_2_2)])
1184 pub fn cs_same_method(f: |&mut ExtCtxt, Span, Vec<@Expr> | -> @Expr,
1185 enum_nonmatch_f: EnumNonMatchFunc,
1188 substructure: &Substructure)
1190 match *substructure.fields {
1191 EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => {
1192 // call self_n.method(other_1_n, other_2_n, ...)
1193 let called = all_fields.iter().map(|field| {
1194 cx.expr_method_call(field.span,
1196 substructure.method_ident,
1198 .map(|e| cx.expr_addr_of(field.span, *e))
1202 f(cx, trait_span, called)
1204 EnumNonMatching(ref all_enums) => enum_nonmatch_f(cx, trait_span,
1206 substructure.nonself_args),
1207 StaticEnum(..) | StaticStruct(..) => {
1208 cx.span_bug(trait_span, "static function in `deriving`")
1214 Fold together the results of calling the derived method on all the
1215 fields. `use_foldl` controls whether this is done left-to-right
1216 (`true`) or right-to-left (`false`).
1219 pub fn cs_same_method_fold(use_foldl: bool,
1220 f: |&mut ExtCtxt, Span, @Expr, @Expr| -> @Expr,
1222 enum_nonmatch_f: EnumNonMatchFunc,
1225 substructure: &Substructure)
1230 vals.iter().fold(base, |old, &new| {
1231 f(cx, span, old, new)
1234 vals.iter().rev().fold(base, |old, &new| {
1235 f(cx, span, old, new)
1240 cx, trait_span, substructure)
1244 Use a given binop to combine the result of calling the derived method
1248 pub fn cs_binop(binop: ast::BinOp, base: @Expr,
1249 enum_nonmatch_f: EnumNonMatchFunc,
1250 cx: &mut ExtCtxt, trait_span: Span,
1251 substructure: &Substructure) -> @Expr {
1252 cs_same_method_fold(
1253 true, // foldl is good enough
1254 |cx, span, old, new| {
1255 cx.expr_binary(span,
1262 cx, trait_span, substructure)
1265 /// cs_binop with binop == or
1267 pub fn cs_or(enum_nonmatch_f: EnumNonMatchFunc,
1268 cx: &mut ExtCtxt, span: Span,
1269 substructure: &Substructure) -> @Expr {
1270 cs_binop(ast::BiOr, cx.expr_bool(span, false),
1272 cx, span, substructure)
1275 /// cs_binop with binop == and
1277 pub fn cs_and(enum_nonmatch_f: EnumNonMatchFunc,
1278 cx: &mut ExtCtxt, span: Span,
1279 substructure: &Substructure) -> @Expr {
1280 cs_binop(ast::BiAnd, cx.expr_bool(span, true),
1282 cx, span, substructure)