]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_expand/src/placeholders.rs
Use `ThinVec` in `ast::Path`.
[rust.git] / compiler / rustc_expand / src / placeholders.rs
1 use crate::expand::{AstFragment, AstFragmentKind};
2 use rustc_ast as ast;
3 use rustc_ast::mut_visit::*;
4 use rustc_ast::ptr::P;
5 use rustc_data_structures::fx::FxHashMap;
6 use rustc_span::source_map::DUMMY_SP;
7 use rustc_span::symbol::Ident;
8 use smallvec::{smallvec, SmallVec};
9 use thin_vec::ThinVec;
10
11 pub fn placeholder(
12     kind: AstFragmentKind,
13     id: ast::NodeId,
14     vis: Option<ast::Visibility>,
15 ) -> AstFragment {
16     fn mac_placeholder() -> P<ast::MacCall> {
17         P(ast::MacCall {
18             path: ast::Path { span: DUMMY_SP, segments: ThinVec::new(), tokens: None },
19             args: P(ast::MacArgs::Empty),
20             prior_type_ascription: None,
21         })
22     }
23
24     let ident = Ident::empty();
25     let attrs = ast::AttrVec::new();
26     let vis = vis.unwrap_or(ast::Visibility {
27         span: DUMMY_SP,
28         kind: ast::VisibilityKind::Inherited,
29         tokens: None,
30     });
31     let span = DUMMY_SP;
32     let expr_placeholder = || {
33         P(ast::Expr {
34             id,
35             span,
36             attrs: ast::AttrVec::new(),
37             kind: ast::ExprKind::MacCall(mac_placeholder()),
38             tokens: None,
39         })
40     };
41     let ty =
42         || P(ast::Ty { id, kind: ast::TyKind::MacCall(mac_placeholder()), span, tokens: None });
43     let pat =
44         || P(ast::Pat { id, kind: ast::PatKind::MacCall(mac_placeholder()), span, tokens: None });
45
46     match kind {
47         AstFragmentKind::Crate => AstFragment::Crate(ast::Crate {
48             attrs: Default::default(),
49             items: Default::default(),
50             spans: ast::ModSpans { inner_span: span, ..Default::default() },
51             id,
52             is_placeholder: true,
53         }),
54         AstFragmentKind::Expr => AstFragment::Expr(expr_placeholder()),
55         AstFragmentKind::OptExpr => AstFragment::OptExpr(Some(expr_placeholder())),
56         AstFragmentKind::MethodReceiverExpr => AstFragment::MethodReceiverExpr(expr_placeholder()),
57         AstFragmentKind::Items => AstFragment::Items(smallvec![P(ast::Item {
58             id,
59             span,
60             ident,
61             vis,
62             attrs,
63             kind: ast::ItemKind::MacCall(mac_placeholder()),
64             tokens: None,
65         })]),
66         AstFragmentKind::TraitItems => AstFragment::TraitItems(smallvec![P(ast::AssocItem {
67             id,
68             span,
69             ident,
70             vis,
71             attrs,
72             kind: ast::AssocItemKind::MacCall(mac_placeholder()),
73             tokens: None,
74         })]),
75         AstFragmentKind::ImplItems => AstFragment::ImplItems(smallvec![P(ast::AssocItem {
76             id,
77             span,
78             ident,
79             vis,
80             attrs,
81             kind: ast::AssocItemKind::MacCall(mac_placeholder()),
82             tokens: None,
83         })]),
84         AstFragmentKind::ForeignItems => {
85             AstFragment::ForeignItems(smallvec![P(ast::ForeignItem {
86                 id,
87                 span,
88                 ident,
89                 vis,
90                 attrs,
91                 kind: ast::ForeignItemKind::MacCall(mac_placeholder()),
92                 tokens: None,
93             })])
94         }
95         AstFragmentKind::Pat => AstFragment::Pat(P(ast::Pat {
96             id,
97             span,
98             kind: ast::PatKind::MacCall(mac_placeholder()),
99             tokens: None,
100         })),
101         AstFragmentKind::Ty => AstFragment::Ty(P(ast::Ty {
102             id,
103             span,
104             kind: ast::TyKind::MacCall(mac_placeholder()),
105             tokens: None,
106         })),
107         AstFragmentKind::Stmts => AstFragment::Stmts(smallvec![{
108             let mac = P(ast::MacCallStmt {
109                 mac: mac_placeholder(),
110                 style: ast::MacStmtStyle::Braces,
111                 attrs: ast::AttrVec::new(),
112                 tokens: None,
113             });
114             ast::Stmt { id, span, kind: ast::StmtKind::MacCall(mac) }
115         }]),
116         AstFragmentKind::Arms => AstFragment::Arms(smallvec![ast::Arm {
117             attrs: Default::default(),
118             body: expr_placeholder(),
119             guard: None,
120             id,
121             pat: pat(),
122             span,
123             is_placeholder: true,
124         }]),
125         AstFragmentKind::ExprFields => AstFragment::ExprFields(smallvec![ast::ExprField {
126             attrs: Default::default(),
127             expr: expr_placeholder(),
128             id,
129             ident,
130             is_shorthand: false,
131             span,
132             is_placeholder: true,
133         }]),
134         AstFragmentKind::PatFields => AstFragment::PatFields(smallvec![ast::PatField {
135             attrs: Default::default(),
136             id,
137             ident,
138             is_shorthand: false,
139             pat: pat(),
140             span,
141             is_placeholder: true,
142         }]),
143         AstFragmentKind::GenericParams => AstFragment::GenericParams(smallvec![{
144             ast::GenericParam {
145                 attrs: Default::default(),
146                 bounds: Default::default(),
147                 id,
148                 ident,
149                 is_placeholder: true,
150                 kind: ast::GenericParamKind::Lifetime,
151                 colon_span: None,
152             }
153         }]),
154         AstFragmentKind::Params => AstFragment::Params(smallvec![ast::Param {
155             attrs: Default::default(),
156             id,
157             pat: pat(),
158             span,
159             ty: ty(),
160             is_placeholder: true,
161         }]),
162         AstFragmentKind::FieldDefs => AstFragment::FieldDefs(smallvec![ast::FieldDef {
163             attrs: Default::default(),
164             id,
165             ident: None,
166             span,
167             ty: ty(),
168             vis,
169             is_placeholder: true,
170         }]),
171         AstFragmentKind::Variants => AstFragment::Variants(smallvec![ast::Variant {
172             attrs: Default::default(),
173             data: ast::VariantData::Struct(Default::default(), false),
174             disr_expr: None,
175             id,
176             ident,
177             span,
178             vis,
179             is_placeholder: true,
180         }]),
181     }
182 }
183
184 #[derive(Default)]
185 pub struct PlaceholderExpander {
186     expanded_fragments: FxHashMap<ast::NodeId, AstFragment>,
187 }
188
189 impl PlaceholderExpander {
190     pub fn add(&mut self, id: ast::NodeId, mut fragment: AstFragment) {
191         fragment.mut_visit_with(self);
192         self.expanded_fragments.insert(id, fragment);
193     }
194
195     fn remove(&mut self, id: ast::NodeId) -> AstFragment {
196         self.expanded_fragments.remove(&id).unwrap()
197     }
198 }
199
200 impl MutVisitor for PlaceholderExpander {
201     fn flat_map_arm(&mut self, arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> {
202         if arm.is_placeholder {
203             self.remove(arm.id).make_arms()
204         } else {
205             noop_flat_map_arm(arm, self)
206         }
207     }
208
209     fn flat_map_expr_field(&mut self, field: ast::ExprField) -> SmallVec<[ast::ExprField; 1]> {
210         if field.is_placeholder {
211             self.remove(field.id).make_expr_fields()
212         } else {
213             noop_flat_map_expr_field(field, self)
214         }
215     }
216
217     fn flat_map_pat_field(&mut self, fp: ast::PatField) -> SmallVec<[ast::PatField; 1]> {
218         if fp.is_placeholder {
219             self.remove(fp.id).make_pat_fields()
220         } else {
221             noop_flat_map_pat_field(fp, self)
222         }
223     }
224
225     fn flat_map_generic_param(
226         &mut self,
227         param: ast::GenericParam,
228     ) -> SmallVec<[ast::GenericParam; 1]> {
229         if param.is_placeholder {
230             self.remove(param.id).make_generic_params()
231         } else {
232             noop_flat_map_generic_param(param, self)
233         }
234     }
235
236     fn flat_map_param(&mut self, p: ast::Param) -> SmallVec<[ast::Param; 1]> {
237         if p.is_placeholder {
238             self.remove(p.id).make_params()
239         } else {
240             noop_flat_map_param(p, self)
241         }
242     }
243
244     fn flat_map_field_def(&mut self, sf: ast::FieldDef) -> SmallVec<[ast::FieldDef; 1]> {
245         if sf.is_placeholder {
246             self.remove(sf.id).make_field_defs()
247         } else {
248             noop_flat_map_field_def(sf, self)
249         }
250     }
251
252     fn flat_map_variant(&mut self, variant: ast::Variant) -> SmallVec<[ast::Variant; 1]> {
253         if variant.is_placeholder {
254             self.remove(variant.id).make_variants()
255         } else {
256             noop_flat_map_variant(variant, self)
257         }
258     }
259
260     fn flat_map_item(&mut self, item: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
261         match item.kind {
262             ast::ItemKind::MacCall(_) => self.remove(item.id).make_items(),
263             _ => noop_flat_map_item(item, self),
264         }
265     }
266
267     fn flat_map_trait_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
268         match item.kind {
269             ast::AssocItemKind::MacCall(_) => self.remove(item.id).make_trait_items(),
270             _ => noop_flat_map_assoc_item(item, self),
271         }
272     }
273
274     fn flat_map_impl_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
275         match item.kind {
276             ast::AssocItemKind::MacCall(_) => self.remove(item.id).make_impl_items(),
277             _ => noop_flat_map_assoc_item(item, self),
278         }
279     }
280
281     fn flat_map_foreign_item(
282         &mut self,
283         item: P<ast::ForeignItem>,
284     ) -> SmallVec<[P<ast::ForeignItem>; 1]> {
285         match item.kind {
286             ast::ForeignItemKind::MacCall(_) => self.remove(item.id).make_foreign_items(),
287             _ => noop_flat_map_foreign_item(item, self),
288         }
289     }
290
291     fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
292         match expr.kind {
293             ast::ExprKind::MacCall(_) => *expr = self.remove(expr.id).make_expr(),
294             _ => noop_visit_expr(expr, self),
295         }
296     }
297
298     fn visit_method_receiver_expr(&mut self, expr: &mut P<ast::Expr>) {
299         match expr.kind {
300             ast::ExprKind::MacCall(_) => *expr = self.remove(expr.id).make_method_receiver_expr(),
301             _ => noop_visit_expr(expr, self),
302         }
303     }
304
305     fn filter_map_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
306         match expr.kind {
307             ast::ExprKind::MacCall(_) => self.remove(expr.id).make_opt_expr(),
308             _ => noop_filter_map_expr(expr, self),
309         }
310     }
311
312     fn flat_map_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> {
313         let (style, mut stmts) = match stmt.kind {
314             ast::StmtKind::MacCall(mac) => (mac.style, self.remove(stmt.id).make_stmts()),
315             _ => return noop_flat_map_stmt(stmt, self),
316         };
317
318         if style == ast::MacStmtStyle::Semicolon {
319             // Implement the proposal described in
320             // https://github.com/rust-lang/rust/issues/61733#issuecomment-509626449
321             //
322             // The macro invocation expands to the list of statements. If the
323             // list of statements is empty, then 'parse' the trailing semicolon
324             // on the original invocation as an empty statement. That is:
325             //
326             // `empty();` is parsed as a single `StmtKind::Empty`
327             //
328             // If the list of statements is non-empty, see if the final
329             // statement already has a trailing semicolon.
330             //
331             // If it doesn't have a semicolon, then 'parse' the trailing
332             // semicolon from the invocation as part of the final statement,
333             // using `stmt.add_trailing_semicolon()`
334             //
335             // If it does have a semicolon, then 'parse' the trailing semicolon
336             // from the invocation as a new StmtKind::Empty
337
338             // FIXME: We will need to preserve the original semicolon token and
339             // span as part of #15701
340             let empty_stmt =
341                 ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Empty, span: DUMMY_SP };
342
343             if let Some(stmt) = stmts.pop() {
344                 if stmt.has_trailing_semicolon() {
345                     stmts.push(stmt);
346                     stmts.push(empty_stmt);
347                 } else {
348                     stmts.push(stmt.add_trailing_semicolon());
349                 }
350             } else {
351                 stmts.push(empty_stmt);
352             }
353         }
354
355         stmts
356     }
357
358     fn visit_pat(&mut self, pat: &mut P<ast::Pat>) {
359         match pat.kind {
360             ast::PatKind::MacCall(_) => *pat = self.remove(pat.id).make_pat(),
361             _ => noop_visit_pat(pat, self),
362         }
363     }
364
365     fn visit_ty(&mut self, ty: &mut P<ast::Ty>) {
366         match ty.kind {
367             ast::TyKind::MacCall(_) => *ty = self.remove(ty.id).make_ty(),
368             _ => noop_visit_ty(ty, self),
369         }
370     }
371
372     fn visit_crate(&mut self, krate: &mut ast::Crate) {
373         if krate.is_placeholder {
374             *krate = self.remove(krate.id).make_crate();
375         } else {
376             noop_visit_crate(krate, self)
377         }
378     }
379 }