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