2014-06-09 13:12:30 -07:00
|
|
|
//! Some code that abstracts away much of the boilerplate of writing
|
2014-12-31 17:25:18 +13:00
|
|
|
//! `derive` instances for traits. Among other things it manages getting
|
2014-06-09 13:12:30 -07: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 13:12:30 -07:00
|
|
|
//! current trait as a bound. (This includes separate type parameters
|
|
|
|
//! and lifetimes for methods.)
|
2015-01-13 00:00:19 +11:00
|
|
|
//! - Additional bounds on the type parameters (`TraitDef.additional_bounds`)
|
2014-06-09 13:12:30 -07:00
|
|
|
//!
|
2017-08-15 21:45:21 +02:00
|
|
|
//! The most important thing for implementors is the `Substructure` and
|
2014-06-09 13:12:30 -07: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 13:12:30 -07: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)`)
|
2014-07-07 09:13:49 +02:00
|
|
|
//! - `EnumNonMatchingCollapsed` when `Self` is an enum and the arguments
|
2018-11-27 02:59:49 +00:00
|
|
|
//! are not the same variant (e.g., `None`, `Some(1)` and `None`).
|
2014-06-09 13:12:30 -07: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
|
2014-07-07 09:13:49 +02:00
|
|
|
//! all the arguments are grouped together. For `EnumNonMatchingCollapsed`
|
2014-06-09 13:12:30 -07:00
|
|
|
//! this isn't possible (different variants have different fields), so the
|
2014-07-07 09:13:49 +02:00
|
|
|
//! fields are inaccessible. (Previous versions of the deriving infrastructure
|
|
|
|
//! had a way to expand into code that could access them, at the cost of
|
|
|
|
//! generating exponential amounts of code; see issue #15375). There are no
|
2014-06-09 13:12:30 -07:00
|
|
|
//! fields with values in the static cases, so these are treated entirely
|
|
|
|
//! differently.
|
|
|
|
//!
|
|
|
|
//! The non-static cases have `Option<ident>` in several places associated
|
|
|
|
//! with field `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 13:12:30 -07:00
|
|
|
//!
|
2015-01-17 23:55:21 +00:00
|
|
|
//! struct B(i32);
|
2014-06-09 13:12:30 -07:00
|
|
|
//!
|
|
|
|
//! enum C {
|
2015-01-17 23:55:21 +00:00
|
|
|
//! C0(i32),
|
|
|
|
//! C1 { x: i32 }
|
2014-06-09 13:12:30 -07: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 13:12:30 -07:00
|
|
|
//! `Option<ident>`s would be `None` for them.
|
|
|
|
//!
|
2018-11-12 13:05:20 -05:00
|
|
|
//! In the static cases, the structure is summarized, either into the just
|
2014-06-09 13:12:30 -07: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-13 00:00:19 +11:00
|
|
|
//! # "`cs`" functions
|
|
|
|
//!
|
2022-06-24 08:31:00 +10:00
|
|
|
//! The `cs_...` functions ("combine substructure") are designed to
|
2015-01-13 00:00:19 +11:00
|
|
|
//! make life easier by providing some pre-made recipes for common
|
2015-05-09 00:12:29 +09:00
|
|
|
//! threads; mostly calling the function being derived on all the
|
2015-01-13 00:00:19 +11: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 13:12:30 -07: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 13:12:30 -07:00
|
|
|
//! }
|
2015-01-17 23:55:21 +00:00
|
|
|
//! impl PartialEq for i32 {
|
|
|
|
//! fn eq(&self, other: &i32) -> bool {
|
2014-06-09 13:12:30 -07: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 13:27:34 +02:00
|
|
|
//! ```{.text}
|
2015-01-13 00:00:19 +11:00
|
|
|
//! Struct(vec![FieldInfo {
|
2014-06-09 13:12:30 -07:00
|
|
|
//! span: <span of x>
|
|
|
|
//! name: Some(<ident of x>),
|
|
|
|
//! self_: <expr for &self.x>,
|
2015-01-13 00:00:19 +11:00
|
|
|
//! other: vec![<expr for &other.x]
|
2014-06-09 13:12:30 -07:00
|
|
|
//! }])
|
2014-09-16 13:27:34 +02:00
|
|
|
//! ```
|
2014-06-09 13:12:30 -07:00
|
|
|
//!
|
|
|
|
//! For the `B` impl, called with `B(a)` and `B(b)`,
|
|
|
|
//!
|
2014-09-16 13:27:34 +02:00
|
|
|
//! ```{.text}
|
2015-01-13 00:00:19 +11:00
|
|
|
//! Struct(vec![FieldInfo {
|
2015-01-17 23:55:21 +00:00
|
|
|
//! span: <span of `i32`>,
|
2014-06-09 13:12:30 -07:00
|
|
|
//! name: None,
|
2015-01-13 00:00:19 +11:00
|
|
|
//! self_: <expr for &a>
|
|
|
|
//! other: vec![<expr for &b>]
|
2014-06-09 13:12:30 -07:00
|
|
|
//! }])
|
2014-09-16 13:27:34 +02:00
|
|
|
//! ```
|
2014-06-09 13:12:30 -07:00
|
|
|
//!
|
|
|
|
//! ## Enums
|
|
|
|
//!
|
|
|
|
//! When generating the `expr` for a call with `self == C0(a)` and `other
|
|
|
|
//! == C0(b)`, the SubstructureFields is
|
|
|
|
//!
|
2014-09-16 13:27:34 +02:00
|
|
|
//! ```{.text}
|
2014-06-09 13:12:30 -07:00
|
|
|
//! EnumMatching(0, <ast::Variant for C0>,
|
2015-01-13 00:00:19 +11:00
|
|
|
//! vec![FieldInfo {
|
2015-01-17 23:55:21 +00:00
|
|
|
//! span: <span of i32>
|
2014-06-09 13:12:30 -07:00
|
|
|
//! name: None,
|
|
|
|
//! self_: <expr for &a>,
|
2015-01-13 00:00:19 +11:00
|
|
|
//! other: vec![<expr for &b>]
|
2014-06-09 13:12:30 -07:00
|
|
|
//! }])
|
2014-09-16 13:27:34 +02:00
|
|
|
//! ```
|
2014-06-09 13:12:30 -07:00
|
|
|
//!
|
2014-07-06 21:19:12 +02:00
|
|
|
//! For `C1 {x}` and `C1 {x}`,
|
2014-06-09 13:12:30 -07:00
|
|
|
//!
|
2014-09-16 13:27:34 +02:00
|
|
|
//! ```{.text}
|
2014-06-09 13:12:30 -07:00
|
|
|
//! EnumMatching(1, <ast::Variant for C1>,
|
2015-01-13 00:00:19 +11:00
|
|
|
//! vec![FieldInfo {
|
2014-06-09 13:12:30 -07:00
|
|
|
//! span: <span of x>
|
|
|
|
//! name: Some(<ident of x>),
|
|
|
|
//! self_: <expr for &self.x>,
|
2015-01-13 00:00:19 +11:00
|
|
|
//! other: vec![<expr for &other.x>]
|
2014-06-09 13:12:30 -07:00
|
|
|
//! }])
|
2014-09-16 13:27:34 +02:00
|
|
|
//! ```
|
2014-06-09 13:12:30 -07:00
|
|
|
//!
|
|
|
|
//! For `C0(a)` and `C1 {x}` ,
|
|
|
|
//!
|
2014-09-16 13:27:34 +02:00
|
|
|
//! ```{.text}
|
2014-07-06 21:19:12 +02:00
|
|
|
//! EnumNonMatchingCollapsed(
|
2016-03-17 00:43:36 +05:30
|
|
|
//! &[<ident for self index value>, <ident of __arg_1 index value>])
|
2014-09-16 13:27:34 +02:00
|
|
|
//! ```
|
2014-06-09 13:12:30 -07:00
|
|
|
//!
|
2014-07-06 21:19:12 +02:00
|
|
|
//! It is the same for when the arguments are flipped to `C1 {x}` and
|
|
|
|
//! `C0(a)`; the only difference is what the values of the identifiers
|
2016-03-17 00:43:36 +05:30
|
|
|
//! <ident for self index value> and <ident of __arg_1 index value> will
|
2014-07-06 21:19:12 +02:00
|
|
|
//! be in the generated code.
|
|
|
|
//!
|
|
|
|
//! `EnumNonMatchingCollapsed` deliberately provides far less information
|
|
|
|
//! than is generally available for a given pair of variants; see #15375
|
|
|
|
//! for discussion.
|
2014-06-09 13:12:30 -07:00
|
|
|
//!
|
|
|
|
//! ## Static
|
|
|
|
//!
|
2015-01-13 00:00:19 +11:00
|
|
|
//! A static method on the types above would result in,
|
2014-06-09 13:12:30 -07:00
|
|
|
//!
|
2014-09-16 13:27:34 +02:00
|
|
|
//! ```{.text}
|
2015-10-08 03:20:57 +03:00
|
|
|
//! StaticStruct(<ast::VariantData of A>, Named(vec![(<ident of x>, <span of x>)]))
|
2014-06-09 13:12:30 -07:00
|
|
|
//!
|
2015-10-08 03:20:57 +03:00
|
|
|
//! StaticStruct(<ast::VariantData of B>, Unnamed(vec![<span of x>]))
|
2014-06-09 13:12:30 -07:00
|
|
|
//!
|
2015-01-13 00:00:19 +11: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-13 00:00:19 +11:00
|
|
|
//! (<ident of C1>, <span of C1>, Named(vec![(<ident of x>, <span of x>)]))])
|
2014-09-16 13:27:34 +02:00
|
|
|
//! ```
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2019-02-04 21:49:54 +09:00
|
|
|
pub use StaticFields::*;
|
|
|
|
pub use SubstructureFields::*;
|
2014-11-06 00:05:53 -08:00
|
|
|
|
2014-04-21 23:25:18 -07:00
|
|
|
use std::cell::RefCell;
|
2018-07-26 17:11:10 +02:00
|
|
|
use std::iter;
|
2014-09-13 19:06:01 +03:00
|
|
|
use std::vec;
|
2014-04-21 23:25:18 -07:00
|
|
|
|
2020-02-29 20:37:32 +03:00
|
|
|
use rustc_ast::ptr::P;
|
2020-04-27 23:26:11 +05:30
|
|
|
use rustc_ast::{self as ast, BinOpKind, EnumDef, Expr, Generics, PatKind};
|
|
|
|
use rustc_ast::{GenericArg, GenericParamKind, VariantData};
|
2020-01-11 13:15:20 +01:00
|
|
|
use rustc_attr as attr;
|
2019-12-29 17:23:55 +03:00
|
|
|
use rustc_expand::base::{Annotatable, ExtCtxt};
|
2020-04-19 13:00:18 +02:00
|
|
|
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
2019-12-31 20:15:40 +03:00
|
|
|
use rustc_span::Span;
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2022-06-30 09:15:07 +10:00
|
|
|
use ty::{Bounds, Path, Ref, Self_, Ty};
|
2014-05-29 12:19:05 +09:00
|
|
|
|
2019-02-04 21:49:54 +09:00
|
|
|
use crate::deriving;
|
2016-03-10 00:31:19 -05:00
|
|
|
|
2014-05-29 12:19:05 +09:00
|
|
|
pub mod ty;
|
2013-05-07 01:23:51 +10:00
|
|
|
|
2013-12-09 23:16:18 -08:00
|
|
|
pub struct TraitDef<'a> {
|
2014-12-31 17:25:18 +13:00
|
|
|
/// The span for the current #[derive(Foo)] header.
|
2014-03-27 15:39:48 -07:00
|
|
|
pub span: Span,
|
2013-12-07 11:57:44 +11:00
|
|
|
|
2014-03-27 15:39:48 -07:00
|
|
|
pub attributes: Vec<ast::Attribute>,
|
2014-02-14 08:09:51 -08:00
|
|
|
|
2013-05-07 01:23:51 +10:00
|
|
|
/// Path of the trait, including any type parameters
|
2020-07-14 15:05:26 +10:00
|
|
|
pub path: Path,
|
2014-02-08 19:39:53 -05:00
|
|
|
|
2013-05-07 01:23:51 +10:00
|
|
|
/// Additional bounds required of any type parameters of the type,
|
|
|
|
/// other than the current trait
|
2020-07-14 15:05:26 +10:00
|
|
|
pub additional_bounds: Vec<Ty>,
|
2013-05-07 01:23:51 +10:00
|
|
|
|
2018-11-27 02:59:49 +00:00
|
|
|
/// Any extra lifetimes and/or bounds, e.g., `D: serialize::Decoder`
|
2020-07-14 15:05:26 +10:00
|
|
|
pub generics: Bounds,
|
2013-05-07 01:23:51 +10:00
|
|
|
|
2016-08-29 11:14:25 +00:00
|
|
|
/// Can this trait be derived for unions?
|
|
|
|
pub supports_unions: bool,
|
|
|
|
|
2014-03-27 15:39:48 -07:00
|
|
|
pub methods: Vec<MethodDef<'a>>,
|
2015-01-25 00:29:24 -05:00
|
|
|
|
2020-07-14 15:05:26 +10:00
|
|
|
pub associated_types: Vec<(Ident, Ty)>,
|
2014-03-27 15:39:48 -07:00
|
|
|
}
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2013-12-09 23:16:18 -08:00
|
|
|
pub struct MethodDef<'a> {
|
2013-03-28 21:50:10 +11:00
|
|
|
/// name of the method
|
2020-07-08 11:04:10 +10:00
|
|
|
pub name: Symbol,
|
2018-11-27 02:59:49 +00:00
|
|
|
/// List of generics, e.g., `R: rand::Rng`
|
2020-07-14 15:05:26 +10:00
|
|
|
pub generics: Bounds,
|
2013-05-07 01:23:51 +10:00
|
|
|
|
2022-06-30 09:15:07 +10:00
|
|
|
/// Is there is a `&self` argument? If not, it is a static function.
|
|
|
|
pub explicit_self: bool,
|
2013-05-07 01:23:51 +10:00
|
|
|
|
2022-07-05 08:25:47 +10:00
|
|
|
/// Arguments other than the self argument.
|
|
|
|
pub nonself_args: Vec<(Ty, Symbol)>,
|
2013-05-07 01:23:51 +10:00
|
|
|
|
2019-02-08 14:53:55 +01:00
|
|
|
/// Returns type
|
2020-07-14 15:05:26 +10:00
|
|
|
pub ret_ty: Ty,
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2014-04-23 22:43:45 +08:00
|
|
|
pub attributes: Vec<ast::Attribute>,
|
2013-11-19 11:13:34 +11:00
|
|
|
|
2016-05-12 17:54:05 +02:00
|
|
|
/// Can we combine fieldless variants for enums into a single match arm?
|
|
|
|
pub unify_fieldless_variants: bool,
|
|
|
|
|
2014-04-21 23:25:18 -07:00
|
|
|
pub combine_substructure: RefCell<CombineSubstructureFunc<'a>>,
|
2013-03-28 21:50:10 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
/// All the data about the data structure/method being derived upon.
|
2013-12-09 23:16:18 -08:00
|
|
|
pub struct Substructure<'a> {
|
2013-05-07 01:23:51 +10:00
|
|
|
/// ident of self
|
2014-03-27 15:39:48 -07:00
|
|
|
pub type_ident: Ident,
|
2022-07-08 07:57:34 +10:00
|
|
|
/// Verbatim access to any non-selflike arguments, i.e. arguments that
|
|
|
|
/// don't have type `&Self`.
|
2022-07-05 08:25:47 +10:00
|
|
|
pub nonselflike_args: &'a [P<Expr>],
|
2016-07-19 23:02:06 +05:30
|
|
|
pub fields: &'a SubstructureFields<'a>,
|
2013-03-28 21:50:10 +11:00
|
|
|
}
|
|
|
|
|
2013-11-07 18:49:01 +11:00
|
|
|
/// Summary of the relevant parts of a struct/enum field.
|
2022-07-05 08:59:17 +10:00
|
|
|
pub struct FieldInfo {
|
2014-03-27 15:39:48 -07:00
|
|
|
pub span: Span,
|
2013-11-07 18:49:01 +11:00
|
|
|
/// None for tuple structs/normal enum variants, Some for normal
|
|
|
|
/// structs/struct enum variants.
|
2014-03-27 15:39:48 -07:00
|
|
|
pub name: Option<Ident>,
|
2013-11-07 18:49:01 +11:00
|
|
|
/// The expression corresponding to this field of `self`
|
|
|
|
/// (specifically, a reference to it).
|
2022-07-05 08:47:04 +10:00
|
|
|
pub self_expr: P<Expr>,
|
2013-11-07 18:49:01 +11:00
|
|
|
/// The expressions corresponding to references to this field in
|
2022-07-05 08:47:04 +10:00
|
|
|
/// the other selflike arguments.
|
|
|
|
pub other_selflike_exprs: Vec<P<Expr>>,
|
2014-03-27 15:39:48 -07:00
|
|
|
}
|
2013-11-07 18:49:01 +11:00
|
|
|
|
|
|
|
/// Fields for a static method
|
|
|
|
pub enum StaticFields {
|
2016-08-15 21:28:17 +03:00
|
|
|
/// Tuple and unit structs/enum variants like this.
|
|
|
|
Unnamed(Vec<Span>, bool /*is tuple*/),
|
2013-11-07 18:49:01 +11:00
|
|
|
/// Normal structs/struct variants.
|
2014-05-16 00:16:13 -07:00
|
|
|
Named(Vec<(Ident, Span)>),
|
2013-11-07 18:49:01 +11:00
|
|
|
}
|
|
|
|
|
2014-09-17 15:12:58 +02:00
|
|
|
/// A summary of the possible sets of fields.
|
2013-12-09 23:16:18 -08:00
|
|
|
pub enum SubstructureFields<'a> {
|
2022-07-05 08:59:17 +10:00
|
|
|
Struct(&'a ast::VariantData, Vec<FieldInfo>),
|
2017-06-16 22:59:20 +03:00
|
|
|
/// Matching variants of the enum: variant index, variant count, ast::Variant,
|
2014-09-16 13:27:34 +02:00
|
|
|
/// fields: the field name is only non-`None` in the case of a struct
|
|
|
|
/// variant.
|
2022-07-05 08:59:17 +10:00
|
|
|
EnumMatching(usize, usize, &'a ast::Variant, Vec<FieldInfo>),
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2022-06-28 08:56:54 +10:00
|
|
|
/// Non-matching variants of the enum, but with all state hidden from the
|
|
|
|
/// consequent code. The field is a list of `Ident`s bound to the variant
|
|
|
|
/// index values for each of the actual input `Self` arguments.
|
|
|
|
EnumNonMatchingCollapsed(&'a [Ident]),
|
2014-07-06 21:19:12 +02:00
|
|
|
|
2014-09-17 15:02:26 +02:00
|
|
|
/// A static method where `Self` is a struct.
|
2015-10-08 03:20:57 +03:00
|
|
|
StaticStruct(&'a ast::VariantData, StaticFields),
|
2014-09-17 15:02:26 +02:00
|
|
|
/// A static method where `Self` is an enum.
|
2014-05-16 00:16:13 -07:00
|
|
|
StaticEnum(&'a ast::EnumDef, Vec<(Ident, Span, StaticFields)>),
|
2013-03-28 21:50:10 +11:00
|
|
|
}
|
|
|
|
|
2014-09-16 13:27:34 +02:00
|
|
|
/// Combine the values of all the fields together. The last argument is
|
2014-09-17 15:12:58 +02:00
|
|
|
/// all the fields of all the structures.
|
2013-12-09 23:16:18 -08:00
|
|
|
pub type CombineSubstructureFunc<'a> =
|
2022-06-28 13:10:36 +10:00
|
|
|
Box<dyn FnMut(&mut ExtCtxt<'_>, Span, &Substructure<'_>) -> BlockOrExpr + 'a>;
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2019-06-21 18:51:27 +02:00
|
|
|
pub fn combine_substructure(
|
|
|
|
f: CombineSubstructureFunc<'_>,
|
|
|
|
) -> RefCell<CombineSubstructureFunc<'_>> {
|
2014-04-21 23:25:18 -07:00
|
|
|
RefCell::new(f)
|
|
|
|
}
|
|
|
|
|
2021-09-29 00:46:29 +02:00
|
|
|
struct TypeParameter {
|
|
|
|
bound_generic_params: Vec<ast::GenericParam>,
|
|
|
|
ty: P<ast::Ty>,
|
|
|
|
}
|
|
|
|
|
2022-06-28 13:10:36 +10: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.
|
|
|
|
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))
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn new_mixed(stmts: Vec<ast::Stmt>, expr: P<Expr>) -> BlockOrExpr {
|
|
|
|
BlockOrExpr(stmts, Some(expr))
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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,
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
cx.expr_block(self.into_block(cx, span))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-24 14:43:26 -07: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-29 00:46:29 +02:00
|
|
|
/// Also include bound generic params from the input type.
|
2019-06-16 12:41:24 +03:00
|
|
|
fn find_type_parameters(
|
|
|
|
ty: &ast::Ty,
|
2020-04-19 13:00:18 +02:00
|
|
|
ty_param_names: &[Symbol],
|
2019-06-16 12:41:24 +03:00
|
|
|
cx: &ExtCtxt<'_>,
|
2021-09-29 00:46:29 +02:00
|
|
|
) -> Vec<TypeParameter> {
|
2020-02-29 20:37:32 +03:00
|
|
|
use rustc_ast::visit;
|
2015-03-24 14:43:26 -07:00
|
|
|
|
2019-06-14 19:39:39 +03:00
|
|
|
struct Visitor<'a, 'b> {
|
2016-06-24 03:23:44 +00:00
|
|
|
cx: &'a ExtCtxt<'b>,
|
2020-04-19 13:00:18 +02:00
|
|
|
ty_param_names: &'a [Symbol],
|
2021-09-29 00:46:29 +02:00
|
|
|
bound_generic_params_stack: Vec<ast::GenericParam>,
|
|
|
|
type_params: Vec<TypeParameter>,
|
2015-03-24 14:43:26 -07:00
|
|
|
}
|
|
|
|
|
2016-12-06 11:26:52 +01:00
|
|
|
impl<'a, 'b> visit::Visitor<'a> for Visitor<'a, 'b> {
|
|
|
|
fn visit_ty(&mut self, ty: &'a ast::Ty) {
|
2019-09-26 17:25:31 +01:00
|
|
|
if let ast::TyKind::Path(_, ref path) = ty.kind {
|
2016-12-05 03:51:11 +00:00
|
|
|
if let Some(segment) = path.segments.first() {
|
2018-03-18 03:53:41 +03:00
|
|
|
if self.ty_param_names.contains(&segment.ident.name) {
|
2021-09-29 00:46:29 +02:00
|
|
|
self.type_params.push(TypeParameter {
|
|
|
|
bound_generic_params: self.bound_generic_params_stack.clone(),
|
|
|
|
ty: P(ty.clone()),
|
|
|
|
});
|
2015-03-24 14:43:26 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
visit::walk_ty(self, ty)
|
|
|
|
}
|
2016-06-24 03:23:44 +00:00
|
|
|
|
2021-09-29 00:46:29 +02:00
|
|
|
// Place bound generic params on a stack, to extract them when a type is encountered.
|
|
|
|
fn visit_poly_trait_ref(
|
|
|
|
&mut self,
|
|
|
|
trait_ref: &'a ast::PolyTraitRef,
|
|
|
|
modifier: &'a ast::TraitBoundModifier,
|
|
|
|
) {
|
2021-09-29 03:18:56 +02:00
|
|
|
let stack_len = self.bound_generic_params_stack.len();
|
2021-09-29 00:46:29 +02:00
|
|
|
self.bound_generic_params_stack
|
|
|
|
.extend(trait_ref.bound_generic_params.clone().into_iter());
|
|
|
|
|
|
|
|
visit::walk_poly_trait_ref(self, trait_ref, modifier);
|
|
|
|
|
|
|
|
self.bound_generic_params_stack.truncate(stack_len);
|
|
|
|
}
|
|
|
|
|
2020-11-03 20:34:57 +03:00
|
|
|
fn visit_mac_call(&mut self, mac: &ast::MacCall) {
|
2019-12-01 15:55:32 +03: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 14:43:26 -07:00
|
|
|
}
|
|
|
|
|
2021-09-29 00:46:29 +02:00
|
|
|
let mut visitor = Visitor {
|
|
|
|
cx,
|
|
|
|
ty_param_names,
|
|
|
|
bound_generic_params_stack: Vec::new(),
|
|
|
|
type_params: Vec::new(),
|
|
|
|
};
|
2015-03-24 14:43:26 -07:00
|
|
|
visit::Visitor::visit_ty(&mut visitor, ty);
|
|
|
|
|
2021-09-29 00:46:29 +02:00
|
|
|
visitor.type_params
|
2015-03-24 14:43:26 -07:00
|
|
|
}
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2013-12-09 23:16:18 -08:00
|
|
|
impl<'a> TraitDef<'a> {
|
2017-10-02 15:15:23 +02:00
|
|
|
pub fn expand(
|
|
|
|
self,
|
2019-02-04 21:49:54 +09:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
2015-03-26 18:07:49 -07:00
|
|
|
mitem: &ast::MetaItem,
|
2015-05-12 14:15:02 +12:00
|
|
|
item: &'a Annotatable,
|
2018-07-12 11:58:16 +02:00
|
|
|
push: &mut dyn FnMut(Annotatable),
|
|
|
|
) {
|
2016-08-26 19:23:42 +03:00
|
|
|
self.expand_ext(cx, mitem, item, push, false);
|
|
|
|
}
|
|
|
|
|
2017-10-02 15:15:23 +02:00
|
|
|
pub fn expand_ext(
|
|
|
|
self,
|
2019-02-04 21:49:54 +09:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
2016-08-26 19:23:42 +03:00
|
|
|
mitem: &ast::MetaItem,
|
|
|
|
item: &'a Annotatable,
|
2018-07-12 11:58:16 +02:00
|
|
|
push: &mut dyn FnMut(Annotatable),
|
2016-08-26 19:23:42 +03:00
|
|
|
from_scratch: bool,
|
|
|
|
) {
|
2015-05-12 14:15:02 +12:00
|
|
|
match *item {
|
|
|
|
Annotatable::Item(ref item) => {
|
2017-10-02 15:15:23 +02:00
|
|
|
let is_packed = item.attrs.iter().any(|attr| {
|
2020-07-30 11:27:50 +10:00
|
|
|
for r in attr::find_repr_attrs(&cx.sess, attr) {
|
2018-02-04 22:10:28 +11:00
|
|
|
if let attr::ReprPacked(_) = r {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
false
|
2017-10-02 15:15:23 +02:00
|
|
|
});
|
2019-09-26 17:51:36 +01:00
|
|
|
let has_no_type_params = match item.kind {
|
2017-11-19 17:04:24 +02:00
|
|
|
ast::ItemKind::Struct(_, ref generics)
|
|
|
|
| ast::ItemKind::Enum(_, ref generics)
|
2020-12-24 02:55:21 +01:00
|
|
|
| ast::ItemKind::Union(_, ref generics) => !generics
|
|
|
|
.params
|
|
|
|
.iter()
|
|
|
|
.any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })),
|
2020-11-19 01:55:59 +03:00
|
|
|
_ => unreachable!(),
|
2017-11-19 17:04:24 +02:00
|
|
|
};
|
2021-06-25 20:43:04 +02:00
|
|
|
let container_id = cx.current_expansion.id.expn_data().parent.expect_local();
|
2019-10-30 11:13:00 +01:00
|
|
|
let always_copy = has_no_type_params && cx.resolver.has_derive_copy(container_id);
|
2017-11-19 17:04:24 +02:00
|
|
|
|
2019-09-26 17:51:36 +01:00
|
|
|
let newitem = match item.kind {
|
2016-02-09 11:36:51 +01:00
|
|
|
ast::ItemKind::Struct(ref struct_def, ref generics) => self.expand_struct_def(
|
2017-10-02 15:15:23 +02:00
|
|
|
cx,
|
|
|
|
&struct_def,
|
|
|
|
item.ident,
|
|
|
|
generics,
|
|
|
|
from_scratch,
|
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 10:20:54 +10:00
|
|
|
is_packed,
|
2022-07-06 16:13:51 +10:00
|
|
|
always_copy,
|
2019-12-22 17:42:04 -05:00
|
|
|
),
|
2016-02-09 11:36:51 +01:00
|
|
|
ast::ItemKind::Enum(ref enum_def, ref generics) => {
|
2022-07-06 16:13:51 +10:00
|
|
|
// We ignore `is_packed`/`always_copy` here, because
|
2017-10-02 15:15:23 +02:00
|
|
|
// `repr(packed)` enums cause an error later on.
|
|
|
|
//
|
|
|
|
// This can only cause further compilation errors
|
|
|
|
// downstream in blatantly illegal code, so it
|
|
|
|
// is fine.
|
2020-04-05 20:36:39 +02:00
|
|
|
self.expand_enum_def(cx, enum_def, item.ident, generics, from_scratch)
|
2015-04-28 17:34:39 +12:00
|
|
|
}
|
2016-08-24 21:10:19 +03:00
|
|
|
ast::ItemKind::Union(ref struct_def, ref generics) => {
|
|
|
|
if self.supports_unions {
|
2016-08-26 19:23:42 +03:00
|
|
|
self.expand_struct_def(
|
|
|
|
cx,
|
|
|
|
&struct_def,
|
|
|
|
item.ident,
|
2017-10-02 15:15:23 +02:00
|
|
|
generics,
|
|
|
|
from_scratch,
|
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 10:20:54 +10:00
|
|
|
is_packed,
|
2022-07-06 16:13:51 +10:00
|
|
|
always_copy,
|
2017-10-02 15:15:23 +02:00
|
|
|
)
|
2016-08-24 21:10:19 +03:00
|
|
|
} else {
|
|
|
|
cx.span_err(mitem.span, "this trait cannot be derived for unions");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2017-11-19 17:04:24 +02:00
|
|
|
_ => unreachable!(),
|
2015-04-28 17:34:39 +12: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 23:02:06 +05:30
|
|
|
attrs.extend(
|
|
|
|
item.attrs
|
|
|
|
.iter()
|
2019-03-17 14:17:47 +03:00
|
|
|
.filter(|a| {
|
2019-05-08 14:33:06 +10:00
|
|
|
[
|
|
|
|
sym::allow,
|
|
|
|
sym::warn,
|
|
|
|
sym::deny,
|
|
|
|
sym::forbid,
|
|
|
|
sym::stable,
|
|
|
|
sym::unstable,
|
|
|
|
]
|
|
|
|
.contains(&a.name_or_empty())
|
2019-03-17 14:17:47 +03:00
|
|
|
})
|
2016-07-19 23:02:06 +05:30
|
|
|
.cloned(),
|
|
|
|
);
|
2020-03-06 19:28:44 +01:00
|
|
|
push(Annotatable::Item(P(ast::Item { attrs, ..(*newitem).clone() })))
|
2014-02-12 23:53:52 -08:00
|
|
|
}
|
2020-11-19 01:55:59 +03:00
|
|
|
_ => unreachable!(),
|
2015-04-28 17:34:39 +12:00
|
|
|
}
|
2013-06-07 17:46:44 +10:00
|
|
|
}
|
|
|
|
|
2015-03-24 14:43:26 -07:00
|
|
|
/// Given that we are deriving a trait `DerivedTrait` for a type like:
|
2014-09-16 13:27:34 +02:00
|
|
|
///
|
2017-06-20 15:15:16 +08:00
|
|
|
/// ```ignore (only-for-syntax-highlight)
|
2015-03-24 14:43:26 -07: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 13:27:34 +02:00
|
|
|
/// ```
|
|
|
|
///
|
2015-03-24 14:43:26 -07:00
|
|
|
/// create an impl like:
|
|
|
|
///
|
2017-06-20 15:15:16 +08:00
|
|
|
/// ```ignore (only-for-syntax-highlight)
|
2019-02-08 14:53:55 +01:00
|
|
|
/// impl<'a, ..., 'z, A, B: DeclaredTrait, C, ... Z> where
|
2015-03-24 14:43:26 -07: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 11:57:44 +11:00
|
|
|
fn create_derived_impl(
|
|
|
|
&self,
|
2019-02-04 21:49:54 +09:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
2014-02-14 08:09:51 -08:00
|
|
|
type_ident: Ident,
|
|
|
|
generics: &Generics,
|
2015-03-24 14:43:26 -07:00
|
|
|
field_tys: Vec<P<ast::Ty>>,
|
2019-12-12 16:41:18 +11:00
|
|
|
methods: Vec<P<ast::AssocItem>>,
|
2016-07-19 23:02:06 +05:30
|
|
|
) -> P<ast::Item> {
|
2013-12-07 11:57:44 +11:00
|
|
|
let trait_path = self.path.to_path(cx, self.span, type_ident, generics);
|
2013-05-07 01:23:51 +10:00
|
|
|
|
2019-12-08 00:08:09 +01:00
|
|
|
// Transform associated types from `deriving::ty::Ty` into `ast::AssocItem`
|
2019-12-12 16:41:18 +11:00
|
|
|
let associated_types = self.associated_types.iter().map(|&(ident, ref type_def)| {
|
|
|
|
P(ast::AssocItem {
|
2015-01-25 00:29:24 -05:00
|
|
|
id: ast::DUMMY_NODE_ID,
|
|
|
|
span: self.span,
|
2017-08-06 22:54:09 -07:00
|
|
|
ident,
|
2020-08-21 19:11:00 -04:00
|
|
|
vis: ast::Visibility {
|
|
|
|
span: self.span.shrink_to_lo(),
|
|
|
|
kind: ast::VisibilityKind::Inherited,
|
|
|
|
tokens: None,
|
|
|
|
},
|
2015-01-25 00:29:24 -05:00
|
|
|
attrs: Vec::new(),
|
2021-11-07 16:43:49 +08:00
|
|
|
kind: ast::AssocItemKind::TyAlias(Box::new(ast::TyAlias {
|
|
|
|
defaultness: ast::Defaultness::Final,
|
|
|
|
generics: Generics::default(),
|
2021-10-19 18:45:48 -04:00
|
|
|
where_clauses: (
|
|
|
|
ast::TyAliasWhereClause::default(),
|
|
|
|
ast::TyAliasWhereClause::default(),
|
|
|
|
),
|
|
|
|
where_predicates_split: 0,
|
2021-11-07 16:43:49 +08:00
|
|
|
bounds: Vec::new(),
|
|
|
|
ty: Some(type_def.to_ty(cx, self.span, type_ident, generics)),
|
|
|
|
})),
|
2017-07-12 09:50:05 -07:00
|
|
|
tokens: None,
|
2019-12-12 16:41:18 +11:00
|
|
|
})
|
|
|
|
});
|
2015-01-25 00:29:24 -05:00
|
|
|
|
2021-11-03 04:19:06 +00:00
|
|
|
let Generics { mut params, mut where_clause, .. } =
|
2016-07-19 23:02:06 +05:30
|
|
|
self.generics.to_generics(cx, self.span, type_ident, generics);
|
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 23:16:56 +11:00
|
|
|
|
2017-10-16 21:07:26 +02:00
|
|
|
// Create the generic parameters
|
2021-04-16 16:29:11 +02:00
|
|
|
params.extend(generics.params.iter().map(|param| match ¶m.kind {
|
2018-05-27 20:07:09 +01:00
|
|
|
GenericParamKind::Lifetime { .. } => param.clone(),
|
2018-05-28 13:33:28 +01:00
|
|
|
GenericParamKind::Type { .. } => {
|
2018-05-27 01:43:03 +01:00
|
|
|
// I don't think this can be moved out of the loop, since
|
2018-06-14 12:08:58 +01:00
|
|
|
// a GenericBound requires an ast id
|
2018-08-09 15:32:23 -04:00
|
|
|
let bounds: Vec<_> =
|
2018-05-27 01:43:03 +01:00
|
|
|
// extra restrictions on the generics parameters to the
|
|
|
|
// type being derived upon
|
|
|
|
self.additional_bounds.iter().map(|p| {
|
2018-06-14 15:00:21 +01:00
|
|
|
cx.trait_bound(p.to_path(cx, self.span, type_ident, generics))
|
2018-07-26 17:11:10 +02:00
|
|
|
}).chain(
|
|
|
|
// require the current trait
|
|
|
|
iter::once(cx.trait_bound(trait_path.clone()))
|
|
|
|
).chain(
|
|
|
|
// also add in any bounds from the declaration
|
|
|
|
param.bounds.iter().cloned()
|
|
|
|
).collect();
|
2018-05-27 01:43:03 +01:00
|
|
|
|
2021-11-20 18:46:36 +00:00
|
|
|
cx.typaram(param.ident.span.with_ctxt(ctxt), param.ident, vec![], bounds, None)
|
2017-10-16 21:07:26 +02:00
|
|
|
}
|
2021-04-16 16:29:11 +02:00
|
|
|
GenericParamKind::Const { ty, kw_span, .. } => {
|
|
|
|
let const_nodefault_kind = GenericParamKind::Const {
|
|
|
|
ty: ty.clone(),
|
2021-11-20 18:46:36 +00:00
|
|
|
kw_span: kw_span.with_ctxt(ctxt),
|
2021-04-16 16:29:11 +02:00
|
|
|
|
|
|
|
// 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
|
|
|
|
}
|
2014-03-19 23:16:56 +11:00
|
|
|
}));
|
2014-12-14 00:35:35 -05: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);
|
2014-12-14 00:35:35 -05:00
|
|
|
ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
|
|
|
|
id: ast::DUMMY_NODE_ID,
|
2021-11-20 18:46:36 +00:00
|
|
|
span,
|
2021-11-17 23:47:47 +00:00
|
|
|
..we.clone()
|
2014-12-14 00:35:35 -05:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}));
|
|
|
|
|
2017-10-16 21:07:26 +02: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 12:00:45 -05:00
|
|
|
.filter(|param| matches!(param.kind, ast::GenericParamKind::Type { .. }))
|
2017-10-16 21:07:26 +02:00
|
|
|
.peekable();
|
|
|
|
|
|
|
|
if ty_params.peek().is_some() {
|
2020-04-19 13:00:18 +02:00
|
|
|
let ty_param_names: Vec<Symbol> =
|
2017-10-16 21:07:26 +02:00
|
|
|
ty_params.map(|ty_param| ty_param.ident.name).collect();
|
|
|
|
|
|
|
|
for field_ty in field_tys {
|
2021-09-29 00:46:29 +02:00
|
|
|
let field_ty_params = find_type_parameters(&field_ty, &ty_param_names, cx);
|
2017-10-16 21:07:26 +02:00
|
|
|
|
2021-09-29 00:46:29 +02:00
|
|
|
for field_ty_param in field_ty_params {
|
2017-10-16 21:07:26 +02:00
|
|
|
// if we have already handled this type, skip it
|
2021-09-29 00:46:29 +02:00
|
|
|
if let ast::TyKind::Path(_, ref p) = field_ty_param.ty.kind {
|
2017-10-16 21:07:26 +02:00
|
|
|
if p.segments.len() == 1
|
2018-03-21 01:58:25 +03:00
|
|
|
&& ty_param_names.contains(&p.segments[0].ident.name)
|
|
|
|
{
|
2017-10-16 21:07:26 +02:00
|
|
|
continue;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
let mut bounds: Vec<_> = self
|
|
|
|
.additional_bounds
|
|
|
|
.iter()
|
2018-06-14 15:00:21 +01:00
|
|
|
.map(|p| cx.trait_bound(p.to_path(cx, self.span, type_ident, generics)))
|
2017-10-16 21:07:26 +02:00
|
|
|
.collect();
|
|
|
|
|
|
|
|
// require the current trait
|
2018-06-14 15:00:21 +01:00
|
|
|
bounds.push(cx.trait_bound(trait_path.clone()));
|
2017-10-16 21:07:26 +02:00
|
|
|
|
|
|
|
let predicate = ast::WhereBoundPredicate {
|
|
|
|
span: self.span,
|
2021-09-29 00:46:29 +02:00
|
|
|
bound_generic_params: field_ty_param.bound_generic_params,
|
|
|
|
bounded_ty: field_ty_param.ty,
|
2017-10-16 21:07:26 +02:00
|
|
|
bounds,
|
2015-07-20 00:09:12 +02:00
|
|
|
};
|
2015-03-24 14:43:26 -07:00
|
|
|
|
2017-10-16 21:07:26 +02:00
|
|
|
let predicate = ast::WherePredicate::BoundPredicate(predicate);
|
|
|
|
where_clause.predicates.push(predicate);
|
|
|
|
}
|
2015-03-24 14:43:26 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-19 23:16:56 +11:00
|
|
|
let trait_generics = Generics { params, where_clause, span };
|
2013-06-07 17:30:38 +10:00
|
|
|
|
|
|
|
// Create the reference to the trait.
|
|
|
|
let trait_ref = cx.trait_ref(trait_path);
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2018-05-27 21:54:10 +01:00
|
|
|
let self_params: Vec<_> = generics
|
|
|
|
.params
|
|
|
|
.iter()
|
|
|
|
.map(|param| match param.kind {
|
2018-05-30 16:49:39 +01: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 21:54:10 +01: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 21:54:10 +01:00
|
|
|
}
|
2019-02-05 16:50:00 +01: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 16:50:00 +01:00
|
|
|
}
|
2018-05-27 21:54:10 +01:00
|
|
|
})
|
|
|
|
.collect();
|
2018-02-08 08:58:13 +00:00
|
|
|
|
2013-06-07 17:30:38 +10:00
|
|
|
// Create the type of `self`.
|
2019-09-21 15:01:10 -04:00
|
|
|
let path = cx.path_all(self.span, false, vec![type_ident], self_params);
|
2018-05-27 21:54:10 +01:00
|
|
|
let self_type = cx.ty_path(path);
|
2016-07-19 23:02:06 +05:30
|
|
|
|
2019-07-30 14:12:52 -04:00
|
|
|
let attr = cx.attribute(cx.meta_word(self.span, sym::automatically_derived));
|
2014-02-14 07:07:09 +02:00
|
|
|
let opt_trait_ref = Some(trait_ref);
|
2016-11-15 04:34:52 +00:00
|
|
|
let unused_qual = {
|
2020-02-29 20:37:32 +03:00
|
|
|
let word = rustc_ast::attr::mk_nested_word_item(Ident::new(
|
2020-07-08 11:04:10 +10:00
|
|
|
sym::unused_qualifications,
|
2019-09-21 15:26:15 -04:00
|
|
|
self.span,
|
|
|
|
));
|
2020-02-29 20:37:32 +03:00
|
|
|
let list = rustc_ast::attr::mk_list_item(Ident::new(sym::allow, self.span), vec![word]);
|
2019-09-21 15:26:15 -04:00
|
|
|
cx.attribute(list)
|
2016-11-15 04:34:52 +00:00
|
|
|
};
|
|
|
|
|
2015-07-23 13:26:49 -04:00
|
|
|
let mut a = vec![attr, unused_qual];
|
2015-02-13 07:33:44 +00:00
|
|
|
a.extend(self.attributes.iter().cloned());
|
2015-08-29 14:50:05 -04:00
|
|
|
|
2016-07-19 23:02:06 +05:30
|
|
|
cx.item(
|
|
|
|
self.span,
|
2021-10-17 23:20:30 +03:00
|
|
|
Ident::empty(),
|
2016-07-19 23:02:06 +05:30
|
|
|
a,
|
2021-11-07 16:43:49 +08:00
|
|
|
ast::ItemKind::Impl(Box::new(ast::Impl {
|
2022-06-28 11:44:37 +10:00
|
|
|
unsafety: ast::Unsafe::No,
|
2020-01-13 20:30:20 -08:00
|
|
|
polarity: ast::ImplPolarity::Positive,
|
|
|
|
defaultness: ast::Defaultness::Final,
|
2020-01-30 02:42:33 +01:00
|
|
|
constness: ast::Const::No,
|
2020-01-13 20:30:20 -08:00
|
|
|
generics: trait_generics,
|
|
|
|
of_trait: opt_trait_ref,
|
|
|
|
self_ty: self_type,
|
|
|
|
items: methods.into_iter().chain(associated_types).collect(),
|
2021-08-05 03:53:21 +02:00
|
|
|
})),
|
2016-07-19 23:02:06 +05:30
|
|
|
)
|
2013-03-28 21:50:10 +11:00
|
|
|
}
|
|
|
|
|
2014-02-21 21:33:23 -08:00
|
|
|
fn expand_struct_def(
|
|
|
|
&self,
|
2019-02-04 21:49:54 +09:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
2015-10-08 03:20:57 +03:00
|
|
|
struct_def: &'a VariantData,
|
2014-02-21 21:33:23 -08:00
|
|
|
type_ident: Ident,
|
2016-08-26 19:23:42 +03:00
|
|
|
generics: &Generics,
|
2017-10-02 15:15:23 +02:00
|
|
|
from_scratch: 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 10:20:54 +10:00
|
|
|
is_packed: bool,
|
2022-07-06 16:13:51 +10:00
|
|
|
always_copy: bool,
|
2016-07-19 23:02:06 +05:30
|
|
|
) -> P<ast::Item> {
|
|
|
|
let field_tys: Vec<P<ast::Ty>> =
|
2016-04-06 11:19:10 +03:00
|
|
|
struct_def.fields().iter().map(|field| field.ty.clone()).collect();
|
2019-12-22 17:42:04 -05:00
|
|
|
|
2016-07-19 23:02:06 +05:30
|
|
|
let methods = self
|
|
|
|
.methods
|
|
|
|
.iter()
|
|
|
|
.map(|method_def| {
|
2022-07-05 08:25:47 +10:00
|
|
|
let (explicit_self, selflike_args, nonselflike_args, nonself_arg_tys) =
|
|
|
|
method_def.extract_arg_details(cx, self, type_ident, generics);
|
2016-07-19 23:02:06 +05:30
|
|
|
|
2016-08-26 19:23:42 +03:00
|
|
|
let body = if from_scratch || method_def.is_static() {
|
2016-07-19 23:02:06 +05:30
|
|
|
method_def.expand_static_struct_method_body(
|
|
|
|
cx,
|
|
|
|
self,
|
|
|
|
struct_def,
|
|
|
|
type_ident,
|
2022-07-05 08:25:47 +10:00
|
|
|
&nonselflike_args,
|
2016-07-19 23:02:06 +05:30
|
|
|
)
|
|
|
|
} else {
|
|
|
|
method_def.expand_struct_method_body(
|
|
|
|
cx,
|
|
|
|
self,
|
|
|
|
struct_def,
|
|
|
|
type_ident,
|
2022-07-05 08:25:47 +10:00
|
|
|
&selflike_args,
|
|
|
|
&nonselflike_args,
|
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 10:20:54 +10:00
|
|
|
is_packed,
|
2022-07-06 16:13:51 +10:00
|
|
|
always_copy,
|
2017-10-02 15:15:23 +02:00
|
|
|
)
|
2016-07-19 23:02:06 +05:30
|
|
|
};
|
|
|
|
|
2022-07-05 08:25:47 +10:00
|
|
|
method_def.create_method(
|
|
|
|
cx,
|
|
|
|
self,
|
|
|
|
type_ident,
|
|
|
|
generics,
|
|
|
|
explicit_self,
|
|
|
|
nonself_arg_tys,
|
|
|
|
body,
|
|
|
|
)
|
2016-07-19 23:02:06 +05:30
|
|
|
})
|
|
|
|
.collect();
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2015-03-24 14:43:26 -07:00
|
|
|
self.create_derived_impl(cx, type_ident, generics, field_tys, methods)
|
2013-03-28 21:50:10 +11:00
|
|
|
}
|
|
|
|
|
2014-02-21 21:33:23 -08:00
|
|
|
fn expand_enum_def(
|
|
|
|
&self,
|
2019-02-04 21:49:54 +09:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
2015-05-01 06:40:06 +05:30
|
|
|
enum_def: &'a EnumDef,
|
2013-09-02 02:50:59 +02:00
|
|
|
type_ident: Ident,
|
2016-08-26 19:23:42 +03:00
|
|
|
generics: &Generics,
|
|
|
|
from_scratch: bool,
|
2016-07-19 23:02:06 +05:30
|
|
|
) -> P<ast::Item> {
|
2015-03-24 14:43:26 -07:00
|
|
|
let mut field_tys = Vec::new();
|
|
|
|
|
2015-06-10 17:22:20 +01:00
|
|
|
for variant in &enum_def.variants {
|
2016-04-06 11:19:10 +03:00
|
|
|
field_tys.extend(variant.data.fields().iter().map(|field| field.ty.clone()));
|
2015-03-24 14:43:26 -07:00
|
|
|
}
|
|
|
|
|
2016-07-19 23:02:06 +05:30
|
|
|
let methods = self
|
|
|
|
.methods
|
|
|
|
.iter()
|
|
|
|
.map(|method_def| {
|
2022-07-05 08:25:47 +10:00
|
|
|
let (explicit_self, selflike_args, nonselflike_args, nonself_arg_tys) =
|
|
|
|
method_def.extract_arg_details(cx, self, type_ident, generics);
|
2016-07-19 23:02:06 +05:30
|
|
|
|
2016-08-26 19:23:42 +03:00
|
|
|
let body = if from_scratch || method_def.is_static() {
|
2016-07-19 23:02:06 +05:30
|
|
|
method_def.expand_static_enum_method_body(
|
|
|
|
cx,
|
|
|
|
self,
|
|
|
|
enum_def,
|
|
|
|
type_ident,
|
2022-07-05 08:25:47 +10:00
|
|
|
&nonselflike_args,
|
2016-07-19 23:02:06 +05:30
|
|
|
)
|
|
|
|
} else {
|
|
|
|
method_def.expand_enum_method_body(
|
|
|
|
cx,
|
|
|
|
self,
|
|
|
|
enum_def,
|
|
|
|
type_ident,
|
2022-07-05 08:25:47 +10:00
|
|
|
selflike_args,
|
|
|
|
&nonselflike_args,
|
2016-07-19 23:02:06 +05:30
|
|
|
)
|
|
|
|
};
|
|
|
|
|
2022-07-05 08:25:47 +10:00
|
|
|
method_def.create_method(
|
|
|
|
cx,
|
|
|
|
self,
|
|
|
|
type_ident,
|
|
|
|
generics,
|
|
|
|
explicit_self,
|
|
|
|
nonself_arg_tys,
|
|
|
|
body,
|
|
|
|
)
|
2016-07-19 23:02:06 +05:30
|
|
|
})
|
|
|
|
.collect();
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2015-03-24 14:43:26 -07:00
|
|
|
self.create_derived_impl(cx, type_ident, generics, field_tys, methods)
|
2013-03-28 21:50:10 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-09 23:16:18 -08:00
|
|
|
impl<'a> MethodDef<'a> {
|
2013-03-28 21:50:10 +11:00
|
|
|
fn call_substructure_method(
|
|
|
|
&self,
|
2019-02-04 21:49:54 +09:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
|
|
|
trait_: &TraitDef<'_>,
|
2013-09-02 02:50:59 +02:00
|
|
|
type_ident: Ident,
|
2022-07-05 08:25:47 +10:00
|
|
|
nonselflike_args: &[P<Expr>],
|
2019-02-04 21:49:54 +09:00
|
|
|
fields: &SubstructureFields<'_>,
|
2022-06-28 13:10:36 +10:00
|
|
|
) -> BlockOrExpr {
|
2021-11-20 18:46:36 +00:00
|
|
|
let span = trait_.span;
|
2022-07-05 08:25:47 +10:00
|
|
|
let substructure = Substructure { type_ident, nonselflike_args, fields };
|
2014-04-21 23:25:18 -07:00
|
|
|
let mut f = self.combine_substructure.borrow_mut();
|
2019-02-04 21:49:54 +09:00
|
|
|
let f: &mut CombineSubstructureFunc<'_> = &mut *f;
|
2021-11-20 18:46:36 +00:00
|
|
|
f(cx, span, &substructure)
|
2013-03-28 21:50:10 +11:00
|
|
|
}
|
|
|
|
|
2014-02-08 19:39:53 -05:00
|
|
|
fn get_ret_ty(
|
|
|
|
&self,
|
2019-02-04 21:49:54 +09:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
|
|
|
trait_: &TraitDef<'_>,
|
2014-02-08 19:39:53 -05:00
|
|
|
generics: &Generics,
|
|
|
|
type_ident: Ident,
|
|
|
|
) -> P<ast::Ty> {
|
|
|
|
self.ret_ty.to_ty(cx, trait_.span, type_ident, generics)
|
2013-05-07 01:23:51 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
fn is_static(&self) -> bool {
|
2022-06-30 09:15:07 +10:00
|
|
|
!self.explicit_self
|
2013-05-07 01:23:51 +10:00
|
|
|
}
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2022-07-05 08:25:47 +10: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 23:02:06 +05:30
|
|
|
&self,
|
2019-02-04 21:49:54 +09:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
|
|
|
trait_: &TraitDef<'_>,
|
2016-07-19 23:02:06 +05:30
|
|
|
type_ident: Ident,
|
|
|
|
generics: &Generics,
|
|
|
|
) -> (Option<ast::ExplicitSelf>, Vec<P<Expr>>, Vec<P<Expr>>, Vec<(Ident, P<ast::Ty>)>) {
|
2022-07-05 08:25:47 +10: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-07 01:23:51 +10:00
|
|
|
|
2022-07-05 08:25:47 +10:00
|
|
|
let explicit_self = if self.explicit_self {
|
2022-06-30 09:15:07 +10:00
|
|
|
let (self_expr, explicit_self) = ty::get_explicit_self(cx, span);
|
2022-07-05 08:25:47 +10:00
|
|
|
selflike_args.push(self_expr);
|
2022-06-30 09:15:07 +10:00
|
|
|
Some(explicit_self)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
2013-05-07 01:23:51 +10:00
|
|
|
|
2022-07-05 08:25:47 +10: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-05 08:25:47 +10:00
|
|
|
nonself_arg_tys.push((ident, ast_ty));
|
2013-05-07 01:23:51 +10:00
|
|
|
|
2021-11-20 18:46:36 +00:00
|
|
|
let arg_expr = cx.expr_ident(span, ident);
|
2013-05-07 01:23:51 +10:00
|
|
|
|
2022-07-08 07:57:34 +10:00
|
|
|
match ty {
|
|
|
|
// Selflike (`&Self`) arguments only occur in non-static methods.
|
2022-07-06 16:13:51 +10:00
|
|
|
Ref(box Self_, _) if !self.is_static() => selflike_args.push(arg_expr),
|
2022-07-05 08:25:47 +10:00
|
|
|
Self_ => cx.span_bug(span, "`Self` in non-return position"),
|
|
|
|
_ => nonselflike_args.push(arg_expr),
|
2013-03-28 21:50:10 +11:00
|
|
|
}
|
|
|
|
}
|
2013-05-07 01:23:51 +10:00
|
|
|
|
2022-07-05 08:25:47 +10:00
|
|
|
(explicit_self, selflike_args, nonselflike_args, nonself_arg_tys)
|
2013-03-28 21:50:10 +11:00
|
|
|
}
|
|
|
|
|
2014-02-08 19:39:53 -05:00
|
|
|
fn create_method(
|
|
|
|
&self,
|
2019-02-04 21:49:54 +09:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
|
|
|
trait_: &TraitDef<'_>,
|
2013-09-02 02:50:59 +02:00
|
|
|
type_ident: Ident,
|
2013-05-07 01:23:51 +10:00
|
|
|
generics: &Generics,
|
2016-03-06 15:54:44 +03:00
|
|
|
explicit_self: Option<ast::ExplicitSelf>,
|
2022-07-05 08:25:47 +10:00
|
|
|
nonself_arg_tys: Vec<(Ident, P<ast::Ty>)>,
|
2022-06-28 13:10:36 +10:00
|
|
|
body: BlockOrExpr,
|
2019-12-12 16:41:18 +11: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-07 01:23:51 +10:00
|
|
|
|
2014-02-09 07:37:33 -05:00
|
|
|
let args = {
|
2022-07-05 08:25:47 +10: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 16:38:34 +01:00
|
|
|
ast::Param::from_self(ast::AttrVec::default(), explicit_self, ident)
|
2016-03-06 15:54:44 +03:00
|
|
|
});
|
2022-07-05 08:25:47 +10: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 07:37:33 -05:00
|
|
|
};
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2014-02-08 19:39:53 -05:00
|
|
|
let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident);
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2021-11-20 18:46:36 +00:00
|
|
|
let method_ident = Ident::new(self.name, span);
|
2020-02-15 12:10:59 +09:00
|
|
|
let fn_decl = cx.fn_decl(args, ast::FnRetTy::Ty(ret_type));
|
2022-06-28 13:10:36 +10:00
|
|
|
let body_block = body.into_block(cx, span);
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2021-11-20 18:46:36 +00:00
|
|
|
let trait_lo_sp = span.shrink_to_lo();
|
2019-10-27 23:14:35 +01:00
|
|
|
|
2022-06-28 11:44:37 +10:00
|
|
|
let sig = ast::FnSig { header: ast::FnHeader::default(), decl: fn_decl, span };
|
2021-11-07 16:43:49 +08:00
|
|
|
let defaultness = ast::Defaultness::Final;
|
2019-10-27 23:14:35 +01:00
|
|
|
|
2013-03-28 21:50:10 +11:00
|
|
|
// Create the method.
|
2019-12-12 16:41:18 +11:00
|
|
|
P(ast::AssocItem {
|
2013-09-06 22:11:55 -04:00
|
|
|
id: ast::DUMMY_NODE_ID,
|
2015-03-10 12:28:44 +02:00
|
|
|
attrs: self.attributes.clone(),
|
2021-11-20 18:46:36 +00:00
|
|
|
span,
|
2020-08-21 19:11:00 -04:00
|
|
|
vis: ast::Visibility {
|
|
|
|
span: trait_lo_sp,
|
|
|
|
kind: ast::VisibilityKind::Inherited,
|
|
|
|
tokens: None,
|
|
|
|
},
|
2015-03-10 12:28:44 +02:00
|
|
|
ident: method_ident,
|
2021-11-07 16:43:49 +08:00
|
|
|
kind: ast::AssocItemKind::Fn(Box::new(ast::Fn {
|
|
|
|
defaultness,
|
2021-08-05 03:53:21 +02:00
|
|
|
sig,
|
2021-11-07 16:43:49 +08:00
|
|
|
generics: fn_generics,
|
|
|
|
body: Some(body_block),
|
|
|
|
})),
|
2017-07-12 09:50:05 -07:00
|
|
|
tokens: None,
|
2019-12-12 16:41:18 +11:00
|
|
|
})
|
2013-03-28 21:50:10 +11: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 10:20:54 +10:00
|
|
|
/// The normal case uses field access.
|
2017-06-20 15:15:16 +08:00
|
|
|
/// ```
|
2014-12-31 17:25:18 +13:00
|
|
|
/// #[derive(PartialEq)]
|
2017-06-20 15:15:16 +08:00
|
|
|
/// # struct Dummy;
|
2022-07-07 11:09:07 +10:00
|
|
|
/// struct A { x: u8, y: u8 }
|
2014-09-16 13:27:34 +02:00
|
|
|
///
|
|
|
|
/// // equivalent to:
|
|
|
|
/// impl PartialEq for A {
|
2018-04-19 20:17:06 +01: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 10:20:54 +10:00
|
|
|
/// self.x == other.x && self.y == other.y
|
2014-09-16 13:27:34 +02:00
|
|
|
/// }
|
|
|
|
/// }
|
2022-04-15 15:04:34 -07: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 10:20:54 +10:00
|
|
|
/// But if the struct is `repr(packed)`, we can't use something like
|
|
|
|
/// `&self.x` on a packed type (as required for e.g. `Debug` and `Hash`)
|
|
|
|
/// because that might cause an unaligned ref. So we use let-destructuring
|
2022-07-07 11:09:07 +10:00
|
|
|
/// instead. If the struct impls `Copy`:
|
2022-04-15 15:04:34 -07:00
|
|
|
/// ```
|
2022-07-07 11:09:07 +10:00
|
|
|
/// # struct A { x: u8, y: u8 }
|
2017-10-02 15:15:23 +02:00
|
|
|
/// impl PartialEq for A {
|
2018-04-19 20:17:06 +01:00
|
|
|
/// fn eq(&self, other: &A) -> bool {
|
2022-07-06 16:13:51 +10:00
|
|
|
/// let Self { x: __self_0_0, y: __self_0_1 } = *self;
|
|
|
|
/// let Self { x: __self_1_0, y: __self_1_1 } = *other;
|
|
|
|
/// __self_0_0 == __self_1_0 && __self_0_1 == __self_1_1
|
2017-10-02 15:15:23 +02:00
|
|
|
/// }
|
|
|
|
/// }
|
2014-09-16 13:27:34 +02:00
|
|
|
/// ```
|
2022-07-07 11:09:07 +10:00
|
|
|
/// If it doesn't impl `Copy`:
|
|
|
|
/// ```
|
|
|
|
/// # struct A { x: u8, y: u8 }
|
|
|
|
/// impl PartialEq for A {
|
|
|
|
/// fn eq(&self, other: &A) -> bool {
|
|
|
|
/// let Self { x: ref __self_0_0, y: ref __self_0_1 } = *self;
|
|
|
|
/// let Self { x: ref __self_1_0, y: ref __self_1_1 } = *other;
|
|
|
|
/// *__self_0_0 == *__self_1_0 && *__self_0_1 == *__self_1_1
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
/// This latter case only works if the fields match the alignment required
|
|
|
|
/// by the `packed(N)` attribute.
|
2015-05-01 06:40:06 +05:30
|
|
|
fn expand_struct_method_body<'b>(
|
|
|
|
&self,
|
2019-02-04 21:49:54 +09:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
2016-07-19 23:02:06 +05:30
|
|
|
trait_: &TraitDef<'b>,
|
|
|
|
struct_def: &'b VariantData,
|
|
|
|
type_ident: Ident,
|
2022-07-05 08:25:47 +10:00
|
|
|
selflike_args: &[P<Expr>],
|
|
|
|
nonselflike_args: &[P<Expr>],
|
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 10:20:54 +10:00
|
|
|
is_packed: bool,
|
2022-07-06 16:13:51 +10:00
|
|
|
always_copy: bool,
|
2022-06-28 13:10:36 +10:00
|
|
|
) -> BlockOrExpr {
|
2021-11-20 18:46:36 +00:00
|
|
|
let span = trait_.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-05 09:04:41 +10:00
|
|
|
assert!(selflike_args.len() == 1 || selflike_args.len() == 2);
|
|
|
|
|
|
|
|
let mk_body = |cx, selflike_fields| {
|
|
|
|
self.call_substructure_method(
|
|
|
|
cx,
|
|
|
|
trait_,
|
|
|
|
type_ident,
|
|
|
|
nonselflike_args,
|
|
|
|
&Struct(struct_def, selflike_fields),
|
|
|
|
)
|
2013-05-07 01:23:51 +10:00
|
|
|
};
|
2013-03-28 21:50:10 +11: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 10:20:54 +10:00
|
|
|
if !is_packed {
|
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-05 09:04:41 +10:00
|
|
|
let selflike_fields =
|
|
|
|
trait_.create_struct_field_access_fields(cx, selflike_args, struct_def);
|
|
|
|
mk_body(cx, selflike_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 10:20:54 +10:00
|
|
|
} else {
|
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-05 09:04:41 +10:00
|
|
|
let prefixes: Vec<_> =
|
|
|
|
(0..selflike_args.len()).map(|i| format!("__self_{}", i)).collect();
|
2022-07-07 11:09:07 +10:00
|
|
|
let addr_of = always_copy;
|
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-05 09:04:41 +10:00
|
|
|
let selflike_fields =
|
2022-07-07 11:09:07 +10:00
|
|
|
trait_.create_struct_pattern_fields(cx, struct_def, &prefixes, addr_of);
|
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-05 09:04:41 +10:00
|
|
|
let mut body = mk_body(cx, selflike_fields);
|
|
|
|
|
|
|
|
let struct_path = cx.path(span, vec![Ident::new(kw::SelfUpper, type_ident.span)]);
|
2022-07-06 16:13:51 +10:00
|
|
|
let use_ref_pat = is_packed && !always_copy;
|
|
|
|
let patterns =
|
|
|
|
trait_.create_struct_patterns(cx, struct_path, struct_def, &prefixes, use_ref_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-05 09:04:41 +10: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 10:20:54 +10:00
|
|
|
// Do the let-destructuring.
|
2022-07-05 08:25:47 +10:00
|
|
|
let mut stmts: Vec<_> = iter::zip(selflike_args, patterns)
|
|
|
|
.map(|(selflike_arg_expr, pat)| {
|
2022-07-06 16:13:51 +10:00
|
|
|
let selflike_arg_expr = cx.expr_deref(span, selflike_arg_expr.clone());
|
|
|
|
cx.stmt_let_pat(span, pat, selflike_arg_expr)
|
2022-07-05 08:25:47 +10: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 10:20:54 +10:00
|
|
|
.collect();
|
2022-06-28 13:10:36 +10:00
|
|
|
stmts.extend(std::mem::take(&mut body.0));
|
|
|
|
BlockOrExpr(stmts, body.1)
|
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 10:20:54 +10:00
|
|
|
}
|
2013-03-28 21:50:10 +11:00
|
|
|
}
|
|
|
|
|
2013-05-07 01:23:51 +10:00
|
|
|
fn expand_static_struct_method_body(
|
|
|
|
&self,
|
2019-02-04 21:49:54 +09:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
|
|
|
trait_: &TraitDef<'_>,
|
2015-10-08 03:20:57 +03:00
|
|
|
struct_def: &VariantData,
|
2013-09-02 02:50:59 +02:00
|
|
|
type_ident: Ident,
|
2022-07-05 08:25:47 +10:00
|
|
|
nonselflike_args: &[P<Expr>],
|
2022-06-28 13:10:36 +10:00
|
|
|
) -> BlockOrExpr {
|
2014-02-08 19:39:53 -05:00
|
|
|
let summary = trait_.summarise_struct(cx, struct_def);
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2014-02-08 19:39:53 -05:00
|
|
|
self.call_substructure_method(
|
|
|
|
cx,
|
|
|
|
trait_,
|
2013-05-07 01:23:51 +10:00
|
|
|
type_ident,
|
2022-07-05 08:25:47 +10:00
|
|
|
nonselflike_args,
|
2013-05-07 01:23:51 +10:00
|
|
|
&StaticStruct(struct_def, summary),
|
|
|
|
)
|
2013-03-28 21:50:10 +11:00
|
|
|
}
|
|
|
|
|
2017-06-20 15:15:16 +08:00
|
|
|
/// ```
|
2014-12-31 17:25:18 +13:00
|
|
|
/// #[derive(PartialEq)]
|
2017-06-20 15:15:16 +08:00
|
|
|
/// # struct Dummy;
|
2014-09-16 13:27:34 +02:00
|
|
|
/// enum A {
|
|
|
|
/// A1,
|
2015-01-17 23:55:21 +00:00
|
|
|
/// A2(i32)
|
2014-09-16 13:27:34 +02:00
|
|
|
/// }
|
2022-06-22 15:26:47 +10:00
|
|
|
/// ```
|
|
|
|
/// is equivalent to:
|
|
|
|
/// ```
|
|
|
|
/// impl ::core::cmp::PartialEq for A {
|
|
|
|
/// #[inline]
|
2022-04-15 15:04:34 -07:00
|
|
|
/// fn eq(&self, other: &A) -> bool {
|
2022-07-06 16:13:51 +10:00
|
|
|
/// let __self_vi = ::core::intrinsics::discriminant_value(self);
|
|
|
|
/// let __arg_1_vi = ::core::intrinsics::discriminant_value(other);
|
|
|
|
/// if __self_vi == __arg_1_vi {
|
|
|
|
/// match (self, other) {
|
|
|
|
/// (A::A2(__self_0), A::A2(__arg_1_0)) =>
|
|
|
|
/// *__self_0 == *__arg_1_0,
|
|
|
|
/// _ => true,
|
2014-09-16 13:27:34 +02:00
|
|
|
/// }
|
2022-07-06 16:13:51 +10:00
|
|
|
/// } else {
|
|
|
|
/// false // catch-all handler
|
2014-09-16 13:27:34 +02:00
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// ```
|
2022-07-05 08:25:47 +10:00
|
|
|
/// Creates a match for a tuple of all `selflike_args`, where either all
|
2014-09-16 13:27:34 +02:00
|
|
|
/// variants match, or it falls into a catch-all for when one variant
|
|
|
|
/// does not match.
|
2022-06-22 15:26:47 +10:00
|
|
|
///
|
2014-09-16 13:27:34 +02:00
|
|
|
/// There are N + 1 cases because is a case for each of the N
|
|
|
|
/// variants where all of the variants match, and one catch-all for
|
|
|
|
/// when one does not match.
|
2022-06-22 15:26:47 +10:00
|
|
|
///
|
2015-06-14 18:24:52 +02:00
|
|
|
/// As an optimization we generate code which checks whether all variants
|
|
|
|
/// match first which makes llvm see that C-like enums can be compiled into
|
|
|
|
/// a simple equality check (for PartialEq).
|
2022-06-22 15:26:47 +10:00
|
|
|
///
|
2014-09-16 13:27:34 +02:00
|
|
|
/// The catch-all handler is provided access the variant index values
|
2022-07-05 08:25:47 +10:00
|
|
|
/// for each of the selflike_args, carried in precomputed variables.
|
2022-06-22 15:26:47 +10:00
|
|
|
fn expand_enum_method_body<'b>(
|
2016-07-19 23:02:06 +05:30
|
|
|
&self,
|
2019-02-04 21:49:54 +09:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
2016-07-19 23:02:06 +05:30
|
|
|
trait_: &TraitDef<'b>,
|
|
|
|
enum_def: &'b EnumDef,
|
|
|
|
type_ident: Ident,
|
2022-07-05 08:25:47 +10:00
|
|
|
mut selflike_args: Vec<P<Expr>>,
|
|
|
|
nonselflike_args: &[P<Expr>],
|
2022-06-28 13:10:36 +10:00
|
|
|
) -> BlockOrExpr {
|
2021-11-20 18:46:36 +00:00
|
|
|
let span = trait_.span;
|
2014-07-06 21:19:12 +02:00
|
|
|
let variants = &enum_def.variants;
|
|
|
|
|
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-05 09:04:41 +10:00
|
|
|
let prefixes = iter::once("__self".to_string())
|
2018-11-05 15:30:04 +01:00
|
|
|
.chain(
|
2022-07-05 08:25:47 +10:00
|
|
|
selflike_args
|
2018-11-05 15:30:04 +01:00
|
|
|
.iter()
|
|
|
|
.enumerate()
|
|
|
|
.skip(1)
|
2022-07-05 08:25:47 +10:00
|
|
|
.map(|(arg_count, _selflike_arg)| format!("__arg_{}", arg_count)),
|
2018-11-05 15:30:04 +01:00
|
|
|
)
|
|
|
|
.collect::<Vec<String>>();
|
2019-12-22 17:42:04 -05:00
|
|
|
|
2014-07-06 21:19:12 +02:00
|
|
|
// The `vi_idents` will be bound, solely in the catch-all, to
|
2022-07-05 08:25:47 +10:00
|
|
|
// a series of let statements mapping each selflike_arg to an int
|
2015-04-10 19:13:34 +02:00
|
|
|
// value corresponding to its discriminant.
|
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-05 09:04:41 +10:00
|
|
|
let vi_idents = prefixes
|
2018-11-05 15:30:04 +01:00
|
|
|
.iter()
|
2016-07-19 23:02:06 +05:30
|
|
|
.map(|name| {
|
2021-12-03 03:06:36 +01:00
|
|
|
let vi_suffix = format!("{}_vi", name);
|
2021-11-20 18:46:36 +00:00
|
|
|
Ident::from_str_and_span(&vi_suffix, span)
|
2016-07-19 23:02:06 +05:30
|
|
|
})
|
2020-04-19 13:00:18 +02:00
|
|
|
.collect::<Vec<Ident>>();
|
2014-07-06 21:19:12 +02:00
|
|
|
|
|
|
|
// Builds, via callback to call_substructure_method, the
|
|
|
|
// delegated expression that handles the catch-all case,
|
|
|
|
// using `__variants_tuple` to drive logic if necessary.
|
2022-06-28 08:56:54 +10:00
|
|
|
let catch_all_substructure = EnumNonMatchingCollapsed(&vi_idents);
|
2014-07-06 21:19:12 +02:00
|
|
|
|
2019-08-13 21:40:21 -03:00
|
|
|
let first_fieldless = variants.iter().find(|v| v.data.fields().is_empty());
|
2016-05-12 17:54:05 +02:00
|
|
|
|
2014-07-06 21:19:12 +02:00
|
|
|
// These arms are of the form:
|
|
|
|
// (Variant1, Variant1, ...) => Body1
|
|
|
|
// (Variant2, Variant2, ...) => Body2
|
|
|
|
// ...
|
2022-07-05 08:25:47 +10:00
|
|
|
// where each tuple has length = selflike_args.len()
|
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-05 09:04:41 +10:00
|
|
|
|
2016-07-19 23:02:06 +05:30
|
|
|
let mut match_arms: Vec<ast::Arm> = variants
|
|
|
|
.iter()
|
|
|
|
.enumerate()
|
2019-08-13 21:40:21 -03:00
|
|
|
.filter(|&(_, v)| !(self.unify_fieldless_variants && v.data.fields().is_empty()))
|
2014-09-13 19:06:01 +03:00
|
|
|
.map(|(index, variant)| {
|
2014-07-06 21:19:12 +02: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-05 09:04:41 +10:00
|
|
|
|
2022-07-07 11:09:07 +10:00
|
|
|
let addr_of = false; // because enums can't be repr(packed)
|
2022-07-06 16:13:51 +10:00
|
|
|
let fields =
|
2022-07-07 11:09:07 +10:00
|
|
|
trait_.create_struct_pattern_fields(cx, &variant.data, &prefixes, addr_of);
|
2022-07-06 16:13:51 +10:00
|
|
|
|
|
|
|
let sp = variant.span.with_ctxt(trait_.span.ctxt());
|
|
|
|
let variant_path = cx.path(sp, vec![type_ident, variant.ident]);
|
|
|
|
let use_ref_pat = false; // because enums can't be repr(packed)
|
|
|
|
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-05 09:04:41 +10:00
|
|
|
cx,
|
2022-07-06 16:13:51 +10: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-05 09:04:41 +10:00
|
|
|
&variant.data,
|
|
|
|
&prefixes,
|
2022-07-06 16:13:51 +10:00
|
|
|
use_ref_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-05 09:04:41 +10:00
|
|
|
);
|
|
|
|
|
2014-07-06 21:19:12 +02:00
|
|
|
// Here is the pat = `(&VariantK, &VariantK, ...)`
|
2022-07-04 15:08:28 +10:00
|
|
|
let single_pat = if subpats.len() == 1 {
|
|
|
|
subpats.pop().unwrap()
|
|
|
|
} else {
|
|
|
|
cx.pat_tuple(span, subpats)
|
|
|
|
};
|
2014-07-06 21:19:12 +02: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-05 09:04:41 +10:00
|
|
|
//
|
2014-07-06 21:19:12 +02: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-05 09:04:41 +10:00
|
|
|
let substructure = EnumMatching(index, variants.len(), variant, fields);
|
2022-06-28 13:10:36 +10:00
|
|
|
let arm_expr = self
|
2022-07-05 08:25:47 +10:00
|
|
|
.call_substructure_method(
|
|
|
|
cx,
|
|
|
|
trait_,
|
|
|
|
type_ident,
|
|
|
|
nonselflike_args,
|
|
|
|
&substructure,
|
|
|
|
)
|
2022-06-28 13:10:36 +10:00
|
|
|
.into_expr(cx, span);
|
2014-07-06 21:19:12 +02:00
|
|
|
|
2021-11-20 18:46:36 +00:00
|
|
|
cx.arm(span, single_pat, arm_expr)
|
2016-07-19 23:02:06 +05:30
|
|
|
})
|
|
|
|
.collect();
|
2016-05-12 17:54:05 +02:00
|
|
|
|
|
|
|
let default = match first_fieldless {
|
|
|
|
Some(v) if self.unify_fieldless_variants => {
|
|
|
|
// We need a default case that handles the fieldless variants.
|
|
|
|
// The index and actual variant aren't meaningful in this case,
|
|
|
|
// so just use whatever
|
2017-06-16 22:59:20 +03:00
|
|
|
let substructure = EnumMatching(0, variants.len(), v, Vec::new());
|
2022-06-28 13:10:36 +10:00
|
|
|
Some(
|
|
|
|
self.call_substructure_method(
|
|
|
|
cx,
|
|
|
|
trait_,
|
|
|
|
type_ident,
|
2022-07-05 08:25:47 +10:00
|
|
|
nonselflike_args,
|
2022-06-28 13:10:36 +10:00
|
|
|
&substructure,
|
|
|
|
)
|
|
|
|
.into_expr(cx, span),
|
|
|
|
)
|
2016-05-12 17:54:05 +02:00
|
|
|
}
|
2022-07-05 08:25:47 +10:00
|
|
|
_ if variants.len() > 1 && selflike_args.len() > 1 => {
|
2016-05-12 17:54:05 +02:00
|
|
|
// Since we know that all the arguments will match if we reach
|
|
|
|
// the match expression we add the unreachable intrinsics as the
|
|
|
|
// result of the catch all which should help llvm in optimizing it
|
2021-11-20 18:46:36 +00:00
|
|
|
Some(deriving::call_unreachable(cx, span))
|
2016-05-12 17:54:05 +02:00
|
|
|
}
|
2016-07-19 23:02:06 +05:30
|
|
|
_ => None,
|
2016-05-12 17:54:05 +02: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 17:54:05 +02:00
|
|
|
}
|
|
|
|
|
2014-07-06 21:19:12 +02:00
|
|
|
// We will usually need the catch-all after matching the
|
|
|
|
// tuples `(VariantK, VariantK, ...)` for each VariantK of the
|
|
|
|
// enum. But:
|
|
|
|
//
|
|
|
|
// * when there is only one Self arg, the arms above suffice
|
|
|
|
// (and the deriving we call back into may not be prepared to
|
|
|
|
// handle EnumNonMatchCollapsed), and,
|
|
|
|
//
|
|
|
|
// * when the enum has only one variant, the single arm that
|
|
|
|
// is already present always suffices.
|
|
|
|
//
|
|
|
|
// * In either of the two cases above, if we *did* add a
|
|
|
|
// catch-all `_` match, it would trigger the
|
|
|
|
// unreachable-pattern error.
|
|
|
|
//
|
2022-07-05 08:25:47 +10:00
|
|
|
if variants.len() > 1 && selflike_args.len() > 1 {
|
|
|
|
// Build a series of let statements mapping each selflike_arg
|
2020-04-05 20:36:39 +02:00
|
|
|
// to its discriminant value.
|
2015-04-10 16:15:12 +02:00
|
|
|
//
|
2022-07-06 16:13:51 +10:00
|
|
|
// i.e., for `enum E<T> { A, B(1), C(T, T) }` for `PartialEq::eq`,
|
|
|
|
// builds two statements:
|
2014-07-06 21:19:12 +02:00
|
|
|
// ```
|
2022-07-06 16:13:51 +10:00
|
|
|
// let __self_vi = ::core::intrinsics::discriminant_value(self);
|
|
|
|
// let __arg_1_vi = ::core::intrinsics::discriminant_value(other);
|
2014-07-06 21:19:12 +02:00
|
|
|
// ```
|
2018-10-31 16:58:51 +01:00
|
|
|
let mut index_let_stmts: Vec<ast::Stmt> = Vec::with_capacity(vi_idents.len() + 1);
|
2015-04-10 19:00:38 +02:00
|
|
|
|
2022-07-06 16:13:51 +10:00
|
|
|
// We also build an expression which checks whether all discriminants are equal, e.g.
|
|
|
|
// `__self_vi == __arg_1_vi`.
|
2021-11-20 18:46:36 +00:00
|
|
|
let mut discriminant_test = cx.expr_bool(span, true);
|
2022-07-05 08:25:47 +10:00
|
|
|
for (i, (&ident, selflike_arg)) in iter::zip(&vi_idents, &selflike_args).enumerate() {
|
|
|
|
let variant_value = deriving::call_intrinsic(
|
|
|
|
cx,
|
|
|
|
span,
|
|
|
|
sym::discriminant_value,
|
2022-07-06 16:13:51 +10:00
|
|
|
vec![selflike_arg.clone()],
|
2022-07-05 08:25:47 +10:00
|
|
|
);
|
2021-11-20 18:46:36 +00:00
|
|
|
let let_stmt = cx.stmt_let(span, false, ident, variant_value);
|
2014-07-06 21:19:12 +02:00
|
|
|
index_let_stmts.push(let_stmt);
|
2015-06-12 09:41:06 +02:00
|
|
|
|
2022-06-22 15:00:53 +10:00
|
|
|
if i > 0 {
|
|
|
|
let id0 = cx.expr_ident(span, vi_idents[0]);
|
|
|
|
let id = cx.expr_ident(span, ident);
|
|
|
|
let test = cx.expr_binary(span, BinOpKind::Eq, id0, id);
|
|
|
|
discriminant_test = if i == 1 {
|
|
|
|
test
|
|
|
|
} else {
|
|
|
|
cx.expr_binary(span, BinOpKind::And, discriminant_test, test)
|
|
|
|
};
|
2015-06-12 09:41:06 +02:00
|
|
|
}
|
2014-07-06 21:19:12 +02:00
|
|
|
}
|
|
|
|
|
2022-06-28 13:10:36 +10:00
|
|
|
let arm_expr = self
|
|
|
|
.call_substructure_method(
|
|
|
|
cx,
|
|
|
|
trait_,
|
|
|
|
type_ident,
|
2022-07-05 08:25:47 +10:00
|
|
|
nonselflike_args,
|
2022-06-28 13:10:36 +10:00
|
|
|
&catch_all_substructure,
|
|
|
|
)
|
|
|
|
.into_expr(cx, span);
|
2014-07-06 21:19:12 +02:00
|
|
|
|
2022-07-05 08:25:47 +10:00
|
|
|
let match_arg = cx.expr(span, ast::ExprKind::Tup(selflike_args));
|
2015-06-12 09:41:06 +02:00
|
|
|
|
2022-07-06 16:13:51 +10:00
|
|
|
// Lastly we create an expression which branches on all discriminants being equal, e.g.
|
|
|
|
// if __self_vi == _arg_1_vi {
|
|
|
|
// match (self, other) {
|
2015-06-12 09:41:06 +02:00
|
|
|
// (Variant1, Variant1, ...) => Body1
|
|
|
|
// (Variant2, Variant2, ...) => Body2,
|
|
|
|
// ...
|
|
|
|
// _ => ::core::intrinsics::unreachable()
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// else {
|
2022-06-22 15:00:53 +10:00
|
|
|
// <delegated expression referring to __self_vi, et al.>
|
2015-06-12 09:41:06 +02:00
|
|
|
// }
|
2021-11-20 18:46:36 +00:00
|
|
|
let all_match = cx.expr_match(span, match_arg, match_arms);
|
|
|
|
let arm_expr = cx.expr_if(span, discriminant_test, all_match, Some(arm_expr));
|
2022-06-28 13:10:36 +10:00
|
|
|
BlockOrExpr(index_let_stmts, Some(arm_expr))
|
2015-03-24 16:53:34 -07:00
|
|
|
} else if variants.is_empty() {
|
2022-07-05 09:50:36 +10:00
|
|
|
// There is no sensible code to be generated for *any* deriving on
|
|
|
|
// a zero-variant enum. So we just generate a failing expression
|
|
|
|
// for the zero variant case.
|
2022-06-28 13:10:36 +10:00
|
|
|
BlockOrExpr(vec![], Some(deriving::call_unreachable(cx, span)))
|
2016-07-19 23:02:06 +05:30
|
|
|
} else {
|
2022-07-05 08:25:47 +10:00
|
|
|
let match_arg = if selflike_args.len() == 1 {
|
|
|
|
selflike_args.pop().unwrap()
|
2022-07-04 15:08:28 +10:00
|
|
|
} else {
|
2022-07-05 08:25:47 +10:00
|
|
|
cx.expr(span, ast::ExprKind::Tup(selflike_args))
|
2022-07-04 15:08:28 +10:00
|
|
|
};
|
2022-06-28 13:10:36 +10:00
|
|
|
BlockOrExpr(vec![], Some(cx.expr_match(span, match_arg, match_arms)))
|
2014-07-06 21:19:12 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-07 01:23:51 +10:00
|
|
|
fn expand_static_enum_method_body(
|
|
|
|
&self,
|
2019-02-04 21:49:54 +09:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
|
|
|
trait_: &TraitDef<'_>,
|
2014-01-09 15:05:33 +02:00
|
|
|
enum_def: &EnumDef,
|
2013-11-07 18:49:01 +11:00
|
|
|
type_ident: Ident,
|
2022-07-05 08:25:47 +10:00
|
|
|
nonselflike_args: &[P<Expr>],
|
2022-06-28 13:10:36 +10:00
|
|
|
) -> BlockOrExpr {
|
2016-07-19 23:02:06 +05:30
|
|
|
let summary = enum_def
|
|
|
|
.variants
|
|
|
|
.iter()
|
|
|
|
.map(|v| {
|
2017-07-31 23:04:34 +03:00
|
|
|
let sp = v.span.with_ctxt(trait_.span.ctxt());
|
2019-08-13 21:40:21 -03:00
|
|
|
let summary = trait_.summarise_struct(cx, &v.data);
|
|
|
|
(v.ident, sp, summary)
|
2016-07-19 23:02:06 +05:30
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
self.call_substructure_method(
|
|
|
|
cx,
|
|
|
|
trait_,
|
|
|
|
type_ident,
|
2022-07-05 08:25:47 +10:00
|
|
|
nonselflike_args,
|
2013-05-07 01:23:51 +10:00
|
|
|
&StaticEnum(enum_def, summary),
|
|
|
|
)
|
|
|
|
}
|
2013-03-28 21:50:10 +11:00
|
|
|
}
|
|
|
|
|
2013-12-07 11:57:44 +11:00
|
|
|
// general helper methods.
|
|
|
|
impl<'a> TraitDef<'a> {
|
2019-02-04 21:49:54 +09:00
|
|
|
fn summarise_struct(&self, cx: &mut ExtCtxt<'_>, struct_def: &VariantData) -> StaticFields {
|
2014-02-28 13:09:09 -08:00
|
|
|
let mut named_idents = Vec::new();
|
|
|
|
let mut just_spans = Vec::new();
|
2016-07-19 23:02:06 +05:30
|
|
|
for field in struct_def.fields() {
|
2017-07-31 23:04:34 +03:00
|
|
|
let sp = field.span.with_ctxt(self.span.ctxt());
|
2016-04-06 11:19:10 +03:00
|
|
|
match field.ident {
|
2016-04-02 16:47:53 +03:00
|
|
|
Some(ident) => named_idents.push((ident, sp)),
|
|
|
|
_ => just_spans.push(sp),
|
2013-12-07 11:57:44 +11:00
|
|
|
}
|
2013-03-28 21:50:10 +11:00
|
|
|
}
|
2013-05-07 01:23:51 +10:00
|
|
|
|
2020-09-18 19:11:06 +02:00
|
|
|
let is_tuple = matches!(struct_def, ast::VariantData::Tuple(..));
|
2013-12-07 11:57:44 +11: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 11:57:44 +11:00
|
|
|
// named fields
|
|
|
|
(_, false) => Named(named_idents),
|
2019-03-24 00:06:58 +03:00
|
|
|
// unnamed fields
|
|
|
|
(false, _) => Unnamed(just_spans, is_tuple),
|
|
|
|
// empty
|
|
|
|
_ => Named(Vec::new()),
|
2013-12-07 11:57:44 +11:00
|
|
|
}
|
2013-03-28 21:50:10 +11: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-05 09:04:41 +10:00
|
|
|
fn create_struct_patterns(
|
2013-12-07 11:57:44 +11:00
|
|
|
&self,
|
2019-02-04 21:49:54 +09: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-05 09:04:41 +10:00
|
|
|
struct_path: ast::Path,
|
|
|
|
struct_def: &'a VariantData,
|
|
|
|
prefixes: &[String],
|
2022-07-06 16:13:51 +10:00
|
|
|
use_ref_pat: bool,
|
2014-09-13 19:06:01 +03: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-05 09:04:41 +10:00
|
|
|
prefixes
|
2016-07-19 23:02:06 +05:30
|
|
|
.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-05 09:04:41 +10:00
|
|
|
.map(|prefix| {
|
2022-07-08 07:57:34 +10: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-05 09:04:41 +10:00
|
|
|
let sp = struct_field.span.with_ctxt(self.span.ctxt());
|
2022-07-06 16:13:51 +10:00
|
|
|
let binding_mode = if use_ref_pat {
|
2022-07-06 16:13:20 +10:00
|
|
|
ast::BindingMode::ByRef(ast::Mutability::Not)
|
2022-07-06 16:13:51 +10:00
|
|
|
} else {
|
|
|
|
ast::BindingMode::ByValue(ast::Mutability::Not)
|
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-05 09:04:41 +10:00
|
|
|
};
|
|
|
|
let ident = self.mk_pattern_ident(prefix, i);
|
|
|
|
let path = ident.with_span_pos(sp);
|
|
|
|
(
|
|
|
|
sp,
|
|
|
|
struct_field.ident,
|
|
|
|
cx.pat(path.span, PatKind::Ident(binding_mode, path, None)),
|
|
|
|
)
|
2022-07-08 07:57:34 +10: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-05 09:04:41 +10:00
|
|
|
|
|
|
|
let struct_path = struct_path.clone();
|
|
|
|
match *struct_def {
|
|
|
|
VariantData::Struct(..) => {
|
2022-07-08 07:57:34 +10: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-05 09:04:41 +10: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-08 07:57:34 +10: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-05 09:04:41 +10:00
|
|
|
cx.pat_tuple_struct(self.span, struct_path, subpats)
|
|
|
|
}
|
|
|
|
VariantData::Unit(..) => cx.pat_path(self.span, struct_path),
|
|
|
|
}
|
2016-07-19 23:02:06 +05:30
|
|
|
})
|
|
|
|
.collect()
|
2013-12-07 11:57:44 +11:00
|
|
|
}
|
2013-06-07 17:30:38 +10: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-05 09:04:41 +10: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 17:30:38 +10: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-05 09:04:41 +10:00
|
|
|
fn mk_pattern_ident(&self, prefix: &str, i: usize) -> Ident {
|
|
|
|
Ident::from_str_and_span(&format!("{}_{}", prefix, i), self.span)
|
2013-12-07 11:57:44 +11:00
|
|
|
}
|
2013-06-07 17:30:38 +10: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-05 09:04:41 +10: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 10:20:54 +10: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-05 09:04:41 +10:00
|
|
|
prefixes: &[String],
|
2022-07-07 11:09:07 +10:00
|
|
|
addr_of: 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-05 09:04:41 +10:00
|
|
|
) -> Vec<FieldInfo> {
|
|
|
|
self.create_fields(struct_def, |i, _struct_field, sp| {
|
|
|
|
prefixes
|
|
|
|
.iter()
|
|
|
|
.map(|prefix| {
|
|
|
|
let ident = self.mk_pattern_ident(prefix, i);
|
|
|
|
let expr = cx.expr_path(cx.path_ident(sp, ident));
|
2022-07-07 11:09:07 +10:00
|
|
|
if addr_of { cx.expr_addr_of(sp, expr) } else { 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-05 09:04:41 +10: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 10:20:54 +10: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-05 09:04:41 +10:00
|
|
|
fn create_struct_field_access_fields(
|
2016-07-19 23:02:06 +05:30
|
|
|
&self,
|
2019-02-04 21:49:54 +09: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-05 09:04:41 +10:00
|
|
|
selflike_args: &[P<Expr>],
|
|
|
|
struct_def: &'a VariantData,
|
|
|
|
) -> Vec<FieldInfo> {
|
|
|
|
self.create_fields(struct_def, |i, struct_field, sp| {
|
|
|
|
selflike_args
|
|
|
|
.iter()
|
2022-07-06 16:13:51 +10:00
|
|
|
.map(|selflike_arg| {
|
2022-07-07 11:09:07 +10: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-05 09:04:41 +10: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-07 11:09:07 +10:00
|
|
|
cx.expr_addr_of(
|
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-05 09:04:41 +10:00
|
|
|
sp,
|
2022-07-07 11:09:07 +10:00
|
|
|
cx.expr(
|
|
|
|
sp,
|
|
|
|
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-05 09:04:41 +10:00
|
|
|
),
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.collect()
|
|
|
|
})
|
2013-06-07 17:30:38 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-05 11:23:55 +10: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,
|
|
|
|
|
|
|
|
/// The fallback case for non-matching enum variants. The slice is the
|
|
|
|
/// identifiers holding the variant index value for each of the `Self`
|
|
|
|
/// arguments.
|
|
|
|
EnumNonMatching(Span, &'a [Ident]),
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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 15:16:54 +01:00
|
|
|
use_foldl: bool,
|
2019-02-04 21:49:54 +09:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
2018-04-11 15:16:54 +01:00
|
|
|
trait_span: Span,
|
2019-02-04 21:49:54 +09:00
|
|
|
substructure: &Substructure<'_>,
|
2022-07-05 11:23:55 +10:00
|
|
|
mut f: F,
|
2018-04-11 15:16:54 +01:00
|
|
|
) -> P<Expr>
|
2019-02-04 21:49:54 +09:00
|
|
|
where
|
2022-07-05 11:23:55 +10:00
|
|
|
F: FnMut(&mut ExtCtxt<'_>, CsFold<'_>) -> P<Expr>,
|
2018-04-11 15:16:54 +01:00
|
|
|
{
|
|
|
|
match *substructure.fields {
|
|
|
|
EnumMatching(.., ref all_fields) | Struct(_, ref all_fields) => {
|
2022-07-05 11:23:55 +10: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 15:16:54 +01:00
|
|
|
};
|
|
|
|
|
2022-07-04 17:10:36 +10:00
|
|
|
if use_foldl {
|
2022-07-05 11:23:55 +10:00
|
|
|
rest.iter().fold(base_expr, op)
|
2022-07-04 17:10:36 +10:00
|
|
|
} else {
|
2022-07-05 11:23:55 +10:00
|
|
|
rest.iter().rfold(base_expr, op)
|
2022-07-04 17:10:36 +10:00
|
|
|
}
|
2018-04-11 15:16:54 +01:00
|
|
|
}
|
2022-07-05 11:23:55 +10:00
|
|
|
EnumNonMatchingCollapsed(tuple) => f(cx, CsFold::EnumNonMatching(trait_span, tuple)),
|
2022-07-04 17:10:36 +10:00
|
|
|
StaticEnum(..) | StaticStruct(..) => cx.span_bug(trait_span, "static function in `derive`"),
|
2018-04-11 15:16:54 +01:00
|
|
|
}
|
|
|
|
}
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2019-02-08 14:53:55 +01:00
|
|
|
/// Returns `true` if the type has no value fields
|
2016-03-01 02:27:27 +01:00
|
|
|
/// (for an enum, no variant has any fields)
|
|
|
|
pub fn is_type_without_fields(item: &Annotatable) -> bool {
|
|
|
|
if let Annotatable::Item(ref item) = *item {
|
2019-09-26 17:51:36 +01:00
|
|
|
match item.kind {
|
2016-03-01 02:27:27 +01:00
|
|
|
ast::ItemKind::Enum(ref enum_def, _) => {
|
2019-08-13 21:40:21 -03:00
|
|
|
enum_def.variants.iter().all(|v| v.data.fields().is_empty())
|
2016-03-01 02:27:27 +01:00
|
|
|
}
|
2016-07-19 23:02:06 +05:30
|
|
|
ast::ItemKind::Struct(ref variant_data, _) => variant_data.fields().is_empty(),
|
|
|
|
_ => false,
|
2016-03-01 02:27:27 +01:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|