about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorHuon Wilson <dbau.pp+github@gmail.com>2013-03-31 01:58:05 +1100
committerHuon Wilson <dbau.pp+github@gmail.com>2013-04-12 17:10:27 +1000
commit7906c5572a8c4c5c0f6aa6e69bb63d64de50d697 (patch)
treec60b9e98a0bd0bbc5198ce74ac7c0d9b6b3217c5 /src/libsyntax
parent85b82c763bfbfd5de59f4c6b026dca58f3ba4687 (diff)
downloadrust-7906c5572a8c4c5c0f6aa6e69bb63d64de50d697.tar.gz
rust-7906c5572a8c4c5c0f6aa6e69bb63d64de50d697.zip
libsyntax: derive Clone, Eq, TotalEq, Ord, TotalOrd with the new generic deriving code.
Closes #4269, #5588 and #5589.
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ext/deriving/clone.rs322
-rw-r--r--src/libsyntax/ext/deriving/cmp/eq.rs65
-rw-r--r--src/libsyntax/ext/deriving/cmp/ord.rs142
-rw-r--r--src/libsyntax/ext/deriving/cmp/totaleq.rs45
-rw-r--r--src/libsyntax/ext/deriving/cmp/totalord.rs77
-rw-r--r--src/libsyntax/ext/deriving/eq.rs500
-rw-r--r--src/libsyntax/ext/deriving/mod.rs21
7 files changed, 411 insertions, 761 deletions
diff --git a/src/libsyntax/ext/deriving/clone.rs b/src/libsyntax/ext/deriving/clone.rs
index 390b72da331..0c62566702d 100644
--- a/src/libsyntax/ext/deriving/clone.rs
+++ b/src/libsyntax/ext/deriving/clone.rs
@@ -8,29 +8,35 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use core::prelude::*;
-
-use ast;
-use ast::*;
+use ast::{meta_item, item, expr};
+use codemap::span;
 use ext::base::ext_ctxt;
 use ext::build;
-use ext::deriving::*;
-use codemap::{span, spanned};
-use ast_util;
-use opt_vec;
+use ext::deriving::generic::*;
+use core::option::{None,Some};
 
