From f2b7fa484739d3f7d1303c7d42138040caaf435e Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 1 May 2022 20:58:24 +0300 Subject: [PATCH] ast: Introduce some traits to get AST node properties generically And use them to avoid constructing some artificial `Nonterminal` tokens during expansion --- compiler/rustc_ast/src/ast.rs | 17 - compiler/rustc_ast/src/ast_like.rs | 320 ------------- compiler/rustc_ast/src/ast_traits.rs | 436 ++++++++++++++++++ compiler/rustc_ast/src/lib.rs | 6 +- compiler/rustc_ast_pretty/src/lib.rs | 2 + compiler/rustc_ast_pretty/src/pprust/mod.rs | 32 +- compiler/rustc_ast_pretty/src/pprust/state.rs | 8 + .../rustc_ast_pretty/src/pprust/state/item.rs | 4 +- compiler/rustc_builtin_macros/src/cfg_eval.rs | 11 +- compiler/rustc_expand/src/base.rs | 62 ++- compiler/rustc_expand/src/config.rs | 8 +- compiler/rustc_expand/src/expand.rs | 86 +--- compiler/rustc_expand/src/proc_macro.rs | 31 +- .../rustc_expand/src/proc_macro_server.rs | 2 +- compiler/rustc_lint/src/early.rs | 3 +- compiler/rustc_parse/src/lib.rs | 30 +- .../rustc_parse/src/parser/attr_wrapper.rs | 4 +- compiler/rustc_parse/src/parser/mod.rs | 6 +- .../rustc_parse/src/parser/nonterminal.rs | 2 +- compiler/rustc_parse/src/parser/stmt.rs | 6 +- src/tools/rustfmt/src/attr.rs | 2 +- src/tools/rustfmt/src/formatting.rs | 1 - src/tools/rustfmt/src/modules.rs | 12 +- src/tools/rustfmt/src/visitor.rs | 2 +- 24 files changed, 593 insertions(+), 500 deletions(-) delete mode 100644 compiler/rustc_ast/src/ast_like.rs create mode 100644 compiler/rustc_ast/src/ast_traits.rs diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index e8cc9d9d291..5a4c997ed9b 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -929,16 +929,6 @@ pub struct Stmt { } impl Stmt { - pub fn tokens(&self) -> Option<&LazyTokenStream> { - match self.kind { - StmtKind::Local(ref local) => local.tokens.as_ref(), - StmtKind::Item(ref item) => item.tokens.as_ref(), - StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => expr.tokens.as_ref(), - StmtKind::Empty => None, - StmtKind::MacCall(ref mac) => mac.tokens.as_ref(), - } - } - pub fn has_trailing_semicolon(&self) -> bool { match &self.kind { StmtKind::Semi(_) => true, @@ -2684,13 +2674,6 @@ pub fn span_with_attributes(&self) -> Span { } } -impl> Item { - pub fn into_item(self) -> Item { - let Item { attrs, id, span, vis, ident, kind, tokens } = self; - Item { attrs, id, span, vis, ident, kind: kind.into(), tokens } - } -} - /// `extern` qualifier on a function item or function type. #[derive(Clone, Copy, Encodable, Decodable, Debug)] pub enum Extern { diff --git a/compiler/rustc_ast/src/ast_like.rs b/compiler/rustc_ast/src/ast_like.rs deleted file mode 100644 index 1a271b0adef..00000000000 --- a/compiler/rustc_ast/src/ast_like.rs +++ /dev/null @@ -1,320 +0,0 @@ -use super::ptr::P; -use super::token::Nonterminal; -use super::tokenstream::LazyTokenStream; -use super::{Arm, Crate, ExprField, FieldDef, GenericParam, Param, PatField, Variant}; -use super::{AssocItem, Expr, ForeignItem, Item, Local, MacCallStmt}; -use super::{AttrItem, AttrKind, Block, Pat, Path, Ty, Visibility}; -use super::{AttrVec, Attribute, Stmt, StmtKind}; - -use std::fmt; -use std::marker::PhantomData; - -/// An `AstLike` represents an AST node (or some wrapper around -/// and AST node) which stores some combination of attributes -/// and tokens. -pub trait AstLike: Sized + fmt::Debug { - /// This is `true` if this `AstLike` might support 'custom' (proc-macro) inner - /// attributes. Attributes like `#![cfg]` and `#![cfg_attr]` are not - /// considered 'custom' attributes - /// - /// If this is `false`, then this `AstLike` definitely does - /// not support 'custom' inner attributes, which enables some optimizations - /// during token collection. - const SUPPORTS_CUSTOM_INNER_ATTRS: bool; - fn attrs(&self) -> &[Attribute]; - fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec)); - fn tokens_mut(&mut self) -> Option<&mut Option>; -} - -impl AstLike for P { - const SUPPORTS_CUSTOM_INNER_ATTRS: bool = T::SUPPORTS_CUSTOM_INNER_ATTRS; - fn attrs(&self) -> &[Attribute] { - (**self).attrs() - } - fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec)) { - (**self).visit_attrs(f); - } - fn tokens_mut(&mut self) -> Option<&mut Option> { - (**self).tokens_mut() - } -} - -impl AstLike for crate::token::Nonterminal { - const SUPPORTS_CUSTOM_INNER_ATTRS: bool = true; - fn attrs(&self) -> &[Attribute] { - match self { - Nonterminal::NtItem(item) => item.attrs(), - Nonterminal::NtStmt(stmt) => stmt.attrs(), - Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.attrs(), - Nonterminal::NtPat(_) - | Nonterminal::NtTy(_) - | Nonterminal::NtMeta(_) - | Nonterminal::NtPath(_) - | Nonterminal::NtVis(_) - | Nonterminal::NtBlock(_) - | Nonterminal::NtIdent(..) - | Nonterminal::NtLifetime(_) => &[], - } - } - fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec)) { - match self { - Nonterminal::NtItem(item) => item.visit_attrs(f), - Nonterminal::NtStmt(stmt) => stmt.visit_attrs(f), - Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.visit_attrs(f), - Nonterminal::NtPat(_) - | Nonterminal::NtTy(_) - | Nonterminal::NtMeta(_) - | Nonterminal::NtPath(_) - | Nonterminal::NtVis(_) - | Nonterminal::NtBlock(_) - | Nonterminal::NtIdent(..) - | Nonterminal::NtLifetime(_) => {} - } - } - fn tokens_mut(&mut self) -> Option<&mut Option> { - match self { - Nonterminal::NtItem(item) => item.tokens_mut(), - Nonterminal::NtStmt(stmt) => stmt.tokens_mut(), - Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens_mut(), - Nonterminal::NtPat(pat) => pat.tokens_mut(), - Nonterminal::NtTy(ty) => ty.tokens_mut(), - Nonterminal::NtMeta(attr_item) => attr_item.tokens_mut(), - Nonterminal::NtPath(path) => path.tokens_mut(), - Nonterminal::NtVis(vis) => vis.tokens_mut(), - Nonterminal::NtBlock(block) => block.tokens_mut(), - Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) => None, - } - } -} - -fn visit_attrvec(attrs: &mut AttrVec, f: impl FnOnce(&mut Vec)) { - crate::mut_visit::visit_clobber(attrs, |attrs| { - let mut vec = attrs.into(); - f(&mut vec); - vec.into() - }); -} - -impl AstLike for StmtKind { - // This might be an `StmtKind::Item`, which contains - // an item that supports inner attrs - const SUPPORTS_CUSTOM_INNER_ATTRS: bool = true; - - fn attrs(&self) -> &[Attribute] { - match self { - StmtKind::Local(local) => local.attrs(), - StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.attrs(), - StmtKind::Item(item) => item.attrs(), - StmtKind::Empty => &[], - StmtKind::MacCall(mac) => &mac.attrs, - } - } - - fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec)) { - match self { - StmtKind::Local(local) => local.visit_attrs(f), - StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.visit_attrs(f), - StmtKind::Item(item) => item.visit_attrs(f), - StmtKind::Empty => {} - StmtKind::MacCall(mac) => visit_attrvec(&mut mac.attrs, f), - } - } - fn tokens_mut(&mut self) -> Option<&mut Option> { - Some(match self { - StmtKind::Local(local) => &mut local.tokens, - StmtKind::Item(item) => &mut item.tokens, - StmtKind::Expr(expr) | StmtKind::Semi(expr) => &mut expr.tokens, - StmtKind::Empty => return None, - StmtKind::MacCall(mac) => &mut mac.tokens, - }) - } -} - -impl AstLike for Stmt { - const SUPPORTS_CUSTOM_INNER_ATTRS: bool = StmtKind::SUPPORTS_CUSTOM_INNER_ATTRS; - - fn attrs(&self) -> &[Attribute] { - self.kind.attrs() - } - - fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec)) { - self.kind.visit_attrs(f); - } - fn tokens_mut(&mut self) -> Option<&mut Option> { - self.kind.tokens_mut() - } -} - -impl AstLike for Attribute { - const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false; - - fn attrs(&self) -> &[Attribute] { - &[] - } - fn visit_attrs(&mut self, _f: impl FnOnce(&mut Vec)) {} - fn tokens_mut(&mut self) -> Option<&mut Option> { - Some(match &mut self.kind { - AttrKind::Normal(_, tokens) => tokens, - kind @ AttrKind::DocComment(..) => { - panic!("Called tokens_mut on doc comment attr {:?}", kind) - } - }) - } -} - -impl AstLike for Option { - const SUPPORTS_CUSTOM_INNER_ATTRS: bool = T::SUPPORTS_CUSTOM_INNER_ATTRS; - - fn attrs(&self) -> &[Attribute] { - self.as_ref().map(|inner| inner.attrs()).unwrap_or(&[]) - } - fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec)) { - if let Some(inner) = self.as_mut() { - inner.visit_attrs(f); - } - } - fn tokens_mut(&mut self) -> Option<&mut Option> { - self.as_mut().and_then(|inner| inner.tokens_mut()) - } -} - -/// Helper trait for the macros below. Abstracts over -/// the two types of attribute fields that AST nodes -/// may have (`Vec` or `AttrVec`) -trait VecOrAttrVec { - fn visit(&mut self, f: impl FnOnce(&mut Vec)); -} - -impl VecOrAttrVec for Vec { - fn visit(&mut self, f: impl FnOnce(&mut Vec)) { - f(self) - } -} - -impl VecOrAttrVec for AttrVec { - fn visit(&mut self, f: impl FnOnce(&mut Vec)) { - visit_attrvec(self, f) - } -} - -macro_rules! derive_has_tokens_and_attrs { - ( - const SUPPORTS_CUSTOM_INNER_ATTRS: bool = $inner_attrs:literal; - $($ty:path),* - ) => { $( - impl AstLike for $ty { - const SUPPORTS_CUSTOM_INNER_ATTRS: bool = $inner_attrs; - - fn attrs(&self) -> &[Attribute] { - &self.attrs - } - - fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec)) { - VecOrAttrVec::visit(&mut self.attrs, f) - } - - fn tokens_mut(&mut self) -> Option<&mut Option> { - Some(&mut self.tokens) - } - - } - )* } -} - -macro_rules! derive_has_attrs_no_tokens { - ($($ty:path),*) => { $( - impl AstLike for $ty { - const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false; - - fn attrs(&self) -> &[Attribute] { - &self.attrs - } - - fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec)) { - VecOrAttrVec::visit(&mut self.attrs, f) - } - - fn tokens_mut(&mut self) -> Option<&mut Option> { - None - } - } - )* } -} - -macro_rules! derive_has_tokens_no_attrs { - ($($ty:path),*) => { $( - impl AstLike for $ty { - const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false; - - fn attrs(&self) -> &[Attribute] { - &[] - } - - fn visit_attrs(&mut self, _f: impl FnOnce(&mut Vec)) {} - fn tokens_mut(&mut self) -> Option<&mut Option> { - Some(&mut self.tokens) - } - } - )* } -} - -// These ast nodes support both active and inert attributes, -// so they have tokens collected to pass to proc macros -derive_has_tokens_and_attrs! { - // Both `Item` and `AssocItem` can have bodies, which - // can contain inner attributes - const SUPPORTS_CUSTOM_INNER_ATTRS: bool = true; - Item, AssocItem, ForeignItem -} - -derive_has_tokens_and_attrs! { - const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false; - Local, MacCallStmt, Expr -} - -// These ast nodes only support inert attributes, so they don't -// store tokens (since nothing can observe them) -derive_has_attrs_no_tokens! { - FieldDef, Arm, ExprField, PatField, Variant, Param, GenericParam, Crate -} - -// These AST nodes don't support attributes, but can -// be captured by a `macro_rules!` matcher. Therefore, -// they need to store tokens. -derive_has_tokens_no_attrs! { - Ty, Block, AttrItem, Pat, Path, Visibility -} - -/// A newtype around an `AstLike` node that implements `AstLike` itself. -pub struct AstLikeWrapper { - pub wrapped: Wrapped, - pub tag: PhantomData, -} - -impl AstLikeWrapper { - pub fn new(wrapped: Wrapped, _tag: Tag) -> AstLikeWrapper { - AstLikeWrapper { wrapped, tag: Default::default() } - } -} - -impl fmt::Debug for AstLikeWrapper { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("AstLikeWrapper") - .field("wrapped", &self.wrapped) - .field("tag", &self.tag) - .finish() - } -} - -impl AstLike for AstLikeWrapper { - const SUPPORTS_CUSTOM_INNER_ATTRS: bool = Wrapped::SUPPORTS_CUSTOM_INNER_ATTRS; - fn attrs(&self) -> &[Attribute] { - self.wrapped.attrs() - } - fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec)) { - self.wrapped.visit_attrs(f) - } - fn tokens_mut(&mut self) -> Option<&mut Option> { - self.wrapped.tokens_mut() - } -} diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs new file mode 100644 index 00000000000..bd401ddbbee --- /dev/null +++ b/compiler/rustc_ast/src/ast_traits.rs @@ -0,0 +1,436 @@ +//! A set of traits implemented for various AST nodes, +//! typically those used in AST fragments during macro expansion. +//! The traits are not implemented exhaustively, only when actually necessary. + +use crate::ptr::P; +use crate::token::Nonterminal; +use crate::tokenstream::LazyTokenStream; +use crate::{Arm, Crate, ExprField, FieldDef, GenericParam, Param, PatField, Variant}; +use crate::{AssocItem, Expr, ForeignItem, Item, NodeId}; +use crate::{AttrItem, AttrKind, Block, Pat, Path, Ty, Visibility}; +use crate::{AttrVec, Attribute, Stmt, StmtKind}; + +use rustc_span::Span; + +use std::fmt; +use std::marker::PhantomData; + +/// A utility trait to reduce boilerplate. +/// Standard `Deref(Mut)` cannot be reused due to coherence. +pub trait AstDeref { + type Target; + fn ast_deref(&self) -> &Self::Target; + fn ast_deref_mut(&mut self) -> &mut Self::Target; +} + +macro_rules! impl_not_ast_deref { + ($($T:ty),+ $(,)?) => { + $( + impl !AstDeref for $T {} + )+ + }; +} + +impl_not_ast_deref!(AssocItem, Expr, ForeignItem, Item, Stmt); + +impl AstDeref for P { + type Target = T; + fn ast_deref(&self) -> &Self::Target { + self + } + fn ast_deref_mut(&mut self) -> &mut Self::Target { + self + } +} + +/// A trait for AST nodes having an ID. +pub trait HasNodeId { + fn node_id(&self) -> NodeId; + fn node_id_mut(&mut self) -> &mut NodeId; +} + +macro_rules! impl_has_node_id { + ($($T:ty),+ $(,)?) => { + $( + impl HasNodeId for $T { + fn node_id(&self) -> NodeId { + self.id + } + fn node_id_mut(&mut self) -> &mut NodeId { + &mut self.id + } + } + )+ + }; +} + +impl_has_node_id!( + Arm, + AssocItem, + Crate, + Expr, + ExprField, + FieldDef, + ForeignItem, + GenericParam, + Item, + Param, + Pat, + PatField, + Stmt, + Ty, + Variant, +); + +impl> HasNodeId for T { + fn node_id(&self) -> NodeId { + self.ast_deref().node_id() + } + fn node_id_mut(&mut self) -> &mut NodeId { + self.ast_deref_mut().node_id_mut() + } +} + +/// A trait for AST nodes having a span. +pub trait HasSpan { + fn span(&self) -> Span; +} + +macro_rules! impl_has_span { + ($($T:ty),+ $(,)?) => { + $( + impl HasSpan for $T { + fn span(&self) -> Span { + self.span + } + } + )+ + }; +} + +impl_has_span!(AssocItem, Expr, ForeignItem, Item, Stmt); + +impl> HasSpan for T { + fn span(&self) -> Span { + self.ast_deref().span() + } +} + +/// A trait for AST nodes having (or not having) collected tokens. +pub trait HasTokens { + fn tokens(&self) -> Option<&LazyTokenStream>; + fn tokens_mut(&mut self) -> Option<&mut Option>; +} + +macro_rules! impl_has_tokens { + ($($T:ty),+ $(,)?) => { + $( + impl HasTokens for $T { + fn tokens(&self) -> Option<&LazyTokenStream> { + self.tokens.as_ref() + } + fn tokens_mut(&mut self) -> Option<&mut Option> { + Some(&mut self.tokens) + } + } + )+ + }; +} + +macro_rules! impl_has_tokens_none { + ($($T:ty),+ $(,)?) => { + $( + impl HasTokens for $T { + fn tokens(&self) -> Option<&LazyTokenStream> { + None + } + fn tokens_mut(&mut self) -> Option<&mut Option> { + None + } + } + )+ + }; +} + +impl_has_tokens!(AssocItem, AttrItem, Block, Expr, ForeignItem, Item, Pat, Path, Ty, Visibility); +impl_has_tokens_none!(Arm, ExprField, FieldDef, GenericParam, Param, PatField, Variant); + +impl> HasTokens for T { + fn tokens(&self) -> Option<&LazyTokenStream> { + self.ast_deref().tokens() + } + fn tokens_mut(&mut self) -> Option<&mut Option> { + self.ast_deref_mut().tokens_mut() + } +} + +impl HasTokens for Option { + fn tokens(&self) -> Option<&LazyTokenStream> { + self.as_ref().and_then(|inner| inner.tokens()) + } + fn tokens_mut(&mut self) -> Option<&mut Option> { + self.as_mut().and_then(|inner| inner.tokens_mut()) + } +} + +impl HasTokens for StmtKind { + fn tokens(&self) -> Option<&LazyTokenStream> { + match self { + StmtKind::Local(local) => local.tokens.as_ref(), + StmtKind::Item(item) => item.tokens(), + StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.tokens(), + StmtKind::Empty => return None, + StmtKind::MacCall(mac) => mac.tokens.as_ref(), + } + } + fn tokens_mut(&mut self) -> Option<&mut Option> { + match self { + StmtKind::Local(local) => Some(&mut local.tokens), + StmtKind::Item(item) => item.tokens_mut(), + StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.tokens_mut(), + StmtKind::Empty => return None, + StmtKind::MacCall(mac) => Some(&mut mac.tokens), + } + } +} + +impl HasTokens for Stmt { + fn tokens(&self) -> Option<&LazyTokenStream> { + self.kind.tokens() + } + fn tokens_mut(&mut self) -> Option<&mut Option> { + self.kind.tokens_mut() + } +} + +impl HasTokens for Attribute { + fn tokens(&self) -> Option<&LazyTokenStream> { + match &self.kind { + AttrKind::Normal(_, tokens) => tokens.as_ref(), + kind @ AttrKind::DocComment(..) => { + panic!("Called tokens on doc comment attr {:?}", kind) + } + } + } + fn tokens_mut(&mut self) -> Option<&mut Option> { + Some(match &mut self.kind { + AttrKind::Normal(_, tokens) => tokens, + kind @ AttrKind::DocComment(..) => { + panic!("Called tokens_mut on doc comment attr {:?}", kind) + } + }) + } +} + +impl HasTokens for Nonterminal { + fn tokens(&self) -> Option<&LazyTokenStream> { + match self { + Nonterminal::NtItem(item) => item.tokens(), + Nonterminal::NtStmt(stmt) => stmt.tokens(), + Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens(), + Nonterminal::NtPat(pat) => pat.tokens(), + Nonterminal::NtTy(ty) => ty.tokens(), + Nonterminal::NtMeta(attr_item) => attr_item.tokens(), + Nonterminal::NtPath(path) => path.tokens(), + Nonterminal::NtVis(vis) => vis.tokens(), + Nonterminal::NtBlock(block) => block.tokens(), + Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) => None, + } + } + fn tokens_mut(&mut self) -> Option<&mut Option> { + match self { + Nonterminal::NtItem(item) => item.tokens_mut(), + Nonterminal::NtStmt(stmt) => stmt.tokens_mut(), + Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens_mut(), + Nonterminal::NtPat(pat) => pat.tokens_mut(), + Nonterminal::NtTy(ty) => ty.tokens_mut(), + Nonterminal::NtMeta(attr_item) => attr_item.tokens_mut(), + Nonterminal::NtPath(path) => path.tokens_mut(), + Nonterminal::NtVis(vis) => vis.tokens_mut(), + Nonterminal::NtBlock(block) => block.tokens_mut(), + Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) => None, + } + } +} + +/// A trait for AST nodes having (or not having) attributes. +pub trait HasAttrs { + /// This is `true` if this `HasAttrs` might support 'custom' (proc-macro) inner + /// attributes. Attributes like `#![cfg]` and `#![cfg_attr]` are not + /// considered 'custom' attributes. + /// + /// If this is `false`, then this `HasAttrs` definitely does + /// not support 'custom' inner attributes, which enables some optimizations + /// during token collection. + const SUPPORTS_CUSTOM_INNER_ATTRS: bool; + fn attrs(&self) -> &[Attribute]; + fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec)); +} + +macro_rules! impl_has_attrs { + (const SUPPORTS_CUSTOM_INNER_ATTRS: bool = $inner:literal, $($T:ty),+ $(,)?) => { + $( + impl HasAttrs for $T { + const SUPPORTS_CUSTOM_INNER_ATTRS: bool = $inner; + + fn attrs(&self) -> &[Attribute] { + &self.attrs + } + + fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec)) { + VecOrAttrVec::visit(&mut self.attrs, f) + } + } + )+ + }; +} + +macro_rules! impl_has_attrs_none { + ($($T:ty),+ $(,)?) => { + $( + impl HasAttrs for $T { + const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false; + fn attrs(&self) -> &[Attribute] { + &[] + } + fn visit_attrs(&mut self, _f: impl FnOnce(&mut Vec)) {} + } + )+ + }; +} + +impl_has_attrs!( + const SUPPORTS_CUSTOM_INNER_ATTRS: bool = true, + AssocItem, + ForeignItem, + Item, +); +impl_has_attrs!( + const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false, + Arm, + Crate, + Expr, + ExprField, + FieldDef, + GenericParam, + Param, + PatField, + Variant, +); +impl_has_attrs_none!(Attribute, AttrItem, Block, Pat, Path, Ty, Visibility); + +impl> HasAttrs for T { + const SUPPORTS_CUSTOM_INNER_ATTRS: bool = T::Target::SUPPORTS_CUSTOM_INNER_ATTRS; + fn attrs(&self) -> &[Attribute] { + self.ast_deref().attrs() + } + fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec)) { + self.ast_deref_mut().visit_attrs(f) + } +} + +impl HasAttrs for Option { + const SUPPORTS_CUSTOM_INNER_ATTRS: bool = T::SUPPORTS_CUSTOM_INNER_ATTRS; + fn attrs(&self) -> &[Attribute] { + self.as_ref().map(|inner| inner.attrs()).unwrap_or(&[]) + } + fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec)) { + if let Some(inner) = self.as_mut() { + inner.visit_attrs(f); + } + } +} + +impl HasAttrs for StmtKind { + // This might be a `StmtKind::Item`, which contains + // an item that supports inner attrs. + const SUPPORTS_CUSTOM_INNER_ATTRS: bool = true; + + fn attrs(&self) -> &[Attribute] { + match self { + StmtKind::Local(local) => &local.attrs, + StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.attrs(), + StmtKind::Item(item) => item.attrs(), + StmtKind::Empty => &[], + StmtKind::MacCall(mac) => &mac.attrs, + } + } + + fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec)) { + match self { + StmtKind::Local(local) => visit_attrvec(&mut local.attrs, f), + StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.visit_attrs(f), + StmtKind::Item(item) => item.visit_attrs(f), + StmtKind::Empty => {} + StmtKind::MacCall(mac) => visit_attrvec(&mut mac.attrs, f), + } + } +} + +impl HasAttrs for Stmt { + const SUPPORTS_CUSTOM_INNER_ATTRS: bool = StmtKind::SUPPORTS_CUSTOM_INNER_ATTRS; + fn attrs(&self) -> &[Attribute] { + self.kind.attrs() + } + fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec)) { + self.kind.visit_attrs(f); + } +} + +/// Helper trait for the impls above. Abstracts over +/// the two types of attribute fields that AST nodes +/// may have (`Vec` or `AttrVec`). +trait VecOrAttrVec { + fn visit(&mut self, f: impl FnOnce(&mut Vec)); +} + +impl VecOrAttrVec for Vec { + fn visit(&mut self, f: impl FnOnce(&mut Vec)) { + f(self) + } +} + +impl VecOrAttrVec for AttrVec { + fn visit(&mut self, f: impl FnOnce(&mut Vec)) { + visit_attrvec(self, f) + } +} + +fn visit_attrvec(attrs: &mut AttrVec, f: impl FnOnce(&mut Vec)) { + crate::mut_visit::visit_clobber(attrs, |attrs| { + let mut vec = attrs.into(); + f(&mut vec); + vec.into() + }); +} + +/// A newtype around an AST node that implements the traits above if the node implements them. +pub struct AstNodeWrapper { + pub wrapped: Wrapped, + pub tag: PhantomData, +} + +impl AstNodeWrapper { + pub fn new(wrapped: Wrapped, _tag: Tag) -> AstNodeWrapper { + AstNodeWrapper { wrapped, tag: Default::default() } + } +} + +impl AstDeref for AstNodeWrapper { + type Target = Wrapped; + fn ast_deref(&self) -> &Self::Target { + &self.wrapped + } + fn ast_deref_mut(&mut self) -> &mut Self::Target { + &mut self.wrapped + } +} + +impl fmt::Debug for AstNodeWrapper { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("AstNodeWrapper") + .field("wrapped", &self.wrapped) + .field("tag", &self.tag) + .finish() + } +} diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index a7c23dbb79c..12467169192 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -8,6 +8,7 @@ html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", test(attr(deny(warnings))) )] +#![feature(associated_type_bounds)] #![feature(box_patterns)] #![feature(const_default_impls)] #![feature(const_trait_impl)] @@ -16,6 +17,7 @@ #![feature(label_break_value)] #![feature(let_chains)] #![feature(min_specialization)] +#![feature(negative_impls)] #![feature(nll)] #![feature(slice_internals)] #![feature(stmt_expr_attributes)] @@ -33,7 +35,7 @@ pub mod util { } pub mod ast; -pub mod ast_like; +pub mod ast_traits; pub mod attr; pub mod entry; pub mod expand; @@ -45,7 +47,7 @@ pub mod util { pub mod visit; pub use self::ast::*; -pub use self::ast_like::{AstLike, AstLikeWrapper}; +pub use self::ast_traits::{AstDeref, AstNodeWrapper, HasAttrs, HasNodeId, HasSpan, HasTokens}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; diff --git a/compiler/rustc_ast_pretty/src/lib.rs b/compiler/rustc_ast_pretty/src/lib.rs index 517ab30b2a4..95beccbb728 100644 --- a/compiler/rustc_ast_pretty/src/lib.rs +++ b/compiler/rustc_ast_pretty/src/lib.rs @@ -1,5 +1,7 @@ +#![feature(associated_type_bounds)] #![feature(crate_visibility_modifier)] #![feature(box_patterns)] +#![feature(with_negative_coherence)] #![recursion_limit = "256"] mod helpers; diff --git a/compiler/rustc_ast_pretty/src/pprust/mod.rs b/compiler/rustc_ast_pretty/src/pprust/mod.rs index ac9e7d06c4e..d2e2fd520cd 100644 --- a/compiler/rustc_ast_pretty/src/pprust/mod.rs +++ b/compiler/rustc_ast_pretty/src/pprust/mod.rs @@ -4,12 +4,42 @@ pub mod state; pub use state::{print_crate, AnnNode, Comments, PpAnn, PrintState, State}; -use rustc_ast as ast; use rustc_ast::token::{Nonterminal, Token, TokenKind}; use rustc_ast::tokenstream::{TokenStream, TokenTree}; +use rustc_ast::{self as ast, AstDeref}; use std::borrow::Cow; +pub trait AstPrettyPrint { + fn pretty_print(&self) -> String; +} + +impl> AstPrettyPrint for T { + fn pretty_print(&self) -> String { + self.ast_deref().pretty_print() + } +} + +macro_rules! impl_ast_pretty_print { + ($($T:ty => $method:ident),+ $(,)?) => { + $( + impl AstPrettyPrint for $T { + fn pretty_print(&self) -> String { + State::new().$method(self) + } + } + )+ + }; +} + +impl_ast_pretty_print! { + ast::Item => item_to_string, + ast::AssocItem => assoc_item_to_string, + ast::ForeignItem => foreign_item_to_string, + ast::Expr => expr_to_string, + ast::Stmt => stmt_to_string, +} + pub fn nonterminal_to_string(nt: &Nonterminal) -> String { State::new().nonterminal_to_string(nt) } diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index c02cdc29561..f520b541124 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -858,6 +858,14 @@ fn item_to_string(&self, i: &ast::Item) -> String { Self::to_string(|s| s.print_item(i)) } + fn assoc_item_to_string(&self, i: &ast::AssocItem) -> String { + Self::to_string(|s| s.print_assoc_item(i)) + } + + fn foreign_item_to_string(&self, i: &ast::ForeignItem) -> String { + Self::to_string(|s| s.print_foreign_item(i)) + } + fn generic_params_to_string(&self, generic_params: &[ast::GenericParam]) -> String { Self::to_string(|s| s.print_generic_params(generic_params)) } diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 2a35dd1006e..23c5a92e352 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -19,7 +19,7 @@ fn print_foreign_mod(&mut self, nmod: &ast::ForeignMod, attrs: &[ast::Attribute] } } - fn print_foreign_item(&mut self, item: &ast::ForeignItem) { + crate fn print_foreign_item(&mut self, item: &ast::ForeignItem) { let ast::Item { id, span, ident, ref attrs, ref kind, ref vis, tokens: _ } = *item; self.ann.pre(self, AnnNode::SubItem(id)); self.hardbreak_if_not_bol(); @@ -496,7 +496,7 @@ fn print_struct( } } - fn print_assoc_item(&mut self, item: &ast::AssocItem) { + crate fn print_assoc_item(&mut self, item: &ast::AssocItem) { let ast::Item { id, span, ident, ref attrs, ref kind, ref vis, tokens: _ } = *item; self.ann.pre(self, AnnNode::SubItem(id)); self.hardbreak_if_not_bol(); diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index 7637bf7edc8..4278fedfee9 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -7,7 +7,7 @@ use rustc_ast::visit::Visitor; use rustc_ast::NodeId; use rustc_ast::{mut_visit, visit}; -use rustc_ast::{AstLike, Attribute}; +use rustc_ast::{Attribute, HasAttrs, HasTokens}; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_expand::config::StripUnconfigured; use rustc_expand::configure; @@ -125,7 +125,7 @@ fn visit_attribute(&mut self, attr: &'ast Attribute) { } impl CfgEval<'_, '_> { - fn configure(&mut self, node: T) -> Option { + fn configure(&mut self, node: T) -> Option { self.cfg.configure(node) } @@ -173,13 +173,8 @@ fn configure_annotatable(&mut self, mut annotatable: Annotatable) -> Option unreachable!(), }; - let nt = annotatable.into_nonterminal(); - let mut orig_tokens = rustc_parse::nt_to_tokenstream( - &nt, - &self.cfg.sess.parse_sess, - CanSynthesizeMissingTokens::No, - ); + let mut orig_tokens = annotatable.to_tokens(&self.cfg.sess.parse_sess); // 'Flatten' all nonterminals (i.e. `TokenKind::Interpolated`) // to `None`-delimited groups containing the corresponding tokens. This diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 2b30ec601a0..48b5502c20f 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -6,14 +6,14 @@ use rustc_ast::token::{self, Nonterminal}; use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream}; use rustc_ast::visit::{AssocCtxt, Visitor}; -use rustc_ast::{self as ast, AstLike, Attribute, Item, NodeId, PatKind}; +use rustc_ast::{self as ast, Attribute, HasAttrs, Item, NodeId, PatKind}; use rustc_attr::{self as attr, Deprecation, Stability}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::{self, Lrc}; use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, PResult}; use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT; use rustc_lint_defs::BuiltinLintDiagnostics; -use rustc_parse::{self, nt_to_tokenstream, parser, MACRO_ARGUMENTS}; +use rustc_parse::{self, parser, to_token_stream, MACRO_ARGUMENTS}; use rustc_session::{parse::ParseSess, Limit, Session}; use rustc_span::def_id::{CrateNum, DefId, LocalDefId}; use rustc_span::edition::Edition; @@ -109,17 +109,20 @@ pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) { } } - pub fn into_nonterminal(self) -> Nonterminal { + pub fn to_tokens(&self, sess: &ParseSess) -> TokenStream { match self { - Annotatable::Item(item) => token::NtItem(item), - Annotatable::TraitItem(item) | Annotatable::ImplItem(item) => { - token::NtItem(P(item.and_then(ast::AssocItem::into_item))) + Annotatable::Item(node) => to_token_stream(node, sess, CanSynthesizeMissingTokens::No), + Annotatable::TraitItem(node) | Annotatable::ImplItem(node) => { + to_token_stream(node, sess, CanSynthesizeMissingTokens::No) } - Annotatable::ForeignItem(item) => { - token::NtItem(P(item.and_then(ast::ForeignItem::into_item))) + Annotatable::ForeignItem(node) => { + to_token_stream(node, sess, CanSynthesizeMissingTokens::No) } - Annotatable::Stmt(stmt) => token::NtStmt(stmt), - Annotatable::Expr(expr) => token::NtExpr(expr), + Annotatable::Stmt(node) => { + assert!(!matches!(node.kind, ast::StmtKind::Empty)); + to_token_stream(node, sess, CanSynthesizeMissingTokens::No) + } + Annotatable::Expr(node) => to_token_stream(node, sess, CanSynthesizeMissingTokens::No), Annotatable::Arm(..) | Annotatable::ExprField(..) | Annotatable::PatField(..) @@ -131,10 +134,6 @@ pub fn into_nonterminal(self) -> Nonterminal { } } - crate fn into_tokens(self, sess: &ParseSess) -> TokenStream { - nt_to_tokenstream(&self.into_nonterminal(), sess, CanSynthesizeMissingTokens::No) - } - pub fn expect_item(self) -> P { match self { Annotatable::Item(i) => i, @@ -1380,16 +1379,7 @@ pub fn parse_macro_name_and_helper_attrs( /// asserts in old versions of those crates and their wide use in the ecosystem. /// See issue #73345 for more details. /// FIXME(#73933): Remove this eventually. -pub(crate) fn pretty_printing_compatibility_hack(nt: &Nonterminal, sess: &ParseSess) -> bool { - let item = match nt { - Nonterminal::NtItem(item) => item, - Nonterminal::NtStmt(stmt) => match &stmt.kind { - ast::StmtKind::Item(item) => item, - _ => return false, - }, - _ => return false, - }; - +fn pretty_printing_compatibility_hack(item: &Item, sess: &ParseSess) -> bool { let name = item.ident.name; if name == sym::ProceduralMasqueradeDummyType { if let ast::ItemKind::Enum(enum_def, _) = &item.kind { @@ -1411,3 +1401,27 @@ pub(crate) fn pretty_printing_compatibility_hack(nt: &Nonterminal, sess: &ParseS } false } + +pub(crate) fn ann_pretty_printing_compatibility_hack(ann: &Annotatable, sess: &ParseSess) -> bool { + let item = match ann { + Annotatable::Item(item) => item, + Annotatable::Stmt(stmt) => match &stmt.kind { + ast::StmtKind::Item(item) => item, + _ => return false, + }, + _ => return false, + }; + pretty_printing_compatibility_hack(item, sess) +} + +pub(crate) fn nt_pretty_printing_compatibility_hack(nt: &Nonterminal, sess: &ParseSess) -> bool { + let item = match nt { + Nonterminal::NtItem(item) => item, + Nonterminal::NtStmt(stmt) => match &stmt.kind { + ast::StmtKind::Item(item) => item, + _ => return false, + }, + _ => return false, + }; + pretty_printing_compatibility_hack(item, sess) +} diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index c91125105d7..0b8cb07a64a 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -6,7 +6,7 @@ use rustc_ast::tokenstream::{DelimSpan, Spacing}; use rustc_ast::tokenstream::{LazyTokenStream, TokenTree}; use rustc_ast::NodeId; -use rustc_ast::{self as ast, AstLike, AttrStyle, Attribute, MetaItem}; +use rustc_ast::{self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem}; use rustc_attr as attr; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::map_in_place::MapInPlace; @@ -246,7 +246,7 @@ macro_rules! configure { } impl<'a> StripUnconfigured<'a> { - pub fn configure(&self, mut node: T) -> Option { + pub fn configure(&self, mut node: T) -> Option { self.process_cfg_attrs(&mut node); if self.in_cfg(node.attrs()) { self.try_configure_tokens(&mut node); @@ -256,7 +256,7 @@ pub fn configure(&self, mut node: T) -> Option { } } - fn try_configure_tokens(&self, node: &mut T) { + fn try_configure_tokens(&self, node: &mut T) { if self.config_tokens { if let Some(Some(tokens)) = node.tokens_mut() { let attr_annotated_tokens = tokens.create_token_stream(); @@ -330,7 +330,7 @@ fn can_skip(stream: &AttrAnnotatedTokenStream) -> bool { /// Gives compiler warnings if any `cfg_attr` does not contain any /// attributes and is in the original source code. Gives compiler errors if /// the syntax of any `cfg_attr` is incorrect. - fn process_cfg_attrs(&self, node: &mut T) { + fn process_cfg_attrs(&self, node: &mut T) { node.visit_attrs(|attrs| { attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr)); }); diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 5bd89f3f42f..a390e7a466d 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -11,7 +11,8 @@ use rustc_ast::token::{self, Delimiter}; use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{self, AssocCtxt, Visitor}; -use rustc_ast::{AssocItemKind, AstLike, AstLikeWrapper, AttrStyle, ExprKind, ForeignItemKind}; +use rustc_ast::{AssocItemKind, AstNodeWrapper, AttrStyle, ExprKind, ForeignItemKind}; +use rustc_ast::{HasAttrs, HasNodeId}; use rustc_ast::{Inline, ItemKind, MacArgs, MacStmtStyle, MetaItemKind, ModKind}; use rustc_ast::{NestedMetaItem, NodeId, PatKind, StmtKind, TyKind}; use rustc_ast_pretty::pprust; @@ -678,12 +679,9 @@ fn expand_invoc( ) ) => { - rustc_parse::fake_token_stream( - &self.cx.sess.parse_sess, - &item.into_nonterminal(), - ) + rustc_parse::fake_token_stream(&self.cx.sess.parse_sess, item_inner) } - _ => item.into_tokens(&self.cx.sess.parse_sess), + _ => item.to_tokens(&self.cx.sess.parse_sess), }; let attr_item = attr.unwrap_normal_item(); if let MacArgs::Eq(..) = attr_item.args { @@ -998,13 +996,12 @@ enum AddSemicolon { /// A trait implemented for all `AstFragment` nodes and providing all pieces /// of functionality used by `InvocationCollector`. -trait InvocationCollectorNode: AstLike { +trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized { type OutputTy = SmallVec<[Self; 1]>; type AttrsTy: Deref = Vec; const KIND: AstFragmentKind; fn to_annotatable(self) -> Annotatable; fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy; - fn id(&mut self) -> &mut NodeId; fn descr() -> &'static str { unreachable!() } @@ -1040,9 +1037,6 @@ fn to_annotatable(self) -> Annotatable { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_items() } - fn id(&mut self) -> &mut NodeId { - &mut self.id - } fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { noop_flat_map_item(self, visitor) } @@ -1142,7 +1136,7 @@ fn wrap_flat_map_node_noop_flat_map( } struct TraitItemTag; -impl InvocationCollectorNode for AstLikeWrapper, TraitItemTag> { +impl InvocationCollectorNode for AstNodeWrapper, TraitItemTag> { type OutputTy = SmallVec<[P; 1]>; const KIND: AstFragmentKind = AstFragmentKind::TraitItems; fn to_annotatable(self) -> Annotatable { @@ -1151,9 +1145,6 @@ fn to_annotatable(self) -> Annotatable { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_trait_items() } - fn id(&mut self) -> &mut NodeId { - &mut self.wrapped.id - } fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { noop_flat_map_assoc_item(self.wrapped, visitor) } @@ -1170,7 +1161,7 @@ fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) { } struct ImplItemTag; -impl InvocationCollectorNode for AstLikeWrapper, ImplItemTag> { +impl InvocationCollectorNode for AstNodeWrapper, ImplItemTag> { type OutputTy = SmallVec<[P; 1]>; const KIND: AstFragmentKind = AstFragmentKind::ImplItems; fn to_annotatable(self) -> Annotatable { @@ -1179,9 +1170,6 @@ fn to_annotatable(self) -> Annotatable { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_impl_items() } - fn id(&mut self) -> &mut NodeId { - &mut self.wrapped.id - } fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { noop_flat_map_assoc_item(self.wrapped, visitor) } @@ -1205,9 +1193,6 @@ fn to_annotatable(self) -> Annotatable { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_foreign_items() } - fn id(&mut self) -> &mut NodeId { - &mut self.id - } fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { noop_flat_map_foreign_item(self, visitor) } @@ -1231,9 +1216,6 @@ fn to_annotatable(self) -> Annotatable { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_variants() } - fn id(&mut self) -> &mut NodeId { - &mut self.id - } fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { noop_flat_map_variant(self, visitor) } @@ -1247,9 +1229,6 @@ fn to_annotatable(self) -> Annotatable { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_field_defs() } - fn id(&mut self) -> &mut NodeId { - &mut self.id - } fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { noop_flat_map_field_def(self, visitor) } @@ -1263,9 +1242,6 @@ fn to_annotatable(self) -> Annotatable { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_pat_fields() } - fn id(&mut self) -> &mut NodeId { - &mut self.id - } fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { noop_flat_map_pat_field(self, visitor) } @@ -1279,9 +1255,6 @@ fn to_annotatable(self) -> Annotatable { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_expr_fields() } - fn id(&mut self) -> &mut NodeId { - &mut self.id - } fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { noop_flat_map_expr_field(self, visitor) } @@ -1295,9 +1268,6 @@ fn to_annotatable(self) -> Annotatable { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_params() } - fn id(&mut self) -> &mut NodeId { - &mut self.id - } fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { noop_flat_map_param(self, visitor) } @@ -1311,9 +1281,6 @@ fn to_annotatable(self) -> Annotatable { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_generic_params() } - fn id(&mut self) -> &mut NodeId { - &mut self.id - } fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { noop_flat_map_generic_param(self, visitor) } @@ -1327,9 +1294,6 @@ fn to_annotatable(self) -> Annotatable { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_arms() } - fn id(&mut self) -> &mut NodeId { - &mut self.id - } fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { noop_flat_map_arm(self, visitor) } @@ -1344,9 +1308,6 @@ fn to_annotatable(self) -> Annotatable { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_stmts() } - fn id(&mut self) -> &mut NodeId { - &mut self.id - } fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { noop_flat_map_stmt(self, visitor) } @@ -1403,9 +1364,6 @@ fn to_annotatable(self) -> Annotatable { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_crate() } - fn id(&mut self) -> &mut NodeId { - &mut self.id - } fn noop_visit(&mut self, visitor: &mut V) { noop_visit_crate(self, visitor) } @@ -1420,9 +1378,6 @@ fn to_annotatable(self) -> Annotatable { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_ty() } - fn id(&mut self) -> &mut NodeId { - &mut self.id - } fn noop_visit(&mut self, visitor: &mut V) { noop_visit_ty(self, visitor) } @@ -1447,9 +1402,6 @@ fn to_annotatable(self) -> Annotatable { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_pat() } - fn id(&mut self) -> &mut NodeId { - &mut self.id - } fn noop_visit(&mut self, visitor: &mut V) { noop_visit_pat(self, visitor) } @@ -1475,9 +1427,6 @@ fn to_annotatable(self) -> Annotatable { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_expr() } - fn id(&mut self) -> &mut NodeId { - &mut self.id - } fn descr() -> &'static str { "an expression" } @@ -1497,7 +1446,7 @@ fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) { } struct OptExprTag; -impl InvocationCollectorNode for AstLikeWrapper, OptExprTag> { +impl InvocationCollectorNode for AstNodeWrapper, OptExprTag> { type OutputTy = Option>; type AttrsTy = ast::AttrVec; const KIND: AstFragmentKind = AstFragmentKind::OptExpr; @@ -1507,9 +1456,6 @@ fn to_annotatable(self) -> Annotatable { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_opt_expr() } - fn id(&mut self) -> &mut NodeId { - &mut self.wrapped.id - } fn noop_flat_map(mut self, visitor: &mut V) -> Self::OutputTy { noop_visit_expr(&mut self.wrapped, visitor); Some(self.wrapped) @@ -1584,7 +1530,7 @@ fn collect_attr( /// legacy derive helpers (helpers written before derives that introduce them). fn take_first_attr( &self, - item: &mut impl AstLike, + item: &mut impl HasAttrs, ) -> Option<(ast::Attribute, usize, Vec)> { let mut attr = None; @@ -1680,7 +1626,7 @@ fn check_attributes(&self, attrs: &[ast::Attribute], call: &ast::MacCall) { fn expand_cfg_true( &mut self, - node: &mut impl AstLike, + node: &mut impl HasAttrs, attr: ast::Attribute, pos: usize, ) -> bool { @@ -1695,7 +1641,7 @@ fn expand_cfg_true( res } - fn expand_cfg_attr(&self, node: &mut impl AstLike, attr: ast::Attribute, pos: usize) { + fn expand_cfg_attr(&self, node: &mut impl HasAttrs, attr: ast::Attribute, pos: usize) { node.visit_attrs(|attrs| { attrs.splice(pos..pos, self.cfg().expand_cfg_attr(attr, false)); }); @@ -1733,7 +1679,7 @@ fn flat_map_node>( } None => { match Node::wrap_flat_map_node_noop_flat_map(node, self, |mut node, this| { - assign_id!(this, node.id(), || node.noop_flat_map(this)) + assign_id!(this, node.node_id_mut(), || node.noop_flat_map(this)) }) { Ok(output) => output, Err(returned_node) => { @@ -1781,7 +1727,7 @@ fn visit_node + DummyAstNode>( }) } None => { - assign_id!(self, node.id(), || node.noop_visit(self)) + assign_id!(self, node.node_id_mut(), || node.noop_visit(self)) } }; } @@ -1794,11 +1740,11 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { } fn flat_map_trait_item(&mut self, node: P) -> SmallVec<[P; 1]> { - self.flat_map_node(AstLikeWrapper::new(node, TraitItemTag)) + self.flat_map_node(AstNodeWrapper::new(node, TraitItemTag)) } fn flat_map_impl_item(&mut self, node: P) -> SmallVec<[P; 1]> { - self.flat_map_node(AstLikeWrapper::new(node, ImplItemTag)) + self.flat_map_node(AstNodeWrapper::new(node, ImplItemTag)) } fn flat_map_foreign_item( @@ -1889,7 +1835,7 @@ fn visit_expr(&mut self, node: &mut P) { } fn filter_map_expr(&mut self, node: P) -> Option> { - self.flat_map_node(AstLikeWrapper::new(node, OptExprTag)) + self.flat_map_node(AstNodeWrapper::new(node, OptExprTag)) } fn visit_block(&mut self, node: &mut P) { diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs index 8e1966a0711..6c74d462fb8 100644 --- a/compiler/rustc_expand/src/proc_macro.rs +++ b/compiler/rustc_expand/src/proc_macro.rs @@ -4,10 +4,9 @@ use rustc_ast as ast; use rustc_ast::ptr::P; use rustc_ast::token; -use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream, TokenTree}; +use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_data_structures::sync::Lrc; use rustc_errors::ErrorGuaranteed; -use rustc_parse::nt_to_tokenstream; use rustc_parse::parser::ForceCollect; use rustc_span::profiling::SpannedEventArgRecorder; use rustc_span::{Span, DUMMY_SP}; @@ -87,25 +86,17 @@ fn expand( ) -> ExpandResult, Annotatable> { // We need special handling for statement items // (e.g. `fn foo() { #[derive(Debug)] struct Bar; }`) - let mut is_stmt = false; - let item = match item { - Annotatable::Item(item) => token::NtItem(item), - Annotatable::Stmt(stmt) => { - is_stmt = true; - assert!(stmt.is_item()); - - // A proc macro can't observe the fact that we're passing - // them an `NtStmt` - it can only see the underlying tokens - // of the wrapped item - token::NtStmt(stmt) - } - _ => unreachable!(), - }; - let input = if crate::base::pretty_printing_compatibility_hack(&item, &ecx.sess.parse_sess) - { - TokenTree::token(token::Interpolated(Lrc::new(item)), DUMMY_SP).into() + let is_stmt = matches!(item, Annotatable::Stmt(..)); + let hack = crate::base::ann_pretty_printing_compatibility_hack(&item, &ecx.sess.parse_sess); + let input = if hack { + let nt = match item { + Annotatable::Item(item) => token::NtItem(item), + Annotatable::Stmt(stmt) => token::NtStmt(stmt), + _ => unreachable!(), + }; + TokenTree::token(token::Interpolated(Lrc::new(nt)), DUMMY_SP).into() } else { - nt_to_tokenstream(&item, &ecx.sess.parse_sess, CanSynthesizeMissingTokens::No) + item.to_tokens(&ecx.sess.parse_sess) }; let stream = { diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index b7230cec3e4..c0c786e4712 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -184,7 +184,7 @@ macro_rules! op { delimiter: pm::Delimiter::None, stream, span: DelimSpan::from_single(span), - flatten: crate::base::pretty_printing_compatibility_hack(&nt, rustc.sess()), + flatten: crate::base::nt_pretty_printing_compatibility_hack(&nt, rustc.sess()), }) } diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index b4262f184c8..3ea68aea3cb 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -18,8 +18,7 @@ use crate::passes::{EarlyLintPass, EarlyLintPassObject}; use rustc_ast::ptr::P; use rustc_ast::visit::{self as ast_visit, Visitor}; -use rustc_ast::AstLike; -use rustc_ast::{self as ast, walk_list}; +use rustc_ast::{self as ast, walk_list, HasAttrs}; use rustc_middle::ty::RegisteredTools; use rustc_session::lint::{BufferedEarlyLint, LintBuffer, LintPass}; use rustc_session::Session; diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 28c2a63db27..423cddd88ee 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -17,17 +17,17 @@ use rustc_ast::tokenstream::{self, AttributesData, CanSynthesizeMissingTokens, LazyTokenStream}; use rustc_ast::tokenstream::{AttrAnnotatedTokenStream, AttrAnnotatedTokenTree}; use rustc_ast::tokenstream::{Spacing, TokenStream}; -use rustc_ast::AstLike; use rustc_ast::Attribute; use rustc_ast::{AttrItem, MetaItem}; -use rustc_ast_pretty::pprust; +use rustc_ast::{HasAttrs, HasSpan, HasTokens}; +use rustc_ast_pretty::pprust::{self, AstPrettyPrint}; use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, Diagnostic, FatalError, Level, PResult}; use rustc_session::parse::ParseSess; use rustc_span::{FileName, SourceFile, Span}; +use std::fmt; use std::path::Path; -use std::str; pub const MACRO_ARGUMENTS: Option<&str> = Some("macro arguments"); @@ -244,6 +244,20 @@ pub fn parse_in<'a, T>( // NOTE(Centril): The following probably shouldn't be here but it acknowledges the // fact that architecturally, we are using parsing (read on below to understand why). +pub fn to_token_stream( + node: &(impl HasAttrs + HasSpan + HasTokens + AstPrettyPrint + fmt::Debug), + sess: &ParseSess, + synthesize_tokens: CanSynthesizeMissingTokens, +) -> TokenStream { + if let Some(tokens) = prepend_attrs(&node.attrs(), node.tokens()) { + return tokens; + } else if matches!(synthesize_tokens, CanSynthesizeMissingTokens::Yes) { + return fake_token_stream(sess, node); + } else { + panic!("Missing tokens for nt {:?} at {:?}: {:?}", node, node.span(), node.pretty_print()); + } +} + pub fn nt_to_tokenstream( nt: &Nonterminal, sess: &ParseSess, @@ -298,7 +312,7 @@ pub fn nt_to_tokenstream( if let Some(tokens) = tokens { return tokens; } else if matches!(synthesize_tokens, CanSynthesizeMissingTokens::Yes) { - return fake_token_stream(sess, nt); + return nt_fake_token_stream(sess, nt); } else { panic!( "Missing tokens for nt {:?} at {:?}: {:?}", @@ -322,7 +336,13 @@ fn prepend_attrs(attrs: &[Attribute], tokens: Option<&LazyTokenStream>) -> Optio Some(wrapped.to_tokenstream()) } -pub fn fake_token_stream(sess: &ParseSess, nt: &Nonterminal) -> TokenStream { +pub fn fake_token_stream(sess: &ParseSess, node: &(impl AstPrettyPrint + HasSpan)) -> TokenStream { + let source = node.pretty_print(); + let filename = FileName::macro_expansion_source_code(&source); + parse_stream_from_source_str(filename, source, sess, Some(node.span())) +} + +fn nt_fake_token_stream(sess: &ParseSess, nt: &Nonterminal) -> TokenStream { let source = pprust::nonterminal_to_string(nt); let filename = FileName::macro_expansion_source_code(&source); parse_stream_from_source_str(filename, source, sess, Some(nt.span())) diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 66db5bf9d7c..6c750ff428f 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -3,7 +3,7 @@ use rustc_ast::tokenstream::{AttrAnnotatedTokenStream, AttributesData, CreateTokenStream}; use rustc_ast::tokenstream::{AttrAnnotatedTokenTree, DelimSpan, LazyTokenStream, Spacing}; use rustc_ast::{self as ast}; -use rustc_ast::{AstLike, AttrVec, Attribute}; +use rustc_ast::{AttrVec, Attribute, HasAttrs, HasTokens}; use rustc_errors::PResult; use rustc_span::{sym, Span}; @@ -192,7 +192,7 @@ impl<'a> Parser<'a> { /// This restriction shouldn't be an issue in practice, /// since this function is used to record the tokens for /// a parsed AST item, which always has matching delimiters. - pub fn collect_tokens_trailing_token( + pub fn collect_tokens_trailing_token( &mut self, attrs: AttrWrapper, force_collect: ForceCollect, diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 63112f23605..f32ee9fc978 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -25,9 +25,9 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_ast::AttrId; use rustc_ast::DUMMY_NODE_ID; -use rustc_ast::{self as ast, AnonConst, AstLike, AttrStyle, AttrVec, Const, CrateSugar, Extern}; +use rustc_ast::{self as ast, AnonConst, AttrStyle, AttrVec, Const, CrateSugar, Extern}; use rustc_ast::{Async, Expr, ExprKind, MacArgs, MacArgsEq, MacDelimiter, Mutability, StrLit}; -use rustc_ast::{Unsafe, Visibility, VisibilityKind}; +use rustc_ast::{HasAttrs, HasTokens, Unsafe, Visibility, VisibilityKind}; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; use rustc_errors::PResult; @@ -1389,7 +1389,7 @@ fn parse_abi(&mut self) -> Option { } } - pub fn collect_tokens_no_attrs( + pub fn collect_tokens_no_attrs( &mut self, f: impl FnOnce(&mut Self) -> PResult<'a, R>, ) -> PResult<'a, R> { diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 6974f318f94..e215b6872bf 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -1,6 +1,6 @@ use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, NonterminalKind, Token}; -use rustc_ast::AstLike; +use rustc_ast::HasTokens; use rustc_ast_pretty::pprust; use rustc_errors::PResult; use rustc_span::symbol::{kw, Ident}; diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index ac693597662..56ebac0953b 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -13,10 +13,8 @@ use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, TokenKind}; use rustc_ast::util::classify; -use rustc_ast::{ - AstLike, AttrStyle, AttrVec, Attribute, LocalKind, MacCall, MacCallStmt, MacStmtStyle, -}; -use rustc_ast::{Block, BlockCheckMode, Expr, ExprKind, Local, Stmt}; +use rustc_ast::{AttrStyle, AttrVec, Attribute, LocalKind, MacCall, MacCallStmt, MacStmtStyle}; +use rustc_ast::{Block, BlockCheckMode, Expr, ExprKind, HasAttrs, Local, Stmt}; use rustc_ast::{StmtKind, DUMMY_NODE_ID}; use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult}; use rustc_span::source_map::{BytePos, Span}; diff --git a/src/tools/rustfmt/src/attr.rs b/src/tools/rustfmt/src/attr.rs index befe12ae2c4..41ba9a847e6 100644 --- a/src/tools/rustfmt/src/attr.rs +++ b/src/tools/rustfmt/src/attr.rs @@ -1,7 +1,7 @@ //! Format attributes and meta items. use rustc_ast::ast; -use rustc_ast::AstLike; +use rustc_ast::HasAttrs; use rustc_span::{symbol::sym, Span, Symbol}; use self::doc_comment::DocCommentFormatter; diff --git a/src/tools/rustfmt/src/formatting.rs b/src/tools/rustfmt/src/formatting.rs index ca93955a549..ebadf3dd598 100644 --- a/src/tools/rustfmt/src/formatting.rs +++ b/src/tools/rustfmt/src/formatting.rs @@ -5,7 +5,6 @@ use std::time::{Duration, Instant}; use rustc_ast::ast; -use rustc_ast::AstLike; use rustc_span::Span; use self::newline_style::apply_newline_style; diff --git a/src/tools/rustfmt/src/modules.rs b/src/tools/rustfmt/src/modules.rs index a65dc66f797..81da724329f 100644 --- a/src/tools/rustfmt/src/modules.rs +++ b/src/tools/rustfmt/src/modules.rs @@ -4,7 +4,6 @@ use rustc_ast::ast; use rustc_ast::visit::Visitor; -use rustc_ast::AstLike; use rustc_span::symbol::{self, sym, Symbol}; use rustc_span::Span; use thiserror::Error; @@ -50,19 +49,10 @@ pub(crate) fn new( ast_mod_kind, } } -} -impl<'a> AstLike for Module<'a> { - const SUPPORTS_CUSTOM_INNER_ATTRS: bool = true; - fn attrs(&self) -> &[ast::Attribute] { + pub(crate) fn attrs(&self) -> &[ast::Attribute] { &self.inner_attr } - fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec)) { - f(&mut self.inner_attr) - } - fn tokens_mut(&mut self) -> Option<&mut Option> { - unimplemented!() - } } /// Maps each module to the corresponding file. diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs index f04fb2e0446..9a0e0752c12 100644 --- a/src/tools/rustfmt/src/visitor.rs +++ b/src/tools/rustfmt/src/visitor.rs @@ -1,7 +1,7 @@ use std::cell::{Cell, RefCell}; use std::rc::Rc; -use rustc_ast::{ast, token::Delimiter, visit, AstLike}; +use rustc_ast::{ast, token::Delimiter, visit}; use rustc_data_structures::sync::Lrc; use rustc_span::{symbol, BytePos, Pos, Span};