Module rustc_builtin_macros::deriving::generic[][src]

Expand description

Some code that abstracts away much of the boilerplate of writing derive instances for traits. Among other things it manages getting access to the fields of the 4 different sorts of structs and enum variants, as well as creating the method and impl ast instances.

Supported features (fairly exhaustive):

  • Methods taking any number of parameters of any type, and returning any type, other than vectors, bottom and closures.
  • Generating impls for types with type parameters and lifetimes (e.g., Option<T>), the parameters are automatically given the current trait as a bound. (This includes separate type parameters and lifetimes for methods.)
  • Additional bounds on the type parameters (TraitDef.additional_bounds)

The most important thing for implementors is the Substructure and SubstructureFields objects. The latter groups 5 possibilities of the arguments:

  • Struct, when Self is a struct (including tuple structs, e.g struct T(i32, char)).
  • EnumMatching, when Self is an enum and all the arguments are the same variant of the enum (e.g., Some(1), Some(3) and Some(4))
  • EnumNonMatchingCollapsed when Self is an enum and the arguments are not the same variant (e.g., None, Some(1) and None).
  • StaticEnum and StaticStruct for static methods, where the type being derived upon is either an enum or struct respectively. (Any argument with type Self is just grouped among the non-self arguments.)

In the first two cases, the values from the corresponding fields in all the arguments are grouped together. For EnumNonMatchingCollapsed this isn’t possible (different variants have different fields), so the fields are inaccessible. (Previous versions of the deriving infrastructure had a way to expand into code that could access them, at the cost of generating exponential amounts of code; see issue #15375). There are no fields with values in the static cases, so these are treated entirely differently.

The non-static cases have Option<ident> in several places associated with field exprs. This represents the name of the field it is associated with. It is only not None when the associated field has an identifier in the source code. For example, the xs in the following snippet

struct A { x : i32 }

struct B(i32);

enum C {
    C0(i32),
    C1 { x: i32 }
}

The i32s in B and C0 don’t have an identifier, so the Option<ident>s would be None for them.

In the static cases, the structure is summarized, either into the just spans of the fields or a list of spans and the field idents (for tuple structs and record structs, respectively), or a list of these, for enums (one for each variant). For empty struct and empty enum variants, it is represented as a count of 0.

cs” functions

The cs_... functions (“combine substructure) are designed to make life easier by providing some pre-made recipes for common threads; mostly calling the function being derived on all the arguments and then combining them back together in some way (or letting the user chose that). They are not meant to be the only way to handle the structures that this code creates.

Examples

The following simplified PartialEq is used for in-code examples:

trait PartialEq {
    fn eq(&self, other: &Self) -> bool;
}
impl PartialEq for i32 {
    fn eq(&self, other: &i32) -> bool {
        *self == *other
    }
}

Some examples of the values of SubstructureFields follow, using the above PartialEq, A, B and C.

Structs

When generating the expr for the A impl, the SubstructureFields is

Struct(vec![FieldInfo {
           span: <span of x>
           name: Some(<ident of x>),
           self_: <expr for &self.x>,
           other: vec![<expr for &other.x]
         }])

For the B impl, called with B(a) and B(b),

Struct(vec![FieldInfo {
          span: <span of `i32`>,
          name: None,
          self_: <expr for &a>
          other: vec![<expr for &b>]
         }])

Enums

When generating the expr for a call with self == C0(a) and other == C0(b), the SubstructureFields is

EnumMatching(0, <ast::Variant for C0>,
             vec![FieldInfo {
                span: <span of i32>
                name: None,
                self_: <expr for &a>,
                other: vec![<expr for &b>]
              }])

For C1 {x} and C1 {x},

EnumMatching(1, <ast::Variant for C1>,
             vec![FieldInfo {
                span: <span of x>
                name: Some(<ident of x>),
                self_: <expr for &self.x>,
                other: vec![<expr for &other.x>]
               }])

For C0(a) and C1 {x} ,

EnumNonMatchingCollapsed(
    vec![<ident of self>, <ident of __arg_1>],
    &[<ast::Variant for C0>, <ast::Variant for C1>],
    &[<ident for self index value>, <ident of __arg_1 index value>])

It is the same for when the arguments are flipped to C1 {x} and C0(a); the only difference is what the values of the identifiers and will be in the generated code.

EnumNonMatchingCollapsed deliberately provides far less information than is generally available for a given pair of variants; see #15375 for discussion.

Static

A static method on the types above would result in,

StaticStruct(<ast::VariantData of A>, Named(vec![(<ident of x>, <span of x>)]))

StaticStruct(<ast::VariantData of B>, Unnamed(vec![<span of x>]))

StaticEnum(<ast::EnumDef of C>,
           vec![(<ident of C0>, <span of C0>, Unnamed(vec![<span of i32>])),
                (<ident of C1>, <span of C1>, Named(vec![(<ident of x>, <span of x>)]))])

Re-exports

pub use StaticFields::*;
pub use SubstructureFields::*;

Modules

A mini version of ast::Ty, which is easier to use, and features an explicit Self type to use when specifying impls to be derived.

Structs

Summary of the relevant parts of a struct/enum field.

All the data about the data structure/method being derived upon.

Enums

Fields for a static method

A summary of the possible sets of fields.

Functions

Fold the fields. use_foldl controls whether this is done left-to-right (true) or right-to-left (false).

Function to fold over fields, with three cases, to generate more efficient and concise code. When the substructure has grouped fields, there are two cases: Zero fields: call the base case function with None (like the usual base case of cs_fold). One or more fields: call the base case function on the first value (which depends on use_fold), and use that as the base case. Then perform cs_fold on the remainder of the fields. When the substructure is an EnumNonMatchingCollapsed, the result of enum_nonmatch_f is returned. Statics may not be folded over. See cs_op in partial_ord.rs for a model example.

This method helps to extract all the type parameters referenced from a type. For a type parameter <T>, it looks for either a TyPath that is not global and starts with T, or a TyQPath. Also include bound generic params from the input type.

Returns true if the type has no value fields (for an enum, no variant has any fields)

Type Definitions

Combine the values of all the fields together. The last argument is all the fields of all the structures.

Deal with non-matching enum variants. The tuple is a list of identifiers (one for each Self argument, which could be any of the variants since they have been collapsed together) and the identifiers holding the variant index value for each of the Self arguments. The last argument is all the non-Self args of the method being derived.