Skip to content

Commit 1140f76

Browse files
committed
Auto merge of #143897 - cjgillot:derive-walk, r=<try>
Implement AST visitors using a derive macro. AST visitors are large and error-prone beasts. This PR attempts to write them using a derive macro. The design uses three traits: `Visitor`, `Visitable`, `Walkable`. - `Visitor` is the trait implemented by downstream crates, it lists `visit_stuff` methods, which call `Walkable::walk_ref` by default; - `Walkable` is derived using the macro, the generated `walk_ref` method calls `Visitable::visit` on each component; - `Visitable` is implemented by `common_visitor_and_walkers` macro, to call the proper `Visitor::visit_stuff` method if it exists, to call `Walkable::walk_ref` if there is none. I agree this is quite a lot of spaghetti macros. I'm open to suggestions on how to reduce the amount of boilerplate code. If this PR is accepted, I believe the same design can be used for the HIR visitor.
2 parents 7e310f4 + 8dea854 commit 1140f76

File tree

17 files changed

+1336
-1806
lines changed

17 files changed

+1336
-1806
lines changed

compiler/rustc_ast/src/ast.rs

Lines changed: 148 additions & 135 deletions
Large diffs are not rendered by default.

compiler/rustc_ast/src/format.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use rustc_data_structures::fx::FxHashMap;
2-
use rustc_macros::{Decodable, Encodable};
2+
use rustc_macros::{Decodable, Encodable, Walkable};
33
use rustc_span::{Ident, Span, Symbol};
44

