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.
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};
16 use std::marker::PhantomData;
18 /// A utility trait to reduce boilerplate.
19 /// Standard `Deref(Mut)` cannot be reused due to coherence.
22 fn ast_deref(&self) -> &Self::Target;
23 fn ast_deref_mut(&mut self) -> &mut Self::Target;
26 macro_rules! impl_not_ast_deref {
27 ($($T:ty),+ $(,)?) => {
29 impl !AstDeref for $T {}
34 impl_not_ast_deref!(AssocItem, Expr, ForeignItem, Item, Stmt);
36 impl<T> AstDeref for P<T> {
38 fn ast_deref(&self) -> &Self::Target {
41 fn ast_deref_mut(&mut self) -> &mut Self::Target {
46 /// A trait for AST nodes having an ID.
48 fn node_id(&self) -> NodeId;
49 fn node_id_mut(&mut self) -> &mut NodeId;
52 macro_rules! impl_has_node_id {
53 ($($T:ty),+ $(,)?) => {
55 impl HasNodeId for $T {
56 fn node_id(&self) -> NodeId {
59 fn node_id_mut(&mut self) -> &mut NodeId {
85 impl<T: AstDeref<Target: HasNodeId>> HasNodeId for T {
86 fn node_id(&self) -> NodeId {
87 self.ast_deref().node_id()
89 fn node_id_mut(&mut self) -> &mut NodeId {
90 self.ast_deref_mut().node_id_mut()
94 /// A trait for AST nodes having a span.
96 fn span(&self) -> Span;
99 macro_rules! impl_has_span {
100 ($($T:ty),+ $(,)?) => {
102 impl HasSpan for $T {
103 fn span(&self) -> Span {
111 impl_has_span!(AssocItem, Block, Expr, ForeignItem, Item, Pat, Path, Stmt, Ty, Visibility);
113 impl<T: AstDeref<Target: HasSpan>> HasSpan for T {
114 fn span(&self) -> Span {
115 self.ast_deref().span()
119 impl HasSpan for AttrItem {
120 fn span(&self) -> Span {
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>>;
131 macro_rules! impl_has_tokens {
132 ($($T:ty),+ $(,)?) => {
134 impl HasTokens for $T {
135 fn tokens(&self) -> Option<&LazyTokenStream> {
138 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
139 Some(&mut self.tokens)
146 macro_rules! impl_has_tokens_none {
147 ($($T:ty),+ $(,)?) => {
149 impl HasTokens for $T {
150 fn tokens(&self) -> Option<&LazyTokenStream> {
153 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
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);
164 impl<T: AstDeref<Target: HasTokens>> HasTokens for T {
165 fn tokens(&self) -> Option<&LazyTokenStream> {
166 self.ast_deref().tokens()
168 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
169 self.ast_deref_mut().tokens_mut()
173 impl<T: HasTokens> HasTokens for Option<T> {
174 fn tokens(&self) -> Option<&LazyTokenStream> {
175 self.as_ref().and_then(|inner| inner.tokens())
177 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
178 self.as_mut().and_then(|inner| inner.tokens_mut())
182 impl HasTokens for StmtKind {
183 fn tokens(&self) -> Option<&LazyTokenStream> {
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(),
192 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
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),
203 impl HasTokens for Stmt {
204 fn tokens(&self) -> Option<&LazyTokenStream> {
207 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
208 self.kind.tokens_mut()
212 impl HasTokens for Attribute {
213 fn tokens(&self) -> Option<&LazyTokenStream> {
215 AttrKind::Normal(normal) => normal.tokens.as_ref(),
216 kind @ AttrKind::DocComment(..) => {
217 panic!("Called tokens on doc comment attr {:?}", kind)
221 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
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)
231 impl HasTokens for Nonterminal {
232 fn tokens(&self) -> Option<&LazyTokenStream> {
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,
246 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
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,
262 /// A trait for AST nodes having (or not having) attributes.
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.
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));
276 macro_rules! impl_has_attrs {
277 (const SUPPORTS_CUSTOM_INNER_ATTRS: bool = $inner:literal, $($T:ty),+ $(,)?) => {
279 impl HasAttrs for $T {
280 const SUPPORTS_CUSTOM_INNER_ATTRS: bool = $inner;
283 fn attrs(&self) -> &[Attribute] {
287 fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) {
295 macro_rules! impl_has_attrs_none {
296 ($($T:ty),+ $(,)?) => {
298 impl HasAttrs for $T {
299 const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false;
300 fn attrs(&self) -> &[Attribute] {
303 fn visit_attrs(&mut self, _f: impl FnOnce(&mut AttrVec)) {}
310 const SUPPORTS_CUSTOM_INNER_ATTRS: bool = true,
316 const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false,
327 impl_has_attrs_none!(Attribute, AttrItem, Block, Pat, Path, Ty, Visibility);
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()
334 fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) {
335 self.ast_deref_mut().visit_attrs(f)
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(&[])
344 fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) {
345 if let Some(inner) = self.as_mut() {
346 inner.visit_attrs(f);
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;
356 fn attrs(&self) -> &[Attribute] {
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,
366 fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) {
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),
377 impl HasAttrs for Stmt {
378 const SUPPORTS_CUSTOM_INNER_ATTRS: bool = StmtKind::SUPPORTS_CUSTOM_INNER_ATTRS;
379 fn attrs(&self) -> &[Attribute] {
382 fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) {
383 self.kind.visit_attrs(f);
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>,
393 impl<Wrapped, Tag> AstNodeWrapper<Wrapped, Tag> {
394 pub fn new(wrapped: Wrapped, _tag: Tag) -> AstNodeWrapper<Wrapped, Tag> {
395 AstNodeWrapper { wrapped, tag: Default::default() }
399 impl<Wrapped, Tag> AstDeref for AstNodeWrapper<Wrapped, Tag> {
400 type Target = Wrapped;
401 fn ast_deref(&self) -> &Self::Target {
404 fn ast_deref_mut(&mut self) -> &mut Self::Target {
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)