]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_expand/src/placeholders.rs
Rollup merge of #92559 - durin42:llvm-14-attributemask, r=nikic
[rust.git] / compiler / rustc_expand / src / placeholders.rs
1 use crate::expand::{AstFragment, AstFragmentKind};
2
3 use rustc_ast as ast;
4 use rustc_ast::mut_visit::*;
5 use rustc_ast::ptr::P;
6 use rustc_span::source_map::DUMMY_SP;
7 use rustc_span::symbol::Ident;
8
9 use smallvec::{smallvec, SmallVec};
10
11 use rustc_data_structures::fx::FxHashMap;
12
13 pub fn placeholder(
14     kind: AstFragmentKind,
15     id: ast::NodeId,
16     vis: Option<ast::Visibility>,
17 ) -> AstFragment {
18     fn mac_placeholder() -> ast::MacCall {
19         ast::MacCall {
20             path: ast::Path { span: DUMMY_SP, segments: Vec::new(), tokens: None },
21             args: P(ast::MacArgs::Empty),
22             prior_type_ascription: None,
23         }
24     }
25
26     let ident = Ident::empty();
27     let attrs = Vec::new();
28     let vis = vis.unwrap_or(ast::Visibility {
29         span: DUMMY_SP,
30         kind: ast::VisibilityKind::Inherited,
31         tokens: None,
32     });
33     let span = DUMMY_SP;
34     let expr_placeholder = || {
35         P(ast::Expr {
36             id,
37             span,
38             attrs: ast::AttrVec::new(),
39             kind: ast::ExprKind::MacCall(mac_placeholder()),
40             tokens: None,
41         })
42     };
43     let ty =
44         || P(ast::Ty { id, kind: ast::TyKind::MacCall(mac_placeholder()), span, tokens: None });
45     let pat =
46         || P(ast::Pat { id, kind: ast::PatKind::MacCall(mac_placeholder()), span, tokens: None });
47
48     match kind {
49         AstFragmentKind::Crate => AstFragment::Crate(ast::Crate {
50             attrs: Default::default(),
51             items: Default::default(),
52             span,
53             id,
54             is_placeholder: true,
55         }),
56         AstFragmentKind::Expr => AstFragment::Expr(expr_placeholder()),
57         AstFragmentKind::OptExpr => AstFragment::OptExpr(Some(expr_placeholder())),
58         AstFragmentKind::Items => AstFragment::Items(smallvec![P(ast::Item {
59             id,
60             span,
61             ident,
62             vis,
63             attrs,
64             kind: ast::ItemKind::MacCall(mac_placeholder()),
65             tokens: None,
66         })]),
67         AstFragmentKind::TraitItems => AstFragment::TraitItems(smallvec![P(ast::AssocItem {
68             id,
69             span,
70             ident,
71             vis,
72             attrs,
73             kind: ast::AssocItemKind::MacCall(mac_placeholder()),
74             tokens: None,
75         })]),
76         AstFragmentKind::ImplItems => AstFragment::ImplItems(smallvec![P(ast::AssocItem {
77             id,
78             span,
79             ident,
80             vis,
81             attrs,
82             kind: ast::AssocItemKind::MacCall(mac_placeholder()),
83             tokens: None,
84         })]),
85         AstFragmentKind::ForeignItems => {
86             AstFragment::ForeignItems(smallvec![P(ast::ForeignItem {
87                 id,
88                 span,
89                 ident,
90                 vis,
91                 attrs,
92                 kind: ast::ForeignItemKind::MacCall(mac_placeholder()),
93                 tokens: None,
94             })])
95         }
96         AstFragmentKind::Pat => AstFragment::Pat(P(ast::Pat {
97             id,
98             span,
99             kind: ast::PatKind::MacCall(mac_placeholder()),
100             tokens: None,
101         })),
102         AstFragmentKind::Ty => AstFragment::Ty(P(ast::Ty {
103             id,
104             span,
105             kind: ast::TyKind::MacCall(mac_placeholder()),
106             tokens: None,
107         })),
108         AstFragmentKind::Stmts => AstFragment::Stmts(smallvec![{
109             let mac = P(ast::MacCallStmt {
110                 mac: mac_placeholder(),
111                 style: ast::MacStmtStyle::Braces,
112                 attrs: ast::AttrVec::new(),
113                 tokens: None,
114             });
115             ast::Stmt { id, span, kind: ast::StmtKind::MacCall(mac) }
116         }]),
117         AstFragmentKind::Arms => AstFragment::Arms(smallvec![ast::Arm {
118             attrs: Default::default(),
119             body: expr_placeholder(),
120             guard: None,
121             id,
122             pat: pat(),
123             span,
124             is_placeholder: true,
125         }]),
126         AstFragmentKind::Fields => AstFragment::Fields(smallvec![ast::ExprField {
127             attrs: Default::default(),
128             expr: expr_placeholder(),
129             id,
130             ident,
131             is_shorthand: false,
132             span,
133             is_placeholder: true,
134         }]),
135         AstFragmentKind::FieldPats => AstFragment::FieldPats(smallvec![ast::PatField {
136             attrs: Default::default(),
137             id,
138             ident,
139             is_shorthand: false,
140             pat: pat(),
141             span,
142             is_placeholder: true,
143         }]),
144         AstFragmentKind::GenericParams => AstFragment::GenericParams(smallvec![{
145             ast::GenericParam {
146                 attrs: Default::default(),
147                 bounds: Default::default(),
148                 id,
149                 ident,
150                 is_placeholder: true,
151                 kind: ast::GenericParamKind::Lifetime,
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::StructFields => AstFragment::StructFields(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 filter_map_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
299         match expr.kind {
300             ast::ExprKind::MacCall(_) => self.remove(expr.id).make_opt_expr(),
301             _ => noop_filter_map_expr(expr, self),
302         }
303     }
304
305     fn flat_map_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> {
306         let (style, mut stmts) = match stmt.kind {
307             ast::StmtKind::MacCall(mac) => (mac.style, self.remove(stmt.id).make_stmts()),
308             _ => return noop_flat_map_stmt(stmt, self),
309         };
310
311         if style == ast::MacStmtStyle::Semicolon {
312             // Implement the proposal described in
313             // https://github.com/rust-lang/rust/issues/61733#issuecomment-509626449
314             //
315             // The macro invocation expands to the list of statements. If the
316             // list of statements is empty, then 'parse' the trailing semicolon
317             // on the original invocation as an empty statement. That is:
318             //
319             // `empty();` is parsed as a single `StmtKind::Empty`
320             //
321             // If the list of statements is non-empty, see if the final
322             // statement already has a trailing semicolon.
323             //
324             // If it doesn't have a semicolon, then 'parse' the trailing
325             // semicolon from the invocation as part of the final statement,
326             // using `stmt.add_trailing_semicolon()`
327             //
328             // If it does have a semicolon, then 'parse' the trailing semicolon
329             // from the invocation as a new StmtKind::Empty
330
331             // FIXME: We will need to preserve the original semicolon token and
332             // span as part of #15701
333             let empty_stmt =
334                 ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Empty, span: DUMMY_SP };
335
336             if let Some(stmt) = stmts.pop() {
337                 if stmt.has_trailing_semicolon() {
338                     stmts.push(stmt);
339                     stmts.push(empty_stmt);
340                 } else {
341                     stmts.push(stmt.add_trailing_semicolon());
342                 }
343             } else {
344                 stmts.push(empty_stmt);
345             }
346         }
347
348         stmts
349     }
350
351     fn visit_pat(&mut self, pat: &mut P<ast::Pat>) {
352         match pat.kind {
353             ast::PatKind::MacCall(_) => *pat = self.remove(pat.id).make_pat(),
354             _ => noop_visit_pat(pat, self),
355         }
356     }
357
358     fn visit_ty(&mut self, ty: &mut P<ast::Ty>) {
359         match ty.kind {
360             ast::TyKind::MacCall(_) => *ty = self.remove(ty.id).make_ty(),
361             _ => noop_visit_ty(ty, self),
362         }
363     }
364
365     fn visit_crate(&mut self, krate: &mut ast::Crate) {
366         if krate.is_placeholder {
367             *krate = self.remove(krate.id).make_crate();
368         } else {
369             noop_visit_crate(krate, self)
370         }
371     }
372 }