derive: Emit only PartialOrd::partial_cmp for simple enums

Using the same logic as for `PartialEq`, when possible define only
`partial_cmp` and leave `lt, le, gt, ge` to their default
implementations. This works well for c-like enums.
This commit is contained in:
Ulrik Sverdrup 2016-03-01 02:27:27 +01:00
parent 57e0a7e5d8
commit edcc02bfee
3 changed files with 35 additions and 24 deletions

View File

@ -11,29 +11,13 @@
use deriving::generic::*;
use deriving::generic::ty::*;
use syntax::ast::{MetaItem, Expr, BinOpKind, ItemKind};
use syntax::ast::{MetaItem, Expr, BinOpKind};
use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, Annotatable};
use syntax::ext::build::AstBuilder;
use syntax::parse::token::InternedString;
use syntax::ptr::P;
fn is_type_without_fields(item: &Annotatable) -> bool {
if let Annotatable::Item(ref item) = *item {
match item.node {
ItemKind::Enum(ref enum_def, _) => {
enum_def.variants.iter().all(|v| v.node.data.fields().is_empty())
}
ItemKind::Struct(ref variant_data, _) => {
variant_data.fields().is_empty()
}
_ => false
}
} else {
false
}
}
pub fn expand_deriving_partial_eq(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,

View File

@ -67,6 +67,21 @@ pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt,
}))
};
// avoid defining extra methods if we can
// c-like enums, enums without any fields and structs without fields
// can safely define only `partial_cmp`.
let methods = if is_type_without_fields(item) {
vec![partial_cmp_def]
} else {
vec![
partial_cmp_def,
md!("lt", true, false),
md!("le", true, true),
md!("gt", false, false),
md!("ge", false, true)
]
};
let trait_def = TraitDef {
span: span,
attributes: vec![],
@ -74,13 +89,7 @@ pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt,
additional_bounds: vec![],
generics: LifetimeBounds::empty(),
is_unsafe: false,
methods: vec![
partial_cmp_def,
md!("lt", true, false),
md!("le", true, true),
md!("gt", false, false),
md!("ge", false, true)
],
methods: methods,
associated_types: Vec::new(),
};
trait_def.expand(cx, mitem, item, push)

View File

@ -1638,3 +1638,21 @@ pub fn cs_same_method<F>(f: F,
}
}
}
/// Return true if the type has no value fields
/// (for an enum, no variant has any fields)
pub fn is_type_without_fields(item: &Annotatable) -> bool {
if let Annotatable::Item(ref item) = *item {
match item.node {
ast::ItemKind::Enum(ref enum_def, _) => {
enum_def.variants.iter().all(|v| v.node.data.fields().is_empty())
}
ast::ItemKind::Struct(ref variant_data, _) => {
variant_data.fields().is_empty()
}
_ => false
}
} else {
false
}
}