55
use crate::Expr;
@@ -41,7 +41,7 @@ use crate::token::LitKind;
4141
/// Basically the "AST" for a complete `format_args!()`.
4242
///
4343
/// E.g., `format_args!("hello {name}");`.
44-
#[derive(Clone, Encodable, Decodable, Debug)]
44+
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
4545
pub struct FormatArgs {
4646
pub span: Span,
4747
pub template: Vec<FormatArgsPiece>,
@@ -63,7 +63,7 @@ pub struct FormatArgs {
6363
/// A piece of a format template string.
6464
///
6565
/// E.g. "hello" or "{name}".
66-
#[derive(Clone, Encodable, Decodable, Debug)]
66+
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
6767
pub enum FormatArgsPiece {
6868
Literal(Symbol),
6969
Placeholder(FormatPlaceholder),
@@ -73,7 +73,7 @@ pub enum FormatArgsPiece {
7373
///
7474
/// E.g. `1, 2, name="ferris", n=3`,
7575
/// but also implicit captured arguments like `x` in `format_args!("{x}")`.
76-
#[derive(Clone, Encodable, Decodable, Debug)]
76+
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
7777
pub struct FormatArguments {
7878
arguments: Vec<FormatArgument>,
7979
num_unnamed_args: usize,
@@ -144,13 +144,13 @@ impl FormatArguments {
144144
}
145145
}
146146

147-
#[derive(Clone, Encodable, Decodable, Debug)]
147+
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
148148
pub struct FormatArgument {
149149
pub kind: FormatArgumentKind,
150150
pub expr: P<Expr>,
151151
}
152152

153-
#[derive(Clone, Encodable, Decodable, Debug)]
153+
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
154154
pub enum FormatArgumentKind {
155155
/// `format_args(…, arg)`
156156
Normal,
@@ -170,24 +170,28 @@ impl FormatArgumentKind {
170170
}
171171
}
172172

173-
#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
173+
#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq, Walkable)]
174174
pub struct FormatPlaceholder {
175175
/// Index into [`FormatArgs::arguments`].
176176
pub argument: FormatArgPosition,
177177
/// The span inside the format string for the full `{…}` placeholder.
178178
pub span: Option<Span>,
179179
/// `{}`, `{:?}`, or `{:x}`, etc.
180+
#[visitable(ignore)]
180181
pub format_trait: FormatTrait,
181182
/// `{}` or `{:.5}` or `{:-^20}`, etc.
183+
#[visitable(ignore)]
182184
pub format_options: FormatOptions,
183185
}
184186

185-
#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
187+
#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq, Walkable)]
186188
pub struct FormatArgPosition {
187189
/// Which argument this position refers to (Ok),
188190
/// or would've referred to if it existed (Err).
191+
#[visitable(ignore)]
189192
pub index: Result<usize, usize>,
190193
/// What kind of position this is. See [`FormatArgPositionKind`].
194+
#[visitable(ignore)]
191195
pub kind: FormatArgPositionKind,
192196
/// The span of the name or number.
193197
pub span: Option<Span>,

compiler/rustc_ast/src/mut_visit.rs

Lines changed: 140 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,19 @@ use std::panic;
1212

1313
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
1414
use rustc_span::source_map::Spanned;
15-
use rustc_span::{Ident, Span};
15+
use rustc_span::{Ident, Span, Symbol};
1616
use smallvec::{SmallVec, smallvec};
1717
use thin_vec::ThinVec;
1818

1919
use crate::ast::*;
2020
use crate::ptr::P;
2121
use crate::tokenstream::*;
22-
use crate::visit::{AssocCtxt, BoundKind, FnCtxt, VisitorResult, try_visit, visit_opt, walk_list};
22+
use crate::visit::{AssocCtxt, BoundKind, FnCtxt, LifetimeCtxt, VisitorResult, try_visit};
23+
use crate::{
24+
define_named_walk, impl_visitable, impl_visitable_calling, impl_visitable_calling_walkable,
25+
impl_visitable_direct, impl_visitable_list, impl_visitable_noop, impl_walkable,
26+
visit_visitable, visit_visitable_with, walk_walkable,
27+
};
2328

2429
mod sealed {
2530
use rustc_ast_ir::visit::VisitorResult;
@@ -36,11 +41,144 @@ mod sealed {
3641

3742
use sealed::MutVisitorResult;
3843

44+
pub(crate) trait MutVisitable<V: MutVisitor> {
45+
type Extra: Copy;
46+
fn visit_mut(&mut self, visitor: &mut V, extra: Self::Extra);
47+
}
48+
49+
impl<V: MutVisitor, T: ?Sized> MutVisitable<V> for P<T>
50+
where
51+
T: MutVisitable<V>,
52+
{
53+
type Extra = T::Extra;
54+
fn visit_mut(&mut self, visitor: &mut V, extra: Self::Extra) {
55+
(**self).visit_mut(visitor, extra)
56+
}
57+
}
58+
59+
impl<V: MutVisitor, T> MutVisitable<V> for Option<T>
60+
where
61+
T: MutVisitable<V>,
62+
{
63+
type Extra = T::Extra;
64+
fn visit_mut(&mut self, visitor: &mut V, extra: Self::Extra) {
65+
if let Some(this) = self {
66+
this.visit_mut(visitor, extra)
67+
}
68+
}
69+
}
70+
71+
impl<V: MutVisitor, T> MutVisitable<V> for Spanned<T>
72+
where
73+
T: MutVisitable<V>,
74+
{
75+
type Extra = T::Extra;
76+
fn visit_mut(&mut self, visitor: &mut V, extra: Self::Extra) {
77+
let Spanned { span, node } = self;
78+
span.visit_mut(visitor, ());
79+
node.visit_mut(visitor, extra);
80+
}
81+
}
82+
83+
impl<V: MutVisitor, T> MutVisitable<V> for [T]
84+
where
85+
T: MutVisitable<V>,
86+
{
87+
type Extra = T::Extra;
88+
fn visit_mut(&mut self, visitor: &mut V, extra: Self::Extra) {
89+
for item in self {
90+
item.visit_mut(visitor, extra);
91+
}
92+
}
93+
}
94+
95+
impl<V: MutVisitor, T> MutVisitable<V> for Vec<T>
96+
where
97+
T: MutVisitable<V>,
98+
{
99+
type Extra = T::Extra;
100+
fn visit_mut(&mut self, visitor: &mut V, extra: Self::Extra) {
101+
for item in self {
102+
item.visit_mut(visitor, extra);
103+
}
104+
}
105+
}
106+
107+
impl<V: MutVisitor, T> MutVisitable<V> for (T,)
108+
where
109+
T: MutVisitable<V>,
110+
{
111+
type Extra = T::Extra;
112+
fn visit_mut(&mut self, visitor: &mut V, extra: Self::Extra) {
113+
self.0.visit_mut(visitor, extra);
114+
}
115+
}
116+
117+
impl<V: MutVisitor, T1, T2> MutVisitable<V> for (T1, T2)
118+
where
119+
T1: MutVisitable<V, Extra = ()>,
120+
T2: MutVisitable<V, Extra = ()>,
121+
{
122+
type Extra = ();
123+
fn visit_mut(&mut self, visitor: &mut V, extra: Self::Extra) {
124+
self.0.visit_mut(visitor, extra);
125+
self.1.visit_mut(visitor, extra);
126+
}
127+
}
128+
129+
impl<V: MutVisitor, T1, T2, T3> MutVisitable<V> for (T1, T2, T3)
130+
where
131+
T1: MutVisitable<V, Extra = ()>,
132+
T2: MutVisitable<V, Extra = ()>,
133+
T3: MutVisitable<V, Extra = ()>,
134+
{
135+
type Extra = ();
136+
fn visit_mut(&mut self, visitor: &mut V, extra: Self::Extra) {
137+
self.0.visit_mut(visitor, extra);
138+
self.1.visit_mut(visitor, extra);
139+
self.2.visit_mut(visitor, extra);
140+
}
141+
}
142+
143+
impl<V: MutVisitor, T1, T2, T3, T4> MutVisitable<V> for (T1, T2, T3, T4)
144+
where
145+
T1: MutVisitable<V, Extra = ()>,
146+
T2: MutVisitable<V, Extra = ()>,
147+
T3: MutVisitable<V, Extra = ()>,
148+
T4: MutVisitable<V, Extra = ()>,
149+
{
150+
type Extra = ();
151+
fn visit_mut(&mut self, visitor: &mut V, extra: Self::Extra) {
152+
self.0.visit_mut(visitor, extra);
153+
self.1.visit_mut(visitor, extra);
154+
self.2.visit_mut(visitor, extra);
155+
self.3.visit_mut(visitor, extra);
156+
}
157+
}
158+
159+
pub trait MutWalkable<V: MutVisitor> {
160+
fn walk_mut(&mut self, visitor: &mut V);
161+
}
162+
39163
super::common_visitor_and_walkers!((mut) MutVisitor);
40164

41165
macro_rules! generate_flat_map_visitor_fns {
42166
($($name:ident, $Ty:ty, $flat_map_fn:ident$(, $param:ident: $ParamTy:ty)*;)+) => {
43167
$(
168+
#[allow(unused_parens)]
169+
impl<V: MutVisitor> MutVisitable<V> for ThinVec<$Ty> {
170+
type Extra = ($($ParamTy),*);
171+
172+
#[inline]
173+
fn visit_mut(
174+
&mut self,
175+
visitor: &mut V,
176+
($($param),*): Self::Extra,
177+
) -> V::Result {
178+
$name(visitor, self $(, $param)*)
179+
}
180+
}
181+
44182
fn $name<V: MutVisitor>(
45183
vis: &mut V,
46184
values: &mut ThinVec<$Ty>,
@@ -78,15 +216,6 @@ pub fn walk_flat_map_pat_field<T: MutVisitor>(
78216
smallvec![fp]
79217
}
80218

81-
fn visit_nested_use_tree<V: MutVisitor>(
82-
vis: &mut V,
83-
nested_tree: &mut UseTree,
84-
nested_id: &mut NodeId,
85-
) {
86-
vis.visit_id(nested_id);
87-
vis.visit_use_tree(nested_tree);
88-
}
89-
90219
macro_rules! generate_walk_flat_map_fns {
91220
($($fn_name:ident($Ty:ty$(,$extra_name:ident: $ExtraTy:ty)*) => $visit_fn_name:ident;)+) => {$(
92221
pub fn $fn_name<V: MutVisitor>(vis: &mut V, mut value: $Ty$(,$extra_name: $ExtraTy)*) -> SmallVec<[$Ty; 1]> {
@@ -109,14 +238,6 @@ generate_walk_flat_map_fns! {
109238
walk_flat_map_assoc_item(P<AssocItem>, ctxt: AssocCtxt) => visit_assoc_item;
110239
}
111240

112-
fn walk_ty_alias_where_clauses<T: MutVisitor>(vis: &mut T, tawcs: &mut TyAliasWhereClauses) {
113-
let TyAliasWhereClauses { before, after, split: _ } = tawcs;
114-
let TyAliasWhereClause { has_where_token: _, span: span_before } = before;
115-
let TyAliasWhereClause { has_where_token: _, span: span_after } = after;
116-
vis.visit_span(span_before);
117-
vis.visit_span(span_after);
118-
}
119-
120241
pub fn walk_filter_map_expr<T: MutVisitor>(vis: &mut T, mut e: P<Expr>) -> Option<P<Expr>> {
121242
vis.visit_expr(&mut e);
122243
Some(e)

compiler/rustc_ast/src/tokenstream.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use std::{cmp, fmt, iter, mem};
2020

2121
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
2222
use rustc_data_structures::sync;
23-
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
23+
use rustc_macros::{Decodable, Encodable, HashStable_Generic, Walkable};
2424
use rustc_serialize::{Decodable, Encodable};
2525
use rustc_span::{DUMMY_SP, Span, SpanDecoder, SpanEncoder, Symbol, sym};
2626
use thin_vec::ThinVec;
@@ -977,7 +977,7 @@ impl TokenCursor {
977977
}
978978
}
979979

980-
#[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)]
980+
#[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic, Walkable)]
981981
pub struct DelimSpan {
982982
pub open: Span,
983983
pub close: Span,

0 commit comments

Comments
 (0)