]> git.lizzy.rs Git - rust.git/blob - src/libsyntax_ext/deriving/cmp/ord.rs
Auto merge of #65495 - Centril:rollup-tguwjt5, r=Centril
[rust.git] / src / libsyntax_ext / deriving / cmp / ord.rs
1 use crate::deriving::path_std;
2 use crate::deriving::generic::*;
3 use crate::deriving::generic::ty::*;
4
5 use syntax::ast::{self, Expr, MetaItem};
6 use syntax_expand::base::{Annotatable, ExtCtxt};
7 use syntax::ptr::P;
8 use syntax::symbol::sym;
9 use syntax_pos::Span;
10
11 pub fn expand_deriving_ord(cx: &mut ExtCtxt<'_>,
12                            span: Span,
13                            mitem: &MetaItem,
14                            item: &Annotatable,
15                            push: &mut dyn FnMut(Annotatable)) {
16     let inline = cx.meta_word(span, sym::inline);
17     let attrs = vec![cx.attribute(inline)];
18     let trait_def = TraitDef {
19         span,
20         attributes: Vec::new(),
21         path: path_std!(cx, cmp::Ord),
22         additional_bounds: Vec::new(),
23         generics: LifetimeBounds::empty(),
24         is_unsafe: false,
25         supports_unions: false,
26         methods: vec![MethodDef {
27                           name: "cmp",
28                           generics: LifetimeBounds::empty(),
29                           explicit_self: borrowed_explicit_self(),
30                           args: vec![(borrowed_self(), "other")],
31                           ret_ty: Literal(path_std!(cx, cmp::Ordering)),
32                           attributes: attrs,
33                           is_unsafe: false,
34                           unify_fieldless_variants: true,
35                           combine_substructure: combine_substructure(Box::new(|a, b, c| {
36                               cs_cmp(a, b, c)
37                           })),
38                       }],
39         associated_types: Vec::new(),
40     };
41
42     trait_def.expand(cx, mitem, item, push)
43 }
44
45
46 pub fn ordering_collapsed(
47     cx: &mut ExtCtxt<'_>,
48     span: Span,
49     self_arg_tags: &[ast::Ident],
50 ) -> P<ast::Expr> {
51     let lft = cx.expr_ident(span, self_arg_tags[0]);
52     let rgt = cx.expr_addr_of(span, cx.expr_ident(span, self_arg_tags[1]));
53     cx.expr_method_call(span, lft, ast::Ident::new(sym::cmp, span), vec![rgt])
54 }
55
56 pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<Expr> {
57     let test_id = ast::Ident::new(sym::cmp, span);
58     let equals_path = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal]));
59
60     let cmp_path = cx.std_path(&[sym::cmp, sym::Ord, sym::cmp]);
61
62     // Builds:
63     //
64     // match ::std::cmp::Ord::cmp(&self_field1, &other_field1) {
65     // ::std::cmp::Ordering::Equal =>
66     // match ::std::cmp::Ord::cmp(&self_field2, &other_field2) {
67     // ::std::cmp::Ordering::Equal => {
68     // ...
69     // }
70     // cmp => cmp
71     // },
72     // cmp => cmp
73     // }
74     //
75     cs_fold(// foldr nests the if-elses correctly, leaving the first field
76             // as the outermost one, and the last as the innermost.
77             false,
78             |cx, span, old, self_f, other_fs| {
79                 // match new {
80                 //     ::std::cmp::Ordering::Equal => old,
81                 //     cmp => cmp
82                 // }
83
84                 let new = {
85                     let other_f = match other_fs {
86                         [o_f] => o_f,
87                         _ => cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`"),
88                     };
89
90                     let args = vec![
91                             cx.expr_addr_of(span, self_f),
92                             cx.expr_addr_of(span, other_f.clone()),
93                         ];
94
95                     cx.expr_call_global(span, cmp_path.clone(), args)
96                 };
97
98                 let eq_arm = cx.arm(span, cx.pat_path(span, equals_path.clone()), old);
99                 let neq_arm = cx.arm(span,
100                                      cx.pat_ident(span, test_id),
101                                      cx.expr_ident(span, test_id));
102
103                 cx.expr_match(span, new, vec![eq_arm, neq_arm])
104             },
105             cx.expr_path(equals_path.clone()),
106             Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| {
107         if self_args.len() != 2 {
108             cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`")
109         } else {
110             ordering_collapsed(cx, span, tag_tuple)
111         }
112     }),
113             cx,
114             span,
115             substr)
116 }