]>
Commit | Line | Data |
---|---|---|
dfeec247 XL |
1 | use crate::deriving::generic::ty::*; |
2 | use crate::deriving::generic::*; | |
3 | use crate::deriving::path_std; | |
4 | ||
064997fb | 5 | use rustc_ast::MetaItem; |
dfeec247 | 6 | use rustc_expand::base::{Annotatable, ExtCtxt}; |
f9f354fc | 7 | use rustc_span::symbol::{sym, Ident}; |
dfeec247 | 8 | use rustc_span::Span; |
dfeec247 XL |
9 | |
10 | pub fn expand_deriving_ord( | |
11 | cx: &mut ExtCtxt<'_>, | |
12 | span: Span, | |
13 | mitem: &MetaItem, | |
14 | item: &Annotatable, | |
15 | push: &mut dyn FnMut(Annotatable), | |
16 | ) { | |
17 | let inline = cx.meta_word(span, sym::inline); | |
18 | let attrs = vec![cx.attribute(inline)]; | |
19 | let trait_def = TraitDef { | |
20 | span, | |
21 | attributes: Vec::new(), | |
3dfed10e | 22 | path: path_std!(cmp::Ord), |
dfeec247 | 23 | additional_bounds: Vec::new(), |
3dfed10e | 24 | generics: Bounds::empty(), |
dfeec247 XL |
25 | supports_unions: false, |
26 | methods: vec![MethodDef { | |
3dfed10e XL |
27 | name: sym::cmp, |
28 | generics: Bounds::empty(), | |
064997fb FG |
29 | explicit_self: true, |
30 | nonself_args: vec![(self_ref(), sym::other)], | |
31 | ret_ty: Path(path_std!(cmp::Ordering)), | |
dfeec247 | 32 | attributes: attrs, |
dfeec247 XL |
33 | unify_fieldless_variants: true, |
34 | combine_substructure: combine_substructure(Box::new(|a, b, c| cs_cmp(a, b, c))), | |
35 | }], | |
36 | associated_types: Vec::new(), | |
37 | }; | |
38 | ||
39 | trait_def.expand(cx, mitem, item, push) | |
40 | } | |
41 | ||
064997fb | 42 | pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr { |
f9f354fc | 43 | let test_id = Ident::new(sym::cmp, span); |
064997fb | 44 | let equal_path = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal])); |
dfeec247 XL |
45 | let cmp_path = cx.std_path(&[sym::cmp, sym::Ord, sym::cmp]); |
46 | ||
47 | // Builds: | |
48 | // | |
064997fb FG |
49 | // match ::core::cmp::Ord::cmp(&self.x, &other.x) { |
50 | // ::std::cmp::Ordering::Equal => | |
51 | // ::core::cmp::Ord::cmp(&self.y, &other.y), | |
52 | // cmp => cmp, | |
dfeec247 | 53 | // } |
064997fb | 54 | let expr = cs_fold( |
dfeec247 XL |
55 | // foldr nests the if-elses correctly, leaving the first field |
56 | // as the outermost one, and the last as the innermost. | |
57 | false, | |
dfeec247 XL |
58 | cx, |
59 | span, | |
60 | substr, | |
064997fb FG |
61 | |cx, fold| match fold { |
62 | CsFold::Single(field) => { | |
63 | let [other_expr] = &field.other_selflike_exprs[..] else { | |
64 | cx.span_bug(field.span, "not exactly 2 arguments in `derive(Ord)`"); | |
65 | }; | |
66 | let args = vec![field.self_expr.clone(), other_expr.clone()]; | |
67 | cx.expr_call_global(field.span, cmp_path.clone(), args) | |
68 | } | |
69 | CsFold::Combine(span, expr1, expr2) => { | |
70 | let eq_arm = cx.arm(span, cx.pat_path(span, equal_path.clone()), expr1); | |
71 | let neq_arm = | |
72 | cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id)); | |
73 | cx.expr_match(span, expr2, vec![eq_arm, neq_arm]) | |
74 | } | |
75 | CsFold::Fieldless => cx.expr_path(equal_path.clone()), | |
76 | }, | |
77 | ); | |
78 | BlockOrExpr::new_expr(expr) | |
dfeec247 | 79 | } |