rustc_builtin_macros/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//! - `EnumDiscr` when `Self` is an enum, for comparing the enum discriminants.
25//! - `StaticEnum` and `StaticStruct` for static methods, where the type
26//!   being derived upon is either an enum or struct respectively. (Any
27//!   argument with type Self is just grouped among the non-self
28//!   arguments.)
29//!
30//! In the first two cases, the values from the corresponding fields in
31//! all the arguments are grouped together.
32//!
33//! The non-static cases have `Option<ident>` in several places associated
34//! with field `expr`s. This represents the name of the field it is
35//! associated with. It is only not `None` when the associated field has
36//! an identifier in the source code. For example, the `x`s in the
37//! following snippet
38//!
39//! ```rust
40//! struct A {
41//!     x: i32,
42//! }
43//!
44//! struct B(i32);
45//!
46//! enum C {
47//!     C0(i32),
48//!     C1 { x: i32 }
49//! }
50//! ```
51//!
52//! The `i32`s in `B` and `C0` don't have an identifier, so the
53//! `Option<ident>`s would be `None` for them.
54//!
55//! In the static cases, the structure is summarized, either into the just
56//! spans of the fields or a list of spans and the field idents (for tuple
57//! structs and record structs, respectively), or a list of these, for
58//! enums (one for each variant). For empty struct and empty enum
59//! variants, it is represented as a count of 0.
60//!
61//! # "`cs`" functions
62//!
63//! The `cs_...` functions ("combine substructure") are designed to
64//! make life easier by providing some pre-made recipes for common
65//! threads; mostly calling the function being derived on all the
66//! arguments and then combining them back together in some way (or
67//! letting the user chose that). They are not meant to be the only
68//! way to handle the structures that this code creates.
69//!
70//! # Examples
71//!
72//! The following simplified `PartialEq` is used for in-code examples:
73//!
74//! ```rust
75//! trait PartialEq {
76//!     fn eq(&self, other: &Self) -> bool;
77//! }
78//!
79//! impl PartialEq for i32 {
80//!     fn eq(&self, other: &i32) -> bool {
81//!         *self == *other
82//!     }
83//! }
84//! ```
85//!
86//! Some examples of the values of `SubstructureFields` follow, using the
87//! above `PartialEq`, `A`, `B` and `C`.
88//!
89//! ## Structs
90//!
91//! When generating the `expr` for the `A` impl, the `SubstructureFields` is
92//!
93//! ```text
94//! Struct(vec![FieldInfo {
95//!     span: <span of x>,
96//!     name: Some(<ident of x>),
97//!     self_: <expr for &self.x>,
98//!     other: vec![<expr for &other.x>],
99//! }])
100//! ```
101//!
102//! For the `B` impl, called with `B(a)` and `B(b)`,
103//!
104//! ```text
105//! Struct(vec![FieldInfo {
106//!     span: <span of i32>,
107//!     name: None,
108//!     self_: <expr for &a>,
109//!     other: vec![<expr for &b>],
110//! }])
111//! ```
112//!
113//! ## Enums
114//!
115//! When generating the `expr` for a call with `self == C0(a)` and `other
116//! == C0(b)`, the SubstructureFields is
117//!
118//! ```text
119//! EnumMatching(
120//!     0,
121//!     <ast::Variant for C0>,
122//!     vec![FieldInfo {
123//!         span: <span of i32>,
124//!         name: None,
125//!         self_: <expr for &a>,
126//!         other: vec![<expr for &b>],
127//!     }],
128//! )
129//! ```
130//!
131//! For `C1 {x}` and `C1 {x}`,
132//!
133//! ```text
134//! EnumMatching(
135//!     1,
136//!     <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//!
146//! For the discriminants,
147//!
148//! ```text
149//! EnumDiscr(
150//!     &[<ident of self discriminant>, <ident of other discriminant>],
151//!     <expr to combine with>,
152//! )
153//! ```
154//!
155//! Note that this setup doesn't allow for the brute-force "match every variant
156//! against every other variant" approach, which is bad because it produces a
157//! quadratic amount of code (see #15375).
158//!
159//! ## Static
160//!
161//! A static method on the types above would result in,
162//!
163//! ```text
164//! StaticStruct(<ast::VariantData of A>, Named(vec![(<ident of x>, <span of x>)]))
165//!
166//! StaticStruct(<ast::VariantData of B>, Unnamed(vec![<span of x>]))
167//!
168//! StaticEnum(
169//!     <ast::EnumDef of C>,
170//!     vec![
171//!         (<ident of C0>, <span of C0>, Unnamed(vec![<span of i32>])),
172//!         (<ident of C1>, <span of C1>, Named(vec![(<ident of x>, <span of x>)])),
173//!     ],
174//! )
175//! ```
176
177use std::cell::RefCell;
178use std::ops::Not;
179use std::{iter, vec};
180
181pub(crate) use StaticFields::*;
182pub(crate) use SubstructureFields::*;
183use rustc_ast::ptr::P;
184use rustc_ast::token::{IdentIsRaw, LitKind, Token, TokenKind};
185use rustc_ast::tokenstream::{DelimSpan, Spacing, TokenTree};
186use rustc_ast::{
187    self as ast, AnonConst, AttrArgs, BindingMode, ByRef, DelimArgs, EnumDef, Expr, GenericArg,
188    GenericParamKind, Generics, Mutability, PatKind, Safety, VariantData,
189};
190use rustc_attr_data_structures::{AttributeKind, ReprPacked};
191use rustc_attr_parsing::AttributeParser;
192use rustc_expand::base::{Annotatable, ExtCtxt};
193use rustc_hir::Attribute;
194use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
195use thin_vec::{ThinVec, thin_vec};
196use ty::{Bounds, Path, Ref, Self_, Ty};
197
198use crate::{deriving, errors};
199
200pub(crate) mod ty;
201
202pub(crate) struct TraitDef<'a> {
203    /// The span for the current #[derive(Foo)] header.
204    pub span: Span,
205
206    /// Path of the trait, including any type parameters
207    pub path: Path,
208
209    /// Whether to skip adding the current trait as a bound to the type parameters of the type.
210    pub skip_path_as_bound: bool,
211
212    /// Whether `Copy` is needed as an additional bound on type parameters in a packed struct.
213    pub needs_copy_as_bound_if_packed: bool,
214
215    /// Additional bounds required of any type parameters of the type,
216    /// other than the current trait
217    pub additional_bounds: Vec<Ty>,
218
219    /// Can this trait be derived for unions?
220    pub supports_unions: bool,
221
222    pub methods: Vec<MethodDef<'a>>,
223
224    pub associated_types: Vec<(Ident, Ty)>,
225
226    pub is_const: bool,
227
228    pub is_staged_api_crate: bool,
229}
230
231pub(crate) struct MethodDef<'a> {
232    /// name of the method
233    pub name: Symbol,
234    /// List of generics, e.g., `R: rand::Rng`
235    pub generics: Bounds,
236
237    /// Is there is a `&self` argument? If not, it is a static function.
238    pub explicit_self: bool,
239
240    /// Arguments other than the self argument.
241    pub nonself_args: Vec<(Ty, Symbol)>,
242
243    /// Returns type
244    pub ret_ty: Ty,
245
246    pub attributes: ast::AttrVec,
247
248    pub fieldless_variants_strategy: FieldlessVariantsStrategy,
249
250    pub combine_substructure: RefCell<CombineSubstructureFunc<'a>>,
251}
252
253/// How to handle fieldless enum variants.
254#[derive(PartialEq)]
255pub(crate) enum FieldlessVariantsStrategy {
256    /// Combine fieldless variants into a single match arm.
257    /// This assumes that relevant information has been handled
258    /// by looking at the enum's discriminant.
259    Unify,
260    /// Don't do anything special about fieldless variants. They are
261    /// handled like any other variant.
262    Default,
263    /// If all variants of the enum are fieldless, expand the special
264    /// `AllFieldLessEnum` substructure, so that the entire enum can be handled
265    /// at once.
266    SpecializeIfAllVariantsFieldless,
267}
268
269/// All the data about the data structure/method being derived upon.
270pub(crate) struct Substructure<'a> {
271    /// ident of self
272    pub type_ident: Ident,
273    /// Verbatim access to any non-selflike arguments, i.e. arguments that
274    /// don't have type `&Self`.
275    pub nonselflike_args: &'a [P<Expr>],
276    pub fields: &'a SubstructureFields<'a>,
277}
278
279/// Summary of the relevant parts of a struct/enum field.
280pub(crate) struct FieldInfo {
281    pub span: Span,
282    /// None for tuple structs/normal enum variants, Some for normal
283    /// structs/struct enum variants.
284    pub name: Option<Ident>,
285    /// The expression corresponding to this field of `self`
286    /// (specifically, a reference to it).
287    pub self_expr: P<Expr>,
288    /// The expressions corresponding to references to this field in
289    /// the other selflike arguments.
290    pub other_selflike_exprs: Vec<P<Expr>>,
291    pub maybe_scalar: bool,
292}
293
294#[derive(Copy, Clone)]
295pub(crate) enum IsTuple {
296    No,
297    Yes,
298}
299
300/// Fields for a static method
301pub(crate) enum StaticFields {
302    /// Tuple and unit structs/enum variants like this.
303    Unnamed(Vec<Span>, IsTuple),
304    /// Normal structs/struct variants.
305    Named(Vec<(Ident, Span, Option<AnonConst>)>),
306}
307
308/// A summary of the possible sets of fields.
309pub(crate) enum SubstructureFields<'a> {
310    /// A non-static method where `Self` is a struct.
311    Struct(&'a ast::VariantData, Vec<FieldInfo>),
312
313    /// A non-static method handling the entire enum at once
314    /// (after it has been determined that none of the enum
315    /// variants has any fields).
316    AllFieldlessEnum(&'a ast::EnumDef),
317
318    /// Matching variants of the enum: variant index, ast::Variant,
319    /// fields: the field name is only non-`None` in the case of a struct
320    /// variant.
321    EnumMatching(&'a ast::Variant, Vec<FieldInfo>),
322
323    /// The discriminant of an enum. The first field is a `FieldInfo` for the discriminants, as
324    /// if they were fields. The second field is the expression to combine the
325    /// discriminant expression with; it will be `None` if no match is necessary.
326    EnumDiscr(FieldInfo, Option<P<Expr>>),
327
328    /// A static method where `Self` is a struct.
329    StaticStruct(&'a ast::VariantData, StaticFields),
330
331    /// A static method where `Self` is an enum.
332    StaticEnum(&'a ast::EnumDef),
333}
334
335/// Combine the values of all the fields together. The last argument is
336/// all the fields of all the structures.
337pub(crate) type CombineSubstructureFunc<'a> =
338    Box<dyn FnMut(&ExtCtxt<'_>, Span, &Substructure<'_>) -> BlockOrExpr + 'a>;
339
340pub(crate) fn combine_substructure(
341    f: CombineSubstructureFunc<'_>,
342) -> RefCell<CombineSubstructureFunc<'_>> {
343    RefCell::new(f)
344}
345
346struct TypeParameter {
347    bound_generic_params: ThinVec<ast::GenericParam>,
348    ty: P<ast::Ty>,
349}
350
351/// The code snippets built up for derived code are sometimes used as blocks
352/// (e.g. in a function body) and sometimes used as expressions (e.g. in a match
353/// arm). This structure avoids committing to either form until necessary,
354/// avoiding the insertion of any unnecessary blocks.
355///
356/// The statements come before the expression.
357pub(crate) struct BlockOrExpr(ThinVec<ast::Stmt>, Option<P<Expr>>);
358
359impl BlockOrExpr {
360    pub(crate) fn new_stmts(stmts: ThinVec<ast::Stmt>) -> BlockOrExpr {
361        BlockOrExpr(stmts, None)
362    }
363
364    pub(crate) fn new_expr(expr: P<Expr>) -> BlockOrExpr {
365        BlockOrExpr(ThinVec::new(), Some(expr))
366    }
367
368    pub(crate) fn new_mixed(stmts: ThinVec<ast::Stmt>, expr: Option<P<Expr>>) -> BlockOrExpr {
369        BlockOrExpr(stmts, expr)
370    }
371
372    // Converts it into a block.
373    fn into_block(mut self, cx: &ExtCtxt<'_>, span: Span) -> P<ast::Block> {
374        if let Some(expr) = self.1 {
375            self.0.push(cx.stmt_expr(expr));
376        }
377        cx.block(span, self.0)
378    }
379
380    // Converts it into an expression.
381    fn into_expr(self, cx: &ExtCtxt<'_>, span: Span) -> P<Expr> {
382        if self.0.is_empty() {
383            match self.1 {
384                None => cx.expr_block(cx.block(span, ThinVec::new())),
385                Some(expr) => expr,
386            }
387        } else if let [stmt] = self.0.as_slice()
388            && let ast::StmtKind::Expr(expr) = &stmt.kind
389            && self.1.is_none()
390        {
391            // There's only a single statement expression. Pull it out.
392            expr.clone()
393        } else {
394            // Multiple statements and/or expressions.
395            cx.expr_block(self.into_block(cx, span))
396        }
397    }
398}
399
400/// This method helps to extract all the type parameters referenced from a
401/// type. For a type parameter `<T>`, it looks for either a `TyPath` that
402/// is not global and starts with `T`, or a `TyQPath`.
403/// Also include bound generic params from the input type.
404fn find_type_parameters(
405    ty: &ast::Ty,
406    ty_param_names: &[Symbol],
407    cx: &ExtCtxt<'_>,
408) -> Vec<TypeParameter> {
409    use rustc_ast::visit;
410
411    struct Visitor<'a, 'b> {
412        cx: &'a ExtCtxt<'b>,
413        ty_param_names: &'a [Symbol],
414        bound_generic_params_stack: ThinVec<ast::GenericParam>,
415        type_params: Vec<TypeParameter>,
416    }
417
418    impl<'a, 'b> visit::Visitor<'a> for Visitor<'a, 'b> {
419        fn visit_ty(&mut self, ty: &'a ast::Ty) {
420            let stack_len = self.bound_generic_params_stack.len();
421            if let ast::TyKind::FnPtr(fn_ptr) = &ty.kind
422                && !fn_ptr.generic_params.is_empty()
423            {
424                // Given a field `x: for<'a> fn(T::SomeType<'a>)`, we wan't to account for `'a` so
425                // that we generate `where for<'a> T::SomeType<'a>: ::core::clone::Clone`. #122622
426                self.bound_generic_params_stack.extend(fn_ptr.generic_params.iter().cloned());
427            }
428
429            if let ast::TyKind::Path(_, path) = &ty.kind
430                && let Some(segment) = path.segments.first()
431                && self.ty_param_names.contains(&segment.ident.name)
432            {
433                self.type_params.push(TypeParameter {
434                    bound_generic_params: self.bound_generic_params_stack.clone(),
435                    ty: P(ty.clone()),
436                });
437            }
438
439            visit::walk_ty(self, ty);
440            self.bound_generic_params_stack.truncate(stack_len);
441        }
442
443        // Place bound generic params on a stack, to extract them when a type is encountered.
444        fn visit_poly_trait_ref(&mut self, trait_ref: &'a ast::PolyTraitRef) {
445            let stack_len = self.bound_generic_params_stack.len();
446            self.bound_generic_params_stack.extend(trait_ref.bound_generic_params.iter().cloned());
447
448            visit::walk_poly_trait_ref(self, trait_ref);
449
450            self.bound_generic_params_stack.truncate(stack_len);
451        }
452
453        fn visit_mac_call(&mut self, mac: &ast::MacCall) {
454            self.cx.dcx().emit_err(errors::DeriveMacroCall { span: mac.span() });
455        }
456    }
457
458    let mut visitor = Visitor {
459        cx,
460        ty_param_names,
461        bound_generic_params_stack: ThinVec::new(),
462        type_params: Vec::new(),
463    };
464    visit::Visitor::visit_ty(&mut visitor, ty);
465
466    visitor.type_params
467}
468
469impl<'a> TraitDef<'a> {
470    pub(crate) fn expand(
471        self,
472        cx: &ExtCtxt<'_>,
473        mitem: &ast::MetaItem,
474        item: &'a Annotatable,
475        push: &mut dyn FnMut(Annotatable),
476    ) {
477        self.expand_ext(cx, mitem, item, push, false);
478    }
479
480    pub(crate) fn expand_ext(
481        self,
482        cx: &ExtCtxt<'_>,
483        mitem: &ast::MetaItem,
484        item: &'a Annotatable,
485        push: &mut dyn FnMut(Annotatable),
486        from_scratch: bool,
487    ) {
488        match item {
489            Annotatable::Item(item) => {
490                let is_packed = matches!(
491                    AttributeParser::parse_limited(cx.sess, &item.attrs, sym::repr, item.span, item.id, None),
492                    Some(Attribute::Parsed(AttributeKind::Repr { reprs, .. })) if reprs.iter().any(|(x, _)| matches!(x, ReprPacked(..)))
493                );
494
495                let newitem = match &item.kind {
496                    ast::ItemKind::Struct(ident, generics, struct_def) => self.expand_struct_def(
497                        cx,
498                        struct_def,
499                        *ident,
500                        generics,
501                        from_scratch,
502                        is_packed,
503                    ),
504                    ast::ItemKind::Enum(ident, generics, enum_def) => {
505                        // We ignore `is_packed` here, because `repr(packed)`
506                        // enums cause an error later on.
507                        //
508                        // This can only cause further compilation errors
509                        // downstream in blatantly illegal code, so it is fine.
510                        self.expand_enum_def(cx, enum_def, *ident, generics, from_scratch)
511                    }
512                    ast::ItemKind::Union(ident, generics, struct_def) => {
513                        if self.supports_unions {
514                            self.expand_struct_def(
515                                cx,
516                                struct_def,
517                                *ident,
518                                generics,
519                                from_scratch,
520                                is_packed,
521                            )
522                        } else {
523                            cx.dcx().emit_err(errors::DeriveUnion { span: mitem.span });
524                            return;
525                        }
526                    }
527                    _ => unreachable!(),
528                };
529                // Keep the lint attributes of the previous item to control how the
530                // generated implementations are linted
531                let mut attrs = newitem.attrs.clone();
532                attrs.extend(
533                    item.attrs
534                        .iter()
535                        .filter(|a| {
536                            a.has_any_name(&[
537                                sym::allow,
538                                sym::warn,
539                                sym::deny,
540                                sym::forbid,
541                                sym::stable,
542                                sym::unstable,
543                            ])
544                        })
545                        .cloned(),
546                );
547                push(Annotatable::Item(P(ast::Item { attrs, ..(*newitem).clone() })))
548            }
549            _ => unreachable!(),
550        }
551    }
552
553    /// Given that we are deriving a trait `DerivedTrait` for a type like:
554    ///
555    /// ```ignore (only-for-syntax-highlight)
556    /// struct Struct<'a, ..., 'z, A, B: DeclaredTrait, C, ..., Z>
557    /// where
558    ///     C: WhereTrait,
559    /// {
560    ///     a: A,
561    ///     b: B::Item,
562    ///     b1: <B as DeclaredTrait>::Item,
563    ///     c1: <C as WhereTrait>::Item,
564    ///     c2: Option<<C as WhereTrait>::Item>,
565    ///     ...
566    /// }
567    /// ```
568    ///
569    /// create an impl like:
570    ///
571    /// ```ignore (only-for-syntax-highlight)
572    /// impl<'a, ..., 'z, A, B: DeclaredTrait, C, ..., Z>
573    /// where
574    ///     C: WhereTrait,
575    ///     A: DerivedTrait + B1 + ... + BN,
576    ///     B: DerivedTrait + B1 + ... + BN,
577    ///     C: DerivedTrait + B1 + ... + BN,
578    ///     B::Item: DerivedTrait + B1 + ... + BN,
579    ///     <C as WhereTrait>::Item: DerivedTrait + B1 + ... + BN,
580    ///     ...
581    /// {
582    ///     ...
583    /// }
584    /// ```
585    ///
586    /// where B1, ..., BN are the bounds given by `bounds_paths`.'. Z is a phantom type, and
587    /// therefore does not get bound by the derived trait.
588    fn create_derived_impl(
589        &self,
590        cx: &ExtCtxt<'_>,
591        type_ident: Ident,
592        generics: &Generics,
593        field_tys: Vec<P<ast::Ty>>,
594        methods: Vec<P<ast::AssocItem>>,
595        is_packed: bool,
596    ) -> P<ast::Item> {
597        let trait_path = self.path.to_path(cx, self.span, type_ident, generics);
598
599        // Transform associated types from `deriving::ty::Ty` into `ast::AssocItem`
600        let associated_types = self.associated_types.iter().map(|&(ident, ref type_def)| {
601            P(ast::AssocItem {
602                id: ast::DUMMY_NODE_ID,
603                span: self.span,
604                vis: ast::Visibility {
605                    span: self.span.shrink_to_lo(),
606                    kind: ast::VisibilityKind::Inherited,
607                    tokens: None,
608                },
609                attrs: ast::AttrVec::new(),
610                kind: ast::AssocItemKind::Type(Box::new(ast::TyAlias {
611                    defaultness: ast::Defaultness::Final,
612                    ident,
613                    generics: Generics::default(),
614                    where_clauses: ast::TyAliasWhereClauses::default(),
615                    bounds: Vec::new(),
616                    ty: Some(type_def.to_ty(cx, self.span, type_ident, generics)),
617                })),
618                tokens: None,
619            })
620        });
621
622        let mut where_clause = ast::WhereClause::default();
623        where_clause.span = generics.where_clause.span;
624        let ctxt = self.span.ctxt();
625        let span = generics.span.with_ctxt(ctxt);
626
627        // Create the generic parameters
628        let params: ThinVec<_> = generics
629            .params
630            .iter()
631            .map(|param| match &param.kind {
632                GenericParamKind::Lifetime { .. } => param.clone(),
633                GenericParamKind::Type { .. } => {
634                    // Extra restrictions on the generics parameters to the
635                    // type being derived upon.
636                    let bounds: Vec<_> = self
637                        .additional_bounds
638                        .iter()
639                        .map(|p| {
640                            cx.trait_bound(
641                                p.to_path(cx, self.span, type_ident, generics),
642                                self.is_const,
643                            )
644                        })
645                        .chain(
646                            // Add a bound for the current trait.
647                            self.skip_path_as_bound
648                                .not()
649                                .then(|| cx.trait_bound(trait_path.clone(), self.is_const)),
650                        )
651                        .chain({
652                            // Add a `Copy` bound if required.
653                            if is_packed && self.needs_copy_as_bound_if_packed {
654                                let p = deriving::path_std!(marker::Copy);
655                                Some(cx.trait_bound(
656                                    p.to_path(cx, self.span, type_ident, generics),
657                                    self.is_const,
658                                ))
659                            } else {
660                                None
661                            }
662                        })
663                        .chain(
664                            // Also add in any bounds from the declaration.
665                            param.bounds.iter().cloned(),
666                        )
667                        .collect();
668
669                    cx.typaram(param.ident.span.with_ctxt(ctxt), param.ident, bounds, None)
670                }
671                GenericParamKind::Const { ty, span, .. } => {
672                    let const_nodefault_kind = GenericParamKind::Const {
673                        ty: ty.clone(),
674                        span: span.with_ctxt(ctxt),
675
676                        // We can't have default values inside impl block
677                        default: None,
678                    };
679                    let mut param_clone = param.clone();
680                    param_clone.kind = const_nodefault_kind;
681                    param_clone
682                }
683            })
684            .map(|mut param| {
685                // Remove all attributes, because there might be helper attributes
686                // from other macros that will not be valid in the expanded implementation.
687                param.attrs.clear();
688                param
689            })
690            .collect();
691
692        // and similarly for where clauses
693        where_clause.predicates.extend(generics.where_clause.predicates.iter().map(|clause| {
694            ast::WherePredicate {
695                attrs: clause.attrs.clone(),
696                kind: clause.kind.clone(),
697                id: ast::DUMMY_NODE_ID,
698                span: clause.span.with_ctxt(ctxt),
699                is_placeholder: false,
700            }
701        }));
702
703        let ty_param_names: Vec<Symbol> = params
704            .iter()
705            .filter(|param| matches!(param.kind, ast::GenericParamKind::Type { .. }))
706            .map(|ty_param| ty_param.ident.name)
707            .collect();
708
709        if !ty_param_names.is_empty() {
710            for field_ty in field_tys {
711                let field_ty_params = find_type_parameters(&field_ty, &ty_param_names, cx);
712
713                for field_ty_param in field_ty_params {
714                    // if we have already handled this type, skip it
715                    if let ast::TyKind::Path(_, p) = &field_ty_param.ty.kind
716                        && let [sole_segment] = &*p.segments
717                        && ty_param_names.contains(&sole_segment.ident.name)
718                    {
719                        continue;
720                    }
721                    let mut bounds: Vec<_> = self
722                        .additional_bounds
723                        .iter()
724                        .map(|p| {
725                            cx.trait_bound(
726                                p.to_path(cx, self.span, type_ident, generics),
727                                self.is_const,
728                            )
729                        })
730                        .collect();
731
732                    // Require the current trait.
733                    if !self.skip_path_as_bound {
734                        bounds.push(cx.trait_bound(trait_path.clone(), self.is_const));
735                    }
736
737                    // Add a `Copy` bound if required.
738                    if is_packed && self.needs_copy_as_bound_if_packed {
739                        let p = deriving::path_std!(marker::Copy);
740                        bounds.push(cx.trait_bound(
741                            p.to_path(cx, self.span, type_ident, generics),
742                            self.is_const,
743                        ));
744                    }
745
746                    if !bounds.is_empty() {
747                        let predicate = ast::WhereBoundPredicate {
748                            bound_generic_params: field_ty_param.bound_generic_params,
749                            bounded_ty: field_ty_param.ty,
750                            bounds,
751                        };
752
753                        let kind = ast::WherePredicateKind::BoundPredicate(predicate);
754                        let predicate = ast::WherePredicate {
755                            attrs: ThinVec::new(),
756                            kind,
757                            id: ast::DUMMY_NODE_ID,
758                            span: self.span,
759                            is_placeholder: false,
760                        };
761                        where_clause.predicates.push(predicate);
762                    }
763                }
764            }
765        }
766
767        let trait_generics = Generics { params, where_clause, span };
768
769        // Create the reference to the trait.
770        let trait_ref = cx.trait_ref(trait_path);
771
772        let self_params: Vec<_> = generics
773            .params
774            .iter()
775            .map(|param| match param.kind {
776                GenericParamKind::Lifetime { .. } => {
777                    GenericArg::Lifetime(cx.lifetime(param.ident.span.with_ctxt(ctxt), param.ident))
778                }
779                GenericParamKind::Type { .. } => {
780                    GenericArg::Type(cx.ty_ident(param.ident.span.with_ctxt(ctxt), param.ident))
781                }
782                GenericParamKind::Const { .. } => {
783                    GenericArg::Const(cx.const_ident(param.ident.span.with_ctxt(ctxt), param.ident))
784                }
785            })
786            .collect();
787
788        // Create the type of `self`.
789        let path = cx.path_all(self.span, false, vec![type_ident], self_params);
790        let self_type = cx.ty_path(path);
791        let rustc_const_unstable =
792            cx.path_ident(self.span, Ident::new(sym::rustc_const_unstable, self.span));
793
794        let mut attrs = thin_vec![cx.attr_word(sym::automatically_derived, self.span),];
795
796        // Only add `rustc_const_unstable` attributes if `derive_const` is used within libcore/libstd,
797        // Other crates don't need stability attributes, so adding them is not useful, but libcore needs them
798        // on all const trait impls.
799        if self.is_const && self.is_staged_api_crate {
800            attrs.push(
801                cx.attr_nested(
802                    rustc_ast::AttrItem {
803                        unsafety: Safety::Default,
804                        path: rustc_const_unstable,
805                        args: AttrArgs::Delimited(DelimArgs {
806                            dspan: DelimSpan::from_single(self.span),
807                            delim: rustc_ast::token::Delimiter::Parenthesis,
808                            tokens: [
809                                TokenKind::Ident(sym::feature, IdentIsRaw::No),
810                                TokenKind::Eq,
811                                TokenKind::lit(LitKind::Str, sym::derive_const, None),
812                                TokenKind::Comma,
813                                TokenKind::Ident(sym::issue, IdentIsRaw::No),
814                                TokenKind::Eq,
815                                TokenKind::lit(LitKind::Str, sym::derive_const_issue, None),
816                            ]
817                            .into_iter()
818                            .map(|kind| {
819                                TokenTree::Token(Token { kind, span: self.span }, Spacing::Alone)
820                            })
821                            .collect(),
822                        }),
823                        tokens: None,
824                    },
825                    self.span,
826                ),
827            )
828        }
829
830        let opt_trait_ref = Some(trait_ref);
831
832        cx.item(
833            self.span,
834            attrs,
835            ast::ItemKind::Impl(Box::new(ast::Impl {
836                safety: ast::Safety::Default,
837                polarity: ast::ImplPolarity::Positive,
838                defaultness: ast::Defaultness::Final,
839                constness: if self.is_const { ast::Const::Yes(DUMMY_SP) } else { ast::Const::No },
840                generics: trait_generics,
841                of_trait: opt_trait_ref,
842                self_ty: self_type,
843                items: methods.into_iter().chain(associated_types).collect(),
844            })),
845        )
846    }
847
848    fn expand_struct_def(
849        &self,
850        cx: &ExtCtxt<'_>,
851        struct_def: &'a VariantData,
852        type_ident: Ident,
853        generics: &Generics,
854        from_scratch: bool,
855        is_packed: bool,
856    ) -> P<ast::Item> {
857        let field_tys: Vec<P<ast::Ty>> =
858            struct_def.fields().iter().map(|field| field.ty.clone()).collect();
859
860        let methods = self
861            .methods
862            .iter()
863            .map(|method_def| {
864                let (explicit_self, selflike_args, nonselflike_args, nonself_arg_tys) =
865                    method_def.extract_arg_details(cx, self, type_ident, generics);
866
867                let body = if from_scratch || method_def.is_static() {
868                    method_def.expand_static_struct_method_body(
869                        cx,
870                        self,
871                        struct_def,
872                        type_ident,
873                        &nonselflike_args,
874                    )
875                } else {
876                    method_def.expand_struct_method_body(
877                        cx,
878                        self,
879                        struct_def,
880                        type_ident,
881                        &selflike_args,
882                        &nonselflike_args,
883                        is_packed,
884                    )
885                };
886
887                method_def.create_method(
888                    cx,
889                    self,
890                    type_ident,
891                    generics,
892                    explicit_self,
893                    nonself_arg_tys,
894                    body,
895                )
896            })
897            .collect();
898
899        self.create_derived_impl(cx, type_ident, generics, field_tys, methods, is_packed)
900    }
901
902    fn expand_enum_def(
903        &self,
904        cx: &ExtCtxt<'_>,
905        enum_def: &'a EnumDef,
906        type_ident: Ident,
907        generics: &Generics,
908        from_scratch: bool,
909    ) -> P<ast::Item> {
910        let mut field_tys = Vec::new();
911
912        for variant in &enum_def.variants {
913            field_tys.extend(variant.data.fields().iter().map(|field| field.ty.clone()));
914        }
915
916        let methods = self
917            .methods
918            .iter()
919            .map(|method_def| {
920                let (explicit_self, selflike_args, nonselflike_args, nonself_arg_tys) =
921                    method_def.extract_arg_details(cx, self, type_ident, generics);
922
923                let body = if from_scratch || method_def.is_static() {
924                    method_def.expand_static_enum_method_body(
925                        cx,
926                        self,
927                        enum_def,
928                        type_ident,
929                        &nonselflike_args,
930                    )
931                } else {
932                    method_def.expand_enum_method_body(
933                        cx,
934                        self,
935                        enum_def,
936                        type_ident,
937                        selflike_args,
938                        &nonselflike_args,
939                    )
940                };
941
942                method_def.create_method(
943                    cx,
944                    self,
945                    type_ident,
946                    generics,
947                    explicit_self,
948                    nonself_arg_tys,
949                    body,
950                )
951            })
952            .collect();
953
954        let is_packed = false; // enums are never packed
955        self.create_derived_impl(cx, type_ident, generics, field_tys, methods, is_packed)
956    }
957}
958
959impl<'a> MethodDef<'a> {
960    fn call_substructure_method(
961        &self,
962        cx: &ExtCtxt<'_>,
963        trait_: &TraitDef<'_>,
964        type_ident: Ident,
965        nonselflike_args: &[P<Expr>],
966        fields: &SubstructureFields<'_>,
967    ) -> BlockOrExpr {
968        let span = trait_.span;
969        let substructure = Substructure { type_ident, nonselflike_args, fields };
970        let mut f = self.combine_substructure.borrow_mut();
971        let f: &mut CombineSubstructureFunc<'_> = &mut *f;
972        f(cx, span, &substructure)
973    }
974
975    fn get_ret_ty(
976        &self,
977        cx: &ExtCtxt<'_>,
978        trait_: &TraitDef<'_>,
979        generics: &Generics,
980        type_ident: Ident,
981    ) -> P<ast::Ty> {
982        self.ret_ty.to_ty(cx, trait_.span, type_ident, generics)
983    }
984
985    fn is_static(&self) -> bool {
986        !self.explicit_self
987    }
988
989    // The return value includes:
990    // - explicit_self: The `&self` arg, if present.
991    // - selflike_args: Expressions for `&self` (if present) and also any other
992    //   args with the same type (e.g. the `other` arg in `PartialEq::eq`).
993    // - nonselflike_args: Expressions for all the remaining args.
994    // - nonself_arg_tys: Additional information about all the args other than
995    //   `&self`.
996    fn extract_arg_details(
997        &self,
998        cx: &ExtCtxt<'_>,
999        trait_: &TraitDef<'_>,
1000        type_ident: Ident,
1001        generics: &Generics,
1002    ) -> (Option<ast::ExplicitSelf>, ThinVec<P<Expr>>, Vec<P<Expr>>, Vec<(Ident, P<ast::Ty>)>) {
1003        let mut selflike_args = ThinVec::new();
1004        let mut nonselflike_args = Vec::new();
1005        let mut nonself_arg_tys = Vec::new();
1006        let span = trait_.span;
1007
1008        let explicit_self = self.explicit_self.then(|| {
1009            let (self_expr, explicit_self) = ty::get_explicit_self(cx, span);
1010            selflike_args.push(self_expr);
1011            explicit_self
1012        });
1013
1014        for (ty, name) in self.nonself_args.iter() {
1015            let ast_ty = ty.to_ty(cx, span, type_ident, generics);
1016            let ident = Ident::new(*name, span);
1017            nonself_arg_tys.push((ident, ast_ty));
1018
1019            let arg_expr = cx.expr_ident(span, ident);
1020
1021            match ty {
1022                // Selflike (`&Self`) arguments only occur in non-static methods.
1023                Ref(box Self_, _) if !self.is_static() => selflike_args.push(arg_expr),
1024                Self_ => cx.dcx().span_bug(span, "`Self` in non-return position"),
1025                _ => nonselflike_args.push(arg_expr),
1026            }
1027        }
1028
1029        (explicit_self, selflike_args, nonselflike_args, nonself_arg_tys)
1030    }
1031
1032    fn create_method(
1033        &self,
1034        cx: &ExtCtxt<'_>,
1035        trait_: &TraitDef<'_>,
1036        type_ident: Ident,
1037        generics: &Generics,
1038        explicit_self: Option<ast::ExplicitSelf>,
1039        nonself_arg_tys: Vec<(Ident, P<ast::Ty>)>,
1040        body: BlockOrExpr,
1041    ) -> P<ast::AssocItem> {
1042        let span = trait_.span;
1043        // Create the generics that aren't for `Self`.
1044        let fn_generics = self.generics.to_generics(cx, span, type_ident, generics);
1045
1046        let args = {
1047            let self_arg = explicit_self.map(|explicit_self| {
1048                let ident = Ident::with_dummy_span(kw::SelfLower).with_span_pos(span);
1049                ast::Param::from_self(ast::AttrVec::default(), explicit_self, ident)
1050            });
1051            let nonself_args =
1052                nonself_arg_tys.into_iter().map(|(name, ty)| cx.param(span, name, ty));
1053            self_arg.into_iter().chain(nonself_args).collect()
1054        };
1055
1056        let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident);
1057
1058        let method_ident = Ident::new(self.name, span);
1059        let fn_decl = cx.fn_decl(args, ast::FnRetTy::Ty(ret_type));
1060        let body_block = body.into_block(cx, span);
1061
1062        let trait_lo_sp = span.shrink_to_lo();
1063
1064        let sig = ast::FnSig { header: ast::FnHeader::default(), decl: fn_decl, span };
1065        let defaultness = ast::Defaultness::Final;
1066
1067        // Create the method.
1068        P(ast::AssocItem {
1069            id: ast::DUMMY_NODE_ID,
1070            attrs: self.attributes.clone(),
1071            span,
1072            vis: ast::Visibility {
1073                span: trait_lo_sp,
1074                kind: ast::VisibilityKind::Inherited,
1075                tokens: None,
1076            },
1077            kind: ast::AssocItemKind::Fn(Box::new(ast::Fn {
1078                defaultness,
1079                sig,
1080                ident: method_ident,
1081                generics: fn_generics,
1082                contract: None,
1083                body: Some(body_block),
1084                define_opaque: None,
1085            })),
1086            tokens: None,
1087        })
1088    }
1089
1090    /// The normal case uses field access.
1091    ///
1092    /// ```
1093    /// #[derive(PartialEq)]
1094    /// # struct Dummy;
1095    /// struct A { x: u8, y: u8 }
1096    ///
1097    /// // equivalent to:
1098    /// impl PartialEq for A {
1099    ///     fn eq(&self, other: &A) -> bool {
1100    ///         self.x == other.x && self.y == other.y
1101    ///     }
1102    /// }
1103    /// ```
1104    ///
1105    /// But if the struct is `repr(packed)`, we can't use something like
1106    /// `&self.x` because that might cause an unaligned ref. So for any trait
1107    /// method that takes a reference, we use a local block to force a copy.
1108    /// This requires that the field impl `Copy`.
1109    ///
1110    /// ```rust,ignore (example)
1111    /// # struct A { x: u8, y: u8 }
1112    /// impl PartialEq for A {
1113    ///     fn eq(&self, other: &A) -> bool {
1114    ///         // Desugars to `{ self.x }.eq(&{ other.y }) && ...`
1115    ///         { self.x } == { other.y } && { self.y } == { other.y }
1116    ///     }
1117    /// }
1118    /// impl Hash for A {
1119    ///     fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
1120    ///         ::core::hash::Hash::hash(&{ self.x }, state);
1121    ///         ::core::hash::Hash::hash(&{ self.y }, state);
1122    ///     }
1123    /// }
1124    /// ```
1125    fn expand_struct_method_body<'b>(
1126        &self,
1127        cx: &ExtCtxt<'_>,
1128        trait_: &TraitDef<'b>,
1129        struct_def: &'b VariantData,
1130        type_ident: Ident,
1131        selflike_args: &[P<Expr>],
1132        nonselflike_args: &[P<Expr>],
1133        is_packed: bool,
1134    ) -> BlockOrExpr {
1135        assert!(selflike_args.len() == 1 || selflike_args.len() == 2);
1136
1137        let selflike_fields =
1138            trait_.create_struct_field_access_fields(cx, selflike_args, struct_def, is_packed);
1139        self.call_substructure_method(
1140            cx,
1141            trait_,
1142            type_ident,
1143            nonselflike_args,
1144            &Struct(struct_def, selflike_fields),
1145        )
1146    }
1147
1148    fn expand_static_struct_method_body(
1149        &self,
1150        cx: &ExtCtxt<'_>,
1151        trait_: &TraitDef<'_>,
1152        struct_def: &VariantData,
1153        type_ident: Ident,
1154        nonselflike_args: &[P<Expr>],
1155    ) -> BlockOrExpr {
1156        let summary = trait_.summarise_struct(cx, struct_def);
1157
1158        self.call_substructure_method(
1159            cx,
1160            trait_,
1161            type_ident,
1162            nonselflike_args,
1163            &StaticStruct(struct_def, summary),
1164        )
1165    }
1166
1167    /// ```
1168    /// #[derive(PartialEq)]
1169    /// # struct Dummy;
1170    /// enum A {
1171    ///     A1,
1172    ///     A2(i32)
1173    /// }
1174    /// ```
1175    ///
1176    /// is equivalent to:
1177    ///
1178    /// ```
1179    /// #![feature(core_intrinsics)]
1180    /// enum A {
1181    ///     A1,
1182    ///     A2(i32)
1183    /// }
1184    /// impl ::core::cmp::PartialEq for A {
1185    ///     #[inline]
1186    ///     fn eq(&self, other: &A) -> bool {
1187    ///         let __self_discr = ::core::intrinsics::discriminant_value(self);
1188    ///         let __arg1_discr = ::core::intrinsics::discriminant_value(other);
1189    ///         __self_discr == __arg1_discr
1190    ///             && match (self, other) {
1191    ///                 (A::A2(__self_0), A::A2(__arg1_0)) => *__self_0 == *__arg1_0,
1192    ///                 _ => true,
1193    ///             }
1194    ///     }
1195    /// }
1196    /// ```
1197    ///
1198    /// Creates a discriminant check combined with a match for a tuple of all
1199    /// `selflike_args`, with an arm for each variant with fields, possibly an
1200    /// arm for each fieldless variant (if `unify_fieldless_variants` is not
1201    /// `Unify`), and possibly a default arm.
1202    fn expand_enum_method_body<'b>(
1203        &self,
1204        cx: &ExtCtxt<'_>,
1205        trait_: &TraitDef<'b>,
1206        enum_def: &'b EnumDef,
1207        type_ident: Ident,
1208        mut selflike_args: ThinVec<P<Expr>>,
1209        nonselflike_args: &[P<Expr>],
1210    ) -> BlockOrExpr {
1211        assert!(
1212            !selflike_args.is_empty(),
1213            "static methods must use `expand_static_enum_method_body`",
1214        );
1215
1216        let span = trait_.span;
1217        let variants = &enum_def.variants;
1218
1219        // Traits that unify fieldless variants always use the discriminant(s).
1220        let unify_fieldless_variants =
1221            self.fieldless_variants_strategy == FieldlessVariantsStrategy::Unify;
1222
1223        // For zero-variant enum, this function body is unreachable. Generate
1224        // `match *self {}`. This produces machine code identical to `unsafe {
1225        // core::intrinsics::unreachable() }` while being safe and stable.
1226        if variants.is_empty() {
1227            selflike_args.truncate(1);
1228            let match_arg = cx.expr_deref(span, selflike_args.pop().unwrap());
1229            let match_arms = ThinVec::new();
1230            let expr = cx.expr_match(span, match_arg, match_arms);
1231            return BlockOrExpr(ThinVec::new(), Some(expr));
1232        }
1233
1234        let prefixes = iter::once("__self".to_string())
1235            .chain(
1236                selflike_args
1237                    .iter()
1238                    .enumerate()
1239                    .skip(1)
1240                    .map(|(arg_count, _selflike_arg)| format!("__arg{arg_count}")),
1241            )
1242            .collect::<Vec<String>>();
1243
1244        // Build a series of let statements mapping each selflike_arg
1245        // to its discriminant value.
1246        //
1247        // e.g. for `PartialEq::eq` builds two statements:
1248        // ```
1249        // let __self_discr = ::core::intrinsics::discriminant_value(self);
1250        // let __arg1_discr = ::core::intrinsics::discriminant_value(other);
1251        // ```
1252        let get_discr_pieces = |cx: &ExtCtxt<'_>| {
1253            let discr_idents: Vec<_> = prefixes
1254                .iter()
1255                .map(|name| Ident::from_str_and_span(&format!("{name}_discr"), span))
1256                .collect();
1257
1258            let mut discr_exprs: Vec<_> = discr_idents
1259                .iter()
1260                .map(|&ident| cx.expr_addr_of(span, cx.expr_ident(span, ident)))
1261                .collect();
1262
1263            let self_expr = discr_exprs.remove(0);
1264            let other_selflike_exprs = discr_exprs;
1265            let discr_field =
1266                FieldInfo { span, name: None, self_expr, other_selflike_exprs, maybe_scalar: true };
1267
1268            let discr_let_stmts: ThinVec<_> = iter::zip(&discr_idents, &selflike_args)
1269                .map(|(&ident, selflike_arg)| {
1270                    let variant_value = deriving::call_intrinsic(
1271                        cx,
1272                        span,
1273                        sym::discriminant_value,
1274                        thin_vec![selflike_arg.clone()],
1275                    );
1276                    cx.stmt_let(span, false, ident, variant_value)
1277                })
1278                .collect();
1279
1280            (discr_field, discr_let_stmts)
1281        };
1282
1283        // There are some special cases involving fieldless enums where no
1284        // match is necessary.
1285        let all_fieldless = variants.iter().all(|v| v.data.fields().is_empty());
1286        if all_fieldless {
1287            if variants.len() > 1 {
1288                match self.fieldless_variants_strategy {
1289                    FieldlessVariantsStrategy::Unify => {
1290                        // If the type is fieldless and the trait uses the discriminant and
1291                        // there are multiple variants, we need just an operation on
1292                        // the discriminant(s).
1293                        let (discr_field, mut discr_let_stmts) = get_discr_pieces(cx);
1294                        let mut discr_check = self.call_substructure_method(
1295                            cx,
1296                            trait_,
1297                            type_ident,
1298                            nonselflike_args,
1299                            &EnumDiscr(discr_field, None),
1300                        );
1301                        discr_let_stmts.append(&mut discr_check.0);
1302                        return BlockOrExpr(discr_let_stmts, discr_check.1);
1303                    }
1304                    FieldlessVariantsStrategy::SpecializeIfAllVariantsFieldless => {
1305                        return self.call_substructure_method(
1306                            cx,
1307                            trait_,
1308                            type_ident,
1309                            nonselflike_args,
1310                            &AllFieldlessEnum(enum_def),
1311                        );
1312                    }
1313                    FieldlessVariantsStrategy::Default => (),
1314                }
1315            } else if let [variant] = variants.as_slice() {
1316                // If there is a single variant, we don't need an operation on
1317                // the discriminant(s). Just use the most degenerate result.
1318                return self.call_substructure_method(
1319                    cx,
1320                    trait_,
1321                    type_ident,
1322                    nonselflike_args,
1323                    &EnumMatching(variant, Vec::new()),
1324                );
1325            }
1326        }
1327
1328        // These arms are of the form:
1329        // (Variant1, Variant1, ...) => Body1
1330        // (Variant2, Variant2, ...) => Body2
1331        // ...
1332        // where each tuple has length = selflike_args.len()
1333        let mut match_arms: ThinVec<ast::Arm> = variants
1334            .iter()
1335            .filter(|&v| !(unify_fieldless_variants && v.data.fields().is_empty()))
1336            .map(|variant| {
1337                // A single arm has form (&VariantK, &VariantK, ...) => BodyK
1338                // (see "Final wrinkle" note below for why.)
1339
1340                let fields = trait_.create_struct_pattern_fields(cx, &variant.data, &prefixes);
1341
1342                let sp = variant.span.with_ctxt(trait_.span.ctxt());
1343                let variant_path = cx.path(sp, vec![type_ident, variant.ident]);
1344                let by_ref = ByRef::No; // because enums can't be repr(packed)
1345                let mut subpats = trait_.create_struct_patterns(
1346                    cx,
1347                    variant_path,
1348                    &variant.data,
1349                    &prefixes,
1350                    by_ref,
1351                );
1352
1353                // `(VariantK, VariantK, ...)` or just `VariantK`.
1354                let single_pat = if subpats.len() == 1 {
1355                    subpats.pop().unwrap()
1356                } else {
1357                    cx.pat_tuple(span, subpats)
1358                };
1359
1360                // For the BodyK, we need to delegate to our caller,
1361                // passing it an EnumMatching to indicate which case
1362                // we are in.
1363                //
1364                // Now, for some given VariantK, we have built up
1365                // expressions for referencing every field of every
1366                // Self arg, assuming all are instances of VariantK.
1367                // Build up code associated with such a case.
1368                let substructure = EnumMatching(variant, fields);
1369                let arm_expr = self
1370                    .call_substructure_method(
1371                        cx,
1372                        trait_,
1373                        type_ident,
1374                        nonselflike_args,
1375                        &substructure,
1376                    )
1377                    .into_expr(cx, span);
1378
1379                cx.arm(span, single_pat, arm_expr)
1380            })
1381            .collect();
1382
1383        // Add a default arm to the match, if necessary.
1384        let first_fieldless = variants.iter().find(|v| v.data.fields().is_empty());
1385        let default = match first_fieldless {
1386            Some(v) if unify_fieldless_variants => {
1387                // We need a default case that handles all the fieldless
1388                // variants. The index and actual variant aren't meaningful in
1389                // this case, so just use dummy values.
1390                Some(
1391                    self.call_substructure_method(
1392                        cx,
1393                        trait_,
1394                        type_ident,
1395                        nonselflike_args,
1396                        &EnumMatching(v, Vec::new()),
1397                    )
1398                    .into_expr(cx, span),
1399                )
1400            }
1401            _ if variants.len() > 1 && selflike_args.len() > 1 => {
1402                // Because we know that all the arguments will match if we reach
1403                // the match expression we add the unreachable intrinsics as the
1404                // result of the default which should help llvm in optimizing it.
1405                Some(deriving::call_unreachable(cx, span))
1406            }
1407            _ => None,
1408        };
1409        if let Some(arm) = default {
1410            match_arms.push(cx.arm(span, cx.pat_wild(span), arm));
1411        }
1412
1413        // Create a match expression with one arm per discriminant plus
1414        // possibly a default arm, e.g.:
1415        //      match (self, other) {
1416        //          (Variant1, Variant1, ...) => Body1
1417        //          (Variant2, Variant2, ...) => Body2,
1418        //          ...
1419        //          _ => ::core::intrinsics::unreachable(),
1420        //      }
1421        let get_match_expr = |mut selflike_args: ThinVec<P<Expr>>| {
1422            let match_arg = if selflike_args.len() == 1 {
1423                selflike_args.pop().unwrap()
1424            } else {
1425                cx.expr(span, ast::ExprKind::Tup(selflike_args))
1426            };
1427            cx.expr_match(span, match_arg, match_arms)
1428        };
1429
1430        // If the trait uses the discriminant and there are multiple variants, we need
1431        // to add a discriminant check operation before the match. Otherwise, the match
1432        // is enough.
1433        if unify_fieldless_variants && variants.len() > 1 {
1434            let (discr_field, mut discr_let_stmts) = get_discr_pieces(cx);
1435
1436            // Combine a discriminant check with the match.
1437            let mut discr_check_plus_match = self.call_substructure_method(
1438                cx,
1439                trait_,
1440                type_ident,
1441                nonselflike_args,
1442                &EnumDiscr(discr_field, Some(get_match_expr(selflike_args))),
1443            );
1444            discr_let_stmts.append(&mut discr_check_plus_match.0);
1445            BlockOrExpr(discr_let_stmts, discr_check_plus_match.1)
1446        } else {
1447            BlockOrExpr(ThinVec::new(), Some(get_match_expr(selflike_args)))
1448        }
1449    }
1450
1451    fn expand_static_enum_method_body(
1452        &self,
1453        cx: &ExtCtxt<'_>,
1454        trait_: &TraitDef<'_>,
1455        enum_def: &EnumDef,
1456        type_ident: Ident,
1457        nonselflike_args: &[P<Expr>],
1458    ) -> BlockOrExpr {
1459        self.call_substructure_method(
1460            cx,
1461            trait_,
1462            type_ident,
1463            nonselflike_args,
1464            &StaticEnum(enum_def),
1465        )
1466    }
1467}
1468
1469// general helper methods.
1470impl<'a> TraitDef<'a> {
1471    fn summarise_struct(&self, cx: &ExtCtxt<'_>, struct_def: &VariantData) -> StaticFields {
1472        let mut named_idents = Vec::new();
1473        let mut just_spans = Vec::new();
1474        for field in struct_def.fields() {
1475            let sp = field.span.with_ctxt(self.span.ctxt());
1476            match field.ident {
1477                Some(ident) => named_idents.push((ident, sp, field.default.clone())),
1478                _ => just_spans.push(sp),
1479            }
1480        }
1481
1482        let is_tuple = match struct_def {
1483            ast::VariantData::Tuple(..) => IsTuple::Yes,
1484            _ => IsTuple::No,
1485        };
1486        match (just_spans.is_empty(), named_idents.is_empty()) {
1487            (false, false) => cx
1488                .dcx()
1489                .span_bug(self.span, "a struct with named and unnamed fields in generic `derive`"),
1490            // named fields
1491            (_, false) => Named(named_idents),
1492            // unnamed fields
1493            (false, _) => Unnamed(just_spans, is_tuple),
1494            // empty
1495            _ => Named(Vec::new()),
1496        }
1497    }
1498
1499    fn create_struct_patterns(
1500        &self,
1501        cx: &ExtCtxt<'_>,
1502        struct_path: ast::Path,
1503        struct_def: &'a VariantData,
1504        prefixes: &[String],
1505        by_ref: ByRef,
1506    ) -> ThinVec<P<ast::Pat>> {
1507        prefixes
1508            .iter()
1509            .map(|prefix| {
1510                let pieces_iter =
1511                    struct_def.fields().iter().enumerate().map(|(i, struct_field)| {
1512                        let sp = struct_field.span.with_ctxt(self.span.ctxt());
1513                        let ident = self.mk_pattern_ident(prefix, i);
1514                        let path = ident.with_span_pos(sp);
1515                        (
1516                            sp,
1517                            struct_field.ident,
1518                            cx.pat(
1519                                path.span,
1520                                PatKind::Ident(BindingMode(by_ref, Mutability::Not), path, None),
1521                            ),
1522                        )
1523                    });
1524
1525                let struct_path = struct_path.clone();
1526                match *struct_def {
1527                    VariantData::Struct { .. } => {
1528                        let field_pats = pieces_iter
1529                            .map(|(sp, ident, pat)| {
1530                                if ident.is_none() {
1531                                    cx.dcx().span_bug(
1532                                        sp,
1533                                        "a braced struct with unnamed fields in `derive`",
1534                                    );
1535                                }
1536                                ast::PatField {
1537                                    ident: ident.unwrap(),
1538                                    is_shorthand: false,
1539                                    attrs: ast::AttrVec::new(),
1540                                    id: ast::DUMMY_NODE_ID,
1541                                    span: pat.span.with_ctxt(self.span.ctxt()),
1542                                    pat,
1543                                    is_placeholder: false,
1544                                }
1545                            })
1546                            .collect();
1547                        cx.pat_struct(self.span, struct_path, field_pats)
1548                    }
1549                    VariantData::Tuple(..) => {
1550                        let subpats = pieces_iter.map(|(_, _, subpat)| subpat).collect();
1551                        cx.pat_tuple_struct(self.span, struct_path, subpats)
1552                    }
1553                    VariantData::Unit(..) => cx.pat_path(self.span, struct_path),
1554                }
1555            })
1556            .collect()
1557    }
1558
1559    fn create_fields<F>(&self, struct_def: &'a VariantData, mk_exprs: F) -> Vec<FieldInfo>
1560    where
1561        F: Fn(usize, &ast::FieldDef, Span) -> Vec<P<ast::Expr>>,
1562    {
1563        struct_def
1564            .fields()
1565            .iter()
1566            .enumerate()
1567            .map(|(i, struct_field)| {
1568                // For this field, get an expr for each selflike_arg. E.g. for
1569                // `PartialEq::eq`, one for each of `&self` and `other`.
1570                let sp = struct_field.span.with_ctxt(self.span.ctxt());
1571                let mut exprs: Vec<_> = mk_exprs(i, struct_field, sp);
1572                let self_expr = exprs.remove(0);
1573                let other_selflike_exprs = exprs;
1574                FieldInfo {
1575                    span: sp.with_ctxt(self.span.ctxt()),
1576                    name: struct_field.ident,
1577                    self_expr,
1578                    other_selflike_exprs,
1579                    maybe_scalar: struct_field.ty.peel_refs().kind.maybe_scalar(),
1580                }
1581            })
1582            .collect()
1583    }
1584
1585    fn mk_pattern_ident(&self, prefix: &str, i: usize) -> Ident {
1586        Ident::from_str_and_span(&format!("{prefix}_{i}"), self.span)
1587    }
1588
1589    fn create_struct_pattern_fields(
1590        &self,
1591        cx: &ExtCtxt<'_>,
1592        struct_def: &'a VariantData,
1593        prefixes: &[String],
1594    ) -> Vec<FieldInfo> {
1595        self.create_fields(struct_def, |i, _struct_field, sp| {
1596            prefixes
1597                .iter()
1598                .map(|prefix| {
1599                    let ident = self.mk_pattern_ident(prefix, i);
1600                    cx.expr_path(cx.path_ident(sp, ident))
1601                })
1602                .collect()
1603        })
1604    }
1605
1606    fn create_struct_field_access_fields(
1607        &self,
1608        cx: &ExtCtxt<'_>,
1609        selflike_args: &[P<Expr>],
1610        struct_def: &'a VariantData,
1611        is_packed: bool,
1612    ) -> Vec<FieldInfo> {
1613        self.create_fields(struct_def, |i, struct_field, sp| {
1614            selflike_args
1615                .iter()
1616                .map(|selflike_arg| {
1617                    // Note: we must use `struct_field.span` rather than `sp` in the
1618                    // `unwrap_or_else` case otherwise the hygiene is wrong and we get
1619                    // "field `0` of struct `Point` is private" errors on tuple
1620                    // structs.
1621                    let mut field_expr = cx.expr(
1622                        sp,
1623                        ast::ExprKind::Field(
1624                            selflike_arg.clone(),
1625                            struct_field.ident.unwrap_or_else(|| {
1626                                Ident::from_str_and_span(&i.to_string(), struct_field.span)
1627                            }),
1628                        ),
1629                    );
1630                    if is_packed {
1631                        // Fields in packed structs are wrapped in a block, e.g. `&{self.0}`,
1632                        // causing a copy instead of a (potentially misaligned) reference.
1633                        field_expr = cx.expr_block(
1634                            cx.block(struct_field.span, thin_vec![cx.stmt_expr(field_expr)]),
1635                        );
1636                    }
1637                    cx.expr_addr_of(sp, field_expr)
1638                })
1639                .collect()
1640        })
1641    }
1642}
1643
1644/// The function passed to `cs_fold` is called repeatedly with a value of this
1645/// type. It describes one part of the code generation. The result is always an
1646/// expression.
1647pub(crate) enum CsFold<'a> {
1648    /// The basic case: a field expression for one or more selflike args. E.g.
1649    /// for `PartialEq::eq` this is something like `self.x == other.x`.
1650    Single(&'a FieldInfo),
1651
1652    /// The combination of two field expressions. E.g. for `PartialEq::eq` this
1653    /// is something like `<field1 equality> && <field2 equality>`.
1654    Combine(Span, P<Expr>, P<Expr>),
1655
1656    // The fallback case for a struct or enum variant with no fields.
1657    Fieldless,
1658}
1659
1660/// Folds over fields, combining the expressions for each field in a sequence.
1661/// Statics may not be folded over.
1662pub(crate) fn cs_fold<F>(
1663    use_foldl: bool,
1664    cx: &ExtCtxt<'_>,
1665    trait_span: Span,
1666    substructure: &Substructure<'_>,
1667    mut f: F,
1668) -> P<Expr>
1669where
1670    F: FnMut(&ExtCtxt<'_>, CsFold<'_>) -> P<Expr>,
1671{
1672    match substructure.fields {
1673        EnumMatching(.., all_fields) | Struct(_, all_fields) => {
1674            if all_fields.is_empty() {
1675                return f(cx, CsFold::Fieldless);
1676            }
1677
1678            let (base_field, rest) = if use_foldl {
1679                all_fields.split_first().unwrap()
1680            } else {
1681                all_fields.split_last().unwrap()
1682            };
1683
1684            let base_expr = f(cx, CsFold::Single(base_field));
1685
1686            let op = |old, field: &FieldInfo| {
1687                let new = f(cx, CsFold::Single(field));
1688                f(cx, CsFold::Combine(field.span, old, new))
1689            };
1690
1691            if use_foldl {
1692                rest.iter().fold(base_expr, op)
1693            } else {
1694                rest.iter().rfold(base_expr, op)
1695            }
1696        }
1697        EnumDiscr(discr_field, match_expr) => {
1698            let discr_check_expr = f(cx, CsFold::Single(discr_field));
1699            if let Some(match_expr) = match_expr {
1700                if use_foldl {
1701                    f(cx, CsFold::Combine(trait_span, discr_check_expr, match_expr.clone()))
1702                } else {
1703                    f(cx, CsFold::Combine(trait_span, match_expr.clone(), discr_check_expr))
1704                }
1705            } else {
1706                discr_check_expr
1707            }
1708        }
1709        StaticEnum(..) | StaticStruct(..) => {
1710            cx.dcx().span_bug(trait_span, "static function in `derive`")
1711        }
1712        AllFieldlessEnum(..) => cx.dcx().span_bug(trait_span, "fieldless enum in `derive`"),
1713    }
1714}