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