1 use crate::deriving::{path_local, path_std};
2 use crate::deriving::generic::*;
3 use crate::deriving::generic::ty::*;
5 use syntax::ast::{BinOpKind, Expr, MetaItem};
6 use syntax::ext::base::{Annotatable, ExtCtxt};
7 use syntax::ext::build::AstBuilder;
9 use syntax::symbol::sym;
12 pub fn expand_deriving_partial_eq(cx: &mut ExtCtxt<'_>,
16 push: &mut dyn FnMut(Annotatable)) {
17 // structures are equal if all fields are equal, and non equal, if
18 // any fields are not equal or if the enum variants are different
19 fn cs_op(cx: &mut ExtCtxt<'_>,
21 substr: &Substructure<'_>,
27 let op = |cx: &mut ExtCtxt<'_>, span: Span, self_f: P<Expr>, other_fs: &[P<Expr>]| {
28 let other_f = match other_fs {
30 _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`"),
33 cx.expr_binary(span, op, self_f, other_f.clone())
36 cs_fold1(true, // use foldl
37 |cx, span, subexpr, self_f, other_fs| {
38 let eq = op(cx, span, self_f, other_fs);
39 cx.expr_binary(span, combiner, subexpr, eq)
43 Some((span, self_f, other_fs)) => {
44 // Special-case the base case to generate cleaner code.
45 op(cx, span, self_f, other_fs)
47 None => cx.expr_bool(span, base),
50 Box::new(|cx, span, _, _| cx.expr_bool(span, !base)),
56 fn cs_eq(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<Expr> {
57 cs_op(cx, span, substr, BinOpKind::Eq, BinOpKind::And, true)
59 fn cs_ne(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<Expr> {
60 cs_op(cx, span, substr, BinOpKind::Ne, BinOpKind::Or, false)
64 ($name:expr, $f:ident) => { {
65 let inline = cx.meta_word(span, sym::inline);
66 let attrs = vec![cx.attribute(inline)];
69 generics: LifetimeBounds::empty(),
70 explicit_self: borrowed_explicit_self(),
71 args: vec![(borrowed_self(), "other")],
72 ret_ty: Literal(path_local!(bool)),
75 unify_fieldless_variants: true,
76 combine_substructure: combine_substructure(Box::new(|a, b, c| {
83 // avoid defining `ne` if we can
84 // c-like enums, enums without any fields and structs without fields
85 // can safely define only `eq`.
86 let mut methods = vec![md!("eq", cs_eq)];
87 if !is_type_without_fields(item) {
88 methods.push(md!("ne", cs_ne));
91 let trait_def = TraitDef {
93 attributes: Vec::new(),
94 path: path_std!(cx, cmp::PartialEq),
95 additional_bounds: Vec::new(),
96 generics: LifetimeBounds::empty(),
98 supports_unions: false,
100 associated_types: Vec::new(),
102 trait_def.expand(cx, mitem, item, push)