2014-06-09 20:12:30 +00:00
|
|
|
//! Some code that abstracts away much of the boilerplate of writing
|
2014-12-31 04:25:18 +00:00
|
|
|
//! `derive` instances for traits. Among other things it manages getting
|
2014-06-09 20:12:30 +00:00
|
|
|
//! 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 `impl`s for types with type parameters and lifetimes
|
2018-11-27 02:59:49 +00:00
|
|
|
//! (e.g., `Option<T>`), the parameters are automatically given the
|
2014-06-09 20:12:30 +00:00
|
|
|
//! current trait as a bound. (This includes separate type parameters
|
|
|
|
//! and lifetimes for methods.)
|
2015-01-12 13:00:19 +00:00
|
|
|
//! - Additional bounds on the type parameters (`TraitDef.additional_bounds`)
|
2014-06-09 20:12:30 +00:00
|
|
|
//!
|
2017-08-15 19:45:21 +00:00
|
|
|
//! The most important thing for implementors is the `Substructure` and
|
2014-06-09 20:12:30 +00:00
|
|
|
//! `SubstructureFields` objects. The latter groups 5 possibilities of the
|
|
|
|
//! arguments:
|
|
|
|
//!
|
|
|
|
//! - `Struct`, when `Self` is a struct (including tuple structs, e.g
|
2015-01-17 23:55:21 +00:00
|
|
|
//! `struct T(i32, char)`).
|
2014-06-09 20:12:30 +00:00
|
|
|
//! - `EnumMatching`, when `Self` is an enum and all the arguments are the
|
2018-11-27 02:59:49 +00:00
|
|
|
//! same variant of the enum (e.g., `Some(1)`, `Some(3)` and `Some(4)`)
|
2022-07-08 05:32:27 +00:00
|
|
|
//! - `EnumTag` when `Self` is an enum, for comparing the enum tags.
|
2014-06-09 20:12:30 +00:00
|
|
|
//! - `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
|
2022-07-08 05:32:27 +00:00
|
|
|
//! all the arguments are grouped together.
|
2014-06-09 20:12:30 +00:00
|
|
|
//!
|
|
|
|
//! The non-static cases have `Option<ident>` in several places associated
|
|
|
|
//! with field `expr`s. 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 `x`s in the
|
|
|
|
//! following snippet
|
|
|
|
//!
|
|
|
|
//! ```rust
|
2015-11-03 16:34:11 +00:00
|
|
|
//! # #![allow(dead_code)]
|
2015-01-17 23:55:21 +00:00
|
|
|
//! struct A { x : i32 }
|
2014-06-09 20:12:30 +00:00
|
|
|
//!
|
2015-01-17 23:55:21 +00:00
|
|
|
//! struct B(i32);
|
2014-06-09 20:12:30 +00:00
|
|
|
//!
|
|
|
|
//! enum C {
|
2015-01-17 23:55:21 +00:00
|
|
|
//! C0(i32),
|
|
|
|
//! C1 { x: i32 }
|
2014-06-09 20:12:30 +00:00
|
|
|
//! }
|
|
|
|
//! ```
|
|
|
|
//!
|
2015-01-17 23:55:21 +00:00
|
|
|
//! The `i32`s in `B` and `C0` don't have an identifier, so the
|
2014-06-09 20:12:30 +00:00
|
|
|
//! `Option<ident>`s would be `None` for them.
|
|
|
|
//!
|
2018-11-12 18:05:20 +00:00
|
|
|
//! In the static cases, the structure is summarized, either into the just
|
2014-06-09 20:12:30 +00:00
|
|
|
//! 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.
|
|
|
|
//!
|
2015-01-12 13:00:19 +00:00
|
|
|
//! # "`cs`" functions
|
|
|
|
//!
|
2022-06-23 22:31:00 +00:00
|
|
|
//! The `cs_...` functions ("combine substructure") are designed to
|
2015-01-12 13:00:19 +00:00
|
|
|
//! make life easier by providing some pre-made recipes for common
|
2015-05-08 15:12:29 +00:00
|
|
|
//! threads; mostly calling the function being derived on all the
|
2015-01-12 13:00:19 +00:00
|
|
|
//! 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.
|
|
|
|
//!
|
2014-06-09 20:12:30 +00:00
|
|
|
//! # Examples
|
|
|
|
//!
|
|
|
|
//! The following simplified `PartialEq` is used for in-code examples:
|
|
|
|
//!
|
|
|
|
//! ```rust
|
|
|
|
//! trait PartialEq {
|
2015-11-03 16:34:11 +00:00
|
|
|
//! fn eq(&self, other: &Self) -> bool;
|
2014-06-09 20:12:30 +00:00
|
|
|
//! }
|
2015-01-17 23:55:21 +00:00
|
|
|
//! impl PartialEq for i32 {
|
|
|
|
//! fn eq(&self, other: &i32) -> bool {
|
2014-06-09 20:12:30 +00:00
|
|
|
//! *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
|
|
|
|
//!
|
2014-09-16 11:27:34 +00:00
|
|
|
//! ```{.text}
|
2015-01-12 13:00:19 +00:00
|
|
|
//! Struct(vec![FieldInfo {
|
2014-06-09 20:12:30 +00:00
|
|
|
//! span: <span of x>
|
|
|
|
//! name: Some(<ident of x>),
|
|
|
|
//! self_: <expr for &self.x>,
|
2015-01-12 13:00:19 +00:00
|
|
|
//! other: vec![<expr for &other.x]
|
2014-06-09 20:12:30 +00:00
|
|
|
//! }])
|
2014-09-16 11:27:34 +00:00
|
|
|
//! ```
|
2014-06-09 20:12:30 +00:00
|
|
|
//!
|
|
|
|
//! For the `B` impl, called with `B(a)` and `B(b)`,
|
|
|
|
//!
|
2014-09-16 11:27:34 +00:00
|
|
|
//! ```{.text}
|
2015-01-12 13:00:19 +00:00
|
|
|
//! Struct(vec![FieldInfo {
|
2015-01-17 23:55:21 +00:00
|
|
|
//! span: <span of `i32`>,
|
2014-06-09 20:12:30 +00:00
|
|
|
//! name: None,
|
2015-01-12 13:00:19 +00:00
|
|
|
//! self_: <expr for &a>
|
|
|
|
//! other: vec![<expr for &b>]
|
2014-06-09 20:12:30 +00:00
|
|
|
//! }])
|
2014-09-16 11:27:34 +00:00
|
|
|
//! ```
|
2014-06-09 20:12:30 +00:00
|
|
|
//!
|
|
|
|
//! ## Enums
|
|
|
|
//!
|
|
|
|
//! When generating the `expr` for a call with `self == C0(a)` and `other
|
|
|
|
//! == C0(b)`, the SubstructureFields is
|
|
|
|
//!
|
2014-09-16 11:27:34 +00:00
|
|
|
//! ```{.text}
|
2014-06-09 20:12:30 +00:00
|
|
|
//! EnumMatching(0, <ast::Variant for C0>,
|
2015-01-12 13:00:19 +00:00
|
|
|
//! vec![FieldInfo {
|
2015-01-17 23:55:21 +00:00
|
|
|
//! span: <span of i32>
|
2014-06-09 20:12:30 +00:00
|
|
|
//! name: None,
|
|
|
|
//! self_: <expr for &a>,
|
2015-01-12 13:00:19 +00:00
|
|
|
//! other: vec![<expr for &b>]
|
2014-06-09 20:12:30 +00:00
|
|
|
//! }])
|
2014-09-16 11:27:34 +00:00
|
|
|
//! ```
|
2014-06-09 20:12:30 +00:00
|
|
|
//!
|
2014-07-06 19:19:12 +00:00
|
|
|
//! For `C1 {x}` and `C1 {x}`,
|
2014-06-09 20:12:30 +00:00
|
|
|
//!
|
2014-09-16 11:27:34 +00:00
|
|
|
//! ```{.text}
|
2014-06-09 20:12:30 +00:00
|
|
|
//! EnumMatching(1, <ast::Variant for C1>,
|
2015-01-12 13:00:19 +00:00
|
|
|
//! vec![FieldInfo {
|
2014-06-09 20:12:30 +00:00
|
|
|
//! span: <span of x>
|
|
|
|
//! name: Some(<ident of x>),
|
|
|
|
//! self_: <expr for &self.x>,
|
2015-01-12 13:00:19 +00:00
|
|
|
//! other: vec![<expr for &other.x>]
|
2014-06-09 20:12:30 +00:00
|
|
|
//! }])
|
2014-09-16 11:27:34 +00:00
|
|
|
//! ```
|
2014-06-09 20:12:30 +00:00
|
|
|
//!
|
2022-07-08 05:32:27 +00:00
|
|
|
//! For the tags,
|
2014-06-09 20:12:30 +00:00
|
|
|
//!
|
2014-09-16 11:27:34 +00:00
|
|
|
//! ```{.text}
|
2022-07-08 05:32:27 +00:00
|
|
|
//! EnumTag(
|
|
|
|
//! &[<ident of self tag>, <ident of other tag>], <expr to combine with>)
|
2014-09-16 11:27:34 +00:00
|
|
|
//! ```
|
2022-07-08 05:32:27 +00:00
|
|
|
//! Note that this setup doesn't allow for the brute-force "match every variant
|
|
|
|
//! against every other variant" approach, which is bad because it produces a
|
|
|
|
//! quadratic amount of code (see #15375).
|
2014-06-09 20:12:30 +00:00
|
|
|
//!
|
|
|
|
//! ## Static
|
|
|
|
//!
|
2015-01-12 13:00:19 +00:00
|
|
|
//! A static method on the types above would result in,
|
2014-06-09 20:12:30 +00:00
|
|
|
//!
|
2014-09-16 11:27:34 +00:00
|
|
|
//! ```{.text}
|
2015-10-08 00:20:57 +00:00
|
|
|
//! StaticStruct(<ast::VariantData of A>, Named(vec![(<ident of x>, <span of x>)]))
|
2014-06-09 20:12:30 +00:00
|
|
|
//!
|
2015-10-08 00:20:57 +00:00
|
|
|
//! StaticStruct(<ast::VariantData of B>, Unnamed(vec![<span of x>]))
|
2014-06-09 20:12:30 +00:00
|
|
|
//!
|
2015-01-12 13:00:19 +00:00
|
|
|
//! StaticEnum(<ast::EnumDef of C>,
|
2015-01-17 23:55:21 +00:00
|
|
|
//! vec![(<ident of C0>, <span of C0>, Unnamed(vec![<span of i32>])),
|
2015-01-12 13:00:19 +00:00
|
|
|
//! (<ident of C1>, <span of C1>, Named(vec![(<ident of x>, <span of x>)]))])
|
2014-09-16 11:27:34 +00:00
|
|
|
//! ```
|
2013-03-28 10:50:10 +00:00
|
|
|
|
2019-02-04 12:49:54 +00:00
|
|
|
pub use StaticFields::*;
|
|
|
|
pub use SubstructureFields::*;
|
2014-11-06 08:05:53 +00:00
|
|
|
|
2022-08-17 04:22:30 +00:00
|
|
|
use crate::deriving;
|
2020-02-29 17:37:32 +00:00
|
|
|
use rustc_ast::ptr::P;
|
2022-08-30 22:34:35 +00:00
|
|
|
use rustc_ast::{
|
|
|
|
self as ast, BindingAnnotation, ByRef, EnumDef, Expr, Generics, Mutability, PatKind,
|
|
|
|
};
|
2020-04-27 17:56:11 +00:00
|
|
|
use rustc_ast::{GenericArg, GenericParamKind, VariantData};
|
2020-01-11 12:15:20 +00:00
|
|
|
use rustc_attr as attr;
|
2019-12-29 14:23:55 +00:00
|
|
|
use rustc_expand::base::{Annotatable, ExtCtxt};
|
2020-04-19 11:00:18 +00:00
|
|
|
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
2022-09-20 11:55:07 +00:00
|
|
|
use rustc_span::{Span, DUMMY_SP};
|
2022-08-17 04:22:30 +00:00
|
|
|
use std::cell::RefCell;
|
|
|
|
use std::iter;
|
2022-08-26 12:59:12 +00:00
|
|
|
use std::ops::Not;
|
2022-08-17 04:22:30 +00:00
|
|
|
use std::vec;
|
|
|
|
use thin_vec::thin_vec;
|
2022-06-29 23:15:07 +00:00
|
|
|
use ty::{Bounds, Path, Ref, Self_, Ty};
|
2014-05-29 03:19:05 +00:00
|
|
|
|
|
|
|
pub mod ty;
|
2013-05-06 15:23:51 +00:00
|
|
|
|
2013-12-10 07:16:18 +00:00
|
|
|
pub struct TraitDef<'a> {
|
2014-12-31 04:25:18 +00:00
|
|
|
/// The span for the current #[derive(Foo)] header.
|
2014-03-27 22:39:48 +00:00
|
|
|
pub span: Span,
|
2013-12-07 00:57:44 +00:00
|
|
|
|
2013-05-06 15:23:51 +00:00
|
|
|
/// Path of the trait, including any type parameters
|
2020-07-14 05:05:26 +00:00
|
|
|
pub path: Path,
|
2014-02-09 00:39:53 +00:00
|
|
|
|
2022-08-26 12:59:12 +00:00
|
|
|
/// Whether to skip adding the current trait as a bound to the type parameters of the type.
|
|
|
|
pub skip_path_as_bound: bool,
|
|
|
|
|
2013-05-06 15:23:51 +00:00
|
|
|
/// Additional bounds required of any type parameters of the type,
|
|
|
|
/// other than the current trait
|
2020-07-14 05:05:26 +00:00
|
|
|
pub additional_bounds: Vec<Ty>,
|
2013-05-06 15:23:51 +00:00
|
|
|
|
2016-08-29 11:14:25 +00:00
|
|
|
/// Can this trait be derived for unions?
|
|
|
|
pub supports_unions: bool,
|
|
|
|
|
2014-03-27 22:39:48 +00:00
|
|
|
pub methods: Vec<MethodDef<'a>>,
|
2015-01-25 05:29:24 +00:00
|
|
|
|
2020-07-14 05:05:26 +00:00
|
|
|
pub associated_types: Vec<(Ident, Ty)>,
|
2022-09-20 11:55:07 +00:00
|
|
|
|
|
|
|
pub is_const: bool,
|
2014-03-27 22:39:48 +00:00
|
|
|
}
|
2013-03-28 10:50:10 +00:00
|
|
|
|
2013-12-10 07:16:18 +00:00
|
|
|
pub struct MethodDef<'a> {
|
2013-03-28 10:50:10 +00:00
|
|
|
/// name of the method
|
2020-07-08 01:04:10 +00:00
|
|
|
pub name: Symbol,
|
2018-11-27 02:59:49 +00:00
|
|
|
/// List of generics, e.g., `R: rand::Rng`
|
2020-07-14 05:05:26 +00:00
|
|
|
pub generics: Bounds,
|
2013-05-06 15:23:51 +00:00
|
|
|
|
2022-06-29 23:15:07 +00:00
|
|
|
/// Is there is a `&self` argument? If not, it is a static function.
|
|
|
|
pub explicit_self: bool,
|
2013-05-06 15:23:51 +00:00
|
|
|
|
2022-07-04 22:25:47 +00:00
|
|
|
/// Arguments other than the self argument.
|
|
|
|
pub nonself_args: Vec<(Ty, Symbol)>,
|
2013-05-06 15:23:51 +00:00
|
|
|
|
2019-02-08 13:53:55 +00:00
|
|
|
/// Returns type
|
2020-07-14 05:05:26 +00:00
|
|
|
pub ret_ty: Ty,
|
2013-03-28 10:50:10 +00:00
|
|
|
|
2022-08-17 02:34:33 +00:00
|
|
|
pub attributes: ast::AttrVec,
|
2013-11-19 00:13:34 +00:00
|
|
|
|
2016-05-12 15:54:05 +00:00
|
|
|
/// Can we combine fieldless variants for enums into a single match arm?
|
2022-07-08 05:32:27 +00:00
|
|
|
/// If true, indicates that the trait operation uses the enum tag in some
|
|
|
|
/// way.
|
2016-05-12 15:54:05 +00:00
|
|
|
pub unify_fieldless_variants: bool,
|
|
|
|
|
2014-04-22 06:25:18 +00:00
|
|
|
pub combine_substructure: RefCell<CombineSubstructureFunc<'a>>,
|
2013-03-28 10:50:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// All the data about the data structure/method being derived upon.
|
2013-12-10 07:16:18 +00:00
|
|
|
pub struct Substructure<'a> {
|
2013-05-06 15:23:51 +00:00
|
|
|
/// ident of self
|
2014-03-27 22:39:48 +00:00
|
|
|
pub type_ident: Ident,
|
2022-07-07 21:57:34 +00:00
|
|
|
/// Verbatim access to any non-selflike arguments, i.e. arguments that
|
|
|
|
/// don't have type `&Self`.
|
2022-07-04 22:25:47 +00:00
|
|
|
pub nonselflike_args: &'a [P<Expr>],
|
2016-07-19 17:32:06 +00:00
|
|
|
pub fields: &'a SubstructureFields<'a>,
|
2013-03-28 10:50:10 +00:00
|
|
|
}
|
|
|
|
|
2013-11-07 07:49:01 +00:00
|
|
|
/// Summary of the relevant parts of a struct/enum field.
|
2022-07-04 22:59:17 +00:00
|
|
|
pub struct FieldInfo {
|
2014-03-27 22:39:48 +00:00
|
|
|
pub span: Span,
|
2013-11-07 07:49:01 +00:00
|
|
|
/// None for tuple structs/normal enum variants, Some for normal
|
|
|
|
/// structs/struct enum variants.
|
2014-03-27 22:39:48 +00:00
|
|
|
pub name: Option<Ident>,
|
2013-11-07 07:49:01 +00:00
|
|
|
/// The expression corresponding to this field of `self`
|
|
|
|
/// (specifically, a reference to it).
|
2022-07-04 22:47:04 +00:00
|
|
|
pub self_expr: P<Expr>,
|
2013-11-07 07:49:01 +00:00
|
|
|
/// The expressions corresponding to references to this field in
|
2022-07-04 22:47:04 +00:00
|
|
|
/// the other selflike arguments.
|
|
|
|
pub other_selflike_exprs: Vec<P<Expr>>,
|
2014-03-27 22:39:48 +00:00
|
|
|
}
|
2013-11-07 07:49:01 +00:00
|
|
|
|
|
|
|
/// Fields for a static method
|
|
|
|
pub enum StaticFields {
|
2016-08-15 18:28:17 +00:00
|
|
|
/// Tuple and unit structs/enum variants like this.
|
|
|
|
Unnamed(Vec<Span>, bool /*is tuple*/),
|
2013-11-07 07:49:01 +00:00
|
|
|
/// Normal structs/struct variants.
|
2014-05-16 07:16:13 +00:00
|
|
|
Named(Vec<(Ident, Span)>),
|
2013-11-07 07:49:01 +00:00
|
|
|
}
|
|
|
|
|
2014-09-17 13:12:58 +00:00
|
|
|
/// A summary of the possible sets of fields.
|
2013-12-10 07:16:18 +00:00
|
|
|
pub enum SubstructureFields<'a> {
|
2022-07-08 05:32:27 +00:00
|
|
|
/// A non-static method with `Self` is a struct.
|
2022-07-04 22:59:17 +00:00
|
|
|
Struct(&'a ast::VariantData, Vec<FieldInfo>),
|
2022-07-08 05:32:27 +00:00
|
|
|
|
2017-06-16 19:59:20 +00:00
|
|
|
/// Matching variants of the enum: variant index, variant count, ast::Variant,
|
2014-09-16 11:27:34 +00:00
|
|
|
/// fields: the field name is only non-`None` in the case of a struct
|
|
|
|
/// variant.
|
2022-07-04 22:59:17 +00:00
|
|
|
EnumMatching(usize, usize, &'a ast::Variant, Vec<FieldInfo>),
|
2013-03-28 10:50:10 +00:00
|
|
|
|
2022-07-08 05:32:27 +00:00
|
|
|
/// The tag of an enum. The first field is a `FieldInfo` for the tags, as
|
|
|
|
/// if they were fields. The second field is the expression to combine the
|
|
|
|
/// tag expression with; it will be `None` if no match is necessary.
|
|
|
|
EnumTag(FieldInfo, Option<P<Expr>>),
|
2014-07-06 19:19:12 +00:00
|
|
|
|
2014-09-17 13:02:26 +00:00
|
|
|
/// A static method where `Self` is a struct.
|
2015-10-08 00:20:57 +00:00
|
|
|
StaticStruct(&'a ast::VariantData, StaticFields),
|
2022-07-08 05:32:27 +00:00
|
|
|
|
2014-09-17 13:02:26 +00:00
|
|
|
/// A static method where `Self` is an enum.
|
2014-05-16 07:16:13 +00:00
|
|
|
StaticEnum(&'a ast::EnumDef, Vec<(Ident, Span, StaticFields)>),
|
2013-03-28 10:50:10 +00:00
|
|
|
}
|
|
|
|
|
2014-09-16 11:27:34 +00:00
|
|
|
/// Combine the values of all the fields together. The last argument is
|
2014-09-17 13:12:58 +00:00
|
|
|
/// all the fields of all the structures.
|
2013-12-10 07:16:18 +00:00
|
|
|
pub type CombineSubstructureFunc<'a> =
|
2022-06-28 03:10:36 +00:00
|
|
|
Box<dyn FnMut(&mut ExtCtxt<'_>, Span, &Substructure<'_>) -> BlockOrExpr + 'a>;
|
2013-03-28 10:50:10 +00:00
|
|
|
|
2019-06-21 16:51:27 +00:00
|
|
|
pub fn combine_substructure(
|
|
|
|
f: CombineSubstructureFunc<'_>,
|
|
|
|
) -> RefCell<CombineSubstructureFunc<'_>> {
|
2014-04-22 06:25:18 +00:00
|
|
|
RefCell::new(f)
|
|
|
|
}
|
|
|
|
|
2021-09-28 22:46:29 +00:00
|
|
|
struct TypeParameter {
|
|
|
|
bound_generic_params: Vec<ast::GenericParam>,
|
|
|
|
ty: P<ast::Ty>,
|
|
|
|
}
|
|
|
|
|
2022-11-27 11:15:06 +00:00
|
|
|
/// The code snippets built up for derived code are sometimes used as blocks
|
|
|
|
/// (e.g. in a function body) and sometimes used as expressions (e.g. in a match
|
|
|
|
/// arm). This structure avoids committing to either form until necessary,
|
|
|
|
/// avoiding the insertion of any unnecessary blocks.
|
|
|
|
///
|
|
|
|
/// The statements come before the expression.
|
2022-06-28 03:10:36 +00:00
|
|
|
pub struct BlockOrExpr(Vec<ast::Stmt>, Option<P<Expr>>);
|
|
|
|
|
|
|
|
impl BlockOrExpr {
|
|
|
|
pub fn new_stmts(stmts: Vec<ast::Stmt>) -> BlockOrExpr {
|
|
|
|
BlockOrExpr(stmts, None)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn new_expr(expr: P<Expr>) -> BlockOrExpr {
|
|
|
|
BlockOrExpr(vec![], Some(expr))
|
|
|
|
}
|
|
|
|
|
2022-07-08 05:32:27 +00:00
|
|
|
pub fn new_mixed(stmts: Vec<ast::Stmt>, expr: Option<P<Expr>>) -> BlockOrExpr {
|
|
|
|
BlockOrExpr(stmts, expr)
|
2022-06-28 03:10:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Converts it into a block.
|
|
|
|
fn into_block(mut self, cx: &ExtCtxt<'_>, span: Span) -> P<ast::Block> {
|
|
|
|
if let Some(expr) = self.1 {
|
|
|
|
self.0.push(cx.stmt_expr(expr));
|
|
|
|
}
|
|
|
|
cx.block(span, self.0)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Converts it into an expression.
|
|
|
|
fn into_expr(self, cx: &ExtCtxt<'_>, span: Span) -> P<Expr> {
|
|
|
|
if self.0.is_empty() {
|
|
|
|
match self.1 {
|
|
|
|
None => cx.expr_block(cx.block(span, vec![])),
|
|
|
|
Some(expr) => expr,
|
|
|
|
}
|
2022-07-08 05:27:42 +00:00
|
|
|
} else if self.0.len() == 1
|
|
|
|
&& let ast::StmtKind::Expr(expr) = &self.0[0].kind
|
|
|
|
&& self.1.is_none()
|
|
|
|
{
|
|
|
|
// There's only a single statement expression. Pull it out.
|
|
|
|
expr.clone()
|
2022-06-28 03:10:36 +00:00
|
|
|
} else {
|
2022-07-08 05:27:42 +00:00
|
|
|
// Multiple statements and/or expressions.
|
2022-06-28 03:10:36 +00:00
|
|
|
cx.expr_block(self.into_block(cx, span))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-24 21:43:26 +00:00
|
|
|
/// 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`.
|
2021-09-28 22:46:29 +00:00
|
|
|
/// Also include bound generic params from the input type.
|
2019-06-16 09:41:24 +00:00
|
|
|
fn find_type_parameters(
|
|
|
|
ty: &ast::Ty,
|
2020-04-19 11:00:18 +00:00
|
|
|
ty_param_names: &[Symbol],
|
2019-06-16 09:41:24 +00:00
|
|
|
cx: &ExtCtxt<'_>,
|
2021-09-28 22:46:29 +00:00
|
|
|
) -> Vec<TypeParameter> {
|
2020-02-29 17:37:32 +00:00
|
|
|
use rustc_ast::visit;
|
2015-03-24 21:43:26 +00:00
|
|
|
|
2019-06-14 16:39:39 +00:00
|
|
|
struct Visitor<'a, 'b> {
|
2016-06-24 03:23:44 +00:00
|
|
|
cx: &'a ExtCtxt<'b>,
|
2020-04-19 11:00:18 +00:00
|
|
|
ty_param_names: &'a [Symbol],
|
2021-09-28 22:46:29 +00:00
|
|
|
bound_generic_params_stack: Vec<ast::GenericParam>,
|
|
|
|
type_params: Vec<TypeParameter>,
|
2015-03-24 21:43:26 +00:00
|
|
|
}
|
|
|
|
|
2016-12-06 10:26:52 +00:00
|
|
|
impl<'a, 'b> visit::Visitor<'a> for Visitor<'a, 'b> {
|
|
|
|
fn visit_ty(&mut self, ty: &'a ast::Ty) {
|
2022-12-06 13:22:36 +00:00
|
|
|
if let ast::TyKind::Path(_, path) = &ty.kind
|
|
|
|
&& let Some(segment) = path.segments.first()
|
|
|
|
&& self.ty_param_names.contains(&segment.ident.name)
|
|
|
|
{
|
|
|
|
self.type_params.push(TypeParameter {
|
|
|
|
bound_generic_params: self.bound_generic_params_stack.clone(),
|
|
|
|
ty: P(ty.clone()),
|
|
|
|
});
|
2015-03-24 21:43:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
visit::walk_ty(self, ty)
|
|
|
|
}
|
2016-06-24 03:23:44 +00:00
|
|
|
|
2021-09-28 22:46:29 +00:00
|
|
|
// Place bound generic params on a stack, to extract them when a type is encountered.
|
2022-08-11 01:05:26 +00:00
|
|
|
fn visit_poly_trait_ref(&mut self, trait_ref: &'a ast::PolyTraitRef) {
|
2021-09-29 01:18:56 +00:00
|
|
|
let stack_len = self.bound_generic_params_stack.len();
|
2022-08-13 13:50:01 +00:00
|
|
|
self.bound_generic_params_stack.extend(trait_ref.bound_generic_params.iter().cloned());
|
2021-09-28 22:46:29 +00:00
|
|
|
|
2022-08-11 01:05:26 +00:00
|
|
|
visit::walk_poly_trait_ref(self, trait_ref);
|
2021-09-28 22:46:29 +00:00
|
|
|
|
|
|
|
self.bound_generic_params_stack.truncate(stack_len);
|
|
|
|
}
|
|
|
|
|
2020-11-03 17:34:57 +00:00
|
|
|
fn visit_mac_call(&mut self, mac: &ast::MacCall) {
|
2019-12-01 12:55:32 +00:00
|
|
|
self.cx.span_err(mac.span(), "`derive` cannot be used on items with type macros");
|
2016-06-24 03:23:44 +00:00
|
|
|
}
|
2015-03-24 21:43:26 +00:00
|
|
|
}
|
|
|
|
|
2021-09-28 22:46:29 +00:00
|
|
|
let mut visitor = Visitor {
|
|
|
|
cx,
|
|
|
|
ty_param_names,
|
|
|
|
bound_generic_params_stack: Vec::new(),
|
|
|
|
type_params: Vec::new(),
|
|
|
|
};
|
2015-03-24 21:43:26 +00:00
|
|
|
visit::Visitor::visit_ty(&mut visitor, ty);
|
|
|
|
|
2021-09-28 22:46:29 +00:00
|
|
|
visitor.type_params
|
2015-03-24 21:43:26 +00:00
|
|
|
}
|
2013-03-28 10:50:10 +00:00
|
|
|
|
2013-12-10 07:16:18 +00:00
|
|
|
impl<'a> TraitDef<'a> {
|
2017-10-02 13:15:23 +00:00
|
|
|
pub fn expand(
|
|
|
|
self,
|
2019-02-04 12:49:54 +00:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
2015-03-27 01:07:49 +00:00
|
|
|
mitem: &ast::MetaItem,
|
2015-05-12 02:15:02 +00:00
|
|
|
item: &'a Annotatable,
|
2018-07-12 09:58:16 +00:00
|
|
|
push: &mut dyn FnMut(Annotatable),
|
|
|
|
) {
|
2016-08-26 16:23:42 +00:00
|
|
|
self.expand_ext(cx, mitem, item, push, false);
|
|
|
|
}
|
|
|
|
|
2017-10-02 13:15:23 +00:00
|
|
|
pub fn expand_ext(
|
|
|
|
self,
|
2019-02-04 12:49:54 +00:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
2016-08-26 16:23:42 +00:00
|
|
|
mitem: &ast::MetaItem,
|
|
|
|
item: &'a Annotatable,
|
2018-07-12 09:58:16 +00:00
|
|
|
push: &mut dyn FnMut(Annotatable),
|
2016-08-26 16:23:42 +00:00
|
|
|
from_scratch: bool,
|
|
|
|
) {
|
2022-12-06 13:22:36 +00:00
|
|
|
match item {
|
|
|
|
Annotatable::Item(item) => {
|
2017-10-02 13:15:23 +00:00
|
|
|
let is_packed = item.attrs.iter().any(|attr| {
|
2020-07-30 01:27:50 +00:00
|
|
|
for r in attr::find_repr_attrs(&cx.sess, attr) {
|
2018-02-04 11:10:28 +00:00
|
|
|
if let attr::ReprPacked(_) = r {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
false
|
2017-10-02 13:15:23 +00:00
|
|
|
});
|
2022-12-06 13:22:36 +00:00
|
|
|
let has_no_type_params = match &item.kind {
|
|
|
|
ast::ItemKind::Struct(_, generics)
|
|
|
|
| ast::ItemKind::Enum(_, generics)
|
|
|
|
| ast::ItemKind::Union(_, generics) => !generics
|
2020-12-24 01:55:21 +00:00
|
|
|
.params
|
|
|
|
.iter()
|
|
|
|
.any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })),
|
2020-11-18 22:55:59 +00:00
|
|
|
_ => unreachable!(),
|
2017-11-19 15:04:24 +00:00
|
|
|
};
|
2021-06-25 18:43:04 +00:00
|
|
|
let container_id = cx.current_expansion.id.expn_data().parent.expect_local();
|
2022-11-21 00:48:25 +00:00
|
|
|
let copy_fields =
|
|
|
|
is_packed && has_no_type_params && cx.resolver.has_derive_copy(container_id);
|
2017-11-19 15:04:24 +00:00
|
|
|
|
2022-12-06 13:22:36 +00:00
|
|
|
let newitem = match &item.kind {
|
|
|
|
ast::ItemKind::Struct(struct_def, generics) => self.expand_struct_def(
|
2017-10-02 13:15:23 +00:00
|
|
|
cx,
|
|
|
|
&struct_def,
|
|
|
|
item.ident,
|
|
|
|
generics,
|
|
|
|
from_scratch,
|
2022-11-21 00:48:25 +00:00
|
|
|
copy_fields,
|
2019-12-22 22:42:04 +00:00
|
|
|
),
|
2022-12-06 13:22:36 +00:00
|
|
|
ast::ItemKind::Enum(enum_def, generics) => {
|
2022-11-21 00:48:25 +00:00
|
|
|
// We ignore `is_packed` here, because `repr(packed)`
|
|
|
|
// enums cause an error later on.
|
2017-10-02 13:15:23 +00:00
|
|
|
//
|
|
|
|
// This can only cause further compilation errors
|
2022-11-21 00:48:25 +00:00
|
|
|
// downstream in blatantly illegal code, so it is fine.
|
2020-04-05 18:36:39 +00:00
|
|
|
self.expand_enum_def(cx, enum_def, item.ident, generics, from_scratch)
|
2015-04-28 05:34:39 +00:00
|
|
|
}
|
2022-12-06 13:22:36 +00:00
|
|
|
ast::ItemKind::Union(struct_def, generics) => {
|
2016-08-24 18:10:19 +00:00
|
|
|
if self.supports_unions {
|
2016-08-26 16:23:42 +00:00
|
|
|
self.expand_struct_def(
|
|
|
|
cx,
|
|
|
|
&struct_def,
|
|
|
|
item.ident,
|
2017-10-02 13:15:23 +00:00
|
|
|
generics,
|
|
|
|
from_scratch,
|
2022-11-21 00:48:25 +00:00
|
|
|
copy_fields,
|
2017-10-02 13:15:23 +00:00
|
|
|
)
|
2016-08-24 18:10:19 +00:00
|
|
|
} else {
|
|
|
|
cx.span_err(mitem.span, "this trait cannot be derived for unions");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2017-11-19 15:04:24 +00:00
|
|
|
_ => unreachable!(),
|
2015-04-28 05:34:39 +00:00
|
|
|
};
|
|
|
|
// Keep the lint attributes of the previous item to control how the
|
|
|
|
// generated implementations are linted
|
|
|
|
let mut attrs = newitem.attrs.clone();
|
2016-07-19 17:32:06 +00:00
|
|
|
attrs.extend(
|
|
|
|
item.attrs
|
|
|
|
.iter()
|
2019-03-17 11:17:47 +00:00
|
|
|
.filter(|a| {
|
2019-05-08 04:33:06 +00:00
|
|
|
[
|
|
|
|
sym::allow,
|
|
|
|
sym::warn,
|
|
|
|
sym::deny,
|
|
|
|
sym::forbid,
|
|
|
|
sym::stable,
|
|
|
|
sym::unstable,
|
|
|
|
]
|
|
|
|
.contains(&a.name_or_empty())
|
2019-03-17 11:17:47 +00:00
|
|
|
})
|
2016-07-19 17:32:06 +00:00
|
|
|
.cloned(),
|
|
|
|
);
|
2020-03-06 18:28:44 +00:00
|
|
|
push(Annotatable::Item(P(ast::Item { attrs, ..(*newitem).clone() })))
|
2014-02-13 07:53:52 +00:00
|
|
|
}
|
2020-11-18 22:55:59 +00:00
|
|
|
_ => unreachable!(),
|
2015-04-28 05:34:39 +00:00
|
|
|
}
|
2013-06-07 07:46:44 +00:00
|
|
|
}
|
|
|
|
|
2015-03-24 21:43:26 +00:00
|
|
|
/// Given that we are deriving a trait `DerivedTrait` for a type like:
|
2014-09-16 11:27:34 +00:00
|
|
|
///
|
2017-06-20 07:15:16 +00:00
|
|
|
/// ```ignore (only-for-syntax-highlight)
|
2015-03-24 21:43:26 +00:00
|
|
|
/// struct Struct<'a, ..., 'z, A, B: DeclaredTrait, C, ..., Z> where C: WhereTrait {
|
|
|
|
/// a: A,
|
|
|
|
/// b: B::Item,
|
|
|
|
/// b1: <B as DeclaredTrait>::Item,
|
|
|
|
/// c1: <C as WhereTrait>::Item,
|
|
|
|
/// c2: Option<<C as WhereTrait>::Item>,
|
|
|
|
/// ...
|
|
|
|
/// }
|
2014-09-16 11:27:34 +00:00
|
|
|
/// ```
|
|
|
|
///
|
2015-03-24 21:43:26 +00:00
|
|
|
/// create an impl like:
|
|
|
|
///
|
2017-06-20 07:15:16 +00:00
|
|
|
/// ```ignore (only-for-syntax-highlight)
|
2019-02-08 13:53:55 +00:00
|
|
|
/// impl<'a, ..., 'z, A, B: DeclaredTrait, C, ... Z> where
|
2015-03-24 21:43:26 +00:00
|
|
|
/// C: WhereTrait,
|
|
|
|
/// A: DerivedTrait + B1 + ... + BN,
|
|
|
|
/// B: DerivedTrait + B1 + ... + BN,
|
|
|
|
/// C: DerivedTrait + B1 + ... + BN,
|
|
|
|
/// B::Item: DerivedTrait + B1 + ... + BN,
|
|
|
|
/// <C as WhereTrait>::Item: DerivedTrait + B1 + ... + BN,
|
|
|
|
/// ...
|
|
|
|
/// {
|
|
|
|
/// ...
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// where B1, ..., BN are the bounds given by `bounds_paths`.'. Z is a phantom type, and
|
|
|
|
/// therefore does not get bound by the derived trait.
|
2013-12-07 00:57:44 +00:00
|
|
|
fn create_derived_impl(
|
|
|
|
&self,
|
2019-02-04 12:49:54 +00:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
2014-02-14 16:09:51 +00:00
|
|
|
type_ident: Ident,
|
|
|
|
generics: &Generics,
|
2015-03-24 21:43:26 +00:00
|
|
|
field_tys: Vec<P<ast::Ty>>,
|
2019-12-12 05:41:18 +00:00
|
|
|
methods: Vec<P<ast::AssocItem>>,
|
2016-07-19 17:32:06 +00:00
|
|
|
) -> P<ast::Item> {
|
2013-12-07 00:57:44 +00:00
|
|
|
let trait_path = self.path.to_path(cx, self.span, type_ident, generics);
|
2013-05-06 15:23:51 +00:00
|
|
|
|
2019-12-07 23:08:09 +00:00
|
|
|
// Transform associated types from `deriving::ty::Ty` into `ast::AssocItem`
|
2019-12-12 05:41:18 +00:00
|
|
|
let associated_types = self.associated_types.iter().map(|&(ident, ref type_def)| {
|
|
|
|
P(ast::AssocItem {
|
2015-01-25 05:29:24 +00:00
|
|
|
id: ast::DUMMY_NODE_ID,
|
|
|
|
span: self.span,
|
2017-08-07 05:54:09 +00:00
|
|
|
ident,
|
2020-08-21 23:11:00 +00:00
|
|
|
vis: ast::Visibility {
|
|
|
|
span: self.span.shrink_to_lo(),
|
|
|
|
kind: ast::VisibilityKind::Inherited,
|
|
|
|
tokens: None,
|
|
|
|
},
|
2022-08-17 02:34:33 +00:00
|
|
|
attrs: ast::AttrVec::new(),
|
2022-10-10 02:05:24 +00:00
|
|
|
kind: ast::AssocItemKind::Type(Box::new(ast::TyAlias {
|
2021-11-07 08:43:49 +00:00
|
|
|
defaultness: ast::Defaultness::Final,
|
|
|
|
generics: Generics::default(),
|
2021-10-19 22:45:48 +00:00
|
|
|
where_clauses: (
|
|
|
|
ast::TyAliasWhereClause::default(),
|
|
|
|
ast::TyAliasWhereClause::default(),
|
|
|
|
),
|
|
|
|
where_predicates_split: 0,
|
2021-11-07 08:43:49 +00:00
|
|
|
bounds: Vec::new(),
|
|
|
|
ty: Some(type_def.to_ty(cx, self.span, type_ident, generics)),
|
|
|
|
})),
|
2017-07-12 16:50:05 +00:00
|
|
|
tokens: None,
|
2019-12-12 05:41:18 +00:00
|
|
|
})
|
|
|
|
});
|
2015-01-25 05:29:24 +00:00
|
|
|
|
2022-11-14 04:43:10 +00:00
|
|
|
let mut where_clause = ast::WhereClause::default();
|
2021-11-03 04:19:06 +00:00
|
|
|
where_clause.span = generics.where_clause.span;
|
2021-11-20 18:46:36 +00:00
|
|
|
let ctxt = self.span.ctxt();
|
|
|
|
let span = generics.span.with_ctxt(ctxt);
|
2014-03-19 12:16:56 +00:00
|
|
|
|
2017-10-16 19:07:26 +00:00
|
|
|
// Create the generic parameters
|
2022-11-14 04:43:10 +00:00
|
|
|
let params: Vec<_> = generics
|
|
|
|
.params
|
|
|
|
.iter()
|
|
|
|
.map(|param| match ¶m.kind {
|
|
|
|
GenericParamKind::Lifetime { .. } => param.clone(),
|
|
|
|
GenericParamKind::Type { .. } => {
|
|
|
|
// I don't think this can be moved out of the loop, since
|
|
|
|
// a GenericBound requires an ast id
|
|
|
|
let bounds: Vec<_> =
|
2018-05-27 00:43:03 +00:00
|
|
|
// extra restrictions on the generics parameters to the
|
|
|
|
// type being derived upon
|
|
|
|
self.additional_bounds.iter().map(|p| {
|
2018-06-14 14:00:21 +00:00
|
|
|
cx.trait_bound(p.to_path(cx, self.span, type_ident, generics))
|
2018-07-26 15:11:10 +00:00
|
|
|
}).chain(
|
|
|
|
// require the current trait
|
2022-08-26 12:59:12 +00:00
|
|
|
self.skip_path_as_bound.not().then(|| cx.trait_bound(trait_path.clone()))
|
2018-07-26 15:11:10 +00:00
|
|
|
).chain(
|
|
|
|
// also add in any bounds from the declaration
|
|
|
|
param.bounds.iter().cloned()
|
|
|
|
).collect();
|
2018-05-27 00:43:03 +00:00
|
|
|
|
2022-11-14 04:43:10 +00:00
|
|
|
cx.typaram(param.ident.span.with_ctxt(ctxt), param.ident, bounds, None)
|
|
|
|
}
|
|
|
|
GenericParamKind::Const { ty, kw_span, .. } => {
|
|
|
|
let const_nodefault_kind = GenericParamKind::Const {
|
|
|
|
ty: ty.clone(),
|
|
|
|
kw_span: kw_span.with_ctxt(ctxt),
|
|
|
|
|
|
|
|
// We can't have default values inside impl block
|
|
|
|
default: None,
|
|
|
|
};
|
|
|
|
let mut param_clone = param.clone();
|
|
|
|
param_clone.kind = const_nodefault_kind;
|
|
|
|
param_clone
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect();
|
2014-12-14 05:35:35 +00:00
|
|
|
|
|
|
|
// and similarly for where clauses
|
|
|
|
where_clause.predicates.extend(generics.where_clause.predicates.iter().map(|clause| {
|
2021-11-17 23:47:47 +00:00
|
|
|
match clause {
|
2021-11-20 18:46:36 +00:00
|
|
|
ast::WherePredicate::BoundPredicate(wb) => {
|
|
|
|
let span = wb.span.with_ctxt(ctxt);
|
|
|
|
ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
|
|
|
|
span,
|
|
|
|
..wb.clone()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
ast::WherePredicate::RegionPredicate(wr) => {
|
|
|
|
let span = wr.span.with_ctxt(ctxt);
|
|
|
|
ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
|
|
|
|
span,
|
|
|
|
..wr.clone()
|
|
|
|
})
|
|
|
|
}
|
2021-11-17 23:47:47 +00:00
|
|
|
ast::WherePredicate::EqPredicate(we) => {
|
2021-11-20 18:46:36 +00:00
|
|
|
let span = we.span.with_ctxt(ctxt);
|
2022-07-29 00:16:25 +00:00
|
|
|
ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { span, ..we.clone() })
|
2014-12-14 05:35:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}));
|
|
|
|
|
2017-10-16 19:07:26 +00:00
|
|
|
{
|
|
|
|
// Extra scope required here so ty_params goes out of scope before params is moved
|
|
|
|
|
|
|
|
let mut ty_params = params
|
|
|
|
.iter()
|
2021-01-09 17:00:45 +00:00
|
|
|
.filter(|param| matches!(param.kind, ast::GenericParamKind::Type { .. }))
|
2017-10-16 19:07:26 +00:00
|
|
|
.peekable();
|
|
|
|
|
|
|
|
if ty_params.peek().is_some() {
|
2020-04-19 11:00:18 +00:00
|
|
|
let ty_param_names: Vec<Symbol> =
|
2017-10-16 19:07:26 +00:00
|
|
|
ty_params.map(|ty_param| ty_param.ident.name).collect();
|
|
|
|
|
|
|
|
for field_ty in field_tys {
|
2021-09-28 22:46:29 +00:00
|
|
|
let field_ty_params = find_type_parameters(&field_ty, &ty_param_names, cx);
|
2017-10-16 19:07:26 +00:00
|
|
|
|
2021-09-28 22:46:29 +00:00
|
|
|
for field_ty_param in field_ty_params {
|
2017-10-16 19:07:26 +00:00
|
|
|
// if we have already handled this type, skip it
|
2022-12-06 13:22:36 +00:00
|
|
|
if let ast::TyKind::Path(_, p) = &field_ty_param.ty.kind
|
|
|
|
&& let [sole_segment] = &*p.segments
|
|
|
|
&& ty_param_names.contains(&sole_segment.ident.name)
|
|
|
|
{
|
|
|
|
continue;
|
2017-10-16 19:07:26 +00:00
|
|
|
}
|
|
|
|
let mut bounds: Vec<_> = self
|
|
|
|
.additional_bounds
|
|
|
|
.iter()
|
2018-06-14 14:00:21 +00:00
|
|
|
.map(|p| cx.trait_bound(p.to_path(cx, self.span, type_ident, generics)))
|
2017-10-16 19:07:26 +00:00
|
|
|
.collect();
|
|
|
|
|
|
|
|
// require the current trait
|
2018-06-14 14:00:21 +00:00
|
|
|
bounds.push(cx.trait_bound(trait_path.clone()));
|
2017-10-16 19:07:26 +00:00
|
|
|
|
|
|
|
let predicate = ast::WhereBoundPredicate {
|
|
|
|
span: self.span,
|
2021-09-28 22:46:29 +00:00
|
|
|
bound_generic_params: field_ty_param.bound_generic_params,
|
|
|
|
bounded_ty: field_ty_param.ty,
|
2017-10-16 19:07:26 +00:00
|
|
|
bounds,
|
2015-07-19 22:09:12 +00:00
|
|
|
};
|
2015-03-24 21:43:26 +00:00
|
|
|
|
2017-10-16 19:07:26 +00:00
|
|
|
let predicate = ast::WherePredicate::BoundPredicate(predicate);
|
|
|
|
where_clause.predicates.push(predicate);
|
|
|
|
}
|
2015-03-24 21:43:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-19 12:16:56 +00:00
|
|
|
let trait_generics = Generics { params, where_clause, span };
|
2013-06-07 07:30:38 +00:00
|
|
|
|
|
|
|
// Create the reference to the trait.
|
|
|
|
let trait_ref = cx.trait_ref(trait_path);
|
2013-03-28 10:50:10 +00:00
|
|
|
|
2018-05-27 20:54:10 +00:00
|
|
|
let self_params: Vec<_> = generics
|
|
|
|
.params
|
|
|
|
.iter()
|
|
|
|
.map(|param| match param.kind {
|
2018-05-30 15:49:39 +00:00
|
|
|
GenericParamKind::Lifetime { .. } => {
|
2021-11-20 18:46:36 +00:00
|
|
|
GenericArg::Lifetime(cx.lifetime(param.ident.span.with_ctxt(ctxt), param.ident))
|
2018-05-27 20:54:10 +00:00
|
|
|
}
|
|
|
|
GenericParamKind::Type { .. } => {
|
2021-11-20 18:46:36 +00:00
|
|
|
GenericArg::Type(cx.ty_ident(param.ident.span.with_ctxt(ctxt), param.ident))
|
2018-05-27 20:54:10 +00:00
|
|
|
}
|
2019-02-05 15:50:00 +00:00
|
|
|
GenericParamKind::Const { .. } => {
|
2021-11-20 18:46:36 +00:00
|
|
|
GenericArg::Const(cx.const_ident(param.ident.span.with_ctxt(ctxt), param.ident))
|
2019-02-05 15:50:00 +00:00
|
|
|
}
|
2018-05-27 20:54:10 +00:00
|
|
|
})
|
|
|
|
.collect();
|
2018-02-08 08:58:13 +00:00
|
|
|
|
2013-06-07 07:30:38 +00:00
|
|
|
// Create the type of `self`.
|
2019-09-21 19:01:10 +00:00
|
|
|
let path = cx.path_all(self.span, false, vec![type_ident], self_params);
|
2018-05-27 20:54:10 +00:00
|
|
|
let self_type = cx.ty_path(path);
|
2016-07-19 17:32:06 +00:00
|
|
|
|
Avoid more `MetaItem`-to-`Attribute` conversions.
There is code for converting `Attribute` (syntactic) to `MetaItem`
(semantic). There is also code for the reverse direction. The reverse
direction isn't really necessary; it's currently only used when
generating attributes, e.g. in `derive` code.
This commit adds some new functions for creating `Attributes`s directly,
without involving `MetaItem`s: `mk_attr_word`, `mk_attr_name_value_str`,
`mk_attr_nested_word`, and
`ExtCtxt::attr_{word,name_value_str,nested_word}`.
These new methods replace the old functions for creating `Attribute`s:
`mk_attr_inner`, `mk_attr_outer`, and `ExtCtxt::attribute`. Those
functions took `MetaItem`s as input, and relied on many other functions
that created `MetaItems`, which are also removed: `mk_name_value_item`,
`mk_list_item`, `mk_word_item`, `mk_nested_word_item`,
`{MetaItem,MetaItemKind,NestedMetaItem}::token_trees`,
`MetaItemKind::attr_args`, `MetaItemLit::{from_lit_kind,to_token}`,
`ExtCtxt::meta_word`.
Overall this cuts more than 100 lines of code and makes thing simpler.
2022-11-29 07:43:44 +00:00
|
|
|
let attr = cx.attr_word(sym::automatically_derived, self.span);
|
2022-08-17 04:22:30 +00:00
|
|
|
let attrs = thin_vec![attr];
|
2014-02-14 05:07:09 +00:00
|
|
|
let opt_trait_ref = Some(trait_ref);
|
2020-05-07 05:23:44 +00:00
|
|
|
|
2016-07-19 17:32:06 +00:00
|
|
|
cx.item(
|
|
|
|
self.span,
|
2021-10-17 20:20:30 +00:00
|
|
|
Ident::empty(),
|
2022-08-17 02:20:25 +00:00
|
|
|
attrs,
|
2021-11-07 08:43:49 +00:00
|
|
|
ast::ItemKind::Impl(Box::new(ast::Impl {
|
2022-06-28 01:44:37 +00:00
|
|
|
unsafety: ast::Unsafe::No,
|
2020-01-14 04:30:20 +00:00
|
|
|
polarity: ast::ImplPolarity::Positive,
|
|
|
|
defaultness: ast::Defaultness::Final,
|
2022-09-20 11:55:07 +00:00
|
|
|
constness: if self.is_const { ast::Const::Yes(DUMMY_SP) } else { ast::Const::No },
|
2020-01-14 04:30:20 +00:00
|
|
|
generics: trait_generics,
|
|
|
|
of_trait: opt_trait_ref,
|
|
|
|
self_ty: self_type,
|
|
|
|
items: methods.into_iter().chain(associated_types).collect(),
|
2021-08-05 01:53:21 +00:00
|
|
|
})),
|
2016-07-19 17:32:06 +00:00
|
|
|
)
|
2013-03-28 10:50:10 +00:00
|
|
|
}
|
|
|
|
|
2014-02-22 05:33:23 +00:00
|
|
|
fn expand_struct_def(
|
|
|
|
&self,
|
2019-02-04 12:49:54 +00:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
2015-10-08 00:20:57 +00:00
|
|
|
struct_def: &'a VariantData,
|
2014-02-22 05:33:23 +00:00
|
|
|
type_ident: Ident,
|
2016-08-26 16:23:42 +00:00
|
|
|
generics: &Generics,
|
2017-10-02 13:15:23 +00:00
|
|
|
from_scratch: bool,
|
2022-11-21 00:48:25 +00:00
|
|
|
copy_fields: bool,
|
2016-07-19 17:32:06 +00:00
|
|
|
) -> P<ast::Item> {
|
|
|
|
let field_tys: Vec<P<ast::Ty>> =
|
2016-04-06 08:19:10 +00:00
|
|
|
struct_def.fields().iter().map(|field| field.ty.clone()).collect();
|
2019-12-22 22:42:04 +00:00
|
|
|
|
2016-07-19 17:32:06 +00:00
|
|
|
let methods = self
|
|
|
|
.methods
|
|
|
|
.iter()
|
|
|
|
.map(|method_def| {
|
2022-07-04 22:25:47 +00:00
|
|
|
let (explicit_self, selflike_args, nonselflike_args, nonself_arg_tys) =
|
|
|
|
method_def.extract_arg_details(cx, self, type_ident, generics);
|
2016-07-19 17:32:06 +00:00
|
|
|
|
2016-08-26 16:23:42 +00:00
|
|
|
let body = if from_scratch || method_def.is_static() {
|
2016-07-19 17:32:06 +00:00
|
|
|
method_def.expand_static_struct_method_body(
|
|
|
|
cx,
|
|
|
|
self,
|
|
|
|
struct_def,
|
|
|
|
type_ident,
|
2022-07-04 22:25:47 +00:00
|
|
|
&nonselflike_args,
|
2016-07-19 17:32:06 +00:00
|
|
|
)
|
|
|
|
} else {
|
|
|
|
method_def.expand_struct_method_body(
|
|
|
|
cx,
|
|
|
|
self,
|
|
|
|
struct_def,
|
|
|
|
type_ident,
|
2022-07-04 22:25:47 +00:00
|
|
|
&selflike_args,
|
|
|
|
&nonselflike_args,
|
2022-11-21 00:48:25 +00:00
|
|
|
copy_fields,
|
2017-10-02 13:15:23 +00:00
|
|
|
)
|
2016-07-19 17:32:06 +00:00
|
|
|
};
|
|
|
|
|
2022-07-04 22:25:47 +00:00
|
|
|
method_def.create_method(
|
|
|
|
cx,
|
|
|
|
self,
|
|
|
|
type_ident,
|
|
|
|
generics,
|
|
|
|
explicit_self,
|
|
|
|
nonself_arg_tys,
|
|
|
|
body,
|
|
|
|
)
|
2016-07-19 17:32:06 +00:00
|
|
|
})
|
|
|
|
.collect();
|
2013-03-28 10:50:10 +00:00
|
|
|
|
2015-03-24 21:43:26 +00:00
|
|
|
self.create_derived_impl(cx, type_ident, generics, field_tys, methods)
|
2013-03-28 10:50:10 +00:00
|
|
|
}
|
|
|
|
|
2014-02-22 05:33:23 +00:00
|
|
|
fn expand_enum_def(
|
|
|
|
&self,
|
2019-02-04 12:49:54 +00:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
2015-05-01 01:10:06 +00:00
|
|
|
enum_def: &'a EnumDef,
|
2013-09-02 00:50:59 +00:00
|
|
|
type_ident: Ident,
|
2016-08-26 16:23:42 +00:00
|
|
|
generics: &Generics,
|
|
|
|
from_scratch: bool,
|
2016-07-19 17:32:06 +00:00
|
|
|
) -> P<ast::Item> {
|
2015-03-24 21:43:26 +00:00
|
|
|
let mut field_tys = Vec::new();
|
|
|
|
|
2015-06-10 16:22:20 +00:00
|
|
|
for variant in &enum_def.variants {
|
2016-04-06 08:19:10 +00:00
|
|
|
field_tys.extend(variant.data.fields().iter().map(|field| field.ty.clone()));
|
2015-03-24 21:43:26 +00:00
|
|
|
}
|
|
|
|
|
2016-07-19 17:32:06 +00:00
|
|
|
let methods = self
|
|
|
|
.methods
|
|
|
|
.iter()
|
|
|
|
.map(|method_def| {
|
2022-07-04 22:25:47 +00:00
|
|
|
let (explicit_self, selflike_args, nonselflike_args, nonself_arg_tys) =
|
|
|
|
method_def.extract_arg_details(cx, self, type_ident, generics);
|
2016-07-19 17:32:06 +00:00
|
|
|
|
2016-08-26 16:23:42 +00:00
|
|
|
let body = if from_scratch || method_def.is_static() {
|
2016-07-19 17:32:06 +00:00
|
|
|
method_def.expand_static_enum_method_body(
|
|
|
|
cx,
|
|
|
|
self,
|
|
|
|
enum_def,
|
|
|
|
type_ident,
|
2022-07-04 22:25:47 +00:00
|
|
|
&nonselflike_args,
|
2016-07-19 17:32:06 +00:00
|
|
|
)
|
|
|
|
} else {
|
|
|
|
method_def.expand_enum_method_body(
|
|
|
|
cx,
|
|
|
|
self,
|
|
|
|
enum_def,
|
|
|
|
type_ident,
|
2022-07-04 22:25:47 +00:00
|
|
|
selflike_args,
|
|
|
|
&nonselflike_args,
|
2016-07-19 17:32:06 +00:00
|
|
|
)
|
|
|
|
};
|
|
|
|
|
2022-07-04 22:25:47 +00:00
|
|
|
method_def.create_method(
|
|
|
|
cx,
|
|
|
|
self,
|
|
|
|
type_ident,
|
|
|
|
generics,
|
|
|
|
explicit_self,
|
|
|
|
nonself_arg_tys,
|
|
|
|
body,
|
|
|
|
)
|
2016-07-19 17:32:06 +00:00
|
|
|
})
|
|
|
|
.collect();
|
2013-03-28 10:50:10 +00:00
|
|
|
|
2015-03-24 21:43:26 +00:00
|
|
|
self.create_derived_impl(cx, type_ident, generics, field_tys, methods)
|
2013-03-28 10:50:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-10 07:16:18 +00:00
|
|
|
impl<'a> MethodDef<'a> {
|
2013-03-28 10:50:10 +00:00
|
|
|
fn call_substructure_method(
|
|
|
|
&self,
|
2019-02-04 12:49:54 +00:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
|
|
|
trait_: &TraitDef<'_>,
|
2013-09-02 00:50:59 +00:00
|
|
|
type_ident: Ident,
|
2022-07-04 22:25:47 +00:00
|
|
|
nonselflike_args: &[P<Expr>],
|
2019-02-04 12:49:54 +00:00
|
|
|
fields: &SubstructureFields<'_>,
|
2022-06-28 03:10:36 +00:00
|
|
|
) -> BlockOrExpr {
|
2021-11-20 18:46:36 +00:00
|
|
|
let span = trait_.span;
|
2022-07-04 22:25:47 +00:00
|
|
|
let substructure = Substructure { type_ident, nonselflike_args, fields };
|
2014-04-22 06:25:18 +00:00
|
|
|
let mut f = self.combine_substructure.borrow_mut();
|
2019-02-04 12:49:54 +00:00
|
|
|
let f: &mut CombineSubstructureFunc<'_> = &mut *f;
|
2021-11-20 18:46:36 +00:00
|
|
|
f(cx, span, &substructure)
|
2013-03-28 10:50:10 +00:00
|
|
|
}
|
|
|
|
|
2014-02-09 00:39:53 +00:00
|
|
|
fn get_ret_ty(
|
|
|
|
&self,
|
2019-02-04 12:49:54 +00:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
|
|
|
trait_: &TraitDef<'_>,
|
2014-02-09 00:39:53 +00:00
|
|
|
generics: &Generics,
|
|
|
|
type_ident: Ident,
|
|
|
|
) -> P<ast::Ty> {
|
|
|
|
self.ret_ty.to_ty(cx, trait_.span, type_ident, generics)
|
2013-05-06 15:23:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn is_static(&self) -> bool {
|
2022-06-29 23:15:07 +00:00
|
|
|
!self.explicit_self
|
2013-05-06 15:23:51 +00:00
|
|
|
}
|
2013-03-28 10:50:10 +00:00
|
|
|
|
2022-07-04 22:25:47 +00:00
|
|
|
// The return value includes:
|
|
|
|
// - explicit_self: The `&self` arg, if present.
|
|
|
|
// - selflike_args: Expressions for `&self` (if present) and also any other
|
|
|
|
// args with the same type (e.g. the `other` arg in `PartialEq::eq`).
|
|
|
|
// - nonselflike_args: Expressions for all the remaining args.
|
|
|
|
// - nonself_arg_tys: Additional information about all the args other than
|
|
|
|
// `&self`.
|
|
|
|
fn extract_arg_details(
|
2016-07-19 17:32:06 +00:00
|
|
|
&self,
|
2019-02-04 12:49:54 +00:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
|
|
|
trait_: &TraitDef<'_>,
|
2016-07-19 17:32:06 +00:00
|
|
|
type_ident: Ident,
|
|
|
|
generics: &Generics,
|
|
|
|
) -> (Option<ast::ExplicitSelf>, Vec<P<Expr>>, Vec<P<Expr>>, Vec<(Ident, P<ast::Ty>)>) {
|
2022-07-04 22:25:47 +00:00
|
|
|
let mut selflike_args = Vec::new();
|
|
|
|
let mut nonselflike_args = Vec::new();
|
|
|
|
let mut nonself_arg_tys = Vec::new();
|
2021-11-20 18:46:36 +00:00
|
|
|
let span = trait_.span;
|
2013-05-06 15:23:51 +00:00
|
|
|
|
2022-07-04 22:25:47 +00:00
|
|
|
let explicit_self = if self.explicit_self {
|
2022-06-29 23:15:07 +00:00
|
|
|
let (self_expr, explicit_self) = ty::get_explicit_self(cx, span);
|
2022-07-04 22:25:47 +00:00
|
|
|
selflike_args.push(self_expr);
|
2022-06-29 23:15:07 +00:00
|
|
|
Some(explicit_self)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
2013-05-06 15:23:51 +00:00
|
|
|
|
2022-07-04 22:25:47 +00:00
|
|
|
for (ty, name) in self.nonself_args.iter() {
|
2021-11-20 18:46:36 +00:00
|
|
|
let ast_ty = ty.to_ty(cx, span, type_ident, generics);
|
|
|
|
let ident = Ident::new(*name, span);
|
2022-07-04 22:25:47 +00:00
|
|
|
nonself_arg_tys.push((ident, ast_ty));
|
2013-05-06 15:23:51 +00:00
|
|
|
|
2021-11-20 18:46:36 +00:00
|
|
|
let arg_expr = cx.expr_ident(span, ident);
|
2013-05-06 15:23:51 +00:00
|
|
|
|
2022-07-07 21:57:34 +00:00
|
|
|
match ty {
|
|
|
|
// Selflike (`&Self`) arguments only occur in non-static methods.
|
2022-07-06 06:13:51 +00:00
|
|
|
Ref(box Self_, _) if !self.is_static() => selflike_args.push(arg_expr),
|
2022-07-04 22:25:47 +00:00
|
|
|
Self_ => cx.span_bug(span, "`Self` in non-return position"),
|
|
|
|
_ => nonselflike_args.push(arg_expr),
|
2013-03-28 10:50:10 +00:00
|
|
|
}
|
|
|
|
}
|
2013-05-06 15:23:51 +00:00
|
|
|
|
2022-07-04 22:25:47 +00:00
|
|
|
(explicit_self, selflike_args, nonselflike_args, nonself_arg_tys)
|
2013-03-28 10:50:10 +00:00
|
|
|
}
|
|
|
|
|
2014-02-09 00:39:53 +00:00
|
|
|
fn create_method(
|
|
|
|
&self,
|
2019-02-04 12:49:54 +00:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
|
|
|
trait_: &TraitDef<'_>,
|
2013-09-02 00:50:59 +00:00
|
|
|
type_ident: Ident,
|
2013-05-06 15:23:51 +00:00
|
|
|
generics: &Generics,
|
2016-03-06 12:54:44 +00:00
|
|
|
explicit_self: Option<ast::ExplicitSelf>,
|
2022-07-04 22:25:47 +00:00
|
|
|
nonself_arg_tys: Vec<(Ident, P<ast::Ty>)>,
|
2022-06-28 03:10:36 +00:00
|
|
|
body: BlockOrExpr,
|
2019-12-12 05:41:18 +00:00
|
|
|
) -> P<ast::AssocItem> {
|
2021-11-20 18:46:36 +00:00
|
|
|
let span = trait_.span;
|
2019-02-28 22:43:53 +00:00
|
|
|
// Create the generics that aren't for `Self`.
|
2021-11-20 18:46:36 +00:00
|
|
|
let fn_generics = self.generics.to_generics(cx, span, type_ident, generics);
|
2013-05-06 15:23:51 +00:00
|
|
|
|
2014-02-09 12:37:33 +00:00
|
|
|
let args = {
|
2022-07-04 22:25:47 +00:00
|
|
|
let self_arg = explicit_self.map(|explicit_self| {
|
2021-11-20 18:46:36 +00:00
|
|
|
let ident = Ident::with_dummy_span(kw::SelfLower).with_span_pos(span);
|
2019-12-03 15:38:34 +00:00
|
|
|
ast::Param::from_self(ast::AttrVec::default(), explicit_self, ident)
|
2016-03-06 12:54:44 +00:00
|
|
|
});
|
2022-07-04 22:25:47 +00:00
|
|
|
let nonself_args =
|
|
|
|
nonself_arg_tys.into_iter().map(|(name, ty)| cx.param(span, name, ty));
|
|
|
|
self_arg.into_iter().chain(nonself_args).collect()
|
2014-02-09 12:37:33 +00:00
|
|
|
};
|
2013-03-28 10:50:10 +00:00
|
|
|
|
2014-02-09 00:39:53 +00:00
|
|
|
let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident);
|
2013-03-28 10:50:10 +00:00
|
|
|
|
2021-11-20 18:46:36 +00:00
|
|
|
let method_ident = Ident::new(self.name, span);
|
2020-02-15 03:10:59 +00:00
|
|
|
let fn_decl = cx.fn_decl(args, ast::FnRetTy::Ty(ret_type));
|
2022-06-28 03:10:36 +00:00
|
|
|
let body_block = body.into_block(cx, span);
|
2013-03-28 10:50:10 +00:00
|
|
|
|
2021-11-20 18:46:36 +00:00
|
|
|
let trait_lo_sp = span.shrink_to_lo();
|
2019-10-27 22:14:35 +00:00
|
|
|
|
2022-06-28 01:44:37 +00:00
|
|
|
let sig = ast::FnSig { header: ast::FnHeader::default(), decl: fn_decl, span };
|
2021-11-07 08:43:49 +00:00
|
|
|
let defaultness = ast::Defaultness::Final;
|
2019-10-27 22:14:35 +00:00
|
|
|
|
2013-03-28 10:50:10 +00:00
|
|
|
// Create the method.
|
2019-12-12 05:41:18 +00:00
|
|
|
P(ast::AssocItem {
|
2013-09-07 02:11:55 +00:00
|
|
|
id: ast::DUMMY_NODE_ID,
|
2015-03-10 10:28:44 +00:00
|
|
|
attrs: self.attributes.clone(),
|
2021-11-20 18:46:36 +00:00
|
|
|
span,
|
2020-08-21 23:11:00 +00:00
|
|
|
vis: ast::Visibility {
|
|
|
|
span: trait_lo_sp,
|
|
|
|
kind: ast::VisibilityKind::Inherited,
|
|
|
|
tokens: None,
|
|
|
|
},
|
2015-03-10 10:28:44 +00:00
|
|
|
ident: method_ident,
|
2021-11-07 08:43:49 +00:00
|
|
|
kind: ast::AssocItemKind::Fn(Box::new(ast::Fn {
|
|
|
|
defaultness,
|
2021-08-05 01:53:21 +00:00
|
|
|
sig,
|
2021-11-07 08:43:49 +00:00
|
|
|
generics: fn_generics,
|
|
|
|
body: Some(body_block),
|
|
|
|
})),
|
2017-07-12 16:50:05 +00:00
|
|
|
tokens: None,
|
2019-12-12 05:41:18 +00:00
|
|
|
})
|
2013-03-28 10:50:10 +00:00
|
|
|
}
|
|
|
|
|
Don't use match-destructuring for derived ops on structs.
All derive ops currently use match-destructuring to access fields. This
is reasonable for enums, but sub-optimal for structs. E.g.:
```
fn eq(&self, other: &Point) -> bool {
match *other {
Self { x: ref __self_1_0, y: ref __self_1_1 } =>
match *self {
Self { x: ref __self_0_0, y: ref __self_0_1 } =>
(*__self_0_0) == (*__self_1_0) &&
(*__self_0_1) == (*__self_1_1),
},
}
}
```
This commit changes derive ops on structs to use field access instead, e.g.:
```
fn eq(&self, other: &Point) -> bool {
self.x == other.x && self.y == other.y
}
```
This is faster to compile, results in smaller binaries, and is simpler to
generate. Unfortunately, we have to keep the old pattern generating code around
for `repr(packed)` structs because something like `&self.x` (which doesn't show
up in `PartialEq` ops, but does show up in `Debug` and `Hash` ops) isn't
allowed. But this commit at least changes those cases to use let-destructuring
instead of match-destructuring, e.g.:
```
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
{
let Self(ref __self_0_0) = *self;
{ ::core::hash::Hash::hash(&(*__self_0_0), state) }
}
}
```
There are some unnecessary blocks remaining in the generated code, but I
will fix them in a follow-up PR.
2022-06-24 00:20:54 +00:00
|
|
|
/// The normal case uses field access.
|
2017-06-20 07:15:16 +00:00
|
|
|
/// ```
|
2014-12-31 04:25:18 +00:00
|
|
|
/// #[derive(PartialEq)]
|
2017-06-20 07:15:16 +00:00
|
|
|
/// # struct Dummy;
|
2022-07-07 01:09:07 +00:00
|
|
|
/// struct A { x: u8, y: u8 }
|
2014-09-16 11:27:34 +00:00
|
|
|
///
|
|
|
|
/// // equivalent to:
|
|
|
|
/// impl PartialEq for A {
|
2018-04-19 19:17:06 +00:00
|
|
|
/// fn eq(&self, other: &A) -> bool {
|
Don't use match-destructuring for derived ops on structs.
All derive ops currently use match-destructuring to access fields. This
is reasonable for enums, but sub-optimal for structs. E.g.:
```
fn eq(&self, other: &Point) -> bool {
match *other {
Self { x: ref __self_1_0, y: ref __self_1_1 } =>
match *self {
Self { x: ref __self_0_0, y: ref __self_0_1 } =>
(*__self_0_0) == (*__self_1_0) &&
(*__self_0_1) == (*__self_1_1),
},
}
}
```
This commit changes derive ops on structs to use field access instead, e.g.:
```
fn eq(&self, other: &Point) -> bool {
self.x == other.x && self.y == other.y
}
```
This is faster to compile, results in smaller binaries, and is simpler to
generate. Unfortunately, we have to keep the old pattern generating code around
for `repr(packed)` structs because something like `&self.x` (which doesn't show
up in `PartialEq` ops, but does show up in `Debug` and `Hash` ops) isn't
allowed. But this commit at least changes those cases to use let-destructuring
instead of match-destructuring, e.g.:
```
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
{
let Self(ref __self_0_0) = *self;
{ ::core::hash::Hash::hash(&(*__self_0_0), state) }
}
}
```
There are some unnecessary blocks remaining in the generated code, but I
will fix them in a follow-up PR.
2022-06-24 00:20:54 +00:00
|
|
|
/// self.x == other.x && self.y == other.y
|
2014-09-16 11:27:34 +00:00
|
|
|
/// }
|
|
|
|
/// }
|
2022-04-15 22:04:34 +00:00
|
|
|
/// ```
|
Don't use match-destructuring for derived ops on structs.
All derive ops currently use match-destructuring to access fields. This
is reasonable for enums, but sub-optimal for structs. E.g.:
```
fn eq(&self, other: &Point) -> bool {
match *other {
Self { x: ref __self_1_0, y: ref __self_1_1 } =>
match *self {
Self { x: ref __self_0_0, y: ref __self_0_1 } =>
(*__self_0_0) == (*__self_1_0) &&
(*__self_0_1) == (*__self_1_1),
},
}
}
```
This commit changes derive ops on structs to use field access instead, e.g.:
```
fn eq(&self, other: &Point) -> bool {
self.x == other.x && self.y == other.y
}
```
This is faster to compile, results in smaller binaries, and is simpler to
generate. Unfortunately, we have to keep the old pattern generating code around
for `repr(packed)` structs because something like `&self.x` (which doesn't show
up in `PartialEq` ops, but does show up in `Debug` and `Hash` ops) isn't
allowed. But this commit at least changes those cases to use let-destructuring
instead of match-destructuring, e.g.:
```
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
{
let Self(ref __self_0_0) = *self;
{ ::core::hash::Hash::hash(&(*__self_0_0), state) }
}
}
```
There are some unnecessary blocks remaining in the generated code, but I
will fix them in a follow-up PR.
2022-06-24 00:20:54 +00:00
|
|
|
/// But if the struct is `repr(packed)`, we can't use something like
|
2022-07-11 02:54:52 +00:00
|
|
|
/// `&self.x` because that might cause an unaligned ref. So for any trait
|
|
|
|
/// method that takes a reference, if the struct impls `Copy` then we use a
|
|
|
|
/// local block to force a copy:
|
2022-04-15 22:04:34 +00:00
|
|
|
/// ```
|
2022-07-07 01:09:07 +00:00
|
|
|
/// # struct A { x: u8, y: u8 }
|
2017-10-02 13:15:23 +00:00
|
|
|
/// impl PartialEq for A {
|
2018-04-19 19:17:06 +00:00
|
|
|
/// fn eq(&self, other: &A) -> bool {
|
2022-07-11 02:54:52 +00:00
|
|
|
/// // Desugars to `{ self.x }.eq(&{ other.y }) && ...`
|
|
|
|
/// { self.x } == { other.y } && { self.y } == { other.y }
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// impl Hash for A {
|
|
|
|
/// fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
|
|
|
|
/// ::core::hash::Hash::hash(&{ self.x }, state);
|
|
|
|
/// ::core::hash::Hash::hash(&{ self.y }, state)
|
2017-10-02 13:15:23 +00:00
|
|
|
/// }
|
|
|
|
/// }
|
2014-09-16 11:27:34 +00:00
|
|
|
/// ```
|
2022-11-21 00:48:25 +00:00
|
|
|
/// If the struct doesn't impl `Copy`, we use the normal `&self.x`. This
|
|
|
|
/// only works if the fields match the alignment required by the
|
|
|
|
/// `packed(N)` attribute. (We'll get errors later on if not.)
|
2015-05-01 01:10:06 +00:00
|
|
|
fn expand_struct_method_body<'b>(
|
|
|
|
&self,
|
2019-02-04 12:49:54 +00:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
2016-07-19 17:32:06 +00:00
|
|
|
trait_: &TraitDef<'b>,
|
|
|
|
struct_def: &'b VariantData,
|
|
|
|
type_ident: Ident,
|
2022-07-04 22:25:47 +00:00
|
|
|
selflike_args: &[P<Expr>],
|
|
|
|
nonselflike_args: &[P<Expr>],
|
2022-11-21 00:48:25 +00:00
|
|
|
copy_fields: bool,
|
2022-06-28 03:10:36 +00:00
|
|
|
) -> BlockOrExpr {
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
assert!(selflike_args.len() == 1 || selflike_args.len() == 2);
|
|
|
|
|
2022-11-21 00:48:25 +00:00
|
|
|
let selflike_fields =
|
|
|
|
trait_.create_struct_field_access_fields(cx, selflike_args, struct_def, copy_fields);
|
|
|
|
self.call_substructure_method(
|
|
|
|
cx,
|
|
|
|
trait_,
|
|
|
|
type_ident,
|
|
|
|
nonselflike_args,
|
|
|
|
&Struct(struct_def, selflike_fields),
|
|
|
|
)
|
2013-03-28 10:50:10 +00:00
|
|
|
}
|
|
|
|
|
2013-05-06 15:23:51 +00:00
|
|
|
fn expand_static_struct_method_body(
|
|
|
|
&self,
|
2019-02-04 12:49:54 +00:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
|
|
|
trait_: &TraitDef<'_>,
|
2015-10-08 00:20:57 +00:00
|
|
|
struct_def: &VariantData,
|
2013-09-02 00:50:59 +00:00
|
|
|
type_ident: Ident,
|
2022-07-04 22:25:47 +00:00
|
|
|
nonselflike_args: &[P<Expr>],
|
2022-06-28 03:10:36 +00:00
|
|
|
) -> BlockOrExpr {
|
2014-02-09 00:39:53 +00:00
|
|
|
let summary = trait_.summarise_struct(cx, struct_def);
|
2013-03-28 10:50:10 +00:00
|
|
|
|
2014-02-09 00:39:53 +00:00
|
|
|
self.call_substructure_method(
|
|
|
|
cx,
|
|
|
|
trait_,
|
2013-05-06 15:23:51 +00:00
|
|
|
type_ident,
|
2022-07-04 22:25:47 +00:00
|
|
|
nonselflike_args,
|
2013-05-06 15:23:51 +00:00
|
|
|
&StaticStruct(struct_def, summary),
|
|
|
|
)
|
2013-03-28 10:50:10 +00:00
|
|
|
}
|
|
|
|
|
2017-06-20 07:15:16 +00:00
|
|
|
/// ```
|
2014-12-31 04:25:18 +00:00
|
|
|
/// #[derive(PartialEq)]
|
2017-06-20 07:15:16 +00:00
|
|
|
/// # struct Dummy;
|
2014-09-16 11:27:34 +00:00
|
|
|
/// enum A {
|
|
|
|
/// A1,
|
2015-01-17 23:55:21 +00:00
|
|
|
/// A2(i32)
|
2014-09-16 11:27:34 +00:00
|
|
|
/// }
|
2022-06-22 05:26:47 +00:00
|
|
|
/// ```
|
|
|
|
/// is equivalent to:
|
|
|
|
/// ```
|
2022-09-16 11:10:25 +00:00
|
|
|
/// #![feature(core_intrinsics)]
|
|
|
|
/// enum A {
|
|
|
|
/// A1,
|
|
|
|
/// A2(i32)
|
|
|
|
/// }
|
2022-06-22 05:26:47 +00:00
|
|
|
/// impl ::core::cmp::PartialEq for A {
|
|
|
|
/// #[inline]
|
2022-04-15 22:04:34 +00:00
|
|
|
/// fn eq(&self, other: &A) -> bool {
|
2022-07-08 05:16:14 +00:00
|
|
|
/// let __self_tag = ::core::intrinsics::discriminant_value(self);
|
|
|
|
/// let __arg1_tag = ::core::intrinsics::discriminant_value(other);
|
2022-07-08 05:32:27 +00:00
|
|
|
/// __self_tag == __arg1_tag &&
|
2022-07-06 06:13:51 +00:00
|
|
|
/// match (self, other) {
|
2022-07-08 05:16:14 +00:00
|
|
|
/// (A::A2(__self_0), A::A2(__arg1_0)) =>
|
|
|
|
/// *__self_0 == *__arg1_0,
|
2022-07-06 06:13:51 +00:00
|
|
|
/// _ => true,
|
2014-09-16 11:27:34 +00:00
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// ```
|
2022-07-08 05:32:27 +00:00
|
|
|
/// Creates a tag check combined with a match for a tuple of all
|
|
|
|
/// `selflike_args`, with an arm for each variant with fields, possibly an
|
|
|
|
/// arm for each fieldless variant (if `!unify_fieldless_variants` is not
|
|
|
|
/// true), and possibly a default arm.
|
2022-06-22 05:26:47 +00:00
|
|
|
fn expand_enum_method_body<'b>(
|
2016-07-19 17:32:06 +00:00
|
|
|
&self,
|
2019-02-04 12:49:54 +00:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
2016-07-19 17:32:06 +00:00
|
|
|
trait_: &TraitDef<'b>,
|
|
|
|
enum_def: &'b EnumDef,
|
|
|
|
type_ident: Ident,
|
2022-07-08 05:32:27 +00:00
|
|
|
selflike_args: Vec<P<Expr>>,
|
2022-07-04 22:25:47 +00:00
|
|
|
nonselflike_args: &[P<Expr>],
|
2022-06-28 03:10:36 +00:00
|
|
|
) -> BlockOrExpr {
|
2021-11-20 18:46:36 +00:00
|
|
|
let span = trait_.span;
|
2014-07-06 19:19:12 +00:00
|
|
|
let variants = &enum_def.variants;
|
|
|
|
|
2022-07-08 05:32:27 +00:00
|
|
|
// Traits that unify fieldless variants always use the tag(s).
|
|
|
|
let uses_tags = self.unify_fieldless_variants;
|
|
|
|
|
2022-07-08 05:31:09 +00:00
|
|
|
// There is no sensible code to be generated for *any* deriving on a
|
|
|
|
// zero-variant enum. So we just generate a failing expression.
|
|
|
|
if variants.is_empty() {
|
|
|
|
return BlockOrExpr(vec![], Some(deriving::call_unreachable(cx, span)));
|
|
|
|
}
|
|
|
|
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
let prefixes = iter::once("__self".to_string())
|
2018-11-05 14:30:04 +00:00
|
|
|
.chain(
|
2022-07-04 22:25:47 +00:00
|
|
|
selflike_args
|
2018-11-05 14:30:04 +00:00
|
|
|
.iter()
|
|
|
|
.enumerate()
|
|
|
|
.skip(1)
|
2022-07-08 05:16:14 +00:00
|
|
|
.map(|(arg_count, _selflike_arg)| format!("__arg{}", arg_count)),
|
2018-11-05 14:30:04 +00:00
|
|
|
)
|
|
|
|
.collect::<Vec<String>>();
|
2019-12-22 22:42:04 +00:00
|
|
|
|
2022-07-08 05:32:27 +00:00
|
|
|
// Build a series of let statements mapping each selflike_arg
|
|
|
|
// to its discriminant value.
|
|
|
|
//
|
|
|
|
// e.g. for `PartialEq::eq` builds two statements:
|
|
|
|
// ```
|
|
|
|
// let __self_tag = ::core::intrinsics::discriminant_value(self);
|
|
|
|
// let __arg1_tag = ::core::intrinsics::discriminant_value(other);
|
|
|
|
// ```
|
|
|
|
let get_tag_pieces = |cx: &ExtCtxt<'_>| {
|
|
|
|
let tag_idents: Vec<_> = prefixes
|
|
|
|
.iter()
|
|
|
|
.map(|name| Ident::from_str_and_span(&format!("{}_tag", name), span))
|
|
|
|
.collect();
|
2014-07-06 19:19:12 +00:00
|
|
|
|
2022-07-08 05:32:27 +00:00
|
|
|
let mut tag_exprs: Vec<_> = tag_idents
|
|
|
|
.iter()
|
|
|
|
.map(|&ident| cx.expr_addr_of(span, cx.expr_ident(span, ident)))
|
|
|
|
.collect();
|
2014-07-06 19:19:12 +00:00
|
|
|
|
2022-07-08 05:32:27 +00:00
|
|
|
let self_expr = tag_exprs.remove(0);
|
|
|
|
let other_selflike_exprs = tag_exprs;
|
|
|
|
let tag_field = FieldInfo { span, name: None, self_expr, other_selflike_exprs };
|
|
|
|
|
|
|
|
let tag_let_stmts: Vec<_> = iter::zip(&tag_idents, &selflike_args)
|
|
|
|
.map(|(&ident, selflike_arg)| {
|
|
|
|
let variant_value = deriving::call_intrinsic(
|
|
|
|
cx,
|
|
|
|
span,
|
|
|
|
sym::discriminant_value,
|
|
|
|
vec![selflike_arg.clone()],
|
|
|
|
);
|
|
|
|
cx.stmt_let(span, false, ident, variant_value)
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
(tag_field, tag_let_stmts)
|
|
|
|
};
|
|
|
|
|
|
|
|
// There are some special cases involving fieldless enums where no
|
|
|
|
// match is necessary.
|
|
|
|
let all_fieldless = variants.iter().all(|v| v.data.fields().is_empty());
|
|
|
|
if all_fieldless {
|
|
|
|
if uses_tags && variants.len() > 1 {
|
|
|
|
// If the type is fieldless and the trait uses the tag and
|
|
|
|
// there are multiple variants, we need just an operation on
|
|
|
|
// the tag(s).
|
|
|
|
let (tag_field, mut tag_let_stmts) = get_tag_pieces(cx);
|
|
|
|
let mut tag_check = self.call_substructure_method(
|
|
|
|
cx,
|
|
|
|
trait_,
|
|
|
|
type_ident,
|
|
|
|
nonselflike_args,
|
|
|
|
&EnumTag(tag_field, None),
|
|
|
|
);
|
|
|
|
tag_let_stmts.append(&mut tag_check.0);
|
|
|
|
return BlockOrExpr(tag_let_stmts, tag_check.1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if variants.len() == 1 {
|
|
|
|
// If there is a single variant, we don't need an operation on
|
|
|
|
// the tag(s). Just use the most degenerate result.
|
|
|
|
return self.call_substructure_method(
|
|
|
|
cx,
|
|
|
|
trait_,
|
|
|
|
type_ident,
|
|
|
|
nonselflike_args,
|
|
|
|
&EnumMatching(0, 1, &variants[0], Vec::new()),
|
|
|
|
);
|
|
|
|
};
|
|
|
|
}
|
2016-05-12 15:54:05 +00:00
|
|
|
|
2014-07-06 19:19:12 +00:00
|
|
|
// These arms are of the form:
|
|
|
|
// (Variant1, Variant1, ...) => Body1
|
|
|
|
// (Variant2, Variant2, ...) => Body2
|
|
|
|
// ...
|
2022-07-04 22:25:47 +00:00
|
|
|
// where each tuple has length = selflike_args.len()
|
2016-07-19 17:32:06 +00:00
|
|
|
let mut match_arms: Vec<ast::Arm> = variants
|
|
|
|
.iter()
|
|
|
|
.enumerate()
|
2019-08-14 00:40:21 +00:00
|
|
|
.filter(|&(_, v)| !(self.unify_fieldless_variants && v.data.fields().is_empty()))
|
2014-09-13 16:06:01 +00:00
|
|
|
.map(|(index, variant)| {
|
2014-07-06 19:19:12 +00:00
|
|
|
// A single arm has form (&VariantK, &VariantK, ...) => BodyK
|
|
|
|
// (see "Final wrinkle" note below for why.)
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
|
2022-11-14 02:59:54 +00:00
|
|
|
let fields = trait_.create_struct_pattern_fields(cx, &variant.data, &prefixes);
|
2022-07-06 06:13:51 +00:00
|
|
|
|
|
|
|
let sp = variant.span.with_ctxt(trait_.span.ctxt());
|
|
|
|
let variant_path = cx.path(sp, vec![type_ident, variant.ident]);
|
2022-08-30 22:34:35 +00:00
|
|
|
let by_ref = ByRef::No; // because enums can't be repr(packed)
|
2022-07-06 06:13:51 +00:00
|
|
|
let mut subpats: Vec<_> = trait_.create_struct_patterns(
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
cx,
|
2022-07-06 06:13:51 +00:00
|
|
|
variant_path,
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
&variant.data,
|
|
|
|
&prefixes,
|
2022-08-30 22:34:35 +00:00
|
|
|
by_ref,
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
);
|
|
|
|
|
2022-07-08 05:32:27 +00:00
|
|
|
// `(VariantK, VariantK, ...)` or just `VariantK`.
|
2022-07-04 05:08:28 +00:00
|
|
|
let single_pat = if subpats.len() == 1 {
|
|
|
|
subpats.pop().unwrap()
|
|
|
|
} else {
|
|
|
|
cx.pat_tuple(span, subpats)
|
|
|
|
};
|
2014-07-06 19:19:12 +00:00
|
|
|
|
|
|
|
// For the BodyK, we need to delegate to our caller,
|
|
|
|
// passing it an EnumMatching to indicate which case
|
|
|
|
// we are in.
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
//
|
2014-07-06 19:19:12 +00:00
|
|
|
// Now, for some given VariantK, we have built up
|
|
|
|
// expressions for referencing every field of every
|
|
|
|
// Self arg, assuming all are instances of VariantK.
|
|
|
|
// Build up code associated with such a case.
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
let substructure = EnumMatching(index, variants.len(), variant, fields);
|
2022-06-28 03:10:36 +00:00
|
|
|
let arm_expr = self
|
2022-07-04 22:25:47 +00:00
|
|
|
.call_substructure_method(
|
|
|
|
cx,
|
|
|
|
trait_,
|
|
|
|
type_ident,
|
|
|
|
nonselflike_args,
|
|
|
|
&substructure,
|
|
|
|
)
|
2022-06-28 03:10:36 +00:00
|
|
|
.into_expr(cx, span);
|
2014-07-06 19:19:12 +00:00
|
|
|
|
2021-11-20 18:46:36 +00:00
|
|
|
cx.arm(span, single_pat, arm_expr)
|
2016-07-19 17:32:06 +00:00
|
|
|
})
|
|
|
|
.collect();
|
2016-05-12 15:54:05 +00:00
|
|
|
|
2022-07-08 05:32:27 +00:00
|
|
|
// Add a default arm to the match, if necessary.
|
|
|
|
let first_fieldless = variants.iter().find(|v| v.data.fields().is_empty());
|
2016-05-12 15:54:05 +00:00
|
|
|
let default = match first_fieldless {
|
|
|
|
Some(v) if self.unify_fieldless_variants => {
|
2022-07-08 05:32:27 +00:00
|
|
|
// We need a default case that handles all the fieldless
|
|
|
|
// variants. The index and actual variant aren't meaningful in
|
|
|
|
// this case, so just use dummy values.
|
2022-06-28 03:10:36 +00:00
|
|
|
Some(
|
|
|
|
self.call_substructure_method(
|
|
|
|
cx,
|
|
|
|
trait_,
|
|
|
|
type_ident,
|
2022-07-04 22:25:47 +00:00
|
|
|
nonselflike_args,
|
2022-07-08 05:32:27 +00:00
|
|
|
&EnumMatching(0, variants.len(), v, Vec::new()),
|
2022-06-28 03:10:36 +00:00
|
|
|
)
|
|
|
|
.into_expr(cx, span),
|
|
|
|
)
|
2016-05-12 15:54:05 +00:00
|
|
|
}
|
2022-07-04 22:25:47 +00:00
|
|
|
_ if variants.len() > 1 && selflike_args.len() > 1 => {
|
2022-07-08 05:32:27 +00:00
|
|
|
// Because we know that all the arguments will match if we reach
|
2016-05-12 15:54:05 +00:00
|
|
|
// the match expression we add the unreachable intrinsics as the
|
2022-07-08 05:32:27 +00:00
|
|
|
// result of the default which should help llvm in optimizing it.
|
2021-11-20 18:46:36 +00:00
|
|
|
Some(deriving::call_unreachable(cx, span))
|
2016-05-12 15:54:05 +00:00
|
|
|
}
|
2016-07-19 17:32:06 +00:00
|
|
|
_ => None,
|
2016-05-12 15:54:05 +00:00
|
|
|
};
|
|
|
|
if let Some(arm) = default {
|
2021-11-20 18:46:36 +00:00
|
|
|
match_arms.push(cx.arm(span, cx.pat_wild(span), arm));
|
2016-05-12 15:54:05 +00:00
|
|
|
}
|
|
|
|
|
2022-07-08 05:32:27 +00:00
|
|
|
// Create a match expression with one arm per discriminant plus
|
|
|
|
// possibly a default arm, e.g.:
|
|
|
|
// match (self, other) {
|
|
|
|
// (Variant1, Variant1, ...) => Body1
|
|
|
|
// (Variant2, Variant2, ...) => Body2,
|
|
|
|
// ...
|
|
|
|
// _ => ::core::intrinsics::unreachable()
|
|
|
|
// }
|
|
|
|
let get_match_expr = |mut selflike_args: Vec<P<Expr>>| {
|
2022-07-04 22:25:47 +00:00
|
|
|
let match_arg = if selflike_args.len() == 1 {
|
|
|
|
selflike_args.pop().unwrap()
|
2022-07-04 05:08:28 +00:00
|
|
|
} else {
|
2022-07-04 22:25:47 +00:00
|
|
|
cx.expr(span, ast::ExprKind::Tup(selflike_args))
|
2022-07-04 05:08:28 +00:00
|
|
|
};
|
2022-07-08 05:32:27 +00:00
|
|
|
cx.expr_match(span, match_arg, match_arms)
|
|
|
|
};
|
|
|
|
|
|
|
|
// If the trait uses the tag and there are multiple variants, we need
|
|
|
|
// to add a tag check operation before the match. Otherwise, the match
|
|
|
|
// is enough.
|
|
|
|
if uses_tags && variants.len() > 1 {
|
|
|
|
let (tag_field, mut tag_let_stmts) = get_tag_pieces(cx);
|
|
|
|
|
|
|
|
// Combine a tag check with the match.
|
|
|
|
let mut tag_check_plus_match = self.call_substructure_method(
|
|
|
|
cx,
|
|
|
|
trait_,
|
|
|
|
type_ident,
|
|
|
|
nonselflike_args,
|
|
|
|
&EnumTag(tag_field, Some(get_match_expr(selflike_args))),
|
|
|
|
);
|
|
|
|
tag_let_stmts.append(&mut tag_check_plus_match.0);
|
|
|
|
BlockOrExpr(tag_let_stmts, tag_check_plus_match.1)
|
|
|
|
} else {
|
|
|
|
BlockOrExpr(vec![], Some(get_match_expr(selflike_args)))
|
2014-07-06 19:19:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-06 15:23:51 +00:00
|
|
|
fn expand_static_enum_method_body(
|
|
|
|
&self,
|
2019-02-04 12:49:54 +00:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
|
|
|
trait_: &TraitDef<'_>,
|
2014-01-09 13:05:33 +00:00
|
|
|
enum_def: &EnumDef,
|
2013-11-07 07:49:01 +00:00
|
|
|
type_ident: Ident,
|
2022-07-04 22:25:47 +00:00
|
|
|
nonselflike_args: &[P<Expr>],
|
2022-06-28 03:10:36 +00:00
|
|
|
) -> BlockOrExpr {
|
2016-07-19 17:32:06 +00:00
|
|
|
let summary = enum_def
|
|
|
|
.variants
|
|
|
|
.iter()
|
|
|
|
.map(|v| {
|
2017-07-31 20:04:34 +00:00
|
|
|
let sp = v.span.with_ctxt(trait_.span.ctxt());
|
2019-08-14 00:40:21 +00:00
|
|
|
let summary = trait_.summarise_struct(cx, &v.data);
|
|
|
|
(v.ident, sp, summary)
|
2016-07-19 17:32:06 +00:00
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
self.call_substructure_method(
|
|
|
|
cx,
|
|
|
|
trait_,
|
|
|
|
type_ident,
|
2022-07-04 22:25:47 +00:00
|
|
|
nonselflike_args,
|
2013-05-06 15:23:51 +00:00
|
|
|
&StaticEnum(enum_def, summary),
|
|
|
|
)
|
|
|
|
}
|
2013-03-28 10:50:10 +00:00
|
|
|
}
|
|
|
|
|
2013-12-07 00:57:44 +00:00
|
|
|
// general helper methods.
|
|
|
|
impl<'a> TraitDef<'a> {
|
2019-02-04 12:49:54 +00:00
|
|
|
fn summarise_struct(&self, cx: &mut ExtCtxt<'_>, struct_def: &VariantData) -> StaticFields {
|
2014-02-28 21:09:09 +00:00
|
|
|
let mut named_idents = Vec::new();
|
|
|
|
let mut just_spans = Vec::new();
|
2016-07-19 17:32:06 +00:00
|
|
|
for field in struct_def.fields() {
|
2017-07-31 20:04:34 +00:00
|
|
|
let sp = field.span.with_ctxt(self.span.ctxt());
|
2016-04-06 08:19:10 +00:00
|
|
|
match field.ident {
|
2016-04-02 13:47:53 +00:00
|
|
|
Some(ident) => named_idents.push((ident, sp)),
|
|
|
|
_ => just_spans.push(sp),
|
2013-12-07 00:57:44 +00:00
|
|
|
}
|
2013-03-28 10:50:10 +00:00
|
|
|
}
|
2013-05-06 15:23:51 +00:00
|
|
|
|
2020-09-18 17:11:06 +00:00
|
|
|
let is_tuple = matches!(struct_def, ast::VariantData::Tuple(..));
|
2013-12-07 00:57:44 +00:00
|
|
|
match (just_spans.is_empty(), named_idents.is_empty()) {
|
2021-11-03 04:19:06 +00:00
|
|
|
(false, false) => {
|
|
|
|
cx.span_bug(self.span, "a struct with named and unnamed fields in generic `derive`")
|
|
|
|
}
|
2013-12-07 00:57:44 +00:00
|
|
|
// named fields
|
|
|
|
(_, false) => Named(named_idents),
|
2019-03-23 21:06:58 +00:00
|
|
|
// unnamed fields
|
|
|
|
(false, _) => Unnamed(just_spans, is_tuple),
|
|
|
|
// empty
|
|
|
|
_ => Named(Vec::new()),
|
2013-12-07 00:57:44 +00:00
|
|
|
}
|
2013-03-28 10:50:10 +00:00
|
|
|
}
|
|
|
|
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
fn create_struct_patterns(
|
2013-12-07 00:57:44 +00:00
|
|
|
&self,
|
2019-02-04 12:49:54 +00:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
struct_path: ast::Path,
|
|
|
|
struct_def: &'a VariantData,
|
|
|
|
prefixes: &[String],
|
2022-08-30 22:34:35 +00:00
|
|
|
by_ref: ByRef,
|
2014-09-13 16:06:01 +00:00
|
|
|
) -> Vec<P<ast::Pat>> {
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
prefixes
|
2016-07-19 17:32:06 +00:00
|
|
|
.iter()
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
.map(|prefix| {
|
2022-07-07 21:57:34 +00:00
|
|
|
let pieces_iter =
|
|
|
|
struct_def.fields().iter().enumerate().map(|(i, struct_field)| {
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
let sp = struct_field.span.with_ctxt(self.span.ctxt());
|
|
|
|
let ident = self.mk_pattern_ident(prefix, i);
|
|
|
|
let path = ident.with_span_pos(sp);
|
|
|
|
(
|
|
|
|
sp,
|
|
|
|
struct_field.ident,
|
2022-08-30 22:34:35 +00:00
|
|
|
cx.pat(
|
|
|
|
path.span,
|
|
|
|
PatKind::Ident(
|
|
|
|
BindingAnnotation(by_ref, Mutability::Not),
|
|
|
|
path,
|
|
|
|
None,
|
|
|
|
),
|
|
|
|
),
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
)
|
2022-07-07 21:57:34 +00:00
|
|
|
});
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
|
|
|
|
let struct_path = struct_path.clone();
|
|
|
|
match *struct_def {
|
|
|
|
VariantData::Struct(..) => {
|
2022-07-07 21:57:34 +00:00
|
|
|
let field_pats = pieces_iter
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
.map(|(sp, ident, pat)| {
|
|
|
|
if ident.is_none() {
|
|
|
|
cx.span_bug(
|
|
|
|
sp,
|
|
|
|
"a braced struct with unnamed fields in `derive`",
|
|
|
|
);
|
|
|
|
}
|
|
|
|
ast::PatField {
|
|
|
|
ident: ident.unwrap(),
|
|
|
|
is_shorthand: false,
|
|
|
|
attrs: ast::AttrVec::new(),
|
|
|
|
id: ast::DUMMY_NODE_ID,
|
|
|
|
span: pat.span.with_ctxt(self.span.ctxt()),
|
|
|
|
pat,
|
|
|
|
is_placeholder: false,
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
cx.pat_struct(self.span, struct_path, field_pats)
|
|
|
|
}
|
|
|
|
VariantData::Tuple(..) => {
|
2022-07-07 21:57:34 +00:00
|
|
|
let subpats = pieces_iter.map(|(_, _, subpat)| subpat).collect();
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
cx.pat_tuple_struct(self.span, struct_path, subpats)
|
|
|
|
}
|
|
|
|
VariantData::Unit(..) => cx.pat_path(self.span, struct_path),
|
|
|
|
}
|
2016-07-19 17:32:06 +00:00
|
|
|
})
|
|
|
|
.collect()
|
2013-12-07 00:57:44 +00:00
|
|
|
}
|
2013-06-07 07:30:38 +00:00
|
|
|
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
fn create_fields<F>(&self, struct_def: &'a VariantData, mk_exprs: F) -> Vec<FieldInfo>
|
|
|
|
where
|
|
|
|
F: Fn(usize, &ast::FieldDef, Span) -> Vec<P<ast::Expr>>,
|
|
|
|
{
|
|
|
|
struct_def
|
|
|
|
.fields()
|
|
|
|
.iter()
|
|
|
|
.enumerate()
|
|
|
|
.map(|(i, struct_field)| {
|
|
|
|
// For this field, get an expr for each selflike_arg. E.g. for
|
|
|
|
// `PartialEq::eq`, one for each of `&self` and `other`.
|
|
|
|
let sp = struct_field.span.with_ctxt(self.span.ctxt());
|
|
|
|
let mut exprs: Vec<_> = mk_exprs(i, struct_field, sp);
|
|
|
|
let self_expr = exprs.remove(0);
|
|
|
|
let other_selflike_exprs = exprs;
|
|
|
|
FieldInfo {
|
|
|
|
span: sp.with_ctxt(self.span.ctxt()),
|
|
|
|
name: struct_field.ident,
|
|
|
|
self_expr,
|
|
|
|
other_selflike_exprs,
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect()
|
|
|
|
}
|
2013-06-07 07:30:38 +00:00
|
|
|
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
fn mk_pattern_ident(&self, prefix: &str, i: usize) -> Ident {
|
|
|
|
Ident::from_str_and_span(&format!("{}_{}", prefix, i), self.span)
|
2013-12-07 00:57:44 +00:00
|
|
|
}
|
2013-06-07 07:30:38 +00:00
|
|
|
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
fn create_struct_pattern_fields(
|
Don't use match-destructuring for derived ops on structs.
All derive ops currently use match-destructuring to access fields. This
is reasonable for enums, but sub-optimal for structs. E.g.:
```
fn eq(&self, other: &Point) -> bool {
match *other {
Self { x: ref __self_1_0, y: ref __self_1_1 } =>
match *self {
Self { x: ref __self_0_0, y: ref __self_0_1 } =>
(*__self_0_0) == (*__self_1_0) &&
(*__self_0_1) == (*__self_1_1),
},
}
}
```
This commit changes derive ops on structs to use field access instead, e.g.:
```
fn eq(&self, other: &Point) -> bool {
self.x == other.x && self.y == other.y
}
```
This is faster to compile, results in smaller binaries, and is simpler to
generate. Unfortunately, we have to keep the old pattern generating code around
for `repr(packed)` structs because something like `&self.x` (which doesn't show
up in `PartialEq` ops, but does show up in `Debug` and `Hash` ops) isn't
allowed. But this commit at least changes those cases to use let-destructuring
instead of match-destructuring, e.g.:
```
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
{
let Self(ref __self_0_0) = *self;
{ ::core::hash::Hash::hash(&(*__self_0_0), state) }
}
}
```
There are some unnecessary blocks remaining in the generated code, but I
will fix them in a follow-up PR.
2022-06-24 00:20:54 +00:00
|
|
|
&self,
|
|
|
|
cx: &mut ExtCtxt<'_>,
|
|
|
|
struct_def: &'a VariantData,
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
prefixes: &[String],
|
|
|
|
) -> Vec<FieldInfo> {
|
|
|
|
self.create_fields(struct_def, |i, _struct_field, sp| {
|
|
|
|
prefixes
|
|
|
|
.iter()
|
|
|
|
.map(|prefix| {
|
|
|
|
let ident = self.mk_pattern_ident(prefix, i);
|
2022-11-14 02:59:54 +00:00
|
|
|
cx.expr_path(cx.path_ident(sp, ident))
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
})
|
|
|
|
.collect()
|
|
|
|
})
|
Don't use match-destructuring for derived ops on structs.
All derive ops currently use match-destructuring to access fields. This
is reasonable for enums, but sub-optimal for structs. E.g.:
```
fn eq(&self, other: &Point) -> bool {
match *other {
Self { x: ref __self_1_0, y: ref __self_1_1 } =>
match *self {
Self { x: ref __self_0_0, y: ref __self_0_1 } =>
(*__self_0_0) == (*__self_1_0) &&
(*__self_0_1) == (*__self_1_1),
},
}
}
```
This commit changes derive ops on structs to use field access instead, e.g.:
```
fn eq(&self, other: &Point) -> bool {
self.x == other.x && self.y == other.y
}
```
This is faster to compile, results in smaller binaries, and is simpler to
generate. Unfortunately, we have to keep the old pattern generating code around
for `repr(packed)` structs because something like `&self.x` (which doesn't show
up in `PartialEq` ops, but does show up in `Debug` and `Hash` ops) isn't
allowed. But this commit at least changes those cases to use let-destructuring
instead of match-destructuring, e.g.:
```
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
{
let Self(ref __self_0_0) = *self;
{ ::core::hash::Hash::hash(&(*__self_0_0), state) }
}
}
```
There are some unnecessary blocks remaining in the generated code, but I
will fix them in a follow-up PR.
2022-06-24 00:20:54 +00:00
|
|
|
}
|
|
|
|
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
fn create_struct_field_access_fields(
|
2016-07-19 17:32:06 +00:00
|
|
|
&self,
|
2019-02-04 12:49:54 +00:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
selflike_args: &[P<Expr>],
|
|
|
|
struct_def: &'a VariantData,
|
2022-11-21 00:48:25 +00:00
|
|
|
copy_fields: bool,
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
) -> Vec<FieldInfo> {
|
|
|
|
self.create_fields(struct_def, |i, struct_field, sp| {
|
|
|
|
selflike_args
|
|
|
|
.iter()
|
2022-07-06 06:13:51 +00:00
|
|
|
.map(|selflike_arg| {
|
2022-07-07 01:09:07 +00:00
|
|
|
// Note: we must use `struct_field.span` rather than `sp` in the
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
// `unwrap_or_else` case otherwise the hygiene is wrong and we get
|
|
|
|
// "field `0` of struct `Point` is private" errors on tuple
|
|
|
|
// structs.
|
2022-07-11 02:54:52 +00:00
|
|
|
let mut field_expr = cx.expr(
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
sp,
|
2022-07-11 02:54:52 +00:00
|
|
|
ast::ExprKind::Field(
|
|
|
|
selflike_arg.clone(),
|
|
|
|
struct_field.ident.unwrap_or_else(|| {
|
|
|
|
Ident::from_str_and_span(&i.to_string(), struct_field.span)
|
|
|
|
}),
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
),
|
2022-07-11 02:54:52 +00:00
|
|
|
);
|
2022-11-21 00:48:25 +00:00
|
|
|
if copy_fields {
|
2022-07-11 02:54:52 +00:00
|
|
|
field_expr = cx.expr_block(
|
|
|
|
cx.block(struct_field.span, vec![cx.stmt_expr(field_expr)]),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
cx.expr_addr_of(sp, field_expr)
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
})
|
|
|
|
.collect()
|
|
|
|
})
|
2013-06-07 07:30:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-05 01:23:55 +00:00
|
|
|
/// The function passed to `cs_fold` is called repeatedly with a value of this
|
|
|
|
/// type. It describes one part of the code generation. The result is always an
|
|
|
|
/// expression.
|
|
|
|
pub enum CsFold<'a> {
|
|
|
|
/// The basic case: a field expression for one or more selflike args. E.g.
|
|
|
|
/// for `PartialEq::eq` this is something like `self.x == other.x`.
|
|
|
|
Single(&'a FieldInfo),
|
|
|
|
|
|
|
|
/// The combination of two field expressions. E.g. for `PartialEq::eq` this
|
|
|
|
/// is something like `<field1 equality> && <field2 equality>`.
|
|
|
|
Combine(Span, P<Expr>, P<Expr>),
|
|
|
|
|
|
|
|
// The fallback case for a struct or enum variant with no fields.
|
|
|
|
Fieldless,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Folds over fields, combining the expressions for each field in a sequence.
|
|
|
|
/// Statics may not be folded over.
|
|
|
|
pub fn cs_fold<F>(
|
2018-04-11 14:16:54 +00:00
|
|
|
use_foldl: bool,
|
2019-02-04 12:49:54 +00:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
2018-04-11 14:16:54 +00:00
|
|
|
trait_span: Span,
|
2019-02-04 12:49:54 +00:00
|
|
|
substructure: &Substructure<'_>,
|
2022-07-05 01:23:55 +00:00
|
|
|
mut f: F,
|
2018-04-11 14:16:54 +00:00
|
|
|
) -> P<Expr>
|
2019-02-04 12:49:54 +00:00
|
|
|
where
|
2022-07-05 01:23:55 +00:00
|
|
|
F: FnMut(&mut ExtCtxt<'_>, CsFold<'_>) -> P<Expr>,
|
2018-04-11 14:16:54 +00:00
|
|
|
{
|
2022-07-08 05:32:27 +00:00
|
|
|
match substructure.fields {
|
|
|
|
EnumMatching(.., all_fields) | Struct(_, all_fields) => {
|
2022-07-05 01:23:55 +00:00
|
|
|
if all_fields.is_empty() {
|
|
|
|
return f(cx, CsFold::Fieldless);
|
|
|
|
}
|
|
|
|
|
|
|
|
let (base_field, rest) = if use_foldl {
|
|
|
|
all_fields.split_first().unwrap()
|
|
|
|
} else {
|
|
|
|
all_fields.split_last().unwrap()
|
|
|
|
};
|
|
|
|
|
|
|
|
let base_expr = f(cx, CsFold::Single(base_field));
|
|
|
|
|
|
|
|
let op = |old, field: &FieldInfo| {
|
|
|
|
let new = f(cx, CsFold::Single(field));
|
|
|
|
f(cx, CsFold::Combine(field.span, old, new))
|
2018-04-11 14:16:54 +00:00
|
|
|
};
|
|
|
|
|
2022-07-04 07:10:36 +00:00
|
|
|
if use_foldl {
|
2022-07-05 01:23:55 +00:00
|
|
|
rest.iter().fold(base_expr, op)
|
2022-07-04 07:10:36 +00:00
|
|
|
} else {
|
2022-07-05 01:23:55 +00:00
|
|
|
rest.iter().rfold(base_expr, op)
|
2022-07-04 07:10:36 +00:00
|
|
|
}
|
2018-04-11 14:16:54 +00:00
|
|
|
}
|
2022-07-08 05:32:27 +00:00
|
|
|
EnumTag(tag_field, match_expr) => {
|
|
|
|
let tag_check_expr = f(cx, CsFold::Single(tag_field));
|
|
|
|
if let Some(match_expr) = match_expr {
|
|
|
|
if use_foldl {
|
|
|
|
f(cx, CsFold::Combine(trait_span, tag_check_expr, match_expr.clone()))
|
|
|
|
} else {
|
|
|
|
f(cx, CsFold::Combine(trait_span, match_expr.clone(), tag_check_expr))
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
tag_check_expr
|
|
|
|
}
|
|
|
|
}
|
2022-07-04 07:10:36 +00:00
|
|
|
StaticEnum(..) | StaticStruct(..) => cx.span_bug(trait_span, "static function in `derive`"),
|
2018-04-11 14:16:54 +00:00
|
|
|
}
|
|
|
|
}
|