ast: Introduce some traits to get AST node properties generically

And use them to avoid constructing some artificial `Nonterminal` tokens during expansion
This commit is contained in:
Vadim Petrochenkov 2022-05-01 20:58:24 +03:00
parent ee6eaabdd4
commit f2b7fa4847
24 changed files with 593 additions and 500 deletions

View File

@ -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 @@ impl Item {
}
}
impl<K: Into<ItemKind>> Item<K> {
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 {

View File

@ -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<Attribute>));
fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>>;
}
impl<T: AstLike + 'static> AstLike for P<T> {
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<Attribute>)) {
(**self).visit_attrs(f);
}
fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
(**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<Attribute>)) {
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<LazyTokenStream>> {
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<Attribute>)) {
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<Attribute>)) {
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<LazyTokenStream>> {
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<Attribute>)) {
self.kind.visit_attrs(f);
}
fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
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<Attribute>)) {}
fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
Some(match &mut self.kind {
AttrKind::Normal(_, tokens) => tokens,
kind @ AttrKind::DocComment(..) => {
panic!("Called tokens_mut on doc comment attr {:?}", kind)
}
})
}
}
impl<T: AstLike> AstLike for Option<T> {
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<Attribute>)) {
if let Some(inner) = self.as_mut() {
inner.visit_attrs(f);
}
}
fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
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<Attribute>` or `AttrVec`)
trait VecOrAttrVec {
fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>));
}
impl VecOrAttrVec for Vec<Attribute> {
fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
f(self)
}
}
impl VecOrAttrVec for AttrVec {
fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
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<Attribute>)) {
VecOrAttrVec::visit(&mut self.attrs, f)
}
fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
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<Attribute>)) {
VecOrAttrVec::visit(&mut self.attrs, f)
}
fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
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<Attribute>)) {}
fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
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<Wrapped, Tag> {
pub wrapped: Wrapped,
pub tag: PhantomData<Tag>,
}
impl<Wrapped, Tag> AstLikeWrapper<Wrapped, Tag> {
pub fn new(wrapped: Wrapped, _tag: Tag) -> AstLikeWrapper<Wrapped, Tag> {
AstLikeWrapper { wrapped, tag: Default::default() }
}
}
impl<Wrapped: fmt::Debug, Tag> fmt::Debug for AstLikeWrapper<Wrapped, Tag> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("AstLikeWrapper")
.field("wrapped", &self.wrapped)
.field("tag", &self.tag)
.finish()
}
}
impl<Wrapped: AstLike, Tag> AstLike for AstLikeWrapper<Wrapped, Tag> {
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<Attribute>)) {
self.wrapped.visit_attrs(f)
}
fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
self.wrapped.tokens_mut()
}
}

View File

@ -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<T> AstDeref for P<T> {
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<T: AstDeref<Target: HasNodeId>> 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<T: AstDeref<Target: HasSpan>> 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<LazyTokenStream>>;
}
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<LazyTokenStream>> {
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<LazyTokenStream>> {
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<T: AstDeref<Target: HasTokens>> HasTokens for T {
fn tokens(&self) -> Option<&LazyTokenStream> {
self.ast_deref().tokens()
}
fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
self.ast_deref_mut().tokens_mut()
}
}
impl<T: HasTokens> HasTokens for Option<T> {
fn tokens(&self) -> Option<&LazyTokenStream> {
self.as_ref().and_then(|inner| inner.tokens())
}
fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
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<LazyTokenStream>> {
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<LazyTokenStream>> {
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<LazyTokenStream>> {
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<LazyTokenStream>> {
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<Attribute>));
}
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<Attribute>)) {
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<Attribute>)) {}
}
)+
};
}
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<T: AstDeref<Target: HasAttrs>> 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<Attribute>)) {
self.ast_deref_mut().visit_attrs(f)
}
}
impl<T: HasAttrs> HasAttrs for Option<T> {
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<Attribute>)) {
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<Attribute>)) {
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<Attribute>)) {
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<Attribute>` or `AttrVec`).
trait VecOrAttrVec {
fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>));
}
impl VecOrAttrVec for Vec<Attribute> {
fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
f(self)
}
}
impl VecOrAttrVec for AttrVec {
fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
visit_attrvec(self, f)
}
}
fn visit_attrvec(attrs: &mut AttrVec, f: impl FnOnce(&mut Vec<Attribute>)) {
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<Wrapped, Tag> {
pub wrapped: Wrapped,
pub tag: PhantomData<Tag>,
}
impl<Wrapped, Tag> AstNodeWrapper<Wrapped, Tag> {
pub fn new(wrapped: Wrapped, _tag: Tag) -> AstNodeWrapper<Wrapped, Tag> {
AstNodeWrapper { wrapped, tag: Default::default() }
}
}
impl<Wrapped, Tag> AstDeref for AstNodeWrapper<Wrapped, Tag> {
type Target = Wrapped;
fn ast_deref(&self) -> &Self::Target {
&self.wrapped
}
fn ast_deref_mut(&mut self) -> &mut Self::Target {
&mut self.wrapped
}
}
impl<Wrapped: fmt::Debug, Tag> fmt::Debug for AstNodeWrapper<Wrapped, Tag> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("AstNodeWrapper")
.field("wrapped", &self.wrapped)
.field("tag", &self.tag)
.finish()
}
}

