]>
Commit | Line | Data |
---|---|---|
04454e1e FG |
1 | //! A set of traits implemented for various AST nodes, |
2 | //! typically those used in AST fragments during macro expansion. | |
3 | //! The traits are not implemented exhaustively, only when actually necessary. | |
4 | ||
5 | use crate::ptr::P; | |
6 | use crate::token::Nonterminal; | |
7 | use crate::tokenstream::LazyTokenStream; | |
8 | use crate::{Arm, Crate, ExprField, FieldDef, GenericParam, Param, PatField, Variant}; | |
9 | use crate::{AssocItem, Expr, ForeignItem, Item, NodeId}; | |
10 | use crate::{AttrItem, AttrKind, Block, Pat, Path, Ty, Visibility}; | |
11 | use crate::{AttrVec, Attribute, Stmt, StmtKind}; | |
12 | ||
13 | use rustc_span::Span; | |
14 | ||
15 | use std::fmt; | |
16 | use std::marker::PhantomData; | |
17 | ||
18 | /// A utility trait to reduce boilerplate. | |
19 | /// Standard `Deref(Mut)` cannot be reused due to coherence. | |
20 | pub trait AstDeref { | |
21 | type Target; | |
22 | fn ast_deref(&self) -> &Self::Target; | |
23 | fn ast_deref_mut(&mut self) -> &mut Self::Target; | |
24 | } | |
25 | ||
26 | macro_rules! impl_not_ast_deref { | |
27 | ($($T:ty),+ $(,)?) => { | |
28 | $( | |
29 | impl !AstDeref for $T {} | |
30 | )+ | |
31 | }; | |
32 | } | |
33 | ||
34 | impl_not_ast_deref!(AssocItem, Expr, ForeignItem, Item, Stmt); | |
35 | ||
36 | impl<T> AstDeref for P<T> { | |
37 | type Target = T; | |
38 | fn ast_deref(&self) -> &Self::Target { | |
39 | self | |
40 | } | |
41 | fn ast_deref_mut(&mut self) -> &mut Self::Target { | |
42 | self | |
43 | } | |
44 | } | |
45 | ||
46 | /// A trait for AST nodes having an ID. | |
47 | pub trait HasNodeId { | |
48 | fn node_id(&self) -> NodeId; | |
49 | fn node_id_mut(&mut self) -> &mut NodeId; | |
50 | } | |
51 | ||
52 | macro_rules! impl_has_node_id { | |
53 | ($($T:ty),+ $(,)?) => { | |
54 | $( | |
55 | impl HasNodeId for $T { | |
56 | fn node_id(&self) -> NodeId { | |
57 | self.id | |
58 | } | |
59 | fn node_id_mut(&mut self) -> &mut NodeId { | |
60 | &mut self.id | |
61 | } | |
62 | } | |
63 | )+ | |
64 | }; | |
65 | } | |
66 | ||
67 | impl_has_node_id!( | |
68 | Arm, | |
69 | AssocItem, | |
70 | Crate, | |
71 | Expr, | |
72 | ExprField, | |
73 | FieldDef, | |
74 | ForeignItem, | |
75 | GenericParam, | |
76 | Item, | |
77 | Param, | |
78 | Pat, | |
79 | PatField, | |
80 | Stmt, | |
81 | Ty, | |
82 | Variant, | |
83 | ); | |
84 | ||
85 | impl<T: AstDeref<Target: HasNodeId>> HasNodeId for T { | |
86 | fn node_id(&self) -> NodeId { | |
87 | self.ast_deref().node_id() | |
88 | } | |
89 | fn node_id_mut(&mut self) -> &mut NodeId { | |
90 | self.ast_deref_mut().node_id_mut() | |
91 | } | |
92 | } | |
93 | ||
94 | /// A trait for AST nodes having a span. | |
95 | pub trait HasSpan { | |
96 | fn span(&self) -> Span; | |
97 | } | |
98 | ||
99 | macro_rules! impl_has_span { | |
100 | ($($T:ty),+ $(,)?) => { | |
101 | $( | |
102 | impl HasSpan for $T { | |
103 | fn span(&self) -> Span { | |
104 | self.span | |
105 | } | |
106 | } | |
107 | )+ | |
108 | }; | |
109 | } | |
110 | ||
111 | impl_has_span!(AssocItem, Expr, ForeignItem, Item, Stmt); | |
112 | ||
113 | impl<T: AstDeref<Target: HasSpan>> HasSpan for T { | |
114 | fn span(&self) -> Span { | |
115 | self.ast_deref().span() | |
116 | } | |
117 | } | |
118 | ||
119 | /// A trait for AST nodes having (or not having) collected tokens. | |
120 | pub trait HasTokens { | |
121 | fn tokens(&self) -> Option<&LazyTokenStream>; | |
122 | fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>>; | |
123 | } | |
124 | ||
125 | macro_rules! impl_has_tokens { | |
126 | ($($T:ty),+ $(,)?) => { | |
127 | $( | |
128 | impl HasTokens for $T { | |
129 | fn tokens(&self) -> Option<&LazyTokenStream> { | |
130 | self.tokens.as_ref() | |
131 | } | |
132 | fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> { | |
133 | Some(&mut self.tokens) | |
134 | } | |
135 | } | |
136 | )+ | |
137 | }; | |
138 | } | |
139 | ||
140 | macro_rules! impl_has_tokens_none { | |
141 | ($($T:ty),+ $(,)?) => { | |
142 | $( | |
143 | impl HasTokens for $T { | |
144 | fn tokens(&self) -> Option<&LazyTokenStream> { | |
145 | None | |
146 | } | |
147 | fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> { | |
148 | None | |
149 | } | |
150 | } | |
151 | )+ | |
152 | }; | |
153 | } | |
154 | ||
155 | impl_has_tokens!(AssocItem, AttrItem, Block, Expr, ForeignItem, Item, Pat, Path, Ty, Visibility); | |
156 | impl_has_tokens_none!(Arm, ExprField, FieldDef, GenericParam, Param, PatField, Variant); | |
157 | ||
158 | impl<T: AstDeref<Target: HasTokens>> HasTokens for T { | |
159 | fn tokens(&self) -> Option<&LazyTokenStream> { | |
160 | self.ast_deref().tokens() | |
161 | } | |
162 | fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> { | |
163 | self.ast_deref_mut().tokens_mut() | |
164 | } | |
165 | } | |
166 | ||
167 | impl<T: HasTokens> HasTokens for Option<T> { | |
168 | fn tokens(&self) -> Option<&LazyTokenStream> { | |
169 | self.as_ref().and_then(|inner| inner.tokens()) | |
170 | } | |
171 | fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> { | |
172 | self.as_mut().and_then(|inner| inner.tokens_mut()) | |
173 | } | |
174 | } | |
175 | ||
176 | impl HasTokens for StmtKind { | |
177 | fn tokens(&self) -> Option<&LazyTokenStream> { | |
178 | match self { | |
179 | StmtKind::Local(local) => local.tokens.as_ref(), | |
180 | StmtKind::Item(item) => item.tokens(), | |
181 | StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.tokens(), | |
182 | StmtKind::Empty => return None, | |
183 | StmtKind::MacCall(mac) => mac.tokens.as_ref(), | |
184 | } | |
185 | } | |
186 | fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> { | |
187 | match self { | |
188 | StmtKind::Local(local) => Some(&mut local.tokens), | |
189 | StmtKind::Item(item) => item.tokens_mut(), | |
190 | StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.tokens_mut(), | |
191 | StmtKind::Empty => return None, | |
192 | StmtKind::MacCall(mac) => Some(&mut mac.tokens), | |
193 | } | |
194 | } | |
195 | } | |
196 | ||
197 | impl HasTokens for Stmt { | |
198 | fn tokens(&self) -> Option<&LazyTokenStream> { | |
199 | self.kind.tokens() | |
200 | } | |
201 | fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> { | |
202 | self.kind.tokens_mut() | |
203 | } | |
204 | } | |
205 | ||
206 | impl HasTokens for Attribute { | |
207 | fn tokens(&self) -> Option<&LazyTokenStream> { | |
208 | match &self.kind { | |
209 | AttrKind::Normal(_, tokens) => tokens.as_ref(), | |
210 | kind @ AttrKind::DocComment(..) => { | |
211 | panic!("Called tokens on doc comment attr {:?}", kind) | |
212 | } | |
213 | } | |
214 | } | |
215 | fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> { | |
216 | Some(match &mut self.kind { | |
217 | AttrKind::Normal(_, tokens) => tokens, | |
218 | kind @ AttrKind::DocComment(..) => { | |
219 | panic!("Called tokens_mut on doc comment attr {:?}", kind) | |
220 | } | |
221 | }) | |
222 | } | |
223 | } | |
224 | ||
225 | impl HasTokens for Nonterminal { | |
226 | fn tokens(&self) -> Option<&LazyTokenStream> { | |
227 | match self { | |
228 | Nonterminal::NtItem(item) => item.tokens(), | |
229 | Nonterminal::NtStmt(stmt) => stmt.tokens(), | |
230 | Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens(), | |
231 | Nonterminal::NtPat(pat) => pat.tokens(), | |
232 | Nonterminal::NtTy(ty) => ty.tokens(), | |
233 | Nonterminal::NtMeta(attr_item) => attr_item.tokens(), | |
234 | Nonterminal::NtPath(path) => path.tokens(), | |
235 | Nonterminal::NtVis(vis) => vis.tokens(), | |
236 | Nonterminal::NtBlock(block) => block.tokens(), | |
237 | Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) => None, | |
238 | } | |
239 | } | |
240 | fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> { | |
241 | match self { | |
242 | Nonterminal::NtItem(item) => item.tokens_mut(), | |
243 | Nonterminal::NtStmt(stmt) => stmt.tokens_mut(), | |
244 | Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens_mut(), | |
245 | Nonterminal::NtPat(pat) => pat.tokens_mut(), | |
246 | Nonterminal::NtTy(ty) => ty.tokens_mut(), | |
247 | Nonterminal::NtMeta(attr_item) => attr_item.tokens_mut(), | |
248 | Nonterminal::NtPath(path) => path.tokens_mut(), | |
249 | Nonterminal::NtVis(vis) => vis.tokens_mut(), | |
250 | Nonterminal::NtBlock(block) => block.tokens_mut(), | |
251 | Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) => None, | |
252 | } | |
253 | } | |
254 | } | |
255 | ||
256 | /// A trait for AST nodes having (or not having) attributes. | |
257 | pub trait HasAttrs { | |
258 | /// This is `true` if this `HasAttrs` might support 'custom' (proc-macro) inner | |
259 | /// attributes. Attributes like `#![cfg]` and `#![cfg_attr]` are not | |
260 | /// considered 'custom' attributes. | |
261 | /// | |
262 | /// If this is `false`, then this `HasAttrs` definitely does | |
263 | /// not support 'custom' inner attributes, which enables some optimizations | |
264 | /// during token collection. | |
265 | const SUPPORTS_CUSTOM_INNER_ATTRS: bool; | |
266 | fn attrs(&self) -> &[Attribute]; | |
267 | fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)); | |
268 | } | |
269 | ||
270 | macro_rules! impl_has_attrs { | |
271 | (const SUPPORTS_CUSTOM_INNER_ATTRS: bool = $inner:literal, $($T:ty),+ $(,)?) => { | |
272 | $( | |
273 | impl HasAttrs for $T { | |
274 | const SUPPORTS_CUSTOM_INNER_ATTRS: bool = $inner; | |
275 | ||
276 | fn attrs(&self) -> &[Attribute] { | |
277 | &self.attrs | |
278 | } | |
279 | ||
280 | fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) { | |
281 | VecOrAttrVec::visit(&mut self.attrs, f) | |
282 | } | |
283 | } | |
284 | )+ | |
285 | }; | |
286 | } | |
287 | ||
288 | macro_rules! impl_has_attrs_none { | |
289 | ($($T:ty),+ $(,)?) => { | |
290 | $( | |
291 | impl HasAttrs for $T { | |
292 | const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false; | |
293 | fn attrs(&self) -> &[Attribute] { | |
294 | &[] | |
295 | } | |
296 | fn visit_attrs(&mut self, _f: impl FnOnce(&mut Vec<Attribute>)) {} | |
297 | } | |
298 | )+ | |
299 | }; | |
300 | } | |
301 | ||
302 | impl_has_attrs!( | |
303 | const SUPPORTS_CUSTOM_INNER_ATTRS: bool = true, | |
304 | AssocItem, | |
305 | ForeignItem, | |
306 | Item, | |
307 | ); | |
308 | impl_has_attrs!( | |
309 | const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false, | |
310 | Arm, | |
311 | Crate, | |
312 | Expr, | |
313 | ExprField, | |
314 | FieldDef, | |
315 | GenericParam, | |
316 | Param, | |
317 | PatField, | |
318 | Variant, | |
319 | ); | |
320 | impl_has_attrs_none!(Attribute, AttrItem, Block, Pat, Path, Ty, Visibility); | |
321 | ||
322 | impl<T: AstDeref<Target: HasAttrs>> HasAttrs for T { | |
323 | const SUPPORTS_CUSTOM_INNER_ATTRS: bool = T::Target::SUPPORTS_CUSTOM_INNER_ATTRS; | |
324 | fn attrs(&self) -> &[Attribute] { | |
325 | self.ast_deref().attrs() | |
326 | } | |
327 | fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) { | |
328 | self.ast_deref_mut().visit_attrs(f) | |
329 | } | |
330 | } | |
331 | ||
332 | impl<T: HasAttrs> HasAttrs for Option<T> { | |
333 | const SUPPORTS_CUSTOM_INNER_ATTRS: bool = T::SUPPORTS_CUSTOM_INNER_ATTRS; | |
334 | fn attrs(&self) -> &[Attribute] { | |
335 | self.as_ref().map(|inner| inner.attrs()).unwrap_or(&[]) | |
336 | } | |
337 | fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) { | |
338 | if let Some(inner) = self.as_mut() { | |
339 | inner.visit_attrs(f); | |
340 | } | |
341 | } | |
342 | } | |
343 | ||
344 | impl HasAttrs for StmtKind { | |
345 | // This might be a `StmtKind::Item`, which contains | |
346 | // an item that supports inner attrs. | |
347 | const SUPPORTS_CUSTOM_INNER_ATTRS: bool = true; | |
348 | ||
349 | fn attrs(&self) -> &[Attribute] { | |
350 | match self { | |
351 | StmtKind::Local(local) => &local.attrs, | |
352 | StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.attrs(), | |
353 | StmtKind::Item(item) => item.attrs(), | |
354 | StmtKind::Empty => &[], | |
355 | StmtKind::MacCall(mac) => &mac.attrs, | |
356 | } | |
357 | } | |
358 | ||
359 | fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) { | |
360 | match self { | |
361 | StmtKind::Local(local) => visit_attrvec(&mut local.attrs, f), | |
362 | StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.visit_attrs(f), | |
363 | StmtKind::Item(item) => item.visit_attrs(f), | |
364 | StmtKind::Empty => {} | |
365 | StmtKind::MacCall(mac) => visit_attrvec(&mut mac.attrs, f), | |
366 | } | |
367 | } | |
368 | } | |
369 | ||
370 | impl HasAttrs for Stmt { | |
371 | const SUPPORTS_CUSTOM_INNER_ATTRS: bool = StmtKind::SUPPORTS_CUSTOM_INNER_ATTRS; | |
372 | fn attrs(&self) -> &[Attribute] { | |
373 | self.kind.attrs() | |
374 | } | |
375 | fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) { | |
376 | self.kind.visit_attrs(f); | |
377 | } | |
378 | } | |
379 | ||
380 | /// Helper trait for the impls above. Abstracts over | |
381 | /// the two types of attribute fields that AST nodes | |
382 | /// may have (`Vec<Attribute>` or `AttrVec`). | |
383 | trait VecOrAttrVec { | |
384 | fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>)); | |
385 | } | |
386 | ||
387 | impl VecOrAttrVec for Vec<Attribute> { | |
388 | fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) { | |
389 | f(self) | |
390 | } | |
391 | } | |
392 | ||
393 | impl VecOrAttrVec for AttrVec { | |
394 | fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) { | |
395 | visit_attrvec(self, f) | |
396 | } | |
397 | } | |
398 | ||
399 | fn visit_attrvec(attrs: &mut AttrVec, f: impl FnOnce(&mut Vec<Attribute>)) { | |
400 | crate::mut_visit::visit_clobber(attrs, |attrs| { | |
401 | let mut vec = attrs.into(); | |
402 | f(&mut vec); | |
403 | vec.into() | |
404 | }); | |
405 | } | |
406 | ||
407 | /// A newtype around an AST node that implements the traits above if the node implements them. | |
408 | pub struct AstNodeWrapper<Wrapped, Tag> { | |
409 | pub wrapped: Wrapped, | |
410 | pub tag: PhantomData<Tag>, | |
411 | } | |
412 | ||
413 | impl<Wrapped, Tag> AstNodeWrapper<Wrapped, Tag> { | |
414 | pub fn new(wrapped: Wrapped, _tag: Tag) -> AstNodeWrapper<Wrapped, Tag> { | |
415 | AstNodeWrapper { wrapped, tag: Default::default() } | |
416 | } | |
417 | } | |
418 | ||
419 | impl<Wrapped, Tag> AstDeref for AstNodeWrapper<Wrapped, Tag> { | |
420 | type Target = Wrapped; | |
421 | fn ast_deref(&self) -> &Self::Target { | |
422 | &self.wrapped | |
423 | } | |
424 | fn ast_deref_mut(&mut self) -> &mut Self::Target { | |
425 | &mut self.wrapped | |
426 | } | |
427 | } | |
428 | ||
429 | impl<Wrapped: fmt::Debug, Tag> fmt::Debug for AstNodeWrapper<Wrapped, Tag> { | |
430 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
431 | f.debug_struct("AstNodeWrapper") | |
432 | .field("wrapped", &self.wrapped) | |
433 | .field("tag", &self.tag) | |
434 | .finish() | |
435 | } | |
436 | } |