Implement RFC#28: Add PartialOrd::partial_cmp

I ended up altering the semantics of Json's PartialOrd implementation.
It used to be the case that Null < Null, but I can't think of any reason
for an ordering other than the default one so I just switched it over to
using the derived implementation.

This also fixes broken `PartialOrd` implementations for `Vec` and
`TreeMap`.

RFC: 0028-partial-cmp
This commit is contained in:
Steven Fackler 2014-06-17 23:25:51 -07:00
parent bb5695b95c
commit 55cae0a094
28 changed files with 343 additions and 161 deletions

View file

@ -43,22 +43,116 @@ pub fn expand_deriving_ord(cx: &mut ExtCtxt,
} }
);
let ordering_ty = Literal(Path::new(vec!["std", "cmp", "Ordering"]));
let ret_ty = Literal(Path::new_(vec!["std", "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,
const_nonmatching: false,
combine_substructure: combine_substructure(|cx, span, substr| {
cs_partial_cmp(cx, span, substr)
})
};
let trait_def = TraitDef {
span: span,
attributes: Vec::new(),
path: Path::new(vec!("std", "cmp", "PartialOrd")),
additional_bounds: Vec::new(),
attributes: vec![],
path: Path::new(vec!["std", "cmp", "PartialOrd"]),
additional_bounds: vec![],
generics: LifetimeBounds::empty(),
methods: vec!(
methods: vec![
partial_cmp_def,
md!("lt", true, false),
md!("le", true, true),
md!("gt", false, false),
md!("ge", false, true)
)
]
};
trait_def.expand(cx, mitem, item, push)
}
pub fn some_ordering_const(cx: &mut ExtCtxt, span: Span, cnst: Ordering) -> Gc<ast::Expr> {
let cnst = match cnst {
Less => "Less",
Equal => "Equal",
Greater => "Greater"
};
let ordering = cx.path_global(span,
vec!(cx.ident_of("std"),
cx.ident_of("cmp"),
cx.ident_of(cnst)));
let ordering = cx.expr_path(ordering);
cx.expr_some(span, ordering)
}
pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span,
substr: &Substructure) -> Gc<Expr> {
let test_id = cx.ident_of("__test");
let equals_expr = some_ordering_const(cx, span, Equal);
/*
Builds:
let __test = self_field1.partial_cmp(&other_field2);
if __test == ::std::option::Some(::std::cmp::Equal) {
let __test = self_field2.partial_cmp(&other_field2);
if __test == ::std::option::Some(::std::cmp::Equal) {
...
} else {
__test
}
} else {
__test
}
FIXME #6449: These `if`s could/should be `match`es.
*/
cs_same_method_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, new| {
// let __test = new;
// if __test == Some(::std::cmp::Equal) {
// old
// } else {
// __test
// }
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(),
|cx, span, list, _| {
match list {
// an earlier nonmatching variant is Less than a
// later one.
[(self_var, _, _), (other_var, _, _)] =>
some_ordering_const(cx, span, self_var.cmp(&other_var)),
_ => cx.span_bug(span, "not exactly 2 arguments in `deriving(Ord)`")
}
},
cx, span, substr)
}
/// Strict inequality.
fn cs_op(less: bool, equal: bool, cx: &mut ExtCtxt, span: Span,
substr: &Substructure) -> Gc<Expr> {