2014-01-30 19:29:35 +01:00
|
|
|
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
|
2013-03-28 21:50:10 +11:00
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
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
|
|
|
|
//! (e.g. `Option<T>`), the parameters are automatically given the
|
|
|
|
//! 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
|
|
|
|
//! 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
|
|
|
|
//! 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.
|
|
|
|
//!
|
|
|
|
//! In the static cases, the structure is summarised, either into the just
|
|
|
|
//! spans of the fields or a list of spans and the field idents (for tuple
|
|
|
|
//! structs and record structs, respectively), or a list of these, for
|
|
|
|
//! enums (one for each variant). For empty struct and empty enum
|
|
|
|
//! variants, it is represented as a count of 0.
|
|
|
|
//!
|
2015-01-13 00:00:19 +11:00
|
|
|
//! # "`cs`" functions
|
|
|
|
//!
|
|
|
|
//! The `cs_...` functions ("combine substructure) are designed to
|
|
|
|
//! 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
|
|
|
//! vec![<ident of self>, <ident of __arg_1>],
|
2014-07-06 21:19:12 +02:00
|
|
|
//! &[<ast::Variant for C0>, <ast::Variant for C1>],
|
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
|
|
|
|
2014-11-06 00:05:53 -08:00
|
|
|
pub use self::StaticFields::*;
|
|
|
|
pub use self::SubstructureFields::*;
|
|
|
|
|
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
|
|
|
|
2018-08-05 12:04:56 +02:00
|
|
|
use rustc_data_structures::thin_vec::ThinVec;
|
2018-04-25 19:30:39 +03:00
|
|
|
use rustc_target::spec::abi::Abi;
|
2018-05-26 19:16:21 +01:00
|
|
|
use syntax::ast::{self, BinOpKind, EnumDef, Expr, Generics, Ident, PatKind};
|
2018-05-27 20:07:09 +01:00
|
|
|
use syntax::ast::{VariantData, GenericParamKind, GenericArg};
|
2015-12-10 23:23:14 +09:00
|
|
|
use syntax::attr;
|
2016-07-19 23:02:06 +05:30
|
|
|
use syntax::ext::base::{Annotatable, ExtCtxt};
|
2015-12-10 23:23:14 +09:00
|
|
|
use syntax::ext::build::AstBuilder;
|
2018-08-18 12:14:03 +02:00
|
|
|
use syntax::source_map::{self, respan};
|
2015-12-10 23:23:14 +09:00
|
|
|
use syntax::util::move_map::MoveMap;
|
|
|
|
use syntax::ptr::P;
|
2016-11-16 08:21:52 +00:00
|
|
|
use syntax::symbol::{Symbol, keywords};
|
2018-10-09 19:49:18 +08:00
|
|
|
use syntax::parse::ParseSess;
|
2016-07-19 23:02:06 +05:30
|
|
|
use syntax_pos::{DUMMY_SP, Span};
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2015-02-10 14:55:45 +01:00
|
|
|
use self::ty::{LifetimeBounds, Path, Ptr, PtrTy, Self_, Ty};
|
2014-05-29 12:19:05 +09:00
|
|
|
|
2016-03-10 00:31:19 -05:00
|
|
|
use deriving;
|
|
|
|
|
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
|
2014-03-27 15:39:48 -07:00
|
|
|
pub path: Path<'a>,
|
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
|
2014-03-27 15:39:48 -07:00
|
|
|
pub additional_bounds: Vec<Ty<'a>>,
|
2013-05-07 01:23:51 +10:00
|
|
|
|
2014-02-05 08:52:54 -08:00
|
|
|
/// Any extra lifetimes and/or bounds, e.g. `D: serialize::Decoder`
|
2014-03-27 15:39:48 -07:00
|
|
|
pub generics: LifetimeBounds<'a>,
|
2013-05-07 01:23:51 +10:00
|
|
|
|
2015-08-29 14:50:05 -04:00
|
|
|
/// Is it an `unsafe` trait?
|
|
|
|
pub is_unsafe: bool,
|
|
|
|
|
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
|
|
|
|
|
|
|
pub associated_types: Vec<(ast::Ident, Ty<'a>)>,
|
2014-03-27 15:39:48 -07:00
|
|
|
}
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2013-05-07 01:23:51 +10: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
|
2014-03-27 15:39:48 -07:00
|
|
|
pub name: &'a str,
|
2014-03-02 11:33:24 +11:00
|
|
|
/// List of generics, e.g. `R: rand::Rng`
|
2014-03-27 15:39:48 -07:00
|
|
|
pub generics: LifetimeBounds<'a>,
|
2013-05-07 01:23:51 +10:00
|
|
|
|
|
|
|
/// Whether there is a self argument (outer Option) i.e. whether
|
|
|
|
/// this is a static function, and whether it is a pointer (inner
|
|
|
|
/// Option)
|
2014-03-27 15:39:48 -07:00
|
|
|
pub explicit_self: Option<Option<PtrTy<'a>>>,
|
2013-05-07 01:23:51 +10:00
|
|
|
|
|
|
|
/// Arguments other than the self argument
|
2018-04-15 20:51:10 +01:00
|
|
|
pub args: Vec<(Ty<'a>, &'a str)>,
|
2013-05-07 01:23:51 +10:00
|
|
|
|
|
|
|
/// Return type
|
2014-03-27 15:39:48 -07:00
|
|
|
pub ret_ty: Ty<'a>,
|
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
|
|
|
|
2015-05-17 11:28:19 +05:30
|
|
|
// Is it an `unsafe fn`?
|
|
|
|
pub is_unsafe: bool,
|
|
|
|
|
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,
|
2013-05-07 01:23:51 +10:00
|
|
|
/// ident of the method
|
2014-03-27 15:39:48 -07:00
|
|
|
pub method_ident: Ident,
|
2015-02-10 14:55:45 +01:00
|
|
|
/// dereferenced access to any `Self_` or `Ptr(Self_, _)` arguments
|
2014-09-13 19:06:01 +03:00
|
|
|
pub self_args: &'a [P<Expr>],
|
2013-05-07 01:23:51 +10:00
|
|
|
/// verbatim access to any other arguments
|
2014-09-13 19:06:01 +03:00
|
|
|
pub nonself_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.
|
2015-05-01 06:40:06 +05:30
|
|
|
pub struct FieldInfo<'a> {
|
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).
|
2014-09-13 19:06:01 +03:00
|
|
|
pub self_: P<Expr>,
|
2013-11-07 18:49:01 +11:00
|
|
|
/// The expressions corresponding to references to this field in
|
2014-09-17 15:02:26 +02:00
|
|
|
/// the other `Self` arguments.
|
2014-09-13 19:06:01 +03:00
|
|
|
pub other: Vec<P<Expr>>,
|
2015-05-01 06:40:06 +05:30
|
|
|
/// The attributes on the field
|
|
|
|
pub attrs: &'a [ast::Attribute],
|
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> {
|
2016-02-22 21:24:32 +03:00
|
|
|
Struct(&'a ast::VariantData, Vec<FieldInfo<'a>>),
|
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.
|
2017-06-16 22:59:20 +03:00
|
|
|
EnumMatching(usize, usize, &'a ast::Variant, Vec<FieldInfo<'a>>),
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2014-09-17 15:02:26 +02:00
|
|
|
/// Non-matching variants of the enum, but with all state hidden from
|
|
|
|
/// the consequent code. The first component holds `Ident`s for all of
|
|
|
|
/// the `Self` arguments; the second component is a slice of all of the
|
2014-09-16 13:27:34 +02:00
|
|
|
/// variants for the enum itself, and the third component is a list of
|
2014-09-17 15:02:26 +02:00
|
|
|
/// `Ident`s bound to the variant index values for each of the actual
|
|
|
|
/// input `Self` arguments.
|
2016-02-11 23:33:09 +03:00
|
|
|
EnumNonMatchingCollapsed(Vec<Ident>, &'a [ast::Variant], &'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
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-05-07 01:23:51 +10: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> =
|
2018-07-12 11:58:16 +02:00
|
|
|
Box<dyn FnMut(&mut ExtCtxt, Span, &Substructure) -> P<Expr> + 'a>;
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2014-09-16 13:27:34 +02:00
|
|
|
/// Deal with non-matching enum variants. The tuple is a list of
|
2014-09-17 15:02:26 +02:00
|
|
|
/// identifiers (one for each `Self` argument, which could be any of the
|
2014-09-16 13:27:34 +02:00
|
|
|
/// variants since they have been collapsed together) and the identifiers
|
2014-09-17 15:02:26 +02:00
|
|
|
/// holding the variant index value for each of the `Self` arguments. The
|
|
|
|
/// last argument is all the non-`Self` args of the method being derived.
|
2014-07-06 21:19:12 +02:00
|
|
|
pub type EnumNonMatchCollapsedFunc<'a> =
|
2018-07-12 11:58:16 +02:00
|
|
|
Box<dyn FnMut(&mut ExtCtxt, Span, (&[Ident], &[Ident]), &[P<Expr>]) -> P<Expr> + 'a>;
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2014-04-21 23:25:18 -07:00
|
|
|
pub fn combine_substructure<'a>(f: CombineSubstructureFunc<'a>)
|
2016-07-19 23:02:06 +05:30
|
|
|
-> RefCell<CombineSubstructureFunc<'a>> {
|
2014-04-21 23:25:18 -07:00
|
|
|
RefCell::new(f)
|
|
|
|
}
|
|
|
|
|
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`.
|
2016-07-19 23:02:06 +05:30
|
|
|
fn find_type_parameters(ty: &ast::Ty,
|
|
|
|
ty_param_names: &[ast::Name],
|
|
|
|
span: Span,
|
|
|
|
cx: &ExtCtxt)
|
2016-06-24 03:23:44 +00:00
|
|
|
-> Vec<P<ast::Ty>> {
|
2015-12-10 23:23:14 +09:00
|
|
|
use syntax::visit;
|
2015-03-24 14:43:26 -07:00
|
|
|
|
2016-06-24 03:23:44 +00:00
|
|
|
struct Visitor<'a, 'b: 'a> {
|
|
|
|
cx: &'a ExtCtxt<'b>,
|
|
|
|
span: Span,
|
2015-03-24 14:43:26 -07:00
|
|
|
ty_param_names: &'a [ast::Name],
|
|
|
|
types: Vec<P<ast::Ty>>,
|
|
|
|
}
|
|
|
|
|
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) {
|
2016-12-05 03:51:11 +00:00
|
|
|
if let ast::TyKind::Path(_, ref path) = ty.node {
|
|
|
|
if let Some(segment) = path.segments.first() {
|
2018-03-18 03:53:41 +03:00
|
|
|
if self.ty_param_names.contains(&segment.ident.name) {
|
2016-12-05 03:51:11 +00:00
|
|
|
self.types.push(P(ty.clone()));
|
2015-03-24 14:43:26 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
visit::walk_ty(self, ty)
|
|
|
|
}
|
2016-06-24 03:23:44 +00:00
|
|
|
|
|
|
|
fn visit_mac(&mut self, mac: &ast::Mac) {
|
2017-07-31 23:04:34 +03:00
|
|
|
let span = mac.span.with_ctxt(self.span.ctxt());
|
2016-06-24 03:23:44 +00:00
|
|
|
self.cx.span_err(span, "`derive` cannot be used on items with type macros");
|
|
|
|
}
|
2015-03-24 14:43:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
let mut visitor = Visitor {
|
2017-08-06 22:54:09 -07:00
|
|
|
ty_param_names,
|
2015-03-24 14:43:26 -07:00
|
|
|
types: Vec::new(),
|
2017-08-06 22:54:09 -07:00
|
|
|
span,
|
|
|
|
cx,
|
2015-03-24 14:43:26 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
visit::Visitor::visit_ty(&mut visitor, ty);
|
|
|
|
|
|
|
|
visitor.types
|
|
|
|
}
|
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,
|
2015-03-26 18:07:49 -07:00
|
|
|
cx: &mut ExtCtxt,
|
|
|
|
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,
|
2016-08-26 19:23:42 +03:00
|
|
|
cx: &mut ExtCtxt,
|
|
|
|
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| {
|
2018-10-09 19:49:18 +08:00
|
|
|
for r in attr::find_repr_attrs(&cx.parse_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
|
|
|
});
|
2017-11-19 17:04:24 +02:00
|
|
|
let has_no_type_params = match item.node {
|
|
|
|
ast::ItemKind::Struct(_, ref generics) |
|
|
|
|
ast::ItemKind::Enum(_, ref generics) |
|
|
|
|
ast::ItemKind::Union(_, ref generics) => {
|
2018-05-26 23:21:08 +01:00
|
|
|
!generics.params.iter().any(|param| match param.kind {
|
2018-05-27 20:07:09 +01:00
|
|
|
ast::GenericParamKind::Type { .. } => true,
|
2018-05-26 23:21:08 +01:00
|
|
|
_ => false,
|
|
|
|
})
|
2017-11-19 17:04:24 +02:00
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
// Non-ADT derive is an error, but it should have been
|
|
|
|
// set earlier; see
|
|
|
|
// libsyntax/ext/expand.rs:MacroExpander::expand()
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
let is_always_copy =
|
|
|
|
attr::contains_name(&item.attrs, "rustc_copy_clone_marker") &&
|
|
|
|
has_no_type_params;
|
|
|
|
let use_temporaries = is_packed && is_always_copy;
|
|
|
|
|
2015-04-28 17:34:39 +12:00
|
|
|
let newitem = match item.node {
|
2016-02-09 11:36:51 +01:00
|
|
|
ast::ItemKind::Struct(ref struct_def, ref generics) => {
|
2017-10-02 15:15:23 +02:00
|
|
|
self.expand_struct_def(cx, &struct_def, item.ident, generics, from_scratch,
|
|
|
|
use_temporaries)
|
2015-04-28 17:34:39 +12:00
|
|
|
}
|
2016-02-09 11:36:51 +01:00
|
|
|
ast::ItemKind::Enum(ref enum_def, ref generics) => {
|
2017-10-02 15:15:23 +02:00
|
|
|
// We ignore `use_temporaries` here, because
|
|
|
|
// `repr(packed)` enums cause an error later on.
|
|
|
|
//
|
|
|
|
// This can only cause further compilation errors
|
|
|
|
// downstream in blatantly illegal code, so it
|
|
|
|
// is fine.
|
2016-08-26 19:23:42 +03:00
|
|
|
self.expand_enum_def(cx, enum_def, &item.attrs,
|
|
|
|
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,
|
|
|
|
use_temporaries)
|
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()
|
|
|
|
.filter(|a| {
|
2018-01-30 14:53:01 +09:00
|
|
|
match &*a.name().as_str() {
|
2016-07-19 23:02:06 +05:30
|
|
|
"allow" | "warn" | "deny" | "forbid" | "stable" | "unstable" => true,
|
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.cloned());
|
|
|
|
push(Annotatable::Item(P(ast::Item { attrs: attrs, ..(*newitem).clone() })))
|
2014-02-12 23:53:52 -08:00
|
|
|
}
|
2014-11-18 14:02:40 -08:00
|
|
|
_ => {
|
2017-08-22 19:22:52 -07:00
|
|
|
// Non-Item derive is an error, but it should have been
|
|
|
|
// set earlier; see
|
|
|
|
// libsyntax/ext/expand.rs:MacroExpander::expand()
|
|
|
|
return;
|
2014-05-11 01:11:33 -07:00
|
|
|
}
|
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)
|
2015-03-24 14:43:26 -07:00
|
|
|
/// impl<'a, ..., 'z, A, B: DeclaredTrait, C, ... Z> where
|
|
|
|
/// 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,
|
2014-02-08 19:39:53 -05: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>>,
|
2016-07-19 23:02:06 +05:30
|
|
|
methods: Vec<ast::ImplItem>)
|
|
|
|
-> 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
|
|
|
|
2015-03-10 12:28:44 +02:00
|
|
|
// Transform associated types from `deriving::ty::Ty` into `ast::ImplItem`
|
2015-01-25 00:29:24 -05:00
|
|
|
let associated_types = self.associated_types.iter().map(|&(ident, ref type_def)| {
|
2016-02-11 23:33:09 +03:00
|
|
|
ast::ImplItem {
|
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,
|
2018-03-10 17:45:47 +03:00
|
|
|
vis: respan(self.span.shrink_to_lo(), ast::VisibilityKind::Inherited),
|
2015-12-18 14:38:28 -08:00
|
|
|
defaultness: ast::Defaultness::Final,
|
2015-01-25 00:29:24 -05:00
|
|
|
attrs: Vec::new(),
|
2017-09-21 22:18:47 -04:00
|
|
|
generics: Generics::default(),
|
2016-07-19 23:02:06 +05:30
|
|
|
node: ast::ImplItemKind::Type(type_def.to_ty(cx, self.span, type_ident, generics)),
|
2017-07-12 09:50:05 -07:00
|
|
|
tokens: None,
|
2016-02-11 23:33:09 +03:00
|
|
|
}
|
2015-01-25 00:29:24 -05:00
|
|
|
});
|
|
|
|
|
2017-10-16 21:07:26 +02:00
|
|
|
let Generics { mut params, mut where_clause, span } = self.generics
|
2016-07-19 23:02:06 +05:30
|
|
|
.to_generics(cx, self.span, type_ident, generics);
|
2014-03-19 23:16:56 +11:00
|
|
|
|
2017-10-16 21:07:26 +02:00
|
|
|
// Create the generic parameters
|
2018-05-27 01:43:03 +01:00
|
|
|
params.extend(generics.params.iter().map(|param| match param.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
|
|
|
|
|
|
|
cx.typaram(self.span, param.ident, vec![], bounds, None)
|
2017-10-16 21:07:26 +02:00
|
|
|
}
|
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| {
|
|
|
|
match *clause {
|
|
|
|
ast::WherePredicate::BoundPredicate(ref wb) => {
|
|
|
|
ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
|
|
|
|
span: self.span,
|
2017-10-16 21:07:26 +02:00
|
|
|
bound_generic_params: wb.bound_generic_params.clone(),
|
2014-12-20 02:29:19 -08:00
|
|
|
bounded_ty: wb.bounded_ty.clone(),
|
2016-04-22 23:43:14 +03:00
|
|
|
bounds: wb.bounds.iter().cloned().collect(),
|
2014-12-14 00:35:35 -05:00
|
|
|
})
|
|
|
|
}
|
2014-12-20 02:29:19 -08:00
|
|
|
ast::WherePredicate::RegionPredicate(ref rb) => {
|
|
|
|
ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
|
|
|
|
span: self.span,
|
|
|
|
lifetime: rb.lifetime,
|
2016-07-19 23:02:06 +05:30
|
|
|
bounds: rb.bounds.iter().cloned().collect(),
|
2014-12-20 02:29:19 -08:00
|
|
|
})
|
|
|
|
}
|
2014-12-14 00:35:35 -05:00
|
|
|
ast::WherePredicate::EqPredicate(ref we) => {
|
|
|
|
ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
|
|
|
|
id: ast::DUMMY_NODE_ID,
|
|
|
|
span: self.span,
|
2017-01-16 21:32:13 +03:00
|
|
|
lhs_ty: we.lhs_ty.clone(),
|
|
|
|
rhs_ty: we.rhs_ty.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()
|
2018-05-26 19:16:21 +01:00
|
|
|
.filter_map(|param| match param.kind {
|
2018-05-27 20:07:09 +01:00
|
|
|
ast::GenericParamKind::Type { .. } => Some(param),
|
2017-10-16 21:07:26 +02:00
|
|
|
_ => None,
|
|
|
|
})
|
|
|
|
.peekable();
|
|
|
|
|
|
|
|
if ty_params.peek().is_some() {
|
|
|
|
let ty_param_names: Vec<ast::Name> = ty_params
|
|
|
|
.map(|ty_param| ty_param.ident.name)
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
for field_ty in field_tys {
|
|
|
|
let tys = find_type_parameters(&field_ty, &ty_param_names, self.span, cx);
|
|
|
|
|
|
|
|
for ty in tys {
|
|
|
|
// if we have already handled this type, skip it
|
|
|
|
if let ast::TyKind::Path(_, ref p) = ty.node {
|
|
|
|
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()
|
|
|
|
.map(|p| {
|
2018-06-14 15:00:21 +01:00
|
|
|
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,
|
|
|
|
bound_generic_params: Vec::new(),
|
|
|
|
bounded_ty: ty,
|
|
|
|
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 {
|
2017-10-16 21:07:26 +02:00
|
|
|
params,
|
2017-08-06 22:54:09 -07:00
|
|
|
where_clause,
|
|
|
|
span,
|
2014-03-19 23:16:56 +11:00
|
|
|
};
|
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 { .. } => {
|
2018-06-15 10:52:46 +01:00
|
|
|
GenericArg::Lifetime(cx.lifetime(self.span, param.ident))
|
2018-05-27 21:54:10 +01:00
|
|
|
}
|
|
|
|
GenericParamKind::Type { .. } => {
|
|
|
|
GenericArg::Type(cx.ty_ident(self.span, param.ident))
|
|
|
|
}
|
|
|
|
}).collect();
|
2018-02-08 08:58:13 +00:00
|
|
|
|
2013-06-07 17:30:38 +10:00
|
|
|
// Create the type of `self`.
|
2018-05-27 21:54:10 +01:00
|
|
|
let path = cx.path_all(self.span, false, vec![type_ident], self_params, vec![]);
|
|
|
|
let self_type = cx.ty_path(path);
|
2016-07-19 23:02:06 +05:30
|
|
|
|
|
|
|
let attr = cx.attribute(self.span,
|
|
|
|
cx.meta_word(self.span,
|
2016-11-16 08:21:52 +00:00
|
|
|
Symbol::intern("automatically_derived")));
|
2014-05-23 08:39:26 -07:00
|
|
|
// Just mark it now since we know that it'll end up used downstream
|
|
|
|
attr::mark_used(&attr);
|
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 = {
|
2016-11-16 08:21:52 +00:00
|
|
|
let word = cx.meta_list_item_word(self.span, Symbol::intern("unused_qualifications"));
|
|
|
|
cx.attribute(self.span, cx.meta_list(self.span, Symbol::intern("allow"), vec![word]))
|
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
|
|
|
|
|
|
|
let unsafety = if self.is_unsafe {
|
|
|
|
ast::Unsafety::Unsafe
|
|
|
|
} else {
|
|
|
|
ast::Unsafety::Normal
|
|
|
|
};
|
|
|
|
|
2016-07-19 23:02:06 +05:30
|
|
|
cx.item(self.span,
|
|
|
|
keywords::Invalid.ident(),
|
|
|
|
a,
|
|
|
|
ast::ItemKind::Impl(unsafety,
|
|
|
|
ast::ImplPolarity::Positive,
|
2016-11-18 17:14:42 +01:00
|
|
|
ast::Defaultness::Final,
|
2016-07-19 23:02:06 +05:30
|
|
|
trait_generics,
|
|
|
|
opt_trait_ref,
|
|
|
|
self_type,
|
|
|
|
methods.into_iter().chain(associated_types).collect()))
|
2013-03-28 21:50:10 +11:00
|
|
|
}
|
|
|
|
|
2014-02-21 21:33:23 -08:00
|
|
|
fn expand_struct_def(&self,
|
|
|
|
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,
|
|
|
|
use_temporaries: bool)
|
2016-07-19 23:02:06 +05:30
|
|
|
-> P<ast::Item> {
|
|
|
|
let field_tys: Vec<P<ast::Ty>> = struct_def.fields()
|
|
|
|
.iter()
|
2016-04-06 11:19:10 +03:00
|
|
|
.map(|field| field.ty.clone())
|
2015-03-24 14:43:26 -07:00
|
|
|
.collect();
|
|
|
|
|
2016-07-19 23:02:06 +05:30
|
|
|
let methods = self.methods
|
|
|
|
.iter()
|
|
|
|
.map(|method_def| {
|
|
|
|
let (explicit_self, self_args, nonself_args, tys) =
|
|
|
|
method_def.split_self_nonself_args(cx, self, type_ident, generics);
|
|
|
|
|
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,
|
|
|
|
&self_args[..],
|
|
|
|
&nonself_args[..])
|
|
|
|
} else {
|
|
|
|
method_def.expand_struct_method_body(cx,
|
|
|
|
self,
|
|
|
|
struct_def,
|
|
|
|
type_ident,
|
|
|
|
&self_args[..],
|
2017-10-02 15:15:23 +02:00
|
|
|
&nonself_args[..],
|
|
|
|
use_temporaries)
|
2016-07-19 23:02:06 +05:30
|
|
|
};
|
|
|
|
|
|
|
|
method_def.create_method(cx,
|
|
|
|
self,
|
|
|
|
type_ident,
|
|
|
|
generics,
|
|
|
|
Abi::Rust,
|
|
|
|
explicit_self,
|
|
|
|
tys,
|
|
|
|
body)
|
|
|
|
})
|
|
|
|
.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,
|
2014-02-08 19:39:53 -05:00
|
|
|
cx: &mut ExtCtxt,
|
2015-05-01 06:40:06 +05:30
|
|
|
enum_def: &'a EnumDef,
|
2015-04-10 19:00:38 +02:00
|
|
|
type_attrs: &[ast::Attribute],
|
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-07-19 23:02:06 +05:30
|
|
|
field_tys.extend(variant.node
|
|
|
|
.data
|
|
|
|
.fields()
|
|
|
|
.iter()
|
2016-04-06 11:19:10 +03:00
|
|
|
.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| {
|
|
|
|
let (explicit_self, self_args, nonself_args, tys) =
|
|
|
|
method_def.split_self_nonself_args(cx, self, type_ident, generics);
|
|
|
|
|
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,
|
|
|
|
&self_args[..],
|
|
|
|
&nonself_args[..])
|
|
|
|
} else {
|
|
|
|
method_def.expand_enum_method_body(cx,
|
|
|
|
self,
|
|
|
|
enum_def,
|
|
|
|
type_attrs,
|
|
|
|
type_ident,
|
|
|
|
self_args,
|
|
|
|
&nonself_args[..])
|
|
|
|
};
|
|
|
|
|
|
|
|
method_def.create_method(cx,
|
|
|
|
self,
|
|
|
|
type_ident,
|
|
|
|
generics,
|
|
|
|
Abi::Rust,
|
|
|
|
explicit_self,
|
|
|
|
tys,
|
|
|
|
body)
|
|
|
|
})
|
|
|
|
.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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-09 19:49:18 +08:00
|
|
|
fn find_repr_type_name(sess: &ParseSess, type_attrs: &[ast::Attribute]) -> &'static str {
|
2016-03-03 14:55:24 -05:00
|
|
|
let mut repr_type_name = "isize";
|
2015-04-10 19:00:38 +02:00
|
|
|
for a in type_attrs {
|
2018-10-09 19:49:18 +08:00
|
|
|
for r in &attr::find_repr_attrs(sess, a) {
|
2015-04-10 19:00:38 +02:00
|
|
|
repr_type_name = match *r {
|
2018-02-04 22:10:28 +11:00
|
|
|
attr::ReprPacked(_) | attr::ReprSimd | attr::ReprAlign(_) | attr::ReprTransparent =>
|
2018-01-03 17:43:30 +01:00
|
|
|
continue,
|
|
|
|
|
2018-01-07 22:05:32 +01:00
|
|
|
attr::ReprC => "i32",
|
2015-04-10 19:00:38 +02:00
|
|
|
|
2018-01-04 03:12:04 +02:00
|
|
|
attr::ReprInt(attr::SignedInt(ast::IntTy::Isize)) => "isize",
|
2016-08-31 14:00:29 +03:00
|
|
|
attr::ReprInt(attr::SignedInt(ast::IntTy::I8)) => "i8",
|
|
|
|
attr::ReprInt(attr::SignedInt(ast::IntTy::I16)) => "i16",
|
|
|
|
attr::ReprInt(attr::SignedInt(ast::IntTy::I32)) => "i32",
|
|
|
|
attr::ReprInt(attr::SignedInt(ast::IntTy::I64)) => "i64",
|
2016-08-23 03:56:52 +03:00
|
|
|
attr::ReprInt(attr::SignedInt(ast::IntTy::I128)) => "i128",
|
2016-08-31 14:00:29 +03:00
|
|
|
|
2018-01-04 03:12:04 +02:00
|
|
|
attr::ReprInt(attr::UnsignedInt(ast::UintTy::Usize)) => "usize",
|
2016-08-31 14:00:29 +03:00
|
|
|
attr::ReprInt(attr::UnsignedInt(ast::UintTy::U8)) => "u8",
|
|
|
|
attr::ReprInt(attr::UnsignedInt(ast::UintTy::U16)) => "u16",
|
|
|
|
attr::ReprInt(attr::UnsignedInt(ast::UintTy::U32)) => "u32",
|
2016-09-27 19:06:44 +03:00
|
|
|
attr::ReprInt(attr::UnsignedInt(ast::UintTy::U64)) => "u64",
|
2016-08-23 03:56:52 +03:00
|
|
|
attr::ReprInt(attr::UnsignedInt(ast::UintTy::U128)) => "u128",
|
2015-04-10 19:00:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
repr_type_name
|
|
|
|
}
|
|
|
|
|
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,
|
2014-02-08 19:39:53 -05:00
|
|
|
cx: &mut ExtCtxt,
|
2013-12-07 11:57:44 +11:00
|
|
|
trait_: &TraitDef,
|
2013-09-02 02:50:59 +02:00
|
|
|
type_ident: Ident,
|
2014-09-13 19:06:01 +03:00
|
|
|
self_args: &[P<Expr>],
|
|
|
|
nonself_args: &[P<Expr>],
|
2013-03-28 21:50:10 +11:00
|
|
|
fields: &SubstructureFields)
|
2016-07-19 23:02:06 +05:30
|
|
|
-> P<Expr> {
|
2013-03-28 21:50:10 +11:00
|
|
|
let substructure = Substructure {
|
2017-08-06 22:54:09 -07:00
|
|
|
type_ident,
|
2014-02-08 19:39:53 -05:00
|
|
|
method_ident: cx.ident_of(self.name),
|
2017-08-06 22:54:09 -07:00
|
|
|
self_args,
|
|
|
|
nonself_args,
|
|
|
|
fields,
|
2013-03-28 21:50:10 +11:00
|
|
|
};
|
2014-04-21 23:25:18 -07:00
|
|
|
let mut f = self.combine_substructure.borrow_mut();
|
|
|
|
let f: &mut CombineSubstructureFunc = &mut *f;
|
2015-01-06 09:24:46 -08:00
|
|
|
f(cx, trait_.span, &substructure)
|
2013-03-28 21:50:10 +11:00
|
|
|
}
|
|
|
|
|
2014-02-08 19:39:53 -05:00
|
|
|
fn get_ret_ty(&self,
|
|
|
|
cx: &mut ExtCtxt,
|
|
|
|
trait_: &TraitDef,
|
|
|
|
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 {
|
2013-04-30 08:49:48 -07:00
|
|
|
self.explicit_self.is_none()
|
2013-05-07 01:23:51 +10:00
|
|
|
}
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2016-07-19 23:02:06 +05:30
|
|
|
fn split_self_nonself_args
|
|
|
|
(&self,
|
|
|
|
cx: &mut ExtCtxt,
|
|
|
|
trait_: &TraitDef,
|
|
|
|
type_ident: Ident,
|
|
|
|
generics: &Generics)
|
|
|
|
-> (Option<ast::ExplicitSelf>, Vec<P<Expr>>, Vec<P<Expr>>, Vec<(Ident, P<ast::Ty>)>) {
|
2013-05-07 01:23:51 +10:00
|
|
|
|
2014-02-28 13:09:09 -08:00
|
|
|
let mut self_args = Vec::new();
|
|
|
|
let mut nonself_args = Vec::new();
|
|
|
|
let mut arg_tys = Vec::new();
|
2013-05-07 01:23:51 +10:00
|
|
|
let mut nonstatic = false;
|
|
|
|
|
2016-03-06 15:54:44 +03:00
|
|
|
let ast_explicit_self = self.explicit_self.as_ref().map(|self_ptr| {
|
|
|
|
let (self_expr, explicit_self) = ty::get_explicit_self(cx, trait_.span, self_ptr);
|
2013-05-07 01:23:51 +10:00
|
|
|
|
2016-03-06 15:54:44 +03:00
|
|
|
self_args.push(self_expr);
|
|
|
|
nonstatic = true;
|
2013-04-30 08:49:48 -07:00
|
|
|
|
2016-03-06 15:54:44 +03:00
|
|
|
explicit_self
|
|
|
|
});
|
2013-05-07 01:23:51 +10:00
|
|
|
|
2018-04-15 20:51:10 +01:00
|
|
|
for (ty, name) in self.args.iter() {
|
2014-02-08 19:39:53 -05:00
|
|
|
let ast_ty = ty.to_ty(cx, trait_.span, type_ident, generics);
|
2018-04-15 20:51:10 +01:00
|
|
|
let ident = cx.ident_of(name).gensym();
|
2013-05-07 01:23:51 +10:00
|
|
|
arg_tys.push((ident, ast_ty));
|
|
|
|
|
2014-02-08 19:39:53 -05:00
|
|
|
let arg_expr = cx.expr_ident(trait_.span, ident);
|
2013-05-07 01:23:51 +10:00
|
|
|
|
|
|
|
match *ty {
|
|
|
|
// for static methods, just treat any Self
|
|
|
|
// arguments as a normal arg
|
2016-07-19 23:02:06 +05:30
|
|
|
Self_ if nonstatic => {
|
2013-05-07 01:23:51 +10:00
|
|
|
self_args.push(arg_expr);
|
|
|
|
}
|
2018-03-21 01:58:25 +03:00
|
|
|
Ptr(ref ty, _) if (if let Self_ = **ty { true } else { false }) && nonstatic => {
|
2014-02-08 19:39:53 -05:00
|
|
|
self_args.push(cx.expr_deref(trait_.span, arg_expr))
|
2013-05-07 01:23:51 +10:00
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
nonself_args.push(arg_expr);
|
|
|
|
}
|
2013-03-28 21:50:10 +11:00
|
|
|
}
|
|
|
|
}
|
2013-05-07 01:23:51 +10:00
|
|
|
|
2013-04-30 08:49:48 -07:00
|
|
|
(ast_explicit_self, self_args, nonself_args, arg_tys)
|
2013-03-28 21:50:10 +11:00
|
|
|
}
|
|
|
|
|
2014-02-08 19:39:53 -05:00
|
|
|
fn create_method(&self,
|
|
|
|
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,
|
2014-05-28 22:26:56 -07:00
|
|
|
abi: Abi,
|
2016-03-06 15:54:44 +03:00
|
|
|
explicit_self: Option<ast::ExplicitSelf>,
|
2016-07-19 23:02:06 +05:30
|
|
|
arg_types: Vec<(Ident, P<ast::Ty>)>,
|
|
|
|
body: P<Expr>)
|
|
|
|
-> ast::ImplItem {
|
shallow Clone for #[derive(Copy,Clone)]
Changes #[derive(Copy, Clone)] to use a faster impl of Clone when
both derives are present, and there are no generics in the type.
The faster impl is simply returning *self (which works because the
type is also Copy). See the comments in libsyntax_ext/deriving/clone.rs
for more details.
There are a few types which are Copy but not Clone, in violation
of the definition of Copy. These include large arrays and tuples. The
very existence of these types is arguably a bug, but in order for this
optimization not to change the applicability of #[derive(Copy, Clone)],
the faster Clone impl also injects calls to a new function,
core::clone::assert_receiver_is_clone, to verify that all members are
actually Clone.
This is not a breaking change, because pursuant to RFC 1521, any type
that implements Copy should not do any observable work in its Clone
impl.
2016-02-03 19:40:59 -05:00
|
|
|
|
2013-05-07 01:23:51 +10:00
|
|
|
// create the generics that aren't for Self
|
2014-02-08 19:39:53 -05:00
|
|
|
let fn_generics = self.generics.to_generics(cx, trait_.span, type_ident, generics);
|
2013-05-07 01:23:51 +10:00
|
|
|
|
2014-02-09 07:37:33 -05:00
|
|
|
let args = {
|
2016-03-06 15:54:44 +03:00
|
|
|
let self_args = explicit_self.map(|explicit_self| {
|
2016-07-19 23:02:06 +05:30
|
|
|
ast::Arg::from_self(explicit_self,
|
2018-03-18 16:47:09 +03:00
|
|
|
keywords::SelfValue.ident().with_span_pos(trait_.span))
|
2016-03-06 15:54:44 +03:00
|
|
|
});
|
|
|
|
let nonself_args = arg_types.into_iter()
|
2016-07-19 23:02:06 +05:30
|
|
|
.map(|(name, ty)| cx.arg(trait_.span, name, ty));
|
2016-03-06 15:54:44 +03:00
|
|
|
self_args.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
|
|
|
|
2014-02-08 19:39:53 -05:00
|
|
|
let method_ident = cx.ident_of(self.name);
|
2018-03-22 15:55:57 +00:00
|
|
|
let fn_decl = cx.fn_decl(args, ast::FunctionRetTy::Ty(ret_type));
|
2014-02-08 19:39:53 -05:00
|
|
|
let body_block = cx.block_expr(body);
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2015-05-17 11:28:19 +05:30
|
|
|
let unsafety = if self.is_unsafe {
|
|
|
|
ast::Unsafety::Unsafe
|
|
|
|
} else {
|
|
|
|
ast::Unsafety::Normal
|
|
|
|
};
|
|
|
|
|
2013-03-28 21:50:10 +11:00
|
|
|
// Create the method.
|
2016-02-11 23:33:09 +03:00
|
|
|
ast::ImplItem {
|
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(),
|
2017-09-21 22:18:47 -04:00
|
|
|
generics: fn_generics,
|
2013-12-07 11:57:44 +11:00
|
|
|
span: trait_.span,
|
2018-03-10 17:45:47 +03:00
|
|
|
vis: respan(trait_.span.shrink_to_lo(), ast::VisibilityKind::Inherited),
|
2015-12-18 14:38:28 -08:00
|
|
|
defaultness: ast::Defaultness::Final,
|
2015-03-10 12:28:44 +02:00
|
|
|
ident: method_ident,
|
2015-11-13 14:15:04 +01:00
|
|
|
node: ast::ImplItemKind::Method(ast::MethodSig {
|
2018-05-16 22:55:18 -07:00
|
|
|
header: ast::FnHeader {
|
|
|
|
unsafety, abi,
|
|
|
|
..ast::FnHeader::default()
|
|
|
|
},
|
2016-07-19 23:02:06 +05:30
|
|
|
decl: fn_decl,
|
|
|
|
},
|
|
|
|
body_block),
|
2017-07-12 09:50:05 -07:00
|
|
|
tokens: None,
|
2016-02-11 23:33:09 +03:00
|
|
|
}
|
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;
|
2015-01-17 23:55:21 +00:00
|
|
|
/// struct A { x: i32, y: i32 }
|
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 {
|
2014-09-16 13:27:34 +02:00
|
|
|
/// match *self {
|
2016-03-17 00:43:36 +05:30
|
|
|
/// A {x: ref __self_0_0, y: ref __self_0_1} => {
|
2018-04-19 20:17:06 +01:00
|
|
|
/// match *other {
|
2016-03-17 00:43:36 +05:30
|
|
|
/// A {x: ref __self_1_0, y: ref __self_1_1} => {
|
|
|
|
/// __self_0_0.eq(__self_1_0) && __self_0_1.eq(__self_1_1)
|
2014-09-16 13:27:34 +02:00
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// }
|
2017-10-02 15:15:23 +02:00
|
|
|
///
|
|
|
|
/// // or if A is repr(packed) - note fields are matched by-value
|
|
|
|
/// // instead of by-reference.
|
|
|
|
/// impl PartialEq for A {
|
2018-04-19 20:17:06 +01:00
|
|
|
/// fn eq(&self, other: &A) -> bool {
|
2017-10-02 15:15:23 +02:00
|
|
|
/// match *self {
|
|
|
|
/// A {x: __self_0_0, y: __self_0_1} => {
|
2018-04-19 20:17:06 +01:00
|
|
|
/// match other {
|
2017-10-02 15:15:23 +02:00
|
|
|
/// A {x: __self_1_0, y: __self_1_1} => {
|
|
|
|
/// __self_0_0.eq(&__self_1_0) && __self_0_1.eq(&__self_1_1)
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// }
|
2014-09-16 13:27:34 +02:00
|
|
|
/// ```
|
2015-05-01 06:40:06 +05:30
|
|
|
fn expand_struct_method_body<'b>(&self,
|
2016-07-19 23:02:06 +05:30
|
|
|
cx: &mut ExtCtxt,
|
|
|
|
trait_: &TraitDef<'b>,
|
|
|
|
struct_def: &'b VariantData,
|
|
|
|
type_ident: Ident,
|
|
|
|
self_args: &[P<Expr>],
|
2017-10-02 15:15:23 +02:00
|
|
|
nonself_args: &[P<Expr>],
|
|
|
|
use_temporaries: bool)
|
2016-07-19 23:02:06 +05:30
|
|
|
-> P<Expr> {
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2015-05-02 16:25:49 -04:00
|
|
|
let mut raw_fields = Vec::new(); // Vec<[fields of self],
|
|
|
|
// [fields of next Self arg], [etc]>
|
2014-02-28 13:09:09 -08:00
|
|
|
let mut patterns = Vec::new();
|
2015-01-28 01:01:48 +00:00
|
|
|
for i in 0..self_args.len() {
|
2016-07-19 23:02:06 +05:30
|
|
|
let struct_path = cx.path(DUMMY_SP, vec![type_ident]);
|
|
|
|
let (pat, ident_expr) = trait_.create_struct_pattern(cx,
|
|
|
|
struct_path,
|
|
|
|
struct_def,
|
|
|
|
&format!("__self_{}", i),
|
2017-10-02 15:15:23 +02:00
|
|
|
ast::Mutability::Immutable,
|
|
|
|
use_temporaries);
|
2013-05-07 01:23:51 +10:00
|
|
|
patterns.push(pat);
|
|
|
|
raw_fields.push(ident_expr);
|
2013-08-01 18:35:46 -04:00
|
|
|
}
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2013-05-07 01:23:51 +10:00
|
|
|
// transpose raw_fields
|
2015-03-24 16:54:09 -07:00
|
|
|
let fields = if !raw_fields.is_empty() {
|
2014-09-14 20:27:36 -07:00
|
|
|
let mut raw_fields = raw_fields.into_iter().map(|v| v.into_iter());
|
2014-09-13 19:06:01 +03:00
|
|
|
let first_field = raw_fields.next().unwrap();
|
2016-07-19 23:02:06 +05:30
|
|
|
let mut other_fields: Vec<vec::IntoIter<_>> = raw_fields.collect();
|
2015-05-01 06:40:06 +05:30
|
|
|
first_field.map(|(span, opt_id, field, attrs)| {
|
2016-07-19 23:02:06 +05:30
|
|
|
FieldInfo {
|
2017-08-06 22:54:09 -07:00
|
|
|
span,
|
2016-07-19 23:02:06 +05:30
|
|
|
name: opt_id,
|
|
|
|
self_: field,
|
|
|
|
other: other_fields.iter_mut()
|
|
|
|
.map(|l| {
|
|
|
|
match l.next().unwrap() {
|
2016-08-26 19:23:42 +03:00
|
|
|
(.., ex, _) => ex,
|
2016-07-19 23:02:06 +05:30
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect(),
|
2017-08-06 22:54:09 -07:00
|
|
|
attrs,
|
2016-07-19 23:02:06 +05:30
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect()
|
2014-02-13 09:46:46 -08:00
|
|
|
} else {
|
|
|
|
cx.span_bug(trait_.span,
|
|
|
|
"no self arguments to non-static method in generic \
|
2014-12-31 17:25:18 +13:00
|
|
|
`derive`")
|
2013-05-07 01:23:51 +10:00
|
|
|
};
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2013-05-07 01:23:51 +10:00
|
|
|
// body of the inner most destructuring match
|
2016-07-19 23:02:06 +05:30
|
|
|
let mut body = self.call_substructure_method(cx,
|
|
|
|
trait_,
|
|
|
|
type_ident,
|
|
|
|
self_args,
|
|
|
|
nonself_args,
|
|
|
|
&Struct(struct_def, fields));
|
2013-05-07 01:23:51 +10:00
|
|
|
|
|
|
|
// make a series of nested matches, to destructure the
|
2014-06-09 00:00:52 -04:00
|
|
|
// structs. This is actually right-to-left, but it shouldn't
|
2013-05-07 01:23:51 +10:00
|
|
|
// matter.
|
2015-06-10 17:22:20 +01:00
|
|
|
for (arg_expr, pat) in self_args.iter().zip(patterns) {
|
2016-07-19 23:02:06 +05:30
|
|
|
body = cx.expr_match(trait_.span,
|
|
|
|
arg_expr.clone(),
|
|
|
|
vec![cx.arm(trait_.span, vec![pat.clone()], body)])
|
2013-03-28 21:50:10 +11:00
|
|
|
}
|
shallow Clone for #[derive(Copy,Clone)]
Changes #[derive(Copy, Clone)] to use a faster impl of Clone when
both derives are present, and there are no generics in the type.
The faster impl is simply returning *self (which works because the
type is also Copy). See the comments in libsyntax_ext/deriving/clone.rs
for more details.
There are a few types which are Copy but not Clone, in violation
of the definition of Copy. These include large arrays and tuples. The
very existence of these types is arguably a bug, but in order for this
optimization not to change the applicability of #[derive(Copy, Clone)],
the faster Clone impl also injects calls to a new function,
core::clone::assert_receiver_is_clone, to verify that all members are
actually Clone.
This is not a breaking change, because pursuant to RFC 1521, any type
that implements Copy should not do any observable work in its Clone
impl.
2016-02-03 19:40:59 -05:00
|
|
|
|
2013-05-07 01:23:51 +10:00
|
|
|
body
|
2013-03-28 21:50:10 +11:00
|
|
|
}
|
|
|
|
|
2013-05-07 01:23:51 +10:00
|
|
|
fn expand_static_struct_method_body(&self,
|
2014-02-08 19:39:53 -05:00
|
|
|
cx: &mut ExtCtxt,
|
2013-12-07 11:57:44 +11:00
|
|
|
trait_: &TraitDef,
|
2015-10-08 03:20:57 +03:00
|
|
|
struct_def: &VariantData,
|
2013-09-02 02:50:59 +02:00
|
|
|
type_ident: Ident,
|
2014-09-13 19:06:01 +03:00
|
|
|
self_args: &[P<Expr>],
|
|
|
|
nonself_args: &[P<Expr>])
|
2016-07-19 23:02:06 +05:30
|
|
|
-> P<Expr> {
|
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,
|
2016-07-19 23:02:06 +05:30
|
|
|
self_args,
|
|
|
|
nonself_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
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// // is equivalent to
|
|
|
|
///
|
|
|
|
/// impl PartialEq for A {
|
2018-04-19 20:17:06 +01:00
|
|
|
/// fn eq(&self, other: &A) -> ::bool {
|
|
|
|
/// match (&*self, &*other) {
|
2014-09-16 13:27:34 +02:00
|
|
|
/// (&A1, &A1) => true,
|
2016-03-07 19:07:06 -05:00
|
|
|
/// (&A2(ref self_0),
|
2016-03-17 00:43:36 +05:30
|
|
|
/// &A2(ref __arg_1_0)) => (*self_0).eq(&(*__arg_1_0)),
|
2014-09-16 13:27:34 +02:00
|
|
|
/// _ => {
|
2016-03-17 00:43:36 +05:30
|
|
|
/// let __self_vi = match *self { A1(..) => 0, A2(..) => 1 };
|
2018-04-19 20:17:06 +01:00
|
|
|
/// let __arg_1_vi = match *other { A1(..) => 0, A2(..) => 1 };
|
2014-09-16 13:27:34 +02:00
|
|
|
/// false
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
///
|
2016-03-17 00:43:36 +05:30
|
|
|
/// (Of course `__self_vi` and `__arg_1_vi` are unused for
|
2014-09-16 13:27:34 +02:00
|
|
|
/// `PartialEq`, and those subcomputations will hopefully be removed
|
2016-03-17 00:43:36 +05:30
|
|
|
/// as their results are unused. The point of `__self_vi` and
|
|
|
|
/// `__arg_1_vi` is for `PartialOrd`; see #15503.)
|
2015-05-01 06:40:06 +05:30
|
|
|
fn expand_enum_method_body<'b>(&self,
|
2016-07-19 23:02:06 +05:30
|
|
|
cx: &mut ExtCtxt,
|
|
|
|
trait_: &TraitDef<'b>,
|
|
|
|
enum_def: &'b EnumDef,
|
|
|
|
type_attrs: &[ast::Attribute],
|
|
|
|
type_ident: Ident,
|
|
|
|
self_args: Vec<P<Expr>>,
|
|
|
|
nonself_args: &[P<Expr>])
|
|
|
|
-> P<Expr> {
|
|
|
|
self.build_enum_match_tuple(cx,
|
|
|
|
trait_,
|
|
|
|
enum_def,
|
|
|
|
type_attrs,
|
|
|
|
type_ident,
|
|
|
|
self_args,
|
|
|
|
nonself_args)
|
2013-03-28 21:50:10 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-09-16 13:27:34 +02:00
|
|
|
/// Creates a match for a tuple of all `self_args`, where either all
|
|
|
|
/// variants match, or it falls into a catch-all for when one variant
|
|
|
|
/// does not match.
|
|
|
|
|
|
|
|
/// 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.
|
|
|
|
|
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).
|
|
|
|
|
2014-09-16 13:27:34 +02:00
|
|
|
/// The catch-all handler is provided access the variant index values
|
2015-06-14 18:24:52 +02:00
|
|
|
/// for each of the self-args, carried in precomputed variables.
|
2014-09-16 13:27:34 +02:00
|
|
|
|
|
|
|
/// ```{.text}
|
2016-03-17 00:43:36 +05:30
|
|
|
/// let __self0_vi = unsafe {
|
2015-06-12 09:41:06 +02:00
|
|
|
/// std::intrinsics::discriminant_value(&self) } as i32;
|
2016-03-17 00:43:36 +05:30
|
|
|
/// let __self1_vi = unsafe {
|
2016-03-07 19:07:06 -05:00
|
|
|
/// std::intrinsics::discriminant_value(&arg1) } as i32;
|
2016-03-17 00:43:36 +05:30
|
|
|
/// let __self2_vi = unsafe {
|
2016-03-07 19:07:06 -05:00
|
|
|
/// std::intrinsics::discriminant_value(&arg2) } as i32;
|
2015-06-12 09:41:06 +02:00
|
|
|
///
|
2016-03-17 00:43:36 +05:30
|
|
|
/// if __self0_vi == __self1_vi && __self0_vi == __self2_vi && ... {
|
2015-06-12 09:41:06 +02:00
|
|
|
/// match (...) {
|
|
|
|
/// (Variant1, Variant1, ...) => Body1
|
|
|
|
/// (Variant2, Variant2, ...) => Body2,
|
|
|
|
/// ...
|
|
|
|
/// _ => ::core::intrinsics::unreachable()
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// else {
|
2014-09-16 13:27:34 +02:00
|
|
|
/// ... // catch-all remainder can inspect above variant index values.
|
|
|
|
/// }
|
|
|
|
/// ```
|
2016-07-19 23:02:06 +05:30
|
|
|
fn build_enum_match_tuple<'b>(&self,
|
|
|
|
cx: &mut ExtCtxt,
|
|
|
|
trait_: &TraitDef<'b>,
|
|
|
|
enum_def: &'b EnumDef,
|
|
|
|
type_attrs: &[ast::Attribute],
|
|
|
|
type_ident: Ident,
|
|
|
|
self_args: Vec<P<Expr>>,
|
|
|
|
nonself_args: &[P<Expr>])
|
|
|
|
-> P<Expr> {
|
2014-07-06 21:19:12 +02:00
|
|
|
let sp = trait_.span;
|
|
|
|
let variants = &enum_def.variants;
|
|
|
|
|
2016-07-19 23:02:06 +05:30
|
|
|
let self_arg_names = self_args.iter()
|
|
|
|
.enumerate()
|
2014-07-06 21:19:12 +02:00
|
|
|
.map(|(arg_count, _self_arg)| {
|
|
|
|
if arg_count == 0 {
|
2016-03-17 00:43:36 +05:30
|
|
|
"__self".to_string()
|
2014-07-06 21:19:12 +02:00
|
|
|
} else {
|
2016-03-17 00:43:36 +05:30
|
|
|
format!("__arg_{}", arg_count)
|
2014-07-06 21:19:12 +02:00
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect::<Vec<String>>();
|
|
|
|
|
|
|
|
let self_arg_idents = self_arg_names.iter()
|
2016-07-19 23:02:06 +05:30
|
|
|
.map(|name| cx.ident_of(&name[..]))
|
2014-07-06 21:19:12 +02:00
|
|
|
.collect::<Vec<ast::Ident>>();
|
|
|
|
|
|
|
|
// The `vi_idents` will be bound, solely in the catch-all, to
|
2015-04-10 19:13:34 +02:00
|
|
|
// a series of let statements mapping each self_arg to an int
|
|
|
|
// value corresponding to its discriminant.
|
2014-09-13 19:06:01 +03:00
|
|
|
let vi_idents: Vec<ast::Ident> = self_arg_names.iter()
|
2016-07-19 23:02:06 +05:30
|
|
|
.map(|name| {
|
|
|
|
let vi_suffix = format!("{}_vi", &name[..]);
|
2018-04-19 19:04:06 +01:00
|
|
|
cx.ident_of(&vi_suffix[..]).gensym()
|
2016-07-19 23:02:06 +05:30
|
|
|
})
|
2014-07-06 21:19:12 +02:00
|
|
|
.collect::<Vec<ast::Ident>>();
|
|
|
|
|
|
|
|
// Builds, via callback to call_substructure_method, the
|
|
|
|
// delegated expression that handles the catch-all case,
|
|
|
|
// using `__variants_tuple` to drive logic if necessary.
|
2016-07-19 23:02:06 +05:30
|
|
|
let catch_all_substructure =
|
|
|
|
EnumNonMatchingCollapsed(self_arg_idents, &variants[..], &vi_idents[..]);
|
2014-07-06 21:19:12 +02:00
|
|
|
|
2016-05-12 17:54:05 +02:00
|
|
|
let first_fieldless = variants.iter().find(|v| v.node.data.fields().is_empty());
|
|
|
|
|
2014-07-06 21:19:12 +02:00
|
|
|
// These arms are of the form:
|
|
|
|
// (Variant1, Variant1, ...) => Body1
|
|
|
|
// (Variant2, Variant2, ...) => Body2
|
|
|
|
// ...
|
|
|
|
// where each tuple has length = self_args.len()
|
2016-07-19 23:02:06 +05:30
|
|
|
let mut match_arms: Vec<ast::Arm> = variants.iter()
|
|
|
|
.enumerate()
|
2016-05-12 17:54:05 +02:00
|
|
|
.filter(|&(_, v)| !(self.unify_fieldless_variants && v.node.data.fields().is_empty()))
|
2014-09-13 19:06:01 +03:00
|
|
|
.map(|(index, variant)| {
|
2015-02-01 12:44:15 -05:00
|
|
|
let mk_self_pat = |cx: &mut ExtCtxt, self_arg_name: &str| {
|
2016-07-19 23:02:06 +05:30
|
|
|
let (p, idents) = trait_.create_enum_variant_pattern(cx,
|
|
|
|
type_ident,
|
|
|
|
variant,
|
|
|
|
self_arg_name,
|
|
|
|
ast::Mutability::Immutable);
|
2016-02-11 21:16:33 +03:00
|
|
|
(cx.pat(sp, PatKind::Ref(p, ast::Mutability::Immutable)), idents)
|
2014-09-13 19:06:01 +03:00
|
|
|
};
|
2014-07-06 21:19:12 +02:00
|
|
|
|
|
|
|
// A single arm has form (&VariantK, &VariantK, ...) => BodyK
|
|
|
|
// (see "Final wrinkle" note below for why.)
|
2014-09-13 19:06:01 +03:00
|
|
|
let mut subpats = Vec::with_capacity(self_arg_names.len());
|
|
|
|
let mut self_pats_idents = Vec::with_capacity(self_arg_names.len() - 1);
|
|
|
|
let first_self_pat_idents = {
|
2015-02-20 14:08:14 -05:00
|
|
|
let (p, idents) = mk_self_pat(cx, &self_arg_names[0]);
|
2014-09-13 19:06:01 +03:00
|
|
|
subpats.push(p);
|
|
|
|
idents
|
|
|
|
};
|
2015-04-16 21:21:26 -07:00
|
|
|
for self_arg_name in &self_arg_names[1..] {
|
2015-02-18 14:48:57 -05:00
|
|
|
let (p, idents) = mk_self_pat(cx, &self_arg_name[..]);
|
2014-09-13 19:06:01 +03:00
|
|
|
subpats.push(p);
|
|
|
|
self_pats_idents.push(idents);
|
|
|
|
}
|
2014-07-06 21:19:12 +02:00
|
|
|
|
|
|
|
// Here is the pat = `(&VariantK, &VariantK, ...)`
|
2014-11-09 16:14:15 +01:00
|
|
|
let single_pat = cx.pat_tuple(sp, 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.
|
|
|
|
|
|
|
|
// All of the Self args have the same variant in these
|
2014-09-13 19:06:01 +03:00
|
|
|
// cases. So we transpose the info in self_pats_idents
|
|
|
|
// to gather the getter expressions together, in the
|
|
|
|
// form that EnumMatching expects.
|
2014-07-06 21:19:12 +02:00
|
|
|
|
|
|
|
// The transposition is driven by walking across the
|
|
|
|
// arg fields of the variant for the first self pat.
|
2014-09-14 20:27:36 -07:00
|
|
|
let field_tuples = first_self_pat_idents.into_iter().enumerate()
|
2014-07-06 21:19:12 +02:00
|
|
|
// For each arg field of self, pull out its getter expr ...
|
2015-05-01 06:40:06 +05:30
|
|
|
.map(|(field_index, (sp, opt_ident, self_getter_expr, attrs))| {
|
2014-07-06 21:19:12 +02:00
|
|
|
// ... but FieldInfo also wants getter expr
|
|
|
|
// for matching other arguments of Self type;
|
2014-09-13 19:06:01 +03:00
|
|
|
// so walk across the *other* self_pats_idents
|
|
|
|
// and pull out getter for same field in each
|
|
|
|
// of them (using `field_index` tracked above).
|
2014-07-06 21:19:12 +02:00
|
|
|
// That is the heart of the transposition.
|
2014-09-13 19:06:01 +03:00
|
|
|
let others = self_pats_idents.iter().map(|fields| {
|
2015-05-01 06:40:06 +05:30
|
|
|
let (_, _opt_ident, ref other_getter_expr, _) =
|
2014-10-14 23:05:01 -07:00
|
|
|
fields[field_index];
|
2014-07-06 21:19:12 +02:00
|
|
|
|
2014-09-13 19:06:01 +03:00
|
|
|
// All Self args have same variant, so
|
|
|
|
// opt_idents are the same. (Assert
|
|
|
|
// here to make it self-evident that
|
|
|
|
// it is okay to ignore `_opt_ident`.)
|
|
|
|
assert!(opt_ident == _opt_ident);
|
2014-07-06 21:19:12 +02:00
|
|
|
|
2014-09-13 19:06:01 +03:00
|
|
|
other_getter_expr.clone()
|
|
|
|
}).collect::<Vec<P<Expr>>>();
|
2014-07-06 21:19:12 +02:00
|
|
|
|
|
|
|
FieldInfo { span: sp,
|
|
|
|
name: opt_ident,
|
|
|
|
self_: self_getter_expr,
|
|
|
|
other: others,
|
2017-08-06 22:54:09 -07:00
|
|
|
attrs,
|
2014-07-06 21:19:12 +02:00
|
|
|
}
|
|
|
|
}).collect::<Vec<FieldInfo>>();
|
|
|
|
|
|
|
|
// 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.
|
2017-06-16 22:59:20 +03:00
|
|
|
let substructure = EnumMatching(index, variants.len(), variant, field_tuples);
|
2016-07-19 23:02:06 +05:30
|
|
|
let arm_expr = self.call_substructure_method(cx,
|
|
|
|
trait_,
|
|
|
|
type_ident,
|
|
|
|
&self_args[..],
|
|
|
|
nonself_args,
|
|
|
|
&substructure);
|
2014-07-06 21:19:12 +02:00
|
|
|
|
|
|
|
cx.arm(sp, vec![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());
|
2016-07-19 23:02:06 +05:30
|
|
|
Some(self.call_substructure_method(cx,
|
|
|
|
trait_,
|
|
|
|
type_ident,
|
|
|
|
&self_args[..],
|
|
|
|
nonself_args,
|
2017-06-16 22:59:20 +03:00
|
|
|
&substructure))
|
2016-05-12 17:54:05 +02:00
|
|
|
}
|
|
|
|
_ if variants.len() > 1 && self_args.len() > 1 => {
|
|
|
|
// 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
|
|
|
|
Some(deriving::call_intrinsic(cx, sp, "unreachable", vec![]))
|
|
|
|
}
|
2016-07-19 23:02:06 +05:30
|
|
|
_ => None,
|
2016-05-12 17:54:05 +02:00
|
|
|
};
|
|
|
|
if let Some(arm) = default {
|
|
|
|
match_arms.push(cx.arm(sp, vec![cx.pat_wild(sp)], arm));
|
|
|
|
}
|
|
|
|
|
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.
|
|
|
|
//
|
|
|
|
if variants.len() > 1 && self_args.len() > 1 {
|
|
|
|
// Build a series of let statements mapping each self_arg
|
2015-04-10 16:15:12 +02:00
|
|
|
// to its discriminant value. If this is a C-style enum
|
|
|
|
// with a specific repr type, then casts the values to
|
2015-04-10 19:13:34 +02:00
|
|
|
// that type. Otherwise casts to `i32` (the default repr
|
|
|
|
// type).
|
2015-04-10 16:15:12 +02:00
|
|
|
//
|
2014-07-06 21:19:12 +02:00
|
|
|
// i.e. for `enum E<T> { A, B(1), C(T, T) }`, and a deriving
|
|
|
|
// with three Self args, builds three statements:
|
|
|
|
//
|
|
|
|
// ```
|
2016-03-17 00:43:36 +05:30
|
|
|
// let __self0_vi = unsafe {
|
2015-04-10 19:13:34 +02:00
|
|
|
// std::intrinsics::discriminant_value(&self) } as i32;
|
2016-03-17 00:43:36 +05:30
|
|
|
// let __self1_vi = unsafe {
|
2016-03-07 19:07:06 -05:00
|
|
|
// std::intrinsics::discriminant_value(&arg1) } as i32;
|
2016-03-17 00:43:36 +05:30
|
|
|
// let __self2_vi = unsafe {
|
2016-03-07 19:07:06 -05:00
|
|
|
// std::intrinsics::discriminant_value(&arg2) } as i32;
|
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
|
|
|
|
2016-07-19 23:02:06 +05:30
|
|
|
// We also build an expression which checks whether all discriminants are equal
|
2016-03-17 00:43:36 +05:30
|
|
|
// discriminant_test = __self0_vi == __self1_vi && __self0_vi == __self2_vi && ...
|
2015-06-12 09:41:06 +02:00
|
|
|
let mut discriminant_test = cx.expr_bool(sp, true);
|
|
|
|
|
2018-10-09 19:49:18 +08:00
|
|
|
let target_type_name = find_repr_type_name(&cx.parse_sess, type_attrs);
|
2015-04-10 19:00:38 +02:00
|
|
|
|
2015-06-12 09:41:06 +02:00
|
|
|
let mut first_ident = None;
|
2015-06-10 17:22:20 +01:00
|
|
|
for (&ident, self_arg) in vi_idents.iter().zip(&self_args) {
|
2016-03-10 00:31:19 -05:00
|
|
|
let self_addr = cx.expr_addr_of(sp, self_arg.clone());
|
2016-07-19 23:02:06 +05:30
|
|
|
let variant_value =
|
|
|
|
deriving::call_intrinsic(cx, sp, "discriminant_value", vec![self_addr]);
|
2015-04-10 16:15:12 +02:00
|
|
|
|
2015-04-10 19:00:38 +02:00
|
|
|
let target_ty = cx.ty_ident(sp, cx.ident_of(target_type_name));
|
2015-04-10 16:15:12 +02:00
|
|
|
let variant_disr = cx.expr_cast(sp, variant_value, target_ty);
|
|
|
|
let let_stmt = cx.stmt_let(sp, false, ident, variant_disr);
|
2014-07-06 21:19:12 +02:00
|
|
|
index_let_stmts.push(let_stmt);
|
2015-06-12 09:41:06 +02:00
|
|
|
|
|
|
|
match first_ident {
|
|
|
|
Some(first) => {
|
|
|
|
let first_expr = cx.expr_ident(sp, first);
|
|
|
|
let id = cx.expr_ident(sp, ident);
|
2016-02-08 13:16:12 +01:00
|
|
|
let test = cx.expr_binary(sp, BinOpKind::Eq, first_expr, id);
|
2016-07-19 23:02:06 +05:30
|
|
|
discriminant_test =
|
|
|
|
cx.expr_binary(sp, BinOpKind::And, discriminant_test, test)
|
2015-06-12 09:41:06 +02:00
|
|
|
}
|
|
|
|
None => {
|
|
|
|
first_ident = Some(ident);
|
|
|
|
}
|
|
|
|
}
|
2014-07-06 21:19:12 +02:00
|
|
|
}
|
|
|
|
|
2016-07-19 23:02:06 +05:30
|
|
|
let arm_expr = self.call_substructure_method(cx,
|
|
|
|
trait_,
|
|
|
|
type_ident,
|
|
|
|
&self_args[..],
|
|
|
|
nonself_args,
|
|
|
|
&catch_all_substructure);
|
2014-07-06 21:19:12 +02:00
|
|
|
|
2015-06-12 09:41:06 +02:00
|
|
|
// Final wrinkle: the self_args are expressions that deref
|
2018-01-29 01:49:29 +02:00
|
|
|
// down to desired places, but we cannot actually deref
|
2015-06-12 09:41:06 +02:00
|
|
|
// them when they are fed as r-values into a tuple
|
|
|
|
// expression; here add a layer of borrowing, turning
|
2016-03-17 00:43:36 +05:30
|
|
|
// `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
|
2015-06-12 09:41:06 +02:00
|
|
|
let borrowed_self_args = self_args.move_map(|self_arg| cx.expr_addr_of(sp, self_arg));
|
2016-02-08 16:05:05 +01:00
|
|
|
let match_arg = cx.expr(sp, ast::ExprKind::Tup(borrowed_self_args));
|
2015-06-12 09:41:06 +02:00
|
|
|
|
2016-07-19 23:02:06 +05:30
|
|
|
// Lastly we create an expression which branches on all discriminants being equal
|
2015-06-12 09:41:06 +02:00
|
|
|
// if discriminant_test {
|
|
|
|
// match (...) {
|
|
|
|
// (Variant1, Variant1, ...) => Body1
|
|
|
|
// (Variant2, Variant2, ...) => Body2,
|
|
|
|
// ...
|
|
|
|
// _ => ::core::intrinsics::unreachable()
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// else {
|
2016-03-17 00:43:36 +05:30
|
|
|
// <delegated expression referring to __self0_vi, et al.>
|
2015-06-12 09:41:06 +02:00
|
|
|
// }
|
|
|
|
let all_match = cx.expr_match(sp, match_arg, match_arms);
|
|
|
|
let arm_expr = cx.expr_if(sp, discriminant_test, all_match, Some(arm_expr));
|
2016-06-23 09:51:18 +00:00
|
|
|
index_let_stmts.push(cx.stmt_expr(arm_expr));
|
2016-06-23 23:26:32 +00:00
|
|
|
cx.expr_block(cx.block(sp, index_let_stmts))
|
2015-03-24 16:53:34 -07:00
|
|
|
} else if variants.is_empty() {
|
2014-07-06 21:19:12 +02:00
|
|
|
// As an additional wrinkle, For a zero-variant enum A,
|
|
|
|
// currently the compiler
|
|
|
|
// will accept `fn (a: &Self) { match *a { } }`
|
|
|
|
// but rejects `fn (a: &Self) { match (&*a,) { } }`
|
|
|
|
// as well as `fn (a: &Self) { match ( *a,) { } }`
|
|
|
|
//
|
|
|
|
// This means that the strategy of building up a tuple of
|
|
|
|
// all Self arguments fails when Self is a zero variant
|
|
|
|
// enum: rustc rejects the expanded program, even though
|
|
|
|
// the actual code tends to be impossible to execute (at
|
|
|
|
// least safely), according to the type system.
|
|
|
|
//
|
|
|
|
// The most expedient fix for this is to just let the
|
|
|
|
// code fall through to the catch-all. But even this is
|
|
|
|
// error-prone, since the catch-all as defined above would
|
|
|
|
// generate code like this:
|
|
|
|
//
|
2016-03-17 00:43:36 +05:30
|
|
|
// _ => { let __self0 = match *self { };
|
|
|
|
// let __self1 = match *__arg_0 { };
|
2014-07-06 21:19:12 +02:00
|
|
|
// <catch-all-expr> }
|
|
|
|
//
|
|
|
|
// Which is yields bindings for variables which type
|
|
|
|
// inference cannot resolve to unique types.
|
|
|
|
//
|
|
|
|
// One option to the above might be to add explicit type
|
|
|
|
// annotations. But the *only* reason to go down that path
|
|
|
|
// would be to try to make the expanded output consistent
|
|
|
|
// with the case when the number of enum variants >= 1.
|
|
|
|
//
|
|
|
|
// That just isn't worth it. In fact, trying to generate
|
|
|
|
// sensible code for *any* deriving on a zero-variant enum
|
|
|
|
// does not make sense. But at the same time, for now, we
|
|
|
|
// do not want to cause a compile failure just because the
|
|
|
|
// user happened to attach a deriving to their
|
|
|
|
// zero-variant enum.
|
|
|
|
//
|
|
|
|
// Instead, just generate a failing expression for the
|
|
|
|
// zero variant case, skipping matches and also skipping
|
|
|
|
// delegating back to the end user code entirely.
|
|
|
|
//
|
|
|
|
// (See also #4499 and #12609; note that some of the
|
|
|
|
// discussions there influence what choice we make here;
|
|
|
|
// e.g. if we feature-gate `match x { ... }` when x refers
|
|
|
|
// to an uninhabited type (e.g. a zero-variant enum or a
|
|
|
|
// type holding such an enum), but do not feature-gate
|
|
|
|
// zero-variant enums themselves, then attempting to
|
2015-01-28 08:34:18 -05:00
|
|
|
// derive Debug on such a type could here generate code
|
2014-07-06 21:19:12 +02:00
|
|
|
// that needs the feature gate enabled.)
|
|
|
|
|
2016-03-10 00:31:19 -05:00
|
|
|
deriving::call_intrinsic(cx, sp, "unreachable", vec![])
|
2016-07-19 23:02:06 +05:30
|
|
|
} else {
|
2015-06-12 09:41:06 +02:00
|
|
|
|
|
|
|
// Final wrinkle: the self_args are expressions that deref
|
2018-01-29 01:49:29 +02:00
|
|
|
// down to desired places, but we cannot actually deref
|
2015-06-12 09:41:06 +02:00
|
|
|
// them when they are fed as r-values into a tuple
|
|
|
|
// expression; here add a layer of borrowing, turning
|
2016-03-17 00:43:36 +05:30
|
|
|
// `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
|
2015-06-12 09:41:06 +02:00
|
|
|
let borrowed_self_args = self_args.move_map(|self_arg| cx.expr_addr_of(sp, self_arg));
|
2016-02-08 16:05:05 +01:00
|
|
|
let match_arg = cx.expr(sp, ast::ExprKind::Tup(borrowed_self_args));
|
2015-06-12 09:41:06 +02:00
|
|
|
cx.expr_match(sp, 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,
|
2014-02-08 19:39:53 -05:00
|
|
|
cx: &mut ExtCtxt,
|
2013-12-07 11:57:44 +11:00
|
|
|
trait_: &TraitDef,
|
2014-01-09 15:05:33 +02:00
|
|
|
enum_def: &EnumDef,
|
2013-11-07 18:49:01 +11:00
|
|
|
type_ident: Ident,
|
2014-09-13 19:06:01 +03:00
|
|
|
self_args: &[P<Expr>],
|
|
|
|
nonself_args: &[P<Expr>])
|
2016-07-19 23:02:06 +05:30
|
|
|
-> P<Expr> {
|
|
|
|
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());
|
2016-07-19 23:02:06 +05:30
|
|
|
let summary = trait_.summarise_struct(cx, &v.node.data);
|
2018-03-19 01:21:30 +03:00
|
|
|
(v.node.ident, sp, summary)
|
2016-07-19 23:02:06 +05:30
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
self.call_substructure_method(cx,
|
|
|
|
trait_,
|
|
|
|
type_ident,
|
|
|
|
self_args,
|
|
|
|
nonself_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> {
|
2016-07-19 23:02:06 +05:30
|
|
|
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
|
|
|
|
2013-12-07 11:57:44 +11:00
|
|
|
match (just_spans.is_empty(), named_idents.is_empty()) {
|
2016-07-19 23:02:06 +05:30
|
|
|
(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),
|
2016-02-22 21:24:32 +03:00
|
|
|
// empty structs
|
|
|
|
_ if struct_def.is_struct() => Named(named_idents),
|
2016-08-15 21:28:17 +03:00
|
|
|
_ => Unnamed(just_spans, struct_def.is_tuple()),
|
2013-12-07 11:57:44 +11:00
|
|
|
}
|
2013-03-28 21:50:10 +11:00
|
|
|
}
|
|
|
|
|
2013-12-07 11:57:44 +11:00
|
|
|
fn create_subpatterns(&self,
|
2014-02-08 19:39:53 -05:00
|
|
|
cx: &mut ExtCtxt,
|
2018-03-18 16:47:09 +03:00
|
|
|
field_paths: Vec<ast::Ident>,
|
2017-10-02 15:15:23 +02:00
|
|
|
mutbl: ast::Mutability,
|
|
|
|
use_temporaries: bool)
|
2014-09-13 19:06:01 +03:00
|
|
|
-> Vec<P<ast::Pat>> {
|
2016-07-19 23:02:06 +05:30
|
|
|
field_paths.iter()
|
|
|
|
.map(|path| {
|
2017-10-02 15:15:23 +02:00
|
|
|
let binding_mode = if use_temporaries {
|
|
|
|
ast::BindingMode::ByValue(ast::Mutability::Immutable)
|
|
|
|
} else {
|
|
|
|
ast::BindingMode::ByRef(mutbl)
|
|
|
|
};
|
2016-07-19 23:02:06 +05:30
|
|
|
cx.pat(path.span,
|
2017-10-02 15:15:23 +02:00
|
|
|
PatKind::Ident(binding_mode, (*path).clone(), None))
|
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
|
|
|
|
2016-07-19 23:02:06 +05:30
|
|
|
fn create_struct_pattern
|
|
|
|
(&self,
|
|
|
|
cx: &mut ExtCtxt,
|
|
|
|
struct_path: ast::Path,
|
|
|
|
struct_def: &'a VariantData,
|
|
|
|
prefix: &str,
|
2017-10-02 15:15:23 +02:00
|
|
|
mutbl: ast::Mutability,
|
|
|
|
use_temporaries: bool)
|
|
|
|
-> (P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>, &'a [ast::Attribute])>)
|
|
|
|
{
|
2014-02-28 13:09:09 -08:00
|
|
|
let mut paths = Vec::new();
|
2016-04-02 16:47:53 +03:00
|
|
|
let mut ident_exprs = Vec::new();
|
2015-10-25 18:33:51 +03:00
|
|
|
for (i, struct_field) in struct_def.fields().iter().enumerate() {
|
2017-07-31 23:04:34 +03:00
|
|
|
let sp = struct_field.span.with_ctxt(self.span.ctxt());
|
2018-04-19 19:04:06 +01:00
|
|
|
let ident = cx.ident_of(&format!("{}_{}", prefix, i)).gensym();
|
2018-03-18 16:47:09 +03:00
|
|
|
paths.push(ident.with_span_pos(sp));
|
2017-10-02 15:15:23 +02:00
|
|
|
let val = cx.expr_path(cx.path_ident(sp, ident));
|
|
|
|
let val = if use_temporaries {
|
|
|
|
val
|
|
|
|
} else {
|
|
|
|
cx.expr_deref(sp, val)
|
|
|
|
};
|
2016-02-08 16:05:05 +01:00
|
|
|
let val = cx.expr(sp, ast::ExprKind::Paren(val));
|
2017-10-02 15:15:23 +02:00
|
|
|
|
2016-04-06 11:19:10 +03:00
|
|
|
ident_exprs.push((sp, struct_field.ident, val, &struct_field.attrs[..]));
|
2013-12-07 11:57:44 +11:00
|
|
|
}
|
2013-06-07 17:30:38 +10:00
|
|
|
|
2017-10-02 15:15:23 +02:00
|
|
|
let subpats = self.create_subpatterns(cx, paths, mutbl, use_temporaries);
|
2016-08-15 21:28:17 +03:00
|
|
|
let pattern = match *struct_def {
|
|
|
|
VariantData::Struct(..) => {
|
|
|
|
let field_pats = subpats.into_iter()
|
|
|
|
.zip(&ident_exprs)
|
2016-08-26 19:23:42 +03:00
|
|
|
.map(|(pat, &(sp, ident, ..))| {
|
2016-08-15 21:28:17 +03:00
|
|
|
if ident.is_none() {
|
|
|
|
cx.span_bug(sp, "a braced struct with unnamed fields in `derive`");
|
|
|
|
}
|
2018-08-18 12:14:03 +02:00
|
|
|
source_map::Spanned {
|
2017-07-31 23:04:34 +03:00
|
|
|
span: pat.span.with_ctxt(self.span.ctxt()),
|
2016-08-15 21:28:17 +03:00
|
|
|
node: ast::FieldPat {
|
|
|
|
ident: ident.unwrap(),
|
2017-08-06 22:54:09 -07:00
|
|
|
pat,
|
2016-08-15 21:28:17 +03:00
|
|
|
is_shorthand: false,
|
2018-08-05 12:04:56 +02:00
|
|
|
attrs: ThinVec::new(),
|
2016-08-15 21:28:17 +03:00
|
|
|
},
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
cx.pat_struct(self.span, struct_path, field_pats)
|
|
|
|
}
|
|
|
|
VariantData::Tuple(..) => {
|
|
|
|
cx.pat_tuple_struct(self.span, struct_path, subpats)
|
|
|
|
}
|
|
|
|
VariantData::Unit(..) => {
|
|
|
|
cx.pat_path(self.span, struct_path)
|
|
|
|
}
|
2013-06-07 17:30:38 +10:00
|
|
|
};
|
|
|
|
|
2016-04-02 16:47:53 +03:00
|
|
|
(pattern, ident_exprs)
|
2013-12-07 11:57:44 +11:00
|
|
|
}
|
2013-06-07 17:30:38 +10:00
|
|
|
|
2016-07-19 23:02:06 +05:30
|
|
|
fn create_enum_variant_pattern
|
|
|
|
(&self,
|
|
|
|
cx: &mut ExtCtxt,
|
|
|
|
enum_ident: ast::Ident,
|
|
|
|
variant: &'a ast::Variant,
|
|
|
|
prefix: &str,
|
|
|
|
mutbl: ast::Mutability)
|
|
|
|
-> (P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>, &'a [ast::Attribute])>) {
|
2017-07-31 23:04:34 +03:00
|
|
|
let sp = variant.span.with_ctxt(self.span.ctxt());
|
2018-03-19 01:21:30 +03:00
|
|
|
let variant_path = cx.path(sp, vec![enum_ident, variant.node.ident]);
|
2017-10-02 15:15:23 +02:00
|
|
|
let use_temporaries = false; // enums can't be repr(packed)
|
|
|
|
self.create_struct_pattern(cx, variant_path, &variant.node.data, prefix, mutbl,
|
|
|
|
use_temporaries)
|
2013-06-07 17:30:38 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-19 23:02:06 +05:30
|
|
|
// helpful premade recipes
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2018-04-11 15:16:54 +01:00
|
|
|
pub fn cs_fold_fields<'a, F>(use_foldl: bool,
|
|
|
|
mut f: F,
|
|
|
|
base: P<Expr>,
|
|
|
|
cx: &mut ExtCtxt,
|
|
|
|
all_fields: &[FieldInfo<'a>])
|
|
|
|
-> P<Expr>
|
|
|
|
where F: FnMut(&mut ExtCtxt, Span, P<Expr>, P<Expr>, &[P<Expr>]) -> P<Expr>
|
|
|
|
{
|
|
|
|
if use_foldl {
|
|
|
|
all_fields.iter().fold(base, |old, field| {
|
|
|
|
f(cx, field.span, old, field.self_.clone(), &field.other)
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
all_fields.iter().rev().fold(base, |old, field| {
|
|
|
|
f(cx, field.span, old, field.self_.clone(), &field.other)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn cs_fold_enumnonmatch(mut enum_nonmatch_f: EnumNonMatchCollapsedFunc,
|
|
|
|
cx: &mut ExtCtxt,
|
|
|
|
trait_span: Span,
|
|
|
|
substructure: &Substructure)
|
|
|
|
-> P<Expr>
|
|
|
|
{
|
|
|
|
match *substructure.fields {
|
|
|
|
EnumNonMatchingCollapsed(ref all_args, _, tuple) => {
|
|
|
|
enum_nonmatch_f(cx,
|
|
|
|
trait_span,
|
|
|
|
(&all_args[..], tuple),
|
|
|
|
substructure.nonself_args)
|
|
|
|
}
|
|
|
|
_ => cx.span_bug(trait_span, "cs_fold_enumnonmatch expected an EnumNonMatchingCollapsed")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn cs_fold_static(cx: &mut ExtCtxt,
|
|
|
|
trait_span: Span)
|
|
|
|
-> P<Expr>
|
|
|
|
{
|
|
|
|
cx.span_bug(trait_span, "static function in `derive`")
|
|
|
|
}
|
|
|
|
|
2014-09-16 13:27:34 +02:00
|
|
|
/// Fold the fields. `use_foldl` controls whether this is done
|
|
|
|
/// left-to-right (`true`) or right-to-left (`false`).
|
2014-12-08 13:28:32 -05:00
|
|
|
pub fn cs_fold<F>(use_foldl: bool,
|
2018-04-11 15:16:54 +01:00
|
|
|
f: F,
|
2014-12-08 13:28:32 -05:00
|
|
|
base: P<Expr>,
|
2018-04-11 15:16:54 +01:00
|
|
|
enum_nonmatch_f: EnumNonMatchCollapsedFunc,
|
2014-12-08 13:28:32 -05:00
|
|
|
cx: &mut ExtCtxt,
|
|
|
|
trait_span: Span,
|
|
|
|
substructure: &Substructure)
|
2016-07-19 23:02:06 +05:30
|
|
|
-> P<Expr>
|
|
|
|
where F: FnMut(&mut ExtCtxt, Span, P<Expr>, P<Expr>, &[P<Expr>]) -> P<Expr>
|
2014-12-08 13:28:32 -05:00
|
|
|
{
|
2013-03-28 21:50:10 +11:00
|
|
|
match *substructure.fields {
|
2016-08-26 19:23:42 +03:00
|
|
|
EnumMatching(.., ref all_fields) |
|
2016-07-19 23:02:06 +05:30
|
|
|
Struct(_, ref all_fields) => {
|
2018-04-11 15:16:54 +01:00
|
|
|
cs_fold_fields(use_foldl, f, base, cx, all_fields)
|
2013-05-07 01:23:51 +10:00
|
|
|
}
|
2018-04-11 15:16:54 +01:00
|
|
|
EnumNonMatchingCollapsed(..) => {
|
|
|
|
cs_fold_enumnonmatch(enum_nonmatch_f, cx, trait_span, substructure)
|
|
|
|
}
|
|
|
|
StaticEnum(..) | StaticStruct(..) => {
|
|
|
|
cs_fold_static(cx, trait_span)
|
2016-07-19 23:02:06 +05:30
|
|
|
}
|
2013-03-28 21:50:10 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-12 01:33:52 +01:00
|
|
|
/// Function to fold over fields, with three cases, to generate more efficient and concise code.
|
|
|
|
/// When the `substructure` has grouped fields, there are two cases:
|
|
|
|
/// Zero fields: call the base case function with None (like the usual base case of `cs_fold`).
|
|
|
|
/// One or more fields: call the base case function on the first value (which depends on
|
|
|
|
/// `use_fold`), and use that as the base case. Then perform `cs_fold` on the remainder of the
|
|
|
|
/// fields.
|
|
|
|
/// When the `substructure` is a `EnumNonMatchingCollapsed`, the result of `enum_nonmatch_f`
|
|
|
|
/// is returned. Statics may not be folded over.
|
|
|
|
/// See `cs_op` in `partial_ord.rs` for a model example.
|
2018-04-11 15:16:54 +01:00
|
|
|
pub fn cs_fold1<F, B>(use_foldl: bool,
|
|
|
|
f: F,
|
|
|
|
mut b: B,
|
|
|
|
enum_nonmatch_f: EnumNonMatchCollapsedFunc,
|
|
|
|
cx: &mut ExtCtxt,
|
|
|
|
trait_span: Span,
|
|
|
|
substructure: &Substructure)
|
|
|
|
-> P<Expr>
|
|
|
|
where F: FnMut(&mut ExtCtxt, Span, P<Expr>, P<Expr>, &[P<Expr>]) -> P<Expr>,
|
|
|
|
B: FnMut(&mut ExtCtxt, Option<(Span, P<Expr>, &[P<Expr>])>) -> P<Expr>
|
|
|
|
{
|
|
|
|
match *substructure.fields {
|
|
|
|
EnumMatching(.., ref all_fields) |
|
|
|
|
Struct(_, ref all_fields) => {
|
|
|
|
let (base, all_fields) = match (all_fields.is_empty(), use_foldl) {
|
|
|
|
(false, true) => {
|
|
|
|
let field = &all_fields[0];
|
|
|
|
let args = (field.span, field.self_.clone(), &field.other[..]);
|
|
|
|
(b(cx, Some(args)), &all_fields[1..])
|
|
|
|
}
|
|
|
|
(false, false) => {
|
|
|
|
let idx = all_fields.len() - 1;
|
|
|
|
let field = &all_fields[idx];
|
|
|
|
let args = (field.span, field.self_.clone(), &field.other[..]);
|
|
|
|
(b(cx, Some(args)), &all_fields[..idx])
|
|
|
|
}
|
|
|
|
(true, _) => (b(cx, None), &all_fields[..])
|
|
|
|
};
|
|
|
|
|
|
|
|
cs_fold_fields(use_foldl, f, base, cx, all_fields)
|
|
|
|
}
|
|
|
|
EnumNonMatchingCollapsed(..) => {
|
|
|
|
cs_fold_enumnonmatch(enum_nonmatch_f, cx, trait_span, substructure)
|
|
|
|
}
|
|
|
|
StaticEnum(..) | StaticStruct(..) => {
|
|
|
|
cs_fold_static(cx, trait_span)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2014-09-16 13:27:34 +02:00
|
|
|
/// Call the method that is being derived on all the fields, and then
|
|
|
|
/// process the collected results. i.e.
|
|
|
|
///
|
2017-06-20 15:15:16 +08:00
|
|
|
/// ```ignore (only-for-syntax-highlight)
|
2016-03-17 00:43:36 +05:30
|
|
|
/// f(cx, span, vec![self_1.method(__arg_1_1, __arg_2_1),
|
|
|
|
/// self_2.method(__arg_1_2, __arg_2_2)])
|
2014-09-16 13:27:34 +02:00
|
|
|
/// ```
|
2013-06-18 14:45:18 -07:00
|
|
|
#[inline]
|
2014-12-08 13:28:32 -05:00
|
|
|
pub fn cs_same_method<F>(f: F,
|
2015-01-01 18:32:49 -05:00
|
|
|
mut enum_nonmatch_f: EnumNonMatchCollapsedFunc,
|
2014-12-08 13:28:32 -05:00
|
|
|
cx: &mut ExtCtxt,
|
|
|
|
trait_span: Span,
|
|
|
|
substructure: &Substructure)
|
2016-07-19 23:02:06 +05:30
|
|
|
-> P<Expr>
|
|
|
|
where F: FnOnce(&mut ExtCtxt, Span, Vec<P<Expr>>) -> P<Expr>
|
2014-12-08 13:28:32 -05:00
|
|
|
{
|
2013-03-28 21:50:10 +11:00
|
|
|
match *substructure.fields {
|
2016-08-26 19:23:42 +03:00
|
|
|
EnumMatching(.., ref all_fields) |
|
2016-07-19 23:02:06 +05:30
|
|
|
Struct(_, ref all_fields) => {
|
2013-03-28 21:50:10 +11:00
|
|
|
// call self_n.method(other_1_n, other_2_n, ...)
|
2016-07-19 23:02:06 +05:30
|
|
|
let called = all_fields.iter()
|
|
|
|
.map(|field| {
|
|
|
|
cx.expr_method_call(field.span,
|
|
|
|
field.self_.clone(),
|
|
|
|
substructure.method_ident,
|
|
|
|
field.other
|
|
|
|
.iter()
|
|
|
|
.map(|e| cx.expr_addr_of(field.span, e.clone()))
|
|
|
|
.collect())
|
|
|
|
})
|
|
|
|
.collect();
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2013-11-07 18:49:01 +11:00
|
|
|
f(cx, trait_span, called)
|
2013-05-07 01:23:51 +10:00
|
|
|
}
|
2016-07-19 23:02:06 +05:30
|
|
|
EnumNonMatchingCollapsed(ref all_self_args, _, tuple) => {
|
|
|
|
enum_nonmatch_f(cx,
|
|
|
|
trait_span,
|
|
|
|
(&all_self_args[..], tuple),
|
|
|
|
substructure.nonself_args)
|
|
|
|
}
|
|
|
|
StaticEnum(..) | StaticStruct(..) => cx.span_bug(trait_span, "static function in `derive`"),
|
2013-03-28 21:50:10 +11:00
|
|
|
}
|
|
|
|
}
|
2016-03-01 02:27:27 +01:00
|
|
|
|
|
|
|
/// Return true if the type has no value fields
|
|
|
|
/// (for an enum, no variant has any fields)
|
|
|
|
pub fn is_type_without_fields(item: &Annotatable) -> bool {
|
|
|
|
if let Annotatable::Item(ref item) = *item {
|
|
|
|
match item.node {
|
|
|
|
ast::ItemKind::Enum(ref enum_def, _) => {
|
|
|
|
enum_def.variants.iter().all(|v| v.node.data.fields().is_empty())
|
|
|
|
}
|
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
|
|
|
|
}
|
|
|
|
}
|