Implement AST visitors using a derive macro.
This commit is contained in:
parent
ca9eecda36
commit
3c81faec23
7 changed files with 1219 additions and 1675 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -1,5 +1,5 @@
|
|||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_macros::{Decodable, Encodable};
|
||||
use rustc_macros::{Decodable, Encodable, Walkable};
|
||||
use rustc_span::{Ident, Span, Symbol};
|
||||
|
||||
use crate::Expr;
|
||||
|
|
@ -41,7 +41,7 @@ use crate::token::LitKind;
|
|||
/// Basically the "AST" for a complete `format_args!()`.
|
||||
///
|
||||
/// E.g., `format_args!("hello {name}");`.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
|
||||
pub struct FormatArgs {
|
||||
pub span: Span,
|
||||
pub template: Vec<FormatArgsPiece>,
|
||||
|
|
@ -63,7 +63,7 @@ pub struct FormatArgs {
|
|||
/// A piece of a format template string.
|
||||
///
|
||||
/// E.g. "hello" or "{name}".
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
|
||||
pub enum FormatArgsPiece {
|
||||
Literal(Symbol),
|
||||
Placeholder(FormatPlaceholder),
|
||||
|
|
@ -73,7 +73,7 @@ pub enum FormatArgsPiece {
|
|||
///
|
||||
/// E.g. `1, 2, name="ferris", n=3`,
|
||||
/// but also implicit captured arguments like `x` in `format_args!("{x}")`.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
|
||||
pub struct FormatArguments {
|
||||
arguments: Vec<FormatArgument>,
|
||||
num_unnamed_args: usize,
|
||||
|
|
@ -144,13 +144,13 @@ impl FormatArguments {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
|
||||
pub struct FormatArgument {
|
||||
pub kind: FormatArgumentKind,
|
||||
pub expr: P<Expr>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
|
||||
pub enum FormatArgumentKind {
|
||||
/// `format_args(…, arg)`
|
||||
Normal,
|
||||
|
|
@ -170,24 +170,28 @@ impl FormatArgumentKind {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
|
||||
#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq, Walkable)]
|
||||
pub struct FormatPlaceholder {
|
||||
/// Index into [`FormatArgs::arguments`].
|
||||
pub argument: FormatArgPosition,
|
||||
/// The span inside the format string for the full `{…}` placeholder.
|
||||
pub span: Option<Span>,
|
||||
/// `{}`, `{:?}`, or `{:x}`, etc.
|
||||
#[visitable(ignore)]
|
||||
pub format_trait: FormatTrait,
|
||||
/// `{}` or `{:.5}` or `{:-^20}`, etc.
|
||||
#[visitable(ignore)]
|
||||
pub format_options: FormatOptions,
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
|
||||
#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq, Walkable)]
|
||||
pub struct FormatArgPosition {
|
||||
/// Which argument this position refers to (Ok),
|
||||
/// or would've referred to if it existed (Err).
|
||||
#[visitable(ignore)]
|
||||
pub index: Result<usize, usize>,
|
||||
/// What kind of position this is. See [`FormatArgPositionKind`].
|
||||
#[visitable(ignore)]
|
||||
pub kind: FormatArgPositionKind,
|
||||
/// The span of the name or number.
|
||||
pub span: Option<Span>,
|
||||
|
|
|
|||
|
|
@ -12,14 +12,14 @@ use std::panic;
|
|||
|
||||
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::{Ident, Span};
|
||||
use rustc_span::{Ident, Span, Symbol};
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
use crate::ast::*;
|
||||
use crate::ptr::P;
|
||||
use crate::tokenstream::*;
|
||||
use crate::visit::{AssocCtxt, BoundKind, FnCtxt, VisitorResult, try_visit, visit_opt, walk_list};
|
||||
use crate::visit::{AssocCtxt, BoundKind, FnCtxt, LifetimeCtxt, VisitorResult, try_visit};
|
||||
|
||||
mod sealed {
|
||||
use rustc_ast_ir::visit::VisitorResult;
|
||||
|
|
@ -36,11 +36,249 @@ mod sealed {
|
|||
|
||||
use sealed::MutVisitorResult;
|
||||
|
||||
pub(crate) trait MutVisitable<V: MutVisitor> {
|
||||
type Extra: Copy;
|
||||
fn visit_mut(&mut self, visitor: &mut V, extra: Self::Extra);
|
||||
}
|
||||
|
||||
impl<V: MutVisitor, T: ?Sized> MutVisitable<V> for P<T>
|
||||
where
|
||||
T: MutVisitable<V>,
|
||||
{
|
||||
type Extra = T::Extra;
|
||||
fn visit_mut(&mut self, visitor: &mut V, extra: Self::Extra) {
|
||||
(**self).visit_mut(visitor, extra)
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: MutVisitor, T> MutVisitable<V> for Option<T>
|
||||
where
|
||||
T: MutVisitable<V>,
|
||||
{
|
||||
type Extra = T::Extra;
|
||||
fn visit_mut(&mut self, visitor: &mut V, extra: Self::Extra) {
|
||||
if let Some(this) = self {
|
||||
this.visit_mut(visitor, extra)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: MutVisitor, T> MutVisitable<V> for Spanned<T>
|
||||
where
|
||||
T: MutVisitable<V>,
|
||||
{
|
||||
type Extra = T::Extra;
|
||||
fn visit_mut(&mut self, visitor: &mut V, extra: Self::Extra) {
|
||||
let Spanned { span, node } = self;
|
||||
span.visit_mut(visitor, ());
|
||||
node.visit_mut(visitor, extra);
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: MutVisitor, T> MutVisitable<V> for [T]
|
||||
where
|
||||
T: MutVisitable<V>,
|
||||
{
|
||||
type Extra = T::Extra;
|
||||
fn visit_mut(&mut self, visitor: &mut V, extra: Self::Extra) {
|
||||
for item in self {
|
||||
item.visit_mut(visitor, extra);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: MutVisitor, T> MutVisitable<V> for Vec<T>
|
||||
where
|
||||
T: MutVisitable<V>,
|
||||
{
|
||||
type Extra = T::Extra;
|
||||
fn visit_mut(&mut self, visitor: &mut V, extra: Self::Extra) {
|
||||
for item in self {
|
||||
item.visit_mut(visitor, extra);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: MutVisitor, T> MutVisitable<V> for (T,)
|
||||
where
|
||||
T: MutVisitable<V>,
|
||||
{
|
||||
type Extra = T::Extra;
|
||||
fn visit_mut(&mut self, visitor: &mut V, extra: Self::Extra) {
|
||||
self.0.visit_mut(visitor, extra);
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: MutVisitor, T1, T2> MutVisitable<V> for (T1, T2)
|
||||
where
|
||||
T1: MutVisitable<V, Extra = ()>,
|
||||
T2: MutVisitable<V, Extra = ()>,
|
||||
{
|
||||
type Extra = ();
|
||||
fn visit_mut(&mut self, visitor: &mut V, extra: Self::Extra) {
|
||||
self.0.visit_mut(visitor, extra);
|
||||
self.1.visit_mut(visitor, extra);
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: MutVisitor, T1, T2, T3> MutVisitable<V> for (T1, T2, T3)
|
||||
where
|
||||
T1: MutVisitable<V, Extra = ()>,
|
||||
T2: MutVisitable<V, Extra = ()>,
|
||||
T3: MutVisitable<V, Extra = ()>,
|
||||
{
|
||||
type Extra = ();
|
||||
fn visit_mut(&mut self, visitor: &mut V, extra: Self::Extra) {
|
||||
self.0.visit_mut(visitor, extra);
|
||||
self.1.visit_mut(visitor, extra);
|
||||
self.2.visit_mut(visitor, extra);
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: MutVisitor, T1, T2, T3, T4> MutVisitable<V> for (T1, T2, T3, T4)
|
||||
where
|
||||
T1: MutVisitable<V, Extra = ()>,
|
||||
T2: MutVisitable<V, Extra = ()>,
|
||||
T3: MutVisitable<V, Extra = ()>,
|
||||
T4: MutVisitable<V, Extra = ()>,
|
||||
{
|
||||
type Extra = ();
|
||||
fn visit_mut(&mut self, visitor: &mut V, extra: Self::Extra) {
|
||||
self.0.visit_mut(visitor, extra);
|
||||
self.1.visit_mut(visitor, extra);
|
||||
self.2.visit_mut(visitor, extra);
|
||||
self.3.visit_mut(visitor, extra);
|
||||
}
|
||||
}
|
||||
|
||||
pub trait MutWalkable<V: MutVisitor> {
|
||||
fn walk_mut(&mut self, visitor: &mut V);
|
||||
}
|
||||
|
||||
macro_rules! visit_visitable {
|
||||
(mut $visitor:expr, $($expr:expr),* $(,)?) => {{
|
||||
$(MutVisitable::visit_mut($expr, $visitor, ());)*
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! visit_visitable_with {
|
||||
(mut $visitor:expr, $expr:expr, $extra:expr $(,)?) => {
|
||||
MutVisitable::visit_mut($expr, $visitor, $extra)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! walk_walkable {
|
||||
($visitor:expr, $expr:expr, mut) => {
|
||||
MutWalkable::walk_mut($expr, $visitor)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_visitable {
|
||||
(|&mut $self:ident: $self_ty:ty,
|
||||
$vis:ident: &mut $vis_ty:ident,
|
||||
$extra:ident: $extra_ty:ty| $block:block) => {
|
||||
#[allow(unused_parens, non_local_definitions)]
|
||||
impl<$vis_ty: MutVisitor> MutVisitable<$vis_ty> for $self_ty {
|
||||
type Extra = $extra_ty;
|
||||
fn visit_mut(&mut $self, $vis: &mut $vis_ty, $extra: Self::Extra) -> V::Result {
|
||||
$block
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_walkable {
|
||||
($(<$K:ident: $Kb:ident>)? |&mut $self:ident: $self_ty:ty,
|
||||
$vis:ident: &mut $vis_ty:ident| $block:block) => {
|
||||
#[allow(unused_parens, non_local_definitions)]
|
||||
impl<$($K: $Kb,)? $vis_ty: MutVisitor> MutWalkable<$vis_ty> for $self_ty {
|
||||
fn walk_mut(&mut $self, $vis: &mut $vis_ty) -> V::Result {
|
||||
$block
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_visitable_noop {
|
||||
(<mut> $($ty:ty,)*) => {
|
||||
$(
|
||||
impl_visitable!(|&mut self: $ty, _vis: &mut V, _extra: ()| {});
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_visitable_list {
|
||||
(<mut> $($ty:ty,)*) => {
|
||||
$(impl<V: MutVisitor, T> MutVisitable<V> for $ty
|
||||
where
|
||||
for<'a> &'a mut $ty: IntoIterator<Item = &'a mut T>,
|
||||
T: MutVisitable<V>,
|
||||
{
|
||||
type Extra = <T as MutVisitable<V>>::Extra;
|
||||
|
||||
#[inline]
|
||||
fn visit_mut(&mut self, visitor: &mut V, extra: Self::Extra) {
|
||||
for i in self {
|
||||
i.visit_mut(visitor, extra);
|
||||
}
|
||||
}
|
||||
})*
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_visitable_direct {
|
||||
(<mut> $($ty:ty,)*) => {
|
||||
$(impl_visitable!(
|
||||
|&mut self: $ty, visitor: &mut V, _extra: ()| {
|
||||
MutWalkable::walk_mut(self, visitor)
|
||||
}
|
||||
);)*
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_visitable_calling_walkable {
|
||||
(<mut>
|
||||
$( fn $method:ident($ty:ty $(, $extra_name:ident: $extra_ty:ty)?); )*
|
||||
) => {
|
||||
$(fn $method(&mut self, node: &mut $ty $(, $extra_name:$extra_ty)?) {
|
||||
impl_visitable!(|&mut self: $ty, visitor: &mut V, extra: ($($extra_ty)?)| {
|
||||
let ($($extra_name)?) = extra;
|
||||
visitor.$method(self $(, $extra_name)?);
|
||||
});
|
||||
walk_walkable!(self, node, mut)
|
||||
})*
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! define_named_walk {
|
||||
((mut) $Visitor:ident
|
||||
$( pub fn $method:ident($ty:ty); )*
|
||||
) => {
|
||||
$(pub fn $method<V: $Visitor>(visitor: &mut V, node: &mut $ty) {
|
||||
walk_walkable!(visitor, node, mut)
|
||||
})*
|
||||
};
|
||||
}
|
||||
|
||||
super::common_visitor_and_walkers!((mut) MutVisitor);
|
||||
|
||||
macro_rules! generate_flat_map_visitor_fns {
|
||||
($($name:ident, $Ty:ty, $flat_map_fn:ident$(, $param:ident: $ParamTy:ty)*;)+) => {
|
||||
$(
|
||||
#[allow(unused_parens)]
|
||||
impl<V: MutVisitor> MutVisitable<V> for ThinVec<$Ty> {
|
||||
type Extra = ($($ParamTy),*);
|
||||
|
||||
#[inline]
|
||||
fn visit_mut(
|
||||
&mut self,
|
||||
visitor: &mut V,
|
||||
($($param),*): Self::Extra,
|
||||
) -> V::Result {
|
||||
$name(visitor, self $(, $param)*)
|
||||
}
|
||||
}
|
||||
|
||||
fn $name<V: MutVisitor>(
|
||||
vis: &mut V,
|
||||
values: &mut ThinVec<$Ty>,
|
||||
|
|
@ -78,15 +316,6 @@ pub fn walk_flat_map_pat_field<T: MutVisitor>(
|
|||
smallvec![fp]
|
||||
}
|
||||
|
||||
fn visit_nested_use_tree<V: MutVisitor>(
|
||||
vis: &mut V,
|
||||
nested_tree: &mut UseTree,
|
||||
nested_id: &mut NodeId,
|
||||
) {
|
||||
vis.visit_id(nested_id);
|
||||
vis.visit_use_tree(nested_tree);
|
||||
}
|
||||
|
||||
macro_rules! generate_walk_flat_map_fns {
|
||||
($($fn_name:ident($Ty:ty$(,$extra_name:ident: $ExtraTy:ty)*) => $visit_fn_name:ident;)+) => {$(
|
||||
pub fn $fn_name<V: MutVisitor>(vis: &mut V, mut value: $Ty$(,$extra_name: $ExtraTy)*) -> SmallVec<[$Ty; 1]> {
|
||||
|
|
@ -109,14 +338,6 @@ generate_walk_flat_map_fns! {
|
|||
walk_flat_map_assoc_item(P<AssocItem>, ctxt: AssocCtxt) => visit_assoc_item;
|
||||
}
|
||||
|
||||
fn walk_ty_alias_where_clauses<T: MutVisitor>(vis: &mut T, tawcs: &mut TyAliasWhereClauses) {
|
||||
let TyAliasWhereClauses { before, after, split: _ } = tawcs;
|
||||
let TyAliasWhereClause { has_where_token: _, span: span_before } = before;
|
||||
let TyAliasWhereClause { has_where_token: _, span: span_after } = after;
|
||||
vis.visit_span(span_before);
|
||||
vis.visit_span(span_after);
|
||||
}
|
||||
|
||||
pub fn walk_filter_map_expr<T: MutVisitor>(vis: &mut T, mut e: P<Expr>) -> Option<P<Expr>> {
|
||||
vis.visit_expr(&mut e);
|
||||
Some(e)
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ use std::{cmp, fmt, iter, mem};
|
|||
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_data_structures::sync;
|
||||
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
|
||||
use rustc_macros::{Decodable, Encodable, HashStable_Generic, Walkable};
|
||||
use rustc_serialize::{Decodable, Encodable};
|
||||
use rustc_span::{DUMMY_SP, Span, SpanDecoder, SpanEncoder, Symbol, sym};
|
||||
use thin_vec::ThinVec;
|
||||
|
|
@ -977,7 +977,7 @@ impl TokenCursor {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic, Walkable)]
|
||||
pub struct DelimSpan {
|
||||
pub open: Span,
|
||||
pub close: Span,
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -21,6 +21,7 @@ mod symbols;
|
|||
mod try_from;
|
||||
mod type_foldable;
|
||||
mod type_visitable;
|
||||
mod visitable;
|
||||
|
||||
// Reads the rust version (e.g. "1.75.0") from the CFG_RELEASE env var and
|
||||
// produces a `RustcVersion` literal containing that version (e.g.
|
||||
|
|
@ -101,6 +102,16 @@ decl_derive!(
|
|||
/// visited (and its type is not required to implement `TypeVisitable`).
|
||||
type_visitable::type_visitable_derive
|
||||
);
|
||||
decl_derive!(
|
||||
[Walkable, attributes(visitable)] =>
|
||||
/// Derives `Walkable` for the annotated `struct` or `enum` (`union` is not supported).
|
||||
///
|
||||
/// Each field of the struct or enum variant will be visited in definition order, using the
|
||||
/// `Walkable` implementation for its type. However, if a field of a struct or an enum
|
||||
/// variant is annotated with `#[visitable(ignore)]` then that field will not be
|
||||
/// visited (and its type is not required to implement `Walkable`).
|
||||
visitable::visitable_derive
|
||||
);
|
||||
decl_derive!([Lift, attributes(lift)] => lift::lift_derive);
|
||||
decl_derive!(
|
||||
[Diagnostic, attributes(
|
||||
|
|
|
|||
82
compiler/rustc_macros/src/visitable.rs
Normal file
82
compiler/rustc_macros/src/visitable.rs
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
use quote::quote;
|
||||
use synstructure::BindingInfo;
|
||||
|
||||
pub(super) fn visitable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
|
||||
if let syn::Data::Union(_) = s.ast().data {
|
||||
panic!("cannot derive on union")
|
||||
}
|
||||
|
||||
let has_attr = |bind: &BindingInfo<'_>, name| {
|
||||
let mut found = false;
|
||||
bind.ast().attrs.iter().for_each(|attr| {
|
||||
if !attr.path().is_ident("visitable") {
|
||||
return;
|
||||
}
|
||||
let _ = attr.parse_nested_meta(|nested| {
|
||||
if nested.path.is_ident(name) {
|
||||
found = true;
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
});
|
||||
found
|
||||
};
|
||||
|
||||
let get_attr = |bind: &BindingInfo<'_>, name: &str| {
|
||||
let mut content = None;
|
||||
bind.ast().attrs.iter().for_each(|attr| {
|
||||
if !attr.path().is_ident("visitable") {
|
||||
return;
|
||||
}
|
||||
let _ = attr.parse_nested_meta(|nested| {
|
||||
if nested.path.is_ident(name) {
|
||||
let value = nested.value()?;
|
||||
let value = value.parse()?;
|
||||
content = Some(value);
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
});
|
||||
content
|
||||
};
|
||||
|
||||
s.add_bounds(synstructure::AddBounds::Generics);
|
||||
s.bind_with(|_| synstructure::BindStyle::Ref);
|
||||
let ref_visit = s.each(|bind| {
|
||||
let extra = get_attr(bind, "extra").unwrap_or(quote! {});
|
||||
if has_attr(bind, "ignore") {
|
||||
quote! {}
|
||||
} else {
|
||||
quote! { rustc_ast_ir::try_visit!(crate::visit::Visitable::visit(#bind, __visitor, (#extra))) }
|
||||
}
|
||||
});
|
||||
|
||||
s.bind_with(|_| synstructure::BindStyle::RefMut);
|
||||
let mut_visit = s.each(|bind| {
|
||||
let extra = get_attr(bind, "extra").unwrap_or(quote! {});
|
||||
if has_attr(bind, "ignore") {
|
||||
quote! {}
|
||||
} else {
|
||||
quote! { crate::mut_visit::MutVisitable::visit_mut(#bind, __visitor, (#extra)) }
|
||||
}
|
||||
});
|
||||
|
||||
s.gen_impl(quote! {
|
||||
gen impl<'__ast, __V> crate::visit::Walkable<'__ast, __V> for @Self
|
||||
where __V: crate::visit::Visitor<'__ast>,
|
||||
{
|
||||
fn walk_ref(&'__ast self, __visitor: &mut __V) -> __V::Result {
|
||||
match *self { #ref_visit }
|
||||
<__V::Result as rustc_ast_ir::visit::VisitorResult>::output()
|
||||
}
|
||||
}
|
||||
|
||||
gen impl<__V> crate::mut_visit::MutWalkable<__V> for @Self
|
||||
where __V: crate::mut_visit::MutVisitor,
|
||||
{
|
||||
fn walk_mut(&mut self, __visitor: &mut __V) {
|
||||
match *self { #mut_visit }
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue