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.
4 //
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.
10
11 /*!
12
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.
17
18 Supported features (fairly exhaustive):
19
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`)
29
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.
33
34 The most important thing for implementers is the `Substructure` and
35 `SubstructureFields` objects. The latter groups 5 possibilities of the
36 arguments:
37
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
48 arguments.)
49
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
55 differently.
56
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
61 following snippet
62
63 ```rust
64 struct A { x : int }
65
66 struct B(int);
67
68 enum C {
69 C0(int),
70 C1 { x: int }
71 }
72 ```
73
74 The `int`s in `B` and `C0` don't have an identifier, so the
75 `Option<ident>`s would be `None` for them.
76
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.
82
83 # Examples
84
85 The following simplified `Eq` is used for in-code examples:
86
87 ```rust
88 trait Eq {
89 fn eq(&self, other: &Self);
90 }
91 impl Eq for int {
92 fn eq(&self, other: &int) -> bool {
93 *self == *other
94 }
95 }
96 ```
97
98 Some examples of the values of `SubstructureFields` follow, using the
99 above `Eq`, `A`, `B` and `C`.
100
101 ## Structs
102
103 When generating the `expr` for the `A` impl, the `SubstructureFields` is
104
105 ~~~notrust
106 Struct(~[FieldInfo {
107 span: <span of x>
108 name: Some(<ident of x>),
109 self_: <expr for &self.x>,
110 other: ~[<expr for &other.x]
111 }])
112 ~~~
113
114 For the `B` impl, called with `B(a)` and `B(b)`,
115
116 ~~~notrust
117 Struct(~[FieldInfo {
118 span: <span of `int`>,
119 name: None,
120 <expr for &a>
121 ~[<expr for &b>]
122 }])
123 ~~~
124
125 ## Enums
126
127 When generating the `expr` for a call with `self == C0(a)` and `other
128 == C0(b)`, the SubstructureFields is
129
130 ~~~notrust
131 EnumMatching(0, <ast::Variant for C0>,
132 ~[FieldInfo {
133 span: <span of int>
134 name: None,
135 self_: <expr for &a>,
136 other: ~[<expr for &b>]
137 }])
138 ~~~
139
140 For `C1 {x}` and `C1 {x}`,
141
142 ~~~notrust
143 EnumMatching(1, <ast::Variant for C1>,
144 ~[FieldInfo {
145 span: <span of x>
146 name: Some(<ident of x>),
147 self_: <expr for &self.x>,
148 other: ~[<expr for &other.x>]
149 }])
150 ~~~
151
152 For `C0(a)` and `C1 {x}` ,
153
154 ~~~notrust
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>)])])
160 ~~~
161
162 (and vice versa, but with the order of the outermost list flipped.)
163
164 ## Static
165
166 A static method on the above would result in,
167
168 ~~~~notrust
169 StaticStruct(<ast::StructDef of A>, Named(~[(<ident of x>, <span of x>)]))
170
171 StaticStruct(<ast::StructDef of B>, Unnamed(~[<span of x>]))
172
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>)]))])
176 ~~~
177
178 */
179
180 use std::cell::RefCell;
181
182 use ast;
183 use ast::{P, EnumDef, Expr, Ident, Generics, StructDef};
184 use ast_util;
185 use ext::base::ExtCtxt;
186 use ext::build::AstBuilder;
187 use codemap;
188 use codemap::Span;
189 use owned_slice::OwnedSlice;
190 use parse::token::InternedString;
191
192 pub use self::ty::*;
193 mod ty;
194
195 pub struct TraitDef<'a> {
196 /// The span for the current #[deriving(Foo)] header.
197 pub span: Span,
198
199 pub attributes: Vec<ast::Attribute>,
200
201 /// Path of the trait, including any type parameters
202 pub path: Path<'a>,
203
204 /// Additional bounds required of any type parameters of the type,
205 /// other than the current trait
206 pub additional_bounds: Vec<Ty<'a>>,
207
208 /// Any extra lifetimes and/or bounds, e.g. `D: serialize::Decoder`
209 pub generics: LifetimeBounds<'a>,
210
211 pub methods: Vec<MethodDef<'a>>,
212 }
213
214
215 pub struct MethodDef<'a> {
216 /// name of the method
217 pub name: &'a str,
218 /// List of generics, e.g. `R: rand::Rng`
219 pub generics: LifetimeBounds<'a>,
220
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
223 /// Option)
224 pub explicit_self: Option<Option<PtrTy<'a>>>,
225
226 /// Arguments other than the self argument
227 pub args: Vec<Ty<'a>>,
228
229 /// Return type
230 pub ret_ty: Ty<'a>,
231
232 pub attributes: Vec<ast::Attribute>,
233
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,
237
238 pub combine_substructure: RefCell<CombineSubstructureFunc<'a>>,
239 }
240
241 /// All the data about the data structure/method being derived upon.
242 pub struct Substructure<'a> {
243 /// ident of self
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>
252 }
253
254 /// Summary of the relevant parts of a struct/enum field.
255 pub struct FieldInfo {
256 pub span: Span,
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).
262 pub self_: @Expr,
263 /// The expressions corresponding to references to this field in
264 /// the other Self arguments.
265 pub other: Vec<@Expr>,
266 }
267
268 /// Fields for a static method
269 pub enum StaticFields {
270 /// Tuple structs/enum variants like this
271 Unnamed(Vec<Span> ),
272 /// Normal structs/struct variants.
273 Named(Vec<(Ident, Span)> )
274 }
275
276 /// A summary of the possible sets of fields. See above for details
277 /// and examples
278 pub enum SubstructureFields<'a> {
279 Struct(Vec<FieldInfo> ),
280 /**
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
283 variant.
284 */
285 EnumMatching(uint, &'a ast::Variant, Vec<FieldInfo> ),
286
287 /**
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.)
291 */
292 EnumNonMatching(&'a [(uint, P<ast::Variant>, Vec<(Span, Option<Ident>, @Expr)> )]),
293
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)> )
298 }
299
300
301
302 /**
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.
305 */
306 pub type CombineSubstructureFunc<'a> =
307 |&mut ExtCtxt, Span, &Substructure|: 'a -> @Expr;
308
309 /**
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
313 */
314 pub type EnumNonMatchFunc<'a> =
315 |&mut ExtCtxt,
316 Span,
317 &[(uint, P<ast::Variant>, Vec<(Span, Option<Ident>, @Expr)> )],
318 &[@Expr]|: 'a
319 -> @Expr;
320
321 pub fn combine_substructure<'a>(f: CombineSubstructureFunc<'a>)
322 -> RefCell<CombineSubstructureFunc<'a>> {
323 RefCell::new(f)
324 }
325
326
327 impl<'a> TraitDef<'a> {
328 pub fn expand(&self,
329 cx: &mut ExtCtxt,
330 _mitem: @ast::MetaItem,
331 item: @ast::Item,
332 push: |@ast::Item|) {
333 match item.node {
334 ast::ItemStruct(struct_def, ref generics) => {
335 push(self.expand_struct_def(cx,
336 struct_def,
337 item.ident,
338 generics));
339 }
340 ast::ItemEnum(ref enum_def, ref generics) => {
341 push(self.expand_enum_def(cx,
342 enum_def,
343 item.ident,
344 generics));
345 }
346 _ => ()
347 }
348 }
349
350 /**
351 *
352 * Given that we are deriving a trait `Tr` for a type `T<'a, ...,
353 * 'z, A, ..., Z>`, creates an impl like:
354 *
355 * ```ignore
356 * impl<'a, ..., 'z, A:Tr B1 B2, ..., Z: Tr B1 B2> Tr for T<A, ..., Z> { ... }
357 * ```
358 *
359 * where B1, B2, ... are the bounds given by `bounds_paths`.'
360 *
361 */
362 fn create_derived_impl(&self,
363 cx: &mut ExtCtxt,
364 type_ident: Ident,
365 generics: &Generics,
366 methods: Vec<@ast::Method> ) -> @ast::Item {
367 let trait_path = self.path.to_path(cx, self.span, type_ident, generics);
368
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();
372
373 // Copy the lifetimes
374 lifetimes.extend(generics.lifetimes.iter().map(|l| *l));
375
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))
385 }).collect();
386 // require the current trait
387 bounds.push(cx.typarambound(trait_path.clone()));
388
389 cx.typaram(self.span,
390 ty_param.ident,
391 ty_param.sized,
392 OwnedSlice::from_vec(bounds),
393 None)
394 }));
395 let trait_generics = Generics {
396 lifetimes: lifetimes,
397 ty_params: OwnedSlice::from_vec(ty_params)
398 };
399
400 // Create the reference to the trait.
401 let trait_ref = cx.trait_ref(trait_path);
402
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)
406 });
407
408 let self_lifetimes = generics.lifetimes.clone();
409
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);
414
415 let attr = cx.attribute(
416 self.span,
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);
421 cx.item(
422 self.span,
423 ident,
424 (vec!(attr)).append(self.attributes.as_slice()),
425 ast::ItemImpl(trait_generics, opt_trait_ref,
426 self_type, methods))
427 }
428
429 fn expand_struct_def(&self,
430 cx: &mut ExtCtxt,
431 struct_def: &StructDef,
432 type_ident: Ident,
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);
438
439 let body = if method_def.is_static() {
440 method_def.expand_static_struct_method_body(
441 cx,
442 self,
443 struct_def,
444 type_ident,
445 self_args.as_slice(),
446 nonself_args.as_slice())
447 } else {
448 method_def.expand_struct_method_body(cx,
449 self,
450 struct_def,
451 type_ident,
452 self_args.as_slice(),
453 nonself_args.as_slice())
454 };
455
456 method_def.create_method(cx, self,
457 type_ident, generics,
458 explicit_self, tys,
459 body)
460 }).collect();
461
462 self.create_derived_impl(cx, type_ident, generics, methods)
463 }
464
465 fn expand_enum_def(&self,
466 cx: &mut ExtCtxt,
467 enum_def: &EnumDef,
468 type_ident: Ident,
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);
474
475 let body = if method_def.is_static() {
476 method_def.expand_static_enum_method_body(
477 cx,
478 self,
479 enum_def,
480 type_ident,
481 self_args.as_slice(),
482 nonself_args.as_slice())
483 } else {
484 method_def.expand_enum_method_body(cx,
485 self,
486 enum_def,
487 type_ident,
488 self_args.as_slice(),
489 nonself_args.as_slice())
490 };
491
492 method_def.create_method(cx, self,
493 type_ident, generics,
494 explicit_self, tys,
495 body)
496 }).collect();
497
498 self.create_derived_impl(cx, type_ident, generics, methods)
499 }
500 }
501
502 impl<'a> MethodDef<'a> {
503 fn call_substructure_method(&self,
504 cx: &mut ExtCtxt,
505 trait_: &TraitDef,
506 type_ident: Ident,
507 self_args: &[@Expr],
508 nonself_args: &[@Expr],
509 fields: &SubstructureFields)
510 -> @Expr {
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,
516 fields: fields
517 };
518 let mut f = self.combine_substructure.borrow_mut();
519 let f: &mut CombineSubstructureFunc = &mut *f;
520 (*f)(cx, trait_.span, &substructure)
521 }
522
523 fn get_ret_ty(&self,
524 cx: &mut ExtCtxt,
525 trait_: &TraitDef,
526 generics: &Generics,
527 type_ident: Ident)
528 -> P<ast::Ty> {
529 self.ret_ty.to_ty(cx, trait_.span, type_ident, generics)
530 }
531
532 fn is_static(&self) -> bool {
533 self.explicit_self.is_none()
534 }
535
536 fn split_self_nonself_args(&self,
537 cx: &mut ExtCtxt,
538 trait_: &TraitDef,
539 type_ident: Ident,
540 generics: &Generics)
541 -> (ast::ExplicitSelf, Vec<@Expr> , Vec<@Expr> , Vec<(Ident, P<ast::Ty>)> ) {
542
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;
547
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);
552
553 self_args.push(self_expr);
554 nonstatic = true;
555
556 explicit_self
557 }
558 None => codemap::respan(trait_.span, ast::SelfStatic),
559 };
560
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));
565
566 let arg_expr = cx.expr_ident(trait_.span, ident);
567
568 match *ty {
569 // for static methods, just treat any Self
570 // arguments as a normal arg
571 Self if nonstatic => {
572 self_args.push(arg_expr);
573 }
574 Ptr(box Self, _) if nonstatic => {
575 self_args.push(cx.expr_deref(trait_.span, arg_expr))
576 }
577 _ => {
578 nonself_args.push(arg_expr);
579 }
580 }
581 }
582
583 (ast_explicit_self, self_args, nonself_args, arg_tys)
584 }
585
586 fn create_method(&self,
587 cx: &mut ExtCtxt,
588 trait_: &TraitDef,
589 type_ident: Ident,
590 generics: &Generics,
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);
596
597 let self_arg = match explicit_self.node {
598 ast::SelfStatic => None,
599 _ => Some(ast::Arg::new_self(trait_.span, ast::MutImmutable))
600 };
601 let args = {
602 let args = arg_types.move_iter().map(|(name, ty)| {
603 cx.arg(trait_.span, name, ty)
604 });
605 self_arg.move_iter().chain(args).collect()
606 };
607
608 let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident);
609
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);
613
614 // Create the method.
615 @ast::Method {
616 ident: method_ident,
617 attrs: self.attributes.clone(),
618 generics: fn_generics,
619 explicit_self: explicit_self,
620 fn_style: ast::NormalFn,
621 decl: fn_decl,
622 body: body_block,
623 id: ast::DUMMY_NODE_ID,
624 span: trait_.span,
625 vis: ast::Inherited,
626 }
627 }
628
629 /**
630 ~~~
631 #[deriving(Eq)]
632 struct A { x: int, y: int }
633
634 // equivalent to:
635 impl Eq for A {
636 fn eq(&self, __arg_1: &A) -> bool {
637 match *self {
638 A {x: ref __self_0_0, y: ref __self_0_1} => {
639 match *__arg_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)
642 }
643 }
644 }
645 }
646 }
647 }
648 ~~~
649 */
650 fn expand_struct_method_body(&self,
651 cx: &mut ExtCtxt,
652 trait_: &TraitDef,
653 struct_def: &StructDef,
654 type_ident: Ident,
655 self_args: &[@Expr],
656 nonself_args: &[@Expr])
657 -> @Expr {
658
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),
665 ast::MutImmutable);
666 patterns.push(pat);
667 raw_fields.push(ident_expr);
668 }
669
670 // transpose raw_fields
671 let fields = if raw_fields.len() > 0 {
672 raw_fields.get(0)
673 .iter()
674 .enumerate()
675 .map(|(i, &(span, opt_id, field))| {
676 let other_fields = raw_fields.tail().iter().map(|l| {
677 match l.get(i) {
678 &(_, _, ex) => ex
679 }
680 }).collect();
681 FieldInfo {
682 span: span,
683 name: opt_id,
684 self_: field,
685 other: other_fields
686 }
687 }).collect()
688 } else {
689 cx.span_bug(trait_.span,
690 "no self arguments to non-static method in generic \
691 `deriving`")
692 };
693
694 // body of the inner most destructuring match
695 let mut body = self.call_substructure_method(
696 cx,
697 trait_,
698 type_ident,
699 self_args,
700 nonself_args,
701 &Struct(fields));
702
703 // make a series of nested matches, to destructure the
704 // structs. This is actually right-to-left, but it shoudn't
705 // matter.
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) ))
709 }
710 body
711 }
712
713 fn expand_static_struct_method_body(&self,
714 cx: &mut ExtCtxt,
715 trait_: &TraitDef,
716 struct_def: &StructDef,
717 type_ident: Ident,
718 self_args: &[@Expr],
719 nonself_args: &[@Expr])
720 -> @Expr {
721 let summary = trait_.summarise_struct(cx, struct_def);
722
723 self.call_substructure_method(cx,
724 trait_,
725 type_ident,
726 self_args, nonself_args,
727 &StaticStruct(struct_def, summary))
728 }
729
730 /**
731 ~~~
732 #[deriving(Eq)]
733 enum A {
734 A1
735 A2(int)
736 }
737
738 // is equivalent to (with const_nonmatching == false)
739
740 impl Eq for A {
741 fn eq(&self, __arg_1: &A) {
742 match *self {
743 A1 => match *__arg_1 {
744 A1 => true
745 A2(ref __arg_1_1) => false
746 },
747 A2(self_1) => match *__arg_1 {
748 A1 => false,
749 A2(ref __arg_1_1) => self_1.eq(__arg_1_1)
750 }
751 }
752 }
753 }
754 ~~~
755 */
756 fn expand_enum_method_body(&self,
757 cx: &mut ExtCtxt,
758 trait_: &TraitDef,
759 enum_def: &EnumDef,
760 type_ident: Ident,
761 self_args: &[@Expr],
762 nonself_args: &[@Expr])
763 -> @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)
768 }
769
770
771 /**
772 Creates the nested matches for an enum definition recursively, i.e.
773
774 ~~~notrust
775 match self {
776 Variant1 => match other { Variant1 => matching, Variant2 => nonmatching, ... },
777 Variant2 => match other { Variant1 => nonmatching, Variant2 => matching, ... },
778 ...
779 }
780 ~~~
781
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
786 exponentially large.
787
788 `matching` is Some(n) if all branches in the tree above the
789 current position are variant `n`, `None` otherwise (including on
790 the first call).
791 */
792 fn build_enum_match(&self,
793 cx: &mut ExtCtxt,
794 trait_: &TraitDef,
795 enum_def: &EnumDef,
796 type_ident: Ident,
797 self_args: &[@Expr],
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`");
810 }
811
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)
816 };
817
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
822 // field.
823
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());
831
832 for triple in matches_so_far.tail().iter() {
833 match triple {
834 &(_, _, ref other_fields) => {
835 for (i, &(_, _, e)) in other_fields.iter().enumerate() {
836 enum_matching_fields.get_mut(i).push(e);
837 }
838 }
839 }
840 }
841 let field_tuples =
842 self_vec.iter()
843 .zip(enum_matching_fields.iter())
844 .map(|(&(span, id, self_f), other)| {
845 FieldInfo {
846 span: span,
847 name: id,
848 self_: self_f,
849 other: (*other).clone()
850 }
851 }).collect();
852 EnumMatching(variant_index, variant, field_tuples)
853 }
854 None => {
855 EnumNonMatching(matches_so_far.as_slice())
856 }
857 };
858 self.call_substructure_method(cx, trait_, type_ident,
859 self_args, nonself_args,
860 &substructure)
861
862 } else { // there are still matches to create
863 let current_match_str = if match_count == 0 {
864 "__self".to_owned()
865 } else {
866 format!("__arg_{}", match_count)
867 };
868
869 let mut arms = Vec::new();
870
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 {
876 Some(i) => i,
877 None => cx.span_bug(trait_.span,
878 "non-matching variants when required to \
879 be matching in generic `deriving`")
880 };
881
882 // matching-variant match
883 let variant = *enum_def.variants.get(index);
884 let (pattern, idents) = trait_.create_enum_variant_pattern(cx,
885 variant,
886 current_match_str,
887 ast::MutImmutable);
888
889 matches_so_far.push((index, variant, idents));
890 let arm_expr = self.build_enum_match(cx,
891 trait_,
892 enum_def,
893 type_ident,
894 self_args, nonself_args,
895 matching,
896 matches_so_far,
897 match_count + 1);
898 matches_so_far.pop().unwrap();
899 arms.push(cx.arm(trait_.span, vec!( pattern ), arm_expr));
900
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,
905 e);
906 let wild_arm = cx.arm(
907 trait_.span,
908 vec!( cx.pat_wild(trait_.span) ),
909 wild_expr);
910 arms.push(wild_arm);
911 }
912 } else {
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,
916 variant,
917 current_match_str,
918 ast::MutImmutable);
919
920 matches_so_far.push((index, variant, idents));
921 let new_matching =
922 match matching {
923 _ if match_count == 0 => Some(index),
924 Some(i) if index == i => Some(i),
925 _ => None
926 };
927 let arm_expr = self.build_enum_match(cx,
928 trait_,
929 enum_def,
930 type_ident,
931 self_args, nonself_args,
932 new_matching,
933 matches_so_far,
934 match_count + 1);
935 matches_so_far.pop().unwrap();
936
937 let arm = cx.arm(trait_.span, vec!( pattern ), arm_expr);
938 arms.push(arm);
939 }
940 }
941
942 // match foo { arm, arm, arm, ... }
943 cx.expr_match(trait_.span, self_args[match_count], arms)
944 }
945 }
946
947 fn expand_static_enum_method_body(&self,
948 cx: &mut ExtCtxt,
949 trait_: &TraitDef,
950 enum_def: &EnumDef,
951 type_ident: Ident,
952 self_args: &[@Expr],
953 nonself_args: &[@Expr])
954 -> @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())
960 }
961 ast::StructVariantKind(struct_def) => {
962 trait_.summarise_struct(cx, struct_def)
963 }
964 };
965 (ident, v.span, summary)
966 }).collect();
967 self.call_substructure_method(cx, trait_, type_ident,
968 self_args, nonself_args,
969 &StaticEnum(enum_def, summary))
970 }
971 }
972
973 #[deriving(Eq)] // dogfooding!
974 enum StructType {
975 Unknown, Record, Tuple
976 }
977
978 // general helper methods.
979 impl<'a> TraitDef<'a> {
980 fn set_expn_info(&self,
981 cx: &mut ExtCtxt,
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`"),
985 Some(name) => *name
986 };
987 to_set.expn_info = Some(@codemap::ExpnInfo {
988 call_site: to_set,
989 callee: codemap::NameAndSpan {
990 name: format!("deriving({})", trait_name).to_strbuf(),
991 format: codemap::MacroAttribute,
992 span: Some(self.span)
993 }
994 });
995 to_set
996 }
997
998 fn summarise_struct(&self,
999 cx: &mut ExtCtxt,
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),
1008 }
1009 }
1010
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`"),
1015 // named fields
1016 (_, false) => Named(named_idents),
1017 // tuple structs (includes empty structs)
1018 (_, _) => Unnamed(just_spans)
1019 }
1020 }
1021
1022 fn create_subpatterns(&self,
1023 cx: &mut ExtCtxt,
1024 field_paths: Vec<ast::Path> ,
1025 mutbl: ast::Mutability)
1026 -> Vec<@ast::Pat> {
1027 field_paths.iter().map(|path| {
1028 cx.pat(path.span,
1029 ast::PatIdent(ast::BindByRef(mutbl), (*path).clone(), None))
1030 }).collect()
1031 }
1032
1033 fn create_struct_pattern(&self,
1034 cx: &mut ExtCtxt,
1035 struct_ident: Ident,
1036 struct_def: &StructDef,
1037 prefix: &str,
1038 mutbl: ast::Mutability)
1039 -> (@ast::Pat, Vec<(Span, Option<Ident>, @Expr)> ) {
1040 if struct_def.fields.is_empty() {
1041 return (
1042 cx.pat_ident_binding_mode(
1043 self.span, struct_ident, ast::BindByValue(ast::MutImmutable)),
1044 Vec::new());
1045 }
1046
1047 let matching_path = cx.path(self.span, vec!( struct_ident ));
1048
1049 let mut paths = Vec::new();
1050 let mut ident_expr = Vec::new();
1051 let mut struct_type = Unknown;
1052
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;
1059 Some(ident)
1060 }
1061 ast::UnnamedField(..) if (struct_type == Unknown ||
1062 struct_type == Tuple) => {
1063 struct_type = Tuple;
1064 None
1065 }
1066 _ => {
1067 cx.span_bug(sp, "a struct with named and unnamed fields in `deriving`");
1068 }
1069 };
1070 let path = cx.path_ident(sp, cx.ident_of(format!("{}_{}", prefix, i)));
1071 paths.push(path.clone());
1072 let val = cx.expr(
1073 sp, ast::ExprParen(
1074 cx.expr_deref(sp, cx.expr_path(path))));
1075 ident_expr.push((sp, opt_id, val));
1076 }
1077
1078 let subpats = self.create_subpatterns(cx, paths, mutbl);
1079
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 }
1086 }).collect();
1087 cx.pat_struct(self.span, matching_path, field_pats)
1088 } else {
1089 cx.pat_enum(self.span, matching_path, subpats)
1090 };
1091
1092 (pattern, ident_expr)
1093 }
1094
1095 fn create_enum_variant_pattern(&self,
1096 cx: &mut ExtCtxt,
1097 variant: &ast::Variant,
1098 prefix: &str,
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)),
1107 Vec::new());
1108 }
1109
1110 let matching_path = cx.path_ident(variant.span, variant_ident);
1111
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)));
1117
1118 paths.push(path.clone());
1119 let val = cx.expr(
1120 sp, ast::ExprParen(cx.expr_deref(sp, cx.expr_path(path))));
1121 ident_expr.push((sp, None, val));
1122 }
1123
1124 let subpats = self.create_subpatterns(cx, paths, mutbl);
1125
1126 (cx.pat_enum(variant.span, matching_path, subpats),
1127 ident_expr)
1128 }
1129 ast::StructVariantKind(struct_def) => {
1130 self.create_struct_pattern(cx, variant_ident, struct_def,
1131 prefix, mutbl)
1132 }
1133 }
1134 }
1135 }
1136
1137 /* helpful premade recipes */
1138
1139 /**
1140 Fold the fields. `use_foldl` controls whether this is done
1141 left-to-right (`true`) or right-to-left (`false`).
1142 */
1143 pub fn cs_fold(use_foldl: bool,
1144 f: |&mut ExtCtxt, Span, @Expr, @Expr, &[@Expr]| -> @Expr,
1145 base: @Expr,
1146 enum_nonmatch_f: EnumNonMatchFunc,
1147 cx: &mut ExtCtxt,
1148 trait_span: Span,
1149 substructure: &Substructure)
1150 -> @Expr {
1151 match *substructure.fields {
1152 EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => {
1153 if use_foldl {
1154 all_fields.iter().fold(base, |old, field| {
1155 f(cx,
1156 field.span,
1157 old,
1158 field.self_,
1159 field.other.as_slice())
1160 })
1161 } else {
1162 all_fields.iter().rev().fold(base, |old, field| {
1163 f(cx,
1164 field.span,
1165 old,
1166 field.self_,
1167 field.other.as_slice())
1168 })
1169 }
1170 },
1171 EnumNonMatching(ref all_enums) => enum_nonmatch_f(cx, trait_span,
1172 *all_enums,
1173 substructure.nonself_args),
1174 StaticEnum(..) | StaticStruct(..) => {
1175 cx.span_bug(trait_span, "static function in `deriving`")
1176 }
1177 }
1178 }
1179
1180
1181 /**
1182 Call the method that is being derived on all the fields, and then
1183 process the collected results. i.e.
1184
1185 ~~~
1186 f(cx, span, ~[self_1.method(__arg_1_1, __arg_2_1),
1187 self_2.method(__arg_1_2, __arg_2_2)])
1188 ~~~
1189 */
1190 #[inline]
1191 pub fn cs_same_method(f: |&mut ExtCtxt, Span, Vec<@Expr> | -> @Expr,
1192 enum_nonmatch_f: EnumNonMatchFunc,
1193 cx: &mut ExtCtxt,
1194 trait_span: Span,
1195 substructure: &Substructure)
1196 -> @Expr {
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,
1202 field.self_,
1203 substructure.method_ident,
1204 field.other.iter()
1205 .map(|e| cx.expr_addr_of(field.span, *e))
1206 .collect())
1207 }).collect();
1208
1209 f(cx, trait_span, called)
1210 },
1211 EnumNonMatching(ref all_enums) => enum_nonmatch_f(cx, trait_span,
1212 *all_enums,
1213 substructure.nonself_args),
1214 StaticEnum(..) | StaticStruct(..) => {
1215 cx.span_bug(trait_span, "static function in `deriving`")
1216 }
1217 }
1218 }
1219
1220 /**
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`).
1224 */
1225 #[inline]
1226 pub fn cs_same_method_fold(use_foldl: bool,
1227 f: |&mut ExtCtxt, Span, @Expr, @Expr| -> @Expr,
1228 base: @Expr,
1229 enum_nonmatch_f: EnumNonMatchFunc,
1230 cx: &mut ExtCtxt,
1231 trait_span: Span,
1232 substructure: &Substructure)
1233 -> @Expr {
1234 cs_same_method(
1235 |cx, span, vals| {
1236 if use_foldl {
1237 vals.iter().fold(base, |old, &new| {
1238 f(cx, span, old, new)
1239 })
1240 } else {
1241 vals.iter().rev().fold(base, |old, &new| {
1242 f(cx, span, old, new)
1243 })
1244 }
1245 },
1246 enum_nonmatch_f,
1247 cx, trait_span, substructure)
1248 }
1249
1250 /**
1251 Use a given binop to combine the result of calling the derived method
1252 on all the fields.
1253 */
1254 #[inline]
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,
1263 binop,
1264 old, new)
1265
1266 },
1267 base,
1268 enum_nonmatch_f,
1269 cx, trait_span, substructure)
1270 }
1271
1272 /// cs_binop with binop == or
1273 #[inline]
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),
1278 enum_nonmatch_f,
1279 cx, span, substructure)
1280 }
1281
1282 /// cs_binop with binop == and
1283 #[inline]
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),
1288 enum_nonmatch_f,
1289 cx, span, substructure)
1290 }
libsyntax/ext/deriving/generic.rs:313:3-313:3 -NK_AS_STR_TODO- definition:
*/
pub type EnumNonMatchFunc<'a> =
|&mut ExtCtxt,
references:- 61145: base: @Expr,
1146: enum_nonmatch_f: EnumNonMatchFunc,
1147: cx: &mut ExtCtxt,
--
1191: pub fn cs_same_method(f: |&mut ExtCtxt, Span, Vec<@Expr> | -> @Expr,
1192: enum_nonmatch_f: EnumNonMatchFunc,
1193: cx: &mut ExtCtxt,
--
1284: pub fn cs_and(enum_nonmatch_f: EnumNonMatchFunc,
1285: cx: &mut ExtCtxt, span: Span,
libsyntax/ext/deriving/generic.rs:305:3-305:3 -NK_AS_STR_TODO- definition:
*/
pub type CombineSubstructureFunc<'a> =
|&mut ExtCtxt, Span, &Substructure|: 'a -> @Expr;
references:- 4518: let mut f = self.combine_substructure.borrow_mut();
519: let f: &mut CombineSubstructureFunc = &mut *f;
520: (*f)(cx, trait_.span, &substructure)
libsyntax/ext/deriving/generic.rs:1190:10-1190:10 -fn- definition:
pub fn cs_same_method(f: |&mut ExtCtxt, Span, Vec<@Expr> | -> @Expr,
enum_nonmatch_f: EnumNonMatchFunc,
cx: &mut ExtCtxt,
references:- 2libsyntax/ext/deriving/cmp/totaleq.rs:
23: fn cs_total_eq_assert(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> @Expr {
24: cs_same_method(|cx, span, exprs| {
25: // create `a.<method>(); b.<method>(); c.<method>(); ...`
libsyntax/ext/deriving/generic.rs:
1233: -> @Expr {
1234: cs_same_method(
1235: |cx, span, vals| {
libsyntax/ext/deriving/generic.rs:194:1-194:1 -struct- definition:
pub struct TraitDef<'a> {
/// The span for the current #[deriving(Foo)] header.
pub span: Span,
references:- 25libsyntax/ext/deriving/bounds.rs:
36: let trait_def = TraitDef {
37: span: span,
libsyntax/ext/deriving/clone.rs:
24: let attrs = vec!(cx.attribute(span, inline));
25: let trait_def = TraitDef {
26: span: span,
libsyntax/ext/deriving/encodable.rs:
97: push: |@Item|) {
98: let trait_def = TraitDef {
99: span: span,
libsyntax/ext/deriving/decodable.rs:
29: push: |@Item|) {
30: let trait_def = TraitDef {
31: span: span,
libsyntax/ext/deriving/hash.rs:
39: let attrs = vec!(cx.attribute(span, inline));
40: let hash_trait_def = TraitDef {
41: span: span,
libsyntax/ext/deriving/rand.rs:
22: push: |@Item|) {
23: let trait_def = TraitDef {
24: span: span,
libsyntax/ext/deriving/show.rs:
32: let trait_def = TraitDef {
33: span: span,
libsyntax/ext/deriving/zero.rs:
24: let attrs = vec!(cx.attribute(span, inline));
25: let trait_def = TraitDef {
26: span: span,
libsyntax/ext/deriving/default.rs:
24: let attrs = vec!(cx.attribute(span, inline));
25: let trait_def = TraitDef {
26: span: span,
libsyntax/ext/deriving/primitive.rs:
25: let attrs = vec!(cx.attribute(span, inline));
26: let trait_def = TraitDef {
27: span: span,
libsyntax/ext/deriving/generic.rs:
978: // general helper methods.
979: impl<'a> TraitDef<'a> {
980: fn set_expn_info(&self,
libsyntax/ext/deriving/cmp/totaleq.rs:
41: cx.attribute(span, doc));
42: let trait_def = TraitDef {
43: span: span,
libsyntax/ext/deriving/cmp/ord.rs:
43: let trait_def = TraitDef {
44: span: span,
libsyntax/ext/deriving/cmp/totalord.rs:
27: let attrs = vec!(cx.attribute(span, inline));
28: let trait_def = TraitDef {
29: span: span,
libsyntax/ext/deriving/cmp/eq.rs:
53: let trait_def = TraitDef {
54: span: span,
libsyntax/ext/deriving/generic.rs:320:1-320:1 -fn- definition:
pub fn combine_substructure<'a>(f: CombineSubstructureFunc<'a>)
-> RefCell<CombineSubstructureFunc<'a>> {
RefCell::new(f)
references:- 19libsyntax/ext/deriving/clone.rs:
39: const_nonmatching: false,
40: combine_substructure: combine_substructure(|c, s, sub| {
41: cs_clone("Clone", c, s, sub)
libsyntax/ext/deriving/encodable.rs:
125: const_nonmatching: true,
126: combine_substructure: combine_substructure(|a, b, c| {
127: encodable_substructure(a, b, c)
libsyntax/ext/deriving/decodable.rs:
55: const_nonmatching: true,
56: combine_substructure: combine_substructure(|a, b, c| {
57: decodable_substructure(a, b, c)
libsyntax/ext/deriving/hash.rs:
54: const_nonmatching: false,
55: combine_substructure: combine_substructure(|a, b, c| {
56: hash_substructure(a, b, c)
libsyntax/ext/deriving/rand.rs:
45: const_nonmatching: false,
46: combine_substructure: combine_substructure(|a, b, c| {
47: rand_substructure(a, b, c)
libsyntax/ext/deriving/show.rs:
46: const_nonmatching: false,
47: combine_substructure: combine_substructure(|a, b, c| {
48: show_substructure(a, b, c)
libsyntax/ext/deriving/zero.rs:
39: const_nonmatching: false,
40: combine_substructure: combine_substructure(|a, b, c| {
41: zero_substructure(a, b, c)
--
51: const_nonmatching: false,
52: combine_substructure: combine_substructure(|cx, span, substr| {
53: cs_and(|cx, span, _, _| cx.span_bug(span,
libsyntax/ext/deriving/default.rs:
39: const_nonmatching: false,
40: combine_substructure: combine_substructure(|a, b, c| {
41: default_substructure(a, b, c)
libsyntax/ext/deriving/primitive.rs:
45: const_nonmatching: false,
46: combine_substructure: combine_substructure(|c, s, sub| {
47: cs_from("i64", c, s, sub)
--
62: const_nonmatching: false,
63: combine_substructure: combine_substructure(|c, s, sub| {
64: cs_from("u64", c, s, sub)
libsyntax/ext/deriving/cmp/eq.rs:
45: const_nonmatching: true,
46: combine_substructure: combine_substructure(|a, b, c| {
47: $f(a, b, c)
libsyntax/ext/deriving/cmp/totaleq.rs:
56: const_nonmatching: true,
57: combine_substructure: combine_substructure(|a, b, c| {
58: cs_total_eq_assert(a, b, c)
libsyntax/ext/deriving/cmp/ord.rs:
35: const_nonmatching: false,
36: combine_substructure: combine_substructure(|cx, span, substr| {
37: cs_op($op, $equal, cx, span, substr)
libsyntax/ext/deriving/cmp/totalord.rs:
42: const_nonmatching: false,
43: combine_substructure: combine_substructure(|a, b, c| {
44: cs_cmp(a, b, c)
libsyntax/ext/deriving/generic.rs:277:17-277:17 -enum- definition:
/// and examples
pub enum SubstructureFields<'a> {
Struct(Vec<FieldInfo> ),
references:- 2250: pub nonself_args: &'a [@Expr],
251: pub fields: &'a SubstructureFields<'a>
252: }
--
508: nonself_args: &[@Expr],
509: fields: &SubstructureFields)
510: -> @Expr {
libsyntax/ext/deriving/generic.rs:214:1-214:1 -struct- definition:
pub struct MethodDef<'a> {
/// name of the method
pub name: &'a str,
references:- 21libsyntax/ext/deriving/clone.rs:
31: methods: vec!(
32: MethodDef {
33: name: "clone",
libsyntax/ext/deriving/encodable.rs:
112: methods: vec!(
113: MethodDef {
114: name: "encode",
libsyntax/ext/deriving/decodable.rs:
44: methods: vec!(
45: MethodDef {
46: name: "decode",
libsyntax/ext/deriving/hash.rs:
46: methods: vec!(
47: MethodDef {
48: name: "hash",
libsyntax/ext/deriving/rand.rs:
29: methods: vec!(
30: MethodDef {
31: name: "rand",
libsyntax/ext/deriving/show.rs:
38: methods: vec!(
39: MethodDef {
40: name: "fmt",
libsyntax/ext/deriving/zero.rs:
43: },
44: MethodDef {
45: name: "is_zero",
libsyntax/ext/deriving/default.rs:
31: methods: vec!(
32: MethodDef {
33: name: "default",
libsyntax/ext/deriving/primitive.rs:
49: },
50: MethodDef {
51: name: "from_u64",
libsyntax/ext/deriving/cmp/eq.rs:
37: let attrs = vec!(cx.attribute(span, inline));
38: MethodDef {
39: name: $name,
libsyntax/ext/deriving/cmp/totaleq.rs:
48: methods: vec!(
49: MethodDef {
50: name: "assert_receiver_is_total_eq",
libsyntax/ext/deriving/generic.rs:
211: pub methods: Vec<MethodDef<'a>>,
212: }
--
502: impl<'a> MethodDef<'a> {
503: fn call_substructure_method(&self,
libsyntax/ext/deriving/cmp/ord.rs:
27: let attrs = vec!(cx.attribute(span, inline));
28: MethodDef {
29: name: $name,
libsyntax/ext/deriving/cmp/totalord.rs:
34: methods: vec!(
35: MethodDef {
36: name: "cmp",
libsyntax/ext/deriving/cmp/ord.rs:
27: let attrs = vec!(cx.attribute(span, inline));
28: MethodDef {
29: name: $name,
libsyntax/ext/deriving/generic.rs:973:31-973:31 -enum- definition:
enum StructType {
Unknown, Record, Tuple
}
references:- 3974: enum StructType {
libsyntax/ext/deriving/generic.rs:254:58-254:58 -struct- definition:
/// Summary of the relevant parts of a struct/enum field.
pub struct FieldInfo {
pub span: Span,
references:- 8680: }).collect();
681: FieldInfo {
682: span: span,
--
844: .map(|(&(span, id, self_f), other)| {
845: FieldInfo {
846: span: span,
libsyntax/ext/deriving/clone.rs:
56: let all_fields;
57: let subcall = |field: &FieldInfo|
58: cx.expr_method_call(field.span, field.self_, clone_ident, Vec::new());
libsyntax/ext/deriving/encodable.rs:
147: let last = fields.len() - 1;
148: for (i, &FieldInfo {
149: name,
--
197: let last = fields.len() - 1;
198: for (i, &FieldInfo { self_, span, .. }) in fields.iter().enumerate() {
199: let enc = cx.expr_method_call(span, self_, encode, vec!(blkencoder));
libsyntax/ext/deriving/hash.rs:
94: for &FieldInfo { self_, span, .. } in fields.iter() {
95: stmts.push(call_hash(span, self_));
libsyntax/ext/deriving/generic.rs:1254:10-1254:10 -fn- definition:
pub fn cs_binop(binop: ast::BinOp, base: @Expr,
enum_nonmatch_f: EnumNonMatchFunc,
cx: &mut ExtCtxt, trait_span: Span,
references:- 21276: substructure: &Substructure) -> @Expr {
1277: cs_binop(ast::BiOr, cx.expr_bool(span, false),
1278: enum_nonmatch_f,
--
1286: substructure: &Substructure) -> @Expr {
1287: cs_binop(ast::BiAnd, cx.expr_bool(span, true),
1288: enum_nonmatch_f,
libsyntax/ext/deriving/generic.rs:1283:10-1283:10 -fn- definition:
pub fn cs_and(enum_nonmatch_f: EnumNonMatchFunc,
cx: &mut ExtCtxt, span: Span,
substructure: &Substructure) -> @Expr {
references:- 2libsyntax/ext/deriving/cmp/eq.rs:
25: fn cs_eq(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> @Expr {
26: cs_and(|cx, span, _, _| cx.expr_bool(span, false),
27: cx, span, substr)
libsyntax/ext/deriving/zero.rs:
52: combine_substructure: combine_substructure(|cx, span, substr| {
53: cs_and(|cx, span, _, _| cx.span_bug(span,
54: "Non-matching enum \
libsyntax/ext/deriving/generic.rs:1225:10-1225:10 -fn- definition:
pub fn cs_same_method_fold(use_foldl: bool,
f: |&mut ExtCtxt, Span, @Expr, @Expr| -> @Expr,
base: @Expr,
references:- 21258: substructure: &Substructure) -> @Expr {
1259: cs_same_method_fold(
1260: true, // foldl is good enough
libsyntax/ext/deriving/cmp/totalord.rs:
87: */
88: cs_same_method_fold(
89: // foldr nests the if-elses correctly, leaving the first field
libsyntax/ext/deriving/generic.rs:268:31-268:31 -enum- definition:
/// Fields for a static method
pub enum StaticFields {
/// Tuple structs/enum variants like this
references:- 5999: cx: &mut ExtCtxt,
1000: struct_def: &StructDef) -> StaticFields {
1001: let mut named_idents = Vec::new();
libsyntax/ext/deriving/decodable.rs:
159: outer_pat_ident: Ident,
160: fields: &StaticFields,
161: getarg: |&mut ExtCtxt, Span, InternedString, uint| -> @Expr)
libsyntax/ext/deriving/rand.rs:
133: ctor_ident: Ident,
134: summary: &StaticFields,
135: rand_call: |&mut ExtCtxt, Span| -> @Expr)
libsyntax/ext/deriving/generic.rs:
296: /// A static method where Self is an enum.
297: StaticEnum(&'a ast::EnumDef, Vec<(Ident, Span, StaticFields)> )
298: }
libsyntax/ext/deriving/generic.rs:241:69-241:69 -struct- definition:
/// All the data about the data structure/method being derived upon.
pub struct Substructure<'a> {
/// ident of self
references:- 22510: -> @Expr {
511: let substructure = Substructure {
512: type_ident: type_ident,
--
1148: trait_span: Span,
1149: substructure: &Substructure)
1150: -> @Expr {
--
1194: trait_span: Span,
1195: substructure: &Substructure)
1196: -> @Expr {
--
1275: cx: &mut ExtCtxt, span: Span,
1276: substructure: &Substructure) -> @Expr {
1277: cs_binop(ast::BiOr, cx.expr_bool(span, false),
--
1285: cx: &mut ExtCtxt, span: Span,
1286: substructure: &Substructure) -> @Expr {
1287: cs_binop(ast::BiAnd, cx.expr_bool(span, true),
libsyntax/ext/deriving/clone.rs:
52: cx: &mut ExtCtxt, trait_span: Span,
53: substr: &Substructure) -> @Expr {
54: let clone_ident = substr.method_ident;
libsyntax/ext/deriving/encodable.rs:
135: fn encodable_substructure(cx: &mut ExtCtxt, trait_span: Span,
136: substr: &Substructure) -> @Expr {
137: let encoder = substr.nonself_args[0];
libsyntax/ext/deriving/decodable.rs:
65: fn decodable_substructure(cx: &mut ExtCtxt, trait_span: Span,
66: substr: &Substructure) -> @Expr {
67: let decoder = substr.nonself_args[0];
libsyntax/ext/deriving/hash.rs:
65: fn hash_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> @Expr {
66: let state_expr = match substr.nonself_args {
libsyntax/ext/deriving/rand.rs:
55: fn rand_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> @Expr {
56: let rng = match substr.nonself_args {
libsyntax/ext/deriving/show.rs:
58: fn show_substructure(cx: &mut ExtCtxt, span: Span,
59: substr: &Substructure) -> @Expr {
60: // build `<name>`, `<name>({}, {}, ...)` or `<name> { <field>: {},
libsyntax/ext/deriving/zero.rs:
65: fn zero_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> @Expr {
66: let zero_ident = vec!(
libsyntax/ext/deriving/default.rs:
48: fn default_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> @Expr {
49: let default_ident = vec!(
libsyntax/ext/deriving/primitive.rs:
72: fn cs_from(name: &str, cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> @Expr {
73: let n = match substr.nonself_args {
libsyntax/ext/deriving/cmp/eq.rs:
28: }
29: fn cs_ne(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> @Expr {
30: cs_or(|cx, span, _, _| cx.expr_bool(span, true),
libsyntax/ext/deriving/cmp/totaleq.rs:
22: push: |@Item|) {
23: fn cs_total_eq_assert(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> @Expr {
24: cs_same_method(|cx, span, exprs| {
libsyntax/ext/deriving/cmp/ord.rs:
59: /// Strict inequality.
60: fn cs_op(less: bool, equal: bool, cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> @Expr {
61: let op = if less {ast::BiLt} else {ast::BiGt};
libsyntax/ext/deriving/cmp/totalord.rs:
66: pub fn cs_cmp(cx: &mut ExtCtxt, span: Span,
67: substr: &Substructure) -> @Expr {
68: let test_id = cx.ident_of("__test");
libsyntax/ext/deriving/generic.rs:
306: pub type CombineSubstructureFunc<'a> =
307: |&mut ExtCtxt, Span, &Substructure|: 'a -> @Expr;