View File

@ -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 tokenstream;
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};

View File

@ -1,5 +1,7 @@
#![feature(associated_type_bounds)]
#![feature(crate_visibility_modifier)]
#![feature(box_patterns)]
#![feature(with_negative_coherence)]
#![recursion_limit = "256"]
mod helpers;

View File

@ -4,12 +4,42 @@ mod tests;
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<T: AstDeref<Target: AstPrettyPrint>> 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)
}

View File

@ -858,6 +858,14 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
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))
}

View File

@ -19,7 +19,7 @@ impl<'a> State<'a> {
}
}
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 @@ impl<'a> State<'a> {
}
}
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();

View File

@ -7,7 +7,7 @@ use rustc_ast::tokenstream::CanSynthesizeMissingTokens;
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 @@ impl<'ast> visit::Visitor<'ast> for CfgFinder {
}
impl CfgEval<'_, '_> {
fn configure<T: AstLike>(&mut self, node: T) -> Option<T> {
fn configure<T: HasAttrs + HasTokens>(&mut self, node: T) -> Option<T> {
self.cfg.configure(node)
}
@ -173,13 +173,8 @@ impl CfgEval<'_, '_> {
}
_ => 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

View File

@ -6,14 +6,14 @@ use rustc_ast::ptr::P;
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 @@ impl Annotatable {
}
}
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 @@ impl Annotatable {
}
}
crate fn into_tokens(self, sess: &ParseSess) -> TokenStream {
nt_to_tokenstream(&self.into_nonterminal(), sess, CanSynthesizeMissingTokens::No)
}
pub fn expect_item(self) -> P<ast::Item> {
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)
}

View File

