]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_ast/src/ast_traits.rs
Rollup merge of #100167 - chenyukang:require-suggestion, r=estebank
[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::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, 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<&LazyTokenStream>;
128     fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>>;
129 }
130
131 macro_rules! impl_has_tokens {
132     ($($T:ty),+ $(,)?) => {
133         $(
134             impl HasTokens for $T {
135                 fn tokens(&self) -> Option<&LazyTokenStream> {
136                     self.tokens.as_ref()
137                 }
138                 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
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<&LazyTokenStream> {
151                     None
152                 }
153                 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
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<&LazyTokenStream> {
166         self.ast_deref().tokens()
167     }
168     fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
169         self.ast_deref_mut().tokens_mut()
170     }
171 }
172
173 impl<T: HasTokens> HasTokens for Option<T> {
174     fn tokens(&self) -> Option<&LazyTokenStream> {
175         self.as_ref().and_then(|inner| inner.tokens())
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 impl HasTokens for StmtKind {
183     fn tokens(&self) -> Option<&LazyTokenStream> {
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<LazyTokenStream>> {
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<&LazyTokenStream> {
205         self.kind.tokens()
206     }
207     fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
208         self.kind.tokens_mut()
209     }
210 }
211
212 impl HasTokens for Attribute {
213     fn tokens(&self) -> Option<&LazyTokenStream> {
214         match &self.kind {
215             AttrKind::Normal(_, tokens) => 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<LazyTokenStream>> {
222         Some(match &mut self.kind {
223             AttrKind::Normal(_, tokens) => 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<&LazyTokenStream> {
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<LazyTokenStream>> {
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 Vec<Attribute>));
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                 fn attrs(&self) -> &[Attribute] {
283                     &self.attrs
284                 }
285
286                 fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
287                     VecOrAttrVec::visit(&mut self.attrs, f)
288                 }
289             }
290         )+
291     };
292 }
293
294 macro_rules! impl_has_attrs_none {
295     ($($T:ty),+ $(,)?) => {
296         $(
297             impl HasAttrs for $T {
298                 const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false;
299                 fn attrs(&self) -> &[Attribute] {
300                     &[]
301                 }
302                 fn visit_attrs(&mut self, _f: impl FnOnce(&mut Vec<Attribute>)) {}
303             }
304         )+
305     };
306 }
307
308 impl_has_attrs!(
309     const SUPPORTS_CUSTOM_INNER_ATTRS: bool = true,
310     AssocItem,
311     ForeignItem,
312     Item,
313 );
314 impl_has_attrs!(
315     const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false,
316     Arm,
317     Crate,
318     Expr,
319     ExprField,
320     FieldDef,
321     GenericParam,
322     Param,
323     PatField,
324     Variant,
325 );
326 impl_has_attrs_none!(Attribute, AttrItem, Block, Pat, Path, Ty, Visibility);
327
328 impl<T: AstDeref<Target: HasAttrs>> HasAttrs for T {
329     const SUPPORTS_CUSTOM_INNER_ATTRS: bool = T::Target::SUPPORTS_CUSTOM_INNER_ATTRS;
330     fn attrs(&self) -> &[Attribute] {
331         self.ast_deref().attrs()
332     }
333     fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
334         self.ast_deref_mut().visit_attrs(f)
335     }
336 }
337
338 impl<T: HasAttrs> HasAttrs for Option<T> {
339     const SUPPORTS_CUSTOM_INNER_ATTRS: bool = T::SUPPORTS_CUSTOM_INNER_ATTRS;
340     fn attrs(&self) -> &[Attribute] {
341         self.as_ref().map(|inner| inner.attrs()).unwrap_or(&[])
342     }
343     fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
344         if let Some(inner) = self.as_mut() {
345             inner.visit_attrs(f);
346         }
347     }
348 }
349
350 impl HasAttrs for StmtKind {
351     // This might be a `StmtKind::Item`, which contains
352     // an item that supports inner attrs.
353     const SUPPORTS_CUSTOM_INNER_ATTRS: bool = true;
354
355     fn attrs(&self) -> &[Attribute] {
356         match self {
357             StmtKind::Local(local) => &local.attrs,
358             StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.attrs(),
359             StmtKind::Item(item) => item.attrs(),
360             StmtKind::Empty => &[],
361             StmtKind::MacCall(mac) => &mac.attrs,
362         }
363     }
364
365     fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
366         match self {
367             StmtKind::Local(local) => visit_attrvec(&mut local.attrs, f),
368             StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.visit_attrs(f),
369             StmtKind::Item(item) => item.visit_attrs(f),
370             StmtKind::Empty => {}
371             StmtKind::MacCall(mac) => visit_attrvec(&mut mac.attrs, f),
372         }
373     }
374 }
375
376 impl HasAttrs for Stmt {
377     const SUPPORTS_CUSTOM_INNER_ATTRS: bool = StmtKind::SUPPORTS_CUSTOM_INNER_ATTRS;
378     fn attrs(&self) -> &[Attribute] {
379         self.kind.attrs()
380     }
381     fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
382         self.kind.visit_attrs(f);
383     }
384 }
385
386 /// Helper trait for the impls above. Abstracts over
387 /// the two types of attribute fields that AST nodes
388 /// may have (`Vec<Attribute>` or `AttrVec`).
389 trait VecOrAttrVec {
390     fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>));
391 }
392
393 impl VecOrAttrVec for Vec<Attribute> {
394     fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
395         f(self)
396     }
397 }
398
399 impl VecOrAttrVec for AttrVec {
400     fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
401         visit_attrvec(self, f)
402     }
403 }
404
405 fn visit_attrvec(attrs: &mut AttrVec, f: impl FnOnce(&mut Vec<Attribute>)) {
406     crate::mut_visit::visit_clobber(attrs, |attrs| {
407         let mut vec = attrs.into();
408         f(&mut vec);
409         vec.into()
410     });
411 }
412
413 /// A newtype around an AST node that implements the traits above if the node implements them.
414 pub struct AstNodeWrapper<Wrapped, Tag> {
415     pub wrapped: Wrapped,
416     pub tag: PhantomData<Tag>,
417 }
418
419 impl<Wrapped, Tag> AstNodeWrapper<Wrapped, Tag> {
420     pub fn new(wrapped: Wrapped, _tag: Tag) -> AstNodeWrapper<Wrapped, Tag> {
421         AstNodeWrapper { wrapped, tag: Default::default() }
422     }
423 }
424
425 impl<Wrapped, Tag> AstDeref for AstNodeWrapper<Wrapped, Tag> {
426     type Target = Wrapped;
427     fn ast_deref(&self) -> &Self::Target {
428         &self.wrapped
429     }
430     fn ast_deref_mut(&mut self) -> &mut Self::Target {
431         &mut self.wrapped
432     }
433 }
434
435 impl<Wrapped: fmt::Debug, Tag> fmt::Debug for AstNodeWrapper<Wrapped, Tag> {
436     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
437         f.debug_struct("AstNodeWrapper")
438             .field("wrapped", &self.wrapped)
439             .field("tag", &self.tag)
440             .finish()
441     }
442 }