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