@ -6,7 +6,7 @@ use rustc_ast::tokenstream::{AttrAnnotatedTokenStream, AttrAnnotatedTokenTree};
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<T: AstLike>(&self, mut node: T) -> Option<T> {
pub fn configure<T: HasAttrs + HasTokens>(&self, mut node: T) -> Option<T> {
self.process_cfg_attrs(&mut node);
if self.in_cfg(node.attrs()) {
self.try_configure_tokens(&mut node);
@ -256,7 +256,7 @@ impl<'a> StripUnconfigured<'a> {
}
}
fn try_configure_tokens<T: AstLike>(&self, node: &mut T) {
fn try_configure_tokens<T: HasTokens>(&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 @@ impl<'a> StripUnconfigured<'a> {
/// 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<T: AstLike>(&self, node: &mut T) {
fn process_cfg_attrs<T: HasAttrs>(&self, node: &mut T) {
node.visit_attrs(|attrs| {
attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr));
});

View File

@ -11,7 +11,8 @@ use rustc_ast::ptr::P;
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 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
)
) =>
{
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<Target = [ast::Attribute]> = Vec<ast::Attribute>;
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 @@ impl InvocationCollectorNode for P<ast::Item> {
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
fragment.make_items()
}
fn id(&mut self) -> &mut NodeId {
&mut self.id
}
fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
noop_flat_map_item(self, visitor)
}
@ -1142,7 +1136,7 @@ impl InvocationCollectorNode for P<ast::Item> {
}
struct TraitItemTag;
impl InvocationCollectorNode for AstLikeWrapper<P<ast::AssocItem>, TraitItemTag> {
impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitItemTag> {
type OutputTy = SmallVec<[P<ast::AssocItem>; 1]>;
const KIND: AstFragmentKind = AstFragmentKind::TraitItems;
fn to_annotatable(self) -> Annotatable {
@ -1151,9 +1145,6 @@ impl InvocationCollectorNode for AstLikeWrapper<P<ast::AssocItem>, TraitItemTag>
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<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
noop_flat_map_assoc_item(self.wrapped, visitor)
}
@ -1170,7 +1161,7 @@ impl InvocationCollectorNode for AstLikeWrapper<P<ast::AssocItem>, TraitItemTag>
}
struct ImplItemTag;
impl InvocationCollectorNode for AstLikeWrapper<P<ast::AssocItem>, ImplItemTag> {
impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, ImplItemTag> {
type OutputTy = SmallVec<[P<ast::AssocItem>; 1]>;
const KIND: AstFragmentKind = AstFragmentKind::ImplItems;
fn to_annotatable(self) -> Annotatable {
@ -1179,9 +1170,6 @@ impl InvocationCollectorNode for AstLikeWrapper<P<ast::AssocItem>, ImplItemTag>
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<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
noop_flat_map_assoc_item(self.wrapped, visitor)
}
@ -1205,9 +1193,6 @@ impl InvocationCollectorNode for P<ast::ForeignItem> {
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<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
noop_flat_map_foreign_item(self, visitor)
}
@ -1231,9 +1216,6 @@ impl InvocationCollectorNode for ast::Variant {
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
fragment.make_variants()
}
fn id(&mut self) -> &mut NodeId {
&mut self.id
}
fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
noop_flat_map_variant(self, visitor)
}
@ -1247,9 +1229,6 @@ impl InvocationCollectorNode for ast::FieldDef {
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<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
noop_flat_map_field_def(self, visitor)
}
@ -1263,9 +1242,6 @@ impl InvocationCollectorNode for ast::PatField {
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<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
noop_flat_map_pat_field(self, visitor)
}
@ -1279,9 +1255,6 @@ impl InvocationCollectorNode for ast::ExprField {
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<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
noop_flat_map_expr_field(self, visitor)
}
@ -1295,9 +1268,6 @@ impl InvocationCollectorNode for ast::Param {
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
fragment.make_params()
}
fn id(&mut self) -> &mut NodeId {
&mut self.id
}
fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
noop_flat_map_param(self, visitor)
}
@ -1311,9 +1281,6 @@ impl InvocationCollectorNode for ast::GenericParam {
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<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
noop_flat_map_generic_param(self, visitor)
}
@ -1327,9 +1294,6 @@ impl InvocationCollectorNode for ast::Arm {
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
fragment.make_arms()
}
fn id(&mut self) -> &mut NodeId {
&mut self.id
}
fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
noop_flat_map_arm(self, visitor)
}
@ -1344,9 +1308,6 @@ impl InvocationCollectorNode for ast::Stmt {
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
fragment.make_stmts()
}
fn id(&mut self) -> &mut NodeId {
&mut self.id
}
fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
noop_flat_map_stmt(self, visitor)
}
@ -1403,9 +1364,6 @@ impl InvocationCollectorNode for ast::Crate {
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
fragment.make_crate()
}
fn id(&mut self) -> &mut NodeId {
&mut self.id
}
fn noop_visit<V: MutVisitor>(&mut self, visitor: &mut V) {
noop_visit_crate(self, visitor)
}
@ -1420,9 +1378,6 @@ impl InvocationCollectorNode for P<ast::Ty> {
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
fragment.make_ty()
}
fn id(&mut self) -> &mut NodeId {
&mut self.id
}
fn noop_visit<V: MutVisitor>(&mut self, visitor: &mut V) {
noop_visit_ty(self, visitor)
}
@ -1447,9 +1402,6 @@ impl InvocationCollectorNode for P<ast::Pat> {
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
fragment.make_pat()
}
fn id(&mut self) -> &mut NodeId {
&mut self.id
}
fn noop_visit<V: MutVisitor>(&mut self, visitor: &mut V) {
noop_visit_pat(self, visitor)
}
@ -1475,9 +1427,6 @@ impl InvocationCollectorNode for P<ast::Expr> {
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 @@ impl InvocationCollectorNode for P<ast::Expr> {
}
struct OptExprTag;
impl InvocationCollectorNode for AstLikeWrapper<P<ast::Expr>, OptExprTag> {
impl InvocationCollectorNode for AstNodeWrapper<P<ast::Expr>, OptExprTag> {
type OutputTy = Option<P<ast::Expr>>;
type AttrsTy = ast::AttrVec;
const KIND: AstFragmentKind = AstFragmentKind::OptExpr;
@ -1507,9 +1456,6 @@ impl InvocationCollectorNode for AstLikeWrapper<P<ast::Expr>, OptExprTag> {
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<V: MutVisitor>(mut self, visitor: &mut V) -> Self::OutputTy {
noop_visit_expr(&mut self.wrapped, visitor);
Some(self.wrapped)
@ -1584,7 +1530,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
/// 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<ast::Path>)> {
let mut attr = None;
@ -1680,7 +1626,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
fn expand_cfg_true(
&mut self,
node: &mut impl AstLike,
node: &mut impl HasAttrs,
attr: ast::Attribute,
pos: usize,
) -> bool {
@ -1695,7 +1641,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
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 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
}
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 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
})
}
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<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 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<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 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 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
}
fn filter_map_expr(&mut self, node: P<ast::Expr>) -> Option<P<ast::Expr>> {
self.flat_map_node(AstLikeWrapper::new(node, OptExprTag))
self.flat_map_node(AstNodeWrapper::new(node, OptExprTag))
}
fn visit_block(&mut self, node: &mut P<ast::Block>) {

View File

@ -4,10 +4,9 @@ use crate::proc_macro_server;
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 @@ impl MultiItemModifier for ProcMacroDerive {
) -> ExpandResult<Vec<Annotatable>, 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 {
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) => {
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)
}
Annotatable::Stmt(stmt) => 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()
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 = {

View File

@ -184,7 +184,7 @@ impl FromInternal<(TreeAndSpacing, &'_ mut Vec<Self>, &mut Rustc<'_, '_>)>
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()),
})
}

