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