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