]> git.proxmox.com Git - rustc.git/blob - src/libsyntax/ext/deriving/generic/mod.rs
1525f1a822bec5436160b91abb9f9f078383b179
[rustc.git] / src / libsyntax / ext / deriving / generic / mod.rs
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 //! Some code that abstracts away much of the boilerplate of writing
12 //! `derive` instances for traits. Among other things it manages getting
13 //! access to the fields of the 4 different sorts of structs and enum
14 //! variants, as well as creating the method and impl ast instances.
15 //!
16 //! Supported features (fairly exhaustive):
17 //!
18 //! - Methods taking any number of parameters of any type, and returning
19 //! any type, other than vectors, bottom and closures.
20 //! - Generating `impl`s for types with type parameters and lifetimes
21 //! (e.g. `Option<T>`), the parameters are automatically given the
22 //! current trait as a bound. (This includes separate type parameters
23 //! and lifetimes for methods.)
24 //! - Additional bounds on the type parameters (`TraitDef.additional_bounds`)
25 //!
26 //! The most important thing for implementers is the `Substructure` and
27 //! `SubstructureFields` objects. The latter groups 5 possibilities of the
28 //! arguments:
29 //!
30 //! - `Struct`, when `Self` is a struct (including tuple structs, e.g
31 //! `struct T(i32, char)`).
32 //! - `EnumMatching`, when `Self` is an enum and all the arguments are the
33 //! same variant of the enum (e.g. `Some(1)`, `Some(3)` and `Some(4)`)
34 //! - `EnumNonMatchingCollapsed` when `Self` is an enum and the arguments
35 //! are not the same variant (e.g. `None`, `Some(1)` and `None`).
36 //! - `StaticEnum` and `StaticStruct` for static methods, where the type
37 //! being derived upon is either an enum or struct respectively. (Any
38 //! argument with type Self is just grouped among the non-self
39 //! arguments.)
40 //!
41 //! In the first two cases, the values from the corresponding fields in
42 //! all the arguments are grouped together. For `EnumNonMatchingCollapsed`
43 //! this isn't possible (different variants have different fields), so the
44 //! fields are inaccessible. (Previous versions of the deriving infrastructure
45 //! had a way to expand into code that could access them, at the cost of
46 //! generating exponential amounts of code; see issue #15375). There are no
47 //! fields with values in the static cases, so these are treated entirely
48 //! differently.
49 //!
50 //! The non-static cases have `Option<ident>` in several places associated
51 //! with field `expr`s. This represents the name of the field it is
52 //! associated with. It is only not `None` when the associated field has
53 //! an identifier in the source code. For example, the `x`s in the
54 //! following snippet
55 //!
56 //! ```rust
57 //! struct A { x : i32 }
58 //!
59 //! struct B(i32);
60 //!
61 //! enum C {
62 //! C0(i32),
63 //! C1 { x: i32 }
64 //! }
65 //! ```
66 //!
67 //! The `i32`s in `B` and `C0` don't have an identifier, so the
68 //! `Option<ident>`s would be `None` for them.
69 //!
70 //! In the static cases, the structure is summarised, either into the just
71 //! spans of the fields or a list of spans and the field idents (for tuple
72 //! structs and record structs, respectively), or a list of these, for
73 //! enums (one for each variant). For empty struct and empty enum
74 //! variants, it is represented as a count of 0.
75 //!
76 //! # "`cs`" functions
77 //!
78 //! The `cs_...` functions ("combine substructure) are designed to
79 //! make life easier by providing some pre-made recipes for common
80 //! threads; mostly calling the function being derived on all the
81 //! arguments and then combining them back together in some way (or
82 //! letting the user chose that). They are not meant to be the only
83 //! way to handle the structures that this code creates.
84 //!
85 //! # Examples
86 //!
87 //! The following simplified `PartialEq` is used for in-code examples:
88 //!
89 //! ```rust
90 //! trait PartialEq {
91 //! fn eq(&self, other: &Self);
92 //! }
93 //! impl PartialEq for i32 {
94 //! fn eq(&self, other: &i32) -> bool {
95 //! *self == *other
96 //! }
97 //! }
98 //! ```
99 //!
100 //! Some examples of the values of `SubstructureFields` follow, using the
101 //! above `PartialEq`, `A`, `B` and `C`.
102 //!
103 //! ## Structs
104 //!
105 //! When generating the `expr` for the `A` impl, the `SubstructureFields` is
106 //!
107 //! ```{.text}
108 //! Struct(vec![FieldInfo {
109 //! span: <span of x>
110 //! name: Some(<ident of x>),
111 //! self_: <expr for &self.x>,
112 //! other: vec![<expr for &other.x]
113 //! }])
114 //! ```
115 //!
116 //! For the `B` impl, called with `B(a)` and `B(b)`,
117 //!
118 //! ```{.text}
119 //! Struct(vec![FieldInfo {
120 //! span: <span of `i32`>,
121 //! name: None,
122 //! self_: <expr for &a>
123 //! other: vec![<expr for &b>]
124 //! }])
125 //! ```
126 //!
127 //! ## Enums
128 //!
129 //! When generating the `expr` for a call with `self == C0(a)` and `other
130 //! == C0(b)`, the SubstructureFields is
131 //!
132 //! ```{.text}
133 //! EnumMatching(0, <ast::Variant for C0>,
134 //! vec![FieldInfo {
135 //! span: <span of i32>
136 //! name: None,
137 //! self_: <expr for &a>,
138 //! other: vec![<expr for &b>]
139 //! }])
140 //! ```
141 //!
142 //! For `C1 {x}` and `C1 {x}`,
143 //!
144 //! ```{.text}
145 //! EnumMatching(1, <ast::Variant for C1>,
146 //! vec![FieldInfo {
147 //! span: <span of x>
148 //! name: Some(<ident of x>),
149 //! self_: <expr for &self.x>,
150 //! other: vec![<expr for &other.x>]
151 //! }])
152 //! ```
153 //!
154 //! For `C0(a)` and `C1 {x}` ,
155 //!
156 //! ```{.text}
157 //! EnumNonMatchingCollapsed(
158 //! vec![<ident of self>, <ident of __arg_1>],
159 //! &[<ast::Variant for C0>, <ast::Variant for C1>],
160 //! &[<ident for self index value>, <ident of __arg_1 index value>])
161 //! ```
162 //!
163 //! It is the same for when the arguments are flipped to `C1 {x}` and
164 //! `C0(a)`; the only difference is what the values of the identifiers
165 //! <ident for self index value> and <ident of __arg_1 index value> will
166 //! be in the generated code.
167 //!
168 //! `EnumNonMatchingCollapsed` deliberately provides far less information
169 //! than is generally available for a given pair of variants; see #15375
170 //! for discussion.
171 //!
172 //! ## Static
173 //!
174 //! A static method on the types above would result in,
175 //!
176 //! ```{.text}
177 //! StaticStruct(<ast::StructDef of A>, Named(vec![(<ident of x>, <span of x>)]))
178 //!
179 //! StaticStruct(<ast::StructDef of B>, Unnamed(vec![<span of x>]))
180 //!
181 //! StaticEnum(<ast::EnumDef of C>,
182 //! vec![(<ident of C0>, <span of C0>, Unnamed(vec![<span of i32>])),
183 //! (<ident of C1>, <span of C1>, Named(vec![(<ident of x>, <span of x>)]))])
184 //! ```
185
186 pub use self::StaticFields::*;
187 pub use self::SubstructureFields::*;
188 use self::StructType::*;
189
190 use std::cell::RefCell;
191 use std::vec;
192
193 use abi::Abi;
194 use abi;
195 use ast;
196 use ast::{EnumDef, Expr, Ident, Generics, StructDef};
197 use ast_util;
198 use attr;
199 use attr::AttrMetaMethods;
200 use ext::base::{ExtCtxt, Annotatable};
201 use ext::build::AstBuilder;
202 use codemap::{self, DUMMY_SP};
203 use codemap::Span;
204 use diagnostic::SpanHandler;
205 use fold::MoveMap;
206 use owned_slice::OwnedSlice;
207 use parse::token::InternedString;
208 use parse::token::special_idents;
209 use ptr::P;
210
211 use self::ty::{LifetimeBounds, Path, Ptr, PtrTy, Self_, Ty};
212
213 pub mod ty;
214
215 pub struct TraitDef<'a> {
216 /// The span for the current #[derive(Foo)] header.
217 pub span: Span,
218
219 pub attributes: Vec<ast::Attribute>,
220
221 /// Path of the trait, including any type parameters
222 pub path: Path<'a>,
223
224 /// Additional bounds required of any type parameters of the type,
225 /// other than the current trait
226 pub additional_bounds: Vec<Ty<'a>>,
227
228 /// Any extra lifetimes and/or bounds, e.g. `D: serialize::Decoder`
229 pub generics: LifetimeBounds<'a>,
230
231 pub methods: Vec<MethodDef<'a>>,
232
233 pub associated_types: Vec<(ast::Ident, Ty<'a>)>,
234 }
235
236
237 pub struct MethodDef<'a> {
238 /// name of the method
239 pub name: &'a str,
240 /// List of generics, e.g. `R: rand::Rng`
241 pub generics: LifetimeBounds<'a>,
242
243 /// Whether there is a self argument (outer Option) i.e. whether
244 /// this is a static function, and whether it is a pointer (inner
245 /// Option)
246 pub explicit_self: Option<Option<PtrTy<'a>>>,
247
248 /// Arguments other than the self argument
249 pub args: Vec<Ty<'a>>,
250
251 /// Return type
252 pub ret_ty: Ty<'a>,
253
254 pub attributes: Vec<ast::Attribute>,
255
256 pub combine_substructure: RefCell<CombineSubstructureFunc<'a>>,
257 }
258
259 /// All the data about the data structure/method being derived upon.
260 pub struct Substructure<'a> {
261 /// ident of self
262 pub type_ident: Ident,
263 /// ident of the method
264 pub method_ident: Ident,
265 /// dereferenced access to any `Self_` or `Ptr(Self_, _)` arguments
266 pub self_args: &'a [P<Expr>],
267 /// verbatim access to any other arguments
268 pub nonself_args: &'a [P<Expr>],
269 pub fields: &'a SubstructureFields<'a>
270 }
271
272 /// Summary of the relevant parts of a struct/enum field.
273 pub struct FieldInfo<'a> {
274 pub span: Span,
275 /// None for tuple structs/normal enum variants, Some for normal
276 /// structs/struct enum variants.
277 pub name: Option<Ident>,
278 /// The expression corresponding to this field of `self`
279 /// (specifically, a reference to it).
280 pub self_: P<Expr>,
281 /// The expressions corresponding to references to this field in
282 /// the other `Self` arguments.
283 pub other: Vec<P<Expr>>,
284 /// The attributes on the field
285 pub attrs: &'a [ast::Attribute],
286 }
287
288 /// Fields for a static method
289 pub enum StaticFields {
290 /// Tuple structs/enum variants like this.
291 Unnamed(Vec<Span>),
292 /// Normal structs/struct variants.
293 Named(Vec<(Ident, Span)>),
294 }
295
296 /// A summary of the possible sets of fields.
297 pub enum SubstructureFields<'a> {
298 Struct(Vec<FieldInfo<'a>>),
299 /// Matching variants of the enum: variant index, ast::Variant,
300 /// fields: the field name is only non-`None` in the case of a struct
301 /// variant.
302 EnumMatching(usize, &'a ast::Variant, Vec<FieldInfo<'a>>),
303
304 /// Non-matching variants of the enum, but with all state hidden from
305 /// the consequent code. The first component holds `Ident`s for all of
306 /// the `Self` arguments; the second component is a slice of all of the
307 /// variants for the enum itself, and the third component is a list of
308 /// `Ident`s bound to the variant index values for each of the actual
309 /// input `Self` arguments.
310 EnumNonMatchingCollapsed(Vec<Ident>, &'a [P<ast::Variant>], &'a [Ident]),
311
312 /// A static method where `Self` is a struct.
313 StaticStruct(&'a ast::StructDef, StaticFields),
314 /// A static method where `Self` is an enum.
315 StaticEnum(&'a ast::EnumDef, Vec<(Ident, Span, StaticFields)>),
316 }
317
318
319
320 /// Combine the values of all the fields together. The last argument is
321 /// all the fields of all the structures.
322 pub type CombineSubstructureFunc<'a> =
323 Box<FnMut(&mut ExtCtxt, Span, &Substructure) -> P<Expr> + 'a>;
324
325 /// Deal with non-matching enum variants. The tuple is a list of
326 /// identifiers (one for each `Self` argument, which could be any of the
327 /// variants since they have been collapsed together) and the identifiers
328 /// holding the variant index value for each of the `Self` arguments. The
329 /// last argument is all the non-`Self` args of the method being derived.
330 pub type EnumNonMatchCollapsedFunc<'a> =
331 Box<FnMut(&mut ExtCtxt, Span, (&[Ident], &[Ident]), &[P<Expr>]) -> P<Expr> + 'a>;
332
333 pub fn combine_substructure<'a>(f: CombineSubstructureFunc<'a>)
334 -> RefCell<CombineSubstructureFunc<'a>> {
335 RefCell::new(f)
336 }
337
338 /// This method helps to extract all the type parameters referenced from a
339 /// type. For a type parameter `<T>`, it looks for either a `TyPath` that
340 /// is not global and starts with `T`, or a `TyQPath`.
341 fn find_type_parameters(ty: &ast::Ty, ty_param_names: &[ast::Name]) -> Vec<P<ast::Ty>> {
342 use visit;
343
344 struct Visitor<'a> {
345 ty_param_names: &'a [ast::Name],
346 types: Vec<P<ast::Ty>>,
347 }
348
349 impl<'a> visit::Visitor<'a> for Visitor<'a> {
350 fn visit_ty(&mut self, ty: &'a ast::Ty) {
351 match ty.node {
352 ast::TyPath(_, ref path) if !path.global => {
353 match path.segments.first() {
354 Some(segment) => {
355 if self.ty_param_names.contains(&segment.identifier.name) {
356 self.types.push(P(ty.clone()));
357 }
358 }
359 None => {}
360 }
361 }
362 _ => {}
363 }
364
365 visit::walk_ty(self, ty)
366 }
367 }
368
369 let mut visitor = Visitor {
370 ty_param_names: ty_param_names,
371 types: Vec::new(),
372 };
373
374 visit::Visitor::visit_ty(&mut visitor, ty);
375
376 visitor.types
377 }
378
379 impl<'a> TraitDef<'a> {
380 pub fn expand(&self,
381 cx: &mut ExtCtxt,
382 mitem: &ast::MetaItem,
383 item: &'a Annotatable,
384 push: &mut FnMut(Annotatable))
385 {
386 match *item {
387 Annotatable::Item(ref item) => {
388 let newitem = match item.node {
389 ast::ItemStruct(ref struct_def, ref generics) => {
390 self.expand_struct_def(cx,
391 &struct_def,
392 item.ident,
393 generics)
394 }
395 ast::ItemEnum(ref enum_def, ref generics) => {
396 self.expand_enum_def(cx,
397 enum_def,
398 &item.attrs,
399 item.ident,
400 generics)
401 }
402 _ => {
403 cx.span_err(mitem.span,
404 "`derive` may only be applied to structs and enums");
405 return;
406 }
407 };
408 // Keep the lint attributes of the previous item to control how the
409 // generated implementations are linted
410 let mut attrs = newitem.attrs.clone();
411 attrs.extend(item.attrs.iter().filter(|a| {
412 match &a.name()[..] {
413 "allow" | "warn" | "deny" | "forbid" => true,
414 _ => false,
415 }
416 }).cloned());
417 push(Annotatable::Item(P(ast::Item {
418 attrs: attrs,
419 ..(*newitem).clone()
420 })))
421 }
422 _ => {
423 cx.span_err(mitem.span, "`derive` may only be applied to structs and enums");
424 }
425 }
426 }
427
428 /// Given that we are deriving a trait `DerivedTrait` for a type like:
429 ///
430 /// ```ignore
431 /// struct Struct<'a, ..., 'z, A, B: DeclaredTrait, C, ..., Z> where C: WhereTrait {
432 /// a: A,
433 /// b: B::Item,
434 /// b1: <B as DeclaredTrait>::Item,
435 /// c1: <C as WhereTrait>::Item,
436 /// c2: Option<<C as WhereTrait>::Item>,
437 /// ...
438 /// }
439 /// ```
440 ///
441 /// create an impl like:
442 ///
443 /// ```ignore
444 /// impl<'a, ..., 'z, A, B: DeclaredTrait, C, ... Z> where
445 /// C: WhereTrait,
446 /// A: DerivedTrait + B1 + ... + BN,
447 /// B: DerivedTrait + B1 + ... + BN,
448 /// C: DerivedTrait + B1 + ... + BN,
449 /// B::Item: DerivedTrait + B1 + ... + BN,
450 /// <C as WhereTrait>::Item: DerivedTrait + B1 + ... + BN,
451 /// ...
452 /// {
453 /// ...
454 /// }
455 /// ```
456 ///
457 /// where B1, ..., BN are the bounds given by `bounds_paths`.'. Z is a phantom type, and
458 /// therefore does not get bound by the derived trait.
459 fn create_derived_impl(&self,
460 cx: &mut ExtCtxt,
461 type_ident: Ident,
462 generics: &Generics,
463 field_tys: Vec<P<ast::Ty>>,
464 methods: Vec<P<ast::ImplItem>>) -> P<ast::Item> {
465 let trait_path = self.path.to_path(cx, self.span, type_ident, generics);
466
467 // Transform associated types from `deriving::ty::Ty` into `ast::ImplItem`
468 let associated_types = self.associated_types.iter().map(|&(ident, ref type_def)| {
469 P(ast::ImplItem {
470 id: ast::DUMMY_NODE_ID,
471 span: self.span,
472 ident: ident,
473 vis: ast::Inherited,
474 attrs: Vec::new(),
475 node: ast::TypeImplItem(type_def.to_ty(cx,
476 self.span,
477 type_ident,
478 generics
479 )),
480 })
481 });
482
483 let Generics { mut lifetimes, ty_params, mut where_clause } =
484 self.generics.to_generics(cx, self.span, type_ident, generics);
485 let mut ty_params = ty_params.into_vec();
486
487 // Copy the lifetimes
488 lifetimes.extend(generics.lifetimes.iter().cloned());
489
490 // Create the type parameters.
491 ty_params.extend(generics.ty_params.iter().map(|ty_param| {
492 // I don't think this can be moved out of the loop, since
493 // a TyParamBound requires an ast id
494 let mut bounds: Vec<_> =
495 // extra restrictions on the generics parameters to the type being derived upon
496 self.additional_bounds.iter().map(|p| {
497 cx.typarambound(p.to_path(cx, self.span,
498 type_ident, generics))
499 }).collect();
500
501 // require the current trait
502 bounds.push(cx.typarambound(trait_path.clone()));
503
504 // also add in any bounds from the declaration
505 for declared_bound in &*ty_param.bounds {
506 bounds.push((*declared_bound).clone());
507 }
508
509 cx.typaram(self.span,
510 ty_param.ident,
511 OwnedSlice::from_vec(bounds),
512 None)
513 }));
514
515 // and similarly for where clauses
516 where_clause.predicates.extend(generics.where_clause.predicates.iter().map(|clause| {
517 match *clause {
518 ast::WherePredicate::BoundPredicate(ref wb) => {
519 ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
520 span: self.span,
521 bound_lifetimes: wb.bound_lifetimes.clone(),
522 bounded_ty: wb.bounded_ty.clone(),
523 bounds: OwnedSlice::from_vec(wb.bounds.iter().cloned().collect())
524 })
525 }
526 ast::WherePredicate::RegionPredicate(ref rb) => {
527 ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
528 span: self.span,
529 lifetime: rb.lifetime,
530 bounds: rb.bounds.iter().cloned().collect()
531 })
532 }
533 ast::WherePredicate::EqPredicate(ref we) => {
534 ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
535 id: ast::DUMMY_NODE_ID,
536 span: self.span,
537 path: we.path.clone(),
538 ty: we.ty.clone()
539 })
540 }
541 }
542 }));
543
544 if !ty_params.is_empty() {
545 let ty_param_names: Vec<ast::Name> = ty_params.iter()
546 .map(|ty_param| ty_param.ident.name)
547 .collect();
548
549 for field_ty in field_tys.into_iter() {
550 let tys = find_type_parameters(&*field_ty, &ty_param_names);
551
552 for ty in tys.into_iter() {
553 let mut bounds: Vec<_> = self.additional_bounds.iter().map(|p| {
554 cx.typarambound(p.to_path(cx, self.span, type_ident, generics))
555 }).collect();
556
557 // require the current trait
558 bounds.push(cx.typarambound(trait_path.clone()));
559
560 let predicate = ast::WhereBoundPredicate {
561 span: self.span,
562 bound_lifetimes: vec![],
563 bounded_ty: ty,
564 bounds: OwnedSlice::from_vec(bounds),
565 };
566
567 let predicate = ast::WherePredicate::BoundPredicate(predicate);
568 where_clause.predicates.push(predicate);
569 }
570 }
571 }
572
573 let trait_generics = Generics {
574 lifetimes: lifetimes,
575 ty_params: OwnedSlice::from_vec(ty_params),
576 where_clause: where_clause
577 };
578
579 // Create the reference to the trait.
580 let trait_ref = cx.trait_ref(trait_path);
581
582 // Create the type parameters on the `self` path.
583 let self_ty_params = generics.ty_params.map(|ty_param| {
584 cx.ty_ident(self.span, ty_param.ident)
585 });
586
587 let self_lifetimes: Vec<ast::Lifetime> =
588 generics.lifetimes
589 .iter()
590 .map(|ld| ld.lifetime)
591 .collect();
592
593 // Create the type of `self`.
594 let self_type = cx.ty_path(
595 cx.path_all(self.span, false, vec!( type_ident ), self_lifetimes,
596 self_ty_params.into_vec(), Vec::new()));
597
598 let attr = cx.attribute(
599 self.span,
600 cx.meta_word(self.span,
601 InternedString::new("automatically_derived")));
602 // Just mark it now since we know that it'll end up used downstream
603 attr::mark_used(&attr);
604 let opt_trait_ref = Some(trait_ref);
605 let ident = ast_util::impl_pretty_name(&opt_trait_ref, Some(&*self_type));
606 let mut a = vec![attr];
607 a.extend(self.attributes.iter().cloned());
608 cx.item(
609 self.span,
610 ident,
611 a,
612 ast::ItemImpl(ast::Unsafety::Normal,
613 ast::ImplPolarity::Positive,
614 trait_generics,
615 opt_trait_ref,
616 self_type,
617 methods.into_iter().chain(associated_types).collect()))
618 }
619
620 fn expand_struct_def(&self,
621 cx: &mut ExtCtxt,
622 struct_def: &'a StructDef,
623 type_ident: Ident,
624 generics: &Generics) -> P<ast::Item> {
625 let field_tys: Vec<P<ast::Ty>> = struct_def.fields.iter()
626 .map(|field| field.node.ty.clone())
627 .collect();
628
629 let methods = self.methods.iter().map(|method_def| {
630 let (explicit_self, self_args, nonself_args, tys) =
631 method_def.split_self_nonself_args(
632 cx, self, type_ident, generics);
633
634 let body = if method_def.is_static() {
635 method_def.expand_static_struct_method_body(
636 cx,
637 self,
638 struct_def,
639 type_ident,
640 &self_args[..],
641 &nonself_args[..])
642 } else {
643 method_def.expand_struct_method_body(cx,
644 self,
645 struct_def,
646 type_ident,
647 &self_args[..],
648 &nonself_args[..])
649 };
650
651 method_def.create_method(cx,
652 self,
653 type_ident,
654 generics,
655 abi::Rust,
656 explicit_self,
657 tys,
658 body)
659 }).collect();
660
661 self.create_derived_impl(cx, type_ident, generics, field_tys, methods)
662 }
663
664 fn expand_enum_def(&self,
665 cx: &mut ExtCtxt,
666 enum_def: &'a EnumDef,
667 type_attrs: &[ast::Attribute],
668 type_ident: Ident,
669 generics: &Generics) -> P<ast::Item> {
670 let mut field_tys = Vec::new();
671
672 for variant in enum_def.variants.iter() {
673 match variant.node.kind {
674 ast::VariantKind::TupleVariantKind(ref args) => {
675 field_tys.extend(args.iter()
676 .map(|arg| arg.ty.clone()));
677 }
678 ast::VariantKind::StructVariantKind(ref args) => {
679 field_tys.extend(args.fields.iter()
680 .map(|field| field.node.ty.clone()));
681 }
682 }
683 }
684
685 let methods = self.methods.iter().map(|method_def| {
686 let (explicit_self, self_args, nonself_args, tys) =
687 method_def.split_self_nonself_args(cx, self,
688 type_ident, generics);
689
690 let body = if method_def.is_static() {
691 method_def.expand_static_enum_method_body(
692 cx,
693 self,
694 enum_def,
695 type_ident,
696 &self_args[..],
697 &nonself_args[..])
698 } else {
699 method_def.expand_enum_method_body(cx,
700 self,
701 enum_def,
702 type_attrs,
703 type_ident,
704 self_args,
705 &nonself_args[..])
706 };
707
708 method_def.create_method(cx,
709 self,
710 type_ident,
711 generics,
712 abi::Rust,
713 explicit_self,
714 tys,
715 body)
716 }).collect();
717
718 self.create_derived_impl(cx, type_ident, generics, field_tys, methods)
719 }
720 }
721
722 fn find_repr_type_name(diagnostic: &SpanHandler,
723 type_attrs: &[ast::Attribute]) -> &'static str {
724 let mut repr_type_name = "i32";
725 for a in type_attrs {
726 for r in &attr::find_repr_attrs(diagnostic, a) {
727 repr_type_name = match *r {
728 attr::ReprAny | attr::ReprPacked => continue,
729 attr::ReprExtern => "i32",
730
731 attr::ReprInt(_, attr::SignedInt(ast::TyIs)) => "isize",
732 attr::ReprInt(_, attr::SignedInt(ast::TyI8)) => "i8",
733 attr::ReprInt(_, attr::SignedInt(ast::TyI16)) => "i16",
734 attr::ReprInt(_, attr::SignedInt(ast::TyI32)) => "i32",
735 attr::ReprInt(_, attr::SignedInt(ast::TyI64)) => "i64",
736
737 attr::ReprInt(_, attr::UnsignedInt(ast::TyUs)) => "usize",
738 attr::ReprInt(_, attr::UnsignedInt(ast::TyU8)) => "u8",
739 attr::ReprInt(_, attr::UnsignedInt(ast::TyU16)) => "u16",
740 attr::ReprInt(_, attr::UnsignedInt(ast::TyU32)) => "u32",
741 attr::ReprInt(_, attr::UnsignedInt(ast::TyU64)) => "u64",
742 }
743 }
744 }
745 repr_type_name
746 }
747
748 impl<'a> MethodDef<'a> {
749 fn call_substructure_method(&self,
750 cx: &mut ExtCtxt,
751 trait_: &TraitDef,
752 type_ident: Ident,
753 self_args: &[P<Expr>],
754 nonself_args: &[P<Expr>],
755 fields: &SubstructureFields)
756 -> P<Expr> {
757 let substructure = Substructure {
758 type_ident: type_ident,
759 method_ident: cx.ident_of(self.name),
760 self_args: self_args,
761 nonself_args: nonself_args,
762 fields: fields
763 };
764 let mut f = self.combine_substructure.borrow_mut();
765 let f: &mut CombineSubstructureFunc = &mut *f;
766 f(cx, trait_.span, &substructure)
767 }
768
769 fn get_ret_ty(&self,
770 cx: &mut ExtCtxt,
771 trait_: &TraitDef,
772 generics: &Generics,
773 type_ident: Ident)
774 -> P<ast::Ty> {
775 self.ret_ty.to_ty(cx, trait_.span, type_ident, generics)
776 }
777
778 fn is_static(&self) -> bool {
779 self.explicit_self.is_none()
780 }
781
782 fn split_self_nonself_args(&self,
783 cx: &mut ExtCtxt,
784 trait_: &TraitDef,
785 type_ident: Ident,
786 generics: &Generics)
787 -> (ast::ExplicitSelf, Vec<P<Expr>>, Vec<P<Expr>>, Vec<(Ident, P<ast::Ty>)>) {
788
789 let mut self_args = Vec::new();
790 let mut nonself_args = Vec::new();
791 let mut arg_tys = Vec::new();
792 let mut nonstatic = false;
793
794 let ast_explicit_self = match self.explicit_self {
795 Some(ref self_ptr) => {
796 let (self_expr, explicit_self) =
797 ty::get_explicit_self(cx, trait_.span, self_ptr);
798
799 self_args.push(self_expr);
800 nonstatic = true;
801
802 explicit_self
803 }
804 None => codemap::respan(trait_.span, ast::SelfStatic),
805 };
806
807 for (i, ty) in self.args.iter().enumerate() {
808 let ast_ty = ty.to_ty(cx, trait_.span, type_ident, generics);
809 let ident = cx.ident_of(&format!("__arg_{}", i));
810 arg_tys.push((ident, ast_ty));
811
812 let arg_expr = cx.expr_ident(trait_.span, ident);
813
814 match *ty {
815 // for static methods, just treat any Self
816 // arguments as a normal arg
817 Self_ if nonstatic => {
818 self_args.push(arg_expr);
819 }
820 Ptr(ref ty, _) if **ty == Self_ && nonstatic => {
821 self_args.push(cx.expr_deref(trait_.span, arg_expr))
822 }
823 _ => {
824 nonself_args.push(arg_expr);
825 }
826 }
827 }
828
829 (ast_explicit_self, self_args, nonself_args, arg_tys)
830 }
831
832 fn create_method(&self,
833 cx: &mut ExtCtxt,
834 trait_: &TraitDef,
835 type_ident: Ident,
836 generics: &Generics,
837 abi: Abi,
838 explicit_self: ast::ExplicitSelf,
839 arg_types: Vec<(Ident, P<ast::Ty>)> ,
840 body: P<Expr>) -> P<ast::ImplItem> {
841 // create the generics that aren't for Self
842 let fn_generics = self.generics.to_generics(cx, trait_.span, type_ident, generics);
843
844 let self_arg = match explicit_self.node {
845 ast::SelfStatic => None,
846 // creating fresh self id
847 _ => Some(ast::Arg::new_self(trait_.span, ast::MutImmutable, special_idents::self_))
848 };
849 let args = {
850 let args = arg_types.into_iter().map(|(name, ty)| {
851 cx.arg(trait_.span, name, ty)
852 });
853 self_arg.into_iter().chain(args).collect()
854 };
855
856 let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident);
857
858 let method_ident = cx.ident_of(self.name);
859 let fn_decl = cx.fn_decl(args, ret_type);
860 let body_block = cx.block_expr(body);
861
862 // Create the method.
863 P(ast::ImplItem {
864 id: ast::DUMMY_NODE_ID,
865 attrs: self.attributes.clone(),
866 span: trait_.span,
867 vis: ast::Inherited,
868 ident: method_ident,
869 node: ast::MethodImplItem(ast::MethodSig {
870 generics: fn_generics,
871 abi: abi,
872 explicit_self: explicit_self,
873 unsafety: ast::Unsafety::Normal,
874 decl: fn_decl
875 }, body_block)
876 })
877 }
878
879 /// ```
880 /// #[derive(PartialEq)]
881 /// struct A { x: i32, y: i32 }
882 ///
883 /// // equivalent to:
884 /// impl PartialEq for A {
885 /// fn eq(&self, __arg_1: &A) -> bool {
886 /// match *self {
887 /// A {x: ref __self_0_0, y: ref __self_0_1} => {
888 /// match *__arg_1 {
889 /// A {x: ref __self_1_0, y: ref __self_1_1} => {
890 /// __self_0_0.eq(__self_1_0) && __self_0_1.eq(__self_1_1)
891 /// }
892 /// }
893 /// }
894 /// }
895 /// }
896 /// }
897 /// ```
898 fn expand_struct_method_body<'b>(&self,
899 cx: &mut ExtCtxt,
900 trait_: &TraitDef<'b>,
901 struct_def: &'b StructDef,
902 type_ident: Ident,
903 self_args: &[P<Expr>],
904 nonself_args: &[P<Expr>])
905 -> P<Expr> {
906
907 let mut raw_fields = Vec::new(); // Vec<[fields of self],
908 // [fields of next Self arg], [etc]>
909 let mut patterns = Vec::new();
910 for i in 0..self_args.len() {
911 let struct_path= cx.path(DUMMY_SP, vec!( type_ident ));
912 let (pat, ident_expr) =
913 trait_.create_struct_pattern(cx,
914 struct_path,
915 struct_def,
916 &format!("__self_{}",
917 i),
918 ast::MutImmutable);
919 patterns.push(pat);
920 raw_fields.push(ident_expr);
921 }
922
923 // transpose raw_fields
924 let fields = if !raw_fields.is_empty() {
925 let mut raw_fields = raw_fields.into_iter().map(|v| v.into_iter());
926 let first_field = raw_fields.next().unwrap();
927 let mut other_fields: Vec<vec::IntoIter<_>>
928 = raw_fields.collect();
929 first_field.map(|(span, opt_id, field, attrs)| {
930 FieldInfo {
931 span: span,
932 name: opt_id,
933 self_: field,
934 other: other_fields.iter_mut().map(|l| {
935 match l.next().unwrap() {
936 (_, _, ex, _) => ex
937 }
938 }).collect(),
939 attrs: attrs,
940 }
941 }).collect()
942 } else {
943 cx.span_bug(trait_.span,
944 "no self arguments to non-static method in generic \
945 `derive`")
946 };
947
948 // body of the inner most destructuring match
949 let mut body = self.call_substructure_method(
950 cx,
951 trait_,
952 type_ident,
953 self_args,
954 nonself_args,
955 &Struct(fields));
956
957 // make a series of nested matches, to destructure the
958 // structs. This is actually right-to-left, but it shouldn't
959 // matter.
960 for (arg_expr, pat) in self_args.iter().zip(patterns.iter()) {
961 body = cx.expr_match(trait_.span, arg_expr.clone(),
962 vec!( cx.arm(trait_.span, vec!(pat.clone()), body) ))
963 }
964 body
965 }
966
967 fn expand_static_struct_method_body(&self,
968 cx: &mut ExtCtxt,
969 trait_: &TraitDef,
970 struct_def: &StructDef,
971 type_ident: Ident,
972 self_args: &[P<Expr>],
973 nonself_args: &[P<Expr>])
974 -> P<Expr> {
975 let summary = trait_.summarise_struct(cx, struct_def);
976
977 self.call_substructure_method(cx,
978 trait_,
979 type_ident,
980 self_args, nonself_args,
981 &StaticStruct(struct_def, summary))
982 }
983
984 /// ```
985 /// #[derive(PartialEq)]
986 /// enum A {
987 /// A1,
988 /// A2(i32)
989 /// }
990 ///
991 /// // is equivalent to
992 ///
993 /// impl PartialEq for A {
994 /// fn eq(&self, __arg_1: &A) -> ::bool {
995 /// match (&*self, &*__arg_1) {
996 /// (&A1, &A1) => true,
997 /// (&A2(ref __self_0),
998 /// &A2(ref __arg_1_0)) => (*__self_0).eq(&(*__arg_1_0)),
999 /// _ => {
1000 /// let __self_vi = match *self { A1(..) => 0, A2(..) => 1 };
1001 /// let __arg_1_vi = match *__arg_1 { A1(..) => 0, A2(..) => 1 };
1002 /// false
1003 /// }
1004 /// }
1005 /// }
1006 /// }
1007 /// ```
1008 ///
1009 /// (Of course `__self_vi` and `__arg_1_vi` are unused for
1010 /// `PartialEq`, and those subcomputations will hopefully be removed
1011 /// as their results are unused. The point of `__self_vi` and
1012 /// `__arg_1_vi` is for `PartialOrd`; see #15503.)
1013 fn expand_enum_method_body<'b>(&self,
1014 cx: &mut ExtCtxt,
1015 trait_: &TraitDef<'b>,
1016 enum_def: &'b EnumDef,
1017 type_attrs: &[ast::Attribute],
1018 type_ident: Ident,
1019 self_args: Vec<P<Expr>>,
1020 nonself_args: &[P<Expr>])
1021 -> P<Expr> {
1022 self.build_enum_match_tuple(
1023 cx, trait_, enum_def, type_attrs, type_ident, self_args, nonself_args)
1024 }
1025
1026
1027 /// Creates a match for a tuple of all `self_args`, where either all
1028 /// variants match, or it falls into a catch-all for when one variant
1029 /// does not match.
1030
1031 /// There are N + 1 cases because is a case for each of the N
1032 /// variants where all of the variants match, and one catch-all for
1033 /// when one does not match.
1034
1035 /// The catch-all handler is provided access the variant index values
1036 /// for each of the self-args, carried in precomputed variables. (Nota
1037 /// bene: the variant index values are not necessarily the
1038 /// discriminant values. See issue #15523.)
1039
1040 /// ```{.text}
1041 /// match (this, that, ...) {
1042 /// (Variant1, Variant1, Variant1) => ... // delegate Matching on Variant1
1043 /// (Variant2, Variant2, Variant2) => ... // delegate Matching on Variant2
1044 /// ...
1045 /// _ => {
1046 /// let __this_vi = match this { Variant1 => 0, Variant2 => 1, ... };
1047 /// let __that_vi = match that { Variant1 => 0, Variant2 => 1, ... };
1048 /// ... // catch-all remainder can inspect above variant index values.
1049 /// }
1050 /// }
1051 /// ```
1052 fn build_enum_match_tuple<'b>(
1053 &self,
1054 cx: &mut ExtCtxt,
1055 trait_: &TraitDef<'b>,
1056 enum_def: &'b EnumDef,
1057 type_attrs: &[ast::Attribute],
1058 type_ident: Ident,
1059 self_args: Vec<P<Expr>>,
1060 nonself_args: &[P<Expr>]) -> P<Expr> {
1061
1062 let sp = trait_.span;
1063 let variants = &enum_def.variants;
1064
1065 let self_arg_names = self_args.iter().enumerate()
1066 .map(|(arg_count, _self_arg)| {
1067 if arg_count == 0 {
1068 "__self".to_string()
1069 } else {
1070 format!("__arg_{}", arg_count)
1071 }
1072 })
1073 .collect::<Vec<String>>();
1074
1075 let self_arg_idents = self_arg_names.iter()
1076 .map(|name|cx.ident_of(&name[..]))
1077 .collect::<Vec<ast::Ident>>();
1078
1079 // The `vi_idents` will be bound, solely in the catch-all, to
1080 // a series of let statements mapping each self_arg to an int
1081 // value corresponding to its discriminant.
1082 let vi_idents: Vec<ast::Ident> = self_arg_names.iter()
1083 .map(|name| { let vi_suffix = format!("{}_vi", &name[..]);
1084 cx.ident_of(&vi_suffix[..]) })
1085 .collect::<Vec<ast::Ident>>();
1086
1087 // Builds, via callback to call_substructure_method, the
1088 // delegated expression that handles the catch-all case,
1089 // using `__variants_tuple` to drive logic if necessary.
1090 let catch_all_substructure = EnumNonMatchingCollapsed(
1091 self_arg_idents, &variants[..], &vi_idents[..]);
1092
1093 // These arms are of the form:
1094 // (Variant1, Variant1, ...) => Body1
1095 // (Variant2, Variant2, ...) => Body2
1096 // ...
1097 // where each tuple has length = self_args.len()
1098 let mut match_arms: Vec<ast::Arm> = variants.iter().enumerate()
1099 .map(|(index, variant)| {
1100 let mk_self_pat = |cx: &mut ExtCtxt, self_arg_name: &str| {
1101 let (p, idents) = trait_.create_enum_variant_pattern(cx, type_ident,
1102 &**variant,
1103 self_arg_name,
1104 ast::MutImmutable);
1105 (cx.pat(sp, ast::PatRegion(p, ast::MutImmutable)), idents)
1106 };
1107
1108 // A single arm has form (&VariantK, &VariantK, ...) => BodyK
1109 // (see "Final wrinkle" note below for why.)
1110 let mut subpats = Vec::with_capacity(self_arg_names.len());
1111 let mut self_pats_idents = Vec::with_capacity(self_arg_names.len() - 1);
1112 let first_self_pat_idents = {
1113 let (p, idents) = mk_self_pat(cx, &self_arg_names[0]);
1114 subpats.push(p);
1115 idents
1116 };
1117 for self_arg_name in &self_arg_names[1..] {
1118 let (p, idents) = mk_self_pat(cx, &self_arg_name[..]);
1119 subpats.push(p);
1120 self_pats_idents.push(idents);
1121 }
1122
1123 // Here is the pat = `(&VariantK, &VariantK, ...)`
1124 let single_pat = cx.pat_tuple(sp, subpats);
1125
1126 // For the BodyK, we need to delegate to our caller,
1127 // passing it an EnumMatching to indicate which case
1128 // we are in.
1129
1130 // All of the Self args have the same variant in these
1131 // cases. So we transpose the info in self_pats_idents
1132 // to gather the getter expressions together, in the
1133 // form that EnumMatching expects.
1134
1135 // The transposition is driven by walking across the
1136 // arg fields of the variant for the first self pat.
1137 let field_tuples = first_self_pat_idents.into_iter().enumerate()
1138 // For each arg field of self, pull out its getter expr ...
1139 .map(|(field_index, (sp, opt_ident, self_getter_expr, attrs))| {
1140 // ... but FieldInfo also wants getter expr
1141 // for matching other arguments of Self type;
1142 // so walk across the *other* self_pats_idents
1143 // and pull out getter for same field in each
1144 // of them (using `field_index` tracked above).
1145 // That is the heart of the transposition.
1146 let others = self_pats_idents.iter().map(|fields| {
1147 let (_, _opt_ident, ref other_getter_expr, _) =
1148 fields[field_index];
1149
1150 // All Self args have same variant, so
1151 // opt_idents are the same. (Assert
1152 // here to make it self-evident that
1153 // it is okay to ignore `_opt_ident`.)
1154 assert!(opt_ident == _opt_ident);
1155
1156 other_getter_expr.clone()
1157 }).collect::<Vec<P<Expr>>>();
1158
1159 FieldInfo { span: sp,
1160 name: opt_ident,
1161 self_: self_getter_expr,
1162 other: others,
1163 attrs: attrs,
1164 }
1165 }).collect::<Vec<FieldInfo>>();
1166
1167 // Now, for some given VariantK, we have built up
1168 // expressions for referencing every field of every
1169 // Self arg, assuming all are instances of VariantK.
1170 // Build up code associated with such a case.
1171 let substructure = EnumMatching(index,
1172 &**variant,
1173 field_tuples);
1174 let arm_expr = self.call_substructure_method(
1175 cx, trait_, type_ident, &self_args[..], nonself_args,
1176 &substructure);
1177
1178 cx.arm(sp, vec![single_pat], arm_expr)
1179 }).collect();
1180
1181 // We will usually need the catch-all after matching the
1182 // tuples `(VariantK, VariantK, ...)` for each VariantK of the
1183 // enum. But:
1184 //
1185 // * when there is only one Self arg, the arms above suffice
1186 // (and the deriving we call back into may not be prepared to
1187 // handle EnumNonMatchCollapsed), and,
1188 //
1189 // * when the enum has only one variant, the single arm that
1190 // is already present always suffices.
1191 //
1192 // * In either of the two cases above, if we *did* add a
1193 // catch-all `_` match, it would trigger the
1194 // unreachable-pattern error.
1195 //
1196 if variants.len() > 1 && self_args.len() > 1 {
1197 // Build a series of let statements mapping each self_arg
1198 // to its discriminant value. If this is a C-style enum
1199 // with a specific repr type, then casts the values to
1200 // that type. Otherwise casts to `i32` (the default repr
1201 // type).
1202 //
1203 // i.e. for `enum E<T> { A, B(1), C(T, T) }`, and a deriving
1204 // with three Self args, builds three statements:
1205 //
1206 // ```
1207 // let __self0_vi = unsafe {
1208 // std::intrinsics::discriminant_value(&self) } as i32;
1209 // let __self1_vi = unsafe {
1210 // std::intrinsics::discriminant_value(&__arg1) } as i32;
1211 // let __self2_vi = unsafe {
1212 // std::intrinsics::discriminant_value(&__arg2) } as i32;
1213 // ```
1214 let mut index_let_stmts: Vec<P<ast::Stmt>> = Vec::new();
1215
1216 let target_type_name =
1217 find_repr_type_name(&cx.parse_sess.span_diagnostic, type_attrs);
1218
1219 for (&ident, self_arg) in vi_idents.iter().zip(self_args.iter()) {
1220 let path = vec![cx.ident_of_std("core"),
1221 cx.ident_of("intrinsics"),
1222 cx.ident_of("discriminant_value")];
1223 let call = cx.expr_call_global(
1224 sp, path, vec![cx.expr_addr_of(sp, self_arg.clone())]);
1225 let variant_value = cx.expr_block(P(ast::Block {
1226 stmts: vec![],
1227 expr: Some(call),
1228 id: ast::DUMMY_NODE_ID,
1229 rules: ast::UnsafeBlock(ast::CompilerGenerated),
1230 span: sp }));
1231
1232 let target_ty = cx.ty_ident(sp, cx.ident_of(target_type_name));
1233 let variant_disr = cx.expr_cast(sp, variant_value, target_ty);
1234 let let_stmt = cx.stmt_let(sp, false, ident, variant_disr);
1235 index_let_stmts.push(let_stmt);
1236 }
1237
1238 let arm_expr = self.call_substructure_method(
1239 cx, trait_, type_ident, &self_args[..], nonself_args,
1240 &catch_all_substructure);
1241
1242 // Builds the expression:
1243 // {
1244 // let __self0_vi = ...;
1245 // let __self1_vi = ...;
1246 // ...
1247 // <delegated expression referring to __self0_vi, et al.>
1248 // }
1249 let arm_expr = cx.expr_block(
1250 cx.block_all(sp, index_let_stmts, Some(arm_expr)));
1251
1252 // Builds arm:
1253 // _ => { let __self0_vi = ...;
1254 // let __self1_vi = ...;
1255 // ...
1256 // <delegated expression as above> }
1257 let catch_all_match_arm =
1258 cx.arm(sp, vec![cx.pat_wild(sp)], arm_expr);
1259
1260 match_arms.push(catch_all_match_arm);
1261
1262 } else if variants.is_empty() {
1263 // As an additional wrinkle, For a zero-variant enum A,
1264 // currently the compiler
1265 // will accept `fn (a: &Self) { match *a { } }`
1266 // but rejects `fn (a: &Self) { match (&*a,) { } }`
1267 // as well as `fn (a: &Self) { match ( *a,) { } }`
1268 //
1269 // This means that the strategy of building up a tuple of
1270 // all Self arguments fails when Self is a zero variant
1271 // enum: rustc rejects the expanded program, even though
1272 // the actual code tends to be impossible to execute (at
1273 // least safely), according to the type system.
1274 //
1275 // The most expedient fix for this is to just let the
1276 // code fall through to the catch-all. But even this is
1277 // error-prone, since the catch-all as defined above would
1278 // generate code like this:
1279 //
1280 // _ => { let __self0 = match *self { };
1281 // let __self1 = match *__arg_0 { };
1282 // <catch-all-expr> }
1283 //
1284 // Which is yields bindings for variables which type
1285 // inference cannot resolve to unique types.
1286 //
1287 // One option to the above might be to add explicit type
1288 // annotations. But the *only* reason to go down that path
1289 // would be to try to make the expanded output consistent
1290 // with the case when the number of enum variants >= 1.
1291 //
1292 // That just isn't worth it. In fact, trying to generate
1293 // sensible code for *any* deriving on a zero-variant enum
1294 // does not make sense. But at the same time, for now, we
1295 // do not want to cause a compile failure just because the
1296 // user happened to attach a deriving to their
1297 // zero-variant enum.
1298 //
1299 // Instead, just generate a failing expression for the
1300 // zero variant case, skipping matches and also skipping
1301 // delegating back to the end user code entirely.
1302 //
1303 // (See also #4499 and #12609; note that some of the
1304 // discussions there influence what choice we make here;
1305 // e.g. if we feature-gate `match x { ... }` when x refers
1306 // to an uninhabited type (e.g. a zero-variant enum or a
1307 // type holding such an enum), but do not feature-gate
1308 // zero-variant enums themselves, then attempting to
1309 // derive Debug on such a type could here generate code
1310 // that needs the feature gate enabled.)
1311
1312 return cx.expr_unreachable(sp);
1313 }
1314
1315 // Final wrinkle: the self_args are expressions that deref
1316 // down to desired l-values, but we cannot actually deref
1317 // them when they are fed as r-values into a tuple
1318 // expression; here add a layer of borrowing, turning
1319 // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
1320 let borrowed_self_args = self_args.move_map(|self_arg| cx.expr_addr_of(sp, self_arg));
1321 let match_arg = cx.expr(sp, ast::ExprTup(borrowed_self_args));
1322 cx.expr_match(sp, match_arg, match_arms)
1323 }
1324
1325 fn expand_static_enum_method_body(&self,
1326 cx: &mut ExtCtxt,
1327 trait_: &TraitDef,
1328 enum_def: &EnumDef,
1329 type_ident: Ident,
1330 self_args: &[P<Expr>],
1331 nonself_args: &[P<Expr>])
1332 -> P<Expr> {
1333 let summary = enum_def.variants.iter().map(|v| {
1334 let ident = v.node.name;
1335 let summary = match v.node.kind {
1336 ast::TupleVariantKind(ref args) => {
1337 Unnamed(args.iter().map(|va| trait_.set_expn_info(cx, va.ty.span)).collect())
1338 }
1339 ast::StructVariantKind(ref struct_def) => {
1340 trait_.summarise_struct(cx, &**struct_def)
1341 }
1342 };
1343 (ident, v.span, summary)
1344 }).collect();
1345 self.call_substructure_method(cx, trait_, type_ident,
1346 self_args, nonself_args,
1347 &StaticEnum(enum_def, summary))
1348 }
1349 }
1350
1351 #[derive(PartialEq)] // dogfooding!
1352 enum StructType {
1353 Unknown, Record, Tuple
1354 }
1355
1356 // general helper methods.
1357 impl<'a> TraitDef<'a> {
1358 fn set_expn_info(&self,
1359 cx: &mut ExtCtxt,
1360 mut to_set: Span) -> Span {
1361 let trait_name = match self.path.path.last() {
1362 None => cx.span_bug(self.span, "trait with empty path in generic `derive`"),
1363 Some(name) => *name
1364 };
1365 to_set.expn_id = cx.codemap().record_expansion(codemap::ExpnInfo {
1366 call_site: to_set,
1367 callee: codemap::NameAndSpan {
1368 name: format!("derive({})", trait_name),
1369 format: codemap::MacroAttribute,
1370 span: Some(self.span),
1371 allow_internal_unstable: false,
1372 }
1373 });
1374 to_set
1375 }
1376
1377 fn summarise_struct(&self,
1378 cx: &mut ExtCtxt,
1379 struct_def: &StructDef) -> StaticFields {
1380 let mut named_idents = Vec::new();
1381 let mut just_spans = Vec::new();
1382 for field in struct_def.fields.iter(){
1383 let sp = self.set_expn_info(cx, field.span);
1384 match field.node.kind {
1385 ast::NamedField(ident, _) => named_idents.push((ident, sp)),
1386 ast::UnnamedField(..) => just_spans.push(sp),
1387 }
1388 }
1389
1390 match (just_spans.is_empty(), named_idents.is_empty()) {
1391 (false, false) => cx.span_bug(self.span,
1392 "a struct with named and unnamed \
1393 fields in generic `derive`"),
1394 // named fields
1395 (_, false) => Named(named_idents),
1396 // tuple structs (includes empty structs)
1397 (_, _) => Unnamed(just_spans)
1398 }
1399 }
1400
1401 fn create_subpatterns(&self,
1402 cx: &mut ExtCtxt,
1403 field_paths: Vec<ast::SpannedIdent> ,
1404 mutbl: ast::Mutability)
1405 -> Vec<P<ast::Pat>> {
1406 field_paths.iter().map(|path| {
1407 cx.pat(path.span,
1408 ast::PatIdent(ast::BindByRef(mutbl), (*path).clone(), None))
1409 }).collect()
1410 }
1411
1412 fn create_struct_pattern(&self,
1413 cx: &mut ExtCtxt,
1414 struct_path: ast::Path,
1415 struct_def: &'a StructDef,
1416 prefix: &str,
1417 mutbl: ast::Mutability)
1418 -> (P<ast::Pat>, Vec<(Span, Option<Ident>,
1419 P<Expr>,
1420 &'a [ast::Attribute])>) {
1421 if struct_def.fields.is_empty() {
1422 return (cx.pat_enum(self.span, struct_path, vec![]), vec![]);
1423 }
1424
1425 let mut paths = Vec::new();
1426 let mut ident_expr = Vec::new();
1427 let mut struct_type = Unknown;
1428
1429 for (i, struct_field) in struct_def.fields.iter().enumerate() {
1430 let sp = self.set_expn_info(cx, struct_field.span);
1431 let opt_id = match struct_field.node.kind {
1432 ast::NamedField(ident, _) if (struct_type == Unknown ||
1433 struct_type == Record) => {
1434 struct_type = Record;
1435 Some(ident)
1436 }
1437 ast::UnnamedField(..) if (struct_type == Unknown ||
1438 struct_type == Tuple) => {
1439 struct_type = Tuple;
1440 None
1441 }
1442 _ => {
1443 cx.span_bug(sp, "a struct with named and unnamed fields in `derive`");
1444 }
1445 };
1446 let ident = cx.ident_of(&format!("{}_{}", prefix, i));
1447 paths.push(codemap::Spanned{span: sp, node: ident});
1448 let val = cx.expr(
1449 sp, ast::ExprParen(cx.expr_deref(sp, cx.expr_path(cx.path_ident(sp,ident)))));
1450 ident_expr.push((sp, opt_id, val, &struct_field.node.attrs[..]));
1451 }
1452
1453 let subpats = self.create_subpatterns(cx, paths, mutbl);
1454
1455 // struct_type is definitely not Unknown, since struct_def.fields
1456 // must be nonempty to reach here
1457 let pattern = if struct_type == Record {
1458 let field_pats = subpats.into_iter().zip(ident_expr.iter())
1459 .map(|(pat, &(_, id, _, _))| {
1460 // id is guaranteed to be Some
1461 codemap::Spanned {
1462 span: pat.span,
1463 node: ast::FieldPat { ident: id.unwrap(), pat: pat, is_shorthand: false },
1464 }
1465 }).collect();
1466 cx.pat_struct(self.span, struct_path, field_pats)
1467 } else {
1468 cx.pat_enum(self.span, struct_path, subpats)
1469 };
1470
1471 (pattern, ident_expr)
1472 }
1473
1474 fn create_enum_variant_pattern(&self,
1475 cx: &mut ExtCtxt,
1476 enum_ident: ast::Ident,
1477 variant: &'a ast::Variant,
1478 prefix: &str,
1479 mutbl: ast::Mutability)
1480 -> (P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>, &'a [ast::Attribute])>) {
1481 let variant_ident = variant.node.name;
1482 let variant_path = cx.path(variant.span, vec![enum_ident, variant_ident]);
1483 match variant.node.kind {
1484 ast::TupleVariantKind(ref variant_args) => {
1485 if variant_args.is_empty() {
1486 return (cx.pat_enum(variant.span, variant_path, vec![]), vec![]);
1487 }
1488
1489 let mut paths = Vec::new();
1490 let mut ident_expr: Vec<(_, _, _, &'a [ast::Attribute])> = Vec::new();
1491 for (i, va) in variant_args.iter().enumerate() {
1492 let sp = self.set_expn_info(cx, va.ty.span);
1493 let ident = cx.ident_of(&format!("{}_{}", prefix, i));
1494 let path1 = codemap::Spanned{span: sp, node: ident};
1495 paths.push(path1);
1496 let expr_path = cx.expr_path(cx.path_ident(sp, ident));
1497 let val = cx.expr(sp, ast::ExprParen(cx.expr_deref(sp, expr_path)));
1498 ident_expr.push((sp, None, val, &[]));
1499 }
1500
1501 let subpats = self.create_subpatterns(cx, paths, mutbl);
1502
1503 (cx.pat_enum(variant.span, variant_path, subpats),
1504 ident_expr)
1505 }
1506 ast::StructVariantKind(ref struct_def) => {
1507 self.create_struct_pattern(cx, variant_path, &**struct_def,
1508 prefix, mutbl)
1509 }
1510 }
1511 }
1512 }
1513
1514 /* helpful premade recipes */
1515
1516 /// Fold the fields. `use_foldl` controls whether this is done
1517 /// left-to-right (`true`) or right-to-left (`false`).
1518 pub fn cs_fold<F>(use_foldl: bool,
1519 mut f: F,
1520 base: P<Expr>,
1521 mut enum_nonmatch_f: EnumNonMatchCollapsedFunc,
1522 cx: &mut ExtCtxt,
1523 trait_span: Span,
1524 substructure: &Substructure)
1525 -> P<Expr> where
1526 F: FnMut(&mut ExtCtxt, Span, P<Expr>, P<Expr>, &[P<Expr>]) -> P<Expr>,
1527 {
1528 match *substructure.fields {
1529 EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => {
1530 if use_foldl {
1531 all_fields.iter().fold(base, |old, field| {
1532 f(cx,
1533 field.span,
1534 old,
1535 field.self_.clone(),
1536 &field.other)
1537 })
1538 } else {
1539 all_fields.iter().rev().fold(base, |old, field| {
1540 f(cx,
1541 field.span,
1542 old,
1543 field.self_.clone(),
1544 &field.other)
1545 })
1546 }
1547 },
1548 EnumNonMatchingCollapsed(ref all_args, _, tuple) =>
1549 enum_nonmatch_f(cx, trait_span, (&all_args[..], tuple),
1550 substructure.nonself_args),
1551 StaticEnum(..) | StaticStruct(..) => {
1552 cx.span_bug(trait_span, "static function in `derive`")
1553 }
1554 }
1555 }
1556
1557
1558 /// Call the method that is being derived on all the fields, and then
1559 /// process the collected results. i.e.
1560 ///
1561 /// ```
1562 /// f(cx, span, vec![self_1.method(__arg_1_1, __arg_2_1),
1563 /// self_2.method(__arg_1_2, __arg_2_2)])
1564 /// ```
1565 #[inline]
1566 pub fn cs_same_method<F>(f: F,
1567 mut enum_nonmatch_f: EnumNonMatchCollapsedFunc,
1568 cx: &mut ExtCtxt,
1569 trait_span: Span,
1570 substructure: &Substructure)
1571 -> P<Expr> where
1572 F: FnOnce(&mut ExtCtxt, Span, Vec<P<Expr>>) -> P<Expr>,
1573 {
1574 match *substructure.fields {
1575 EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => {
1576 // call self_n.method(other_1_n, other_2_n, ...)
1577 let called = all_fields.iter().map(|field| {
1578 cx.expr_method_call(field.span,
1579 field.self_.clone(),
1580 substructure.method_ident,
1581 field.other.iter()
1582 .map(|e| cx.expr_addr_of(field.span, e.clone()))
1583 .collect())
1584 }).collect();
1585
1586 f(cx, trait_span, called)
1587 },
1588 EnumNonMatchingCollapsed(ref all_self_args, _, tuple) =>
1589 enum_nonmatch_f(cx, trait_span, (&all_self_args[..], tuple),
1590 substructure.nonself_args),
1591 StaticEnum(..) | StaticStruct(..) => {
1592 cx.span_bug(trait_span, "static function in `derive`")
1593 }
1594 }
1595 }
1596
1597 /// Fold together the results of calling the derived method on all the
1598 /// fields. `use_foldl` controls whether this is done left-to-right
1599 /// (`true`) or right-to-left (`false`).
1600 #[inline]
1601 pub fn cs_same_method_fold<F>(use_foldl: bool,
1602 mut f: F,
1603 base: P<Expr>,
1604 enum_nonmatch_f: EnumNonMatchCollapsedFunc,
1605 cx: &mut ExtCtxt,
1606 trait_span: Span,
1607 substructure: &Substructure)
1608 -> P<Expr> where
1609 F: FnMut(&mut ExtCtxt, Span, P<Expr>, P<Expr>) -> P<Expr>,
1610 {
1611 cs_same_method(
1612 |cx, span, vals| {
1613 if use_foldl {
1614 vals.into_iter().fold(base.clone(), |old, new| {
1615 f(cx, span, old, new)
1616 })
1617 } else {
1618 vals.into_iter().rev().fold(base.clone(), |old, new| {
1619 f(cx, span, old, new)
1620 })
1621 }
1622 },
1623 enum_nonmatch_f,
1624 cx, trait_span, substructure)
1625 }
1626
1627 /// Use a given binop to combine the result of calling the derived method
1628 /// on all the fields.
1629 #[inline]
1630 pub fn cs_binop(binop: ast::BinOp_, base: P<Expr>,
1631 enum_nonmatch_f: EnumNonMatchCollapsedFunc,
1632 cx: &mut ExtCtxt, trait_span: Span,
1633 substructure: &Substructure) -> P<Expr> {
1634 cs_same_method_fold(
1635 true, // foldl is good enough
1636 |cx, span, old, new| {
1637 cx.expr_binary(span,
1638 binop,
1639 old, new)
1640
1641 },
1642 base,
1643 enum_nonmatch_f,
1644 cx, trait_span, substructure)
1645 }
1646
1647 /// cs_binop with binop == or
1648 #[inline]
1649 pub fn cs_or(enum_nonmatch_f: EnumNonMatchCollapsedFunc,
1650 cx: &mut ExtCtxt, span: Span,
1651 substructure: &Substructure) -> P<Expr> {
1652 cs_binop(ast::BiOr, cx.expr_bool(span, false),
1653 enum_nonmatch_f,
1654 cx, span, substructure)
1655 }
1656
1657 /// cs_binop with binop == and
1658 #[inline]
1659 pub fn cs_and(enum_nonmatch_f: EnumNonMatchCollapsedFunc,
1660 cx: &mut ExtCtxt, span: Span,
1661 substructure: &Substructure) -> P<Expr> {
1662 cs_binop(ast::BiAnd, cx.expr_bool(span, true),
1663 enum_nonmatch_f,
1664 cx, span, substructure)
1665 }