]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_ast/src/ast_like.rs
Auto merge of #90000 - matthiaskrgr:rollup-vj7wwur, r=matthiaskrgr
[rust.git] / compiler / rustc_ast / src / ast_like.rs
1 use super::ptr::P;
2 use super::token::Nonterminal;
3 use super::tokenstream::LazyTokenStream;
4 use super::{Arm, ExprField, FieldDef, GenericParam, Param, PatField, Variant};
5 use super::{AssocItem, Expr, ForeignItem, Item, Local, MacCallStmt};
6 use super::{AttrItem, AttrKind, Block, Pat, Path, Ty, Visibility};
7 use super::{AttrVec, Attribute, Stmt, StmtKind};
8
9 use std::fmt::Debug;
10
11 /// An `AstLike` represents an AST node (or some wrapper around
12 /// and AST node) which stores some combination of attributes
13 /// and tokens.
14 pub trait AstLike: Sized + Debug {
15     /// This is `true` if this `AstLike` might support 'custom' (proc-macro) inner
16     /// attributes. Attributes like `#![cfg]` and `#![cfg_attr]` are not
17     /// considered 'custom' attributes
18     ///
19     /// If this is `false`, then this `AstLike` definitely does
20     /// not support 'custom' inner attributes, which enables some optimizations
21     /// during token collection.
22     const SUPPORTS_CUSTOM_INNER_ATTRS: bool;
23     fn attrs(&self) -> &[Attribute];
24     fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>));
25     fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>>;
26 }
27
28 impl<T: AstLike + 'static> AstLike for P<T> {
29     const SUPPORTS_CUSTOM_INNER_ATTRS: bool = T::SUPPORTS_CUSTOM_INNER_ATTRS;
30     fn attrs(&self) -> &[Attribute] {
31         (**self).attrs()
32     }
33     fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
34         (**self).visit_attrs(f);
35     }
36     fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
37         (**self).tokens_mut()
38     }
39 }
40
41 impl AstLike for crate::token::Nonterminal {
42     const SUPPORTS_CUSTOM_INNER_ATTRS: bool = true;
43     fn attrs(&self) -> &[Attribute] {
44         match self {
45             Nonterminal::NtItem(item) => item.attrs(),
46             Nonterminal::NtStmt(stmt) => stmt.attrs(),
47             Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.attrs(),
48             Nonterminal::NtPat(_)
49             | Nonterminal::NtTy(_)
50             | Nonterminal::NtMeta(_)
51             | Nonterminal::NtPath(_)
52             | Nonterminal::NtVis(_)
53             | Nonterminal::NtTT(_)
54             | Nonterminal::NtBlock(_)
55             | Nonterminal::NtIdent(..)
56             | Nonterminal::NtLifetime(_) => &[],
57         }
58     }
59     fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
60         match self {
61             Nonterminal::NtItem(item) => item.visit_attrs(f),
62             Nonterminal::NtStmt(stmt) => stmt.visit_attrs(f),
63             Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.visit_attrs(f),
64             Nonterminal::NtPat(_)
65             | Nonterminal::NtTy(_)
66             | Nonterminal::NtMeta(_)
67             | Nonterminal::NtPath(_)
68             | Nonterminal::NtVis(_)
69             | Nonterminal::NtTT(_)
70             | Nonterminal::NtBlock(_)
71             | Nonterminal::NtIdent(..)
72             | Nonterminal::NtLifetime(_) => {}
73         }
74     }
75     fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
76         match self {
77             Nonterminal::NtItem(item) => item.tokens_mut(),
78             Nonterminal::NtStmt(stmt) => stmt.tokens_mut(),
79             Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens_mut(),
80             Nonterminal::NtPat(pat) => pat.tokens_mut(),
81             Nonterminal::NtTy(ty) => ty.tokens_mut(),
82             Nonterminal::NtMeta(attr_item) => attr_item.tokens_mut(),
83             Nonterminal::NtPath(path) => path.tokens_mut(),
84             Nonterminal::NtVis(vis) => vis.tokens_mut(),
85             Nonterminal::NtBlock(block) => block.tokens_mut(),
86             Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) | Nonterminal::NtTT(..) => None,
87         }
88     }
89 }
90
91 fn visit_attrvec(attrs: &mut AttrVec, f: impl FnOnce(&mut Vec<Attribute>)) {
92     crate::mut_visit::visit_clobber(attrs, |attrs| {
93         let mut vec = attrs.into();
94         f(&mut vec);
95         vec.into()
96     });
97 }
98
99 impl AstLike for StmtKind {
100     // This might be an `StmtKind::Item`, which contains
101     // an item that supports inner attrs
102     const SUPPORTS_CUSTOM_INNER_ATTRS: bool = true;
103
104     fn attrs(&self) -> &[Attribute] {
105         match self {
106             StmtKind::Local(local) => local.attrs(),
107             StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.attrs(),
108             StmtKind::Item(item) => item.attrs(),
109             StmtKind::Empty => &[],
110             StmtKind::MacCall(mac) => &mac.attrs,
111         }
112     }
113
114     fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
115         match self {
116             StmtKind::Local(local) => local.visit_attrs(f),
117             StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.visit_attrs(f),
118             StmtKind::Item(item) => item.visit_attrs(f),
119             StmtKind::Empty => {}
120             StmtKind::MacCall(mac) => visit_attrvec(&mut mac.attrs, f),
121         }
122     }
123     fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
124         Some(match self {
125             StmtKind::Local(local) => &mut local.tokens,
126             StmtKind::Item(item) => &mut item.tokens,
127             StmtKind::Expr(expr) | StmtKind::Semi(expr) => &mut expr.tokens,
128             StmtKind::Empty => return None,
129             StmtKind::MacCall(mac) => &mut mac.tokens,
130         })
131     }
132 }
133
134 impl AstLike for Stmt {
135     const SUPPORTS_CUSTOM_INNER_ATTRS: bool = StmtKind::SUPPORTS_CUSTOM_INNER_ATTRS;
136
137     fn attrs(&self) -> &[Attribute] {
138         self.kind.attrs()
139     }
140
141     fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
142         self.kind.visit_attrs(f);
143     }
144     fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
145         self.kind.tokens_mut()
146     }
147 }
148
149 impl AstLike for Attribute {
150     const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false;
151
152     fn attrs(&self) -> &[Attribute] {
153         &[]
154     }
155     fn visit_attrs(&mut self, _f: impl FnOnce(&mut Vec<Attribute>)) {}
156     fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
157         Some(match &mut self.kind {
158             AttrKind::Normal(_, tokens) => tokens,
159             kind @ AttrKind::DocComment(..) => {
160                 panic!("Called tokens_mut on doc comment attr {:?}", kind)
161             }
162         })
163     }
164 }
165
166 impl<T: AstLike> AstLike for Option<T> {
167     const SUPPORTS_CUSTOM_INNER_ATTRS: bool = T::SUPPORTS_CUSTOM_INNER_ATTRS;
168
169     fn attrs(&self) -> &[Attribute] {
170         self.as_ref().map(|inner| inner.attrs()).unwrap_or(&[])
171     }
172     fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
173         if let Some(inner) = self.as_mut() {
174             inner.visit_attrs(f);
175         }
176     }
177     fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
178         self.as_mut().and_then(|inner| inner.tokens_mut())
179     }
180 }
181
182 /// Helper trait for the macros below. Abstracts over
183 /// the two types of attribute fields that AST nodes
184 /// may have (`Vec<Attribute>` or `AttrVec`)
185 trait VecOrAttrVec {
186     fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>));
187 }
188
189 impl VecOrAttrVec for Vec<Attribute> {
190     fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
191         f(self)
192     }
193 }
194
195 impl VecOrAttrVec for AttrVec {
196     fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
197         visit_attrvec(self, f)
198     }
199 }
200
201 macro_rules! derive_has_tokens_and_attrs {
202     (
203         const SUPPORTS_CUSTOM_INNER_ATTRS: bool = $inner_attrs:literal;
204         $($ty:path),*
205     ) => { $(
206         impl AstLike for $ty {
207             const SUPPORTS_CUSTOM_INNER_ATTRS: bool = $inner_attrs;
208
209             fn attrs(&self) -> &[Attribute] {
210                 &self.attrs
211             }
212
213             fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
214                 VecOrAttrVec::visit(&mut self.attrs, f)
215             }
216
217             fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
218                 Some(&mut self.tokens)
219             }
220
221         }
222     )* }
223 }
224
225 macro_rules! derive_has_attrs_no_tokens {
226     ($($ty:path),*) => { $(
227         impl AstLike for $ty {
228             const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false;
229
230             fn attrs(&self) -> &[Attribute] {
231                 &self.attrs
232             }
233
234             fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
235                 VecOrAttrVec::visit(&mut self.attrs, f)
236             }
237
238             fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
239                 None
240             }
241         }
242     )* }
243 }
244
245 macro_rules! derive_has_tokens_no_attrs {
246     ($($ty:path),*) => { $(
247         impl AstLike for $ty {
248             const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false;
249
250             fn attrs(&self) -> &[Attribute] {
251                 &[]
252             }
253
254             fn visit_attrs(&mut self, _f: impl FnOnce(&mut Vec<Attribute>)) {}
255             fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
256                 Some(&mut self.tokens)
257             }
258         }
259     )* }
260 }
261
262 // These ast nodes support both active and inert attributes,
263 // so they have tokens collected to pass to proc macros
264 derive_has_tokens_and_attrs! {
265     // Both `Item` and `AssocItem` can have bodies, which
266     // can contain inner attributes
267     const SUPPORTS_CUSTOM_INNER_ATTRS: bool = true;
268     Item, AssocItem, ForeignItem
269 }
270
271 derive_has_tokens_and_attrs! {
272     const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false;
273     Local, MacCallStmt, Expr
274 }
275
276 // These ast nodes only support inert attributes, so they don't
277 // store tokens (since nothing can observe them)
278 derive_has_attrs_no_tokens! {
279     FieldDef, Arm, ExprField, PatField, Variant, Param, GenericParam
280 }
281
282 // These AST nodes don't support attributes, but can
283 // be captured by a `macro_rules!` matcher. Therefore,
284 // they need to store tokens.
285 derive_has_tokens_no_attrs! {
286     Ty, Block, AttrItem, Pat, Path, Visibility
287 }