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