]>
Commit | Line | Data |
---|---|---|
9fa01778 | 1 | use crate::deriving::generic::ty::*; |
dfeec247 XL |
2 | use crate::deriving::generic::*; |
3 | use crate::deriving::path_std; | |
9cc50fc6 | 4 | |
74b04a01 XL |
5 | use rustc_ast::ast::{self, Ident}; |
6 | use rustc_ast::ast::{Expr, MetaItem}; | |
7 | use rustc_ast::ptr::P; | |
dfeec247 XL |
8 | use rustc_expand::base::{Annotatable, ExtCtxt}; |
9 | use rustc_span::symbol::sym; | |
10 | use rustc_span::{Span, DUMMY_SP}; | |
1a4d82fc | 11 | |
dfeec247 XL |
12 | pub fn expand_deriving_debug( |
13 | cx: &mut ExtCtxt<'_>, | |
14 | span: Span, | |
15 | mitem: &MetaItem, | |
16 | item: &Annotatable, | |
17 | push: &mut dyn FnMut(Annotatable), | |
18 | ) { | |
1a4d82fc | 19 | // &mut ::std::fmt::Formatter |
dfeec247 XL |
20 | let fmtr = |
21 | Ptr(Box::new(Literal(path_std!(cx, fmt::Formatter))), Borrowed(None, ast::Mutability::Mut)); | |
1a4d82fc JJ |
22 | |
23 | let trait_def = TraitDef { | |
3b2f2976 | 24 | span, |
1a4d82fc | 25 | attributes: Vec::new(), |
ff7c6d11 | 26 | path: path_std!(cx, fmt::Debug), |
1a4d82fc JJ |
27 | additional_bounds: Vec::new(), |
28 | generics: LifetimeBounds::empty(), | |
e9174d1e | 29 | is_unsafe: false, |
9e0c209e | 30 | supports_unions: false, |
5bcae85e | 31 | methods: vec![MethodDef { |
dfeec247 XL |
32 | name: "fmt", |
33 | generics: LifetimeBounds::empty(), | |
34 | explicit_self: borrowed_explicit_self(), | |
35 | args: vec![(fmtr, "f")], | |
36 | ret_ty: Literal(path_std!(cx, fmt::Result)), | |
37 | attributes: Vec::new(), | |
38 | is_unsafe: false, | |
39 | unify_fieldless_variants: false, | |
40 | combine_substructure: combine_substructure(Box::new(|a, b, c| { | |
41 | show_substructure(a, b, c) | |
42 | })), | |
43 | }], | |
85aaf69f | 44 | associated_types: Vec::new(), |
1a4d82fc | 45 | }; |
62682a34 | 46 | trait_def.expand(cx, mitem, item, push) |
1a4d82fc JJ |
47 | } |
48 | ||
c34b1796 | 49 | /// We use the debug builders to do the heavy lifting here |
9fa01778 | 50 | fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<Expr> { |
c34b1796 AL |
51 | // build fmt.debug_struct(<name>).field(<fieldname>, &<fieldval>)....build() |
52 | // or fmt.debug_tuple(<name>).field(&<fieldval>)....build() | |
53 | // based on the "shape". | |
532ac7d7 XL |
54 | let (ident, vdata, fields) = match substr.fields { |
55 | Struct(vdata, fields) => (substr.type_ident, *vdata, fields), | |
e1599b0c | 56 | EnumMatching(_, _, v, fields) => (v.ident, &v.data, fields), |
dfeec247 XL |
57 | EnumNonMatchingCollapsed(..) | StaticStruct(..) | StaticEnum(..) => { |
58 | cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`") | |
59 | } | |
1a4d82fc JJ |
60 | }; |
61 | ||
cc61c64b | 62 | // We want to make sure we have the ctxt set so that we can use unstable methods |
e1599b0c | 63 | let span = cx.with_def_site_ctxt(span); |
476ff2be | 64 | let name = cx.expr_lit(span, ast::LitKind::Str(ident.name, ast::StrStyle::Cooked)); |
e1599b0c | 65 | let builder = cx.ident_of("debug_trait_builder", span); |
ba9703b0 | 66 | let builder_expr = cx.expr_ident(span, builder); |
1a4d82fc | 67 | |
92a42be0 | 68 | let fmt = substr.nonself_args[0].clone(); |
62682a34 | 69 | |
532ac7d7 XL |
70 | let mut stmts = vec![]; |
71 | match vdata { | |
72 | ast::VariantData::Tuple(..) | ast::VariantData::Unit(..) => { | |
73 | // tuple struct/"normal" variant | |
dfeec247 | 74 | let expr = cx.expr_method_call(span, fmt, cx.ident_of("debug_tuple", span), vec![name]); |
e1599b0c | 75 | stmts.push(cx.stmt_let(span, true, builder, expr)); |
532ac7d7 XL |
76 | |
77 | for field in fields { | |
78 | // Use double indirection to make sure this works for unsized types | |
79 | let field = cx.expr_addr_of(field.span, field.self_.clone()); | |
80 | let field = cx.expr_addr_of(field.span, field); | |
81 | ||
dfeec247 XL |
82 | let expr = cx.expr_method_call( |
83 | span, | |
84 | builder_expr.clone(), | |
85 | Ident::new(sym::field, span), | |
86 | vec![field], | |
87 | ); | |
532ac7d7 XL |
88 | |
89 | // Use `let _ = expr;` to avoid triggering the | |
90 | // unused_results lint. | |
91 | stmts.push(stmt_let_undescore(cx, span, expr)); | |
1a4d82fc JJ |
92 | } |
93 | } | |
532ac7d7 XL |
94 | ast::VariantData::Struct(..) => { |
95 | // normal struct/struct variant | |
96 | let expr = | |
e1599b0c | 97 | cx.expr_method_call(span, fmt, cx.ident_of("debug_struct", span), vec![name]); |
532ac7d7 XL |
98 | stmts.push(cx.stmt_let(DUMMY_SP, true, builder, expr)); |
99 | ||
100 | for field in fields { | |
dfeec247 XL |
101 | let name = cx.expr_lit( |
102 | field.span, | |
103 | ast::LitKind::Str(field.name.unwrap().name, ast::StrStyle::Cooked), | |
104 | ); | |
532ac7d7 XL |
105 | |
106 | // Use double indirection to make sure this works for unsized types | |
107 | let field = cx.expr_addr_of(field.span, field.self_.clone()); | |
108 | let field = cx.expr_addr_of(field.span, field); | |
dfeec247 XL |
109 | let expr = cx.expr_method_call( |
110 | span, | |
111 | builder_expr.clone(), | |
112 | Ident::new(sym::field, span), | |
113 | vec![name, field], | |
114 | ); | |
532ac7d7 XL |
115 | stmts.push(stmt_let_undescore(cx, span, expr)); |
116 | } | |
117 | } | |
118 | } | |
92a42be0 | 119 | |
e1599b0c | 120 | let expr = cx.expr_method_call(span, builder_expr, cx.ident_of("finish", span), vec![]); |
92a42be0 | 121 | |
3157f602 XL |
122 | stmts.push(cx.stmt_expr(expr)); |
123 | let block = cx.block(span, stmts); | |
92a42be0 SL |
124 | cx.expr_block(block) |
125 | } | |
1a4d82fc | 126 | |
9fa01778 | 127 | fn stmt_let_undescore(cx: &mut ExtCtxt<'_>, sp: Span, expr: P<ast::Expr>) -> ast::Stmt { |
92a42be0 SL |
128 | let local = P(ast::Local { |
129 | pat: cx.pat_wild(sp), | |
130 | ty: None, | |
131 | init: Some(expr), | |
132 | id: ast::DUMMY_NODE_ID, | |
133 | span: sp, | |
dfeec247 | 134 | attrs: ast::AttrVec::new(), |
92a42be0 | 135 | }); |
dfeec247 | 136 | ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span: sp } |
1a4d82fc | 137 | } |