libsyntax: derive Clone, Eq, TotalEq, Ord, TotalOrd with the new generic deriving code.
Closes #4269, #5588 and #5589.
This commit is contained in:
parent
85b82c763b
commit
7906c5572a
7 changed files with 410 additions and 760 deletions
|
|
@ -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);
|
||||
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)`")
|
||||
}
|
||||
|
||||
// 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
|
||||
};
|
||||
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) }
|
||||
};
|
||||
|
||||
// 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 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)`");
|
||||
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)
|
||||
}
|
||||
|
|
|
|||
65
src/libsyntax/ext/deriving/cmp/eq.rs
Normal file
65
src/libsyntax/ext/deriving/cmp/eq.rs
Normal file
|
|
@ -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
|
||||
}
|
||||
142
src/libsyntax/ext/deriving/cmp/ord.rs
Normal file
142
src/libsyntax/ext/deriving/cmp/ord.rs
Normal file
|
|
@ -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)
|
||||
}
|
||||
45
src/libsyntax/ext/deriving/cmp/totaleq.rs
Normal file
45
src/libsyntax/ext/deriving/cmp/totaleq.rs
Normal file
|
|
@ -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)
|
||||
}
|
||||
77
src/libsyntax/ext/deriving/cmp/totalord.rs
Normal file
77
src/libsyntax/ext/deriving/cmp/totalord.rs
Normal file
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue