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 `PartialEq` bound at the
28 moment. (`TraitDef.additional_bounds`)
30 Unsupported: FIXME #6257: calling methods on reference fields,
31 e.g. deriving Eq/Ord/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 `PartialEq` is used for in-code examples:
89 fn eq(&self, other: &Self);
91 impl PartialEq for int {
92 fn eq(&self, other: &int) -> bool {
98 Some examples of the values of `SubstructureFields` follow, using the
99 above `PartialEq`, `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;
181 use std::gc::{Gc, GC};
184 use ast::{P, EnumDef, Expr, Ident, Generics, StructDef};
187 use attr::AttrMetaMethods;
188 use ext::base::ExtCtxt;
189 use ext::build::AstBuilder;
192 use owned_slice::OwnedSlice;
193 use parse::token::InternedString;
199 pub struct TraitDef<'a> {
200 /// The span for the current #[deriving(Foo)] header.
203 pub attributes: Vec<ast::Attribute>,
205 /// Path of the trait, including any type parameters
208 /// Additional bounds required of any type parameters of the type,
209 /// other than the current trait
210 pub additional_bounds: Vec<Ty<'a>>,
212 /// Any extra lifetimes and/or bounds, e.g. `D: serialize::Decoder`
213 pub generics: LifetimeBounds<'a>,
215 pub methods: Vec<MethodDef<'a>>,
219 pub struct MethodDef<'a> {
220 /// name of the method
222 /// List of generics, e.g. `R: rand::Rng`
223 pub generics: LifetimeBounds<'a>,
225 /// Whether there is a self argument (outer Option) i.e. whether
226 /// this is a static function, and whether it is a pointer (inner
228 pub explicit_self: Option<Option<PtrTy<'a>>>,
230 /// Arguments other than the self argument
231 pub args: Vec<Ty<'a>>,
236 pub attributes: Vec<ast::Attribute>,
238 /// if the value of the nonmatching enums is independent of the
239 /// actual enum variants, i.e. can use _ => .. match.
240 pub const_nonmatching: bool,
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, [(variant index, ast::Variant,
293 [field span, field ident, fields])] \(i.e. all fields for self are in the
294 first tuple, for other1 are in the second tuple, etc.)
296 EnumNonMatching(&'a [(uint, P<ast::Variant>,
297 Vec<(Span, Option<Ident>, Gc<Expr>)>)]),
299 /// A static method where Self is a struct.
300 StaticStruct(&'a ast::StructDef, StaticFields),
301 /// A static method where Self is an enum.
302 StaticEnum(&'a ast::EnumDef, Vec<(Ident, Span, StaticFields)>),
308 Combine the values of all the fields together. The last argument is
309 all the fields of all the structures, see above for details.
311 pub type CombineSubstructureFunc<'a> =
312 |&mut ExtCtxt, Span, &Substructure|: 'a -> Gc<Expr>;
315 Deal with non-matching enum variants, the arguments are a list
316 representing each variant: (variant index, ast::Variant instance,
317 [variant fields]), and a list of the nonself args of the type
319 pub type EnumNonMatchFunc<'a> =
322 &[(uint, P<ast::Variant>, Vec<(Span, Option<Ident>, Gc<Expr>)>)],
326 pub fn combine_substructure<'a>(f: CombineSubstructureFunc<'a>)
327 -> RefCell<CombineSubstructureFunc<'a>> {
332 impl<'a> TraitDef<'a> {
335 _mitem: Gc<ast::MetaItem>,
337 push: |Gc<ast::Item>|) {
338 let newitem = match item.node {
339 ast::ItemStruct(ref struct_def, ref generics) => {
340 self.expand_struct_def(cx,
345 ast::ItemEnum(ref enum_def, ref generics) => {
346 self.expand_enum_def(cx,
353 // Keep the lint attributes of the previous item to control how the
354 // generated implementations are linted
355 let mut attrs = newitem.attrs.clone();
356 attrs.extend(item.attrs.iter().filter(|a| {
357 match a.name().get() {
358 "allow" | "warn" | "deny" | "forbid" => true,
361 }).map(|a| a.clone()));
362 push(box(GC) ast::Item {
370 * Given that we are deriving a trait `Tr` for a type `T<'a, ...,
371 * 'z, A, ..., Z>`, creates an impl like:
374 * impl<'a, ..., 'z, A:Tr B1 B2, ..., Z: Tr B1 B2> Tr for T<A, ..., Z> { ... }
377 * where B1, B2, ... are the bounds given by `bounds_paths`.'
380 fn create_derived_impl(&self,
384 methods: Vec<Gc<ast::Method>> ) -> Gc<ast::Item> {
385 let trait_path = self.path.to_path(cx, self.span, type_ident, generics);
387 let Generics { mut lifetimes, ty_params } =
388 self.generics.to_generics(cx, self.span, type_ident, generics);
389 let mut ty_params = ty_params.into_vec();
391 // Copy the lifetimes
392 lifetimes.extend(generics.lifetimes.iter().map(|l| *l));
394 // Create the type parameters.
395 ty_params.extend(generics.ty_params.iter().map(|ty_param| {
396 // I don't think this can be moved out of the loop, since
397 // a TyParamBound requires an ast id
398 let mut bounds: Vec<_> =
399 // extra restrictions on the generics parameters to the type being derived upon
400 self.additional_bounds.iter().map(|p| {
401 cx.typarambound(p.to_path(cx, self.span,
402 type_ident, generics))
404 // require the current trait
405 bounds.push(cx.typarambound(trait_path.clone()));
407 cx.typaram(self.span,
410 OwnedSlice::from_vec(bounds),
413 let trait_generics = Generics {
414 lifetimes: lifetimes,
415 ty_params: OwnedSlice::from_vec(ty_params)
418 // Create the reference to the trait.
419 let trait_ref = cx.trait_ref(trait_path);
421 // Create the type parameters on the `self` path.
422 let self_ty_params = generics.ty_params.map(|ty_param| {
423 cx.ty_ident(self.span, ty_param.ident)
426 let self_lifetimes = generics.lifetimes.clone();
428 // Create the type of `self`.
429 let self_type = cx.ty_path(
430 cx.path_all(self.span, false, vec!( type_ident ), self_lifetimes,
431 self_ty_params.into_vec()), None);
433 let attr = cx.attribute(
435 cx.meta_word(self.span,
436 InternedString::new("automatically_derived")));
437 // Just mark it now since we know that it'll end up used downstream
438 attr::mark_used(&attr);
439 let opt_trait_ref = Some(trait_ref);
440 let ident = ast_util::impl_pretty_name(&opt_trait_ref, &*self_type);
444 (vec!(attr)).append(self.attributes.as_slice()),
445 ast::ItemImpl(trait_generics, opt_trait_ref,
449 fn expand_struct_def(&self,
451 struct_def: &StructDef,
453 generics: &Generics) -> Gc<ast::Item> {
454 let methods = self.methods.iter().map(|method_def| {
455 let (explicit_self, self_args, nonself_args, tys) =
456 method_def.split_self_nonself_args(
457 cx, self, type_ident, generics);
459 let body = if method_def.is_static() {
460 method_def.expand_static_struct_method_body(
465 self_args.as_slice(),
466 nonself_args.as_slice())
468 method_def.expand_struct_method_body(cx,
472 self_args.as_slice(),
473 nonself_args.as_slice())
476 method_def.create_method(cx, self,
477 type_ident, generics,
482 self.create_derived_impl(cx, type_ident, generics, methods)
485 fn expand_enum_def(&self,
489 generics: &Generics) -> Gc<ast::Item> {
490 let methods = self.methods.iter().map(|method_def| {
491 let (explicit_self, self_args, nonself_args, tys) =
492 method_def.split_self_nonself_args(cx, self,
493 type_ident, generics);
495 let body = if method_def.is_static() {
496 method_def.expand_static_enum_method_body(
501 self_args.as_slice(),
502 nonself_args.as_slice())
504 method_def.expand_enum_method_body(cx,
508 self_args.as_slice(),
509 nonself_args.as_slice())
512 method_def.create_method(cx, self,
513 type_ident, generics,
518 self.create_derived_impl(cx, type_ident, generics, methods)
522 impl<'a> MethodDef<'a> {
523 fn call_substructure_method(&self,
527 self_args: &[Gc<Expr>],
528 nonself_args: &[Gc<Expr>],
529 fields: &SubstructureFields)
531 let substructure = Substructure {
532 type_ident: type_ident,
533 method_ident: cx.ident_of(self.name),
534 self_args: self_args,
535 nonself_args: nonself_args,
538 let mut f = self.combine_substructure.borrow_mut();
539 let f: &mut CombineSubstructureFunc = &mut *f;
540 (*f)(cx, trait_.span, &substructure)
549 self.ret_ty.to_ty(cx, trait_.span, type_ident, generics)
552 fn is_static(&self) -> bool {
553 self.explicit_self.is_none()
556 fn split_self_nonself_args(&self,
561 -> (ast::ExplicitSelf, Vec<Gc<Expr>>, Vec<Gc<Expr>>,
562 Vec<(Ident, P<ast::Ty>)>) {
564 let mut self_args = Vec::new();
565 let mut nonself_args = Vec::new();
566 let mut arg_tys = Vec::new();
567 let mut nonstatic = false;
569 let ast_explicit_self = match self.explicit_self {
570 Some(ref self_ptr) => {
571 let (self_expr, explicit_self) =
572 ty::get_explicit_self(cx, trait_.span, self_ptr);
574 self_args.push(self_expr);
579 None => codemap::respan(trait_.span, ast::SelfStatic),
582 for (i, ty) in self.args.iter().enumerate() {
583 let ast_ty = ty.to_ty(cx, trait_.span, type_ident, generics);
584 let ident = cx.ident_of(format!("__arg_{}", i).as_slice());
585 arg_tys.push((ident, ast_ty));
587 let arg_expr = cx.expr_ident(trait_.span, ident);
590 // for static methods, just treat any Self
591 // arguments as a normal arg
592 Self if nonstatic => {
593 self_args.push(arg_expr);
595 Ptr(box Self, _) if nonstatic => {
596 self_args.push(cx.expr_deref(trait_.span, arg_expr))
599 nonself_args.push(arg_expr);
604 (ast_explicit_self, self_args, nonself_args, arg_tys)
607 fn create_method(&self,
612 explicit_self: ast::ExplicitSelf,
613 arg_types: Vec<(Ident, P<ast::Ty>)> ,
614 body: Gc<Expr>) -> Gc<ast::Method> {
615 // create the generics that aren't for Self
616 let fn_generics = self.generics.to_generics(cx, trait_.span, type_ident, generics);
618 let self_arg = match explicit_self.node {
619 ast::SelfStatic => None,
620 _ => Some(ast::Arg::new_self(trait_.span, ast::MutImmutable))
623 let args = arg_types.move_iter().map(|(name, ty)| {
624 cx.arg(trait_.span, name, ty)
626 self_arg.move_iter().chain(args).collect()
629 let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident);
631 let method_ident = cx.ident_of(self.name);
632 let fn_decl = cx.fn_decl(args, ret_type);
633 let body_block = cx.block_expr(body);
635 // Create the method.
636 box(GC) ast::Method {
638 attrs: self.attributes.clone(),
639 generics: fn_generics,
640 explicit_self: explicit_self,
641 fn_style: ast::NormalFn,
644 id: ast::DUMMY_NODE_ID,
652 #[deriving(PartialEq)]
653 struct A { x: int, y: int }
656 impl PartialEq for A {
657 fn eq(&self, __arg_1: &A) -> bool {
659 A {x: ref __self_0_0, y: ref __self_0_1} => {
661 A {x: ref __self_1_0, y: ref __self_1_1} => {
662 __self_0_0.eq(__self_1_0) && __self_0_1.eq(__self_1_1)
671 fn expand_struct_method_body(&self,
674 struct_def: &StructDef,
676 self_args: &[Gc<Expr>],
677 nonself_args: &[Gc<Expr>])
680 let mut raw_fields = Vec::new(); // ~[[fields of self],
681 // [fields of next Self arg], [etc]]
682 let mut patterns = Vec::new();
683 for i in range(0u, self_args.len()) {
684 let (pat, ident_expr) =
685 trait_.create_struct_pattern(cx,
692 raw_fields.push(ident_expr);
695 // transpose raw_fields
696 let fields = if raw_fields.len() > 0 {
700 .map(|(i, &(span, opt_id, field))| {
701 let other_fields = raw_fields.tail().iter().map(|l| {
714 cx.span_bug(trait_.span,
715 "no self arguments to non-static method in generic \
719 // body of the inner most destructuring match
720 let mut body = self.call_substructure_method(
728 // make a series of nested matches, to destructure the
729 // structs. This is actually right-to-left, but it shouldn't
731 for (&arg_expr, &pat) in self_args.iter().zip(patterns.iter()) {
732 body = cx.expr_match(trait_.span, arg_expr,
733 vec!( cx.arm(trait_.span, vec!(pat), body) ))
738 fn expand_static_struct_method_body(&self,
741 struct_def: &StructDef,
743 self_args: &[Gc<Expr>],
744 nonself_args: &[Gc<Expr>])
746 let summary = trait_.summarise_struct(cx, struct_def);
748 self.call_substructure_method(cx,
751 self_args, nonself_args,
752 &StaticStruct(struct_def, summary))
757 #[deriving(PartialEq)]
763 // is equivalent to (with const_nonmatching == false)
765 impl PartialEq for A {
766 fn eq(&self, __arg_1: &A) {
768 A1 => match *__arg_1 {
770 A2(ref __arg_1_1) => false
772 A2(self_1) => match *__arg_1 {
774 A2(ref __arg_1_1) => self_1.eq(__arg_1_1)
781 fn expand_enum_method_body(&self,
786 self_args: &[Gc<Expr>],
787 nonself_args: &[Gc<Expr>])
789 let mut matches = Vec::new();
790 self.build_enum_match(cx, trait_, enum_def, type_ident,
791 self_args, nonself_args,
792 None, &mut matches, 0)
797 Creates the nested matches for an enum definition recursively, i.e.
801 Variant1 => match other { Variant1 => matching, Variant2 => nonmatching, ... },
802 Variant2 => match other { Variant1 => nonmatching, Variant2 => matching, ... },
807 It acts in the most naive way, so every branch (and subbranch,
808 subsubbranch, etc) exists, not just the ones where all the variants in
809 the tree are the same. Hopefully the optimisers get rid of any
810 repetition, otherwise derived methods with many Self arguments will be
813 `matching` is Some(n) if all branches in the tree above the
814 current position are variant `n`, `None` otherwise (including on
817 fn build_enum_match(&self,
822 self_args: &[Gc<Expr>],
823 nonself_args: &[Gc<Expr>],
824 matching: Option<uint>,
825 matches_so_far: &mut Vec<(uint, P<ast::Variant>,
826 Vec<(Span, Option<Ident>, Gc<Expr>)>)> ,
827 match_count: uint) -> Gc<Expr> {
828 if match_count == self_args.len() {
829 // we've matched against all arguments, so make the final
830 // expression at the bottom of the match tree
831 if matches_so_far.len() == 0 {
832 cx.span_bug(trait_.span,
833 "no self match on an enum in \
834 generic `deriving`");
837 // `ref` inside let matches is buggy. Causes havoc with rusc.
838 // let (variant_index, ref self_vec) = matches_so_far[0];
839 let (variant, self_vec) = match matches_so_far.get(0) {
840 &(_, v, ref s) => (v, s)
843 // we currently have a vec of vecs, where each
844 // subvec is the fields of one of the arguments,
845 // but if the variants all match, we want this as
846 // vec of tuples, where each tuple represents a
849 // most arms don't have matching variants, so do a
850 // quick check to see if they match (even though
851 // this means iterating twice) instead of being
852 // optimistic and doing a pile of allocations etc.
853 let substructure = match matching {
854 Some(variant_index) => {
855 let mut enum_matching_fields = Vec::from_elem(self_vec.len(), Vec::new());
857 for triple in matches_so_far.tail().iter() {
859 &(_, _, ref other_fields) => {
860 for (i, &(_, _, e)) in other_fields.iter().enumerate() {
861 enum_matching_fields.get_mut(i).push(e);
868 .zip(enum_matching_fields.iter())
869 .map(|(&(span, id, self_f), other)| {
874 other: (*other).clone()
877 EnumMatching(variant_index, &*variant, field_tuples)
880 EnumNonMatching(matches_so_far.as_slice())
883 self.call_substructure_method(cx, trait_, type_ident,
884 self_args, nonself_args,
887 } else { // there are still matches to create
888 let current_match_str = if match_count == 0 {
891 format!("__arg_{}", match_count)
894 let mut arms = Vec::new();
896 // the code for nonmatching variants only matters when
897 // we've seen at least one other variant already
898 if self.const_nonmatching && match_count > 0 {
899 // make a matching-variant match, and a _ match.
900 let index = match matching {
902 None => cx.span_bug(trait_.span,
903 "non-matching variants when required to \
904 be matching in generic `deriving`")
907 // matching-variant match
908 let variant = *enum_def.variants.get(index);
909 let (pattern, idents) = trait_.create_enum_variant_pattern(
912 current_match_str.as_slice(),
915 matches_so_far.push((index, variant, idents));
916 let arm_expr = self.build_enum_match(cx,
920 self_args, nonself_args,
924 matches_so_far.pop().unwrap();
925 arms.push(cx.arm(trait_.span, vec!( pattern ), arm_expr));
927 if enum_def.variants.len() > 1 {
928 let e = &EnumNonMatching(&[]);
929 let wild_expr = self.call_substructure_method(cx, trait_, type_ident,
930 self_args, nonself_args,
932 let wild_arm = cx.arm(
934 vec!( cx.pat_wild(trait_.span) ),
939 // create an arm matching on each variant
940 for (index, &variant) in enum_def.variants.iter().enumerate() {
941 let (pattern, idents) =
942 trait_.create_enum_variant_pattern(
945 current_match_str.as_slice(),
948 matches_so_far.push((index, variant, idents));
951 _ if match_count == 0 => Some(index),
952 Some(i) if index == i => Some(i),
955 let arm_expr = self.build_enum_match(cx,
959 self_args, nonself_args,
963 matches_so_far.pop().unwrap();
965 let arm = cx.arm(trait_.span, vec!( pattern ), arm_expr);
970 // match foo { arm, arm, arm, ... }
971 cx.expr_match(trait_.span, self_args[match_count], arms)
975 fn expand_static_enum_method_body(&self,
980 self_args: &[Gc<Expr>],
981 nonself_args: &[Gc<Expr>])
983 let summary = enum_def.variants.iter().map(|v| {
984 let ident = v.node.name;
985 let summary = match v.node.kind {
986 ast::TupleVariantKind(ref args) => {
987 Unnamed(args.iter().map(|va| trait_.set_expn_info(cx, va.ty.span)).collect())
989 ast::StructVariantKind(ref struct_def) => {
990 trait_.summarise_struct(cx, &**struct_def)
993 (ident, v.span, summary)
995 self.call_substructure_method(cx, trait_, type_ident,
996 self_args, nonself_args,
997 &StaticEnum(enum_def, summary))
1001 #[deriving(PartialEq)] // dogfooding!
1003 Unknown, Record, Tuple
1006 // general helper methods.
1007 impl<'a> TraitDef<'a> {
1008 fn set_expn_info(&self,
1010 mut to_set: Span) -> Span {
1011 let trait_name = match self.path.path.last() {
1012 None => cx.span_bug(self.span, "trait with empty path in generic `deriving`"),
1015 to_set.expn_info = Some(box(GC) codemap::ExpnInfo {
1017 callee: codemap::NameAndSpan {
1018 name: format!("deriving({})", trait_name),
1019 format: codemap::MacroAttribute,
1020 span: Some(self.span)
1026 fn summarise_struct(&self,
1028 struct_def: &StructDef) -> StaticFields {
1029 let mut named_idents = Vec::new();
1030 let mut just_spans = Vec::new();
1031 for field in struct_def.fields.iter(){
1032 let sp = self.set_expn_info(cx, field.span);
1033 match field.node.kind {
1034 ast::NamedField(ident, _) => named_idents.push((ident, sp)),
1035 ast::UnnamedField(..) => just_spans.push(sp),
1039 match (just_spans.is_empty(), named_idents.is_empty()) {
1040 (false, false) => cx.span_bug(self.span,
1041 "a struct with named and unnamed \
1042 fields in generic `deriving`"),
1044 (_, false) => Named(named_idents),
1045 // tuple structs (includes empty structs)
1046 (_, _) => Unnamed(just_spans)
1050 fn create_subpatterns(&self,
1052 field_paths: Vec<ast::SpannedIdent> ,
1053 mutbl: ast::Mutability)
1054 -> Vec<Gc<ast::Pat>> {
1055 field_paths.iter().map(|path| {
1057 ast::PatIdent(ast::BindByRef(mutbl), (*path).clone(), None))
1061 fn create_struct_pattern(&self,
1063 struct_ident: Ident,
1064 struct_def: &StructDef,
1066 mutbl: ast::Mutability)
1067 -> (Gc<ast::Pat>, Vec<(Span, Option<Ident>, Gc<Expr>)>) {
1068 if struct_def.fields.is_empty() {
1070 cx.pat_ident_binding_mode(
1071 self.span, struct_ident, ast::BindByValue(ast::MutImmutable)),
1075 let matching_path = cx.path(self.span, vec!( struct_ident ));
1077 let mut paths = Vec::new();
1078 let mut ident_expr = Vec::new();
1079 let mut struct_type = Unknown;
1081 for (i, struct_field) in struct_def.fields.iter().enumerate() {
1082 let sp = self.set_expn_info(cx, struct_field.span);
1083 let opt_id = match struct_field.node.kind {
1084 ast::NamedField(ident, _) if (struct_type == Unknown ||
1085 struct_type == Record) => {
1086 struct_type = Record;
1089 ast::UnnamedField(..) if (struct_type == Unknown ||
1090 struct_type == Tuple) => {
1091 struct_type = Tuple;
1095 cx.span_bug(sp, "a struct with named and unnamed fields in `deriving`");
1098 let ident = cx.ident_of(format!("{}_{}", prefix, i).as_slice());
1099 paths.push(codemap::Spanned{span: sp, node: ident});
1101 sp, ast::ExprParen(cx.expr_deref(sp, cx.expr_path(cx.path_ident(sp,ident)))));
1102 ident_expr.push((sp, opt_id, val));
1105 let subpats = self.create_subpatterns(cx, paths, mutbl);
1107 // struct_type is definitely not Unknown, since struct_def.fields
1108 // must be nonempty to reach here
1109 let pattern = if struct_type == Record {
1110 let field_pats = subpats.iter().zip(ident_expr.iter()).map(|(&pat, &(_, id, _))| {
1111 // id is guaranteed to be Some
1112 ast::FieldPat { ident: id.unwrap(), pat: pat }
1114 cx.pat_struct(self.span, matching_path, field_pats)
1116 cx.pat_enum(self.span, matching_path, subpats)
1119 (pattern, ident_expr)
1122 fn create_enum_variant_pattern(&self,
1124 variant: &ast::Variant,
1126 mutbl: ast::Mutability)
1127 -> (Gc<ast::Pat>, Vec<(Span, Option<Ident>, Gc<Expr>)> ) {
1128 let variant_ident = variant.node.name;
1129 match variant.node.kind {
1130 ast::TupleVariantKind(ref variant_args) => {
1131 if variant_args.is_empty() {
1132 return (cx.pat_ident_binding_mode(variant.span, variant_ident,
1133 ast::BindByValue(ast::MutImmutable)),
1137 let matching_path = cx.path_ident(variant.span, variant_ident);
1139 let mut paths = Vec::new();
1140 let mut ident_expr = Vec::new();
1141 for (i, va) in variant_args.iter().enumerate() {
1142 let sp = self.set_expn_info(cx, va.ty.span);
1143 let ident = cx.ident_of(format!("{}_{}", prefix, i).as_slice());
1144 let path1 = codemap::Spanned{span: sp, node: ident};
1146 let expr_path = cx.expr_path(cx.path_ident(sp, ident));
1147 let val = cx.expr(sp, ast::ExprParen(cx.expr_deref(sp, expr_path)));
1148 ident_expr.push((sp, None, val));
1151 let subpats = self.create_subpatterns(cx, paths, mutbl);
1153 (cx.pat_enum(variant.span, matching_path, subpats),
1156 ast::StructVariantKind(ref struct_def) => {
1157 self.create_struct_pattern(cx, variant_ident, &**struct_def,
1164 /* helpful premade recipes */
1167 Fold the fields. `use_foldl` controls whether this is done
1168 left-to-right (`true`) or right-to-left (`false`).
1170 pub fn cs_fold(use_foldl: bool,
1171 f: |&mut ExtCtxt, Span, Gc<Expr>, Gc<Expr>, &[Gc<Expr>]| -> Gc<Expr>,
1173 enum_nonmatch_f: EnumNonMatchFunc,
1176 substructure: &Substructure)
1178 match *substructure.fields {
1179 EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => {
1181 all_fields.iter().fold(base, |old, field| {
1186 field.other.as_slice())
1189 all_fields.iter().rev().fold(base, |old, field| {
1194 field.other.as_slice())
1198 EnumNonMatching(ref all_enums) => enum_nonmatch_f(cx, trait_span,
1200 substructure.nonself_args),
1201 StaticEnum(..) | StaticStruct(..) => {
1202 cx.span_bug(trait_span, "static function in `deriving`")
1209 Call the method that is being derived on all the fields, and then
1210 process the collected results. i.e.
1213 f(cx, span, ~[self_1.method(__arg_1_1, __arg_2_1),
1214 self_2.method(__arg_1_2, __arg_2_2)])
1218 pub fn cs_same_method(f: |&mut ExtCtxt, Span, Vec<Gc<Expr>>| -> Gc<Expr>,
1219 enum_nonmatch_f: EnumNonMatchFunc,
1222 substructure: &Substructure)
1224 match *substructure.fields {
1225 EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => {
1226 // call self_n.method(other_1_n, other_2_n, ...)
1227 let called = all_fields.iter().map(|field| {
1228 cx.expr_method_call(field.span,
1230 substructure.method_ident,
1232 .map(|e| cx.expr_addr_of(field.span, *e))
1236 f(cx, trait_span, called)
1238 EnumNonMatching(ref all_enums) => enum_nonmatch_f(cx, trait_span,
1240 substructure.nonself_args),
1241 StaticEnum(..) | StaticStruct(..) => {
1242 cx.span_bug(trait_span, "static function in `deriving`")
1248 Fold together the results of calling the derived method on all the
1249 fields. `use_foldl` controls whether this is done left-to-right
1250 (`true`) or right-to-left (`false`).
1253 pub fn cs_same_method_fold(use_foldl: bool,
1254 f: |&mut ExtCtxt, Span, Gc<Expr>, Gc<Expr>| -> Gc<Expr>,
1256 enum_nonmatch_f: EnumNonMatchFunc,
1259 substructure: &Substructure)
1264 vals.iter().fold(base, |old, &new| {
1265 f(cx, span, old, new)
1268 vals.iter().rev().fold(base, |old, &new| {
1269 f(cx, span, old, new)
1274 cx, trait_span, substructure)
1278 Use a given binop to combine the result of calling the derived method
1282 pub fn cs_binop(binop: ast::BinOp, base: Gc<Expr>,
1283 enum_nonmatch_f: EnumNonMatchFunc,
1284 cx: &mut ExtCtxt, trait_span: Span,
1285 substructure: &Substructure) -> Gc<Expr> {
1286 cs_same_method_fold(
1287 true, // foldl is good enough
1288 |cx, span, old, new| {
1289 cx.expr_binary(span,
1296 cx, trait_span, substructure)
1299 /// cs_binop with binop == or
1301 pub fn cs_or(enum_nonmatch_f: EnumNonMatchFunc,
1302 cx: &mut ExtCtxt, span: Span,
1303 substructure: &Substructure) -> Gc<Expr> {
1304 cs_binop(ast::BiOr, cx.expr_bool(span, false),
1306 cx, span, substructure)
1309 /// cs_binop with binop == and
1311 pub fn cs_and(enum_nonmatch_f: EnumNonMatchFunc,
1312 cx: &mut ExtCtxt, span: Span,
1313 substructure: &Substructure) -> Gc<Expr> {
1314 cs_binop(ast::BiAnd, cx.expr_bool(span, true),
1316 cx, span, substructure)