Auto merge of #23985 - erickt:derive-cleanup, r=erickt

This extracts some of the minor cleanup patches from #23905.
This commit is contained in:
bors
2015-04-18 00:48:34 +00:00
18 changed files with 500 additions and 521 deletions

View File

@@ -15,22 +15,20 @@ use ext::deriving::generic::*;
use ext::deriving::generic::ty::*; use ext::deriving::generic::ty::*;
use ptr::P; use ptr::P;
pub fn expand_deriving_unsafe_bound<F>(cx: &mut ExtCtxt, pub fn expand_deriving_unsafe_bound(cx: &mut ExtCtxt,
span: Span, span: Span,
_: &MetaItem, _: &MetaItem,
_: &Item, _: &Item,
_: F) where _: &mut FnMut(P<Item>))
F: FnOnce(P<Item>),
{ {
cx.span_err(span, "this unsafe trait should be implemented explicitly"); cx.span_err(span, "this unsafe trait should be implemented explicitly");
} }
pub fn expand_deriving_copy<F>(cx: &mut ExtCtxt, pub fn expand_deriving_copy(cx: &mut ExtCtxt,
span: Span, span: Span,
mitem: &MetaItem, mitem: &MetaItem,
item: &Item, item: &Item,
push: F) where push: &mut FnMut(P<Item>))
F: FnOnce(P<Item>),
{ {
let path = Path::new(vec![ let path = Path::new(vec![
if cx.use_std { "std" } else { "core" }, if cx.use_std { "std" } else { "core" },
@@ -48,5 +46,5 @@ pub fn expand_deriving_copy<F>(cx: &mut ExtCtxt,
associated_types: Vec::new(), associated_types: Vec::new(),
}; };
trait_def.expand(cx, mitem, item, push) trait_def.expand(cx, mitem, item, push);
} }

View File

@@ -17,12 +17,11 @@ use ext::deriving::generic::ty::*;
use parse::token::InternedString; use parse::token::InternedString;
use ptr::P; use ptr::P;
pub fn expand_deriving_clone<F>(cx: &mut ExtCtxt, pub fn expand_deriving_clone(cx: &mut ExtCtxt,
span: Span, span: Span,
mitem: &MetaItem, mitem: &MetaItem,
item: &Item, item: &Item,
push: F) where push: &mut FnMut(P<Item>))
F: FnOnce(P<Item>),
{ {
let inline = cx.meta_word(span, InternedString::new("inline")); let inline = cx.meta_word(span, InternedString::new("inline"));
let attrs = vec!(cx.attribute(span, inline)); let attrs = vec!(cx.attribute(span, inline));

View File

@@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use ast::{MetaItem, Item, Expr, self}; use ast::{MetaItem, Item, Expr};
use codemap::Span; use codemap::Span;
use ext::base::ExtCtxt; use ext::base::ExtCtxt;
use ext::build::AstBuilder; use ext::build::AstBuilder;
@@ -17,77 +17,52 @@ use ext::deriving::generic::ty::*;
use parse::token::InternedString; use parse::token::InternedString;
use ptr::P; use ptr::P;
pub fn expand_deriving_eq<F>(cx: &mut ExtCtxt, pub fn expand_deriving_eq(cx: &mut ExtCtxt,
span: Span, span: Span,
mitem: &MetaItem, mitem: &MetaItem,
item: &Item, item: &Item,
push: F) where push: &mut FnMut(P<Item>))
F: FnOnce(P<Item>),
{ {
// structures are equal if all fields are equal, and non equal, if fn cs_total_eq_assert(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<Expr> {
// any fields are not equal or if the enum variants are different cs_same_method(
fn cs_eq(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<Expr> { |cx, span, exprs| {
cs_fold( // create `a.<method>(); b.<method>(); c.<method>(); ...`
true, // use foldl // (where method is `assert_receiver_is_total_eq`)
|cx, span, subexpr, self_f, other_fs| { let stmts = exprs.into_iter().map(|e| cx.stmt_expr(e)).collect();
let other_f = match other_fs { let block = cx.block(span, stmts, None);
[ref o_f] => o_f, cx.expr_block(block)
_ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`")
};
let eq = cx.expr_binary(span, ast::BiEq, self_f, other_f.clone());
cx.expr_binary(span, ast::BiAnd, subexpr, eq)
}, },
cx.expr_bool(span, true), Box::new(|cx, sp, _, _| {
Box::new(|cx, span, _, _| cx.expr_bool(span, false)), cx.span_bug(sp, "non matching enums in derive(Eq)?") }),
cx, span, substr) cx,
} span,
fn cs_ne(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<Expr> { substr
cs_fold( )
true, // use foldl
|cx, span, subexpr, self_f, other_fs| {
let other_f = match other_fs {
[ref o_f] => o_f,
_ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`")
};
let eq = cx.expr_binary(span, ast::BiNe, self_f, other_f.clone());
cx.expr_binary(span, ast::BiOr, subexpr, eq)
},
cx.expr_bool(span, false),
Box::new(|cx, span, _, _| cx.expr_bool(span, true)),
cx, span, substr)
}
macro_rules! md {
($name:expr, $f:ident) => { {
let inline = cx.meta_word(span, InternedString::new("inline"));
let attrs = vec!(cx.attribute(span, inline));
MethodDef {
name: $name,
generics: LifetimeBounds::empty(),
explicit_self: borrowed_explicit_self(),
args: vec!(borrowed_self()),
ret_ty: Literal(path_local!(bool)),
attributes: attrs,
combine_substructure: combine_substructure(Box::new(|a, b, c| {
$f(a, b, c)
}))
}
} }
} }
let inline = cx.meta_word(span, InternedString::new("inline"));
let hidden = cx.meta_word(span, InternedString::new("hidden"));
let doc = cx.meta_list(span, InternedString::new("doc"), vec!(hidden));
let attrs = vec!(cx.attribute(span, inline),
cx.attribute(span, doc));
let trait_def = TraitDef { let trait_def = TraitDef {
span: span, span: span,
attributes: Vec::new(), attributes: Vec::new(),
path: path_std!(cx, core::cmp::PartialEq), path: path_std!(cx, core::cmp::Eq),
additional_bounds: Vec::new(), additional_bounds: Vec::new(),
generics: LifetimeBounds::empty(), generics: LifetimeBounds::empty(),
methods: vec!( methods: vec!(
md!("eq", cs_eq), MethodDef {
md!("ne", cs_ne) name: "assert_receiver_is_total_eq",
generics: LifetimeBounds::empty(),
explicit_self: borrowed_explicit_self(),
args: vec!(),
ret_ty: nil_ty(),
attributes: attrs,
combine_substructure: combine_substructure(Box::new(|a, b, c| {
cs_total_eq_assert(a, b, c)
}))
}
), ),
associated_types: Vec::new(), associated_types: Vec::new(),
}; };

View File

@@ -8,8 +8,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
pub use self::OrderingOp::*;
use ast; use ast;
use ast::{MetaItem, Item, Expr}; use ast::{MetaItem, Item, Expr};
use codemap::Span; use codemap::Span;
@@ -20,114 +18,71 @@ use ext::deriving::generic::ty::*;
use parse::token::InternedString; use parse::token::InternedString;
use ptr::P; use ptr::P;
pub fn expand_deriving_ord<F>(cx: &mut ExtCtxt, pub fn expand_deriving_ord(cx: &mut ExtCtxt,
span: Span, span: Span,
mitem: &MetaItem, mitem: &MetaItem,
item: &Item, item: &Item,
push: F) where push: &mut FnMut(P<Item>))
F: FnOnce(P<Item>),
{ {
macro_rules! md { let inline = cx.meta_word(span, InternedString::new("inline"));
($name:expr, $op:expr, $equal:expr) => { { let attrs = vec!(cx.attribute(span, inline));
let inline = cx.meta_word(span, InternedString::new("inline")); let trait_def = TraitDef {
let attrs = vec!(cx.attribute(span, inline)); span: span,
attributes: Vec::new(),
path: path_std!(cx, core::cmp::Ord),
additional_bounds: Vec::new(),
generics: LifetimeBounds::empty(),
methods: vec!(
MethodDef { MethodDef {
name: $name, name: "cmp",
generics: LifetimeBounds::empty(), generics: LifetimeBounds::empty(),
explicit_self: borrowed_explicit_self(), explicit_self: borrowed_explicit_self(),
args: vec!(borrowed_self()), args: vec!(borrowed_self()),
ret_ty: Literal(path_local!(bool)), ret_ty: Literal(path_std!(cx, core::cmp::Ordering)),
attributes: attrs, attributes: attrs,
combine_substructure: combine_substructure(Box::new(|cx, span, substr| { combine_substructure: combine_substructure(Box::new(|a, b, c| {
cs_op($op, $equal, cx, span, substr) cs_cmp(a, b, c)
})) })),
} }
} } ),
}
let ordering_ty = Literal(path_std!(cx, core::cmp::Ordering));
let ret_ty = Literal(Path::new_(pathvec_std!(cx, core::option::Option),
None,
vec![box ordering_ty],
true));
let inline = cx.meta_word(span, InternedString::new("inline"));
let attrs = vec!(cx.attribute(span, inline));
let partial_cmp_def = MethodDef {
name: "partial_cmp",
generics: LifetimeBounds::empty(),
explicit_self: borrowed_explicit_self(),
args: vec![borrowed_self()],
ret_ty: ret_ty,
attributes: attrs,
combine_substructure: combine_substructure(Box::new(|cx, span, substr| {
cs_partial_cmp(cx, span, substr)
}))
};
let trait_def = TraitDef {
span: span,
attributes: vec![],
path: path_std!(cx, core::cmp::PartialOrd),
additional_bounds: vec![],
generics: LifetimeBounds::empty(),
methods: vec![
partial_cmp_def,
md!("lt", true, false),
md!("le", true, true),
md!("gt", false, false),
md!("ge", false, true)
],
associated_types: Vec::new(), associated_types: Vec::new(),
}; };
trait_def.expand(cx, mitem, item, push) trait_def.expand(cx, mitem, item, push)
} }
#[derive(Copy, Clone)]
pub enum OrderingOp {
PartialCmpOp, LtOp, LeOp, GtOp, GeOp,
}
pub fn some_ordering_collapsed(cx: &mut ExtCtxt, pub fn ordering_collapsed(cx: &mut ExtCtxt,
span: Span, span: Span,
op: OrderingOp, self_arg_tags: &[ast::Ident]) -> P<ast::Expr> {
self_arg_tags: &[ast::Ident]) -> P<ast::Expr> {
let lft = cx.expr_ident(span, self_arg_tags[0]); let lft = cx.expr_ident(span, self_arg_tags[0]);
let rgt = cx.expr_addr_of(span, cx.expr_ident(span, self_arg_tags[1])); let rgt = cx.expr_addr_of(span, cx.expr_ident(span, self_arg_tags[1]));
let op_str = match op { cx.expr_method_call(span, lft, cx.ident_of("cmp"), vec![rgt])
PartialCmpOp => "partial_cmp",
LtOp => "lt", LeOp => "le",
GtOp => "gt", GeOp => "ge",
};
cx.expr_method_call(span, lft, cx.ident_of(op_str), vec![rgt])
} }
pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, pub fn cs_cmp(cx: &mut ExtCtxt, span: Span,
substr: &Substructure) -> P<Expr> { substr: &Substructure) -> P<Expr> {
let test_id = cx.ident_of("__test"); let test_id = cx.ident_of("__test");
let ordering = cx.path_global(span, let equals_path = cx.path_global(span,
vec!(cx.ident_of_std("core"), vec!(cx.ident_of_std("core"),
cx.ident_of("cmp"), cx.ident_of("cmp"),
cx.ident_of("Ordering"), cx.ident_of("Ordering"),
cx.ident_of("Equal"))); cx.ident_of("Equal")));
let ordering = cx.expr_path(ordering);
let equals_expr = cx.expr_some(span, ordering);
let partial_cmp_path = vec![ let cmp_path = vec![
cx.ident_of_std("core"), cx.ident_of_std("core"),
cx.ident_of("cmp"), cx.ident_of("cmp"),
cx.ident_of("PartialOrd"), cx.ident_of("Ord"),
cx.ident_of("partial_cmp"), cx.ident_of("cmp"),
]; ];
/* /*
Builds: Builds:
let __test = ::std::cmp::PartialOrd::partial_cmp(&self_field1, &other_field1); let __test = ::std::cmp::Ord::cmp(&self_field1, &other_field1);
if __test == ::std::option::Option::Some(::std::cmp::Ordering::Equal) { if other == ::std::cmp::Ordering::Equal {
let __test = ::std::cmp::PartialOrd::partial_cmp(&self_field2, &other_field2); let __test = ::std::cmp::Ord::cmp(&self_field2, &other_field2);
if __test == ::std::option::Option::Some(::std::cmp::Ordering::Equal) { if __test == ::std::cmp::Ordering::Equal {
... ...
} else { } else {
__test __test
@@ -144,7 +99,7 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span,
false, false,
|cx, span, old, self_f, other_fs| { |cx, span, old, self_f, other_fs| {
// let __test = new; // let __test = new;
// if __test == Some(::std::cmp::Ordering::Equal) { // if __test == ::std::cmp::Ordering::Equal {
// old // old
// } else { // } else {
// __test // __test
@@ -161,77 +116,25 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span,
cx.expr_addr_of(span, other_f.clone()), cx.expr_addr_of(span, other_f.clone()),
]; ];
cx.expr_call_global(span, partial_cmp_path.clone(), args) cx.expr_call_global(span, cmp_path.clone(), args)
}; };
let assign = cx.stmt_let(span, false, test_id, new); let assign = cx.stmt_let(span, false, test_id, new);
let cond = cx.expr_binary(span, ast::BiEq, let cond = cx.expr_binary(span, ast::BiEq,
cx.expr_ident(span, test_id), cx.expr_ident(span, test_id),
equals_expr.clone()); cx.expr_path(equals_path.clone()));
let if_ = cx.expr_if(span, let if_ = cx.expr_if(span,
cond, cond,
old, Some(cx.expr_ident(span, test_id))); old, Some(cx.expr_ident(span, test_id)));
cx.expr_block(cx.block(span, vec!(assign), Some(if_))) cx.expr_block(cx.block(span, vec!(assign), Some(if_)))
}, },
equals_expr.clone(), cx.expr_path(equals_path.clone()),
Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| { Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| {
if self_args.len() != 2 { if self_args.len() != 2 {
cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`") cx.span_bug(span, "not exactly 2 arguments in `derives(Ord)`")
} else { } else {
some_ordering_collapsed(cx, span, PartialCmpOp, tag_tuple) ordering_collapsed(cx, span, tag_tuple)
}
}),
cx, span, substr)
}
/// Strict inequality.
fn cs_op(less: bool, equal: bool, cx: &mut ExtCtxt,
span: Span, substr: &Substructure) -> P<Expr> {
let op = if less {ast::BiLt} else {ast::BiGt};
cs_fold(
false, // need foldr,
|cx, span, subexpr, self_f, other_fs| {
/*
build up a series of chain ||'s and &&'s from the inside
out (hence foldr) to get lexical ordering, i.e. for op ==
`ast::lt`
```
self.f1 < other.f1 || (!(other.f1 < self.f1) &&
(self.f2 < other.f2 || (!(other.f2 < self.f2) &&
(false)
))
)
```
The optimiser should remove the redundancy. We explicitly
get use the binops to avoid auto-deref dereferencing too many
layers of pointers, if the type includes pointers.
*/
let other_f = match other_fs {
[ref o_f] => o_f,
_ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`")
};
let cmp = cx.expr_binary(span, op, self_f.clone(), other_f.clone());
let not_cmp = cx.expr_unary(span, ast::UnNot,
cx.expr_binary(span, op, other_f.clone(), self_f));
let and = cx.expr_binary(span, ast::BiAnd, not_cmp, subexpr);
cx.expr_binary(span, ast::BiOr, cmp, and)
},
cx.expr_bool(span, equal),
Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| {
if self_args.len() != 2 {
cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`")
} else {
let op = match (less, equal) {
(true, true) => LeOp, (true, false) => LtOp,
(false, true) => GeOp, (false, false) => GtOp,
};
some_ordering_collapsed(cx, span, op, tag_tuple)
} }
}), }),
cx, span, substr) cx, span, substr)

View File

@@ -0,0 +1,94 @@
// 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::{MetaItem, Item, Expr, self};
use codemap::Span;
use ext::base::ExtCtxt;
use ext::build::AstBuilder;
use ext::deriving::generic::*;
use ext::deriving::generic::ty::*;
use parse::token::InternedString;
use ptr::P;
pub fn expand_deriving_partial_eq(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
item: &Item,
push: &mut FnMut(P<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: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<Expr> {
cs_fold(
true, // use foldl
|cx, span, subexpr, self_f, other_fs| {
let other_f = match other_fs {
[ref o_f] => o_f,
_ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`")
};
let eq = cx.expr_binary(span, ast::BiEq, self_f, other_f.clone());
cx.expr_binary(span, ast::BiAnd, subexpr, eq)
},
cx.expr_bool(span, true),
Box::new(|cx, span, _, _| cx.expr_bool(span, false)),
cx, span, substr)
}
fn cs_ne(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<Expr> {
cs_fold(
true, // use foldl
|cx, span, subexpr, self_f, other_fs| {
let other_f = match other_fs {
[ref o_f] => o_f,
_ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`")
};
let eq = cx.expr_binary(span, ast::BiNe, self_f, other_f.clone());
cx.expr_binary(span, ast::BiOr, subexpr, eq)
},
cx.expr_bool(span, false),
Box::new(|cx, span, _, _| cx.expr_bool(span, true)),
cx, span, substr)
}
macro_rules! md {
($name:expr, $f:ident) => { {
let inline = cx.meta_word(span, InternedString::new("inline"));
let attrs = vec!(cx.attribute(span, inline));
MethodDef {
name: $name,
generics: LifetimeBounds::empty(),
explicit_self: borrowed_explicit_self(),
args: vec!(borrowed_self()),
ret_ty: Literal(path_local!(bool)),
attributes: attrs,
combine_substructure: combine_substructure(Box::new(|a, b, c| {
$f(a, b, c)
}))
}
} }
}
let trait_def = TraitDef {
span: span,
attributes: Vec::new(),
path: path_std!(cx, core::cmp::PartialEq),
additional_bounds: Vec::new(),
generics: LifetimeBounds::empty(),
methods: vec!(
md!("eq", cs_eq),
md!("ne", cs_ne)
),
associated_types: Vec::new(),
};
trait_def.expand(cx, mitem, item, push)
}

View File

@@ -0,0 +1,237 @@
// 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.
pub use self::OrderingOp::*;
use ast;
use ast::{MetaItem, Item, Expr};
use codemap::Span;
use ext::base::ExtCtxt;
use ext::build::AstBuilder;
use ext::deriving::generic::*;
use ext::deriving::generic::ty::*;
use parse::token::InternedString;
use ptr::P;
pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
item: &Item,
push: &mut FnMut(P<Item>))
{
macro_rules! md {
($name:expr, $op:expr, $equal:expr) => { {
let inline = cx.meta_word(span, InternedString::new("inline"));
let attrs = vec!(cx.attribute(span, inline));
MethodDef {
name: $name,
generics: LifetimeBounds::empty(),
explicit_self: borrowed_explicit_self(),
args: vec!(borrowed_self()),
ret_ty: Literal(path_local!(bool)),
attributes: attrs,
combine_substructure: combine_substructure(Box::new(|cx, span, substr| {
cs_op($op, $equal, cx, span, substr)
}))
}
} }
}
let ordering_ty = Literal(path_std!(cx, core::cmp::Ordering));
let ret_ty = Literal(Path::new_(pathvec_std!(cx, core::option::Option),
None,
vec![box ordering_ty],
true));
let inline = cx.meta_word(span, InternedString::new("inline"));
let attrs = vec!(cx.attribute(span, inline));
let partial_cmp_def = MethodDef {
name: "partial_cmp",
generics: LifetimeBounds::empty(),
explicit_self: borrowed_explicit_self(),
args: vec![borrowed_self()],
ret_ty: ret_ty,
attributes: attrs,
combine_substructure: combine_substructure(Box::new(|cx, span, substr| {
cs_partial_cmp(cx, span, substr)
}))
};
let trait_def = TraitDef {
span: span,
attributes: vec![],
path: path_std!(cx, core::cmp::PartialOrd),
additional_bounds: vec![],
generics: LifetimeBounds::empty(),
methods: vec![
partial_cmp_def,
md!("lt", true, false),
md!("le", true, true),
md!("gt", false, false),
md!("ge", false, true)
],
associated_types: Vec::new(),
};
trait_def.expand(cx, mitem, item, push)
}
#[derive(Copy, Clone)]
pub enum OrderingOp {
PartialCmpOp, LtOp, LeOp, GtOp, GeOp,
}
pub fn some_ordering_collapsed(cx: &mut ExtCtxt,
span: Span,
op: OrderingOp,
self_arg_tags: &[ast::Ident]) -> P<ast::Expr> {
let lft = cx.expr_ident(span, self_arg_tags[0]);
let rgt = cx.expr_addr_of(span, cx.expr_ident(span, self_arg_tags[1]));
let op_str = match op {
PartialCmpOp => "partial_cmp",
LtOp => "lt", LeOp => "le",
GtOp => "gt", GeOp => "ge",
};
cx.expr_method_call(span, lft, cx.ident_of(op_str), vec![rgt])
}
pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span,
substr: &Substructure) -> P<Expr> {
let test_id = cx.ident_of("__test");
let ordering = cx.path_global(span,
vec!(cx.ident_of_std("core"),
cx.ident_of("cmp"),
cx.ident_of("Ordering"),
cx.ident_of("Equal")));
let ordering = cx.expr_path(ordering);
let equals_expr = cx.expr_some(span, ordering);
let partial_cmp_path = vec![
cx.ident_of_std("core"),
cx.ident_of("cmp"),
cx.ident_of("PartialOrd"),
cx.ident_of("partial_cmp"),
];
/*
Builds:
let __test = ::std::cmp::PartialOrd::partial_cmp(&self_field1, &other_field1);
if __test == ::std::option::Option::Some(::std::cmp::Ordering::Equal) {
let __test = ::std::cmp::PartialOrd::partial_cmp(&self_field2, &other_field2);
if __test == ::std::option::Option::Some(::std::cmp::Ordering::Equal) {
...
} else {
__test
}
} else {
__test
}
FIXME #6449: These `if`s could/should be `match`es.
*/
cs_fold(
// foldr nests the if-elses correctly, leaving the first field
// as the outermost one, and the last as the innermost.
false,
|cx, span, old, self_f, other_fs| {
// let __test = new;
// if __test == Some(::std::cmp::Ordering::Equal) {
// old
// } else {
// __test
// }
let new = {
let other_f = match other_fs {
[ref o_f] => o_f,
_ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"),
};
let args = vec![
cx.expr_addr_of(span, self_f),
cx.expr_addr_of(span, other_f.clone()),
];
cx.expr_call_global(span, partial_cmp_path.clone(), args)
};
let assign = cx.stmt_let(span, false, test_id, new);
let cond = cx.expr_binary(span, ast::BiEq,
cx.expr_ident(span, test_id),
equals_expr.clone());
let if_ = cx.expr_if(span,
cond,
old, Some(cx.expr_ident(span, test_id)));
cx.expr_block(cx.block(span, vec!(assign), Some(if_)))
},
equals_expr.clone(),
Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| {
if self_args.len() != 2 {
cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`")
} else {
some_ordering_collapsed(cx, span, PartialCmpOp, tag_tuple)
}
}),
cx, span, substr)
}
/// Strict inequality.
fn cs_op(less: bool, equal: bool, cx: &mut ExtCtxt,
span: Span, substr: &Substructure) -> P<Expr> {
let op = if less {ast::BiLt} else {ast::BiGt};
cs_fold(
false, // need foldr,
|cx, span, subexpr, self_f, other_fs| {
/*
build up a series of chain ||'s and &&'s from the inside
out (hence foldr) to get lexical ordering, i.e. for op ==
`ast::lt`
```
self.f1 < other.f1 || (!(other.f1 < self.f1) &&
(self.f2 < other.f2 || (!(other.f2 < self.f2) &&
(false)
))
)
```
The optimiser should remove the redundancy. We explicitly
get use the binops to avoid auto-deref dereferencing too many
layers of pointers, if the type includes pointers.
*/
let other_f = match other_fs {
[ref o_f] => o_f,
_ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`")
};
let cmp = cx.expr_binary(span, op, self_f.clone(), other_f.clone());
let not_cmp = cx.expr_unary(span, ast::UnNot,
cx.expr_binary(span, op, other_f.clone(), self_f));
let and = cx.expr_binary(span, ast::BiAnd, not_cmp, subexpr);
cx.expr_binary(span, ast::BiOr, cmp, and)
},
cx.expr_bool(span, equal),
Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| {
if self_args.len() != 2 {
cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`")
} else {
let op = match (less, equal) {
(true, true) => LeOp, (true, false) => LtOp,
(false, true) => GeOp, (false, false) => GtOp,
};
some_ordering_collapsed(cx, span, op, tag_tuple)
}
}),
cx, span, substr)
}

View File

@@ -1,69 +0,0 @@
// 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::{MetaItem, Item, Expr};
use codemap::Span;
use ext::base::ExtCtxt;
use ext::build::AstBuilder;
use ext::deriving::generic::*;
use ext::deriving::generic::ty::*;
use parse::token::InternedString;
use ptr::P;
pub fn expand_deriving_totaleq<F>(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
item: &Item,
push: F) where
F: FnOnce(P<Item>),
{
fn cs_total_eq_assert(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<Expr> {
cs_same_method(|cx, span, exprs| {
// create `a.<method>(); b.<method>(); c.<method>(); ...`
// (where method is `assert_receiver_is_total_eq`)
let stmts = exprs.into_iter().map(|e| cx.stmt_expr(e)).collect();
let block = cx.block(span, stmts, None);
cx.expr_block(block)
},
Box::new(|cx, sp, _, _| {
cx.span_bug(sp, "non matching enums in derive(Eq)?") }),
cx,
span,
substr)
}
let inline = cx.meta_word(span, InternedString::new("inline"));
let hidden = cx.meta_word(span, InternedString::new("hidden"));
let doc = cx.meta_list(span, InternedString::new("doc"), vec!(hidden));
let attrs = vec!(cx.attribute(span, inline),
cx.attribute(span, doc));
let trait_def = TraitDef {
span: span,
attributes: Vec::new(),
path: path_std!(cx, core::cmp::Eq),
additional_bounds: Vec::new(),
generics: LifetimeBounds::empty(),
methods: vec!(
MethodDef {
name: "assert_receiver_is_total_eq",
generics: LifetimeBounds::empty(),
explicit_self: borrowed_explicit_self(),
args: vec!(),
ret_ty: nil_ty(),
attributes: attrs,
combine_substructure: combine_substructure(Box::new(|a, b, c| {
cs_total_eq_assert(a, b, c)
}))
}
),
associated_types: Vec::new(),
};
trait_def.expand(cx, mitem, item, push)
}

View File

@@ -1,142 +0,0 @@
// 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;
use ast::{MetaItem, Item, Expr};
use codemap::Span;
use ext::base::ExtCtxt;
use ext::build::AstBuilder;
use ext::deriving::generic::*;
use ext::deriving::generic::ty::*;
use parse::token::InternedString;
use ptr::P;
pub fn expand_deriving_totalord<F>(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
item: &Item,
push: F) where
F: FnOnce(P<Item>),
{
let inline = cx.meta_word(span, InternedString::new("inline"));
let attrs = vec!(cx.attribute(span, inline));
let trait_def = TraitDef {
span: span,
attributes: Vec::new(),
path: path_std!(cx, core::cmp::Ord),
additional_bounds: Vec::new(),
generics: LifetimeBounds::empty(),
methods: vec!(
MethodDef {
name: "cmp",
generics: LifetimeBounds::empty(),
explicit_self: borrowed_explicit_self(),
args: vec!(borrowed_self()),
ret_ty: Literal(path_std!(cx, core::cmp::Ordering)),
attributes: attrs,
combine_substructure: combine_substructure(Box::new(|a, b, c| {
cs_cmp(a, b, c)
})),
}
),
associated_types: Vec::new(),
};
trait_def.expand(cx, mitem, item, push)
}
pub fn ordering_collapsed(cx: &mut ExtCtxt,
span: Span,
self_arg_tags: &[ast::Ident]) -> P<ast::Expr> {
let lft = cx.expr_ident(span, self_arg_tags[0]);
let rgt = cx.expr_addr_of(span, cx.expr_ident(span, self_arg_tags[1]));
cx.expr_method_call(span, lft, cx.ident_of("cmp"), vec![rgt])
}
pub fn cs_cmp(cx: &mut ExtCtxt, span: Span,
substr: &Substructure) -> P<Expr> {
let test_id = cx.ident_of("__test");
let equals_path = cx.path_global(span,
vec!(cx.ident_of_std("core"),
cx.ident_of("cmp"),
cx.ident_of("Ordering"),
cx.ident_of("Equal")));
let cmp_path = vec![
cx.ident_of_std("core"),
cx.ident_of("cmp"),
cx.ident_of("Ord"),
cx.ident_of("cmp"),
];
/*
Builds:
let __test = ::std::cmp::Ord::cmp(&self_field1, &other_field1);
if other == ::std::cmp::Ordering::Equal {
let __test = ::std::cmp::Ord::cmp(&self_field2, &other_field2);
if __test == ::std::cmp::Ordering::Equal {
...
} else {
__test
}
} else {
__test
}
FIXME #6449: These `if`s could/should be `match`es.
*/
cs_fold(
// foldr nests the if-elses correctly, leaving the first field
// as the outermost one, and the last as the innermost.
false,
|cx, span, old, self_f, other_fs| {
// let __test = new;
// if __test == ::std::cmp::Ordering::Equal {
// old
// } else {
// __test
// }
let new = {
let other_f = match other_fs {
[ref o_f] => o_f,
_ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"),
};
let args = vec![
cx.expr_addr_of(span, self_f),
cx.expr_addr_of(span, other_f.clone()),
];
cx.expr_call_global(span, cmp_path.clone(), args)
};
let assign = cx.stmt_let(span, false, test_id, new);
let cond = cx.expr_binary(span, ast::BiEq,
cx.expr_ident(span, test_id),
cx.expr_path(equals_path.clone()));
let if_ = cx.expr_if(span,
cond,
old, Some(cx.expr_ident(span, test_id)));
cx.expr_block(cx.block(span, vec!(assign), Some(if_)))
},
cx.expr_path(equals_path.clone()),
Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| {
if self_args.len() != 2 {
cx.span_bug(span, "not exactly 2 arguments in `derives(Ord)`")
} else {
ordering_collapsed(cx, span, tag_tuple)
}
}),
cx, span, substr)
}

View File

@@ -21,33 +21,30 @@ use parse::token::InternedString;
use parse::token; use parse::token;
use ptr::P; use ptr::P;
pub fn expand_deriving_rustc_decodable<F>(cx: &mut ExtCtxt, pub fn expand_deriving_rustc_decodable(cx: &mut ExtCtxt,
span: Span, span: Span,
mitem: &MetaItem, mitem: &MetaItem,
item: &Item, item: &Item,
push: F) where push: &mut FnMut(P<Item>))
F: FnOnce(P<Item>),
{ {
expand_deriving_decodable_imp(cx, span, mitem, item, push, "rustc_serialize") expand_deriving_decodable_imp(cx, span, mitem, item, push, "rustc_serialize")
} }
pub fn expand_deriving_decodable<F>(cx: &mut ExtCtxt, pub fn expand_deriving_decodable(cx: &mut ExtCtxt,
span: Span, span: Span,
mitem: &MetaItem, mitem: &MetaItem,
item: &Item, item: &Item,
push: F) where push: &mut FnMut(P<Item>))
F: FnOnce(P<Item>),
{ {
expand_deriving_decodable_imp(cx, span, mitem, item, push, "serialize") expand_deriving_decodable_imp(cx, span, mitem, item, push, "serialize")
} }
fn expand_deriving_decodable_imp<F>(cx: &mut ExtCtxt, fn expand_deriving_decodable_imp(cx: &mut ExtCtxt,
span: Span, span: Span,
mitem: &MetaItem, mitem: &MetaItem,
item: &Item, item: &Item,
push: F, push: &mut FnMut(P<Item>),
krate: &'static str) where krate: &'static str)
F: FnOnce(P<Item>),
{ {
if !cx.use_std { if !cx.use_std {
// FIXME(#21880): lift this requirement. // FIXME(#21880): lift this requirement.

View File

@@ -17,12 +17,11 @@ use ext::deriving::generic::ty::*;
use parse::token::InternedString; use parse::token::InternedString;
use ptr::P; use ptr::P;
pub fn expand_deriving_default<F>(cx: &mut ExtCtxt, pub fn expand_deriving_default(cx: &mut ExtCtxt,
span: Span, span: Span,
mitem: &MetaItem, mitem: &MetaItem,
item: &Item, item: &Item,
push: F) where push: &mut FnMut(P<Item>))
F: FnOnce(P<Item>),
{ {
let inline = cx.meta_word(span, InternedString::new("inline")); let inline = cx.meta_word(span, InternedString::new("inline"));
let attrs = vec!(cx.attribute(span, inline)); let attrs = vec!(cx.attribute(span, inline));

View File

@@ -97,33 +97,30 @@ use ext::deriving::generic::ty::*;
use parse::token; use parse::token;
use ptr::P; use ptr::P;
pub fn expand_deriving_rustc_encodable<F>(cx: &mut ExtCtxt, pub fn expand_deriving_rustc_encodable(cx: &mut ExtCtxt,
span: Span, span: Span,
mitem: &MetaItem, mitem: &MetaItem,
item: &Item, item: &Item,
push: F) where push: &mut FnMut(P<Item>))
F: FnOnce(P<Item>),
{ {
expand_deriving_encodable_imp(cx, span, mitem, item, push, "rustc_serialize") expand_deriving_encodable_imp(cx, span, mitem, item, push, "rustc_serialize")
} }
pub fn expand_deriving_encodable<F>(cx: &mut ExtCtxt, pub fn expand_deriving_encodable(cx: &mut ExtCtxt,
span: Span, span: Span,
mitem: &MetaItem, mitem: &MetaItem,
item: &Item, item: &Item,
push: F) where push: &mut FnMut(P<Item>))
F: FnOnce(P<Item>),
{ {
expand_deriving_encodable_imp(cx, span, mitem, item, push, "serialize") expand_deriving_encodable_imp(cx, span, mitem, item, push, "serialize")
} }
fn expand_deriving_encodable_imp<F>(cx: &mut ExtCtxt, fn expand_deriving_encodable_imp(cx: &mut ExtCtxt,
span: Span, span: Span,
mitem: &MetaItem, mitem: &MetaItem,
item: &Item, item: &Item,
push: F, push: &mut FnMut(P<Item>),
krate: &'static str) where krate: &'static str)
F: FnOnce(P<Item>),
{ {
if !cx.use_std { if !cx.use_std {
// FIXME(#21880): lift this requirement. // FIXME(#21880): lift this requirement.

View File

@@ -375,12 +375,11 @@ fn find_type_parameters(ty: &ast::Ty, ty_param_names: &[ast::Name]) -> Vec<P<ast
} }
impl<'a> TraitDef<'a> { impl<'a> TraitDef<'a> {
pub fn expand<F>(&self, pub fn expand(&self,
cx: &mut ExtCtxt, cx: &mut ExtCtxt,
mitem: &ast::MetaItem, mitem: &ast::MetaItem,
item: &ast::Item, item: &ast::Item,
push: F) where push: &mut FnMut(P<ast::Item>))
F: FnOnce(P<ast::Item>),
{ {
let newitem = match item.node { let newitem = match item.node {
ast::ItemStruct(ref struct_def, ref generics) => { ast::ItemStruct(ref struct_def, ref generics) => {

View File

@@ -16,12 +16,11 @@ use ext::deriving::generic::*;
use ext::deriving::generic::ty::*; use ext::deriving::generic::ty::*;
use ptr::P; use ptr::P;
pub fn expand_deriving_hash<F>(cx: &mut ExtCtxt, pub fn expand_deriving_hash(cx: &mut ExtCtxt,
span: Span, span: Span,
mitem: &MetaItem, mitem: &MetaItem,
item: &Item, item: &Item,
push: F) where push: &mut FnMut(P<Item>))
F: FnOnce(P<Item>),
{ {
let path = Path::new_(pathvec_std!(cx, core::hash::Hash), None, let path = Path::new_(pathvec_std!(cx, core::hash::Hash), None,

View File

@@ -65,14 +65,14 @@ pub mod show;
pub mod default; pub mod default;
pub mod primitive; pub mod primitive;
#[path="cmp/partial_eq.rs"]
pub mod partial_eq;
#[path="cmp/eq.rs"] #[path="cmp/eq.rs"]
pub mod eq; pub mod eq;
#[path="cmp/totaleq.rs"] #[path="cmp/partial_ord.rs"]
pub mod totaleq; pub mod partial_ord;
#[path="cmp/ord.rs"] #[path="cmp/ord.rs"]
pub mod ord; pub mod ord;
#[path="cmp/totalord.rs"]
pub mod totalord;
pub mod generic; pub mod generic;
@@ -118,7 +118,7 @@ fn expand_derive(cx: &mut ExtCtxt,
} }
macro_rules! derive_traits { macro_rules! derive_traits {
($( $name:expr => $func:path, )*) => { ($( $name:expr => $func:path, )+) => {
pub fn register_all(env: &mut SyntaxEnv) { pub fn register_all(env: &mut SyntaxEnv) {
// Define the #[derive_*] extensions. // Define the #[derive_*] extensions.
$({ $({
@@ -132,13 +132,13 @@ macro_rules! derive_traits {
item: &Item, item: &Item,
push: &mut FnMut(P<Item>)) { push: &mut FnMut(P<Item>)) {
warn_if_deprecated(ecx, sp, $name); warn_if_deprecated(ecx, sp, $name);
$func(ecx, sp, mitem, item, |i| push(i)); $func(ecx, sp, mitem, item, push);
} }
} }
env.insert(intern(concat!("derive_", $name)), env.insert(intern(concat!("derive_", $name)),
Decorator(Box::new(DeriveExtension))); Decorator(Box::new(DeriveExtension)));
})* })+
env.insert(intern("derive"), env.insert(intern("derive"),
Modifier(Box::new(expand_derive))); Modifier(Box::new(expand_derive)));
@@ -146,7 +146,7 @@ macro_rules! derive_traits {
fn is_builtin_trait(name: &str) -> bool { fn is_builtin_trait(name: &str) -> bool {
match name { match name {
$( $name )|* => true, $( $name )|+ => true,
_ => false, _ => false,
} }
} }
@@ -162,10 +162,10 @@ derive_traits! {
"RustcDecodable" => decodable::expand_deriving_rustc_decodable, "RustcDecodable" => decodable::expand_deriving_rustc_decodable,
"PartialEq" => eq::expand_deriving_eq, "PartialEq" => partial_eq::expand_deriving_partial_eq,
"Eq" => totaleq::expand_deriving_totaleq, "Eq" => eq::expand_deriving_eq,
"PartialOrd" => ord::expand_deriving_ord, "PartialOrd" => partial_ord::expand_deriving_partial_ord,
"Ord" => totalord::expand_deriving_totalord, "Ord" => ord::expand_deriving_ord,
"Debug" => show::expand_deriving_show, "Debug" => show::expand_deriving_show,

View File

@@ -18,12 +18,11 @@ use ext::deriving::generic::ty::*;
use parse::token::InternedString; use parse::token::InternedString;
use ptr::P; use ptr::P;
pub fn expand_deriving_from_primitive<F>(cx: &mut ExtCtxt, pub fn expand_deriving_from_primitive(cx: &mut ExtCtxt,
span: Span, span: Span,
mitem: &MetaItem, mitem: &MetaItem,
item: &Item, item: &Item,
push: F) where push: &mut FnMut(P<Item>))
F: FnOnce(P<Item>),
{ {
let inline = cx.meta_word(span, InternedString::new("inline")); let inline = cx.meta_word(span, InternedString::new("inline"));
let attrs = vec!(cx.attribute(span, inline)); let attrs = vec!(cx.attribute(span, inline));

View File

@@ -18,12 +18,11 @@ use ext::deriving::generic::ty::*;
use parse::token; use parse::token;
use ptr::P; use ptr::P;
pub fn expand_deriving_show<F>(cx: &mut ExtCtxt, pub fn expand_deriving_show(cx: &mut ExtCtxt,
span: Span, span: Span,
mitem: &MetaItem, mitem: &MetaItem,
item: &Item, item: &Item,
push: F) where push: &mut FnMut(P<Item>))
F: FnOnce(P<Item>),
{ {
// &mut ::std::fmt::Formatter // &mut ::std::fmt::Formatter
let fmtr = Ptr(box Literal(path_std!(cx, core::fmt::Formatter)), let fmtr = Ptr(box Literal(path_std!(cx, core::fmt::Formatter)),

View File

@@ -122,7 +122,6 @@ impl fmt::Display for TestName {
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
enum NamePadding { enum NamePadding {
PadNone, PadNone,
PadOnLeft,
PadOnRight, PadOnRight,
} }
@@ -130,13 +129,9 @@ impl TestDesc {
fn padded_name(&self, column_count: usize, align: NamePadding) -> String { fn padded_name(&self, column_count: usize, align: NamePadding) -> String {
let mut name = String::from_str(self.name.as_slice()); let mut name = String::from_str(self.name.as_slice());
let fill = column_count.saturating_sub(name.len()); let fill = column_count.saturating_sub(name.len());
let mut pad = repeat(" ").take(fill).collect::<String>(); let pad = repeat(" ").take(fill).collect::<String>();
match align { match align {
PadNone => name, PadNone => name,
PadOnLeft => {
pad.push_str(&name);
pad
}
PadOnRight => { PadOnRight => {
name.push_str(&pad); name.push_str(&pad);
name name
@@ -690,7 +685,7 @@ pub fn run_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn> ) -> io::Res
fn len_if_padded(t: &TestDescAndFn) -> usize { fn len_if_padded(t: &TestDescAndFn) -> usize {
match t.testfn.padding() { match t.testfn.padding() {
PadNone => 0, PadNone => 0,
PadOnLeft | PadOnRight => t.desc.name.as_slice().len(), PadOnRight => t.desc.name.as_slice().len(),
} }
} }
match tests.iter().max_by(|t|len_if_padded(*t)) { match tests.iter().max_by(|t|len_if_padded(*t)) {

View File

@@ -70,5 +70,5 @@ fn expand(cx: &mut ExtCtxt,
], ],
}; };
trait_def.expand(cx, mitem, item, |i| push(i)) trait_def.expand(cx, mitem, item, push)
} }