]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
New upstream version 1.61.0+dfsg1
[rustc.git] / compiler / rustc_builtin_macros / src / deriving / cmp / partial_eq.rs
CommitLineData
9fa01778 1use crate::deriving::generic::ty::*;
dfeec247
XL
2use crate::deriving::generic::*;
3use crate::deriving::{path_local, path_std};
9cc50fc6 4
74b04a01 5use rustc_ast::ptr::P;
3dfed10e 6use rustc_ast::{BinOpKind, Expr, MetaItem};
dfeec247
XL
7use rustc_expand::base::{Annotatable, ExtCtxt};
8use rustc_span::symbol::sym;
9use rustc_span::Span;
d9579d0f 10
dfeec247
XL
11pub 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}