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.
6 //! Supported features (fairly exhaustive):
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`)
16 //! The most important thing for implementors is the `Substructure` and
17 //! `SubstructureFields` objects. The latter groups 5 possibilities of the
20 //! - `Struct`, when `Self` is a struct (including tuple structs, e.g
21 //! `struct T(i32, char)`).
22 //! - `EnumMatching`, when `Self` is an enum and all the arguments are the
23 //! same variant of the enum (e.g., `Some(1)`, `Some(3)` and `Some(4)`)
24 //! - `EnumNonMatchingCollapsed` when `Self` is an enum and the arguments
25 //! are not the same variant (e.g., `None`, `Some(1)` and `None`).
26 //! - `StaticEnum` and `StaticStruct` for static methods, where the type
27 //! being derived upon is either an enum or struct respectively. (Any
28 //! argument with type Self is just grouped among the non-self
31 //! In the first two cases, the values from the corresponding fields in
32 //! all the arguments are grouped together. For `EnumNonMatchingCollapsed`
33 //! this isn't possible (different variants have different fields), so the
34 //! fields are inaccessible. (Previous versions of the deriving infrastructure
35 //! had a way to expand into code that could access them, at the cost of
36 //! generating exponential amounts of code; see issue #15375). There are no
37 //! fields with values in the static cases, so these are treated entirely
40 //! The non-static cases have `Option<ident>` in several places associated
41 //! with field `expr`s. This represents the name of the field it is
42 //! associated with. It is only not `None` when the associated field has
43 //! an identifier in the source code. For example, the `x`s in the
47 //! # #![allow(dead_code)]
48 //! struct A { x : i32 }
58 //! The `i32`s in `B` and `C0` don't have an identifier, so the
59 //! `Option<ident>`s would be `None` for them.
61 //! In the static cases, the structure is summarized, either into the just
62 //! spans of the fields or a list of spans and the field idents (for tuple
63 //! structs and record structs, respectively), or a list of these, for
64 //! enums (one for each variant). For empty struct and empty enum
65 //! variants, it is represented as a count of 0.
67 //! # "`cs`" functions
69 //! The `cs_...` functions ("combine substructure) are designed to
70 //! make life easier by providing some pre-made recipes for common
71 //! threads; mostly calling the function being derived on all the
72 //! arguments and then combining them back together in some way (or
73 //! letting the user chose that). They are not meant to be the only
74 //! way to handle the structures that this code creates.
78 //! The following simplified `PartialEq` is used for in-code examples:
82 //! fn eq(&self, other: &Self) -> bool;
84 //! impl PartialEq for i32 {
85 //! fn eq(&self, other: &i32) -> bool {
91 //! Some examples of the values of `SubstructureFields` follow, using the
92 //! above `PartialEq`, `A`, `B` and `C`.
96 //! When generating the `expr` for the `A` impl, the `SubstructureFields` is
99 //! Struct(vec![FieldInfo {
100 //! span: <span of x>
101 //! name: Some(<ident of x>),
102 //! self_: <expr for &self.x>,
103 //! other: vec![<expr for &other.x]
107 //! For the `B` impl, called with `B(a)` and `B(b)`,
110 //! Struct(vec![FieldInfo {
111 //! span: <span of `i32`>,
113 //! self_: <expr for &a>
114 //! other: vec![<expr for &b>]
120 //! When generating the `expr` for a call with `self == C0(a)` and `other
121 //! == C0(b)`, the SubstructureFields is
124 //! EnumMatching(0, <ast::Variant for C0>,
126 //! span: <span of i32>
128 //! self_: <expr for &a>,
129 //! other: vec![<expr for &b>]
133 //! For `C1 {x}` and `C1 {x}`,
136 //! EnumMatching(1, <ast::Variant for C1>,
138 //! span: <span of x>
139 //! name: Some(<ident of x>),
140 //! self_: <expr for &self.x>,
141 //! other: vec![<expr for &other.x>]
145 //! For `C0(a)` and `C1 {x}` ,
148 //! EnumNonMatchingCollapsed(
149 //! vec![<ident of self>, <ident of __arg_1>],
150 //! &[<ast::Variant for C0>, <ast::Variant for C1>],
151 //! &[<ident for self index value>, <ident of __arg_1 index value>])
154 //! It is the same for when the arguments are flipped to `C1 {x}` and
155 //! `C0(a)`; the only difference is what the values of the identifiers
156 //! <ident for self index value> and <ident of __arg_1 index value> will
157 //! be in the generated code.
159 //! `EnumNonMatchingCollapsed` deliberately provides far less information
160 //! than is generally available for a given pair of variants; see #15375
165 //! A static method on the types above would result in,
168 //! StaticStruct(<ast::VariantData of A>, Named(vec![(<ident of x>, <span of x>)]))
170 //! StaticStruct(<ast::VariantData of B>, Unnamed(vec![<span of x>]))
172 //! StaticEnum(<ast::EnumDef of C>,
173 //! vec![(<ident of C0>, <span of C0>, Unnamed(vec![<span of i32>])),
174 //! (<ident of C1>, <span of C1>, Named(vec![(<ident of x>, <span of x>)]))])
177 pub use StaticFields::*;
178 pub use SubstructureFields::*;
180 use std::cell::RefCell;
184 use rustc_ast::ptr::P;
185 use rustc_ast::{self as ast, BinOpKind, EnumDef, Expr, Generics, PatKind};
186 use rustc_ast::{GenericArg, GenericParamKind, VariantData};
187 use rustc_attr as attr;
188 use rustc_data_structures::map_in_place::MapInPlace;
189 use rustc_expand::base::{Annotatable, ExtCtxt};
190 use rustc_span::symbol::{kw, sym, Ident, Symbol};
191 use rustc_span::Span;
193 use ty::{Bounds, Path, Ptr, PtrTy, Self_, Ty};
199 pub struct TraitDef<'a> {
200 /// The span for the current #[derive(Foo)] header.
203 pub attributes: Vec<ast::Attribute>,
205 /// Path of the trait, including any type parameters
208 /// Additional bounds required of any type parameters of the type,
209 /// other than the current trait
210 pub additional_bounds: Vec<Ty>,
212 /// Any extra lifetimes and/or bounds, e.g., `D: serialize::Decoder`
213 pub generics: Bounds,
215 /// Is it an `unsafe` trait?
218 /// Can this trait be derived for unions?
219 pub supports_unions: bool,
221 pub methods: Vec<MethodDef<'a>>,
223 pub associated_types: Vec<(Ident, Ty)>,
226 pub struct MethodDef<'a> {
227 /// name of the method
229 /// List of generics, e.g., `R: rand::Rng`
230 pub generics: Bounds,
232 /// Whether there is a self argument (outer Option) i.e., whether
233 /// this is a static function, and whether it is a pointer (inner
235 pub explicit_self: Option<Option<PtrTy>>,
237 /// Arguments other than the self argument
238 pub args: Vec<(Ty, Symbol)>,
243 pub attributes: Vec<ast::Attribute>,
245 // Is it an `unsafe fn`?
248 /// Can we combine fieldless variants for enums into a single match arm?
249 pub unify_fieldless_variants: bool,
251 pub combine_substructure: RefCell<CombineSubstructureFunc<'a>>,
254 /// All the data about the data structure/method being derived upon.
255 pub struct Substructure<'a> {
257 pub type_ident: Ident,
258 /// ident of the method
259 pub method_ident: Ident,
260 /// dereferenced access to any [`Self_`] or [`Ptr(Self_, _)`][ptr] arguments
262 /// [`Self_`]: ty::Ty::Self_
263 /// [ptr]: ty::Ty::Ptr
264 pub self_args: &'a [P<Expr>],
265 /// verbatim access to any other arguments
266 pub nonself_args: &'a [P<Expr>],
267 pub fields: &'a SubstructureFields<'a>,
270 /// Summary of the relevant parts of a struct/enum field.
271 pub struct FieldInfo<'a> {
273 /// None for tuple structs/normal enum variants, Some for normal
274 /// structs/struct enum variants.
275 pub name: Option<Ident>,
276 /// The expression corresponding to this field of `self`
277 /// (specifically, a reference to it).
279 /// The expressions corresponding to references to this field in
280 /// the other `Self` arguments.
281 pub other: Vec<P<Expr>>,
282 /// The attributes on the field
283 pub attrs: &'a [ast::Attribute],
286 /// Fields for a static method
287 pub enum StaticFields {
288 /// Tuple and unit structs/enum variants like this.
289 Unnamed(Vec<Span>, bool /*is tuple*/),
290 /// Normal structs/struct variants.
291 Named(Vec<(Ident, Span)>),
294 /// A summary of the possible sets of fields.
295 pub enum SubstructureFields<'a> {
296 Struct(&'a ast::VariantData, Vec<FieldInfo<'a>>),
297 /// Matching variants of the enum: variant index, variant count, ast::Variant,
298 /// fields: the field name is only non-`None` in the case of a struct
300 EnumMatching(usize, usize, &'a ast::Variant, Vec<FieldInfo<'a>>),
302 /// Non-matching variants of the enum, but with all state hidden from
303 /// the consequent code. The first component holds `Ident`s for all of
304 /// the `Self` arguments; the second component is a slice of all of the
305 /// variants for the enum itself, and the third component is a list of
306 /// `Ident`s bound to the variant index values for each of the actual
307 /// input `Self` arguments.
308 EnumNonMatchingCollapsed(Vec<Ident>, &'a [ast::Variant], &'a [Ident]),
310 /// A static method where `Self` is a struct.
311 StaticStruct(&'a ast::VariantData, StaticFields),
312 /// A static method where `Self` is an enum.
313 StaticEnum(&'a ast::EnumDef, Vec<(Ident, Span, StaticFields)>),
316 /// Combine the values of all the fields together. The last argument is
317 /// all the fields of all the structures.
318 pub type CombineSubstructureFunc<'a> =
319 Box<dyn FnMut(&mut ExtCtxt<'_>, Span, &Substructure<'_>) -> P<Expr> + 'a>;
321 /// Deal with non-matching enum variants. The tuple is a list of
322 /// identifiers (one for each `Self` argument, which could be any of the
323 /// variants since they have been collapsed together) and the identifiers
324 /// holding the variant index value for each of the `Self` arguments. The
325 /// last argument is all the non-`Self` args of the method being derived.
326 pub type EnumNonMatchCollapsedFunc<'a> =
327 Box<dyn FnMut(&mut ExtCtxt<'_>, Span, (&[Ident], &[Ident]), &[P<Expr>]) -> P<Expr> + 'a>;
329 pub fn combine_substructure(
330 f: CombineSubstructureFunc<'_>,
331 ) -> RefCell<CombineSubstructureFunc<'_>> {
335 struct TypeParameter {
336 bound_generic_params: Vec<ast::GenericParam>,
340 /// This method helps to extract all the type parameters referenced from a
341 /// type. For a type parameter `<T>`, it looks for either a `TyPath` that
342 /// is not global and starts with `T`, or a `TyQPath`.
343 /// Also include bound generic params from the input type.
344 fn find_type_parameters(
346 ty_param_names: &[Symbol],
348 ) -> Vec<TypeParameter> {
349 use rustc_ast::visit;
351 struct Visitor<'a, 'b> {
353 ty_param_names: &'a [Symbol],
354 bound_generic_params_stack: Vec<ast::GenericParam>,
355 type_params: Vec<TypeParameter>,
358 impl<'a, 'b> visit::Visitor<'a> for Visitor<'a, 'b> {
359 fn visit_ty(&mut self, ty: &'a ast::Ty) {
360 if let ast::TyKind::Path(_, ref path) = ty.kind {
361 if let Some(segment) = path.segments.first() {
362 if self.ty_param_names.contains(&segment.ident.name) {
363 self.type_params.push(TypeParameter {
364 bound_generic_params: self.bound_generic_params_stack.clone(),
371 visit::walk_ty(self, ty)
374 // Place bound generic params on a stack, to extract them when a type is encountered.
375 fn visit_poly_trait_ref(
377 trait_ref: &'a ast::PolyTraitRef,
378 modifier: &'a ast::TraitBoundModifier,
380 let stack_len = self.bound_generic_params_stack.len();
381 self.bound_generic_params_stack
382 .extend(trait_ref.bound_generic_params.clone().into_iter());
384 visit::walk_poly_trait_ref(self, trait_ref, modifier);
386 self.bound_generic_params_stack.truncate(stack_len);
389 fn visit_mac_call(&mut self, mac: &ast::MacCall) {
390 self.cx.span_err(mac.span(), "`derive` cannot be used on items with type macros");
394 let mut visitor = Visitor {
397 bound_generic_params_stack: Vec::new(),
398 type_params: Vec::new(),
400 visit::Visitor::visit_ty(&mut visitor, ty);
405 impl<'a> TraitDef<'a> {
408 cx: &mut ExtCtxt<'_>,
409 mitem: &ast::MetaItem,
410 item: &'a Annotatable,
411 push: &mut dyn FnMut(Annotatable),
413 self.expand_ext(cx, mitem, item, push, false);
418 cx: &mut ExtCtxt<'_>,
419 mitem: &ast::MetaItem,
420 item: &'a Annotatable,
421 push: &mut dyn FnMut(Annotatable),
425 Annotatable::Item(ref item) => {
426 let is_packed = item.attrs.iter().any(|attr| {
427 for r in attr::find_repr_attrs(&cx.sess, attr) {
428 if let attr::ReprPacked(_) = r {
434 let has_no_type_params = match item.kind {
435 ast::ItemKind::Struct(_, ref generics)
436 | ast::ItemKind::Enum(_, ref generics)
437 | ast::ItemKind::Union(_, ref generics) => !generics
440 .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })),
443 let container_id = cx.current_expansion.id.expn_data().parent.expect_local();
444 let always_copy = has_no_type_params && cx.resolver.has_derive_copy(container_id);
445 let use_temporaries = is_packed && always_copy;
447 let newitem = match item.kind {
448 ast::ItemKind::Struct(ref struct_def, ref generics) => self.expand_struct_def(
456 ast::ItemKind::Enum(ref enum_def, ref generics) => {
457 // We ignore `use_temporaries` here, because
458 // `repr(packed)` enums cause an error later on.
460 // This can only cause further compilation errors
461 // downstream in blatantly illegal code, so it
463 self.expand_enum_def(cx, enum_def, item.ident, generics, from_scratch)
465 ast::ItemKind::Union(ref struct_def, ref generics) => {
466 if self.supports_unions {
467 self.expand_struct_def(
476 cx.span_err(mitem.span, "this trait cannot be derived for unions");
482 // Keep the lint attributes of the previous item to control how the
483 // generated implementations are linted
484 let mut attrs = newitem.attrs.clone();
497 .contains(&a.name_or_empty())
501 push(Annotatable::Item(P(ast::Item { attrs, ..(*newitem).clone() })))
507 /// Given that we are deriving a trait `DerivedTrait` for a type like:
509 /// ```ignore (only-for-syntax-highlight)
510 /// struct Struct<'a, ..., 'z, A, B: DeclaredTrait, C, ..., Z> where C: WhereTrait {
513 /// b1: <B as DeclaredTrait>::Item,
514 /// c1: <C as WhereTrait>::Item,
515 /// c2: Option<<C as WhereTrait>::Item>,
520 /// create an impl like:
522 /// ```ignore (only-for-syntax-highlight)
523 /// impl<'a, ..., 'z, A, B: DeclaredTrait, C, ... Z> where
525 /// A: DerivedTrait + B1 + ... + BN,
526 /// B: DerivedTrait + B1 + ... + BN,
527 /// C: DerivedTrait + B1 + ... + BN,
528 /// B::Item: DerivedTrait + B1 + ... + BN,
529 /// <C as WhereTrait>::Item: DerivedTrait + B1 + ... + BN,
536 /// where B1, ..., BN are the bounds given by `bounds_paths`.'. Z is a phantom type, and
537 /// therefore does not get bound by the derived trait.
538 fn create_derived_impl(
540 cx: &mut ExtCtxt<'_>,
543 field_tys: Vec<P<ast::Ty>>,
544 methods: Vec<P<ast::AssocItem>>,
546 let trait_path = self.path.to_path(cx, self.span, type_ident, generics);
548 // Transform associated types from `deriving::ty::Ty` into `ast::AssocItem`
549 let associated_types = self.associated_types.iter().map(|&(ident, ref type_def)| {
551 id: ast::DUMMY_NODE_ID,
554 vis: ast::Visibility {
555 span: self.span.shrink_to_lo(),
556 kind: ast::VisibilityKind::Inherited,
560 kind: ast::AssocItemKind::TyAlias(Box::new(ast::TyAlias {
561 defaultness: ast::Defaultness::Final,
562 generics: Generics::default(),
564 ast::TyAliasWhereClause::default(),
565 ast::TyAliasWhereClause::default(),
567 where_predicates_split: 0,
569 ty: Some(type_def.to_ty(cx, self.span, type_ident, generics)),
575 let Generics { mut params, mut where_clause, .. } =
576 self.generics.to_generics(cx, self.span, type_ident, generics);
577 where_clause.span = generics.where_clause.span;
578 let ctxt = self.span.ctxt();
579 let span = generics.span.with_ctxt(ctxt);
581 // Create the generic parameters
582 params.extend(generics.params.iter().map(|param| match ¶m.kind {
583 GenericParamKind::Lifetime { .. } => param.clone(),
584 GenericParamKind::Type { .. } => {
585 // I don't think this can be moved out of the loop, since
586 // a GenericBound requires an ast id
588 // extra restrictions on the generics parameters to the
589 // type being derived upon
590 self.additional_bounds.iter().map(|p| {
591 cx.trait_bound(p.to_path(cx, self.span, type_ident, generics))
593 // require the current trait
594 iter::once(cx.trait_bound(trait_path.clone()))
596 // also add in any bounds from the declaration
597 param.bounds.iter().cloned()
600 cx.typaram(param.ident.span.with_ctxt(ctxt), param.ident, vec![], bounds, None)
602 GenericParamKind::Const { ty, kw_span, .. } => {
603 let const_nodefault_kind = GenericParamKind::Const {
605 kw_span: kw_span.with_ctxt(ctxt),
607 // We can't have default values inside impl block
610 let mut param_clone = param.clone();
611 param_clone.kind = const_nodefault_kind;
616 // and similarly for where clauses
617 where_clause.predicates.extend(generics.where_clause.predicates.iter().map(|clause| {
619 ast::WherePredicate::BoundPredicate(wb) => {
620 let span = wb.span.with_ctxt(ctxt);
621 ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
626 ast::WherePredicate::RegionPredicate(wr) => {
627 let span = wr.span.with_ctxt(ctxt);
628 ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
633 ast::WherePredicate::EqPredicate(we) => {
634 let span = we.span.with_ctxt(ctxt);
635 ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
636 id: ast::DUMMY_NODE_ID,
645 // Extra scope required here so ty_params goes out of scope before params is moved
647 let mut ty_params = params
649 .filter(|param| matches!(param.kind, ast::GenericParamKind::Type { .. }))
652 if ty_params.peek().is_some() {
653 let ty_param_names: Vec<Symbol> =
654 ty_params.map(|ty_param| ty_param.ident.name).collect();
656 for field_ty in field_tys {
657 let field_ty_params = find_type_parameters(&field_ty, &ty_param_names, cx);
659 for field_ty_param in field_ty_params {
660 // if we have already handled this type, skip it
661 if let ast::TyKind::Path(_, ref p) = field_ty_param.ty.kind {
662 if p.segments.len() == 1
663 && ty_param_names.contains(&p.segments[0].ident.name)
668 let mut bounds: Vec<_> = self
671 .map(|p| cx.trait_bound(p.to_path(cx, self.span, type_ident, generics)))
674 // require the current trait
675 bounds.push(cx.trait_bound(trait_path.clone()));
677 let predicate = ast::WhereBoundPredicate {
679 bound_generic_params: field_ty_param.bound_generic_params,
680 bounded_ty: field_ty_param.ty,
684 let predicate = ast::WherePredicate::BoundPredicate(predicate);
685 where_clause.predicates.push(predicate);
691 let trait_generics = Generics { params, where_clause, span };
693 // Create the reference to the trait.
694 let trait_ref = cx.trait_ref(trait_path);
696 let self_params: Vec<_> = generics
699 .map(|param| match param.kind {
700 GenericParamKind::Lifetime { .. } => {
701 GenericArg::Lifetime(cx.lifetime(param.ident.span.with_ctxt(ctxt), param.ident))
703 GenericParamKind::Type { .. } => {
704 GenericArg::Type(cx.ty_ident(param.ident.span.with_ctxt(ctxt), param.ident))
706 GenericParamKind::Const { .. } => {
707 GenericArg::Const(cx.const_ident(param.ident.span.with_ctxt(ctxt), param.ident))
712 // Create the type of `self`.
713 let path = cx.path_all(self.span, false, vec![type_ident], self_params);
714 let self_type = cx.ty_path(path);
716 let attr = cx.attribute(cx.meta_word(self.span, sym::automatically_derived));
717 let opt_trait_ref = Some(trait_ref);
719 let word = rustc_ast::attr::mk_nested_word_item(Ident::new(
720 sym::unused_qualifications,
723 let list = rustc_ast::attr::mk_list_item(Ident::new(sym::allow, self.span), vec![word]);
727 let mut a = vec![attr, unused_qual];
728 a.extend(self.attributes.iter().cloned());
730 let unsafety = if self.is_unsafe { ast::Unsafe::Yes(self.span) } else { ast::Unsafe::No };
736 ast::ItemKind::Impl(Box::new(ast::Impl {
738 polarity: ast::ImplPolarity::Positive,
739 defaultness: ast::Defaultness::Final,
740 constness: ast::Const::No,
741 generics: trait_generics,
742 of_trait: opt_trait_ref,
744 items: methods.into_iter().chain(associated_types).collect(),
749 fn expand_struct_def(
751 cx: &mut ExtCtxt<'_>,
752 struct_def: &'a VariantData,
756 use_temporaries: bool,
758 let field_tys: Vec<P<ast::Ty>> =
759 struct_def.fields().iter().map(|field| field.ty.clone()).collect();
765 let (explicit_self, self_args, nonself_args, tys) =
766 method_def.split_self_nonself_args(cx, self, type_ident, generics);
768 let body = if from_scratch || method_def.is_static() {
769 method_def.expand_static_struct_method_body(
778 method_def.expand_struct_method_body(
789 method_def.create_method(cx, self, type_ident, generics, explicit_self, tys, body)
793 self.create_derived_impl(cx, type_ident, generics, field_tys, methods)
798 cx: &mut ExtCtxt<'_>,
799 enum_def: &'a EnumDef,
804 let mut field_tys = Vec::new();
806 for variant in &enum_def.variants {
807 field_tys.extend(variant.data.fields().iter().map(|field| field.ty.clone()));
814 let (explicit_self, self_args, nonself_args, tys) =
815 method_def.split_self_nonself_args(cx, self, type_ident, generics);
817 let body = if from_scratch || method_def.is_static() {
818 method_def.expand_static_enum_method_body(
827 method_def.expand_enum_method_body(
837 method_def.create_method(cx, self, type_ident, generics, explicit_self, tys, body)
841 self.create_derived_impl(cx, type_ident, generics, field_tys, methods)
845 impl<'a> MethodDef<'a> {
846 fn call_substructure_method(
848 cx: &mut ExtCtxt<'_>,
849 trait_: &TraitDef<'_>,
851 self_args: &[P<Expr>],
852 nonself_args: &[P<Expr>],
853 fields: &SubstructureFields<'_>,
855 let span = trait_.span;
856 let substructure = Substructure {
858 method_ident: Ident::new(self.name, span),
863 let mut f = self.combine_substructure.borrow_mut();
864 let f: &mut CombineSubstructureFunc<'_> = &mut *f;
865 f(cx, span, &substructure)
870 cx: &mut ExtCtxt<'_>,
871 trait_: &TraitDef<'_>,
875 self.ret_ty.to_ty(cx, trait_.span, type_ident, generics)
878 fn is_static(&self) -> bool {
879 self.explicit_self.is_none()
882 fn split_self_nonself_args(
884 cx: &mut ExtCtxt<'_>,
885 trait_: &TraitDef<'_>,
888 ) -> (Option<ast::ExplicitSelf>, Vec<P<Expr>>, Vec<P<Expr>>, Vec<(Ident, P<ast::Ty>)>) {
889 let mut self_args = Vec::new();
890 let mut nonself_args = Vec::new();
891 let mut arg_tys = Vec::new();
892 let mut nonstatic = false;
893 let span = trait_.span;
895 let ast_explicit_self = self.explicit_self.as_ref().map(|self_ptr| {
896 let (self_expr, explicit_self) = ty::get_explicit_self(cx, span, self_ptr);
898 self_args.push(self_expr);
904 for (ty, name) in self.args.iter() {
905 let ast_ty = ty.to_ty(cx, span, type_ident, generics);
906 let ident = Ident::new(*name, span);
907 arg_tys.push((ident, ast_ty));
909 let arg_expr = cx.expr_ident(span, ident);
912 // for static methods, just treat any Self
913 // arguments as a normal arg
914 Self_ if nonstatic => {
915 self_args.push(arg_expr);
917 Ptr(ref ty, _) if matches!(**ty, Self_) && nonstatic => {
918 self_args.push(cx.expr_deref(span, arg_expr))
921 nonself_args.push(arg_expr);
926 (ast_explicit_self, self_args, nonself_args, arg_tys)
931 cx: &mut ExtCtxt<'_>,
932 trait_: &TraitDef<'_>,
935 explicit_self: Option<ast::ExplicitSelf>,
936 arg_types: Vec<(Ident, P<ast::Ty>)>,
938 ) -> P<ast::AssocItem> {
939 let span = trait_.span;
940 // Create the generics that aren't for `Self`.
941 let fn_generics = self.generics.to_generics(cx, span, type_ident, generics);
944 let self_args = explicit_self.map(|explicit_self| {
945 let ident = Ident::with_dummy_span(kw::SelfLower).with_span_pos(span);
946 ast::Param::from_self(ast::AttrVec::default(), explicit_self, ident)
948 let nonself_args = arg_types.into_iter().map(|(name, ty)| cx.param(span, name, ty));
949 self_args.into_iter().chain(nonself_args).collect()
952 let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident);
954 let method_ident = Ident::new(self.name, span);
955 let fn_decl = cx.fn_decl(args, ast::FnRetTy::Ty(ret_type));
956 let body_block = cx.block_expr(body);
958 let unsafety = if self.is_unsafe { ast::Unsafe::Yes(span) } else { ast::Unsafe::No };
960 let trait_lo_sp = span.shrink_to_lo();
962 let sig = ast::FnSig {
963 header: ast::FnHeader { unsafety, ext: ast::Extern::None, ..ast::FnHeader::default() },
967 let defaultness = ast::Defaultness::Final;
969 // Create the method.
971 id: ast::DUMMY_NODE_ID,
972 attrs: self.attributes.clone(),
974 vis: ast::Visibility {
976 kind: ast::VisibilityKind::Inherited,
980 kind: ast::AssocItemKind::Fn(Box::new(ast::Fn {
983 generics: fn_generics,
984 body: Some(body_block),
991 /// #[derive(PartialEq)]
993 /// struct A { x: i32, y: i32 }
995 /// // equivalent to:
996 /// impl PartialEq for A {
997 /// fn eq(&self, other: &A) -> bool {
999 /// A {x: ref __self_0_0, y: ref __self_0_1} => {
1001 /// A {x: ref __self_1_0, y: ref __self_1_1} => {
1002 /// __self_0_0.eq(__self_1_0) && __self_0_1.eq(__self_1_1)
1010 /// or if A is repr(packed) - note fields are matched by-value
1011 /// instead of by-reference.
1013 /// # struct A { x: i32, y: i32 }
1014 /// impl PartialEq for A {
1015 /// fn eq(&self, other: &A) -> bool {
1017 /// A {x: __self_0_0, y: __self_0_1} => {
1019 /// A {x: __self_1_0, y: __self_1_1} => {
1020 /// __self_0_0.eq(&__self_1_0) && __self_0_1.eq(&__self_1_1)
1028 fn expand_struct_method_body<'b>(
1030 cx: &mut ExtCtxt<'_>,
1031 trait_: &TraitDef<'b>,
1032 struct_def: &'b VariantData,
1034 self_args: &[P<Expr>],
1035 nonself_args: &[P<Expr>],
1036 use_temporaries: bool,
1038 let mut raw_fields = Vec::new(); // Vec<[fields of self], [fields of next Self arg], [etc]>
1039 let span = trait_.span;
1040 let mut patterns = Vec::new();
1041 for i in 0..self_args.len() {
1042 // We could use `type_ident` instead of `Self`, but in the case of a type parameter
1043 // shadowing the struct name, that causes a second, unnecessary E0578 error. #97343
1044 let struct_path = cx.path(span, vec![Ident::new(kw::SelfUpper, type_ident.span)]);
1045 let (pat, ident_expr) = trait_.create_struct_pattern(
1049 &format!("__self_{}", i),
1050 ast::Mutability::Not,
1054 raw_fields.push(ident_expr);
1057 // transpose raw_fields
1058 let fields = if !raw_fields.is_empty() {
1059 let mut raw_fields = raw_fields.into_iter().map(|v| v.into_iter());
1060 let first_field = raw_fields.next().unwrap();
1061 let mut other_fields: Vec<vec::IntoIter<_>> = raw_fields.collect();
1063 .map(|(span, opt_id, field, attrs)| FieldInfo {
1064 span: span.with_ctxt(trait_.span.ctxt()),
1070 let (.., ex, _) = l.next().unwrap();
1078 cx.span_bug(span, "no `self` parameter for method in generic `derive`")
1081 // body of the inner most destructuring match
1082 let mut body = self.call_substructure_method(
1088 &Struct(struct_def, fields),
1091 // make a series of nested matches, to destructure the
1092 // structs. This is actually right-to-left, but it shouldn't
1094 for (arg_expr, pat) in iter::zip(self_args, patterns) {
1095 body = cx.expr_match(span, arg_expr.clone(), vec![cx.arm(span, pat.clone(), body)])
1101 fn expand_static_struct_method_body(
1103 cx: &mut ExtCtxt<'_>,
1104 trait_: &TraitDef<'_>,
1105 struct_def: &VariantData,
1107 self_args: &[P<Expr>],
1108 nonself_args: &[P<Expr>],
1110 let summary = trait_.summarise_struct(cx, struct_def);
1112 self.call_substructure_method(
1118 &StaticStruct(struct_def, summary),
1123 /// #[derive(PartialEq)]
1130 /// is equivalent to:
1132 /// impl ::core::cmp::PartialEq for A {
1134 /// fn eq(&self, other: &A) -> bool {
1136 /// let __self_vi = ::core::intrinsics::discriminant_value(&*self);
1137 /// let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other);
1138 /// if true && __self_vi == __arg_1_vi {
1139 /// match (&*self, &*other) {
1140 /// (&A::A2(ref __self_0), &A::A2(ref __arg_1_0)) =>
1141 /// (*__self_0) == (*__arg_1_0),
1145 /// false // catch-all handler
1151 /// Creates a match for a tuple of all `self_args`, where either all
1152 /// variants match, or it falls into a catch-all for when one variant
1155 /// There are N + 1 cases because is a case for each of the N
1156 /// variants where all of the variants match, and one catch-all for
1157 /// when one does not match.
1159 /// As an optimization we generate code which checks whether all variants
1160 /// match first which makes llvm see that C-like enums can be compiled into
1161 /// a simple equality check (for PartialEq).
1163 /// The catch-all handler is provided access the variant index values
1164 /// for each of the self-args, carried in precomputed variables.
1165 fn expand_enum_method_body<'b>(
1167 cx: &mut ExtCtxt<'_>,
1168 trait_: &TraitDef<'b>,
1169 enum_def: &'b EnumDef,
1171 mut self_args: Vec<P<Expr>>,
1172 nonself_args: &[P<Expr>],
1174 let span = trait_.span;
1175 let variants = &enum_def.variants;
1177 let self_arg_names = iter::once("__self".to_string())
1183 .map(|(arg_count, _self_arg)| format!("__arg_{}", arg_count)),
1185 .collect::<Vec<String>>();
1187 let self_arg_idents = self_arg_names
1189 .map(|name| Ident::from_str_and_span(name, span))
1190 .collect::<Vec<Ident>>();
1192 // The `vi_idents` will be bound, solely in the catch-all, to
1193 // a series of let statements mapping each self_arg to an int
1194 // value corresponding to its discriminant.
1195 let vi_idents = self_arg_names
1198 let vi_suffix = format!("{}_vi", name);
1199 Ident::from_str_and_span(&vi_suffix, span)
1201 .collect::<Vec<Ident>>();
1203 // Builds, via callback to call_substructure_method, the
1204 // delegated expression that handles the catch-all case,
1205 // using `__variants_tuple` to drive logic if necessary.
1206 let catch_all_substructure =
1207 EnumNonMatchingCollapsed(self_arg_idents, &variants, &vi_idents);
1209 let first_fieldless = variants.iter().find(|v| v.data.fields().is_empty());
1211 // These arms are of the form:
1212 // (Variant1, Variant1, ...) => Body1
1213 // (Variant2, Variant2, ...) => Body2
1215 // where each tuple has length = self_args.len()
1216 let mut match_arms: Vec<ast::Arm> = variants
1219 .filter(|&(_, v)| !(self.unify_fieldless_variants && v.data.fields().is_empty()))
1220 .map(|(index, variant)| {
1221 let mk_self_pat = |cx: &mut ExtCtxt<'_>, self_arg_name: &str| {
1222 let (p, idents) = trait_.create_enum_variant_pattern(
1227 ast::Mutability::Not,
1229 (cx.pat(span, PatKind::Ref(p, ast::Mutability::Not)), idents)
1232 // A single arm has form (&VariantK, &VariantK, ...) => BodyK
1233 // (see "Final wrinkle" note below for why.)
1234 let mut subpats = Vec::with_capacity(self_arg_names.len());
1235 let mut self_pats_idents = Vec::with_capacity(self_arg_names.len() - 1);
1236 let first_self_pat_idents = {
1237 let (p, idents) = mk_self_pat(cx, &self_arg_names[0]);
1241 for self_arg_name in &self_arg_names[1..] {
1242 let (p, idents) = mk_self_pat(cx, &self_arg_name);
1244 self_pats_idents.push(idents);
1247 // Here is the pat = `(&VariantK, &VariantK, ...)`
1248 let single_pat = cx.pat_tuple(span, subpats);
1250 // For the BodyK, we need to delegate to our caller,
1251 // passing it an EnumMatching to indicate which case
1254 // All of the Self args have the same variant in these
1255 // cases. So we transpose the info in self_pats_idents
1256 // to gather the getter expressions together, in the
1257 // form that EnumMatching expects.
1259 // The transposition is driven by walking across the
1260 // arg fields of the variant for the first self pat.
1261 let field_tuples = first_self_pat_idents
1264 // For each arg field of self, pull out its getter expr ...
1265 .map(|(field_index, (span, opt_ident, self_getter_expr, attrs))| {
1266 // ... but FieldInfo also wants getter expr
1267 // for matching other arguments of Self type;
1268 // so walk across the *other* self_pats_idents
1269 // and pull out getter for same field in each
1270 // of them (using `field_index` tracked above).
1271 // That is the heart of the transposition.
1272 let others = self_pats_idents
1275 let (_, _opt_ident, ref other_getter_expr, _) = fields[field_index];
1277 // All Self args have same variant, so
1278 // opt_idents are the same. (Assert
1279 // here to make it self-evident that
1280 // it is okay to ignore `_opt_ident`.)
1281 assert!(opt_ident == _opt_ident);
1283 other_getter_expr.clone()
1285 .collect::<Vec<P<Expr>>>();
1290 self_: self_getter_expr,
1295 .collect::<Vec<FieldInfo<'_>>>();
1297 // Now, for some given VariantK, we have built up
1298 // expressions for referencing every field of every
1299 // Self arg, assuming all are instances of VariantK.
1300 // Build up code associated with such a case.
1301 let substructure = EnumMatching(index, variants.len(), variant, field_tuples);
1302 let arm_expr = self.call_substructure_method(
1311 cx.arm(span, single_pat, arm_expr)
1315 let default = match first_fieldless {
1316 Some(v) if self.unify_fieldless_variants => {
1317 // We need a default case that handles the fieldless variants.
1318 // The index and actual variant aren't meaningful in this case,
1319 // so just use whatever
1320 let substructure = EnumMatching(0, variants.len(), v, Vec::new());
1321 Some(self.call_substructure_method(
1330 _ if variants.len() > 1 && self_args.len() > 1 => {
1331 // Since we know that all the arguments will match if we reach
1332 // the match expression we add the unreachable intrinsics as the
1333 // result of the catch all which should help llvm in optimizing it
1334 Some(deriving::call_unreachable(cx, span))
1338 if let Some(arm) = default {
1339 match_arms.push(cx.arm(span, cx.pat_wild(span), arm));
1342 // We will usually need the catch-all after matching the
1343 // tuples `(VariantK, VariantK, ...)` for each VariantK of the
1346 // * when there is only one Self arg, the arms above suffice
1347 // (and the deriving we call back into may not be prepared to
1348 // handle EnumNonMatchCollapsed), and,
1350 // * when the enum has only one variant, the single arm that
1351 // is already present always suffices.
1353 // * In either of the two cases above, if we *did* add a
1354 // catch-all `_` match, it would trigger the
1355 // unreachable-pattern error.
1357 if variants.len() > 1 && self_args.len() > 1 {
1358 // Build a series of let statements mapping each self_arg
1359 // to its discriminant value.
1361 // i.e., for `enum E<T> { A, B(1), C(T, T) }`, and a deriving
1362 // with three Self args, builds three statements:
1364 // let __self_vi = std::intrinsics::discriminant_value(&self);
1365 // let __arg_1_vi = std::intrinsics::discriminant_value(&arg1);
1366 // let __arg_2_vi = std::intrinsics::discriminant_value(&arg2);
1368 let mut index_let_stmts: Vec<ast::Stmt> = Vec::with_capacity(vi_idents.len() + 1);
1370 // We also build an expression which checks whether all discriminants are equal:
1371 // `__self_vi == __arg_1_vi && __self_vi == __arg_2_vi && ...`
1372 let mut discriminant_test = cx.expr_bool(span, true);
1373 for (i, (&ident, self_arg)) in iter::zip(&vi_idents, &self_args).enumerate() {
1374 let self_addr = cx.expr_addr_of(span, self_arg.clone());
1376 deriving::call_intrinsic(cx, span, sym::discriminant_value, vec![self_addr]);
1377 let let_stmt = cx.stmt_let(span, false, ident, variant_value);
1378 index_let_stmts.push(let_stmt);
1381 let id0 = cx.expr_ident(span, vi_idents[0]);
1382 let id = cx.expr_ident(span, ident);
1383 let test = cx.expr_binary(span, BinOpKind::Eq, id0, id);
1384 discriminant_test = if i == 1 {
1387 cx.expr_binary(span, BinOpKind::And, discriminant_test, test)
1392 let arm_expr = self.call_substructure_method(
1398 &catch_all_substructure,
1401 // Final wrinkle: the self_args are expressions that deref
1402 // down to desired places, but we cannot actually deref
1403 // them when they are fed as r-values into a tuple
1404 // expression; here add a layer of borrowing, turning
1405 // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
1406 self_args.map_in_place(|self_arg| cx.expr_addr_of(span, self_arg));
1407 let match_arg = cx.expr(span, ast::ExprKind::Tup(self_args));
1409 // Lastly we create an expression which branches on all discriminants being equal
1410 // if discriminant_test {
1412 // (Variant1, Variant1, ...) => Body1
1413 // (Variant2, Variant2, ...) => Body2,
1415 // _ => ::core::intrinsics::unreachable()
1419 // <delegated expression referring to __self_vi, et al.>
1421 let all_match = cx.expr_match(span, match_arg, match_arms);
1422 let arm_expr = cx.expr_if(span, discriminant_test, all_match, Some(arm_expr));
1423 index_let_stmts.push(cx.stmt_expr(arm_expr));
1424 cx.expr_block(cx.block(span, index_let_stmts))
1425 } else if variants.is_empty() {
1426 // As an additional wrinkle, For a zero-variant enum A,
1427 // currently the compiler
1428 // will accept `fn (a: &Self) { match *a { } }`
1429 // but rejects `fn (a: &Self) { match (&*a,) { } }`
1430 // as well as `fn (a: &Self) { match ( *a,) { } }`
1432 // This means that the strategy of building up a tuple of
1433 // all Self arguments fails when Self is a zero variant
1434 // enum: rustc rejects the expanded program, even though
1435 // the actual code tends to be impossible to execute (at
1436 // least safely), according to the type system.
1438 // The most expedient fix for this is to just let the
1439 // code fall through to the catch-all. But even this is
1440 // error-prone, since the catch-all as defined above would
1441 // generate code like this:
1443 // _ => { let __self0 = match *self { };
1444 // let __self1 = match *__arg_0 { };
1445 // <catch-all-expr> }
1447 // Which is yields bindings for variables which type
1448 // inference cannot resolve to unique types.
1450 // One option to the above might be to add explicit type
1451 // annotations. But the *only* reason to go down that path
1452 // would be to try to make the expanded output consistent
1453 // with the case when the number of enum variants >= 1.
1455 // That just isn't worth it. In fact, trying to generate
1456 // sensible code for *any* deriving on a zero-variant enum
1457 // does not make sense. But at the same time, for now, we
1458 // do not want to cause a compile failure just because the
1459 // user happened to attach a deriving to their
1460 // zero-variant enum.
1462 // Instead, just generate a failing expression for the
1463 // zero variant case, skipping matches and also skipping
1464 // delegating back to the end user code entirely.
1466 // (See also #4499 and #12609; note that some of the
1467 // discussions there influence what choice we make here;
1468 // e.g., if we feature-gate `match x { ... }` when x refers
1469 // to an uninhabited type (e.g., a zero-variant enum or a
1470 // type holding such an enum), but do not feature-gate
1471 // zero-variant enums themselves, then attempting to
1472 // derive Debug on such a type could here generate code
1473 // that needs the feature gate enabled.)
1475 deriving::call_unreachable(cx, span)
1477 // Final wrinkle: the self_args are expressions that deref
1478 // down to desired places, but we cannot actually deref
1479 // them when they are fed as r-values into a tuple
1480 // expression; here add a layer of borrowing, turning
1481 // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
1482 self_args.map_in_place(|self_arg| cx.expr_addr_of(span, self_arg));
1483 let match_arg = cx.expr(span, ast::ExprKind::Tup(self_args));
1484 cx.expr_match(span, match_arg, match_arms)
1488 fn expand_static_enum_method_body(
1490 cx: &mut ExtCtxt<'_>,
1491 trait_: &TraitDef<'_>,
1494 self_args: &[P<Expr>],
1495 nonself_args: &[P<Expr>],
1497 let summary = enum_def
1501 let sp = v.span.with_ctxt(trait_.span.ctxt());
1502 let summary = trait_.summarise_struct(cx, &v.data);
1503 (v.ident, sp, summary)
1506 self.call_substructure_method(
1512 &StaticEnum(enum_def, summary),
1517 // general helper methods.
1518 impl<'a> TraitDef<'a> {
1519 fn summarise_struct(&self, cx: &mut ExtCtxt<'_>, struct_def: &VariantData) -> StaticFields {
1520 let mut named_idents = Vec::new();
1521 let mut just_spans = Vec::new();
1522 for field in struct_def.fields() {
1523 let sp = field.span.with_ctxt(self.span.ctxt());
1525 Some(ident) => named_idents.push((ident, sp)),
1526 _ => just_spans.push(sp),
1530 let is_tuple = matches!(struct_def, ast::VariantData::Tuple(..));
1531 match (just_spans.is_empty(), named_idents.is_empty()) {
1533 cx.span_bug(self.span, "a struct with named and unnamed fields in generic `derive`")
1536 (_, false) => Named(named_idents),
1538 (false, _) => Unnamed(just_spans, is_tuple),
1540 _ => Named(Vec::new()),
1544 fn create_subpatterns(
1546 cx: &mut ExtCtxt<'_>,
1547 field_paths: Vec<Ident>,
1548 mutbl: ast::Mutability,
1549 use_temporaries: bool,
1550 ) -> Vec<P<ast::Pat>> {
1554 let binding_mode = if use_temporaries {
1555 ast::BindingMode::ByValue(ast::Mutability::Not)
1557 ast::BindingMode::ByRef(mutbl)
1559 cx.pat(path.span, PatKind::Ident(binding_mode, *path, None))
1564 fn create_struct_pattern(
1566 cx: &mut ExtCtxt<'_>,
1567 struct_path: ast::Path,
1568 struct_def: &'a VariantData,
1570 mutbl: ast::Mutability,
1571 use_temporaries: bool,
1572 ) -> (P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>, &'a [ast::Attribute])>) {
1573 let mut paths = Vec::new();
1574 let mut ident_exprs = Vec::new();
1575 for (i, struct_field) in struct_def.fields().iter().enumerate() {
1576 let sp = struct_field.span.with_ctxt(self.span.ctxt());
1577 let ident = Ident::from_str_and_span(&format!("{}_{}", prefix, i), self.span);
1578 paths.push(ident.with_span_pos(sp));
1579 let val = cx.expr_path(cx.path_ident(sp, ident));
1580 let val = if use_temporaries { val } else { cx.expr_deref(sp, val) };
1581 let val = cx.expr(sp, ast::ExprKind::Paren(val));
1583 ident_exprs.push((sp, struct_field.ident, val, &struct_field.attrs[..]));
1586 let subpats = self.create_subpatterns(cx, paths, mutbl, use_temporaries);
1587 let pattern = match *struct_def {
1588 VariantData::Struct(..) => {
1589 let field_pats = iter::zip(subpats, &ident_exprs)
1590 .map(|(pat, &(sp, ident, ..))| {
1591 if ident.is_none() {
1592 cx.span_bug(sp, "a braced struct with unnamed fields in `derive`");
1595 ident: ident.unwrap(),
1596 is_shorthand: false,
1597 attrs: ast::AttrVec::new(),
1598 id: ast::DUMMY_NODE_ID,
1599 span: pat.span.with_ctxt(self.span.ctxt()),
1601 is_placeholder: false,
1605 cx.pat_struct(self.span, struct_path, field_pats)
1607 VariantData::Tuple(..) => cx.pat_tuple_struct(self.span, struct_path, subpats),
1608 VariantData::Unit(..) => cx.pat_path(self.span, struct_path),
1611 (pattern, ident_exprs)
1614 fn create_enum_variant_pattern(
1616 cx: &mut ExtCtxt<'_>,
1618 variant: &'a ast::Variant,
1620 mutbl: ast::Mutability,
1621 ) -> (P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>, &'a [ast::Attribute])>) {
1622 let sp = variant.span.with_ctxt(self.span.ctxt());
1623 let variant_path = cx.path(sp, vec![enum_ident, variant.ident]);
1624 let use_temporaries = false; // enums can't be repr(packed)
1625 self.create_struct_pattern(cx, variant_path, &variant.data, prefix, mutbl, use_temporaries)
1629 // helpful premade recipes
1631 pub fn cs_fold_fields<'a, F>(
1635 cx: &mut ExtCtxt<'_>,
1636 all_fields: &[FieldInfo<'a>],
1639 F: FnMut(&mut ExtCtxt<'_>, Span, P<Expr>, P<Expr>, &[P<Expr>]) -> P<Expr>,
1644 .fold(base, |old, field| f(cx, field.span, old, field.self_.clone(), &field.other))
1649 .fold(base, |old, field| f(cx, field.span, old, field.self_.clone(), &field.other))
1653 pub fn cs_fold_enumnonmatch(
1654 mut enum_nonmatch_f: EnumNonMatchCollapsedFunc<'_>,
1655 cx: &mut ExtCtxt<'_>,
1657 substructure: &Substructure<'_>,
1659 match *substructure.fields {
1660 EnumNonMatchingCollapsed(ref all_args, _, tuple) => {
1661 enum_nonmatch_f(cx, trait_span, (&all_args[..], tuple), substructure.nonself_args)
1663 _ => cx.span_bug(trait_span, "cs_fold_enumnonmatch expected an EnumNonMatchingCollapsed"),
1667 pub fn cs_fold_static(cx: &mut ExtCtxt<'_>, trait_span: Span) -> P<Expr> {
1668 cx.span_bug(trait_span, "static function in `derive`")
1671 /// Fold the fields. `use_foldl` controls whether this is done
1672 /// left-to-right (`true`) or right-to-left (`false`).
1677 enum_nonmatch_f: EnumNonMatchCollapsedFunc<'_>,
1678 cx: &mut ExtCtxt<'_>,
1680 substructure: &Substructure<'_>,
1683 F: FnMut(&mut ExtCtxt<'_>, Span, P<Expr>, P<Expr>, &[P<Expr>]) -> P<Expr>,
1685 match *substructure.fields {
1686 EnumMatching(.., ref all_fields) | Struct(_, ref all_fields) => {
1687 cs_fold_fields(use_foldl, f, base, cx, all_fields)
1689 EnumNonMatchingCollapsed(..) => {
1690 cs_fold_enumnonmatch(enum_nonmatch_f, cx, trait_span, substructure)
1692 StaticEnum(..) | StaticStruct(..) => cs_fold_static(cx, trait_span),
1696 /// Function to fold over fields, with three cases, to generate more efficient and concise code.
1697 /// When the `substructure` has grouped fields, there are two cases:
1698 /// Zero fields: call the base case function with `None` (like the usual base case of `cs_fold`).
1699 /// One or more fields: call the base case function on the first value (which depends on
1700 /// `use_fold`), and use that as the base case. Then perform `cs_fold` on the remainder of the
1702 /// When the `substructure` is an `EnumNonMatchingCollapsed`, the result of `enum_nonmatch_f`
1703 /// is returned. Statics may not be folded over.
1704 /// See `cs_op` in `partial_ord.rs` for a model example.
1705 pub fn cs_fold1<F, B>(
1709 enum_nonmatch_f: EnumNonMatchCollapsedFunc<'_>,
1710 cx: &mut ExtCtxt<'_>,
1712 substructure: &Substructure<'_>,
1715 F: FnMut(&mut ExtCtxt<'_>, Span, P<Expr>, P<Expr>, &[P<Expr>]) -> P<Expr>,
1716 B: FnMut(&mut ExtCtxt<'_>, Option<(Span, P<Expr>, &[P<Expr>])>) -> P<Expr>,
1718 match *substructure.fields {
1719 EnumMatching(.., ref all_fields) | Struct(_, ref all_fields) => {
1720 let (base, all_fields) = match (all_fields.is_empty(), use_foldl) {
1722 let field = &all_fields[0];
1723 let args = (field.span, field.self_.clone(), &field.other[..]);
1724 (b(cx, Some(args)), &all_fields[1..])
1727 let idx = all_fields.len() - 1;
1728 let field = &all_fields[idx];
1729 let args = (field.span, field.self_.clone(), &field.other[..]);
1730 (b(cx, Some(args)), &all_fields[..idx])
1732 (true, _) => (b(cx, None), &all_fields[..]),
1735 cs_fold_fields(use_foldl, f, base, cx, all_fields)
1737 EnumNonMatchingCollapsed(..) => {
1738 cs_fold_enumnonmatch(enum_nonmatch_f, cx, trait_span, substructure)
1740 StaticEnum(..) | StaticStruct(..) => cs_fold_static(cx, trait_span),
1744 /// Returns `true` if the type has no value fields
1745 /// (for an enum, no variant has any fields)
1746 pub fn is_type_without_fields(item: &Annotatable) -> bool {
1747 if let Annotatable::Item(ref item) = *item {
1749 ast::ItemKind::Enum(ref enum_def, _) => {
1750 enum_def.variants.iter().all(|v| v.data.fields().is_empty())
1752 ast::ItemKind::Struct(ref variant_data, _) => variant_data.fields().is_empty(),