rustc_builtin_macros/deriving/cmp/
partial_eq.rs
1use rustc_ast::ptr::P;
2use rustc_ast::{BinOpKind, BorrowKind, Expr, ExprKind, MetaItem, Mutability};
3use rustc_expand::base::{Annotatable, ExtCtxt};
4use rustc_span::{Span, sym};
5use thin_vec::thin_vec;
6
7use crate::deriving::generic::ty::*;
8use crate::deriving::generic::*;
9use crate::deriving::{path_local, path_std};
10
11pub(crate) fn expand_deriving_partial_eq(
12 cx: &ExtCtxt<'_>,
13 span: Span,
14 mitem: &MetaItem,
15 item: &Annotatable,
16 push: &mut dyn FnMut(Annotatable),
17 is_const: bool,
18) {
19 fn cs_eq(cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
20 let base = true;
21 let expr = cs_fold(
22 true, cx,
24 span,
25 substr,
26 |cx, fold| match fold {
27 CsFold::Single(field) => {
28 let [other_expr] = &field.other_selflike_exprs[..] else {
29 cx.dcx()
30 .span_bug(field.span, "not exactly 2 arguments in `derive(PartialEq)`");
31 };
32
33 let convert = |expr: &P<Expr>| {
45 if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) =
46 &expr.kind
47 {
48 if let ExprKind::Block(..) = &inner.kind {
49 cx.expr_paren(field.span, inner.clone())
51 } else {
52 inner.clone()
54 }
55 } else {
56 expr.clone()
57 }
58 };
59 cx.expr_binary(
60 field.span,
61 BinOpKind::Eq,
62 convert(&field.self_expr),
63 convert(other_expr),
64 )
65 }
66 CsFold::Combine(span, expr1, expr2) => {
67 cx.expr_binary(span, BinOpKind::And, expr1, expr2)
68 }
69 CsFold::Fieldless => cx.expr_bool(span, base),
70 },
71 );
72 BlockOrExpr::new_expr(expr)
73 }
74
75 let structural_trait_def = TraitDef {
76 span,
77 path: path_std!(marker::StructuralPartialEq),
78 skip_path_as_bound: true, needs_copy_as_bound_if_packed: false,
80 additional_bounds: Vec::new(),
81 supports_unions: true,
84 methods: Vec::new(),
85 associated_types: Vec::new(),
86 is_const: false,
87 };
88 structural_trait_def.expand(cx, mitem, item, push);
89
90 let methods = vec![MethodDef {
93 name: sym::eq,
94 generics: Bounds::empty(),
95 explicit_self: true,
96 nonself_args: vec![(self_ref(), sym::other)],
97 ret_ty: Path(path_local!(bool)),
98 attributes: thin_vec![cx.attr_word(sym::inline, span)],
99 fieldless_variants_strategy: FieldlessVariantsStrategy::Unify,
100 combine_substructure: combine_substructure(Box::new(|a, b, c| cs_eq(a, b, c))),
101 }];
102
103 let trait_def = TraitDef {
104 span,
105 path: path_std!(cmp::PartialEq),
106 skip_path_as_bound: false,
107 needs_copy_as_bound_if_packed: true,
108 additional_bounds: Vec::new(),
109 supports_unions: false,
110 methods,
111 associated_types: Vec::new(),
112 is_const,
113 };
114 trait_def.expand(cx, mitem, item, push)
115}