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 /// This method helps to extract all the type parameters referenced from a
336 /// type. For a type parameter `<T>`, it looks for either a `TyPath` that
337 /// is not global and starts with `T`, or a `TyQPath`.
338 fn find_type_parameters(
340 ty_param_names
: &[Symbol
],
342 ) -> Vec
<P
<ast
::Ty
>> {
343 use rustc_ast
::visit
;
345 struct Visitor
<'a
, 'b
> {
347 ty_param_names
: &'a
[Symbol
],
348 types
: Vec
<P
<ast
::Ty
>>,
351 impl<'a
, 'b
> visit
::Visitor
<'a
> for Visitor
<'a
, 'b
> {
352 fn visit_ty(&mut self, ty
: &'a ast
::Ty
) {
353 if let ast
::TyKind
::Path(_
, ref path
) = ty
.kind
{
354 if let Some(segment
) = path
.segments
.first() {
355 if self.ty_param_names
.contains(&segment
.ident
.name
) {
356 self.types
.push(P(ty
.clone()));
361 visit
::walk_ty(self, ty
)
364 fn visit_mac_call(&mut self, mac
: &ast
::MacCall
) {
365 self.cx
.span_err(mac
.span(), "`derive` cannot be used on items with type macros");
369 let mut visitor
= Visitor { cx, ty_param_names, types: Vec::new() }
;
370 visit
::Visitor
::visit_ty(&mut visitor
, ty
);
375 impl<'a
> TraitDef
<'a
> {
378 cx
: &mut ExtCtxt
<'_
>,
379 mitem
: &ast
::MetaItem
,
380 item
: &'a Annotatable
,
381 push
: &mut dyn FnMut(Annotatable
),
383 self.expand_ext(cx
, mitem
, item
, push
, false);
388 cx
: &mut ExtCtxt
<'_
>,
389 mitem
: &ast
::MetaItem
,
390 item
: &'a Annotatable
,
391 push
: &mut dyn FnMut(Annotatable
),
395 Annotatable
::Item(ref item
) => {
396 let is_packed
= item
.attrs
.iter().any(|attr
| {
397 for r
in attr
::find_repr_attrs(&cx
.sess
, attr
) {
398 if let attr
::ReprPacked(_
) = r
{
404 let has_no_type_params
= match item
.kind
{
405 ast
::ItemKind
::Struct(_
, ref generics
)
406 | ast
::ItemKind
::Enum(_
, ref generics
)
407 | ast
::ItemKind
::Union(_
, ref generics
) => !generics
410 .any(|param
| matches
!(param
.kind
, ast
::GenericParamKind
::Type { .. }
)),
413 let container_id
= cx
.current_expansion
.id
.expn_data().parent
.expect_local();
414 let always_copy
= has_no_type_params
&& cx
.resolver
.has_derive_copy(container_id
);
415 let use_temporaries
= is_packed
&& always_copy
;
417 let newitem
= match item
.kind
{
418 ast
::ItemKind
::Struct(ref struct_def
, ref generics
) => self.expand_struct_def(
426 ast
::ItemKind
::Enum(ref enum_def
, ref generics
) => {
427 // We ignore `use_temporaries` here, because
428 // `repr(packed)` enums cause an error later on.
430 // This can only cause further compilation errors
431 // downstream in blatantly illegal code, so it
433 self.expand_enum_def(cx
, enum_def
, item
.ident
, generics
, from_scratch
)
435 ast
::ItemKind
::Union(ref struct_def
, ref generics
) => {
436 if self.supports_unions
{
437 self.expand_struct_def(
446 cx
.span_err(mitem
.span
, "this trait cannot be derived for unions");
452 // Keep the lint attributes of the previous item to control how the
453 // generated implementations are linted
454 let mut attrs
= newitem
.attrs
.clone();
467 .contains(&a
.name_or_empty())
471 push(Annotatable
::Item(P(ast
::Item { attrs, ..(*newitem).clone() }
)))
477 /// Given that we are deriving a trait `DerivedTrait` for a type like:
479 /// ```ignore (only-for-syntax-highlight)
480 /// struct Struct<'a, ..., 'z, A, B: DeclaredTrait, C, ..., Z> where C: WhereTrait {
483 /// b1: <B as DeclaredTrait>::Item,
484 /// c1: <C as WhereTrait>::Item,
485 /// c2: Option<<C as WhereTrait>::Item>,
490 /// create an impl like:
492 /// ```ignore (only-for-syntax-highlight)
493 /// impl<'a, ..., 'z, A, B: DeclaredTrait, C, ... Z> where
495 /// A: DerivedTrait + B1 + ... + BN,
496 /// B: DerivedTrait + B1 + ... + BN,
497 /// C: DerivedTrait + B1 + ... + BN,
498 /// B::Item: DerivedTrait + B1 + ... + BN,
499 /// <C as WhereTrait>::Item: DerivedTrait + B1 + ... + BN,
506 /// where B1, ..., BN are the bounds given by `bounds_paths`.'. Z is a phantom type, and
507 /// therefore does not get bound by the derived trait.
508 fn create_derived_impl(
510 cx
: &mut ExtCtxt
<'_
>,
513 field_tys
: Vec
<P
<ast
::Ty
>>,
514 methods
: Vec
<P
<ast
::AssocItem
>>,
516 let trait_path
= self.path
.to_path(cx
, self.span
, type_ident
, generics
);
518 // Transform associated types from `deriving::ty::Ty` into `ast::AssocItem`
519 let associated_types
= self.associated_types
.iter().map(|&(ident
, ref type_def
)| {
521 id
: ast
::DUMMY_NODE_ID
,
524 vis
: ast
::Visibility
{
525 span
: self.span
.shrink_to_lo(),
526 kind
: ast
::VisibilityKind
::Inherited
,
530 kind
: ast
::AssocItemKind
::TyAlias(Box
::new(ast
::TyAliasKind(
531 ast
::Defaultness
::Final
,
534 Some(type_def
.to_ty(cx
, self.span
, type_ident
, generics
)),
540 let Generics { mut params, mut where_clause, span }
=
541 self.generics
.to_generics(cx
, self.span
, type_ident
, generics
);
543 // Create the generic parameters
544 params
.extend(generics
.params
.iter().map(|param
| match ¶m
.kind
{
545 GenericParamKind
::Lifetime { .. }
=> param
.clone(),
546 GenericParamKind
::Type { .. }
=> {
547 // I don't think this can be moved out of the loop, since
548 // a GenericBound requires an ast id
550 // extra restrictions on the generics parameters to the
551 // type being derived upon
552 self.additional_bounds
.iter().map(|p
| {
553 cx
.trait_bound(p
.to_path(cx
, self.span
, type_ident
, generics
))
555 // require the current trait
556 iter
::once(cx
.trait_bound(trait_path
.clone()))
558 // also add in any bounds from the declaration
559 param
.bounds
.iter().cloned()
562 cx
.typaram(self.span
, param
.ident
, vec
![], bounds
, None
)
564 GenericParamKind
::Const { ty, kw_span, .. }
=> {
565 let const_nodefault_kind
= GenericParamKind
::Const
{
567 kw_span
: kw_span
.clone(),
569 // We can't have default values inside impl block
572 let mut param_clone
= param
.clone();
573 param_clone
.kind
= const_nodefault_kind
;
578 // and similarly for where clauses
579 where_clause
.predicates
.extend(generics
.where_clause
.predicates
.iter().map(|clause
| {
581 ast
::WherePredicate
::BoundPredicate(ref wb
) => {
582 ast
::WherePredicate
::BoundPredicate(ast
::WhereBoundPredicate
{
584 bound_generic_params
: wb
.bound_generic_params
.clone(),
585 bounded_ty
: wb
.bounded_ty
.clone(),
586 bounds
: wb
.bounds
.to_vec(),
589 ast
::WherePredicate
::RegionPredicate(ref rb
) => {
590 ast
::WherePredicate
::RegionPredicate(ast
::WhereRegionPredicate
{
592 lifetime
: rb
.lifetime
,
593 bounds
: rb
.bounds
.to_vec(),
596 ast
::WherePredicate
::EqPredicate(ref we
) => {
597 ast
::WherePredicate
::EqPredicate(ast
::WhereEqPredicate
{
598 id
: ast
::DUMMY_NODE_ID
,
600 lhs_ty
: we
.lhs_ty
.clone(),
601 rhs_ty
: we
.rhs_ty
.clone(),
608 // Extra scope required here so ty_params goes out of scope before params is moved
610 let mut ty_params
= params
612 .filter(|param
| matches
!(param
.kind
, ast
::GenericParamKind
::Type { .. }
))
615 if ty_params
.peek().is_some() {
616 let ty_param_names
: Vec
<Symbol
> =
617 ty_params
.map(|ty_param
| ty_param
.ident
.name
).collect();
619 for field_ty
in field_tys
{
620 let tys
= find_type_parameters(&field_ty
, &ty_param_names
, cx
);
623 // if we have already handled this type, skip it
624 if let ast
::TyKind
::Path(_
, ref p
) = ty
.kind
{
625 if p
.segments
.len() == 1
626 && ty_param_names
.contains(&p
.segments
[0].ident
.name
)
631 let mut bounds
: Vec
<_
> = self
634 .map(|p
| cx
.trait_bound(p
.to_path(cx
, self.span
, type_ident
, generics
)))
637 // require the current trait
638 bounds
.push(cx
.trait_bound(trait_path
.clone()));
640 let predicate
= ast
::WhereBoundPredicate
{
642 bound_generic_params
: Vec
::new(),
647 let predicate
= ast
::WherePredicate
::BoundPredicate(predicate
);
648 where_clause
.predicates
.push(predicate
);
654 let trait_generics
= Generics { params, where_clause, span }
;
656 // Create the reference to the trait.
657 let trait_ref
= cx
.trait_ref(trait_path
);
659 let self_params
: Vec
<_
> = generics
662 .map(|param
| match param
.kind
{
663 GenericParamKind
::Lifetime { .. }
=> {
664 GenericArg
::Lifetime(cx
.lifetime(self.span
, param
.ident
))
666 GenericParamKind
::Type { .. }
=> {
667 GenericArg
::Type(cx
.ty_ident(self.span
, param
.ident
))
669 GenericParamKind
::Const { .. }
=> {
670 GenericArg
::Const(cx
.const_ident(self.span
, param
.ident
))
675 // Create the type of `self`.
676 let path
= cx
.path_all(self.span
, false, vec
![type_ident
], self_params
);
677 let self_type
= cx
.ty_path(path
);
679 let attr
= cx
.attribute(cx
.meta_word(self.span
, sym
::automatically_derived
));
680 let opt_trait_ref
= Some(trait_ref
);
682 let word
= rustc_ast
::attr
::mk_nested_word_item(Ident
::new(
683 sym
::unused_qualifications
,
686 let list
= rustc_ast
::attr
::mk_list_item(Ident
::new(sym
::allow
, self.span
), vec
![word
]);
690 let mut a
= vec
![attr
, unused_qual
];
691 a
.extend(self.attributes
.iter().cloned());
693 let unsafety
= if self.is_unsafe { ast::Unsafe::Yes(self.span) }
else { ast::Unsafe::No }
;
699 ast
::ItemKind
::Impl(Box
::new(ast
::ImplKind
{
701 polarity
: ast
::ImplPolarity
::Positive
,
702 defaultness
: ast
::Defaultness
::Final
,
703 constness
: ast
::Const
::No
,
704 generics
: trait_generics
,
705 of_trait
: opt_trait_ref
,
707 items
: methods
.into_iter().chain(associated_types
).collect(),
712 fn expand_struct_def(
714 cx
: &mut ExtCtxt
<'_
>,
715 struct_def
: &'a VariantData
,
719 use_temporaries
: bool
,
721 let field_tys
: Vec
<P
<ast
::Ty
>> =
722 struct_def
.fields().iter().map(|field
| field
.ty
.clone()).collect();
728 let (explicit_self
, self_args
, nonself_args
, tys
) =
729 method_def
.split_self_nonself_args(cx
, self, type_ident
, generics
);
731 let body
= if from_scratch
|| method_def
.is_static() {
732 method_def
.expand_static_struct_method_body(
741 method_def
.expand_struct_method_body(
752 method_def
.create_method(cx
, self, type_ident
, generics
, explicit_self
, tys
, body
)
756 self.create_derived_impl(cx
, type_ident
, generics
, field_tys
, methods
)
761 cx
: &mut ExtCtxt
<'_
>,
762 enum_def
: &'a EnumDef
,
767 let mut field_tys
= Vec
::new();
769 for variant
in &enum_def
.variants
{
770 field_tys
.extend(variant
.data
.fields().iter().map(|field
| field
.ty
.clone()));
777 let (explicit_self
, self_args
, nonself_args
, tys
) =
778 method_def
.split_self_nonself_args(cx
, self, type_ident
, generics
);
780 let body
= if from_scratch
|| method_def
.is_static() {
781 method_def
.expand_static_enum_method_body(
790 method_def
.expand_enum_method_body(
800 method_def
.create_method(cx
, self, type_ident
, generics
, explicit_self
, tys
, body
)
804 self.create_derived_impl(cx
, type_ident
, generics
, field_tys
, methods
)
808 impl<'a
> MethodDef
<'a
> {
809 fn call_substructure_method(
811 cx
: &mut ExtCtxt
<'_
>,
812 trait_
: &TraitDef
<'_
>,
814 self_args
: &[P
<Expr
>],
815 nonself_args
: &[P
<Expr
>],
816 fields
: &SubstructureFields
<'_
>,
818 let substructure
= Substructure
{
820 method_ident
: Ident
::new(self.name
, trait_
.span
),
825 let mut f
= self.combine_substructure
.borrow_mut();
826 let f
: &mut CombineSubstructureFunc
<'_
> = &mut *f
;
827 f(cx
, trait_
.span
, &substructure
)
832 cx
: &mut ExtCtxt
<'_
>,
833 trait_
: &TraitDef
<'_
>,
837 self.ret_ty
.to_ty(cx
, trait_
.span
, type_ident
, generics
)
840 fn is_static(&self) -> bool
{
841 self.explicit_self
.is_none()
844 fn split_self_nonself_args(
846 cx
: &mut ExtCtxt
<'_
>,
847 trait_
: &TraitDef
<'_
>,
850 ) -> (Option
<ast
::ExplicitSelf
>, Vec
<P
<Expr
>>, Vec
<P
<Expr
>>, Vec
<(Ident
, P
<ast
::Ty
>)>) {
851 let mut self_args
= Vec
::new();
852 let mut nonself_args
= Vec
::new();
853 let mut arg_tys
= Vec
::new();
854 let mut nonstatic
= false;
856 let ast_explicit_self
= self.explicit_self
.as_ref().map(|self_ptr
| {
857 let (self_expr
, explicit_self
) = ty
::get_explicit_self(cx
, trait_
.span
, self_ptr
);
859 self_args
.push(self_expr
);
865 for (ty
, name
) in self.args
.iter() {
866 let ast_ty
= ty
.to_ty(cx
, trait_
.span
, type_ident
, generics
);
867 let ident
= Ident
::new(*name
, trait_
.span
);
868 arg_tys
.push((ident
, ast_ty
));
870 let arg_expr
= cx
.expr_ident(trait_
.span
, ident
);
873 // for static methods, just treat any Self
874 // arguments as a normal arg
875 Self_
if nonstatic
=> {
876 self_args
.push(arg_expr
);
878 Ptr(ref ty
, _
) if matches
!(**ty
, Self_
) && nonstatic
=> {
879 self_args
.push(cx
.expr_deref(trait_
.span
, arg_expr
))
882 nonself_args
.push(arg_expr
);
887 (ast_explicit_self
, self_args
, nonself_args
, arg_tys
)
892 cx
: &mut ExtCtxt
<'_
>,
893 trait_
: &TraitDef
<'_
>,
896 explicit_self
: Option
<ast
::ExplicitSelf
>,
897 arg_types
: Vec
<(Ident
, P
<ast
::Ty
>)>,
899 ) -> P
<ast
::AssocItem
> {
900 // Create the generics that aren't for `Self`.
901 let fn_generics
= self.generics
.to_generics(cx
, trait_
.span
, type_ident
, generics
);
904 let self_args
= explicit_self
.map(|explicit_self
| {
905 let ident
= Ident
::with_dummy_span(kw
::SelfLower
).with_span_pos(trait_
.span
);
906 ast
::Param
::from_self(ast
::AttrVec
::default(), explicit_self
, ident
)
909 arg_types
.into_iter().map(|(name
, ty
)| cx
.param(trait_
.span
, name
, ty
));
910 self_args
.into_iter().chain(nonself_args
).collect()
913 let ret_type
= self.get_ret_ty(cx
, trait_
, generics
, type_ident
);
915 let method_ident
= Ident
::new(self.name
, trait_
.span
);
916 let fn_decl
= cx
.fn_decl(args
, ast
::FnRetTy
::Ty(ret_type
));
917 let body_block
= cx
.block_expr(body
);
919 let unsafety
= if self.is_unsafe { ast::Unsafe::Yes(trait_.span) }
else { ast::Unsafe::No }
;
921 let trait_lo_sp
= trait_
.span
.shrink_to_lo();
923 let sig
= ast
::FnSig
{
924 header
: ast
::FnHeader { unsafety, ext: ast::Extern::None, ..ast::FnHeader::default() }
,
928 let def
= ast
::Defaultness
::Final
;
930 // Create the method.
932 id
: ast
::DUMMY_NODE_ID
,
933 attrs
: self.attributes
.clone(),
935 vis
: ast
::Visibility
{
937 kind
: ast
::VisibilityKind
::Inherited
,
941 kind
: ast
::AssocItemKind
::Fn(Box
::new(ast
::FnKind(
952 /// #[derive(PartialEq)]
954 /// struct A { x: i32, y: i32 }
956 /// // equivalent to:
957 /// impl PartialEq for A {
958 /// fn eq(&self, other: &A) -> bool {
960 /// A {x: ref __self_0_0, y: ref __self_0_1} => {
962 /// A {x: ref __self_1_0, y: ref __self_1_1} => {
963 /// __self_0_0.eq(__self_1_0) && __self_0_1.eq(__self_1_1)
971 /// // or if A is repr(packed) - note fields are matched by-value
972 /// // instead of by-reference.
973 /// impl PartialEq for A {
974 /// fn eq(&self, other: &A) -> bool {
976 /// A {x: __self_0_0, y: __self_0_1} => {
978 /// A {x: __self_1_0, y: __self_1_1} => {
979 /// __self_0_0.eq(&__self_1_0) && __self_0_1.eq(&__self_1_1)
987 fn expand_struct_method_body
<'b
>(
989 cx
: &mut ExtCtxt
<'_
>,
990 trait_
: &TraitDef
<'b
>,
991 struct_def
: &'b VariantData
,
993 self_args
: &[P
<Expr
>],
994 nonself_args
: &[P
<Expr
>],
995 use_temporaries
: bool
,
997 let mut raw_fields
= Vec
::new(); // Vec<[fields of self],
998 // [fields of next Self arg], [etc]>
999 let mut patterns
= Vec
::new();
1000 for i
in 0..self_args
.len() {
1001 let struct_path
= cx
.path(trait_
.span
, vec
![type_ident
]);
1002 let (pat
, ident_expr
) = trait_
.create_struct_pattern(
1006 &format
!("__self_{}", i
),
1007 ast
::Mutability
::Not
,
1011 raw_fields
.push(ident_expr
);
1014 // transpose raw_fields
1015 let fields
= if !raw_fields
.is_empty() {
1016 let mut raw_fields
= raw_fields
.into_iter().map(|v
| v
.into_iter());
1017 let first_field
= raw_fields
.next().unwrap();
1018 let mut other_fields
: Vec
<vec
::IntoIter
<_
>> = raw_fields
.collect();
1020 .map(|(span
, opt_id
, field
, attrs
)| FieldInfo
{
1027 let (.., ex
, _
) = l
.next().unwrap();
1035 cx
.span_bug(trait_
.span
, "no `self` parameter for method in generic `derive`")
1038 // body of the inner most destructuring match
1039 let mut body
= self.call_substructure_method(
1045 &Struct(struct_def
, fields
),
1048 // make a series of nested matches, to destructure the
1049 // structs. This is actually right-to-left, but it shouldn't
1051 for (arg_expr
, pat
) in iter
::zip(self_args
, patterns
) {
1052 body
= cx
.expr_match(
1055 vec
![cx
.arm(trait_
.span
, pat
.clone(), body
)],
1062 fn expand_static_struct_method_body(
1064 cx
: &mut ExtCtxt
<'_
>,
1065 trait_
: &TraitDef
<'_
>,
1066 struct_def
: &VariantData
,
1068 self_args
: &[P
<Expr
>],
1069 nonself_args
: &[P
<Expr
>],
1071 let summary
= trait_
.summarise_struct(cx
, struct_def
);
1073 self.call_substructure_method(
1079 &StaticStruct(struct_def
, summary
),
1084 /// #[derive(PartialEq)]
1091 /// // is equivalent to
1093 /// impl PartialEq for A {
1094 /// fn eq(&self, other: &A) -> ::bool {
1095 /// match (&*self, &*other) {
1096 /// (&A1, &A1) => true,
1097 /// (&A2(ref self_0),
1098 /// &A2(ref __arg_1_0)) => (*self_0).eq(&(*__arg_1_0)),
1100 /// let __self_vi = match *self { A1(..) => 0, A2(..) => 1 };
1101 /// let __arg_1_vi = match *other { A1(..) => 0, A2(..) => 1 };
1109 /// (Of course `__self_vi` and `__arg_1_vi` are unused for
1110 /// `PartialEq`, and those subcomputations will hopefully be removed
1111 /// as their results are unused. The point of `__self_vi` and
1112 /// `__arg_1_vi` is for `PartialOrd`; see #15503.)
1113 fn expand_enum_method_body
<'b
>(
1115 cx
: &mut ExtCtxt
<'_
>,
1116 trait_
: &TraitDef
<'b
>,
1117 enum_def
: &'b EnumDef
,
1119 self_args
: Vec
<P
<Expr
>>,
1120 nonself_args
: &[P
<Expr
>],
1122 self.build_enum_match_tuple(cx
, trait_
, enum_def
, type_ident
, self_args
, nonself_args
)
1125 /// Creates a match for a tuple of all `self_args`, where either all
1126 /// variants match, or it falls into a catch-all for when one variant
1129 /// There are N + 1 cases because is a case for each of the N
1130 /// variants where all of the variants match, and one catch-all for
1131 /// when one does not match.
1133 /// As an optimization we generate code which checks whether all variants
1134 /// match first which makes llvm see that C-like enums can be compiled into
1135 /// a simple equality check (for PartialEq).
1137 /// The catch-all handler is provided access the variant index values
1138 /// for each of the self-args, carried in precomputed variables.
1141 /// let __self0_vi = std::intrinsics::discriminant_value(&self);
1142 /// let __self1_vi = std::intrinsics::discriminant_value(&arg1);
1143 /// let __self2_vi = std::intrinsics::discriminant_value(&arg2);
1145 /// if __self0_vi == __self1_vi && __self0_vi == __self2_vi && ... {
1147 /// (Variant1, Variant1, ...) => Body1
1148 /// (Variant2, Variant2, ...) => Body2,
1150 /// _ => ::core::intrinsics::unreachable()
1154 /// ... // catch-all remainder can inspect above variant index values.
1157 fn build_enum_match_tuple
<'b
>(
1159 cx
: &mut ExtCtxt
<'_
>,
1160 trait_
: &TraitDef
<'b
>,
1161 enum_def
: &'b EnumDef
,
1163 mut self_args
: Vec
<P
<Expr
>>,
1164 nonself_args
: &[P
<Expr
>],
1166 let sp
= trait_
.span
;
1167 let variants
= &enum_def
.variants
;
1169 let self_arg_names
= iter
::once("__self".to_string())
1175 .map(|(arg_count
, _self_arg
)| format
!("__arg_{}", arg_count
)),
1177 .collect
::<Vec
<String
>>();
1179 let self_arg_idents
= self_arg_names
1181 .map(|name
| Ident
::from_str_and_span(name
, sp
))
1182 .collect
::<Vec
<Ident
>>();
1184 // The `vi_idents` will be bound, solely in the catch-all, to
1185 // a series of let statements mapping each self_arg to an int
1186 // value corresponding to its discriminant.
1187 let vi_idents
= self_arg_names
1190 let vi_suffix
= format
!("{}_vi", &name
[..]);
1191 Ident
::from_str_and_span(&vi_suffix
, trait_
.span
)
1193 .collect
::<Vec
<Ident
>>();
1195 // Builds, via callback to call_substructure_method, the
1196 // delegated expression that handles the catch-all case,
1197 // using `__variants_tuple` to drive logic if necessary.
1198 let catch_all_substructure
=
1199 EnumNonMatchingCollapsed(self_arg_idents
, &variants
[..], &vi_idents
[..]);
1201 let first_fieldless
= variants
.iter().find(|v
| v
.data
.fields().is_empty());
1203 // These arms are of the form:
1204 // (Variant1, Variant1, ...) => Body1
1205 // (Variant2, Variant2, ...) => Body2
1207 // where each tuple has length = self_args.len()
1208 let mut match_arms
: Vec
<ast
::Arm
> = variants
1211 .filter(|&(_
, v
)| !(self.unify_fieldless_variants
&& v
.data
.fields().is_empty()))
1212 .map(|(index
, variant
)| {
1213 let mk_self_pat
= |cx
: &mut ExtCtxt
<'_
>, self_arg_name
: &str| {
1214 let (p
, idents
) = trait_
.create_enum_variant_pattern(
1219 ast
::Mutability
::Not
,
1221 (cx
.pat(sp
, PatKind
::Ref(p
, ast
::Mutability
::Not
)), idents
)
1224 // A single arm has form (&VariantK, &VariantK, ...) => BodyK
1225 // (see "Final wrinkle" note below for why.)
1226 let mut subpats
= Vec
::with_capacity(self_arg_names
.len());
1227 let mut self_pats_idents
= Vec
::with_capacity(self_arg_names
.len() - 1);
1228 let first_self_pat_idents
= {
1229 let (p
, idents
) = mk_self_pat(cx
, &self_arg_names
[0]);
1233 for self_arg_name
in &self_arg_names
[1..] {
1234 let (p
, idents
) = mk_self_pat(cx
, &self_arg_name
[..]);
1236 self_pats_idents
.push(idents
);
1239 // Here is the pat = `(&VariantK, &VariantK, ...)`
1240 let single_pat
= cx
.pat_tuple(sp
, subpats
);
1242 // For the BodyK, we need to delegate to our caller,
1243 // passing it an EnumMatching to indicate which case
1246 // All of the Self args have the same variant in these
1247 // cases. So we transpose the info in self_pats_idents
1248 // to gather the getter expressions together, in the
1249 // form that EnumMatching expects.
1251 // The transposition is driven by walking across the
1252 // arg fields of the variant for the first self pat.
1253 let field_tuples
= first_self_pat_idents
1256 // For each arg field of self, pull out its getter expr ...
1257 .map(|(field_index
, (sp
, opt_ident
, self_getter_expr
, attrs
))| {
1258 // ... but FieldInfo also wants getter expr
1259 // for matching other arguments of Self type;
1260 // so walk across the *other* self_pats_idents
1261 // and pull out getter for same field in each
1262 // of them (using `field_index` tracked above).
1263 // That is the heart of the transposition.
1264 let others
= self_pats_idents
1267 let (_
, _opt_ident
, ref other_getter_expr
, _
) = fields
[field_index
];
1269 // All Self args have same variant, so
1270 // opt_idents are the same. (Assert
1271 // here to make it self-evident that
1272 // it is okay to ignore `_opt_ident`.)
1273 assert
!(opt_ident
== _opt_ident
);
1275 other_getter_expr
.clone()
1277 .collect
::<Vec
<P
<Expr
>>>();
1282 self_
: self_getter_expr
,
1287 .collect
::<Vec
<FieldInfo
<'_
>>>();
1289 // Now, for some given VariantK, we have built up
1290 // expressions for referencing every field of every
1291 // Self arg, assuming all are instances of VariantK.
1292 // Build up code associated with such a case.
1293 let substructure
= EnumMatching(index
, variants
.len(), variant
, field_tuples
);
1294 let arm_expr
= self.call_substructure_method(
1303 cx
.arm(sp
, single_pat
, arm_expr
)
1307 let default = match first_fieldless
{
1308 Some(v
) if self.unify_fieldless_variants
=> {
1309 // We need a default case that handles the fieldless variants.
1310 // The index and actual variant aren't meaningful in this case,
1311 // so just use whatever
1312 let substructure
= EnumMatching(0, variants
.len(), v
, Vec
::new());
1313 Some(self.call_substructure_method(
1322 _
if variants
.len() > 1 && self_args
.len() > 1 => {
1323 // Since we know that all the arguments will match if we reach
1324 // the match expression we add the unreachable intrinsics as the
1325 // result of the catch all which should help llvm in optimizing it
1326 Some(deriving
::call_unreachable(cx
, sp
))
1330 if let Some(arm
) = default {
1331 match_arms
.push(cx
.arm(sp
, cx
.pat_wild(sp
), arm
));
1334 // We will usually need the catch-all after matching the
1335 // tuples `(VariantK, VariantK, ...)` for each VariantK of the
1338 // * when there is only one Self arg, the arms above suffice
1339 // (and the deriving we call back into may not be prepared to
1340 // handle EnumNonMatchCollapsed), and,
1342 // * when the enum has only one variant, the single arm that
1343 // is already present always suffices.
1345 // * In either of the two cases above, if we *did* add a
1346 // catch-all `_` match, it would trigger the
1347 // unreachable-pattern error.
1349 if variants
.len() > 1 && self_args
.len() > 1 {
1350 // Build a series of let statements mapping each self_arg
1351 // to its discriminant value.
1353 // i.e., for `enum E<T> { A, B(1), C(T, T) }`, and a deriving
1354 // with three Self args, builds three statements:
1357 // let __self0_vi = std::intrinsics::discriminant_value(&self);
1358 // let __self1_vi = std::intrinsics::discriminant_value(&arg1);
1359 // let __self2_vi = std::intrinsics::discriminant_value(&arg2);
1361 let mut index_let_stmts
: Vec
<ast
::Stmt
> = Vec
::with_capacity(vi_idents
.len() + 1);
1363 // We also build an expression which checks whether all discriminants are equal
1364 // discriminant_test = __self0_vi == __self1_vi && __self0_vi == __self2_vi && ...
1365 let mut discriminant_test
= cx
.expr_bool(sp
, true);
1367 let mut first_ident
= None
;
1368 for (&ident
, self_arg
) in iter
::zip(&vi_idents
, &self_args
) {
1369 let self_addr
= cx
.expr_addr_of(sp
, self_arg
.clone());
1371 deriving
::call_intrinsic(cx
, sp
, sym
::discriminant_value
, vec
![self_addr
]);
1372 let let_stmt
= cx
.stmt_let(sp
, false, ident
, variant_value
);
1373 index_let_stmts
.push(let_stmt
);
1377 let first_expr
= cx
.expr_ident(sp
, first
);
1378 let id
= cx
.expr_ident(sp
, ident
);
1379 let test
= cx
.expr_binary(sp
, BinOpKind
::Eq
, first_expr
, id
);
1381 cx
.expr_binary(sp
, BinOpKind
::And
, discriminant_test
, test
)
1384 first_ident
= Some(ident
);
1389 let arm_expr
= self.call_substructure_method(
1395 &catch_all_substructure
,
1398 // Final wrinkle: the self_args are expressions that deref
1399 // down to desired places, but we cannot actually deref
1400 // them when they are fed as r-values into a tuple
1401 // expression; here add a layer of borrowing, turning
1402 // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
1403 self_args
.map_in_place(|self_arg
| cx
.expr_addr_of(sp
, self_arg
));
1404 let match_arg
= cx
.expr(sp
, ast
::ExprKind
::Tup(self_args
));
1406 // Lastly we create an expression which branches on all discriminants being equal
1407 // if discriminant_test {
1409 // (Variant1, Variant1, ...) => Body1
1410 // (Variant2, Variant2, ...) => Body2,
1412 // _ => ::core::intrinsics::unreachable()
1416 // <delegated expression referring to __self0_vi, et al.>
1418 let all_match
= cx
.expr_match(sp
, match_arg
, match_arms
);
1419 let arm_expr
= cx
.expr_if(sp
, discriminant_test
, all_match
, Some(arm_expr
));
1420 index_let_stmts
.push(cx
.stmt_expr(arm_expr
));
1421 cx
.expr_block(cx
.block(sp
, index_let_stmts
))
1422 } else if variants
.is_empty() {
1423 // As an additional wrinkle, For a zero-variant enum A,
1424 // currently the compiler
1425 // will accept `fn (a: &Self) { match *a { } }`
1426 // but rejects `fn (a: &Self) { match (&*a,) { } }`
1427 // as well as `fn (a: &Self) { match ( *a,) { } }`
1429 // This means that the strategy of building up a tuple of
1430 // all Self arguments fails when Self is a zero variant
1431 // enum: rustc rejects the expanded program, even though
1432 // the actual code tends to be impossible to execute (at
1433 // least safely), according to the type system.
1435 // The most expedient fix for this is to just let the
1436 // code fall through to the catch-all. But even this is
1437 // error-prone, since the catch-all as defined above would
1438 // generate code like this:
1440 // _ => { let __self0 = match *self { };
1441 // let __self1 = match *__arg_0 { };
1442 // <catch-all-expr> }
1444 // Which is yields bindings for variables which type
1445 // inference cannot resolve to unique types.
1447 // One option to the above might be to add explicit type
1448 // annotations. But the *only* reason to go down that path
1449 // would be to try to make the expanded output consistent
1450 // with the case when the number of enum variants >= 1.
1452 // That just isn't worth it. In fact, trying to generate
1453 // sensible code for *any* deriving on a zero-variant enum
1454 // does not make sense. But at the same time, for now, we
1455 // do not want to cause a compile failure just because the
1456 // user happened to attach a deriving to their
1457 // zero-variant enum.
1459 // Instead, just generate a failing expression for the
1460 // zero variant case, skipping matches and also skipping
1461 // delegating back to the end user code entirely.
1463 // (See also #4499 and #12609; note that some of the
1464 // discussions there influence what choice we make here;
1465 // e.g., if we feature-gate `match x { ... }` when x refers
1466 // to an uninhabited type (e.g., a zero-variant enum or a
1467 // type holding such an enum), but do not feature-gate
1468 // zero-variant enums themselves, then attempting to
1469 // derive Debug on such a type could here generate code
1470 // that needs the feature gate enabled.)
1472 deriving
::call_unreachable(cx
, sp
)
1474 // Final wrinkle: the self_args are expressions that deref
1475 // down to desired places, but we cannot actually deref
1476 // them when they are fed as r-values into a tuple
1477 // expression; here add a layer of borrowing, turning
1478 // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
1479 self_args
.map_in_place(|self_arg
| cx
.expr_addr_of(sp
, self_arg
));
1480 let match_arg
= cx
.expr(sp
, ast
::ExprKind
::Tup(self_args
));
1481 cx
.expr_match(sp
, match_arg
, match_arms
)
1485 fn expand_static_enum_method_body(
1487 cx
: &mut ExtCtxt
<'_
>,
1488 trait_
: &TraitDef
<'_
>,
1491 self_args
: &[P
<Expr
>],
1492 nonself_args
: &[P
<Expr
>],
1494 let summary
= enum_def
1498 let sp
= v
.span
.with_ctxt(trait_
.span
.ctxt());
1499 let summary
= trait_
.summarise_struct(cx
, &v
.data
);
1500 (v
.ident
, sp
, summary
)
1503 self.call_substructure_method(
1509 &StaticEnum(enum_def
, summary
),
1514 // general helper methods.
1515 impl<'a
> TraitDef
<'a
> {
1516 fn summarise_struct(&self, cx
: &mut ExtCtxt
<'_
>, struct_def
: &VariantData
) -> StaticFields
{
1517 let mut named_idents
= Vec
::new();
1518 let mut just_spans
= Vec
::new();
1519 for field
in struct_def
.fields() {
1520 let sp
= field
.span
.with_ctxt(self.span
.ctxt());
1522 Some(ident
) => named_idents
.push((ident
, sp
)),
1523 _
=> just_spans
.push(sp
),
1527 let is_tuple
= matches
!(struct_def
, ast
::VariantData
::Tuple(..));
1528 match (just_spans
.is_empty(), named_idents
.is_empty()) {
1529 (false, false) => cx
.span_bug(
1531 "a struct with named and unnamed \
1532 fields in generic `derive`",
1535 (_
, false) => Named(named_idents
),
1537 (false, _
) => Unnamed(just_spans
, is_tuple
),
1539 _
=> Named(Vec
::new()),
1543 fn create_subpatterns(
1545 cx
: &mut ExtCtxt
<'_
>,
1546 field_paths
: Vec
<Ident
>,
1547 mutbl
: ast
::Mutability
,
1548 use_temporaries
: bool
,
1549 ) -> Vec
<P
<ast
::Pat
>> {
1553 let binding_mode
= if use_temporaries
{
1554 ast
::BindingMode
::ByValue(ast
::Mutability
::Not
)
1556 ast
::BindingMode
::ByRef(mutbl
)
1558 cx
.pat(path
.span
, PatKind
::Ident(binding_mode
, *path
, None
))
1563 fn create_struct_pattern(
1565 cx
: &mut ExtCtxt
<'_
>,
1566 struct_path
: ast
::Path
,
1567 struct_def
: &'a VariantData
,
1569 mutbl
: ast
::Mutability
,
1570 use_temporaries
: bool
,
1571 ) -> (P
<ast
::Pat
>, Vec
<(Span
, Option
<Ident
>, P
<Expr
>, &'a
[ast
::Attribute
])>) {
1572 let mut paths
= Vec
::new();
1573 let mut ident_exprs
= Vec
::new();
1574 for (i
, struct_field
) in struct_def
.fields().iter().enumerate() {
1575 let sp
= struct_field
.span
.with_ctxt(self.span
.ctxt());
1576 let ident
= Ident
::from_str_and_span(&format
!("{}_{}", prefix
, i
), self.span
);
1577 paths
.push(ident
.with_span_pos(sp
));
1578 let val
= cx
.expr_path(cx
.path_ident(sp
, ident
));
1579 let val
= if use_temporaries { val }
else { cx.expr_deref(sp, val) }
;
1580 let val
= cx
.expr(sp
, ast
::ExprKind
::Paren(val
));
1582 ident_exprs
.push((sp
, struct_field
.ident
, val
, &struct_field
.attrs
[..]));
1585 let subpats
= self.create_subpatterns(cx
, paths
, mutbl
, use_temporaries
);
1586 let pattern
= match *struct_def
{
1587 VariantData
::Struct(..) => {
1588 let field_pats
= iter
::zip(subpats
, &ident_exprs
)
1589 .map(|(pat
, &(sp
, ident
, ..))| {
1590 if ident
.is_none() {
1591 cx
.span_bug(sp
, "a braced struct with unnamed fields in `derive`");
1594 ident
: ident
.unwrap(),
1595 is_shorthand
: false,
1596 attrs
: ast
::AttrVec
::new(),
1597 id
: ast
::DUMMY_NODE_ID
,
1598 span
: pat
.span
.with_ctxt(self.span
.ctxt()),
1600 is_placeholder
: false,
1604 cx
.pat_struct(self.span
, struct_path
, field_pats
)
1606 VariantData
::Tuple(..) => cx
.pat_tuple_struct(self.span
, struct_path
, subpats
),
1607 VariantData
::Unit(..) => cx
.pat_path(self.span
, struct_path
),
1610 (pattern
, ident_exprs
)
1613 fn create_enum_variant_pattern(
1615 cx
: &mut ExtCtxt
<'_
>,
1617 variant
: &'a ast
::Variant
,
1619 mutbl
: ast
::Mutability
,
1620 ) -> (P
<ast
::Pat
>, Vec
<(Span
, Option
<Ident
>, P
<Expr
>, &'a
[ast
::Attribute
])>) {
1621 let sp
= variant
.span
.with_ctxt(self.span
.ctxt());
1622 let variant_path
= cx
.path(sp
, vec
![enum_ident
, variant
.ident
]);
1623 let use_temporaries
= false; // enums can't be repr(packed)
1624 self.create_struct_pattern(cx
, variant_path
, &variant
.data
, prefix
, mutbl
, use_temporaries
)
1628 // helpful premade recipes
1630 pub fn cs_fold_fields
<'a
, F
>(
1634 cx
: &mut ExtCtxt
<'_
>,
1635 all_fields
: &[FieldInfo
<'a
>],
1638 F
: FnMut(&mut ExtCtxt
<'_
>, Span
, P
<Expr
>, P
<Expr
>, &[P
<Expr
>]) -> P
<Expr
>,
1643 .fold(base
, |old
, field
| f(cx
, field
.span
, old
, field
.self_
.clone(), &field
.other
))
1648 .fold(base
, |old
, field
| f(cx
, field
.span
, old
, field
.self_
.clone(), &field
.other
))
1652 pub fn cs_fold_enumnonmatch(
1653 mut enum_nonmatch_f
: EnumNonMatchCollapsedFunc
<'_
>,
1654 cx
: &mut ExtCtxt
<'_
>,
1656 substructure
: &Substructure
<'_
>,
1658 match *substructure
.fields
{
1659 EnumNonMatchingCollapsed(ref all_args
, _
, tuple
) => {
1660 enum_nonmatch_f(cx
, trait_span
, (&all_args
[..], tuple
), substructure
.nonself_args
)
1662 _
=> cx
.span_bug(trait_span
, "cs_fold_enumnonmatch expected an EnumNonMatchingCollapsed"),
1666 pub fn cs_fold_static(cx
: &mut ExtCtxt
<'_
>, trait_span
: Span
) -> P
<Expr
> {
1667 cx
.span_bug(trait_span
, "static function in `derive`")
1670 /// Fold the fields. `use_foldl` controls whether this is done
1671 /// left-to-right (`true`) or right-to-left (`false`).
1676 enum_nonmatch_f
: EnumNonMatchCollapsedFunc
<'_
>,
1677 cx
: &mut ExtCtxt
<'_
>,
1679 substructure
: &Substructure
<'_
>,
1682 F
: FnMut(&mut ExtCtxt
<'_
>, Span
, P
<Expr
>, P
<Expr
>, &[P
<Expr
>]) -> P
<Expr
>,
1684 match *substructure
.fields
{
1685 EnumMatching(.., ref all_fields
) | Struct(_
, ref all_fields
) => {
1686 cs_fold_fields(use_foldl
, f
, base
, cx
, all_fields
)
1688 EnumNonMatchingCollapsed(..) => {
1689 cs_fold_enumnonmatch(enum_nonmatch_f
, cx
, trait_span
, substructure
)
1691 StaticEnum(..) | StaticStruct(..) => cs_fold_static(cx
, trait_span
),
1695 /// Function to fold over fields, with three cases, to generate more efficient and concise code.
1696 /// When the `substructure` has grouped fields, there are two cases:
1697 /// Zero fields: call the base case function with `None` (like the usual base case of `cs_fold`).
1698 /// One or more fields: call the base case function on the first value (which depends on
1699 /// `use_fold`), and use that as the base case. Then perform `cs_fold` on the remainder of the
1701 /// When the `substructure` is an `EnumNonMatchingCollapsed`, the result of `enum_nonmatch_f`
1702 /// is returned. Statics may not be folded over.
1703 /// See `cs_op` in `partial_ord.rs` for a model example.
1704 pub fn cs_fold1
<F
, B
>(
1708 enum_nonmatch_f
: EnumNonMatchCollapsedFunc
<'_
>,
1709 cx
: &mut ExtCtxt
<'_
>,
1711 substructure
: &Substructure
<'_
>,
1714 F
: FnMut(&mut ExtCtxt
<'_
>, Span
, P
<Expr
>, P
<Expr
>, &[P
<Expr
>]) -> P
<Expr
>,
1715 B
: FnMut(&mut ExtCtxt
<'_
>, Option
<(Span
, P
<Expr
>, &[P
<Expr
>])>) -> P
<Expr
>,
1717 match *substructure
.fields
{
1718 EnumMatching(.., ref all_fields
) | Struct(_
, ref all_fields
) => {
1719 let (base
, all_fields
) = match (all_fields
.is_empty(), use_foldl
) {
1721 let field
= &all_fields
[0];
1722 let args
= (field
.span
, field
.self_
.clone(), &field
.other
[..]);
1723 (b(cx
, Some(args
)), &all_fields
[1..])
1726 let idx
= all_fields
.len() - 1;
1727 let field
= &all_fields
[idx
];
1728 let args
= (field
.span
, field
.self_
.clone(), &field
.other
[..]);
1729 (b(cx
, Some(args
)), &all_fields
[..idx
])
1731 (true, _
) => (b(cx
, None
), &all_fields
[..]),
1734 cs_fold_fields(use_foldl
, f
, base
, cx
, all_fields
)
1736 EnumNonMatchingCollapsed(..) => {
1737 cs_fold_enumnonmatch(enum_nonmatch_f
, cx
, trait_span
, substructure
)
1739 StaticEnum(..) | StaticStruct(..) => cs_fold_static(cx
, trait_span
),
1743 /// Returns `true` if the type has no value fields
1744 /// (for an enum, no variant has any fields)
1745 pub fn is_type_without_fields(item
: &Annotatable
) -> bool
{
1746 if let Annotatable
::Item(ref item
) = *item
{
1748 ast
::ItemKind
::Enum(ref enum_def
, _
) => {
1749 enum_def
.variants
.iter().all(|v
| v
.data
.fields().is_empty())
1751 ast
::ItemKind
::Struct(ref variant_data
, _
) => variant_data
.fields().is_empty(),