about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-11-08 08:36:08 -0800
committerbors <bors@rust-lang.org>2013-11-08 08:36:08 -0800
commita594a999fbccf04710c9dfea3ef3d231c14e1bd1 (patch)
tree7d908a83dba710322af3cde01f791a87e23234bf /src/libsyntax
parent9d8dc004a021af5807120ae9ef2854ab99350cbf (diff)
parent812ea9e169d6edcc138e334e7e2b2cb5f7ba66b3 (diff)
downloadrust-a594a999fbccf04710c9dfea3ef3d231c14e1bd1.tar.gz
rust-a594a999fbccf04710c9dfea3ef3d231c14e1bd1.zip
auto merge of #10355 : huonw/rust/deriving-field-spans, r=alexcrichton
This rearranges the deriving code so that #[deriving] a trait on a field
that doesn't implement that trait will point to the field in question,
e.g.

    struct NotEq; // doesn't implement Eq

    #[deriving(Eq)]
    struct Foo {
        ok: int,
        also_ok: ~str,
        bad: NotEq // error points here.
    }

Unfortunately, this means the error is disconnected from the `deriving`
itself but there's no current way to pass that information through to
rustc except via the spans, at the moment.

Fixes #7724.
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ext/deriving/clone.rs10
-rw-r--r--src/libsyntax/ext/deriving/decodable.rs81
-rw-r--r--src/libsyntax/ext/deriving/default.rs16
-rw-r--r--src/libsyntax/ext/deriving/encodable.rs11
-rw-r--r--src/libsyntax/ext/deriving/generic.rs471
-rw-r--r--src/libsyntax/ext/deriving/iter_bytes.rs4
-rw-r--r--src/libsyntax/ext/deriving/rand.rs22
-rw-r--r--src/libsyntax/ext/deriving/to_str.rs8
-rw-r--r--src/libsyntax/ext/deriving/zero.rs16
9 files changed, 327 insertions, 312 deletions
diff --git a/src/libsyntax/ext/deriving/clone.rs b/src/libsyntax/ext/deriving/clone.rs
index 5b107a49175..6ff39351448 100644
--- a/src/libsyntax/ext/deriving/clone.rs
+++ b/src/libsyntax/ext/deriving/clone.rs
@@ -94,21 +94,21 @@ fn cs_clone(
     }
 
     match *all_fields {
-        [(None, _, _), .. _] => {
+        [FieldInfo { name: None, _ }, .. _] => {
             // enum-like
-            let subcalls = all_fields.map(|&(_, self_f, _)| subcall(self_f));
+            let subcalls = all_fields.map(|field| subcall(field.self_));
             cx.expr_call_ident(span, ctor_ident, subcalls)
         },
         _ => {
             // struct-like
-            let fields = do all_fields.map |&(o_id, self_f, _)| {
-                let ident = match o_id {
+            let fields = do all_fields.map |field| {
+                let ident = match field.name {
                     Some(i) => i,
                     None => cx.span_bug(span,
                                         format!("unnamed field in normal struct in `deriving({})`",
                                              name))
                 };
-                cx.field_imm(span, ident, subcall(self_f))
+                cx.field_imm(span, ident, subcall(field.self_))
             };
 
             if fields.is_empty() {
diff --git a/src/libsyntax/ext/deriving/decodable.rs b/src/libsyntax/ext/deriving/decodable.rs
index 91fe71c5414..4ad835f032f 100644
--- a/src/libsyntax/ext/deriving/decodable.rs
+++ b/src/libsyntax/ext/deriving/decodable.rs
@@ -13,9 +13,7 @@ The compiler code necessary for #[deriving(Decodable)]. See
 encodable.rs for more.
 */
 
-use std::vec;
-
-use ast::{MetaItem, item, Expr, MutMutable};
+use ast::{MetaItem, item, Expr, MutMutable, Ident};
 use codemap::Span;
 use ext::base::ExtCtxt;
 use ext::build::AstBuilder;
@@ -66,37 +64,18 @@ fn decodable_substructure(cx: @ExtCtxt, span: Span,
     return match *substr.fields {
         StaticStruct(_, ref summary) => {
             let nfields = match *summary {
-                Left(n) => n, Right(ref fields) => fields.len()
+                Unnamed(ref fields) => fields.len(),
+                Named(ref fields) => fields.len()
             };
             let read_struct_field = cx.ident_of("read_struct_field");
 
-            let getarg = |name: @str, field: uint| {
+            let result = do decode_static_fields(cx, span, substr.type_ident,
+                                                 summary) |span, name, field| {
                 cx.expr_method_call(span, blkdecoder, read_struct_field,
                                     ~[cx.expr_str(span, name),
                                       cx.expr_uint(span, field),
                                       lambdadecode])
             };
-
-            let result = match *summary {
-                Left(n) => {
-                    if n == 0 {
-                        cx.expr_ident(span, substr.type_ident)
-                    } else {
-                        let mut fields = vec::with_capacity(n);
-                        for i in range(0, n) {
-                            fields.push(getarg(format!("_field{}", i).to_managed(), i));
-                        }
-                        cx.expr_call_ident(span, substr.type_ident, fields)
-                    }
-                }
-                Right(ref fields) => {
-                    let fields = do fields.iter().enumerate().map |(i, f)| {
-                        cx.field_imm(span, *f, getarg(cx.str_of(*f), i))
-                    }.collect();
-                    cx.expr_struct_ident(span, substr.type_ident, fields)
-                }
-            };
-
             cx.expr_method_call(span, decoder, cx.ident_of("read_struct"),
                                 ~[cx.expr_str(span, cx.str_of(substr.type_ident)),
                                   cx.expr_uint(span, nfields),
@@ -113,31 +92,13 @@ fn decodable_substructure(cx: @ExtCtxt, span: Span,
                 let (name, parts) = match *f { (i, ref p) => (i, p) };
                 variants.push(cx.expr_str(span, cx.str_of(name)));
 
-                let getarg = |field: uint| {
+                let decoded = do decode_static_fields(cx, span, name,
+                                                      parts) |span, _, field| {
                     cx.expr_method_call(span, blkdecoder, rvariant_arg,
                                         ~[cx.expr_uint(span, field),
                                           lambdadecode])
                 };
 
-                let decoded = match *parts {
-                    Left(n) => {
-                        if n == 0 {
-                            cx.expr_ident(span, name)
-                        } else {
-                            let mut fields = vec::with_capacity(n);
-                            for i in range(0u, n) {
-                                fields.push(getarg(i));
-                            }
-                            cx.expr_call_ident(span, name, fields)
-                        }
-                    }
-                    Right(ref fields) => {
-                        let fields = do fields.iter().enumerate().map |(i, f)| {
-                            cx.field_imm(span, *f, getarg(i))
-                        }.collect();
-                        cx.expr_struct_ident(span, name, fields)
-                    }
-                };
                 arms.push(cx.arm(span,
                                  ~[cx.pat_lit(span, cx.expr_uint(span, i))],
                                  decoded));
@@ -158,3 +119,31 @@ fn decodable_substructure(cx: @ExtCtxt, span: Span,
         _ => cx.bug("expected StaticEnum or StaticStruct in deriving(Decodable)")
     };
 }
+
+/// Create a decoder for a single enum variant/struct:
+/// - `outer_pat_ident` is the name of this enum variant/struct
+/// - `getarg` should retrieve the `uint`-th field with name `@str`.
+fn decode_static_fields(cx: @ExtCtxt, outer_span: Span, outer_pat_ident: Ident,
+                        fields: &StaticFields,
+                        getarg: &fn(Span, @str, uint) -> @Expr) -> @Expr {
+    match *fields {
+        Unnamed(ref fields) => {
+            if fields.is_empty() {
+                cx.expr_ident(outer_span, outer_pat_ident)
+            } else {
+                let fields = do fields.iter().enumerate().map |(i, &span)| {
+                    getarg(span, format!("_field{}", i).to_managed(), i)
+                }.collect();
+
+                cx.expr_call_ident(outer_span, outer_pat_ident, fields)
+            }
+        }
+        Named(ref fields) => {
+            // use the field's span to get nicer error messages.
+            let fields = do fields.iter().enumerate().map |(i, &(name, span))| {
+                cx.field_imm(span, name, getarg(span, cx.str_of(name), i))
+            }.collect();
+            cx.expr_struct_ident(outer_span, outer_pat_ident, fields)
+        }
+    }
+}
diff --git a/src/libsyntax/ext/deriving/default.rs b/src/libsyntax/ext/deriving/default.rs
index d8c78842808..6bc2b06806b 100644
--- a/src/libsyntax/ext/deriving/default.rs
+++ b/src/libsyntax/ext/deriving/default.rs
@@ -14,8 +14,6 @@ use ext::base::ExtCtxt;
 use ext::build::AstBuilder;
 use ext::deriving::generic::*;
 
-use std::vec;
-
 pub fn expand_deriving_default(cx: @ExtCtxt,
                             span: Span,
                             mitem: @MetaItem,
@@ -47,22 +45,22 @@ fn default_substructure(cx: @ExtCtxt, span: Span, substr: &Substructure) -> @Exp
         cx.ident_of("Default"),
         cx.ident_of("default")
     ];
-    let default_call = cx.expr_call_global(span, default_ident.clone(), ~[]);
+    let default_call = |span| cx.expr_call_global(span, default_ident.clone(), ~[]);
 
     return match *substr.fields {
         StaticStruct(_, ref summary) => {
             match *summary {
-                Left(count) => {
-                    if count == 0 {
+                Unnamed(ref fields) => {
+                    if fields.is_empty() {
                         cx.expr_ident(span, substr.type_ident)
                     } else {
-                        let exprs = vec::from_elem(count, default_call);
+                        let exprs = fields.map(|sp| default_call(*sp));
                         cx.expr_call_ident(span, substr.type_ident, exprs)
                     }
                 }
-                Right(ref fields) => {
-                    let default_fields = do fields.map |ident| {
-                        cx.field_imm(span, *ident, default_call)
+                Named(ref fields) => {
+                    let default_fields = do fields.map |&(ident, span)| {
+                        cx.field_imm(span, ident, default_call(span))
                     };
                     cx.expr_struct_ident(span, substr.type_ident, default_fields)
                 }
diff --git a/src/libsyntax/ext/deriving/encodable.rs b/src/libsyntax/ext/deriving/encodable.rs
index d1c436c045d..a037a4daabf 100644
--- a/src/libsyntax/ext/deriving/encodable.rs
+++ b/src/libsyntax/ext/deriving/encodable.rs
@@ -123,11 +123,11 @@ fn encodable_substructure(cx: @ExtCtxt, span: Span,
             let emit_struct_field = cx.ident_of("emit_struct_field");
             let mut stmts = ~[];
             for (i, f) in fields.iter().enumerate() {
-                let (name, val) = match *f {
-                    (Some(id), e, _) => (cx.str_of(id), e),
-                    (None, e, _) => (format!("_field{}", i).to_managed(), e)
+                let name = match f.name {
+                    Some(id) => cx.str_of(id),
+                    None => format!("_field{}", i).to_managed()
                 };
-                let enc = cx.expr_method_call(span, val, encode, ~[blkencoder]);
+                let enc = cx.expr_method_call(span, f.self_, encode, ~[blkencoder]);
                 let lambda = cx.lambda_expr_1(span, enc, blkarg);
                 let call = cx.expr_method_call(span, blkencoder,
                                                emit_struct_field,
@@ -154,8 +154,7 @@ fn encodable_substructure(cx: @ExtCtxt, span: Span,
             let emit_variant_arg = cx.ident_of("emit_enum_variant_arg");
             let mut stmts = ~[];
             for (i, f) in fields.iter().enumerate() {
-                let val = match *f { (_, e, _) => e };
-                let enc = cx.expr_method_call(span, val, encode, ~[blkencoder]);
+                let enc = cx.expr_method_call(span, f.self_, encode, ~[blkencoder]);
                 let lambda = cx.lambda_expr_1(span, enc, blkarg);
                 let call = cx.expr_method_call(span, blkencoder,
                                                emit_variant_arg,
diff --git a/src/libsyntax/ext/deriving/generic.rs b/src/libsyntax/ext/deriving/generic.rs
index 82a779546fc..cfb6048df18 100644
--- a/src/libsyntax/ext/deriving/generic.rs
+++ b/src/libsyntax/ext/deriving/generic.rs
@@ -59,7 +59,7 @@ 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
 
- ```
+~~~
 struct A { x : int }
 
 struct B(int);
@@ -72,17 +72,17 @@ enum C {
 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
-number of fields or a list of 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.
+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 `Eq` is used for in-code examples:
 
- ```
+~~~
 trait Eq {
     fn eq(&self, other: &Self);
 }
@@ -91,7 +91,7 @@ impl Eq for int {
         *self == *other
     }
 }
- ```
+~~~
 
 Some examples of the values of `SubstructureFields` follow, using the
 above `Eq`, `A`, `B` and `C`.
@@ -100,50 +100,62 @@ above `Eq`, `A`, `B` and `C`.
 
 When generating the `expr` for the `A` impl, the `SubstructureFields` is
 
- ```
-Struct(~[(Some(<ident of x>),
-         <expr for &self.x>,
-         ~[<expr for &other.x])])
- ```
+~~~
+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)`,
 
- ```
-Struct(~[(None,
+~~~
+Struct(~[FieldInfo {
+          span: <span of `int`>,
+          name: None,
           <expr for &a>
-          ~[<expr for &b>])])
- ```
+          ~[<expr for &b>]
+         }])
+~~~
 
 ## Enums
 
 When generating the `expr` for a call with `self == C0(a)` and `other
 == C0(b)`, the SubstructureFields is
 
- ```
+~~~
 EnumMatching(0, <ast::variant for C0>,
-             ~[None,
-               <expr for &a>,
-               ~[<expr for &b>]])
- ```
+             ~[FieldInfo {
+                span: <span of int>
+                name: None,
+                self_: <expr for &a>,
+                other: ~[<expr for &b>]
+              }])
+~~~
 
 For `C1 {x}` and `C1 {x}`,
 
- ```
+~~~
 EnumMatching(1, <ast::variant for C1>,
-             ~[Some(<ident of x>),
-               <expr for &self.x>,
-               ~[<expr for &other.x>]])
- ```
+             ~[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}` ,
 
- ```
+~~~
 EnumNonMatching(~[(0, <ast::variant for B0>,
-                   ~[(None, <expr for &a>)]),
+                   ~[(<span of int>, None, <expr for &a>)]),
                   (1, <ast::variant for B1>,
-                   ~[(Some(<ident of x>),
+                   ~[(<span of x>, Some(<ident of x>),
                       <expr for &other.x>)])])
- ```
+~~~
 
 (and vice versa, but with the order of the outermost list flipped.)
 
@@ -152,13 +164,13 @@ EnumNonMatching(~[(0, <ast::variant for B0>,
 A static method on the above would result in,
 
 ~~~~
-StaticStruct(<ast::struct_def of A>, Right(~[<ident of x>]))
+StaticStruct(<ast::struct_def of A>, Named(~[(<ident of x>, <span of x>)]))
 
-StaticStruct(<ast::struct_def of B>, Left(1))
+StaticStruct(<ast::struct_def of B>, Unnamed(~[<span of x>]))
 
-StaticEnum(<ast::enum_def of C>, ~[(<ident of C0>, Left(1)),
-                                   (<ident of C1>, Right(~[<ident of x>]))])
- ```
+StaticEnum(<ast::enum_def of C>, ~[(<ident of C0>, Unnamed(~[<span of int>])),
+                                   (<ident of C1>, Named(~[(<ident of x>, <span of x>)]))])
+~~~
 
 */
 
@@ -226,34 +238,50 @@ pub struct Substructure<'self> {
     fields: &'self SubstructureFields<'self>
 }
 
+/// Summary of the relevant parts of a struct/enum field.
+pub struct FieldInfo {
+    span: Span,
+    /// None for tuple structs/normal enum variants, Some for normal
+    /// structs/struct enum variants.
+    name: Option<Ident>,
+    /// The expression corresponding to this field of `self`
+    /// (specifically, a reference to it).
+    self_: @Expr,
+    /// The expressions corresponding to references to this field in
+    /// the other Self arguments.
+    other: ~[@Expr]
+}
+
+/// Fields for a static method
+pub enum StaticFields {
+    /// Tuple structs/enum variants like this
+    Unnamed(~[Span]),
+    /// Normal structs/struct variants.
+    Named(~[(Ident, Span)])
+}
+
 /// A summary of the possible sets of fields. See above for details
 /// and examples
 pub enum SubstructureFields<'self> {
-    /**
-    Vec of `(field ident, self_or_other)` where the field
-    ident is the ident of the current field (`None` for all fields in tuple
-    structs).
-    */
-    Struct(~[(Option<Ident>, @Expr, ~[@Expr])]),
-
+    Struct(~[FieldInfo]),
     /**
     Matching variants of the enum: variant index, ast::variant,
-    fields: `(field ident, self, [others])`, where the field ident is
-    only non-`None` in the case of a struct variant.
+    fields: the field name is only non-`None` in the case of a struct
+    variant.
     */
-    EnumMatching(uint, &'self ast::variant, ~[(Option<Ident>, @Expr, ~[@Expr])]),
+    EnumMatching(uint, &'self ast::variant, ~[FieldInfo]),
 
     /**
     non-matching variants of the enum, [(variant index, ast::variant,
-    [field ident, fields])] (i.e. all fields for self are in the
+    [field span, field ident, fields])] (i.e. all fields for self are in the
     first tuple, for other1 are in the second tuple, etc.)
     */
-    EnumNonMatching(&'self [(uint, ast::variant, ~[(Option<Ident>, @Expr)])]),
+    EnumNonMatching(&'self [(uint, ast::variant, ~[(Span, Option<Ident>, @Expr)])]),
 
-    /// A static method where Self is a struct
-    StaticStruct(&'self ast::struct_def, Either<uint, ~[Ident]>),
-    /// A static method where Self is an enum
-    StaticEnum(&'self ast::enum_def, ~[(Ident, Either<uint, ~[Ident]>)])
+    /// A static method where Self is a struct.
+    StaticStruct(&'self ast::struct_def, StaticFields),
+    /// A static method where Self is an enum.
+    StaticEnum(&'self ast::enum_def, ~[(Ident, StaticFields)])
 }
 
 
@@ -273,13 +301,13 @@ representing each variant: (variant index, ast::variant instance,
 pub type EnumNonMatchFunc<'self> =
     &'self fn(@ExtCtxt, Span,
               &[(uint, ast::variant,
-                 ~[(Option<Ident>, @Expr)])],
+                 ~[(Span, Option<Ident>, @Expr)])],
               &[@Expr]) -> @Expr;
 
 
 impl<'self> TraitDef<'self> {
     pub fn expand(&self, cx: @ExtCtxt,
-                  span: Span,
+                  trait_span: Span,
                   _mitem: @ast::MetaItem,
                   in_items: ~[@ast::item]) -> ~[@ast::item] {
         let mut result = ~[];
@@ -287,13 +315,13 @@ impl<'self> TraitDef<'self> {
             result.push(*item);
             match item.node {
                 ast::item_struct(struct_def, ref generics) => {
-                    result.push(self.expand_struct_def(cx, span,
+                    result.push(self.expand_struct_def(cx, trait_span,
                                                        struct_def,
                                                        item.ident,
                                                        generics));
                 }
                 ast::item_enum(ref enum_def, ref generics) => {
-                    result.push(self.expand_enum_def(cx, span,
+                    result.push(self.expand_enum_def(cx, trait_span,
                                                      enum_def,
                                                      item.ident,
                                                      generics));
@@ -314,12 +342,12 @@ impl<'self> TraitDef<'self> {
      * where B1, B2, ... are the bounds given by `bounds_paths`.'
      *
      */
-    fn create_derived_impl(&self, cx: @ExtCtxt, span: Span,
+    fn create_derived_impl(&self, cx: @ExtCtxt, trait_span: Span,
                            type_ident: Ident, generics: &Generics,
                            methods: ~[@ast::method]) -> @ast::item {
-        let trait_path = self.path.to_path(cx, span, type_ident, generics);
+        let trait_path = self.path.to_path(cx, trait_span, type_ident, generics);
 
-        let mut trait_generics = self.generics.to_generics(cx, span, type_ident, generics);
+        let mut trait_generics = self.generics.to_generics(cx, trait_span, type_ident, generics);
         // Copy the lifetimes
         for l in generics.lifetimes.iter() {
             trait_generics.lifetimes.push(*l)
@@ -331,7 +359,7 @@ impl<'self> TraitDef<'self> {
             let mut bounds = opt_vec::from(
                 // extra restrictions on the generics parameters to the type being derived upon
                 do self.additional_bounds.map |p| {
-                    cx.typarambound(p.to_path(cx, span, type_ident, generics))
+                    cx.typarambound(p.to_path(cx, trait_span, type_ident, generics))
                 });
             // require the current trait
             bounds.push(cx.typarambound(trait_path.clone()));
@@ -344,7 +372,7 @@ impl<'self> TraitDef<'self> {
 
         // Create the type parameters on the `self` path.
         let self_ty_params = do generics.ty_params.map |ty_param| {
-            cx.ty_ident(span, ty_param.ident)
+            cx.ty_ident(trait_span, ty_param.ident)
         };
 
         let self_lifetime = if generics.lifetimes.is_empty() {
@@ -354,16 +382,16 @@ impl<'self> TraitDef<'self> {
         };
 
         // Create the type of `self`.
-        let self_type = cx.ty_path(cx.path_all(span, false, ~[ type_ident ], self_lifetime,
+        let self_type = cx.ty_path(cx.path_all(trait_span, false, ~[ type_ident ], self_lifetime,
                                                opt_vec::take_vec(self_ty_params)), None);
 
         let doc_attr = cx.attribute(
-            span,
-            cx.meta_name_value(span,
+            trait_span,
+            cx.meta_name_value(trait_span,
                                @"doc",
                                ast::lit_str(@"Automatically derived.", ast::CookedStr)));
         cx.item(
-            span,
+            trait_span,
             ::parse::token::special_idents::clownshoes_extensions,
             ~[doc_attr],
             ast::item_impl(trait_generics,
@@ -373,72 +401,72 @@ impl<'self> TraitDef<'self> {
     }
 
     fn expand_struct_def(&self, cx: @ExtCtxt,
-                         span: Span,
+                         trait_span: Span,
                          struct_def: &struct_def,
                          type_ident: Ident,
                          generics: &Generics) -> @ast::item {
         let methods = do self.methods.map |method_def| {
             let (explicit_self, self_args, nonself_args, tys) =
-                method_def.split_self_nonself_args(cx, span, type_ident, generics);
+                method_def.split_self_nonself_args(cx, trait_span, type_ident, generics);
 
             let body = if method_def.is_static() {
                 method_def.expand_static_struct_method_body(
-                    cx, span,
+                    cx, trait_span,
                     struct_def,
                     type_ident,
                     self_args, nonself_args)
             } else {
-                method_def.expand_struct_method_body(cx, span,
+                method_def.expand_struct_method_body(cx, trait_span,
                                                      struct_def,
                                                      type_ident,
                                                      self_args, nonself_args)
             };
 
-            method_def.create_method(cx, span,
+            method_def.create_method(cx, trait_span,
                                      type_ident, generics,
                                      explicit_self, tys,
                                      body)
         };
 
-        self.create_derived_impl(cx, span, type_ident, generics, methods)
+        self.create_derived_impl(cx, trait_span, type_ident, generics, methods)
     }
 
     fn expand_enum_def(&self,
-                       cx: @ExtCtxt, span: Span,
+                       cx: @ExtCtxt, trait_span: Span,
                        enum_def: &enum_def,
                        type_ident: Ident,
                        generics: &Generics) -> @ast::item {
         let methods = do self.methods.map |method_def| {
             let (explicit_self, self_args, nonself_args, tys) =
-                method_def.split_self_nonself_args(cx, span, type_ident, generics);
+                method_def.split_self_nonself_args(cx, trait_span, type_ident, generics);
 
             let body = if method_def.is_static() {
                 method_def.expand_static_enum_method_body(
-                    cx, span,
+                    cx, trait_span,
                     enum_def,
                     type_ident,
                     self_args, nonself_args)
             } else {
-                method_def.expand_enum_method_body(cx, span,
+                method_def.expand_enum_method_body(cx, trait_span,
                                                    enum_def,
                                                    type_ident,
                                                    self_args, nonself_args)
             };
 
-            method_def.create_method(cx, span,
+            method_def.create_method(cx, trait_span,
                                      type_ident, generics,
                                      explicit_self, tys,
                                      body)
         };
 
-        self.create_derived_impl(cx, span, type_ident, generics, methods)
+        self.create_derived_impl(cx, trait_span, type_ident, generics, methods)
     }
 }
 
 impl<'self> MethodDef<'self> {
     fn call_substructure_method(&self,
                                 cx: @ExtCtxt,
-                                span: Span,
+                                trait_span: Span,
                                 type_ident: Ident,
                                 self_args: &[@Expr],
                                 nonself_args: &[@Expr],
@@ -451,21 +479,21 @@ impl<'self> MethodDef<'self> {
             nonself_args: nonself_args,
             fields: fields
         };
-        (self.combine_substructure)(cx, span,
+        (self.combine_substructure)(cx, trait_span,
                                     &substructure)
     }
 
-    fn get_ret_ty(&self, cx: @ExtCtxt, span: Span,
-                     generics: &Generics, type_ident: Ident) -> ast::Ty {
-        self.ret_ty.to_ty(cx, span, type_ident, generics)
+    fn get_ret_ty(&self, cx: @ExtCtxt, trait_span: Span,
+                  generics: &Generics, type_ident: Ident) -> ast::Ty {
+        self.ret_ty.to_ty(cx, trait_span, type_ident, generics)
     }
 
     fn is_static(&self) -> bool {
         self.explicit_self.is_none()
     }
 
-    fn split_self_nonself_args(&self, cx: @ExtCtxt, span: Span,
-                             type_ident: Ident, generics: &Generics)
+    fn split_self_nonself_args(&self, cx: @ExtCtxt, trait_span: Span,
+                               type_ident: Ident, generics: &Generics)
         -> (ast::explicit_self, ~[@Expr], ~[@Expr], ~[(Ident, ast::Ty)]) {
 
         let mut self_args = ~[];
@@ -475,22 +503,22 @@ impl<'self> MethodDef<'self> {
 
         let ast_explicit_self = match self.explicit_self {
             Some(ref self_ptr) => {
-                let (self_expr, explicit_self) = ty::get_explicit_self(cx, span, self_ptr);
+                let (self_expr, explicit_self) = ty::get_explicit_self(cx, trait_span, self_ptr);
 
                 self_args.push(self_expr);
                 nonstatic = true;
 
                 explicit_self
             }
-            None => respan(span, ast::sty_static),
+            None => respan(trait_span, ast::sty_static),
         };
 
         for (i, ty) in self.args.iter().enumerate() {
-            let ast_ty = ty.to_ty(cx, span, type_ident, generics);
+            let ast_ty = ty.to_ty(cx, trait_span, type_ident, generics);
             let ident = cx.ident_of(format!("__arg_{}", i));
             arg_tys.push((ident, ast_ty));
 
-            let arg_expr = cx.expr_ident(span, ident);
+            let arg_expr = cx.expr_ident(trait_span, ident);
 
             match *ty {
                 // for static methods, just treat any Self
@@ -499,7 +527,7 @@ impl<'self> MethodDef<'self> {
                     self_args.push(arg_expr);
                 }
                 Ptr(~Self, _) if nonstatic => {
-                    self_args.push(cx.expr_deref(span, arg_expr))
+                    self_args.push(cx.expr_deref(trait_span, arg_expr))
                 }
                 _ => {
                     nonself_args.push(arg_expr);
@@ -510,20 +538,20 @@ impl<'self> MethodDef<'self> {
         (ast_explicit_self, self_args, nonself_args, arg_tys)
     }
 
-    fn create_method(&self, cx: @ExtCtxt, span: Span,
+    fn create_method(&self, cx: @ExtCtxt, trait_span: Span,
                      type_ident: Ident,
                      generics: &Generics,
                      explicit_self: ast::explicit_self,
                      arg_types: ~[(Ident, ast::Ty)],
                      body: @Expr) -> @ast::method {
         // create the generics that aren't for Self
-        let fn_generics = self.generics.to_generics(cx, span, type_ident, generics);
+        let fn_generics = self.generics.to_generics(cx, trait_span, type_ident, generics);
 
-        let args = do arg_types.map |pair| {
-            cx.arg(span, pair.first(), pair.second())
-        };
+        let args = do arg_types.move_iter().map |(name, ty)| {
+            cx.arg(trait_span, name, ty)
+        }.collect();
 
-        let ret_type = self.get_ret_ty(cx, span, generics, type_ident);
+        let ret_type = self.get_ret_ty(cx, trait_span, generics, type_ident);
 
         let method_ident = cx.ident_of(self.name);
         let fn_decl = cx.fn_decl(args, ret_type);
@@ -540,14 +568,14 @@ impl<'self> MethodDef<'self> {
             decl: fn_decl,
             body: body_block,
             id: ast::DUMMY_NODE_ID,
-            span: span,
+            span: trait_span,
             self_id: ast::DUMMY_NODE_ID,
             vis: ast::inherited,
         }
     }
 
     /**
-    ```
+   ~~~
     #[deriving(Eq)]
     struct A { x: int, y: int }
 
@@ -565,11 +593,11 @@ impl<'self> MethodDef<'self> {
             }
         }
     }
-    ```
+   ~~~
     */
     fn expand_struct_method_body(&self,
                                  cx: @ExtCtxt,
-                                 span: Span,
+                                 trait_span: Span,
                                  struct_def: &struct_def,
                                  type_ident: Ident,
                                  self_args: &[@Expr],
@@ -580,7 +608,7 @@ impl<'self> MethodDef<'self> {
                                  // [fields of next Self arg], [etc]]
         let mut patterns = ~[];
         for i in range(0u, self_args.len()) {
-            let (pat, ident_expr) = create_struct_pattern(cx, span,
+            let (pat, ident_expr) = create_struct_pattern(cx, trait_span,
                                                           type_ident, struct_def,
                                                           format!("__self_{}", i),
                                                           ast::MutImmutable);
@@ -591,22 +619,27 @@ impl<'self> MethodDef<'self> {
         // transpose raw_fields
         let fields = match raw_fields {
             [ref self_arg, .. rest] => {
-                do self_arg.iter().enumerate().map |(i, &(opt_id, field))| {
+                do self_arg.iter().enumerate().map |(i, &(span, opt_id, field))| {
                     let other_fields = do rest.map |l| {
                         match &l[i] {
-                            &(_, ex) => ex
+                            &(_, _, ex) => ex
                         }
                     };
-                    (opt_id, field, other_fields)
+                    FieldInfo {
+                        span: span,
+                        name: opt_id,
+                        self_: field,
+                        other: other_fields
+                    }
                 }.collect()
             }
-            [] => { cx.span_bug(span, "No self arguments to non-static \
+            [] => { cx.span_bug(trait_span, "No self arguments to non-static \
                                        method in generic `deriving`") }
         };
 
         // body of the inner most destructuring match
         let mut body = self.call_substructure_method(
-            cx, span,
+            cx, trait_span,
             type_ident,
             self_args,
             nonself_args,
@@ -616,30 +649,30 @@ impl<'self> MethodDef<'self> {
         // structs. This is actually right-to-left, but it shoudn't
         // matter.
         for (&arg_expr, &pat) in self_args.iter().zip(patterns.iter()) {
-            body = cx.expr_match(span, arg_expr,
-                                 ~[ cx.arm(span, ~[pat], body) ])
+            body = cx.expr_match(trait_span, arg_expr,
+                                 ~[ cx.arm(trait_span, ~[pat], body) ])
         }
         body
     }
 
     fn expand_static_struct_method_body(&self,
                                         cx: @ExtCtxt,
-                                        span: Span,
+                                        trait_span: Span,
                                         struct_def: &struct_def,
                                         type_ident: Ident,
                                         self_args: &[@Expr],
                                         nonself_args: &[@Expr])
         -> @Expr {
-        let summary = summarise_struct(cx, span, struct_def);
+        let summary = summarise_struct(cx, trait_span, struct_def);
 
-        self.call_substructure_method(cx, span,
+        self.call_substructure_method(cx, trait_span,
                                       type_ident,
                                       self_args, nonself_args,
                                       &StaticStruct(struct_def, summary))
     }
 
     /**
-    ```
+   ~~~
     #[deriving(Eq)]
     enum A {
         A1
@@ -662,18 +695,18 @@ impl<'self> MethodDef<'self> {
             }
         }
     }
-    ```
+   ~~~
     */
     fn expand_enum_method_body(&self,
                                cx: @ExtCtxt,
-                               span: Span,
+                               trait_span: Span,
                                enum_def: &enum_def,
                                type_ident: Ident,
                                self_args: &[@Expr],
                                nonself_args: &[@Expr])
         -> @Expr {
         let mut matches = ~[];
-        self.build_enum_match(cx, span, enum_def, type_ident,
+        self.build_enum_match(cx, trait_span, enum_def, type_ident,
                               self_args, nonself_args,
                               None, &mut matches, 0)
     }
@@ -682,13 +715,13 @@ impl<'self> MethodDef<'self> {
     /**
     Creates the nested matches for an enum definition recursively, i.e.
 
-    ```
+   ~~~
     match self {
        Variant1 => match other { Variant1 => matching, Variant2 => nonmatching, ... },
        Variant2 => match other { Variant1 => nonmatching, Variant2 => matching, ... },
        ...
     }
-    ```
+   ~~~
 
     It acts in the most naive way, so every branch (and subbranch,
     subsubbranch, etc) exists, not just the ones where all the variants in
@@ -701,20 +734,20 @@ impl<'self> MethodDef<'self> {
     the first call).
     */
     fn build_enum_match(&self,
-                        cx: @ExtCtxt, span: Span,
+                        cx: @ExtCtxt, trait_span: Span,
                         enum_def: &enum_def,
                         type_ident: Ident,
                         self_args: &[@Expr],
                         nonself_args: &[@Expr],
                         matching: Option<uint>,
                         matches_so_far: &mut ~[(uint, ast::variant,
-                                              ~[(Option<Ident>, @Expr)])],
+                                              ~[(Span, Option<Ident>, @Expr)])],
                         match_count: uint) -> @Expr {
         if match_count == self_args.len() {
             // we've matched against all arguments, so make the final
             // expression at the bottom of the match tree
             if matches_so_far.len() == 0 {
-                cx.span_bug(span, "no self match on an enum in generic \
+                cx.span_bug(trait_span, "no self match on an enum in generic \
                                    `deriving`");
             }
             // we currently have a vec of vecs, where each
@@ -742,8 +775,8 @@ impl<'self> MethodDef<'self> {
                     for triple in matches_so_far.tail().iter() {
                         match triple {
                             &(_, _, ref other_fields) => {
-                                for (i, pair) in other_fields.iter().enumerate() {
-                                    enum_matching_fields[i].push(pair.second());
+                                for (i, &(_, _, e)) in other_fields.iter().enumerate() {
+                                    enum_matching_fields[i].push(e);
                                 }
                             }
                         }
@@ -751,8 +784,13 @@ impl<'self> MethodDef<'self> {
                     let field_tuples =
                         do self_vec.iter()
                            .zip(enum_matching_fields.iter())
-                           .map |(&(id, self_f), other)| {
-                        (id, self_f, (*other).clone())
+                           .map |(&(span, id, self_f), other)| {
+                        FieldInfo {
+                            span: span,
+                            name: id,
+                            self_: self_f,
+                            other: (*other).clone()
+                        }
                     }.collect();
                     substructure = EnumMatching(variant_index, variant, field_tuples);
                 }
@@ -760,7 +798,7 @@ impl<'self> MethodDef<'self> {
                     substructure = EnumNonMatching(*matches_so_far);
                 }
             }
-            self.call_substructure_method(cx, span, type_ident,
+            self.call_substructure_method(cx, trait_span, type_ident,
                                           self_args, nonself_args,
                                           &substructure)
 
@@ -779,13 +817,14 @@ impl<'self> MethodDef<'self> {
                 // make a matching-variant match, and a _ match.
                 let index = match matching {
                     Some(i) => i,
-                    None => cx.span_bug(span, "Non-matching variants when required to \
-                                               be matching in generic `deriving`")
+                    None => cx.span_bug(trait_span,
+                                        "Non-matching variants when required to \
+                                        be matching in generic `deriving`")
                 };
 
                 // matching-variant match
                 let variant = &enum_def.variants[index];
-                let (pattern, idents) = create_enum_variant_pattern(cx, span,
+                let (pattern, idents) = create_enum_variant_pattern(cx,
                                                                     variant,
                                                                     current_match_str,
                                                                     ast::MutImmutable);
@@ -793,7 +832,7 @@ impl<'self> MethodDef<'self> {
                 matches_so_far.push((index,
                                      /*bad*/ (*variant).clone(),
                                      idents));
-                let arm_expr = self.build_enum_match(cx, span,
+                let arm_expr = self.build_enum_match(cx, trait_span,
                                                      enum_def,
                                                      type_ident,
                                                      self_args, nonself_args,
@@ -801,25 +840,25 @@ impl<'self> MethodDef<'self> {
                                                      matches_so_far,
                                                      match_count + 1);
                 matches_so_far.pop();
-                arms.push(cx.arm(span, ~[ pattern ], arm_expr));
+                arms.push(cx.arm(trait_span, ~[ pattern ], arm_expr));
 
                 if enum_def.variants.len() > 1 {
                     let e = &EnumNonMatching(&[]);
-                    let wild_expr = self.call_substructure_method(cx, span, type_ident,
+                    let wild_expr = self.call_substructure_method(cx, trait_span, type_ident,
                                                                   self_args, nonself_args,
                                                                   e);
-                    let wild_arm = cx.arm(span,
-                                          ~[ cx.pat_wild(span) ],
+                    let wild_arm = cx.arm(trait_span,
+                                          ~[ cx.pat_wild(trait_span) ],
                                           wild_expr);
                     arms.push(wild_arm);
                 }
             } else {
                 // create an arm matching on each variant
                 for (index, variant) in enum_def.variants.iter().enumerate() {
-                    let (pattern, idents) = create_enum_variant_pattern(cx, span,
-                                                                       variant,
-                                                                       current_match_str,
-                                                                       ast::MutImmutable);
+                    let (pattern, idents) = create_enum_variant_pattern(cx,
+                                                                        variant,
+                                                                        current_match_str,
+                                                                        ast::MutImmutable);
 
                     matches_so_far.push((index,
                                          /*bad*/ (*variant).clone(),
@@ -830,7 +869,7 @@ impl<'self> MethodDef<'self> {
                             Some(i) if index == i => Some(i),
                             _ => None
                         };
-                    let arm_expr = self.build_enum_match(cx, span,
+                    let arm_expr = self.build_enum_match(cx, trait_span,
                                                          enum_def,
                                                          type_ident,
                                                          self_args, nonself_args,
@@ -839,70 +878,69 @@ impl<'self> MethodDef<'self> {
                                                          match_count + 1);
                     matches_so_far.pop();
 
-                    let arm = cx.arm(span, ~[ pattern ], arm_expr);
+                    let arm = cx.arm(trait_span, ~[ pattern ], arm_expr);
                     arms.push(arm);
                 }
             }
 
             // match foo { arm, arm, arm, ... }
-            cx.expr_match(span, self_args[match_count], arms)
+            cx.expr_match(trait_span, self_args[match_count], arms)
         }
     }
 
     fn expand_static_enum_method_body(&self,
-                               cx: @ExtCtxt,
-                               span: Span,
-                               enum_def: &enum_def,
-                               type_ident: Ident,
-                               self_args: &[@Expr],
-                               nonself_args: &[@Expr])
+                                      cx: @ExtCtxt,
+                                      trait_span: Span,
+                                      enum_def: &enum_def,
+                                      type_ident: Ident,
+                                      self_args: &[@Expr],
+                                      nonself_args: &[@Expr])
         -> @Expr {
         let summary = do enum_def.variants.map |v| {
             let ident = v.node.name;
             let summary = match v.node.kind {
-                ast::tuple_variant_kind(ref args) => Left(args.len()),
+                ast::tuple_variant_kind(ref args) => Unnamed(args.map(|va| va.ty.span)),
                 ast::struct_variant_kind(struct_def) => {
-                    summarise_struct(cx, span, struct_def)
+                    summarise_struct(cx, trait_span, struct_def)
                 }
             };
             (ident, summary)
         };
         self.call_substructure_method(cx,
-                                      span, type_ident,
+                                      trait_span, type_ident,
                                       self_args, nonself_args,
                                       &StaticEnum(enum_def, summary))
     }
 }
 
-fn summarise_struct(cx: @ExtCtxt, span: Span,
-                    struct_def: &struct_def) -> Either<uint, ~[Ident]> {
+fn summarise_struct(cx: @ExtCtxt, trait_span: Span,
+                    struct_def: &struct_def) -> StaticFields {
     let mut named_idents = ~[];
-    let mut unnamed_count = 0;
+    let mut just_spans = ~[];
     for field in struct_def.fields.iter() {
         match field.node.kind {
-            ast::named_field(ident, _) => named_idents.push(ident),
-            ast::unnamed_field => unnamed_count += 1,
+            ast::named_field(ident, _) => named_idents.push((ident, field.span)),
+            ast::unnamed_field => just_spans.push(field.span),
         }
     }
 
-    match (unnamed_count > 0, named_idents.is_empty()) {
-        (true, false) => cx.span_bug(span,
-                                     "A struct with named and unnamed \
+    match (just_spans.is_empty(), named_idents.is_empty()) {
+        (false, false) => cx.span_bug(trait_span,
+                                      "A struct with named and unnamed \
                                       fields in generic `deriving`"),
         // named fields
-        (_, false) => Right(named_idents),
+        (_, false) => Named(named_idents),
         // tuple structs (includes empty structs)
-        (_, _)     => Left(unnamed_count)
+        (_, _)     => Unnamed(just_spans)
     }
 }
 
 pub fn create_subpatterns(cx: @ExtCtxt,
-                          span: Span,
                           field_paths: ~[ast::Path],
                           mutbl: ast::Mutability)
                    -> ~[@ast::Pat] {
     do field_paths.map |path| {
-        cx.pat(span,
+        cx.pat(path.span,
                ast::PatIdent(ast::BindByRef(mutbl), (*path).clone(), None))
     }
 }
@@ -913,20 +951,20 @@ enum StructType {
 }
 
 fn create_struct_pattern(cx: @ExtCtxt,
-                             span: Span,
-                             struct_ident: Ident,
-                             struct_def: &struct_def,
-                             prefix: &str,
-                             mutbl: ast::Mutability)
-    -> (@ast::Pat, ~[(Option<Ident>, @Expr)]) {
+                         trait_span: Span,
+                         struct_ident: Ident,
+                         struct_def: &struct_def,
+                         prefix: &str,
+                         mutbl: ast::Mutability)
+    -> (@ast::Pat, ~[(Span, Option<Ident>, @Expr)]) {
     if struct_def.fields.is_empty() {
         return (
             cx.pat_ident_binding_mode(
-                span, struct_ident, ast::BindByValue(ast::MutImmutable)),
+                trait_span, struct_ident, ast::BindByValue(ast::MutImmutable)),
             ~[]);
     }
 
-    let matching_path = cx.path(span, ~[ struct_ident ]);
+    let matching_path = cx.path(trait_span, ~[ struct_ident ]);
 
     let mut paths = ~[];
     let mut ident_expr = ~[];
@@ -945,68 +983,67 @@ fn create_struct_pattern(cx: @ExtCtxt,
                 None
             }
             _ => {
-                cx.span_bug(span, "A struct with named and unnamed fields in `deriving`");
+                cx.span_bug(struct_field.span,
+                            "A struct with named and unnamed fields in `deriving`");
             }
         };
-        let path = cx.path_ident(span,
+        let path = cx.path_ident(struct_field.span,
                                  cx.ident_of(format!("{}_{}", prefix, i)));
         paths.push(path.clone());
-        ident_expr.push((opt_id, cx.expr_path(path)));
+        ident_expr.push((struct_field.span, opt_id, cx.expr_path(path)));
     }
 
-    let subpats = create_subpatterns(cx, span, paths, mutbl);
+    let subpats = create_subpatterns(cx, paths, mutbl);
 
     // 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 = do vec::build(None) |push| {
-            for (&pat, &(id, _)) in subpats.iter().zip(ident_expr.iter()) {
-                // id is guaranteed to be Some
-                push(ast::FieldPat { ident: id.unwrap(), pat: pat })
-            }
-        };
-        cx.pat_struct(span, matching_path, field_pats)
+        let field_pats = do 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(trait_span, matching_path, field_pats)
     } else {
-        cx.pat_enum(span, matching_path, subpats)
+        cx.pat_enum(trait_span, matching_path, subpats)
     };
 
     (pattern, ident_expr)
 }
 
 fn create_enum_variant_pattern(cx: @ExtCtxt,
-                                   span: Span,
-                                   variant: &ast::variant,
-                                   prefix: &str,
-                                   mutbl: ast::Mutability)
-    -> (@ast::Pat, ~[(Option<Ident>, @Expr)]) {
+                               variant: &ast::variant,
+                               prefix: &str,
+                               mutbl: ast::Mutability)
+    -> (@ast::Pat, ~[(Span, Option<Ident>, @Expr)]) {
 
     let variant_ident = variant.node.name;
     match variant.node.kind {
         ast::tuple_variant_kind(ref variant_args) => {
             if variant_args.is_empty() {
-                return (cx.pat_ident_binding_mode(
-                    span, variant_ident, ast::BindByValue(ast::MutImmutable)), ~[]);
+                return (cx.pat_ident_binding_mode(variant.span, variant_ident,
+                                                  ast::BindByValue(ast::MutImmutable)),
+                        ~[]);
             }
 
-            let matching_path = cx.path_ident(span, variant_ident);
+            let matching_path = cx.path_ident(variant.span, variant_ident);
 
             let mut paths = ~[];
             let mut ident_expr = ~[];
-            for i in range(0u, variant_args.len()) {
-                let path = cx.path_ident(span,
+            for (i, va) in variant_args.iter().enumerate() {
+                let path = cx.path_ident(va.ty.span,
                                          cx.ident_of(format!("{}_{}", prefix, i)));
 
                 paths.push(path.clone());
-                ident_expr.push((None, cx.expr_path(path)));
+                ident_expr.push((va.ty.span, None, cx.expr_path(path)));
             }
 
-            let subpats = create_subpatterns(cx, span, paths, mutbl);
+            let subpats = create_subpatterns(cx, paths, mutbl);
 
-            (cx.pat_enum(span, matching_path, subpats),
+            (cx.pat_enum(variant.span, matching_path, subpats),
              ident_expr)
         }
         ast::struct_variant_kind(struct_def) => {
-            create_struct_pattern(cx, span,
+            create_struct_pattern(cx, variant.span,
                                   variant_ident, struct_def,
                                   prefix,
                                   mutbl)
@@ -1029,27 +1066,25 @@ pub fn cs_fold(use_foldl: bool,
                       other_fs: &[@Expr]) -> @Expr,
                base: @Expr,
                enum_nonmatch_f: EnumNonMatchFunc,
-               cx: @ExtCtxt, span: Span,
+               cx: @ExtCtxt, trait_span: Span,
                substructure: &Substructure) -> @Expr {
     match *substructure.fields {
         EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => {
             if use_foldl {
-                do all_fields.iter().fold(base) |old, triple| {
-                    let (_, self_f, other_fs) = (*triple).clone();
-                    f(cx, span, old, self_f, other_fs)
+                do all_fields.iter().fold(base) |old, field| {
+                    f(cx, field.span, old, field.self_, field.other)
                 }
             } else {
-                do all_fields.rev_iter().fold(base) |old, triple| {
-                    let (_, self_f, other_fs) = (*triple).clone();
-                    f(cx, span, old, self_f, other_fs)
+                do all_fields.rev_iter().fold(base) |old, field| {
+                    f(cx, field.span, old, field.self_, field.other)
                 }
             }
         },
-        EnumNonMatching(ref all_enums) => enum_nonmatch_f(cx, span,
+        EnumNonMatching(ref all_enums) => enum_nonmatch_f(cx, trait_span,
                                                           *all_enums,
                                                           substructure.nonself_args),
         StaticEnum(*) | StaticStruct(*) => {
-            cx.span_bug(span, "Static function in `deriving`")
+            cx.span_bug(trait_span, "Static function in `deriving`")
         }
     }
 }
@@ -1059,34 +1094,33 @@ pub fn cs_fold(use_foldl: bool,
 Call the method that is being derived on all the fields, and then
 process the collected results. i.e.
 
- ```
+~~~
 f(cx, span, ~[self_1.method(__arg_1_1, __arg_2_1),
               self_2.method(__arg_1_2, __arg_2_2)])
- ```
+~~~
 */
 #[inline]
 pub fn cs_same_method(f: &fn(@ExtCtxt, Span, ~[@Expr]) -> @Expr,
                       enum_nonmatch_f: EnumNonMatchFunc,
-                      cx: @ExtCtxt, span: Span,
+                      cx: @ExtCtxt, trait_span: Span,
                       substructure: &Substructure) -> @Expr {
     match *substructure.fields {
         EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => {
             // call self_n.method(other_1_n, other_2_n, ...)
-            let called = do all_fields.map |triple| {
-                let (_, self_field, other_fields) = (*triple).clone();
-                cx.expr_method_call(span,
-                                    self_field,
+            let called = do all_fields.map |field| {
+                cx.expr_method_call(field.span,
+                                    field.self_,
                                     substructure.method_ident,
-                                    other_fields)
+                                    field.other.clone())
             };
 
-            f(cx, span, called)
+            f(cx, trait_span, called)
         },
-        EnumNonMatching(ref all_enums) => enum_nonmatch_f(cx, span,
+        EnumNonMatching(ref all_enums) => enum_nonmatch_f(cx, trait_span,
                                                           *all_enums,
                                                           substructure.nonself_args),
         StaticEnum(*) | StaticStruct(*) => {
-            cx.span_bug(span, "Static function in `deriving`")
+            cx.span_bug(trait_span, "Static function in `deriving`")
         }
     }
 }
@@ -1101,7 +1135,7 @@ pub fn cs_same_method_fold(use_foldl: bool,
                            f: &fn(@ExtCtxt, Span, @Expr, @Expr) -> @Expr,
                            base: @Expr,
                            enum_nonmatch_f: EnumNonMatchFunc,
-                           cx: @ExtCtxt, span: Span,
+                           cx: @ExtCtxt, trait_span: Span,
                            substructure: &Substructure) -> @Expr {
     cs_same_method(
         |cx, span, vals| {
@@ -1116,8 +1150,7 @@ pub fn cs_same_method_fold(use_foldl: bool,
             }
         },
         enum_nonmatch_f,
-        cx, span, substructure)
-
+        cx, trait_span, substructure)
 }
 
 /**
@@ -1127,7 +1160,7 @@ on all the fields.
 #[inline]
 pub fn cs_binop(binop: ast::BinOp, base: @Expr,
                 enum_nonmatch_f: EnumNonMatchFunc,
-                cx: @ExtCtxt, span: Span,
+                cx: @ExtCtxt, trait_span: Span,
                 substructure: &Substructure) -> @Expr {
     cs_same_method_fold(
         true, // foldl is good enough
@@ -1139,7 +1172,7 @@ pub fn cs_binop(binop: ast::BinOp, base: @Expr,
         },
         base,
         enum_nonmatch_f,
-        cx, span, substructure)
+        cx, trait_span, substructure)
 }
 
 /// cs_binop with binop == or
diff --git a/src/libsyntax/ext/deriving/iter_bytes.rs b/src/libsyntax/ext/deriving/iter_bytes.rs
index 0f4e57b0889..82f449fc116 100644
--- a/src/libsyntax/ext/deriving/iter_bytes.rs
+++ b/src/libsyntax/ext/deriving/iter_bytes.rs
@@ -81,8 +81,8 @@ fn iter_bytes_substructure(cx: @ExtCtxt, span: Span, substr: &Substructure) -> @
         _ => cx.span_bug(span, "Impossible substructure in `deriving(IterBytes)`")
     }
 
-    for &(_, field, _) in fields.iter() {
-        exprs.push(call_iterbytes(field));
+    for &FieldInfo { self_, _ } in fields.iter() {
+        exprs.push(call_iterbytes(self_));
     }
 
     if exprs.len() == 0 {
diff --git a/src/libsyntax/ext/deriving/rand.rs b/src/libsyntax/ext/deriving/rand.rs
index 56f92246d8f..1e2a6fa2eb5 100644
--- a/src/libsyntax/ext/deriving/rand.rs
+++ b/src/libsyntax/ext/deriving/rand.rs
@@ -15,8 +15,6 @@ use ext::base::ExtCtxt;
 use ext::build::{AstBuilder};
 use ext::deriving::generic::*;
 
-use std::vec;
-
 pub fn expand_deriving_rand(cx: @ExtCtxt,
                             span: Span,
                             mitem: @MetaItem,
@@ -59,7 +57,7 @@ fn rand_substructure(cx: @ExtCtxt, span: Span, substr: &Substructure) -> @Expr {
         cx.ident_of("Rand"),
         cx.ident_of("rand")
     ];
-    let rand_call = || {
+    let rand_call = |span| {
         cx.expr_call_global(span,
                             rand_ident.clone(),
                             ~[ rng[0] ])
@@ -112,7 +110,7 @@ fn rand_substructure(cx: @ExtCtxt, span: Span, substr: &Substructure) -> @Expr {
                     (ident, ref summary) => {
                         cx.arm(span,
                                ~[ pat ],
-                               rand_thing(cx, span, ident, summary, || rand_call()))
+                               rand_thing(cx, span, ident, summary, |sp| rand_call(sp)))
                     }
                 }
             }.collect::<~[ast::Arm]>();
@@ -130,20 +128,20 @@ fn rand_substructure(cx: @ExtCtxt, span: Span, substr: &Substructure) -> @Expr {
 
     fn rand_thing(cx: @ExtCtxt, span: Span,
                   ctor_ident: Ident,
-                  summary: &Either<uint, ~[Ident]>,
-                  rand_call: &fn() -> @Expr) -> @Expr {
+                  summary: &StaticFields,
+                  rand_call: &fn(Span) -> @Expr) -> @Expr {
         match *summary {
-            Left(count) => {
-                if count == 0 {
+            Unnamed(ref fields) => {
+                if fields.is_empty() {
                     cx.expr_ident(span, ctor_ident)
                 } else {
-                    let exprs = vec::from_fn(count, |_| rand_call());
+                    let exprs = fields.map(|span| rand_call(*span));
                     cx.expr_call_ident(span, ctor_ident, exprs)
                 }
             }
-            Right(ref fields) => {
-                let rand_fields = do fields.map |ident| {
-                    cx.field_imm(span, *ident, rand_call())
+            Named(ref fields) => {
+                let rand_fields = do fields.map |&(ident, span)| {
+                    cx.field_imm(span, ident, rand_call(span))
                 };
                 cx.expr_struct_ident(span, ctor_ident, rand_fields)
             }
diff --git a/src/libsyntax/ext/deriving/to_str.rs b/src/libsyntax/ext/deriving/to_str.rs
index 77dbafa5ad7..69e5ce566f4 100644
--- a/src/libsyntax/ext/deriving/to_str.rs
+++ b/src/libsyntax/ext/deriving/to_str.rs
@@ -49,7 +49,7 @@ fn to_str_substructure(cx: @ExtCtxt, span: Span,
     let to_str = cx.ident_of("to_str");
 
     let doit = |start: &str, end: @str, name: ast::Ident,
-                fields: &[(Option<ast::Ident>, @Expr, ~[@Expr])]| {
+                fields: &[FieldInfo]| {
         if fields.len() == 0 {
             cx.expr_str_uniq(span, cx.str_of(name))
         } else {
@@ -65,7 +65,7 @@ fn to_str_substructure(cx: @ExtCtxt, span: Span,
                 stmts.push(cx.stmt_expr(call));
             };
 
-            for (i, &(name, e, _)) in fields.iter().enumerate() {
+            for (i, &FieldInfo {name, span, self_, _}) in fields.iter().enumerate() {
                 if i > 0 {
                     push(cx.expr_str(span, @", "));
                 }
@@ -76,7 +76,7 @@ fn to_str_substructure(cx: @ExtCtxt, span: Span,
                         push(cx.expr_str(span, name.to_managed()));
                     }
                 }
-                push(cx.expr_method_call(span, e, to_str, ~[]));
+                push(cx.expr_method_call(span, self_, to_str, ~[]));
             }
             push(cx.expr_str(span, end));
 
@@ -86,7 +86,7 @@ fn to_str_substructure(cx: @ExtCtxt, span: Span,
 
     return match *substr.fields {
         Struct(ref fields) => {
-            if fields.len() == 0 || fields[0].n0_ref().is_none() {
+            if fields.len() == 0 || fields[0].name.is_none() {
                 doit("(", @")", substr.type_ident, *fields)
             } else {
                 doit("{", @"}", substr.type_ident, *fields)
diff --git a/src/libsyntax/ext/deriving/zero.rs b/src/libsyntax/ext/deriving/zero.rs
index 2546cfc2e39..827491ad8cb 100644
--- a/src/libsyntax/ext/deriving/zero.rs
+++ b/src/libsyntax/ext/deriving/zero.rs
@@ -14,8 +14,6 @@ use ext::base::ExtCtxt;
 use ext::build::AstBuilder;
 use ext::deriving::generic::*;
 
-use std::vec;
-
 pub fn expand_deriving_zero(cx: @ExtCtxt,
                             span: Span,
                             mitem: @MetaItem,
@@ -62,22 +60,22 @@ fn zero_substructure(cx: @ExtCtxt, span: Span, substr: &Substructure) -> @Expr {
         cx.ident_of("Zero"),
         cx.ident_of("zero")
     ];
-    let zero_call = cx.expr_call_global(span, zero_ident.clone(), ~[]);
+    let zero_call = |span| cx.expr_call_global(span, zero_ident.clone(), ~[]);
 
     return match *substr.fields {
         StaticStruct(_, ref summary) => {
             match *summary {
-                Left(count) => {
-                    if count == 0 {
+                Unnamed(ref fields) => {
+                    if fields.is_empty() {
                         cx.expr_ident(span, substr.type_ident)
                     } else {
-                        let exprs = vec::from_elem(count, zero_call);
+                        let exprs = fields.map(|sp| zero_call(*sp));
                         cx.expr_call_ident(span, substr.type_ident, exprs)
                     }
                 }
-                Right(ref fields) => {
-                    let zero_fields = do fields.map |ident| {
-                        cx.field_imm(span, *ident, zero_call)
+                Named(ref fields) => {
+                    let zero_fields = do fields.map |&(ident, span)| {
+                        cx.field_imm(span, ident, zero_call(span))
                     };
                     cx.expr_struct_ident(span, substr.type_ident, zero_fields)
                 }