]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
Remove TraitDef::generics.
[rust.git] / compiler / rustc_builtin_macros / src / deriving / cmp / partial_eq.rs
1 use crate::deriving::generic::ty::*;
2 use crate::deriving::generic::*;
3 use crate::deriving::{path_local, path_std};
4 use rustc_ast::ptr::P;
5 use rustc_ast::{BinOpKind, BorrowKind, Expr, ExprKind, MetaItem, Mutability};
6 use rustc_expand::base::{Annotatable, ExtCtxt};
7 use rustc_span::symbol::sym;
8 use rustc_span::Span;
9 use thin_vec::thin_vec;
10
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 ) {
18     fn cs_eq(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
19         let base = true;
20         let expr = cs_fold(
21             true, // use foldl
22             cx,
23             span,
24             substr,
25             |cx, fold| match fold {
26                 CsFold::Single(field) => {
27                     let [other_expr] = &field.other_selflike_exprs[..] else {
28                         cx.span_bug(field.span, "not exactly 2 arguments in `derive(PartialEq)`");
29                     };
30
31                     // We received `&T` arguments. Convert them to `T` by
32                     // stripping `&` or adding `*`. This isn't necessary for
33                     // type checking, but it results in much better error
34                     // messages if something goes wrong.
35                     let convert = |expr: &P<Expr>| {
36                         if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) =
37                             &expr.kind
38                         {
39                             inner.clone()
40                         } else {
41                             cx.expr_deref(field.span, expr.clone())
42                         }
43                     };
44                     cx.expr_binary(
45                         field.span,
46                         BinOpKind::Eq,
47                         convert(&field.self_expr),
48                         convert(other_expr),
49                     )
50                 }
51                 CsFold::Combine(span, expr1, expr2) => {
52                     cx.expr_binary(span, BinOpKind::And, expr1, expr2)
53                 }
54                 CsFold::Fieldless => cx.expr_bool(span, base),
55             },
56         );
57         BlockOrExpr::new_expr(expr)
58     }
59
60     super::inject_impl_of_structural_trait(
61         cx,
62         span,
63         item,
64         path_std!(marker::StructuralPartialEq),
65         push,
66     );
67
68     // No need to generate `ne`, the default suffices, and not generating it is
69     // faster.
70     let inline = cx.meta_word(span, sym::inline);
71     let attrs = thin_vec![cx.attribute(inline)];
72     let methods = vec![MethodDef {
73         name: sym::eq,
74         generics: Bounds::empty(),
75         explicit_self: true,
76         nonself_args: vec![(self_ref(), sym::other)],
77         ret_ty: Path(path_local!(bool)),
78         attributes: attrs,
79         unify_fieldless_variants: true,
80         combine_substructure: combine_substructure(Box::new(|a, b, c| cs_eq(a, b, c))),
81     }];
82
83     let trait_def = TraitDef {
84         span,
85         path: path_std!(cmp::PartialEq),
86         skip_path_as_bound: false,
87         additional_bounds: Vec::new(),
88         supports_unions: false,
89         methods,
90         associated_types: Vec::new(),
91     };
92     trait_def.expand(cx, mitem, item, push)
93 }