use syntax::ast::{
self, BinOpKind, EnumDef, Expr, GenericParam, Generics, Ident, PatKind, VariantData
};
+
use syntax::attr;
use syntax::ext::base::{Annotatable, ExtCtxt};
use syntax::ext::build::AstBuilder;
fn visit_ty(&mut self, ty: &'a ast::Ty) {
if let ast::TyKind::Path(_, ref path) = ty.node {
if let Some(segment) = path.segments.first() {
- if self.ty_param_names.contains(&segment.identifier.name) {
+ if self.ty_param_names.contains(&segment.ident.name) {
self.types.push(P(ty.clone()));
}
}
match *item {
Annotatable::Item(ref item) => {
let is_packed = item.attrs.iter().any(|attr| {
- attr::find_repr_attrs(&cx.parse_sess.span_diagnostic, attr)
- .contains(&attr::ReprPacked)
+ for r in attr::find_repr_attrs(&cx.parse_sess.span_diagnostic, attr) {
+ if let attr::ReprPacked(_) = r {
+ return true;
+ }
+ }
+ false
});
let has_no_type_params = match item.node {
ast::ItemKind::Struct(_, ref generics) |
// if we have already handled this type, skip it
if let ast::TyKind::Path(_, ref p) = ty.node {
if p.segments.len() == 1 &&
- ty_param_names.contains(&p.segments[0].identifier.name) ||
+ ty_param_names.contains(&p.segments[0].ident.name) ||
processed_field_types.contains(&p.segments) {
continue;
};
for a in type_attrs {
for r in &attr::find_repr_attrs(diagnostic, a) {
repr_type_name = match *r {
- attr::ReprPacked | attr::ReprSimd | attr::ReprAlign(_) | attr::ReprTransparent =>
+ attr::ReprPacked(_) | attr::ReprSimd | attr::ReprAlign(_) | attr::ReprTransparent =>
continue,
attr::ReprC => "i32",
let args = {
let self_args = explicit_self.map(|explicit_self| {
ast::Arg::from_self(explicit_self,
- respan(trait_.span, keywords::SelfValue.ident()))
+ keywords::SelfValue.ident().with_span_pos(trait_.span))
});
let nonself_args = arg_types.into_iter()
.map(|(name, ty)| cx.arg(trait_.span, name, ty));
let summary = enum_def.variants
.iter()
.map(|v| {
- let ident = v.node.name;
let sp = v.span.with_ctxt(trait_.span.ctxt());
let summary = trait_.summarise_struct(cx, &v.node.data);
- (ident, sp, summary)
+ (v.node.ident, sp, summary)
})
.collect();
self.call_substructure_method(cx,
fn create_subpatterns(&self,
cx: &mut ExtCtxt,
- field_paths: Vec<ast::SpannedIdent>,
+ field_paths: Vec<ast::Ident>,
mutbl: ast::Mutability,
use_temporaries: bool)
-> Vec<P<ast::Pat>> {
for (i, struct_field) in struct_def.fields().iter().enumerate() {
let sp = struct_field.span.with_ctxt(self.span.ctxt());
let ident = cx.ident_of(&format!("{}_{}", prefix, i));
- paths.push(codemap::Spanned {
- span: sp,
- node: ident,
- });
+ paths.push(ident.with_span_pos(sp));
let val = cx.expr_path(cx.path_ident(sp, ident));
let val = if use_temporaries {
val
prefix: &str,
mutbl: ast::Mutability)
-> (P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>, &'a [ast::Attribute])>) {
- let variant_ident = variant.node.name;
let sp = variant.span.with_ctxt(self.span.ctxt());
- let variant_path = cx.path(sp, vec![enum_ident, variant_ident]);
+ let variant_path = cx.path(sp, vec![enum_ident, variant.node.ident]);
let use_temporaries = false; // enums can't be repr(packed)
self.create_struct_pattern(cx, variant_path, &variant.node.data, prefix, mutbl,
use_temporaries)
// helpful premade recipes
+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`")
+}
+
/// Fold the fields. `use_foldl` controls whether this is done
/// left-to-right (`true`) or right-to-left (`false`).
pub fn cs_fold<F>(use_foldl: bool,
- mut f: F,
+ f: F,
base: P<Expr>,
- mut enum_nonmatch_f: EnumNonMatchCollapsedFunc,
+ enum_nonmatch_f: EnumNonMatchCollapsedFunc,
cx: &mut ExtCtxt,
trait_span: Span,
substructure: &Substructure)
match *substructure.fields {
EnumMatching(.., ref all_fields) |
Struct(_, ref all_fields) => {
- 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)
- })
- }
+ cs_fold_fields(use_foldl, f, base, cx, all_fields)
}
- EnumNonMatchingCollapsed(ref all_args, _, tuple) => {
- enum_nonmatch_f(cx,
- trait_span,
- (&all_args[..], tuple),
- substructure.nonself_args)
+ EnumNonMatchingCollapsed(..) => {
+ cs_fold_enumnonmatch(enum_nonmatch_f, cx, trait_span, substructure)
+ }
+ StaticEnum(..) | StaticStruct(..) => {
+ cs_fold_static(cx, trait_span)
}
- StaticEnum(..) | StaticStruct(..) => cx.span_bug(trait_span, "static function in `derive`"),
}
}
+/// 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.
+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)
+ }
+ }
+}
/// Call the method that is being derived on all the fields, and then
/// process the collected results. i.e.