]> git.lizzy.rs Git - rust.git/blob - src/libsyntax_ext/deriving/cmp/partial_eq.rs
Replace AstBuilder with inherent methods
[rust.git] / src / libsyntax_ext / deriving / cmp / partial_eq.rs
1 use crate::deriving::{path_local, path_std};
2 use crate::deriving::generic::*;
3 use crate::deriving::generic::ty::*;
4
5 use syntax::ast::{BinOpKind, Expr, MetaItem};
6 use syntax::ext::base::{Annotatable, ExtCtxt};
7 use syntax::ptr::P;
8 use syntax::symbol::sym;
9 use syntax_pos::Span;
10
11 pub fn expand_deriving_partial_eq(cx: &mut ExtCtxt<'_>,
12                                   span: Span,
13                                   mitem: &MetaItem,
14                                   item: &Annotatable,
15                                   push: &mut dyn FnMut(Annotatable)) {
16     // structures are equal if all fields are equal, and non equal, if
17     // any fields are not equal or if the enum variants are different
18     fn cs_op(cx: &mut ExtCtxt<'_>,
19              span: Span,
20              substr: &Substructure<'_>,
21              op: BinOpKind,
22              combiner: BinOpKind,
23              base: bool)
24              -> P<Expr>
25     {
26         let op = |cx: &mut ExtCtxt<'_>, span: Span, self_f: P<Expr>, other_fs: &[P<Expr>]| {
27             let other_f = match other_fs {
28                 [o_f] => o_f,
29                 _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`"),
30             };
31
32             cx.expr_binary(span, op, self_f, other_f.clone())
33         };
34
35         cs_fold1(true, // use foldl
36             |cx, span, subexpr, self_f, other_fs| {
37                 let eq = op(cx, span, self_f, other_fs);
38                 cx.expr_binary(span, combiner, subexpr, eq)
39             },
40             |cx, args| {
41                 match args {
42                     Some((span, self_f, other_fs)) => {
43                         // Special-case the base case to generate cleaner code.
44                         op(cx, span, self_f, other_fs)
45                     }
46                     None => cx.expr_bool(span, base),
47                 }
48             },
49             Box::new(|cx, span, _, _| cx.expr_bool(span, !base)),
50             cx,
51             span,
52             substr)
53     }
54
55     fn cs_eq(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<Expr> {
56         cs_op(cx, span, substr, BinOpKind::Eq, BinOpKind::And, true)
57     }
58     fn cs_ne(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<Expr> {
59         cs_op(cx, span, substr, BinOpKind::Ne, BinOpKind::Or, false)
60     }
61
62     macro_rules! md {
63         ($name:expr, $f:ident) => { {
64             let inline = cx.meta_word(span, sym::inline);
65             let attrs = vec![cx.attribute(inline)];
66             MethodDef {
67                 name: $name,
68                 generics: LifetimeBounds::empty(),
69                 explicit_self: borrowed_explicit_self(),
70                 args: vec![(borrowed_self(), "other")],
71                 ret_ty: Literal(path_local!(bool)),
72                 attributes: attrs,
73                 is_unsafe: false,
74                 unify_fieldless_variants: true,
75                 combine_substructure: combine_substructure(Box::new(|a, b, c| {
76                     $f(a, b, c)
77                 }))
78             }
79         } }
80     }
81
82     // avoid defining `ne` if we can
83     // c-like enums, enums without any fields and structs without fields
84     // can safely define only `eq`.
85     let mut methods = vec![md!("eq", cs_eq)];
86     if !is_type_without_fields(item) {
87         methods.push(md!("ne", cs_ne));
88     }
89
90     let trait_def = TraitDef {
91         span,
92         attributes: Vec::new(),
93         path: path_std!(cx, cmp::PartialEq),
94         additional_bounds: Vec::new(),
95         generics: LifetimeBounds::empty(),
96         is_unsafe: false,
97         supports_unions: false,
98         methods,
99         associated_types: Vec::new(),
100     };
101     trait_def.expand(cx, mitem, item, push)
102 }