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