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