]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_ast/src/ast_traits.rs
Rollup merge of #107422 - Nilstrieb:erase-the-ice, r=compiler-errors
[rust.git] / compiler / rustc_ast / src / ast_traits.rs
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::LazyAttrTokenStream;
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, Block, Expr, ForeignItem, Item, Pat, Path, Stmt, Ty, Visibility);
112
113 impl<T: AstDeref<Target: HasSpan>> HasSpan for T {
114     fn span(&self) -> Span {
115         self.ast_deref().span()
116     }
117 }
118
119 impl HasSpan for AttrItem {
120     fn span(&self) -> Span {
121         self.span()
122     }
123 }
124
125 /// A trait for AST nodes having (or not having) collected tokens.
126 pub trait HasTokens {
127     fn tokens(&self) -> Option<&LazyAttrTokenStream>;
128     fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>>;
129 }
130
131 macro_rules! impl_has_tokens {
132     ($($T:ty),+ $(,)?) => {
133         $(
134             impl HasTokens for $T {
135                 fn tokens(&self) -> Option<&LazyAttrTokenStream> {
136                     self.tokens.as_ref()
137                 }
138                 fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> {
139                     Some(&mut self.tokens)
140                 }
141             }
142         )+
143     };
144 }
145
146 macro_rules! impl_has_tokens_none {
147     ($($T:ty),+ $(,)?) => {
148         $(
149             impl HasTokens for $T {
150                 fn tokens(&self) -> Option<&LazyAttrTokenStream> {
151                     None
152                 }
153                 fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> {
154                     None
155                 }
156             }
157         )+
158     };
159 }
160
161 impl_has_tokens!(AssocItem, AttrItem, Block, Expr, ForeignItem, Item, Pat, Path, Ty, Visibility);
162 impl_has_tokens_none!(Arm, ExprField, FieldDef, GenericParam, Param, PatField, Variant);
163
164 impl<T: AstDeref<Target: HasTokens>> HasTokens for T {
165     fn tokens(&self) -> Option<&LazyAttrTokenStream> {
166         self.ast_deref().tokens()
167     }
168     fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> {
169         self.ast_deref_mut().tokens_mut()
170     }
171 }
172
173 impl<T: HasTokens> HasTokens for Option<T> {
174     fn tokens(&self) -> Option<&LazyAttrTokenStream> {
175         self.as_ref().and_then(|inner| inner.tokens())
176     }
177     fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> {
178         self.as_mut().and_then(|inner| inner.tokens_mut())
179     }
180 }
181
182 impl HasTokens for StmtKind {
183     fn tokens(&self) -> Option<&LazyAttrTokenStream> {
184         match self {
185             StmtKind::Local(local) => local.tokens.as_ref(),
186             StmtKind::Item(item) => item.tokens(),
187             StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.tokens(),
188             StmtKind::Empty => return None,
189             StmtKind::MacCall(mac) => mac.tokens.as_ref(),
190         }
191     }
192     fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> {
193         match self {
194             StmtKind::Local(local) => Some(&mut local.tokens),
195             StmtKind::Item(item) => item.tokens_mut(),
196             StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.tokens_mut(),
197             StmtKind::Empty => return None,
198             StmtKind::MacCall(mac) => Some(&mut mac.tokens),
199         }
200     }
201 }
202
203 impl HasTokens for Stmt {
204     fn tokens(&self) -> Option<&LazyAttrTokenStream> {
205         self.kind.tokens()
206     }
207     fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> {
208         self.kind.tokens_mut()
209     }
210 }
211
212 impl HasTokens for Attribute {
213     fn tokens(&self) -> Option<&LazyAttrTokenStream> {
214         match &self.kind {
215             AttrKind::Normal(normal) => normal.tokens.as_ref(),
216             kind @ AttrKind::DocComment(..) => {
217                 panic!("Called tokens on doc comment attr {kind:?}")
218             }
219         }
220     }
221     fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> {
222         Some(match &mut self.kind {
223             AttrKind::Normal(normal) => &mut normal.tokens,
224             kind @ AttrKind::DocComment(..) => {
225                 panic!("Called tokens_mut on doc comment attr {kind:?}")
226             }
227         })
228     }
229 }
230
231 impl HasTokens for Nonterminal {
232     fn tokens(&self) -> Option<&LazyAttrTokenStream> {
233         match self {
234             Nonterminal::NtItem(item) => item.tokens(),
235             Nonterminal::NtStmt(stmt) => stmt.tokens(),
236             Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens(),
237             Nonterminal::NtPat(pat) => pat.tokens(),
238             Nonterminal::NtTy(ty) => ty.tokens(),
239             Nonterminal::NtMeta(attr_item) => attr_item.tokens(),
240             Nonterminal::NtPath(path) => path.tokens(),
241             Nonterminal::NtVis(vis) => vis.tokens(),
242             Nonterminal::NtBlock(block) => block.tokens(),
243             Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) => None,
244         }
245     }
246     fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> {
247         match self {
248             Nonterminal::NtItem(item) => item.tokens_mut(),
249             Nonterminal::NtStmt(stmt) => stmt.tokens_mut(),
250             Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens_mut(),
251             Nonterminal::NtPat(pat) => pat.tokens_mut(),
252             Nonterminal::NtTy(ty) => ty.tokens_mut(),
253             Nonterminal::NtMeta(attr_item) => attr_item.tokens_mut(),
254             Nonterminal::NtPath(path) => path.tokens_mut(),
255             Nonterminal::NtVis(vis) => vis.tokens_mut(),
256             Nonterminal::NtBlock(block) => block.tokens_mut(),
257             Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) => None,
258         }
259     }
260 }
261
262 /// A trait for AST nodes having (or not having) attributes.
263 pub trait HasAttrs {
264     /// This is `true` if this `HasAttrs` might support 'custom' (proc-macro) inner
265     /// attributes. Attributes like `#![cfg]` and `#![cfg_attr]` are not
266     /// considered 'custom' attributes.
267     ///
268     /// If this is `false`, then this `HasAttrs` definitely does
269     /// not support 'custom' inner attributes, which enables some optimizations
270     /// during token collection.
271     const SUPPORTS_CUSTOM_INNER_ATTRS: bool;
272     fn attrs(&self) -> &[Attribute];
273     fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec));
274 }
275
276 macro_rules! impl_has_attrs {
277     (const SUPPORTS_CUSTOM_INNER_ATTRS: bool = $inner:literal, $($T:ty),+ $(,)?) => {
278         $(
279             impl HasAttrs for $T {
280                 const SUPPORTS_CUSTOM_INNER_ATTRS: bool = $inner;
281
282                 #[inline]
283                 fn attrs(&self) -> &[Attribute] {
284                     &self.attrs
285                 }
286
287                 fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) {
288                     f(&mut self.attrs)
289                 }
290             }
291         )+
292     };
293 }
294
295 macro_rules! impl_has_attrs_none {
296     ($($T:ty),+ $(,)?) => {
297         $(
298             impl HasAttrs for $T {
299                 const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false;
300                 fn attrs(&self) -> &[Attribute] {
301                     &[]
302                 }
303                 fn visit_attrs(&mut self, _f: impl FnOnce(&mut AttrVec)) {}
304             }
305         )+
306     };
307 }
308
309 impl_has_attrs!(
310     const SUPPORTS_CUSTOM_INNER_ATTRS: bool = true,
311     AssocItem,
312     ForeignItem,
313     Item,
314 );
315 impl_has_attrs!(
316     const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false,
317     Arm,
318     Crate,
319     Expr,
320     ExprField,
321     FieldDef,
322     GenericParam,
323     Param,
324     PatField,
325     Variant,
326 );
327 impl_has_attrs_none!(Attribute, AttrItem, Block, Pat, Path, Ty, Visibility);
328
329 impl<T: AstDeref<Target: HasAttrs>> HasAttrs for T {
330     const SUPPORTS_CUSTOM_INNER_ATTRS: bool = T::Target::SUPPORTS_CUSTOM_INNER_ATTRS;
331     fn attrs(&self) -> &[Attribute] {
332         self.ast_deref().attrs()
333     }
334     fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) {
335         self.ast_deref_mut().visit_attrs(f)
336     }
337 }
338
339 impl<T: HasAttrs> HasAttrs for Option<T> {
340     const SUPPORTS_CUSTOM_INNER_ATTRS: bool = T::SUPPORTS_CUSTOM_INNER_ATTRS;
341     fn attrs(&self) -> &[Attribute] {
342         self.as_ref().map(|inner| inner.attrs()).unwrap_or(&[])
343     }
344     fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) {
345         if let Some(inner) = self.as_mut() {
346             inner.visit_attrs(f);
347         }
348     }
349 }
350
351 impl HasAttrs for StmtKind {
352     // This might be a `StmtKind::Item`, which contains
353     // an item that supports inner attrs.
354     const SUPPORTS_CUSTOM_INNER_ATTRS: bool = true;
355
356     fn attrs(&self) -> &[Attribute] {
357         match self {
358             StmtKind::Local(local) => &local.attrs,
359             StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.attrs(),
360             StmtKind::Item(item) => item.attrs(),
361             StmtKind::Empty => &[],
362             StmtKind::MacCall(mac) => &mac.attrs,
363         }
364     }
365
366     fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) {
367         match self {
368             StmtKind::Local(local) => f(&mut local.attrs),
369             StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.visit_attrs(f),
370             StmtKind::Item(item) => item.visit_attrs(f),
371             StmtKind::Empty => {}
372             StmtKind::MacCall(mac) => f(&mut mac.attrs),
373         }
374     }
375 }
376
377 impl HasAttrs for Stmt {
378     const SUPPORTS_CUSTOM_INNER_ATTRS: bool = StmtKind::SUPPORTS_CUSTOM_INNER_ATTRS;
379     fn attrs(&self) -> &[Attribute] {
380         self.kind.attrs()
381     }
382     fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) {
383         self.kind.visit_attrs(f);
384     }
385 }
386
387 /// A newtype around an AST node that implements the traits above if the node implements them.
388 pub struct AstNodeWrapper<Wrapped, Tag> {
389     pub wrapped: Wrapped,
390     pub tag: PhantomData<Tag>,
391 }
392
393 impl<Wrapped, Tag> AstNodeWrapper<Wrapped, Tag> {
394     pub fn new(wrapped: Wrapped, _tag: Tag) -> AstNodeWrapper<Wrapped, Tag> {
395         AstNodeWrapper { wrapped, tag: Default::default() }
396     }
397 }
398
399 impl<Wrapped, Tag> AstDeref for AstNodeWrapper<Wrapped, Tag> {
400     type Target = Wrapped;
401     fn ast_deref(&self) -> &Self::Target {
402         &self.wrapped
403     }
404     fn ast_deref_mut(&mut self) -> &mut Self::Target {
405         &mut self.wrapped
406     }
407 }
408
409 impl<Wrapped: fmt::Debug, Tag> fmt::Debug for AstNodeWrapper<Wrapped, Tag> {
410     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
411         f.debug_struct("AstNodeWrapper")
412             .field("wrapped", &self.wrapped)
413             .field("tag", &self.tag)
414             .finish()
415     }
416 }