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 ¶m.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}