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