]> git.lizzy.rs Git - rust.git/blob - src/librustc_builtin_macros/deriving/default.rs
Auto merge of #67733 - pietroalbini:gha-2, r=alexcrichton
[rust.git] / src / librustc_builtin_macros / deriving / default.rs
1 use crate::deriving::generic::ty::*;
2 use crate::deriving::generic::*;
3 use crate::deriving::path_std;
4
5 use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt};
6 use rustc_span::symbol::{kw, sym};
7 use rustc_span::Span;
8 use syntax::ast::{Expr, MetaItem};
9 use syntax::ptr::P;
10 use syntax::span_err;
11
12 use rustc_error_codes::*;
13
14 pub fn expand_deriving_default(
15     cx: &mut ExtCtxt<'_>,
16     span: Span,
17     mitem: &MetaItem,
18     item: &Annotatable,
19     push: &mut dyn FnMut(Annotatable),
20 ) {
21     let inline = cx.meta_word(span, sym::inline);
22     let attrs = vec![cx.attribute(inline)];
23     let trait_def = TraitDef {
24         span,
25         attributes: Vec::new(),
26         path: path_std!(cx, default::Default),
27         additional_bounds: Vec::new(),
28         generics: LifetimeBounds::empty(),
29         is_unsafe: false,
30         supports_unions: false,
31         methods: vec![MethodDef {
32             name: "default",
33             generics: LifetimeBounds::empty(),
34             explicit_self: None,
35             args: Vec::new(),
36             ret_ty: Self_,
37             attributes: attrs,
38             is_unsafe: false,
39             unify_fieldless_variants: false,
40             combine_substructure: combine_substructure(Box::new(|a, b, c| {
41                 default_substructure(a, b, c)
42             })),
43         }],
44         associated_types: Vec::new(),
45     };
46     trait_def.expand(cx, mitem, item, push)
47 }
48
49 fn default_substructure(
50     cx: &mut ExtCtxt<'_>,
51     trait_span: Span,
52     substr: &Substructure<'_>,
53 ) -> P<Expr> {
54     // Note that `kw::Default` is "default" and `sym::Default` is "Default"!
55     let default_ident = cx.std_path(&[kw::Default, sym::Default, kw::Default]);
56     let default_call = |span| cx.expr_call_global(span, default_ident.clone(), Vec::new());
57
58     return match *substr.fields {
59         StaticStruct(_, ref summary) => match *summary {
60             Unnamed(ref fields, is_tuple) => {
61                 if !is_tuple {
62                     cx.expr_ident(trait_span, substr.type_ident)
63                 } else {
64                     let exprs = fields.iter().map(|sp| default_call(*sp)).collect();
65                     cx.expr_call_ident(trait_span, substr.type_ident, exprs)
66                 }
67             }
68             Named(ref fields) => {
69                 let default_fields = fields
70                     .iter()
71                     .map(|&(ident, span)| cx.field_imm(span, ident, default_call(span)))
72                     .collect();
73                 cx.expr_struct_ident(trait_span, substr.type_ident, default_fields)
74             }
75         },
76         StaticEnum(..) => {
77             span_err!(cx, trait_span, E0665, "`Default` cannot be derived for enums, only structs");
78             // let compilation continue
79             DummyResult::raw_expr(trait_span, true)
80         }
81         _ => cx.span_bug(trait_span, "method in `derive(Default)`"),
82     };
83 }