]>
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 | 5 | use rustc_ast::ptr::P; |
3dfed10e | 6 | use rustc_ast::{self as ast, Expr, MetaItem}; |
dfeec247 | 7 | use rustc_expand::base::{Annotatable, ExtCtxt}; |
f9f354fc | 8 | use rustc_span::symbol::{sym, Ident}; |
dfeec247 | 9 | use rustc_span::{Span, DUMMY_SP}; |
1a4d82fc | 10 | |
dfeec247 XL |
11 | pub fn expand_deriving_debug( |
12 | cx: &mut ExtCtxt<'_>, | |
13 | span: Span, | |
14 | mitem: &MetaItem, | |
15 | item: &Annotatable, | |
16 | push: &mut dyn FnMut(Annotatable), | |
17 | ) { | |
1a4d82fc | 18 | // &mut ::std::fmt::Formatter |
dfeec247 | 19 | let fmtr = |
3dfed10e | 20 | Ptr(Box::new(Literal(path_std!(fmt::Formatter))), Borrowed(None, ast::Mutability::Mut)); |
1a4d82fc JJ |
21 | |
22 | let trait_def = TraitDef { | |
3b2f2976 | 23 | span, |
1a4d82fc | 24 | attributes: Vec::new(), |
3dfed10e | 25 | path: path_std!(fmt::Debug), |
1a4d82fc | 26 | additional_bounds: Vec::new(), |
3dfed10e | 27 | generics: Bounds::empty(), |
e9174d1e | 28 | is_unsafe: false, |
9e0c209e | 29 | supports_unions: false, |
5bcae85e | 30 | methods: vec![MethodDef { |
3dfed10e XL |
31 | name: sym::fmt, |
32 | generics: Bounds::empty(), | |
dfeec247 | 33 | explicit_self: borrowed_explicit_self(), |
3dfed10e XL |
34 | args: vec![(fmtr, sym::f)], |
35 | ret_ty: Literal(path_std!(fmt::Result)), | |
dfeec247 XL |
36 | attributes: Vec::new(), |
37 | is_unsafe: false, | |
38 | unify_fieldless_variants: false, | |
39 | combine_substructure: combine_substructure(Box::new(|a, b, c| { | |
40 | show_substructure(a, b, c) | |
41 | })), | |
42 | }], | |
85aaf69f | 43 | associated_types: Vec::new(), |
1a4d82fc | 44 | }; |
62682a34 | 45 | trait_def.expand(cx, mitem, item, push) |
1a4d82fc JJ |
46 | } |
47 | ||
c34b1796 | 48 | /// We use the debug builders to do the heavy lifting here |
9fa01778 | 49 | fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<Expr> { |
c34b1796 AL |
50 | // build fmt.debug_struct(<name>).field(<fieldname>, &<fieldval>)....build() |
51 | // or fmt.debug_tuple(<name>).field(&<fieldval>)....build() | |
52 | // based on the "shape". | |
532ac7d7 XL |
53 | let (ident, vdata, fields) = match substr.fields { |
54 | Struct(vdata, fields) => (substr.type_ident, *vdata, fields), | |
e1599b0c | 55 | EnumMatching(_, _, v, fields) => (v.ident, &v.data, fields), |
dfeec247 XL |
56 | EnumNonMatchingCollapsed(..) | StaticStruct(..) | StaticEnum(..) => { |
57 | cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`") | |
58 | } | |
1a4d82fc JJ |
59 | }; |
60 | ||
cc61c64b | 61 | // We want to make sure we have the ctxt set so that we can use unstable methods |
e1599b0c | 62 | let span = cx.with_def_site_ctxt(span); |
476ff2be | 63 | let name = cx.expr_lit(span, ast::LitKind::Str(ident.name, ast::StrStyle::Cooked)); |
3dfed10e | 64 | let builder = Ident::new(sym::debug_trait_builder, span); |
ba9703b0 | 65 | let builder_expr = cx.expr_ident(span, builder); |
1a4d82fc | 66 | |
92a42be0 | 67 | let fmt = substr.nonself_args[0].clone(); |
62682a34 | 68 | |
532ac7d7 XL |
69 | let mut stmts = vec![]; |
70 | match vdata { | |
71 | ast::VariantData::Tuple(..) | ast::VariantData::Unit(..) => { | |
72 | // tuple struct/"normal" variant | |
3dfed10e XL |
73 | let expr = |
74 | cx.expr_method_call(span, fmt, Ident::new(sym::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. | |
f9f354fc | 91 | stmts.push(stmt_let_underscore(cx, span, expr)); |
1a4d82fc JJ |
92 | } |
93 | } | |
532ac7d7 XL |
94 | ast::VariantData::Struct(..) => { |
95 | // normal struct/struct variant | |
96 | let expr = | |
3dfed10e | 97 | cx.expr_method_call(span, fmt, Ident::new(sym::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 | ); | |
f9f354fc | 115 | stmts.push(stmt_let_underscore(cx, span, expr)); |
532ac7d7 XL |
116 | } |
117 | } | |
118 | } | |
92a42be0 | 119 | |
3dfed10e | 120 | let expr = cx.expr_method_call(span, builder_expr, Ident::new(sym::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 | |
f9f354fc | 127 | fn stmt_let_underscore(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 | } |