-use core::uint;
 
 pub fn expand_deriving_clone(cx: @ext_ctxt,
                              span: span,
-                             _: @meta_item,
+                             mitem: @meta_item,
                              in_items: ~[@item])
                           -> ~[@item] {
-    expand_deriving(cx,
-                    span,
-                    in_items,
-                    expand_deriving_clone_struct_def,
-                    expand_deriving_clone_enum_def)
+    let trait_def = TraitDef {
+        path: ~[~"core", ~"clone", ~"Clone"],
+        additional_bounds: ~[],
+        methods: ~[
+            MethodDef {
+                name: ~"clone",
+                nargs: 0,
+                output_type: None, // return Self
+                combine_substructure: cs_clone
+            }
+        ]
+    };
+
+    expand_deriving_generic(cx, span,
+                            mitem, in_items,
+                            &trait_def)
 }
 
 pub fn expand_deriving_obsolete(cx: @ext_ctxt,
@@ -42,252 +48,52 @@ pub fn expand_deriving_obsolete(cx: @ext_ctxt,
     in_items
 }
 
-fn create_derived_clone_impl(cx: @ext_ctxt,
-                             span: span,
-                             type_ident: ident,
-                             generics: &Generics,
-                             method: @method)
-                          -> @item {
-    let methods = [ method ];
-    let trait_path = ~[
-        cx.ident_of(~"core"),
-        cx.ident_of(~"clone"),
-        cx.ident_of(~"Clone"),
-    ];
-    let trait_path = build::mk_raw_path_global(span, trait_path);
-    create_derived_impl(cx, span, type_ident, generics, methods, trait_path,
-                        opt_vec::Empty, opt_vec::Empty)
-}
-// Creates a method from the given expression conforming to the signature of
-// the `clone` method.
-fn create_clone_method(cx: @ext_ctxt,
-                       span: span,
-                       +type_ident: ast::ident,
-                       generics: &Generics,
-                       expr: @ast::expr)
-                    -> @method {
-    // Create the type parameters of the return value.
-    let mut output_ty_params = ~[];
-    for generics.ty_params.each |ty_param| {
-        let path = build::mk_ty_path(cx, span, ~[ ty_param.ident ]);
-        output_ty_params.push(path);
-    }
-
-    // Create the type of the return value.
-    let output_type_path = build::mk_raw_path_(span,
-                                               ~[ type_ident ],
-                                               output_ty_params);
-    let output_type = ast::ty_path(output_type_path, cx.next_id());
-    let output_type = @ast::Ty {
-        id: cx.next_id(),
-        node: output_type,
-        span: span
-    };
-
-    // Create the function declaration.
-    let fn_decl = build::mk_fn_decl(~[], output_type);
-
-    // Create the body block.
-    let body_block = build::mk_simple_block(cx, span, expr);
-
-    // Create the self type and method identifier.
-    let self_ty = spanned { node: sty_region(None, m_imm), span: span };
-    let method_ident = cx.ident_of(~"clone");
-
-    // Create the method.
-    @ast::method {
-        ident: method_ident,
-        attrs: ~[],
-        generics: ast_util::empty_generics(),
-        self_ty: self_ty,
-        purity: impure_fn,
-        decl: fn_decl,
-        body: body_block,
-        id: cx.next_id(),
-        span: span,
-        self_id: cx.next_id(),
-        vis: public,
+fn cs_clone(cx: @ext_ctxt, span: span,
+            substr: &Substructure) -> @expr {
+    let clone_ident = substr.method_ident;
+    let ctor_ident;
+    let all_fields;
+    let subcall = |field|
+        build::mk_method_call(cx, span, field, clone_ident, ~[]);
+
+    match *substr.fields {
+        Struct(af) => {
+            ctor_ident = ~[ substr.type_ident ];
+            all_fields = af;
+        }
+        EnumMatching(_, variant, af) => {
+            ctor_ident = ~[ variant.node.name ];
+            all_fields = af;
+        },
+        EnumNonMatching(*) => cx.bug("Non-matching enum variants in `deriving(Clone)`")
     }
-}
-
-fn call_substructure_clone_method(cx: @ext_ctxt,
-                                  span: span,
-                                  self_field: @expr)
-                               -> @expr {
-    // Call the substructure method.
-    let clone_ident = cx.ident_of(~"clone");
-    build::mk_method_call(cx, span,
-                          self_field, clone_ident,
-                          ~[])
-}
-
-fn expand_deriving_clone_struct_def(cx: @ext_ctxt,
-                                    span: span,
-                                    struct_def: &struct_def,
-                                    type_ident: ident,
-                                    generics: &Generics)
-                                 -> @item {
-    // Create the method.
-    let method = if !is_struct_tuple(struct_def) {
-        expand_deriving_clone_struct_method(cx,
-                                            span,
-                                            struct_def,
-                                            type_ident,
-                                            generics)
-    } else {
-        expand_deriving_clone_tuple_struct_method(cx,
-                                                  span,
-                                                  struct_def,
-                                                  type_ident,
-                                                  generics)
-    };
-
-    // Create the implementation.
-    create_derived_clone_impl(cx, span, type_ident, generics, method)
-}
-
-fn expand_deriving_clone_enum_def(cx: @ext_ctxt,
-                                  span: span,
-                                  enum_definition: &enum_def,
-                                  type_ident: ident,
-                                  generics: &Generics)
-                               -> @item {
-    // Create the method.
-    let method = expand_deriving_clone_enum_method(cx,
-                                                   span,
-                                                   enum_definition,
-                                                   type_ident,
-                                                   generics);
-
-    // Create the implementation.
-    create_derived_clone_impl(cx, span, type_ident, generics, method)
-}
-
-fn expand_deriving_clone_struct_method(cx: @ext_ctxt,
-                                       span: span,
-                                       struct_def: &struct_def,
-                                       type_ident: ident,
-                                       generics: &Generics)
-                                    -> @method {
-    let self_ident = cx.ident_of(~"self");
-
-    // Create the new fields.
-    let mut fields = ~[];
-    for struct_def.fields.each |struct_field| {
-        match struct_field.node.kind {
-            named_field(ident, _, _) => {
-                // Create the accessor for this field.
-                let self_field = build::mk_access(cx,
-                                                  span,
-                                                  ~[ self_ident ],
-                                                  ident);
 
-                // Call the substructure method.
-                let call = call_substructure_clone_method(cx,
-                                                          span,
-                                                          self_field);
-
-                let field = build::Field { ident: ident, ex: call };
-                fields.push(field);
-            }
-            unnamed_field => {
-                cx.span_bug(span, ~"unnamed fields in `deriving(Clone)`");
+    match all_fields {
+        [(None, _, _), .. _] => {
+            // enum-like
+            let subcalls = all_fields.map(|&(_, self_f, _)| subcall(self_f));
+            build::mk_call(cx, span, ctor_ident, subcalls)
+        },
+        _ => {
+            // struct-like
+            let fields = do all_fields.map |&(o_id, self_f, _)| {
+                let ident = match o_id {
+                    Some(i) => i,
+                    None => cx.span_bug(span,
+                                        ~"unnamed field in normal struct \
+                                          in `deriving(Clone)`")
+                };
+                build::Field { ident: ident, ex: subcall(self_f) }
+            };
+
+            if fields.is_empty() {
+                // no fields, so construct like `None`
+                build::mk_path(cx, span, ctor_ident)
+            } else {
+                build::mk_struct_e(cx, span,
+                                   ctor_ident,
+                                   fields)
             }
         }
     }
-
-    // Create the struct literal.
-    let struct_literal = build::mk_struct_e(cx,
-                                            span,
-                                            ~[ type_ident ],
-                                            fields);
-    create_clone_method(cx, span, type_ident, generics, struct_literal)
-}
-
-fn expand_deriving_clone_tuple_struct_method(cx: @ext_ctxt,
-                                             span: span,
-                                             struct_def: &struct_def,
-                                             type_ident: ident,
-                                             generics: &Generics)
-                                          -> @method {
-    // Create the pattern for the match.
-    let matching_path = build::mk_raw_path(span, ~[ type_ident ]);
-    let field_count = struct_def.fields.len();
-    let subpats = create_subpatterns(cx, span, ~"__self", field_count);
-    let pat = build::mk_pat_enum(cx, span, matching_path, subpats);
-
-    // Create the new fields.
-    let mut subcalls = ~[];
-    for uint::range(0, struct_def.fields.len()) |i| {
-        // Create the expression for this field.
-        let field_ident = cx.ident_of(~"__self_" + i.to_str());
-        let field = build::mk_path(cx, span, ~[ field_ident ]);
-
-        // Call the substructure method.
-        let subcall = call_substructure_clone_method(cx, span, field);
-        subcalls.push(subcall);
-    }
-
-    // Create the call to the struct constructor.
-    let call = build::mk_call(cx, span, ~[ type_ident ], subcalls);
-
-    // Create the pattern body.
-    let match_body_block = build::mk_simple_block(cx, span, call);
-
-    // Create the arm.
-    let arm = ast::arm {
-        pats: ~[ pat ],
-        guard: None,
-        body: match_body_block
-    };
-
-    // Create the method body.
-    let self_match_expr = expand_enum_or_struct_match(cx, span, ~[ arm ]);
-
-    // Create the method.
-    create_clone_method(cx, span, type_ident, generics, self_match_expr)
-}
-
-fn expand_deriving_clone_enum_method(cx: @ext_ctxt,
-                                     span: span,
-                                     enum_definition: &enum_def,
-                                     type_ident: ident,
-                                     generics: &Generics)
-                                  -> @method {
-    // Create the arms of the match in the method body.
-    let arms = do enum_definition.variants.map |variant| {
-        // Create the matching pattern.
-        let pat = create_enum_variant_pattern(cx, span, variant, ~"__self");
-
-        // Iterate over the variant arguments, creating the subcalls.
-        let mut subcalls = ~[];
-        for uint::range(0, variant_arg_count(cx, span, variant)) |j| {
-            // Create the expression for this field.
-            let field_ident = cx.ident_of(~"__self_" + j.to_str());
-            let field = build::mk_path(cx, span, ~[ field_ident ]);
-
-            // Call the substructure method.
-            let subcall = call_substructure_clone_method(cx, span, field);
-            subcalls.push(subcall);
-        }
-
-        // Create the call to the enum variant (if necessary).
-        let call = if subcalls.len() > 0 {
-            build::mk_call(cx, span, ~[ variant.node.name ], subcalls)
-        } else {
-            build::mk_path(cx, span, ~[ variant.node.name ])
-        };
-
-        // Create the pattern body.
-        let match_body_block = build::mk_simple_block(cx, span, call);
-
-        // Create the arm.
-        ast::arm { pats: ~[ pat ], guard: None, body: match_body_block }
-    };
-
-    // Create the method body.
-    let self_match_expr = expand_enum_or_struct_match(cx, span, arms);
-
-    // Create the method.
-    create_clone_method(cx, span, type_ident, generics, self_match_expr)
 }
diff --git a/src/libsyntax/ext/deriving/cmp/eq.rs b/src/libsyntax/ext/deriving/cmp/eq.rs
new file mode 100644
index 00000000000..142f0565e14
--- /dev/null
+++ b/src/libsyntax/ext/deriving/cmp/eq.rs
@@ -0,0 +1,65 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// 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.
+
+
+use ast::{meta_item, item, expr};
+use codemap::span;
+use ext::base::ext_ctxt;
+use ext::build;
+use ext::deriving::generic::*;
+
+use core::option::Some;
+
+pub fn expand_deriving_eq(cx: @ext_ctxt,
+                          span: span,
+                          mitem: @meta_item,
+                          in_items: ~[@item]) -> ~[@item] {
+    // structures are equal if all fields are equal, and non equal, if
+    // any fields are not equal or if the enum variants are different
+    fn cs_eq(cx: @ext_ctxt, span: span, substr: &Substructure) -> @expr {
+        cs_and(|cx, span, _| build::mk_bool(cx, span, false),
+                                 cx, span, substr)
+    }
+    fn cs_ne(cx: @ext_ctxt, span: span, substr: &Substructure) -> @expr {
+        cs_or(|cx, span, _| build::mk_bool(cx, span, true),
+              cx, span, substr)
+    }
+
+
+    let trait_def = TraitDef {
+        path: ~[~"core", ~"cmp", ~"Eq"],
+        additional_bounds: ~[],
+        methods: ~[
+            MethodDef {
+                name: ~"ne",
+                output_type: Some(~[~"bool"]),
+                nargs: 1,
+                combine_substructure: cs_ne
+            },
+            MethodDef {
+                name: ~"eq",
+                output_type: Some(~[~"bool"]),
+                nargs: 1,
+                combine_substructure: cs_eq
+            }
+        ]
+    };
+
+    expand_deriving_generic(cx, span, mitem, in_items,
+                            &trait_def)
+}
+
+pub fn expand_deriving_obsolete(cx: @ext_ctxt,
+                                span: span,
+                                _mitem: @meta_item,
+                                in_items: ~[@item]) -> ~[@item] {
+    cx.span_err(span, ~"`#[deriving_eq]` is obsolete; use `#[deriving(Eq)]` instead");
+    in_items
+}
diff --git a/src/libsyntax/ext/deriving/cmp/ord.rs b/src/libsyntax/ext/deriving/cmp/ord.rs
new file mode 100644
index 00000000000..7f7babab45c
--- /dev/null
+++ b/src/libsyntax/ext/deriving/cmp/ord.rs
@@ -0,0 +1,142 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// 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.
+
+
+use ast::{meta_item, item, expr_if, expr};
+use codemap::span;
+use ext::base::ext_ctxt;
+use ext::build;
+use ext::deriving::generic::*;
+use core::option::Some;
+
+macro_rules! mk_cso {
+    ($less:expr, $equal:expr) => {
+        |cx, span, substr|
+        cs_ord($less, $equal, cx, span, substr)
+    }
+}
+
+pub fn expand_deriving_ord(cx: @ext_ctxt,
+                           span: span,
+                           mitem: @meta_item,
+                           in_items: ~[@item]) -> ~[@item] {
+    let trait_def = TraitDef {
+        path: ~[~"core", ~"cmp", ~"Ord"],
+        // XXX: Ord doesn't imply Eq yet
+        additional_bounds: ~[~[~"core", ~"cmp", ~"Eq"]],
+        methods: ~[
+            MethodDef {
+                name: ~"lt",
+                output_type: Some(~[~"bool"]),
+                nargs: 1,
+                combine_substructure: mk_cso!(true, false)
+            },
+            MethodDef {
+                name: ~"le",
+                output_type: Some(~[~"bool"]),
+                nargs: 1,
+                combine_substructure: mk_cso!(true, true)
+            },
+            MethodDef {
+                name: ~"gt",
+                output_type: Some(~[~"bool"]),
+                nargs: 1,
+                combine_substructure: mk_cso!(false, false)
+            },
+            MethodDef {
+                name: ~"ge",
+                output_type: Some(~[~"bool"]),
+                nargs: 1,
+                combine_substructure: mk_cso!(false, true)
+            },
+        ]
+    };
+
+    expand_deriving_generic(cx, span, mitem, in_items,
+                            &trait_def)
+}
+
+/// `less`: is this `lt` or `le`? `equal`: is this `le` or `ge`?
+fn cs_ord(less: bool, equal: bool,
+          cx: @ext_ctxt, span: span,
+          substr: &Substructure) -> @expr {
+    let binop = if less {
+        cx.ident_of(~"lt")
+    } else {
+        cx.ident_of(~"gt")
+    };
+    let false_blk_expr = build::mk_block(cx, span,
+                                         ~[], ~[],
+                                         Some(build::mk_bool(cx, span, false)));
+    let true_blk = build::mk_simple_block(cx, span,
+                                          build::mk_bool(cx, span, true));
+    let base = build::mk_bool(cx, span, equal);
+
+    cs_fold(
+        false, // need foldr,
+        |cx, span, subexpr, self_f, other_fs| {
+            /*
+
+            build up a series of nested ifs from the inside out to get
+            lexical ordering (hence foldr), i.e.
+
+            ```
+            if self.f1 `binop` other.f1 {
+                true
+            } else if self.f1 == other.f1 {
+                if self.f2 `binop` other.f2 {
+                    true
+                } else if self.f2 == other.f2 {
+                    `equal`
+                } else {
+                    false
+                }
+            } else {
+                false
+            }
+            ```
+
+            The inner "`equal`" case is only reached if the two
+            items have all fields equal.
+            */
+            if other_fs.len() != 1 {
+                cx.span_bug(span, "Not exactly 2 arguments in `deriving(Ord)`");
+            }
+
+            let cmp = build::mk_method_call(cx, span,
+                                            self_f, cx.ident_of(~"eq"), other_fs);
+            let subexpr = build::mk_simple_block(cx, span, subexpr);
+            let elseif = expr_if(cmp, subexpr, Some(false_blk_expr));
+            let elseif = build::mk_expr(cx, span, elseif);
+
+            let cmp = build::mk_method_call(cx, span,
+                                            self_f, binop, other_fs);
+            let if_ = expr_if(cmp, true_blk, Some(elseif));
+
+            build::mk_expr(cx, span, if_)
+        },
+        base,
+        |cx, span, args| {
+            // nonmatching enums, order by the order the variants are
+            // written
+            match args {
+                [(self_var, _, _),
+                 (other_var, _, _)] =>
+                    build::mk_bool(cx, span,
+                                   if less {
+                                       self_var < other_var
+                                   } else {
+                                       self_var > other_var
+                                   }),
+                _ => cx.span_bug(span, "Not exactly 2 arguments in `deriving(Ord)`")
+            }
+        },
+        cx, span, substr)
+}
diff --git a/src/libsyntax/ext/deriving/cmp/totaleq.rs b/src/libsyntax/ext/deriving/cmp/totaleq.rs
new file mode 100644
index 00000000000..d71db22591d
--- /dev/null
+++ b/src/libsyntax/ext/deriving/cmp/totaleq.rs
@@ -0,0 +1,45 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// 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.
+
+
+use ast::{meta_item, item, expr};
+use codemap::span;
+use ext::base::ext_ctxt;
+use ext::build;
+use ext::deriving::generic::*;
+
+use core::option::Some;
+
+pub fn expand_deriving_totaleq(cx: @ext_ctxt,
+                          span: span,
+                          mitem: @meta_item,
+                          in_items: ~[@item]) -> ~[@item] {
+
+    fn cs_equals(cx: @ext_ctxt, span: span, substr: &Substructure) -> @expr {
+        cs_and(|cx, span, _| build::mk_bool(cx, span, false),
+               cx, span, substr)
+    }
+
+    let trait_def = TraitDef {
+        path: ~[~"core", ~"cmp", ~"TotalEq"],
+        additional_bounds: ~[],
+        methods: ~[
+            MethodDef {
+                name: ~"equals",
+                output_type: Some(~[~"bool"]),
+                nargs: 1,
+                combine_substructure: cs_equals
+            }
+        ]
+    };
+
+    expand_deriving_generic(cx, span, mitem, in_items,
+                            &trait_def)
+}
diff --git a/src/libsyntax/ext/deriving/cmp/totalord.rs b/src/libsyntax/ext/deriving/cmp/totalord.rs
new file mode 100644
index 00000000000..d82c63e9dd3
--- /dev/null
+++ b/src/libsyntax/ext/deriving/cmp/totalord.rs
@@ -0,0 +1,77 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// 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.
+
+use ast::{meta_item, item, expr};
+use codemap::span;
+use ext::base::ext_ctxt;
+use ext::build;
+use ext::deriving::generic::*;
+use core::cmp::{Ordering, Equal, Less, Greater};
+use core::option::Some;
+
+pub fn expand_deriving_totalord(cx: @ext_ctxt,
+                                span: span,
+                                mitem: @meta_item,
+                                in_items: ~[@item]) -> ~[@item] {
+    let trait_def = TraitDef {
+        path: ~[~"core", ~"cmp", ~"TotalOrd"],
+        additional_bounds: ~[],
+        methods: ~[
+            MethodDef {
+                name: ~"cmp",
+                output_type: Some(~[~"core", ~"cmp", ~"Ordering"]),
+                nargs: 1,
+                combine_substructure: cs_cmp
+            }
+        ]
+    };
+
+    expand_deriving_generic(cx, span, mitem, in_items,
+                            &trait_def)
+}
+
+
+pub fn ordering_const(cx: @ext_ctxt, span: span, cnst: Ordering) -> @expr {
+    let cnst = match cnst {
+        Less => ~"Less",
+        Equal => ~"Equal",
+        Greater => ~"Greater"
+    };
+    build::mk_path(cx, span,
+                   ~[cx.ident_of(~"core"),
+                     cx.ident_of(~"cmp"),
+                     cx.ident_of(cnst)])
+}
+
+pub fn cs_cmp(cx: @ext_ctxt, span: span,
+              substr: &Substructure) -> @expr {
+    let lexical_ord = ~[cx.ident_of(~"core"),
+                        cx.ident_of(~"cmp"),
+                        cx.ident_of(~"lexical_ordering")];
+
+    cs_same_method_fold(
+        // foldr (possibly) nests the matches in lexical_ordering better
+        false,
+        |cx, span, old, new| {
+            build::mk_call(cx, span, lexical_ord, ~[old, new])
+        },
+        ordering_const(cx, span, Equal),
+        |cx, span, list| {
+            match list {
+                // an earlier nonmatching variant is Less than a
+                // later one
+                [(self_var, _, _),
+                 (other_var, _, _)] => ordering_const(cx, span,
+                                                   self_var.cmp(&other_var)),
+                _ => cx.span_bug(span, "Not exactly 2 arguments in `deriving(TotalOrd)`")
+            }
+        },
+        cx, span, substr)
+}
diff --git a/src/libsyntax/ext/deriving/eq.rs b/src/libsyntax/ext/deriving/eq.rs
deleted file mode 100644
index 0afb667c69a..00000000000
--- a/src/libsyntax/ext/deriving/eq.rs
+++ /dev/null
@@ -1,500 +0,0 @@
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
-// 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.
-
-use core::prelude::*;
-
-use ast;
-use ast::*;
-use ext::base::ext_ctxt;
-use ext::build;
-use ext::deriving::*;
-use codemap::{span, spanned};
-use ast_util;
-use opt_vec;
-
-use core::uint;
-
-enum Junction {
-    Conjunction,
-    Disjunction,
-}
-
-pub impl Junction {
-    fn to_binop(self) -> binop {
-        match self {
-            Conjunction => and,
-            Disjunction => or,
-        }
-    }
-}
-
-pub fn expand_deriving_eq(cx: @ext_ctxt,
-                          span: span,
-                          _mitem: @meta_item,
-                          in_items: ~[@item])
-                       -> ~[@item] {
-    expand_deriving(cx,
-                    span,
-                    in_items,
-                    expand_deriving_eq_struct_def,
-                    expand_deriving_eq_enum_def)
-}
-
-pub fn expand_deriving_obsolete(cx: @ext_ctxt,
-                                span: span,
-                                _mitem: @meta_item,
-                                in_items: ~[@item])
-                             -> ~[@item] {
-    cx.span_err(span, ~"`#[deriving_eq]` is obsolete; use `#[deriving(Eq)]` instead");
-    in_items
-}
-
-/// Creates a method from the given expression, the signature of which
-/// conforms to the `eq` or `ne` method.
-fn create_eq_method(cx: @ext_ctxt,
-                    span: span,
-                    method_ident: ident,
-                    type_ident: ident,
-                    generics: &Generics,
-                    body: @expr)
-                 -> @method {
-    // Create the type of the `other` parameter.
-    let arg_path_type = create_self_type_with_params(cx,
-                                                     span,
-                                                     type_ident,
-                                                     generics);
-    let arg_type = ty_rptr(
-        None,
-        ast::mt { ty: arg_path_type, mutbl: m_imm }
-    );
-    let arg_type = @ast::Ty {
-        id: cx.next_id(),
-        node: arg_type,
-        span: span,
-    };
-
-    // Create the `other` parameter.
-    let other_ident = cx.ident_of(~"__other");
-    let arg = build::mk_arg(cx, span, other_ident, arg_type);
-
-    // Create the type of the return value.
-    let bool_ident = cx.ident_of(~"bool");
-    let output_type = build::mk_raw_path(span, ~[ bool_ident ]);
-    let output_type = ty_path(output_type, cx.next_id());
-    let output_type = @ast::Ty {
-        id: cx.next_id(),
-        node: output_type,
-        span: span,
-    };
-
-    // Create the function declaration.
-    let fn_decl = build::mk_fn_decl(~[ arg ], output_type);
-
-    // Create the body block.
-    let body_block = build::mk_simple_block(cx, span, body);
-
-    // Create the method.
-    let self_ty = spanned { node: sty_region(None, m_imm), span: span };
-    @ast::method {
-        ident: method_ident,
-        attrs: ~[],
-        generics: ast_util::empty_generics(),
-        self_ty: self_ty,
-        purity: impure_fn,
-        decl: fn_decl,
-        body: body_block,
-        id: cx.next_id(),
-        span: span,
-        self_id: cx.next_id(),
-        vis: public
-    }
-}
-
-fn create_derived_eq_impl(cx: @ext_ctxt,
-                          span: span,
-                          type_ident: ident,
-                          generics: &Generics,
-                          eq_method: @method,
-                          ne_method: @method)
-                       -> @item {
-    let methods = [ eq_method, ne_method ];
-    let trait_path = ~[
-        cx.ident_of(~"core"),
-        cx.ident_of(~"cmp"),
-        cx.ident_of(~"Eq")
-    ];
-    let trait_path = build::mk_raw_path_global(span, trait_path);
-    create_derived_impl(cx, span, type_ident, generics, methods, trait_path, opt_vec::Empty, [])
-}
-
-fn call_substructure_eq_method(cx: @ext_ctxt,
-                               span: span,
-                               self_field: @expr,
-                               other_field_ref: @expr,
-                               method_ident: ident,
-                               junction: Junction,
-                               chain_expr: &mut Option<@expr>) {
-    // Call the substructure method.
-    let self_call = build::mk_method_call(cx, span,
-                                          self_field, method_ident,
-                                          ~[ other_field_ref ]);
-
-    // Connect to the outer expression if necessary.
-    *chain_expr = match *chain_expr {
-        None => Some(self_call),
-        Some(copy old_outer_expr) => {
-            let binop = junction.to_binop();
-            let chain_expr = build::mk_binary(cx,
-                                              span,
-                                              binop,
-                                              old_outer_expr,
-                                              self_call);
-            Some(chain_expr)
-        }
-    };
-}
-
-fn finish_eq_chain_expr(cx: @ext_ctxt,
-                        span: span,
-                        chain_expr: Option<@expr>,
-                        junction: Junction)
-                     -> @expr {
-    match chain_expr {
-        None => {
-            match junction {
-                Conjunction => build::mk_bool(cx, span, true),
-                Disjunction => build::mk_bool(cx, span, false),
-            }
-        }
-        Some(ref outer_expr) => *outer_expr,
-    }
-}
-
-fn expand_deriving_eq_struct_def(cx: @ext_ctxt,
-                                 span: span,
-                                 struct_def: &struct_def,
-                                 type_ident: ident,
-                                 generics: &Generics)
-                              -> @item {
-    // Create the methods.
-    let eq_ident = cx.ident_of(~"eq");
-    let ne_ident = cx.ident_of(~"ne");
-
-    let derive_struct_fn = if is_struct_tuple(struct_def) {
-        expand_deriving_eq_struct_tuple_method
-    } else {
-        expand_deriving_eq_struct_method
-    };
-
-    let eq_method = derive_struct_fn(cx,
-                                     span,
-                                     struct_def,
-                                     eq_ident,
-                                     type_ident,
-                                     generics,
-                                     Conjunction);
-    let ne_method = derive_struct_fn(cx,
-                                     span,
-                                     struct_def,
-                                     ne_ident,
-                                     type_ident,
-                                     generics,
-                                     Disjunction);
-
-    // Create the implementation.
-    return create_derived_eq_impl(cx,
-                                  span,
-                                  type_ident,
-                                  generics,
-                                  eq_method,
-                                  ne_method);
-}
-
-fn expand_deriving_eq_enum_def(cx: @ext_ctxt,
-                               span: span,
-                               enum_definition: &enum_def,
-                               type_ident: ident,
-                               generics: &Generics)
-                            -> @item {
-    // Create the methods.
-    let eq_ident = cx.ident_of(~"eq");
-    let ne_ident = cx.ident_of(~"ne");
-    let eq_method = expand_deriving_eq_enum_method(cx,
-                                                   span,
-                                                   enum_definition,
-                                                   eq_ident,
-                                                   type_ident,
-                                                   generics,
-                                                   Conjunction);
-    let ne_method = expand_deriving_eq_enum_method(cx,
-                                                   span,
-                                                   enum_definition,
-                                                   ne_ident,
-                                                   type_ident,
-                                                   generics,
-                                                   Disjunction);
-
-    // Create the implementation.
-    return create_derived_eq_impl(cx,
-                                  span,
-                                  type_ident,
-                                  generics,
-                                  eq_method,
-                                  ne_method);
-}
-
-fn expand_deriving_eq_struct_method(cx: @ext_ctxt,
-                                    span: span,
-                                    struct_def: &struct_def,
-                                    method_ident: ident,
-                                    type_ident: ident,
-                                    generics: &Generics,
-                                    junction: Junction)
-                                 -> @method {
-    let self_ident = cx.ident_of(~"self");
-    let other_ident = cx.ident_of(~"__other");
-
-    // Create the body of the method.
-    let mut outer_expr = None;
-    for struct_def.fields.each |struct_field| {
-        match struct_field.node.kind {
-            named_field(ident, _, _) => {
-                // Create the accessor for the other field.
-                let other_field = build::mk_access(cx,
-                                                   span,
-                                                   ~[ other_ident ],
-                                                   ident);
-                let other_field_ref = build::mk_addr_of(cx,
-                                                        span,
-                                                        other_field);
-
-                // Create the accessor for this field.
-                let self_field = build::mk_access(cx,
-                                                  span,
-                                                  ~[ self_ident ],
-                                                  ident);
-
-                // Call the substructure method.
-                call_substructure_eq_method(cx,
-                                            span,
-                                            self_field,
-                                            other_field_ref,
-                                            method_ident,
-                                            junction,
-                                            &mut outer_expr);
-            }
-            unnamed_field => {
-                cx.span_unimpl(span, ~"unnamed fields with `deriving(Eq)`");
-            }
-        }
-    }
-
-    // Create the method itself.
-    let body = finish_eq_chain_expr(cx, span, outer_expr, junction);
-    return create_eq_method(cx,
-                            span,
-                            method_ident,
-                            type_ident,
-                            generics,
-                            body);
-}
-
-fn expand_deriving_eq_enum_method(cx: @ext_ctxt,
-                                  span: span,
-                                  enum_definition: &enum_def,
-                                  method_ident: ident,
-                                  type_ident: ident,
-                                  generics: &Generics,
-                                  junction: Junction)
-                               -> @method {
-    let self_ident = cx.ident_of(~"self");
-    let other_ident = cx.ident_of(~"__other");
-
-    let is_eq;
-    match junction {
-        Conjunction => is_eq = true,
-        Disjunction => is_eq = false,
-    }
-
-    // Create the arms of the self match in the method body.
-    let mut self_arms = ~[];
-    for enum_definition.variants.each |self_variant| {
-        let mut other_arms = ~[];
-
-        // Create the matching pattern.
-        let matching_pat = create_enum_variant_pattern(cx,
-                                                       span,
-                                                       self_variant,
-                                                       ~"__other");
-
-        // Create the matching pattern body.
-        let mut matching_body_expr = None;
-        for uint::range(0, variant_arg_count(cx, span, self_variant)) |i| {
-            // Create the expression for the other field.
-            let other_field_ident = cx.ident_of(~"__other_" + i.to_str());
-            let other_field = build::mk_path(cx,
-                                             span,
-                                             ~[ other_field_ident ]);
-
-            // Create the expression for this field.
-            let self_field_ident = cx.ident_of(~"__self_" + i.to_str());
-            let self_field = build::mk_path(cx, span, ~[ self_field_ident ]);
-
-            // Call the substructure method.
-            call_substructure_eq_method(cx,
-                                        span,
-                                        self_field,
-                                        other_field,
-                                        method_ident,
-                                        junction,
-                                        &mut matching_body_expr);
-        }
-
-        let matching_body_expr = finish_eq_chain_expr(cx,
-                                                      span,
-                                                      matching_body_expr,
-                                                      junction);
-        let matching_body_block = build::mk_simple_block(cx,
-                                                         span,
-                                                         matching_body_expr);
-
-        // Create the matching arm.
-        let matching_arm = ast::arm {
-            pats: ~[ matching_pat ],
-            guard: None,
-            body: matching_body_block
-        };
-        other_arms.push(matching_arm);
-
-        // Maybe generate a non-matching case. If there is only one
-        // variant then there will always be a match.
-        if enum_definition.variants.len() > 1 {
-            // Create the nonmatching pattern.
-            let nonmatching_pat = @ast::pat {
-                id: cx.next_id(),
-                node: pat_wild,
-                span: span
-            };
-
-            // Create the nonmatching pattern body.
-            let nonmatching_expr = build::mk_bool(cx, span, !is_eq);
-            let nonmatching_body_block =
-                build::mk_simple_block(cx,
-                                       span,
-                                       nonmatching_expr);
-
-            // Create the nonmatching arm.
-            let nonmatching_arm = ast::arm {
-                pats: ~[ nonmatching_pat ],
-                guard: None,
-                body: nonmatching_body_block,
-            };
-            other_arms.push(nonmatching_arm);
-        }
-
-        // Create the self pattern.
-        let self_pat = create_enum_variant_pattern(cx,
-                                                   span,
-                                                   self_variant,
-                                                   ~"__self");
-
-        // Create the self pattern body.
-        let other_expr = build::mk_path(cx, span, ~[ other_ident ]);
-        let other_expr = build::mk_unary(cx, span, deref, other_expr);
-        let other_match_expr = expr_match(other_expr, other_arms);
-        let other_match_expr = build::mk_expr(cx,
-                                              span,
-                                              other_match_expr);
-        let other_match_body_block = build::mk_simple_block(cx,
-                                                            span,
-                                                            other_match_expr);
-
-        // Create the self arm.
-        let self_arm = ast::arm {
-            pats: ~[ self_pat ],
-            guard: None,
-            body: other_match_body_block,
-        };
-        self_arms.push(self_arm);
-    }
-
-    // Create the method body.
-    let self_expr = build::mk_path(cx, span, ~[ self_ident ]);
-    let self_expr = build::mk_unary(cx, span, deref, self_expr);
-    let self_match_expr = expr_match(self_expr, self_arms);
-    let self_match_expr = build::mk_expr(cx, span, self_match_expr);
-
-    // Create the method.
-    return create_eq_method(cx,
-                            span,
-                            method_ident,
-                            type_ident,
-                            generics,
-                            self_match_expr);
-}
-
-fn expand_deriving_eq_struct_tuple_method(cx: @ext_ctxt,
-                                          span: span,
-                                          struct_def: &struct_def,
-                                          method_ident: ident,
-                                          type_ident: ident,
-                                          generics: &Generics,
-                                          junction: Junction)
-                                        -> @method {
-    let self_str = ~"self";
-    let other_str = ~"__other";
-    let type_path = build::mk_raw_path(span, ~[type_ident]);
-    let fields = copy struct_def.fields;
-
-    // Create comparison expression, comparing each of the fields
-    let mut match_body = None;
-    for fields.eachi |i, _| {
-        let other_field_ident = cx.ident_of(fmt!("%s_%u", other_str, i));
-        let other_field = build::mk_path(cx, span, ~[ other_field_ident ]);
-
-        let self_field_ident = cx.ident_of(fmt!("%s_%u", self_str, i));
-        let self_field = build::mk_path(cx, span, ~[ self_field_ident ]);
-
-        call_substructure_eq_method(cx, span, self_field, other_field,
-            method_ident, junction, &mut match_body);
-    }
-    let match_body = finish_eq_chain_expr(cx, span, match_body, junction);
-
-    // Create arm for the '__other' match, containing the comparison expr
-    let other_subpats = create_subpatterns(cx, span, other_str, fields.len());
-    let other_arm = ast::arm {
-        pats: ~[ build::mk_pat_enum(cx, span, type_path, other_subpats) ],
-        guard: None,
-        body: build::mk_simple_block(cx, span, match_body),
-    };
-
-    // Create the match on '__other'
-    let other_expr = build::mk_path(cx, span, ~[ cx.ident_of(other_str) ]);
-    let other_expr = build::mk_unary(cx, span, deref, other_expr);
-    let other_match_expr = expr_match(other_expr, ~[other_arm]);
-    let other_match_expr = build::mk_expr(cx, span, other_match_expr);
-
-    // Create arm for the 'self' match, which contains the '__other' match
-    let self_subpats = create_subpatterns(cx, span, self_str, fields.len());
-    let self_arm = ast::arm {
-        pats: ~[build::mk_pat_enum(cx, span, type_path, self_subpats)],
-        guard: None,
-        body: build::mk_simple_block(cx, span, other_match_expr),
-    };
-
-    // Create the match on 'self'
-    let self_expr = build::mk_path(cx, span, ~[ cx.ident_of(self_str) ]);
-    let self_expr = build::mk_unary(cx, span, deref, self_expr);
-    let self_match_expr = expr_match(self_expr, ~[self_arm]);
-    let self_match_expr = build::mk_expr(cx, span, self_match_expr);
-
-    create_eq_method(cx, span, method_ident,
-        type_ident, generics, self_match_expr)
-}
diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs
index 1241d4fa711..78faf5556b2 100644
--- a/src/libsyntax/ext/deriving/mod.rs
+++ b/src/libsyntax/ext/deriving/mod.rs
@@ -30,12 +30,21 @@ use opt_vec;
 
 use core::uint;
 
-pub mod eq;
 pub mod clone;
 pub mod iter_bytes;
 pub mod encodable;
 pub mod decodable;
 
+#[path="cmp/eq.rs"]
+pub mod eq;
+#[path="cmp/totaleq.rs"]
+pub mod totaleq;
+#[path="cmp/ord.rs"]
+pub mod ord;
+#[path="cmp/totalord.rs"]
+pub mod totalord;
+
+
 pub mod generic;
 
 pub type ExpandDerivingStructDefFn<'self> = &'self fn(@ext_ctxt,
@@ -74,8 +83,6 @@ pub fn expand_meta_deriving(cx: @ext_ctxt,
                     meta_list(tname, _) |
                     meta_word(tname) => {
                         match *tname {
-                            ~"Eq" => eq::expand_deriving_eq(cx, titem.span,
-                                                            titem, in_items),
                             ~"Clone" => clone::expand_deriving_clone(cx,
                                 titem.span, titem, in_items),
                             ~"IterBytes" => iter_bytes::expand_deriving_iter_bytes(cx,
@@ -84,6 +91,14 @@ pub fn expand_meta_deriving(cx: @ext_ctxt,
                                 titem.span, titem, in_items),
                             ~"Decodable" => decodable::expand_deriving_decodable(cx,
                                 titem.span, titem, in_items),
+                            ~"Eq" => eq::expand_deriving_eq(cx, titem.span,
+                                                             titem, in_items),
+                            ~"TotalEq" => totaleq::expand_deriving_totaleq(cx, titem.span,
+                                                                           titem, in_items),
+                            ~"Ord" => ord::expand_deriving_ord(cx, titem.span,
+                                                               titem, in_items),
+                            ~"TotalOrd" => totalord::expand_deriving_totalord(cx, titem.span,
+                                                                              titem, in_items),
                             tname => {
                                 cx.span_err(titem.span, fmt!("unknown \
                                     `deriving` trait: `%s`", tname));