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
|
|
|
|
//! `deriving` instances for traits. Among other things it manages getting
|
|
|
|
//! access to the fields of the 4 different sorts of structs and enum
|
|
|
|
//! variants, as well as creating the method and impl ast instances.
|
|
|
|
//!
|
|
|
|
//! Supported features (fairly exhaustive):
|
|
|
|
//!
|
|
|
|
//! - Methods taking any number of parameters of any type, and returning
|
|
|
|
//! any type, other than vectors, bottom and closures.
|
|
|
|
//! - Generating `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.)
|
|
|
|
//! - Additional bounds on the type parameters, e.g. the `Ord` instance
|
|
|
|
//! requires an explicit `PartialEq` bound at the
|
|
|
|
//! moment. (`TraitDef.additional_bounds`)
|
|
|
|
//!
|
|
|
|
//! Unsupported: FIXME #6257: calling methods on reference fields,
|
|
|
|
//! e.g. deriving Eq/Ord/Clone don't work on `struct A(&int)`,
|
|
|
|
//! because of how the auto-dereferencing happens.
|
|
|
|
//!
|
|
|
|
//! The most important thing for implementers is the `Substructure` and
|
|
|
|
//! `SubstructureFields` objects. The latter groups 5 possibilities of the
|
|
|
|
//! arguments:
|
|
|
|
//!
|
|
|
|
//! - `Struct`, when `Self` is a struct (including tuple structs, e.g
|
|
|
|
//! `struct T(int, char)`).
|
|
|
|
//! - `EnumMatching`, when `Self` is an enum and all the arguments are the
|
|
|
|
//! same variant of the enum (e.g. `Some(1)`, `Some(3)` and `Some(4)`)
|
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
|
|
|
|
//! struct A { x : int }
|
|
|
|
//!
|
|
|
|
//! struct B(int);
|
|
|
|
//!
|
|
|
|
//! enum C {
|
|
|
|
//! C0(int),
|
|
|
|
//! C1 { x: int }
|
|
|
|
//! }
|
|
|
|
//! ```
|
|
|
|
//!
|
|
|
|
//! The `int`s in `B` and `C0` don't have an identifier, so the
|
|
|
|
//! `Option<ident>`s would be `None` for them.
|
|
|
|
//!
|
|
|
|
//! In the static cases, the structure is 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.
|
|
|
|
//!
|
|
|
|
//! # Examples
|
|
|
|
//!
|
|
|
|
//! The following simplified `PartialEq` is used for in-code examples:
|
|
|
|
//!
|
|
|
|
//! ```rust
|
|
|
|
//! trait PartialEq {
|
|
|
|
//! fn eq(&self, other: &Self);
|
|
|
|
//! }
|
|
|
|
//! impl PartialEq for int {
|
|
|
|
//! fn eq(&self, other: &int) -> bool {
|
|
|
|
//! *self == *other
|
|
|
|
//! }
|
|
|
|
//! }
|
|
|
|
//! ```
|
|
|
|
//!
|
|
|
|
//! Some examples of the values of `SubstructureFields` follow, using the
|
|
|
|
//! above `PartialEq`, `A`, `B` and `C`.
|
|
|
|
//!
|
|
|
|
//! ## Structs
|
|
|
|
//!
|
|
|
|
//! When generating the `expr` for the `A` impl, the `SubstructureFields` is
|
|
|
|
//!
|
|
|
|
//! ~~~text
|
|
|
|
//! Struct(~[FieldInfo {
|
|
|
|
//! span: <span of x>
|
|
|
|
//! name: Some(<ident of x>),
|
|
|
|
//! self_: <expr for &self.x>,
|
|
|
|
//! other: ~[<expr for &other.x]
|
|
|
|
//! }])
|
|
|
|
//! ~~~
|
|
|
|
//!
|
|
|
|
//! For the `B` impl, called with `B(a)` and `B(b)`,
|
|
|
|
//!
|
|
|
|
//! ~~~text
|
|
|
|
//! Struct(~[FieldInfo {
|
|
|
|
//! span: <span of `int`>,
|
|
|
|
//! name: None,
|
|
|
|
//! <expr for &a>
|
|
|
|
//! ~[<expr for &b>]
|
|
|
|
//! }])
|
|
|
|
//! ~~~
|
|
|
|
//!
|
|
|
|
//! ## Enums
|
|
|
|
//!
|
|
|
|
//! When generating the `expr` for a call with `self == C0(a)` and `other
|
|
|
|
//! == C0(b)`, the SubstructureFields is
|
|
|
|
//!
|
|
|
|
//! ~~~text
|
|
|
|
//! EnumMatching(0, <ast::Variant for C0>,
|
|
|
|
//! ~[FieldInfo {
|
|
|
|
//! span: <span of int>
|
|
|
|
//! name: None,
|
|
|
|
//! self_: <expr for &a>,
|
|
|
|
//! other: ~[<expr for &b>]
|
|
|
|
//! }])
|
|
|
|
//! ~~~
|
|
|
|
//!
|
2014-07-06 21:19:12 +02:00
|
|
|
//! For `C1 {x}` and `C1 {x}`,
|
2014-06-09 13:12:30 -07:00
|
|
|
//!
|
|
|
|
//! ~~~text
|
|
|
|
//! EnumMatching(1, <ast::Variant for C1>,
|
|
|
|
//! ~[FieldInfo {
|
|
|
|
//! span: <span of x>
|
|
|
|
//! name: Some(<ident of x>),
|
|
|
|
//! self_: <expr for &self.x>,
|
|
|
|
//! other: ~[<expr for &other.x>]
|
|
|
|
//! }])
|
|
|
|
//! ~~~
|
|
|
|
//!
|
|
|
|
//! For `C0(a)` and `C1 {x}` ,
|
|
|
|
//!
|
|
|
|
//! ~~~text
|
2014-07-06 21:19:12 +02:00
|
|
|
//! EnumNonMatchingCollapsed(
|
|
|
|
//! ~[<ident of self>, <ident of __arg_1>],
|
|
|
|
//! &[<ast::Variant for C0>, <ast::Variant for C1>],
|
|
|
|
//! &[<ident for self index value>, <ident of __arg_1 index value>])
|
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
|
|
|
|
//! <ident for self index value> and <ident of __arg_1 index value> will
|
|
|
|
//! be in the generated code.
|
|
|
|
//!
|
|
|
|
//! `EnumNonMatchingCollapsed` deliberately provides far less information
|
|
|
|
//! than is generally available for a given pair of variants; see #15375
|
|
|
|
//! for discussion.
|
2014-06-09 13:12:30 -07:00
|
|
|
//!
|
|
|
|
//! ## Static
|
|
|
|
//!
|
|
|
|
//! A static method on the above would result in,
|
|
|
|
//!
|
|
|
|
//! ~~~text
|
|
|
|
//! StaticStruct(<ast::StructDef of A>, Named(~[(<ident of x>, <span of x>)]))
|
|
|
|
//!
|
|
|
|
//! StaticStruct(<ast::StructDef of B>, Unnamed(~[<span of x>]))
|
|
|
|
//!
|
|
|
|
//! StaticEnum(<ast::EnumDef of C>, ~[(<ident of C0>, <span of C0>, Unnamed(~[<span of int>])),
|
|
|
|
//! (<ident of C1>, <span of C1>,
|
|
|
|
//! Named(~[(<ident of x>, <span of x>)]))])
|
|
|
|
//! ~~~
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2014-04-21 23:25:18 -07:00
|
|
|
use std::cell::RefCell;
|
2014-06-11 19:33:52 -07:00
|
|
|
use std::gc::{Gc, GC};
|
2014-04-21 23:25:18 -07:00
|
|
|
|
2013-03-28 21:50:10 +11:00
|
|
|
use ast;
|
2014-01-09 15:05:33 +02:00
|
|
|
use ast::{P, EnumDef, Expr, Ident, Generics, StructDef};
|
2014-02-14 07:07:09 +02:00
|
|
|
use ast_util;
|
2014-05-20 00:07:24 -07:00
|
|
|
use attr;
|
2014-05-11 01:11:33 -07:00
|
|
|
use attr::AttrMetaMethods;
|
2013-05-17 21:27:17 +10:00
|
|
|
use ext::base::ExtCtxt;
|
2013-05-18 00:19:28 +10:00
|
|
|
use ext::build::AstBuilder;
|
2013-12-07 11:57:44 +11:00
|
|
|
use codemap;
|
|
|
|
use codemap::Span;
|
2014-03-20 01:52:37 +11:00
|
|
|
use owned_slice::OwnedSlice;
|
2014-01-08 10:35:15 -08:00
|
|
|
use parse::token::InternedString;
|
2014-07-06 15:10:57 -07:00
|
|
|
use parse::token::special_idents;
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2014-05-29 12:19:05 +09:00
|
|
|
use self::ty::*;
|
|
|
|
|
|
|
|
pub mod ty;
|
2013-05-07 01:23:51 +10:00
|
|
|
|
2013-12-09 23:16:18 -08:00
|
|
|
pub struct TraitDef<'a> {
|
2013-12-07 11:57:44 +11:00
|
|
|
/// The span for the current #[deriving(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
|
|
|
|
2014-03-27 15:39:48 -07:00
|
|
|
pub methods: Vec<MethodDef<'a>>,
|
|
|
|
}
|
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
|
2014-03-27 15:39:48 -07:00
|
|
|
pub args: Vec<Ty<'a>>,
|
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
|
|
|
|
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,
|
2013-05-07 01:23:51 +10:00
|
|
|
/// dereferenced access to any Self or Ptr(Self, _) arguments
|
2014-05-16 00:16:13 -07:00
|
|
|
pub self_args: &'a [Gc<Expr>],
|
2013-05-07 01:23:51 +10:00
|
|
|
/// verbatim access to any other arguments
|
2014-05-16 00:16:13 -07:00
|
|
|
pub nonself_args: &'a [Gc<Expr>],
|
2014-03-27 15:39:48 -07:00
|
|
|
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.
|
|
|
|
pub struct FieldInfo {
|
2014-03-27 15:39:48 -07:00
|
|
|
pub span: Span,
|
2013-11-07 18:49:01 +11:00
|
|
|
/// None for tuple structs/normal enum variants, Some for normal
|
|
|
|
/// structs/struct enum variants.
|
2014-03-27 15:39:48 -07:00
|
|
|
pub name: Option<Ident>,
|
2013-11-07 18:49:01 +11:00
|
|
|
/// The expression corresponding to this field of `self`
|
|
|
|
/// (specifically, a reference to it).
|
2014-05-16 00:16:13 -07:00
|
|
|
pub self_: Gc<Expr>,
|
2013-11-07 18:49:01 +11:00
|
|
|
/// The expressions corresponding to references to this field in
|
|
|
|
/// the other Self arguments.
|
2014-05-16 00:16:13 -07:00
|
|
|
pub other: Vec<Gc<Expr>>,
|
2014-03-27 15:39:48 -07:00
|
|
|
}
|
2013-11-07 18:49:01 +11:00
|
|
|
|
|
|
|
/// Fields for a static method
|
|
|
|
pub enum StaticFields {
|
|
|
|
/// Tuple structs/enum variants like this
|
2014-05-16 00:16:13 -07:00
|
|
|
Unnamed(Vec<Span>),
|
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
|
|
|
}
|
|
|
|
|
2013-03-28 21:50:10 +11:00
|
|
|
/// A summary of the possible sets of fields. See above for details
|
|
|
|
/// and examples
|
2013-12-09 23:16:18 -08:00
|
|
|
pub enum SubstructureFields<'a> {
|
2014-05-16 00:16:13 -07:00
|
|
|
Struct(Vec<FieldInfo>),
|
2013-03-28 21:50:10 +11:00
|
|
|
/**
|
2014-01-09 15:05:33 +02:00
|
|
|
Matching variants of the enum: variant index, ast::Variant,
|
2013-11-07 18:49:01 +11:00
|
|
|
fields: the field name is only non-`None` in the case of a struct
|
|
|
|
variant.
|
2013-03-28 21:50:10 +11:00
|
|
|
*/
|
2014-05-16 00:16:13 -07:00
|
|
|
EnumMatching(uint, &'a ast::Variant, Vec<FieldInfo>),
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2014-07-06 21:19:12 +02:00
|
|
|
/**
|
|
|
|
non-matching variants of the enum, but with all state hidden from
|
|
|
|
the consequent code. The first component holds Idents for all of
|
|
|
|
the Self arguments; the second component is a slice of all of the
|
|
|
|
variants for the enum itself, and the third component is a list of
|
|
|
|
Idents bound to the variant index values for each of the actual
|
|
|
|
input Self arguments.
|
|
|
|
*/
|
|
|
|
EnumNonMatchingCollapsed(Vec<Ident>, &'a [Gc<ast::Variant>], &'a [Ident]),
|
|
|
|
|
2013-11-07 18:49:01 +11:00
|
|
|
/// A static method where Self is a struct.
|
2014-01-09 15:05:33 +02:00
|
|
|
StaticStruct(&'a ast::StructDef, StaticFields),
|
2013-11-07 18:49:01 +11: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
|
|
|
|
2013-03-28 21:50:10 +11:00
|
|
|
/**
|
|
|
|
Combine the values of all the fields together. The last argument is
|
|
|
|
all the fields of all the structures, see above for details.
|
|
|
|
*/
|
2013-12-09 23:16:18 -08:00
|
|
|
pub type CombineSubstructureFunc<'a> =
|
2014-05-16 00:16:13 -07:00
|
|
|
|&mut ExtCtxt, Span, &Substructure|: 'a -> Gc<Expr>;
|
2013-03-28 21:50:10 +11:00
|
|
|
|
|
|
|
/**
|
2014-07-06 21:19:12 +02:00
|
|
|
Deal with non-matching enum variants. The tuple is a list of
|
|
|
|
identifiers (one for each Self argument, which could be any of the
|
|
|
|
variants since they have been collapsed together) and the identifiers
|
|
|
|
holding the variant index value for each of the Self arguments. The
|
|
|
|
last argument is all the non-Self args of the method being derived.
|
2013-03-28 21:50:10 +11:00
|
|
|
*/
|
2014-07-06 21:19:12 +02:00
|
|
|
pub type EnumNonMatchCollapsedFunc<'a> =
|
2014-04-07 13:30:48 -07:00
|
|
|
|&mut ExtCtxt,
|
2013-11-19 17:36:32 -08:00
|
|
|
Span,
|
2014-07-06 21:19:12 +02:00
|
|
|
(&[Ident], &[Ident]),
|
2014-05-16 00:16:13 -07:00
|
|
|
&[Gc<Expr>]|: 'a
|
|
|
|
-> Gc<Expr>;
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2014-04-21 23:25:18 -07:00
|
|
|
pub fn combine_substructure<'a>(f: CombineSubstructureFunc<'a>)
|
|
|
|
-> RefCell<CombineSubstructureFunc<'a>> {
|
|
|
|
RefCell::new(f)
|
|
|
|
}
|
|
|
|
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2013-12-09 23:16:18 -08:00
|
|
|
impl<'a> TraitDef<'a> {
|
2013-12-07 11:57:44 +11:00
|
|
|
pub fn expand(&self,
|
2014-02-08 19:39:53 -05:00
|
|
|
cx: &mut ExtCtxt,
|
2014-05-16 00:16:13 -07:00
|
|
|
_mitem: Gc<ast::MetaItem>,
|
|
|
|
item: Gc<ast::Item>,
|
|
|
|
push: |Gc<ast::Item>|) {
|
2014-05-11 01:11:33 -07:00
|
|
|
let newitem = match item.node {
|
2014-05-16 00:16:13 -07:00
|
|
|
ast::ItemStruct(ref struct_def, ref generics) => {
|
2014-05-11 01:11:33 -07:00
|
|
|
self.expand_struct_def(cx,
|
2014-05-16 00:16:13 -07:00
|
|
|
&**struct_def,
|
2014-05-11 01:11:33 -07:00
|
|
|
item.ident,
|
|
|
|
generics)
|
2013-06-07 17:46:44 +10:00
|
|
|
}
|
2014-02-12 23:53:52 -08:00
|
|
|
ast::ItemEnum(ref enum_def, ref generics) => {
|
2014-05-11 01:11:33 -07:00
|
|
|
self.expand_enum_def(cx,
|
|
|
|
enum_def,
|
|
|
|
item.ident,
|
|
|
|
generics)
|
2014-02-12 23:53:52 -08:00
|
|
|
}
|
2014-05-11 01:11:33 -07:00
|
|
|
_ => return
|
|
|
|
};
|
|
|
|
// Keep the lint attributes of the previous item to control how the
|
|
|
|
// generated implementations are linted
|
|
|
|
let mut attrs = newitem.attrs.clone();
|
|
|
|
attrs.extend(item.attrs.iter().filter(|a| {
|
|
|
|
match a.name().get() {
|
|
|
|
"allow" | "warn" | "deny" | "forbid" => true,
|
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}).map(|a| a.clone()));
|
2014-05-16 00:16:13 -07:00
|
|
|
push(box(GC) ast::Item {
|
2014-05-11 01:11:33 -07:00
|
|
|
attrs: attrs,
|
|
|
|
..(*newitem).clone()
|
|
|
|
})
|
2013-06-07 17:46:44 +10:00
|
|
|
}
|
|
|
|
|
2013-06-07 17:30:38 +10:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* Given that we are deriving a trait `Tr` for a type `T<'a, ...,
|
|
|
|
* 'z, A, ..., Z>`, creates an impl like:
|
|
|
|
*
|
2014-02-14 23:44:22 -08:00
|
|
|
* ```ignore
|
2013-06-07 17:30:38 +10:00
|
|
|
* impl<'a, ..., 'z, A:Tr B1 B2, ..., Z: Tr B1 B2> Tr for T<A, ..., Z> { ... }
|
2014-02-14 23:44:22 -08:00
|
|
|
* ```
|
2013-06-07 17:30:38 +10:00
|
|
|
*
|
|
|
|
* where B1, B2, ... are the bounds given by `bounds_paths`.'
|
|
|
|
*
|
|
|
|
*/
|
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,
|
2014-05-16 00:16:13 -07:00
|
|
|
methods: Vec<Gc<ast::Method>> ) -> Gc<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
|
|
|
|
2014-03-19 23:16:56 +11:00
|
|
|
let Generics { mut lifetimes, ty_params } =
|
|
|
|
self.generics.to_generics(cx, self.span, type_ident, generics);
|
2014-03-20 01:52:37 +11:00
|
|
|
let mut ty_params = ty_params.into_vec();
|
2014-03-19 23:16:56 +11:00
|
|
|
|
2013-06-07 17:30:38 +10:00
|
|
|
// Copy the lifetimes
|
2014-03-20 14:12:56 +01:00
|
|
|
lifetimes.extend(generics.lifetimes.iter().map(|l| *l));
|
2014-03-19 23:16:56 +11:00
|
|
|
|
2013-06-07 17:30:38 +10:00
|
|
|
// Create the type parameters.
|
2014-03-20 14:12:56 +01:00
|
|
|
ty_params.extend(generics.ty_params.iter().map(|ty_param| {
|
2013-06-07 17:30:38 +10:00
|
|
|
// I don't think this can be moved out of the loop, since
|
|
|
|
// a TyParamBound requires an ast id
|
2014-03-28 20:42:34 +01:00
|
|
|
let mut bounds: Vec<_> =
|
2013-06-07 17:30:38 +10:00
|
|
|
// extra restrictions on the generics parameters to the type being derived upon
|
2014-03-28 20:42:34 +01:00
|
|
|
self.additional_bounds.iter().map(|p| {
|
2014-02-08 19:39:53 -05:00
|
|
|
cx.typarambound(p.to_path(cx, self.span,
|
|
|
|
type_ident, generics))
|
2014-03-28 20:42:34 +01:00
|
|
|
}).collect();
|
2013-06-07 17:30:38 +10:00
|
|
|
// require the current trait
|
2013-07-02 12:47:32 -07:00
|
|
|
bounds.push(cx.typarambound(trait_path.clone()));
|
2013-06-07 17:30:38 +10:00
|
|
|
|
2014-04-03 13:38:45 +13:00
|
|
|
cx.typaram(self.span,
|
|
|
|
ty_param.ident,
|
|
|
|
OwnedSlice::from_vec(bounds),
|
2014-07-08 14:26:02 +12:00
|
|
|
ty_param.unbound.clone(),
|
2014-04-03 13:38:45 +13:00
|
|
|
None)
|
2014-03-19 23:16:56 +11:00
|
|
|
}));
|
|
|
|
let trait_generics = Generics {
|
|
|
|
lifetimes: lifetimes,
|
2014-03-20 01:52:37 +11:00
|
|
|
ty_params: OwnedSlice::from_vec(ty_params)
|
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
|
|
|
|
2013-06-07 17:30:38 +10:00
|
|
|
// Create the type parameters on the `self` path.
|
2013-11-20 16:23:04 -08:00
|
|
|
let self_ty_params = generics.ty_params.map(|ty_param| {
|
2013-12-07 11:57:44 +11:00
|
|
|
cx.ty_ident(self.span, ty_param.ident)
|
2013-11-20 16:23:04 -08:00
|
|
|
});
|
2013-05-07 01:23:51 +10:00
|
|
|
|
2013-10-29 06:03:32 -04:00
|
|
|
let self_lifetimes = generics.lifetimes.clone();
|
2013-06-07 17:30:38 +10:00
|
|
|
|
|
|
|
// Create the type of `self`.
|
2013-12-07 11:57:44 +11:00
|
|
|
let self_type = cx.ty_path(
|
2014-02-28 13:09:09 -08:00
|
|
|
cx.path_all(self.span, false, vec!( type_ident ), self_lifetimes,
|
2014-03-20 01:52:37 +11:00
|
|
|
self_ty_params.into_vec()), None);
|
2013-06-07 17:30:38 +10:00
|
|
|
|
2014-03-15 22:49:41 -07:00
|
|
|
let attr = cx.attribute(
|
2013-12-07 11:57:44 +11:00
|
|
|
self.span,
|
2014-03-15 22:49:41 -07:00
|
|
|
cx.meta_word(self.span,
|
|
|
|
InternedString::new("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);
|
2014-05-16 00:16:13 -07:00
|
|
|
let ident = ast_util::impl_pretty_name(&opt_trait_ref, &*self_type);
|
2013-06-07 17:30:38 +10:00
|
|
|
cx.item(
|
2013-12-07 11:57:44 +11:00
|
|
|
self.span,
|
2014-02-14 07:07:09 +02:00
|
|
|
ident,
|
2014-03-30 23:53:26 -04:00
|
|
|
(vec!(attr)).append(self.attributes.as_slice()),
|
2014-02-14 07:07:09 +02:00
|
|
|
ast::ItemImpl(trait_generics, opt_trait_ref,
|
2014-03-28 20:42:34 +01:00
|
|
|
self_type, methods))
|
2013-03-28 21:50:10 +11:00
|
|
|
}
|
|
|
|
|
2014-02-21 21:33:23 -08:00
|
|
|
fn expand_struct_def(&self,
|
|
|
|
cx: &mut ExtCtxt,
|
|
|
|
struct_def: &StructDef,
|
|
|
|
type_ident: Ident,
|
2014-05-16 00:16:13 -07:00
|
|
|
generics: &Generics) -> Gc<ast::Item> {
|
2014-03-28 20:42:34 +01:00
|
|
|
let methods = self.methods.iter().map(|method_def| {
|
2013-04-30 08:49:48 -07:00
|
|
|
let (explicit_self, self_args, nonself_args, tys) =
|
2014-02-08 19:39:53 -05:00
|
|
|
method_def.split_self_nonself_args(
|
|
|
|
cx, self, type_ident, generics);
|
2013-05-07 01:23:51 +10:00
|
|
|
|
|
|
|
let body = if method_def.is_static() {
|
|
|
|
method_def.expand_static_struct_method_body(
|
2014-02-08 19:39:53 -05:00
|
|
|
cx,
|
2013-12-07 11:57:44 +11:00
|
|
|
self,
|
2013-05-07 01:23:51 +10:00
|
|
|
struct_def,
|
|
|
|
type_ident,
|
2014-02-28 12:54:01 -08:00
|
|
|
self_args.as_slice(),
|
|
|
|
nonself_args.as_slice())
|
2013-03-28 21:50:10 +11:00
|
|
|
} else {
|
2014-02-08 19:39:53 -05:00
|
|
|
method_def.expand_struct_method_body(cx,
|
|
|
|
self,
|
2013-03-28 21:50:10 +11:00
|
|
|
struct_def,
|
2013-05-07 01:23:51 +10:00
|
|
|
type_ident,
|
2014-02-28 12:54:01 -08:00
|
|
|
self_args.as_slice(),
|
|
|
|
nonself_args.as_slice())
|
2013-03-28 21:50:10 +11:00
|
|
|
};
|
|
|
|
|
2014-02-08 19:39:53 -05:00
|
|
|
method_def.create_method(cx, self,
|
2013-05-07 01:23:51 +10:00
|
|
|
type_ident, generics,
|
2013-04-30 08:49:48 -07:00
|
|
|
explicit_self, tys,
|
2013-05-07 01:23:51 +10:00
|
|
|
body)
|
2014-03-28 20:42:34 +01:00
|
|
|
}).collect();
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2014-02-08 19:39:53 -05:00
|
|
|
self.create_derived_impl(cx, type_ident, generics, 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,
|
2014-01-09 15:05:33 +02:00
|
|
|
enum_def: &EnumDef,
|
2013-09-02 02:50:59 +02:00
|
|
|
type_ident: Ident,
|
2014-05-16 00:16:13 -07:00
|
|
|
generics: &Generics) -> Gc<ast::Item> {
|
2014-03-28 20:42:34 +01:00
|
|
|
let methods = self.methods.iter().map(|method_def| {
|
2013-04-30 08:49:48 -07:00
|
|
|
let (explicit_self, self_args, nonself_args, tys) =
|
2014-02-08 19:39:53 -05:00
|
|
|
method_def.split_self_nonself_args(cx, self,
|
|
|
|
type_ident, generics);
|
2013-05-07 01:23:51 +10:00
|
|
|
|
|
|
|
let body = if method_def.is_static() {
|
|
|
|
method_def.expand_static_enum_method_body(
|
2014-02-08 19:39:53 -05:00
|
|
|
cx,
|
2013-12-07 11:57:44 +11:00
|
|
|
self,
|
2013-05-07 01:23:51 +10:00
|
|
|
enum_def,
|
|
|
|
type_ident,
|
2014-02-28 12:54:01 -08:00
|
|
|
self_args.as_slice(),
|
|
|
|
nonself_args.as_slice())
|
2013-05-07 01:23:51 +10:00
|
|
|
} else {
|
2014-02-08 19:39:53 -05:00
|
|
|
method_def.expand_enum_method_body(cx,
|
|
|
|
self,
|
2013-05-07 01:23:51 +10:00
|
|
|
enum_def,
|
|
|
|
type_ident,
|
2014-02-28 12:54:01 -08:00
|
|
|
self_args.as_slice(),
|
|
|
|
nonself_args.as_slice())
|
2013-05-07 01:23:51 +10:00
|
|
|
};
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2014-02-08 19:39:53 -05:00
|
|
|
method_def.create_method(cx, self,
|
2013-05-07 01:23:51 +10:00
|
|
|
type_ident, generics,
|
2013-04-30 08:49:48 -07:00
|
|
|
explicit_self, tys,
|
2013-05-07 01:23:51 +10:00
|
|
|
body)
|
2014-03-28 20:42:34 +01:00
|
|
|
}).collect();
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2014-02-08 19:39:53 -05:00
|
|
|
self.create_derived_impl(cx, type_ident, generics, methods)
|
2013-03-28 21:50:10 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-06 21:19:12 +02:00
|
|
|
fn variant_to_pat(cx: &mut ExtCtxt, sp: Span, variant: &ast::Variant)
|
|
|
|
-> Gc<ast::Pat> {
|
|
|
|
let ident = cx.path_ident(sp, variant.node.name);
|
|
|
|
cx.pat(sp, match variant.node.kind {
|
|
|
|
ast::TupleVariantKind(..) => ast::PatEnum(ident, None),
|
|
|
|
ast::StructVariantKind(..) => ast::PatStruct(ident, Vec::new(), true),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
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-05-16 00:16:13 -07:00
|
|
|
self_args: &[Gc<Expr>],
|
|
|
|
nonself_args: &[Gc<Expr>],
|
2013-03-28 21:50:10 +11:00
|
|
|
fields: &SubstructureFields)
|
2014-05-16 00:16:13 -07:00
|
|
|
-> Gc<Expr> {
|
2013-03-28 21:50:10 +11:00
|
|
|
let substructure = Substructure {
|
|
|
|
type_ident: type_ident,
|
2014-02-08 19:39:53 -05:00
|
|
|
method_ident: cx.ident_of(self.name),
|
2013-05-07 01:23:51 +10:00
|
|
|
self_args: self_args,
|
|
|
|
nonself_args: nonself_args,
|
2013-03-28 21:50:10 +11:00
|
|
|
fields: fields
|
|
|
|
};
|
2014-04-21 23:25:18 -07:00
|
|
|
let mut f = self.combine_substructure.borrow_mut();
|
|
|
|
let f: &mut CombineSubstructureFunc = &mut *f;
|
|
|
|
(*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
|
|
|
|
2014-02-08 19:39:53 -05:00
|
|
|
fn split_self_nonself_args(&self,
|
|
|
|
cx: &mut ExtCtxt,
|
|
|
|
trait_: &TraitDef,
|
|
|
|
type_ident: Ident,
|
|
|
|
generics: &Generics)
|
2014-05-16 00:16:13 -07:00
|
|
|
-> (ast::ExplicitSelf, Vec<Gc<Expr>>, Vec<Gc<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;
|
|
|
|
|
2013-04-30 08:49:48 -07:00
|
|
|
let ast_explicit_self = match self.explicit_self {
|
2013-05-12 00:25:31 -04:00
|
|
|
Some(ref self_ptr) => {
|
2013-12-07 11:57:44 +11:00
|
|
|
let (self_expr, explicit_self) =
|
2014-02-08 19:39:53 -05:00
|
|
|
ty::get_explicit_self(cx, trait_.span, self_ptr);
|
2013-05-07 01:23:51 +10:00
|
|
|
|
|
|
|
self_args.push(self_expr);
|
|
|
|
nonstatic = true;
|
2013-04-30 08:49:48 -07:00
|
|
|
|
|
|
|
explicit_self
|
2013-03-28 21:50:10 +11:00
|
|
|
}
|
2014-01-09 15:05:33 +02:00
|
|
|
None => codemap::respan(trait_.span, ast::SelfStatic),
|
2013-04-30 08:49:48 -07:00
|
|
|
};
|
2013-05-07 01:23:51 +10:00
|
|
|
|
2013-08-03 12:45:23 -04:00
|
|
|
for (i, ty) in self.args.iter().enumerate() {
|
2014-02-08 19:39:53 -05:00
|
|
|
let ast_ty = ty.to_ty(cx, trait_.span, type_ident, generics);
|
2014-05-16 10:45:16 -07:00
|
|
|
let ident = cx.ident_of(format!("__arg_{}", i).as_slice());
|
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
|
|
|
|
Self if nonstatic => {
|
|
|
|
self_args.push(arg_expr);
|
|
|
|
}
|
2014-05-05 18:56:44 -07:00
|
|
|
Ptr(box Self, _) if 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-01-09 15:05:33 +02:00
|
|
|
explicit_self: ast::ExplicitSelf,
|
2014-02-28 13:09:09 -08:00
|
|
|
arg_types: Vec<(Ident, P<ast::Ty>)> ,
|
2014-05-16 00:16:13 -07:00
|
|
|
body: Gc<Expr>) -> Gc<ast::Method> {
|
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-01-27 14:18:36 +02:00
|
|
|
let self_arg = match explicit_self.node {
|
|
|
|
ast::SelfStatic => None,
|
2014-07-06 15:10:57 -07:00
|
|
|
// creating fresh self id
|
|
|
|
_ => Some(ast::Arg::new_self(trait_.span, ast::MutImmutable, special_idents::self_))
|
2014-01-27 14:18:36 +02:00
|
|
|
};
|
2014-02-09 07:37:33 -05:00
|
|
|
let args = {
|
|
|
|
let args = arg_types.move_iter().map(|(name, ty)| {
|
|
|
|
cx.arg(trait_.span, name, ty)
|
|
|
|
});
|
|
|
|
self_arg.move_iter().chain(args).collect()
|
|
|
|
};
|
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);
|
|
|
|
let fn_decl = cx.fn_decl(args, ret_type);
|
|
|
|
let body_block = cx.block_expr(body);
|
2013-03-28 21:50:10 +11:00
|
|
|
|
|
|
|
// Create the method.
|
2014-05-16 00:16:13 -07:00
|
|
|
box(GC) ast::Method {
|
2014-04-23 22:43:45 +08:00
|
|
|
attrs: self.attributes.clone(),
|
2013-09-06 22:11:55 -04:00
|
|
|
id: ast::DUMMY_NODE_ID,
|
2013-12-07 11:57:44 +11:00
|
|
|
span: trait_.span,
|
2014-07-11 21:22:11 -07:00
|
|
|
node: ast::MethDecl(method_ident,
|
|
|
|
fn_generics,
|
|
|
|
explicit_self,
|
|
|
|
ast::NormalFn,
|
|
|
|
fn_decl,
|
|
|
|
body_block,
|
|
|
|
ast::Inherited)
|
2013-03-28 21:50:10 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2014-02-24 12:29:45 +11:00
|
|
|
~~~
|
2014-05-29 17:45:07 -07:00
|
|
|
#[deriving(PartialEq)]
|
2013-05-07 01:23:51 +10:00
|
|
|
struct A { x: int, y: int }
|
2013-03-28 21:50:10 +11:00
|
|
|
|
|
|
|
// equivalent to:
|
2014-05-29 17:45:07 -07:00
|
|
|
impl PartialEq for A {
|
2013-05-07 01:23:51 +10:00
|
|
|
fn eq(&self, __arg_1: &A) -> bool {
|
2013-03-28 21:50:10 +11:00
|
|
|
match *self {
|
2013-05-07 01:23:51 +10:00
|
|
|
A {x: ref __self_0_0, y: ref __self_0_1} => {
|
|
|
|
match *__arg_1 {
|
|
|
|
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)
|
2013-03-28 21:50:10 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-11-07 18:49:01 +11:00
|
|
|
~~~
|
2013-03-28 21:50:10 +11:00
|
|
|
*/
|
2013-05-07 01:23:51 +10:00
|
|
|
fn expand_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,
|
2014-01-09 15:05:33 +02:00
|
|
|
struct_def: &StructDef,
|
2013-09-02 02:50:59 +02:00
|
|
|
type_ident: Ident,
|
2014-05-16 00:16:13 -07:00
|
|
|
self_args: &[Gc<Expr>],
|
|
|
|
nonself_args: &[Gc<Expr>])
|
|
|
|
-> Gc<Expr> {
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2014-02-28 13:09:09 -08:00
|
|
|
let mut raw_fields = Vec::new(); // ~[[fields of self],
|
2013-06-04 21:43:41 -07:00
|
|
|
// [fields of next Self arg], [etc]]
|
2014-02-28 13:09:09 -08:00
|
|
|
let mut patterns = Vec::new();
|
2013-08-03 12:45:23 -04:00
|
|
|
for i in range(0u, self_args.len()) {
|
2014-05-16 10:45:16 -07:00
|
|
|
let (pat, ident_expr) =
|
|
|
|
trait_.create_struct_pattern(cx,
|
|
|
|
type_ident,
|
|
|
|
struct_def,
|
|
|
|
format!("__self_{}",
|
|
|
|
i).as_slice(),
|
|
|
|
ast::MutImmutable);
|
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
|
2014-02-13 09:46:46 -08:00
|
|
|
let fields = if raw_fields.len() > 0 {
|
2014-02-28 12:54:01 -08:00
|
|
|
raw_fields.get(0)
|
|
|
|
.iter()
|
|
|
|
.enumerate()
|
|
|
|
.map(|(i, &(span, opt_id, field))| {
|
|
|
|
let other_fields = raw_fields.tail().iter().map(|l| {
|
|
|
|
match l.get(i) {
|
2014-02-13 09:46:46 -08:00
|
|
|
&(_, _, ex) => ex
|
2013-11-07 18:49:01 +11:00
|
|
|
}
|
2014-02-28 12:54:01 -08:00
|
|
|
}).collect();
|
2014-02-13 09:46:46 -08:00
|
|
|
FieldInfo {
|
|
|
|
span: span,
|
|
|
|
name: opt_id,
|
|
|
|
self_: field,
|
|
|
|
other: other_fields
|
|
|
|
}
|
|
|
|
}).collect()
|
|
|
|
} else {
|
|
|
|
cx.span_bug(trait_.span,
|
|
|
|
"no self arguments to non-static method in generic \
|
|
|
|
`deriving`")
|
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
|
|
|
|
let mut body = self.call_substructure_method(
|
2014-02-08 19:39:53 -05:00
|
|
|
cx,
|
2013-12-07 11:57:44 +11:00
|
|
|
trait_,
|
2013-05-07 01:23:51 +10:00
|
|
|
type_ident,
|
|
|
|
self_args,
|
|
|
|
nonself_args,
|
|
|
|
&Struct(fields));
|
|
|
|
|
|
|
|
// 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.
|
2013-08-03 12:45:23 -04:00
|
|
|
for (&arg_expr, &pat) in self_args.iter().zip(patterns.iter()) {
|
2014-02-08 19:39:53 -05:00
|
|
|
body = cx.expr_match(trait_.span, arg_expr,
|
2014-02-28 13:09:09 -08:00
|
|
|
vec!( cx.arm(trait_.span, vec!(pat), body) ))
|
2013-03-28 21:50:10 +11: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,
|
2014-01-09 15:05:33 +02:00
|
|
|
struct_def: &StructDef,
|
2013-09-02 02:50:59 +02:00
|
|
|
type_ident: Ident,
|
2014-05-16 00:16:13 -07:00
|
|
|
self_args: &[Gc<Expr>],
|
|
|
|
nonself_args: &[Gc<Expr>])
|
|
|
|
-> Gc<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,
|
|
|
|
self_args, nonself_args,
|
|
|
|
&StaticStruct(struct_def, summary))
|
2013-03-28 21:50:10 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2014-02-24 12:29:45 +11:00
|
|
|
~~~
|
2014-05-29 17:45:07 -07:00
|
|
|
#[deriving(PartialEq)]
|
2013-03-28 21:50:10 +11:00
|
|
|
enum A {
|
2014-07-06 21:19:12 +02:00
|
|
|
A1,
|
2013-03-28 21:50:10 +11:00
|
|
|
A2(int)
|
|
|
|
}
|
|
|
|
|
2014-07-06 21:19:12 +02:00
|
|
|
// is equivalent to
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2014-05-29 17:45:07 -07:00
|
|
|
impl PartialEq for A {
|
2014-07-06 21:19:12 +02:00
|
|
|
fn eq(&self, __arg_1: &A) -> ::bool {
|
|
|
|
match (&*self, &*__arg_1) {
|
|
|
|
(&A1, &A1) => true,
|
|
|
|
(&A2(ref __self_0),
|
|
|
|
&A2(ref __arg_1_0)) => (*__self_0).eq(&(*__arg_1_0)),
|
|
|
|
_ => {
|
|
|
|
let __self_vi = match *self { A1(..) => 0u, A2(..) => 1u };
|
|
|
|
let __arg_1_vi = match *__arg_1 { A1(..) => 0u, A2(..) => 1u };
|
|
|
|
false
|
2013-03-28 21:50:10 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-11-07 18:49:01 +11:00
|
|
|
~~~
|
2014-07-06 21:19:12 +02:00
|
|
|
|
|
|
|
(Of course `__self_vi` and `__arg_1_vi` are unused for
|
|
|
|
`PartialEq`, and those subcomputations will hopefully be removed
|
|
|
|
as their results are unused. The point of `__self_vi` and
|
|
|
|
`__arg_1_vi` is for `PartialOrd`; see #15503.)
|
2013-03-28 21:50:10 +11:00
|
|
|
*/
|
|
|
|
fn expand_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-09-02 02:50:59 +02:00
|
|
|
type_ident: Ident,
|
2014-05-16 00:16:13 -07:00
|
|
|
self_args: &[Gc<Expr>],
|
|
|
|
nonself_args: &[Gc<Expr>])
|
|
|
|
-> Gc<Expr> {
|
2014-07-07 09:13:49 +02:00
|
|
|
self.build_enum_match_tuple(
|
|
|
|
cx, trait_, enum_def, type_ident, self_args, nonself_args)
|
2013-03-28 21:50:10 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-07-06 21:19:12 +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.
|
|
|
|
|
|
|
|
The catch-all handler is provided access the variant index values
|
|
|
|
for each of the self-args, carried in precomputed variables. (Nota
|
|
|
|
bene: the variant index values are not necessarily the
|
|
|
|
discriminant values. See issue #15523.)
|
|
|
|
|
|
|
|
~~~text
|
|
|
|
match (this, that, ...) {
|
|
|
|
(Variant1, Variant1, Variant1) => ... // delegate Matching on Variant1
|
|
|
|
(Variant2, Variant2, Variant2) => ... // delegate Matching on Variant2
|
|
|
|
...
|
|
|
|
_ => {
|
|
|
|
let __this_vi = match this { Variant1 => 0u, Variant2 => 1u, ... };
|
|
|
|
let __that_vi = match that { Variant1 => 0u, Variant2 => 1u, ... };
|
|
|
|
... // catch-all remainder can inspect above variant index values.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
~~~
|
|
|
|
*/
|
|
|
|
fn build_enum_match_tuple(
|
|
|
|
&self,
|
|
|
|
cx: &mut ExtCtxt,
|
|
|
|
trait_: &TraitDef,
|
|
|
|
enum_def: &EnumDef,
|
|
|
|
type_ident: Ident,
|
|
|
|
self_args: &[Gc<Expr>],
|
|
|
|
nonself_args: &[Gc<Expr>]) -> Gc<Expr> {
|
|
|
|
|
|
|
|
let sp = trait_.span;
|
|
|
|
let variants = &enum_def.variants;
|
|
|
|
|
|
|
|
let self_arg_names = self_args.iter().enumerate()
|
|
|
|
.map(|(arg_count, _self_arg)| {
|
|
|
|
if arg_count == 0 {
|
|
|
|
"__self".to_string()
|
|
|
|
} else {
|
|
|
|
format!("__arg_{}", arg_count)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect::<Vec<String>>();
|
|
|
|
|
|
|
|
let self_arg_idents = self_arg_names.iter()
|
|
|
|
.map(|name|cx.ident_of(name.as_slice()))
|
|
|
|
.collect::<Vec<ast::Ident>>();
|
|
|
|
|
|
|
|
// The `vi_idents` will be bound, solely in the catch-all, to
|
|
|
|
// a series of let statements mapping each self_arg to a uint
|
|
|
|
// corresponding to its variant index.
|
|
|
|
let vi_idents : Vec<ast::Ident> = self_arg_names.iter()
|
|
|
|
.map(|name| { let vi_suffix = format!("{:s}_vi", name.as_slice());
|
|
|
|
cx.ident_of(vi_suffix.as_slice()) })
|
|
|
|
.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.
|
|
|
|
let catch_all_substructure = EnumNonMatchingCollapsed(
|
|
|
|
self_arg_idents, variants.as_slice(), vi_idents.as_slice());
|
|
|
|
|
|
|
|
// These arms are of the form:
|
|
|
|
// (Variant1, Variant1, ...) => Body1
|
|
|
|
// (Variant2, Variant2, ...) => Body2
|
|
|
|
// ...
|
|
|
|
// where each tuple has length = self_args.len()
|
|
|
|
let mut match_arms : Vec<ast::Arm> = variants.iter().enumerate()
|
|
|
|
.map(|(index, &variant)| {
|
|
|
|
|
|
|
|
// These self_pats have form Variant1, Variant2, ...
|
|
|
|
let self_pats : Vec<(Gc<ast::Pat>,
|
|
|
|
Vec<(Span, Option<Ident>, Gc<Expr>)>)>;
|
|
|
|
self_pats = self_arg_names.iter()
|
|
|
|
.map(|self_arg_name|
|
|
|
|
trait_.create_enum_variant_pattern(
|
|
|
|
cx, &*variant, self_arg_name.as_slice(),
|
|
|
|
ast::MutImmutable))
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
// A single arm has form (&VariantK, &VariantK, ...) => BodyK
|
|
|
|
// (see "Final wrinkle" note below for why.)
|
|
|
|
let subpats = self_pats.iter()
|
|
|
|
.map(|&(p, ref _idents)| cx.pat(sp, ast::PatRegion(p)))
|
|
|
|
.collect::<Vec<Gc<ast::Pat>>>();
|
|
|
|
|
|
|
|
// Here is the pat = `(&VariantK, &VariantK, ...)`
|
|
|
|
let single_pat = cx.pat(sp, ast::PatTup(subpats));
|
|
|
|
|
|
|
|
// 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
|
|
|
|
// cases. So we transpose the info in self_pats to
|
|
|
|
// gather the getter expressions together, in the form
|
|
|
|
// that EnumMatching expects.
|
|
|
|
|
|
|
|
// The transposition is driven by walking across the
|
|
|
|
// arg fields of the variant for the first self pat.
|
|
|
|
let &(_, ref self_arg_fields) = self_pats.get(0);
|
|
|
|
|
|
|
|
let field_tuples : Vec<FieldInfo>;
|
|
|
|
|
|
|
|
field_tuples = self_arg_fields.iter().enumerate()
|
|
|
|
// For each arg field of self, pull out its getter expr ...
|
|
|
|
.map(|(field_index, &(sp, opt_ident, self_getter_expr))| {
|
|
|
|
// ... but FieldInfo also wants getter expr
|
|
|
|
// for matching other arguments of Self type;
|
|
|
|
// so walk across the *other* self_pats and
|
|
|
|
// pull out getter for same field in each of
|
|
|
|
// them (using `field_index` tracked above).
|
|
|
|
// That is the heart of the transposition.
|
|
|
|
let others = self_pats.tail().iter()
|
|
|
|
.map(|&(_pat, ref fields)| {
|
|
|
|
|
|
|
|
let &(_, _opt_ident, other_getter_expr) =
|
|
|
|
fields.get(field_index);
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
|
|
|
other_getter_expr
|
|
|
|
}).collect::<Vec<Gc<Expr>>>();
|
|
|
|
|
|
|
|
FieldInfo { span: sp,
|
|
|
|
name: opt_ident,
|
|
|
|
self_: self_getter_expr,
|
|
|
|
other: others,
|
|
|
|
}
|
|
|
|
}).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.
|
|
|
|
let substructure = EnumMatching(index, variant, field_tuples);
|
|
|
|
let arm_expr = self.call_substructure_method(
|
|
|
|
cx, trait_, type_ident, self_args, nonself_args,
|
|
|
|
&substructure);
|
|
|
|
|
|
|
|
cx.arm(sp, vec![single_pat], arm_expr)
|
|
|
|
}).collect();
|
|
|
|
|
|
|
|
// 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 {
|
|
|
|
let arms : Vec<ast::Arm> = variants.iter().enumerate()
|
|
|
|
.map(|(index, &variant)| {
|
|
|
|
let pat = variant_to_pat(cx, sp, &*variant);
|
|
|
|
let lit = ast::LitUint(index as u64, ast::TyU);
|
|
|
|
cx.arm(sp, vec![pat], cx.expr_lit(sp, lit))
|
|
|
|
}).collect();
|
|
|
|
|
|
|
|
// Build a series of let statements mapping each self_arg
|
|
|
|
// to a uint corresponding to its variant index.
|
|
|
|
// i.e. for `enum E<T> { A, B(1), C(T, T) }`, and a deriving
|
|
|
|
// with three Self args, builds three statements:
|
|
|
|
//
|
|
|
|
// ```
|
|
|
|
// let __self0_vi = match self {
|
|
|
|
// A => 0u, B(..) => 1u, C(..) => 2u
|
|
|
|
// };
|
|
|
|
// let __self1_vi = match __arg1 {
|
|
|
|
// A => 0u, B(..) => 1u, C(..) => 2u
|
|
|
|
// };
|
|
|
|
// let __self2_vi = match __arg2 {
|
|
|
|
// A => 0u, B(..) => 1u, C(..) => 2u
|
|
|
|
// };
|
|
|
|
// ```
|
|
|
|
let mut index_let_stmts : Vec<Gc<ast::Stmt>> = Vec::new();
|
|
|
|
for (&ident, &self_arg) in vi_idents.iter().zip(self_args.iter()) {
|
|
|
|
let variant_idx = cx.expr_match(sp, self_arg, arms.clone());
|
|
|
|
let let_stmt = cx.stmt_let(sp, false, ident, variant_idx);
|
|
|
|
index_let_stmts.push(let_stmt);
|
|
|
|
}
|
|
|
|
|
|
|
|
let arm_expr = self.call_substructure_method(
|
|
|
|
cx, trait_, type_ident, self_args, nonself_args,
|
|
|
|
&catch_all_substructure);
|
|
|
|
|
|
|
|
// Builds the expression:
|
|
|
|
// {
|
|
|
|
// let __self0_vi = ...;
|
|
|
|
// let __self1_vi = ...;
|
|
|
|
// ...
|
|
|
|
// <delegated expression referring to __self0_vi, et al.>
|
|
|
|
// }
|
|
|
|
let arm_expr = cx.expr_block(
|
|
|
|
cx.block_all(sp, Vec::new(), index_let_stmts, Some(arm_expr)));
|
|
|
|
|
|
|
|
// Builds arm:
|
|
|
|
// _ => { let __self0_vi = ...;
|
|
|
|
// let __self1_vi = ...;
|
|
|
|
// ...
|
|
|
|
// <delegated expression as above> }
|
|
|
|
let catch_all_match_arm =
|
|
|
|
cx.arm(sp, vec![cx.pat_wild(sp)], arm_expr);
|
|
|
|
|
|
|
|
match_arms.push(catch_all_match_arm);
|
|
|
|
|
|
|
|
} else if variants.len() == 0 {
|
|
|
|
// 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:
|
|
|
|
//
|
|
|
|
// _ => { let __self0 = match *self { };
|
|
|
|
// let __self1 = match *__arg_0 { };
|
|
|
|
// <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
|
|
|
|
// derive Show on such a type could here generate code
|
|
|
|
// that needs the feature gate enabled.)
|
|
|
|
|
|
|
|
return cx.expr_unreachable(sp);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Final wrinkle: the self_args are expressions that deref
|
|
|
|
// down to desired l-values, but we cannot actually deref
|
|
|
|
// them when they are fed as r-values into a tuple
|
|
|
|
// expression; here add a layer of borrowing, turning
|
|
|
|
// `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
|
|
|
|
let borrowed_self_args = self_args.iter()
|
|
|
|
.map(|&self_arg| cx.expr_addr_of(sp, self_arg))
|
|
|
|
.collect::<Vec<Gc<ast::Expr>>>();
|
|
|
|
let match_arg = cx.expr(sp, ast::ExprTup(borrowed_self_args));
|
|
|
|
cx.expr_match(sp, match_arg, match_arms)
|
|
|
|
}
|
|
|
|
|
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-05-16 00:16:13 -07:00
|
|
|
self_args: &[Gc<Expr>],
|
|
|
|
nonself_args: &[Gc<Expr>])
|
|
|
|
-> Gc<Expr> {
|
2014-03-28 20:42:34 +01:00
|
|
|
let summary = enum_def.variants.iter().map(|v| {
|
2013-05-07 01:23:51 +10:00
|
|
|
let ident = v.node.name;
|
|
|
|
let summary = match v.node.kind {
|
2014-01-09 15:05:33 +02:00
|
|
|
ast::TupleVariantKind(ref args) => {
|
2014-03-28 20:42:34 +01:00
|
|
|
Unnamed(args.iter().map(|va| trait_.set_expn_info(cx, va.ty.span)).collect())
|
2013-12-07 13:43:22 +11:00
|
|
|
}
|
2014-05-16 00:16:13 -07:00
|
|
|
ast::StructVariantKind(ref struct_def) => {
|
|
|
|
trait_.summarise_struct(cx, &**struct_def)
|
2013-05-07 01:23:51 +10:00
|
|
|
}
|
|
|
|
};
|
2014-01-27 15:25:37 +11:00
|
|
|
(ident, v.span, summary)
|
2014-03-28 20:42:34 +01:00
|
|
|
}).collect();
|
2014-02-08 19:39:53 -05:00
|
|
|
self.call_substructure_method(cx, trait_, type_ident,
|
2013-05-07 01:23:51 +10:00
|
|
|
self_args, nonself_args,
|
|
|
|
&StaticEnum(enum_def, summary))
|
|
|
|
}
|
2013-03-28 21:50:10 +11:00
|
|
|
}
|
|
|
|
|
2014-05-29 17:45:07 -07:00
|
|
|
#[deriving(PartialEq)] // dogfooding!
|
2013-12-07 11:57:44 +11:00
|
|
|
enum StructType {
|
|
|
|
Unknown, Record, Tuple
|
|
|
|
}
|
|
|
|
|
|
|
|
// general helper methods.
|
|
|
|
impl<'a> TraitDef<'a> {
|
2014-02-08 19:39:53 -05:00
|
|
|
fn set_expn_info(&self,
|
|
|
|
cx: &mut ExtCtxt,
|
|
|
|
mut to_set: Span) -> Span {
|
2013-12-23 15:08:23 +01:00
|
|
|
let trait_name = match self.path.path.last() {
|
2014-02-08 19:39:53 -05:00
|
|
|
None => cx.span_bug(self.span, "trait with empty path in generic `deriving`"),
|
2013-12-07 13:43:22 +11:00
|
|
|
Some(name) => *name
|
|
|
|
};
|
2014-05-16 00:16:13 -07:00
|
|
|
to_set.expn_info = Some(box(GC) codemap::ExpnInfo {
|
2013-12-07 13:43:22 +11:00
|
|
|
call_site: to_set,
|
|
|
|
callee: codemap::NameAndSpan {
|
2014-06-26 08:15:14 +02:00
|
|
|
name: format!("deriving({})", trait_name),
|
2013-12-07 13:43:22 +11:00
|
|
|
format: codemap::MacroAttribute,
|
|
|
|
span: Some(self.span)
|
|
|
|
}
|
|
|
|
});
|
|
|
|
to_set
|
|
|
|
}
|
|
|
|
|
2014-02-08 19:39:53 -05:00
|
|
|
fn summarise_struct(&self,
|
|
|
|
cx: &mut ExtCtxt,
|
|
|
|
struct_def: &StructDef) -> StaticFields {
|
2014-02-28 13:09:09 -08:00
|
|
|
let mut named_idents = Vec::new();
|
|
|
|
let mut just_spans = Vec::new();
|
2013-12-07 11:57:44 +11:00
|
|
|
for field in struct_def.fields.iter(){
|
2014-02-08 19:39:53 -05:00
|
|
|
let sp = self.set_expn_info(cx, field.span);
|
2013-12-07 11:57:44 +11:00
|
|
|
match field.node.kind {
|
2014-01-09 15:05:33 +02:00
|
|
|
ast::NamedField(ident, _) => named_idents.push((ident, sp)),
|
2014-03-25 16:53:52 -07:00
|
|
|
ast::UnnamedField(..) => 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()) {
|
2014-02-08 19:39:53 -05:00
|
|
|
(false, false) => cx.span_bug(self.span,
|
|
|
|
"a struct with named and unnamed \
|
|
|
|
fields in generic `deriving`"),
|
2013-12-07 11:57:44 +11:00
|
|
|
// named fields
|
|
|
|
(_, false) => Named(named_idents),
|
|
|
|
// tuple structs (includes empty structs)
|
|
|
|
(_, _) => Unnamed(just_spans)
|
|
|
|
}
|
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,
|
2014-06-30 18:02:14 -07:00
|
|
|
field_paths: Vec<ast::SpannedIdent> ,
|
2013-09-02 03:45:37 +02:00
|
|
|
mutbl: ast::Mutability)
|
2014-05-16 00:16:13 -07:00
|
|
|
-> Vec<Gc<ast::Pat>> {
|
2014-03-28 20:42:34 +01:00
|
|
|
field_paths.iter().map(|path| {
|
2014-02-08 19:39:53 -05:00
|
|
|
cx.pat(path.span,
|
2013-12-07 11:57:44 +11:00
|
|
|
ast::PatIdent(ast::BindByRef(mutbl), (*path).clone(), None))
|
2014-03-28 20:42:34 +01:00
|
|
|
}).collect()
|
2013-12-07 11:57:44 +11:00
|
|
|
}
|
2013-06-07 17:30:38 +10:00
|
|
|
|
2013-12-07 11:57:44 +11:00
|
|
|
fn create_struct_pattern(&self,
|
2014-02-08 19:39:53 -05:00
|
|
|
cx: &mut ExtCtxt,
|
2013-12-07 11:57:44 +11:00
|
|
|
struct_ident: Ident,
|
2014-01-09 15:05:33 +02:00
|
|
|
struct_def: &StructDef,
|
2013-12-07 11:57:44 +11:00
|
|
|
prefix: &str,
|
|
|
|
mutbl: ast::Mutability)
|
2014-05-16 00:16:13 -07:00
|
|
|
-> (Gc<ast::Pat>, Vec<(Span, Option<Ident>, Gc<Expr>)>) {
|
2013-12-07 11:57:44 +11:00
|
|
|
if struct_def.fields.is_empty() {
|
|
|
|
return (
|
|
|
|
cx.pat_ident_binding_mode(
|
|
|
|
self.span, struct_ident, ast::BindByValue(ast::MutImmutable)),
|
2014-02-28 13:09:09 -08:00
|
|
|
Vec::new());
|
2013-12-07 11:57:44 +11:00
|
|
|
}
|
2013-06-07 17:30:38 +10:00
|
|
|
|
2014-02-28 13:09:09 -08:00
|
|
|
let matching_path = cx.path(self.span, vec!( struct_ident ));
|
2013-06-07 17:30:38 +10:00
|
|
|
|
2014-02-28 13:09:09 -08:00
|
|
|
let mut paths = Vec::new();
|
|
|
|
let mut ident_expr = Vec::new();
|
2013-12-07 11:57:44 +11:00
|
|
|
let mut struct_type = Unknown;
|
2013-06-07 17:30:38 +10:00
|
|
|
|
2013-12-07 11:57:44 +11:00
|
|
|
for (i, struct_field) in struct_def.fields.iter().enumerate() {
|
2014-02-08 19:39:53 -05:00
|
|
|
let sp = self.set_expn_info(cx, struct_field.span);
|
2013-12-07 11:57:44 +11:00
|
|
|
let opt_id = match struct_field.node.kind {
|
2014-01-09 15:05:33 +02:00
|
|
|
ast::NamedField(ident, _) if (struct_type == Unknown ||
|
|
|
|
struct_type == Record) => {
|
2013-12-07 11:57:44 +11:00
|
|
|
struct_type = Record;
|
|
|
|
Some(ident)
|
|
|
|
}
|
2014-03-25 16:53:52 -07:00
|
|
|
ast::UnnamedField(..) if (struct_type == Unknown ||
|
|
|
|
struct_type == Tuple) => {
|
2013-12-07 11:57:44 +11:00
|
|
|
struct_type = Tuple;
|
|
|
|
None
|
|
|
|
}
|
|
|
|
_ => {
|
2014-02-06 10:38:08 +01:00
|
|
|
cx.span_bug(sp, "a struct with named and unnamed fields in `deriving`");
|
2013-12-07 11:57:44 +11:00
|
|
|
}
|
|
|
|
};
|
2014-06-30 18:02:14 -07:00
|
|
|
let ident = cx.ident_of(format!("{}_{}", prefix, i).as_slice());
|
|
|
|
paths.push(codemap::Spanned{span: sp, node: ident});
|
2014-02-08 19:39:53 -05:00
|
|
|
let val = cx.expr(
|
2014-06-30 18:02:14 -07:00
|
|
|
sp, ast::ExprParen(cx.expr_deref(sp, cx.expr_path(cx.path_ident(sp,ident)))));
|
2014-01-28 00:20:50 +11:00
|
|
|
ident_expr.push((sp, opt_id, val));
|
2013-12-07 11:57:44 +11:00
|
|
|
}
|
2013-06-07 17:30:38 +10:00
|
|
|
|
2014-02-08 19:39:53 -05:00
|
|
|
let subpats = self.create_subpatterns(cx, paths, mutbl);
|
2013-12-07 11:57:44 +11:00
|
|
|
|
|
|
|
// struct_type is definitely not Unknown, since struct_def.fields
|
|
|
|
// must be nonempty to reach here
|
|
|
|
let pattern = if struct_type == Record {
|
|
|
|
let field_pats = subpats.iter().zip(ident_expr.iter()).map(|(&pat, &(_, id, _))| {
|
|
|
|
// id is guaranteed to be Some
|
|
|
|
ast::FieldPat { ident: id.unwrap(), pat: pat }
|
|
|
|
}).collect();
|
|
|
|
cx.pat_struct(self.span, matching_path, field_pats)
|
|
|
|
} else {
|
|
|
|
cx.pat_enum(self.span, matching_path, subpats)
|
2013-06-07 17:30:38 +10:00
|
|
|
};
|
|
|
|
|
2013-12-07 11:57:44 +11:00
|
|
|
(pattern, ident_expr)
|
|
|
|
}
|
2013-06-07 17:30:38 +10:00
|
|
|
|
2013-12-07 11:57:44 +11:00
|
|
|
fn create_enum_variant_pattern(&self,
|
2014-02-08 19:39:53 -05:00
|
|
|
cx: &mut ExtCtxt,
|
2014-01-09 15:05:33 +02:00
|
|
|
variant: &ast::Variant,
|
2013-12-07 11:57:44 +11:00
|
|
|
prefix: &str,
|
|
|
|
mutbl: ast::Mutability)
|
2014-05-16 00:16:13 -07:00
|
|
|
-> (Gc<ast::Pat>, Vec<(Span, Option<Ident>, Gc<Expr>)> ) {
|
2013-12-07 11:57:44 +11:00
|
|
|
let variant_ident = variant.node.name;
|
|
|
|
match variant.node.kind {
|
2014-01-09 15:05:33 +02:00
|
|
|
ast::TupleVariantKind(ref variant_args) => {
|
2013-12-07 11:57:44 +11:00
|
|
|
if variant_args.is_empty() {
|
|
|
|
return (cx.pat_ident_binding_mode(variant.span, variant_ident,
|
2014-02-08 19:39:53 -05:00
|
|
|
ast::BindByValue(ast::MutImmutable)),
|
2014-02-28 13:09:09 -08:00
|
|
|
Vec::new());
|
2013-12-07 11:57:44 +11:00
|
|
|
}
|
2013-06-07 17:30:38 +10:00
|
|
|
|
2013-12-07 11:57:44 +11:00
|
|
|
let matching_path = cx.path_ident(variant.span, variant_ident);
|
2013-06-07 17:30:38 +10:00
|
|
|
|
2014-02-28 13:09:09 -08:00
|
|
|
let mut paths = Vec::new();
|
|
|
|
let mut ident_expr = Vec::new();
|
2013-12-07 11:57:44 +11:00
|
|
|
for (i, va) in variant_args.iter().enumerate() {
|
2014-02-08 19:39:53 -05:00
|
|
|
let sp = self.set_expn_info(cx, va.ty.span);
|
2014-06-30 18:02:14 -07:00
|
|
|
let ident = cx.ident_of(format!("{}_{}", prefix, i).as_slice());
|
|
|
|
let path1 = codemap::Spanned{span: sp, node: ident};
|
|
|
|
paths.push(path1);
|
|
|
|
let expr_path = cx.expr_path(cx.path_ident(sp, ident));
|
|
|
|
let val = cx.expr(sp, ast::ExprParen(cx.expr_deref(sp, expr_path)));
|
2014-01-28 00:20:50 +11:00
|
|
|
ident_expr.push((sp, None, val));
|
2013-12-07 11:57:44 +11:00
|
|
|
}
|
2013-06-07 17:30:38 +10:00
|
|
|
|
2014-02-08 19:39:53 -05:00
|
|
|
let subpats = self.create_subpatterns(cx, paths, mutbl);
|
2013-06-07 17:30:38 +10:00
|
|
|
|
2013-12-07 11:57:44 +11:00
|
|
|
(cx.pat_enum(variant.span, matching_path, subpats),
|
|
|
|
ident_expr)
|
|
|
|
}
|
2014-05-16 00:16:13 -07:00
|
|
|
ast::StructVariantKind(ref struct_def) => {
|
|
|
|
self.create_struct_pattern(cx, variant_ident, &**struct_def,
|
2013-12-07 11:57:44 +11:00
|
|
|
prefix, mutbl)
|
2013-06-07 17:30:38 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-28 21:50:10 +11:00
|
|
|
/* helpful premade recipes */
|
|
|
|
|
|
|
|
/**
|
|
|
|
Fold the fields. `use_foldl` controls whether this is done
|
|
|
|
left-to-right (`true`) or right-to-left (`false`).
|
|
|
|
*/
|
|
|
|
pub fn cs_fold(use_foldl: bool,
|
2014-05-16 00:16:13 -07:00
|
|
|
f: |&mut ExtCtxt, Span, Gc<Expr>, Gc<Expr>, &[Gc<Expr>]| -> Gc<Expr>,
|
|
|
|
base: Gc<Expr>,
|
2014-07-07 09:13:49 +02:00
|
|
|
enum_nonmatch_f: EnumNonMatchCollapsedFunc,
|
2014-02-06 08:50:21 +11:00
|
|
|
cx: &mut ExtCtxt,
|
2013-11-19 12:21:21 -08:00
|
|
|
trait_span: Span,
|
|
|
|
substructure: &Substructure)
|
2014-05-16 00:16:13 -07:00
|
|
|
-> Gc<Expr> {
|
2013-03-28 21:50:10 +11:00
|
|
|
match *substructure.fields {
|
2013-05-12 00:25:31 -04:00
|
|
|
EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => {
|
2013-03-28 21:50:10 +11:00
|
|
|
if use_foldl {
|
2013-11-20 16:23:04 -08:00
|
|
|
all_fields.iter().fold(base, |old, field| {
|
2014-02-28 12:54:01 -08:00
|
|
|
f(cx,
|
|
|
|
field.span,
|
|
|
|
old,
|
|
|
|
field.self_,
|
|
|
|
field.other.as_slice())
|
2013-11-20 16:23:04 -08:00
|
|
|
})
|
2013-03-28 21:50:10 +11:00
|
|
|
} else {
|
2014-03-16 16:04:29 -07:00
|
|
|
all_fields.iter().rev().fold(base, |old, field| {
|
2014-02-28 12:54:01 -08:00
|
|
|
f(cx,
|
|
|
|
field.span,
|
|
|
|
old,
|
|
|
|
field.self_,
|
|
|
|
field.other.as_slice())
|
2013-11-20 16:23:04 -08:00
|
|
|
})
|
2013-03-28 21:50:10 +11:00
|
|
|
}
|
|
|
|
},
|
2014-07-06 21:19:12 +02:00
|
|
|
EnumNonMatchingCollapsed(ref all_args, _, tuple) =>
|
2014-07-07 09:13:49 +02:00
|
|
|
enum_nonmatch_f(cx, trait_span, (all_args.as_slice(), tuple),
|
2014-07-06 21:19:12 +02:00
|
|
|
substructure.nonself_args),
|
2013-11-28 12:22:53 -08:00
|
|
|
StaticEnum(..) | StaticStruct(..) => {
|
2014-02-06 10:38:08 +01:00
|
|
|
cx.span_bug(trait_span, "static function in `deriving`")
|
2013-05-07 01:23:51 +10:00
|
|
|
}
|
2013-03-28 21:50:10 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
Call the method that is being derived on all the fields, and then
|
|
|
|
process the collected results. i.e.
|
|
|
|
|
2014-02-24 12:29:45 +11:00
|
|
|
~~~
|
2013-05-07 01:23:51 +10:00
|
|
|
f(cx, span, ~[self_1.method(__arg_1_1, __arg_2_1),
|
|
|
|
self_2.method(__arg_1_2, __arg_2_2)])
|
2013-11-07 18:49:01 +11:00
|
|
|
~~~
|
2013-03-28 21:50:10 +11:00
|
|
|
*/
|
2013-06-18 14:45:18 -07:00
|
|
|
#[inline]
|
2014-05-16 00:16:13 -07:00
|
|
|
pub fn cs_same_method(f: |&mut ExtCtxt, Span, Vec<Gc<Expr>>| -> Gc<Expr>,
|
2014-07-07 09:13:49 +02:00
|
|
|
enum_nonmatch_f: EnumNonMatchCollapsedFunc,
|
2014-02-06 08:50:21 +11:00
|
|
|
cx: &mut ExtCtxt,
|
2013-11-19 12:21:21 -08:00
|
|
|
trait_span: Span,
|
|
|
|
substructure: &Substructure)
|
2014-05-16 00:16:13 -07:00
|
|
|
-> Gc<Expr> {
|
2013-03-28 21:50:10 +11:00
|
|
|
match *substructure.fields {
|
2013-05-12 00:25:31 -04:00
|
|
|
EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => {
|
2013-03-28 21:50:10 +11:00
|
|
|
// call self_n.method(other_1_n, other_2_n, ...)
|
2014-03-28 20:42:34 +01:00
|
|
|
let called = all_fields.iter().map(|field| {
|
2013-11-07 18:49:01 +11:00
|
|
|
cx.expr_method_call(field.span,
|
|
|
|
field.self_,
|
2013-05-19 15:53:42 +10:00
|
|
|
substructure.method_ident,
|
2014-03-28 20:42:34 +01:00
|
|
|
field.other.iter()
|
|
|
|
.map(|e| cx.expr_addr_of(field.span, *e))
|
|
|
|
.collect())
|
|
|
|
}).collect();
|
2013-03-28 21:50:10 +11:00
|
|
|
|
2013-11-07 18:49:01 +11:00
|
|
|
f(cx, trait_span, called)
|
2013-03-28 21:50:10 +11:00
|
|
|
},
|
2014-07-06 21:19:12 +02:00
|
|
|
EnumNonMatchingCollapsed(ref all_self_args, _, tuple) =>
|
2014-07-07 09:13:49 +02:00
|
|
|
enum_nonmatch_f(cx, trait_span, (all_self_args.as_slice(), tuple),
|
2014-07-06 21:19:12 +02:00
|
|
|
substructure.nonself_args),
|
2013-11-28 12:22:53 -08:00
|
|
|
StaticEnum(..) | StaticStruct(..) => {
|
2014-02-06 10:38:08 +01:00
|
|
|
cx.span_bug(trait_span, "static function in `deriving`")
|
2013-05-07 01:23:51 +10:00
|
|
|
}
|
2013-03-28 21:50:10 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Fold together the results of calling the derived method on all the
|
|
|
|
fields. `use_foldl` controls whether this is done left-to-right
|
|
|
|
(`true`) or right-to-left (`false`).
|
|
|
|
*/
|
2013-06-18 14:45:18 -07:00
|
|
|
#[inline]
|
2013-03-28 21:50:10 +11:00
|
|
|
pub fn cs_same_method_fold(use_foldl: bool,
|
2014-05-16 00:16:13 -07:00
|
|
|
f: |&mut ExtCtxt, Span, Gc<Expr>, Gc<Expr>| -> Gc<Expr>,
|
|
|
|
base: Gc<Expr>,
|
2014-07-07 09:13:49 +02:00
|
|
|
enum_nonmatch_f: EnumNonMatchCollapsedFunc,
|
2014-02-06 08:50:21 +11:00
|
|
|
cx: &mut ExtCtxt,
|
2013-11-19 12:21:21 -08:00
|
|
|
trait_span: Span,
|
|
|
|
substructure: &Substructure)
|
2014-05-16 00:16:13 -07:00
|
|
|
-> Gc<Expr> {
|
2013-03-28 21:50:10 +11:00
|
|
|
cs_same_method(
|
|
|
|
|cx, span, vals| {
|
|
|
|
if use_foldl {
|
2013-11-20 16:23:04 -08:00
|
|
|
vals.iter().fold(base, |old, &new| {
|
2013-03-28 21:50:10 +11:00
|
|
|
f(cx, span, old, new)
|
2013-11-20 16:23:04 -08:00
|
|
|
})
|
2013-03-28 21:50:10 +11:00
|
|
|
} else {
|
2014-03-16 16:04:29 -07:00
|
|
|
vals.iter().rev().fold(base, |old, &new| {
|
2013-03-28 21:50:10 +11:00
|
|
|
f(cx, span, old, new)
|
2013-11-20 16:23:04 -08:00
|
|
|
})
|
2013-03-28 21:50:10 +11:00
|
|
|
}
|
|
|
|
},
|
|
|
|
enum_nonmatch_f,
|
2013-11-07 18:49:01 +11:00
|
|
|
cx, trait_span, substructure)
|
2013-03-28 21:50:10 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Use a given binop to combine the result of calling the derived method
|
|
|
|
on all the fields.
|
|
|
|
*/
|
2013-06-18 14:45:18 -07:00
|
|
|
#[inline]
|
2014-05-16 00:16:13 -07:00
|
|
|
pub fn cs_binop(binop: ast::BinOp, base: Gc<Expr>,
|
2014-07-07 09:13:49 +02:00
|
|
|
enum_nonmatch_f: EnumNonMatchCollapsedFunc,
|
2014-02-06 08:50:21 +11:00
|
|
|
cx: &mut ExtCtxt, trait_span: Span,
|
2014-05-16 00:16:13 -07:00
|
|
|
substructure: &Substructure) -> Gc<Expr> {
|
2013-03-28 21:50:10 +11:00
|
|
|
cs_same_method_fold(
|
|
|
|
true, // foldl is good enough
|
|
|
|
|cx, span, old, new| {
|
2013-05-19 15:53:42 +10:00
|
|
|
cx.expr_binary(span,
|
|
|
|
binop,
|
|
|
|
old, new)
|
2013-03-28 21:50:10 +11:00
|
|
|
|
|
|
|
},
|
|
|
|
base,
|
|
|
|
enum_nonmatch_f,
|
2013-11-07 18:49:01 +11:00
|
|
|
cx, trait_span, substructure)
|
2013-03-28 21:50:10 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
/// cs_binop with binop == or
|
2013-06-18 14:45:18 -07:00
|
|
|
#[inline]
|
2014-07-07 09:13:49 +02:00
|
|
|
pub fn cs_or(enum_nonmatch_f: EnumNonMatchCollapsedFunc,
|
2014-02-06 08:50:21 +11:00
|
|
|
cx: &mut ExtCtxt, span: Span,
|
2014-05-16 00:16:13 -07:00
|
|
|
substructure: &Substructure) -> Gc<Expr> {
|
2013-09-02 03:45:37 +02:00
|
|
|
cs_binop(ast::BiOr, cx.expr_bool(span, false),
|
2013-03-28 21:50:10 +11:00
|
|
|
enum_nonmatch_f,
|
|
|
|
cx, span, substructure)
|
|
|
|
}
|
2013-09-16 21:12:18 -07:00
|
|
|
|
2013-03-28 21:50:10 +11:00
|
|
|
/// cs_binop with binop == and
|
2013-06-18 14:45:18 -07:00
|
|
|
#[inline]
|
2014-07-07 09:13:49 +02:00
|
|
|
pub fn cs_and(enum_nonmatch_f: EnumNonMatchCollapsedFunc,
|
2014-02-06 08:50:21 +11:00
|
|
|
cx: &mut ExtCtxt, span: Span,
|
2014-05-16 00:16:13 -07:00
|
|
|
substructure: &Substructure) -> Gc<Expr> {
|
2013-09-02 03:45:37 +02:00
|
|
|
cs_binop(ast::BiAnd, cx.expr_bool(span, true),
|
2013-03-28 21:50:10 +11:00
|
|
|
enum_nonmatch_f,
|
|
|
|
cx, span, substructure)
|
|
|
|
}
|