View File

@ -18,8 +18,7 @@ use crate::context::{EarlyContext, LintContext, LintStore};
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;

View File

@ -17,17 +17,17 @@ use rustc_ast::token::{self, Nonterminal, Token, TokenKind};
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()))

View File

@ -3,7 +3,7 @@ use rustc_ast::token::{self, Delimiter, Token, TokenKind};
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<R: AstLike>(
pub fn collect_tokens_trailing_token<R: HasAttrs + HasTokens>(
&mut self,
attrs: AttrWrapper,
force_collect: ForceCollect,

View File

@ -25,9 +25,9 @@ use rustc_ast::tokenstream::{self, DelimSpan, Spacing};
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 @@ impl<'a> Parser<'a> {
}
}
pub fn collect_tokens_no_attrs<R: AstLike>(
pub fn collect_tokens_no_attrs<R: HasAttrs + HasTokens>(
&mut self,
f: impl FnOnce(&mut Self) -> PResult<'a, R>,
) -> PResult<'a, R> {

View File

@ -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};

View File

@ -13,10 +13,8 @@ use rustc_ast as ast;
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};

View File

@ -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;

View File

@ -5,7 +5,6 @@ use std::io::{self, Write};
use std::time::{Duration, Instant};
use rustc_ast::ast;
use rustc_ast::AstLike;
use rustc_span::Span;
use self::newline_style::apply_newline_style;

View File

@ -4,7 +4,6 @@ use std::path::{Path, PathBuf};
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 @@ impl<'a> Module<'a> {
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<ast::Attribute>)) {
f(&mut self.inner_attr)
}
fn tokens_mut(&mut self) -> Option<&mut Option<rustc_ast::tokenstream::LazyTokenStream>> {
unimplemented!()
}
}
/// Maps each module to the corresponding file.

View File

@ -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};