Skip to content

Commit

Permalink
ast: Generalize item kind visiting
Browse files Browse the repository at this point in the history
And avoid duplicating logic for visiting `Item`s with different kinds (regular, associated, foreign).
  • Loading branch information
petrochenkov committed Apr 25, 2024
1 parent 9e6c4fd commit db43ec7
Show file tree
Hide file tree
Showing 17 changed files with 383 additions and 355 deletions.
356 changes: 174 additions & 182 deletions compiler/rustc_ast/src/mut_visit.rs

Large diffs are not rendered by default.

296 changes: 167 additions & 129 deletions compiler/rustc_ast/src/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,15 @@ pub enum LifetimeCtxt {
GenericArg,
}

pub trait WalkItemKind: Sized {
fn walk<'a, V: Visitor<'a>>(
&'a self,
item: &'a Item<Self>,
ctxt: AssocCtxt,
visitor: &mut V,
) -> V::Result;
}

/// Each method of the `Visitor` trait is a hook to be potentially
/// overridden. Each method's default implementation recursively visits
/// the substructure of the input via the corresponding `walk` method;
Expand All @@ -120,7 +129,7 @@ pub trait Visitor<'ast>: Sized {
Self::Result::output()
}
fn visit_foreign_item(&mut self, i: &'ast ForeignItem) -> Self::Result {
walk_foreign_item(self, i)
walk_item(self, i)
}
fn visit_item(&mut self, i: &'ast Item) -> Self::Result {
walk_item(self, i)
Expand Down Expand Up @@ -312,87 +321,98 @@ pub fn walk_trait_ref<'a, V: Visitor<'a>>(visitor: &mut V, trait_ref: &'a TraitR
visitor.visit_path(&trait_ref.path, trait_ref.ref_id)
}

pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) -> V::Result {
try_visit!(visitor.visit_vis(&item.vis));
try_visit!(visitor.visit_ident(item.ident));
match &item.kind {
ItemKind::ExternCrate(_) => {}
ItemKind::Use(use_tree) => try_visit!(visitor.visit_use_tree(use_tree, item.id, false)),
ItemKind::Static(box StaticItem { ty, mutability: _, expr }) => {
try_visit!(visitor.visit_ty(ty));
visit_opt!(visitor, visit_expr, expr);
}
ItemKind::Const(box ConstItem { defaultness: _, generics, ty, expr }) => {
try_visit!(visitor.visit_generics(generics));
try_visit!(visitor.visit_ty(ty));
visit_opt!(visitor, visit_expr, expr);
}
ItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
let kind =
FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref());
try_visit!(visitor.visit_fn(kind, item.span, item.id));
}
ItemKind::Mod(_unsafety, mod_kind) => match mod_kind {
ModKind::Loaded(items, _inline, _inner_span) => {
walk_list!(visitor, visit_item, items);
impl WalkItemKind for ItemKind {
fn walk<'a, V: Visitor<'a>>(
&'a self,
item: &'a Item<Self>,
_ctxt: AssocCtxt,
visitor: &mut V,
) -> V::Result {
match self {
ItemKind::ExternCrate(_) => {}
ItemKind::Use(use_tree) => try_visit!(visitor.visit_use_tree(use_tree, item.id, false)),
ItemKind::Static(box StaticItem { ty, mutability: _, expr }) => {
try_visit!(visitor.visit_ty(ty));
visit_opt!(visitor, visit_expr, expr);
}
ModKind::Unloaded => {}
},
ItemKind::ForeignMod(foreign_module) => {
walk_list!(visitor, visit_foreign_item, &foreign_module.items);
}
ItemKind::GlobalAsm(asm) => try_visit!(visitor.visit_inline_asm(asm)),
ItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => {
try_visit!(visitor.visit_generics(generics));
walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
visit_opt!(visitor, visit_ty, ty);
}
ItemKind::Enum(enum_definition, generics) => {
try_visit!(visitor.visit_generics(generics));
try_visit!(visitor.visit_enum_def(enum_definition));
}
ItemKind::Impl(box Impl {
defaultness: _,
unsafety: _,
generics,
constness: _,
polarity: _,
of_trait,
self_ty,
items,
}) => {
try_visit!(visitor.visit_generics(generics));
visit_opt!(visitor, visit_trait_ref, of_trait);
try_visit!(visitor.visit_ty(self_ty));
walk_list!(visitor, visit_assoc_item, items, AssocCtxt::Impl);
}
ItemKind::Struct(struct_definition, generics)
| ItemKind::Union(struct_definition, generics) => {
try_visit!(visitor.visit_generics(generics));
try_visit!(visitor.visit_variant_data(struct_definition));
}
ItemKind::Trait(box Trait { unsafety: _, is_auto: _, generics, bounds, items }) => {
try_visit!(visitor.visit_generics(generics));
walk_list!(visitor, visit_param_bound, bounds, BoundKind::SuperTraits);
walk_list!(visitor, visit_assoc_item, items, AssocCtxt::Trait);
}
ItemKind::TraitAlias(generics, bounds) => {
try_visit!(visitor.visit_generics(generics));
walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
}
ItemKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)),
ItemKind::MacroDef(ts) => try_visit!(visitor.visit_mac_def(ts, item.id)),
ItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => {
if let Some(qself) = qself {
try_visit!(visitor.visit_ty(&qself.ty));
ItemKind::Const(box ConstItem { defaultness: _, generics, ty, expr }) => {
try_visit!(visitor.visit_generics(generics));
try_visit!(visitor.visit_ty(ty));
visit_opt!(visitor, visit_expr, expr);
}
ItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
let kind =
FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref());
try_visit!(visitor.visit_fn(kind, item.span, item.id));
}
ItemKind::Mod(_unsafety, mod_kind) => match mod_kind {
ModKind::Loaded(items, _inline, _inner_span) => {
walk_list!(visitor, visit_item, items);
}
ModKind::Unloaded => {}
},
ItemKind::ForeignMod(foreign_module) => {
walk_list!(visitor, visit_foreign_item, &foreign_module.items);
}
ItemKind::GlobalAsm(asm) => try_visit!(visitor.visit_inline_asm(asm)),
ItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => {
try_visit!(visitor.visit_generics(generics));
walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
visit_opt!(visitor, visit_ty, ty);
}
ItemKind::Enum(enum_definition, generics) => {
try_visit!(visitor.visit_generics(generics));
try_visit!(visitor.visit_enum_def(enum_definition));
}
ItemKind::Impl(box Impl {
defaultness: _,
unsafety: _,
generics,
constness: _,
polarity: _,
of_trait,
self_ty,
items,
}) => {
try_visit!(visitor.visit_generics(generics));
visit_opt!(visitor, visit_trait_ref, of_trait);
try_visit!(visitor.visit_ty(self_ty));
walk_list!(visitor, visit_assoc_item, items, AssocCtxt::Impl);
}
ItemKind::Struct(struct_definition, generics)
| ItemKind::Union(struct_definition, generics) => {
try_visit!(visitor.visit_generics(generics));
try_visit!(visitor.visit_variant_data(struct_definition));
}
ItemKind::Trait(box Trait { unsafety: _, is_auto: _, generics, bounds, items }) => {
try_visit!(visitor.visit_generics(generics));
walk_list!(visitor, visit_param_bound, bounds, BoundKind::SuperTraits);
walk_list!(visitor, visit_assoc_item, items, AssocCtxt::Trait);
}
ItemKind::TraitAlias(generics, bounds) => {
try_visit!(visitor.visit_generics(generics));
walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
}
ItemKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)),
ItemKind::MacroDef(ts) => try_visit!(visitor.visit_mac_def(ts, item.id)),
ItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => {
if let Some(qself) = qself {
try_visit!(visitor.visit_ty(&qself.ty));
}
try_visit!(visitor.visit_path(path, *id));
visit_opt!(visitor, visit_ident, *rename);
visit_opt!(visitor, visit_block, body);
}
try_visit!(visitor.visit_path(path, *id));
visit_opt!(visitor, visit_ident, *rename);
visit_opt!(visitor, visit_block, body);
}
V::Result::output()
}
walk_list!(visitor, visit_attribute, &item.attrs);
V::Result::output()
}

pub fn walk_item<'a, V: Visitor<'a>>(
visitor: &mut V,
item: &'a Item<impl WalkItemKind>,
) -> V::Result {
walk_assoc_item(visitor, item, AssocCtxt::Trait /*ignored*/)
}

pub fn walk_enum_def<'a, V: Visitor<'a>>(
Expand Down Expand Up @@ -613,30 +633,34 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Res
V::Result::output()
}

pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a ForeignItem) -> V::Result {
let &Item { id, span, ident, ref vis, ref attrs, ref kind, tokens: _ } = item;
try_visit!(visitor.visit_vis(vis));
try_visit!(visitor.visit_ident(ident));
walk_list!(visitor, visit_attribute, attrs);
match kind {
ForeignItemKind::Static(ty, _, expr) => {
try_visit!(visitor.visit_ty(ty));
visit_opt!(visitor, visit_expr, expr);
}
ForeignItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, generics, body.as_deref());
try_visit!(visitor.visit_fn(kind, span, id));
}
ForeignItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => {
try_visit!(visitor.visit_generics(generics));
walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
visit_opt!(visitor, visit_ty, ty);
}
ForeignItemKind::MacCall(mac) => {
try_visit!(visitor.visit_mac_call(mac));
impl WalkItemKind for ForeignItemKind {
fn walk<'a, V: Visitor<'a>>(
&'a self,
item: &'a Item<Self>,
_ctxt: AssocCtxt,
visitor: &mut V,
) -> V::Result {
let &Item { id, span, ident, ref vis, .. } = item;
match self {
ForeignItemKind::Static(ty, _, expr) => {
try_visit!(visitor.visit_ty(ty));
visit_opt!(visitor, visit_expr, expr);
}
ForeignItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, generics, body.as_deref());
try_visit!(visitor.visit_fn(kind, span, id));
}
ForeignItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => {
try_visit!(visitor.visit_generics(generics));
walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
visit_opt!(visitor, visit_ty, ty);
}
ForeignItemKind::MacCall(mac) => {
try_visit!(visitor.visit_mac_call(mac));
}
}
V::Result::output()
}
V::Result::output()
}

pub fn walk_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a GenericBound) -> V::Result {
Expand Down Expand Up @@ -756,42 +780,56 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Resu
V::Result::output()
}

impl WalkItemKind for AssocItemKind {
fn walk<'a, V: Visitor<'a>>(
&'a self,
item: &'a Item<Self>,
ctxt: AssocCtxt,
visitor: &mut V,
) -> V::Result {
let &Item { id, span, ident, ref vis, .. } = item;
match self {
AssocItemKind::Const(box ConstItem { defaultness: _, generics, ty, expr }) => {
try_visit!(visitor.visit_generics(generics));
try_visit!(visitor.visit_ty(ty));
visit_opt!(visitor, visit_expr, expr);
}
AssocItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
let kind =
FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, generics, body.as_deref());
try_visit!(visitor.visit_fn(kind, span, id));
}
AssocItemKind::Type(box TyAlias { generics, bounds, ty, .. }) => {
try_visit!(visitor.visit_generics(generics));
walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
visit_opt!(visitor, visit_ty, ty);
}
AssocItemKind::MacCall(mac) => {
try_visit!(visitor.visit_mac_call(mac));
}
AssocItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => {
if let Some(qself) = qself {
try_visit!(visitor.visit_ty(&qself.ty));
}
try_visit!(visitor.visit_path(path, *id));
visit_opt!(visitor, visit_ident, *rename);
visit_opt!(visitor, visit_block, body);
}
}
V::Result::output()
}
}

pub fn walk_assoc_item<'a, V: Visitor<'a>>(
visitor: &mut V,
item: &'a AssocItem,
item: &'a Item<impl WalkItemKind>,
ctxt: AssocCtxt,
) -> V::Result {
let &Item { id, span, ident, ref vis, ref attrs, ref kind, tokens: _ } = item;
let &Item { id: _, span: _, ident, ref vis, ref attrs, ref kind, tokens: _ } = item;
try_visit!(visitor.visit_vis(vis));
try_visit!(visitor.visit_ident(ident));
walk_list!(visitor, visit_attribute, attrs);
match kind {
AssocItemKind::Const(box ConstItem { defaultness: _, generics, ty, expr }) => {
try_visit!(visitor.visit_generics(generics));
try_visit!(visitor.visit_ty(ty));
visit_opt!(visitor, visit_expr, expr);
}
AssocItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, generics, body.as_deref());
try_visit!(visitor.visit_fn(kind, span, id));
}
AssocItemKind::Type(box TyAlias { generics, bounds, ty, .. }) => {
try_visit!(visitor.visit_generics(generics));
walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
visit_opt!(visitor, visit_ty, ty);
}
AssocItemKind::MacCall(mac) => {
try_visit!(visitor.visit_mac_call(mac));
}
AssocItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => {
if let Some(qself) = qself {
try_visit!(visitor.visit_ty(&qself.ty));
}
try_visit!(visitor.visit_path(path, *id));
visit_opt!(visitor, visit_ident, *rename);
visit_opt!(visitor, visit_block, body);
}
}
try_visit!(kind.walk(item, ctxt, visitor));
V::Result::output()
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ fn index_crate<'a>(
let def_id = self.node_id_to_def_id[&item.id];
*self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner) =
AstOwner::ForeignItem(item);
visit::walk_foreign_item(self, item);
visit::walk_item(self, item);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1192,7 +1192,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
ForeignItemKind::MacCall(..) => {}
}

visit::walk_foreign_item(self, fi)
visit::walk_item(self, fi)
}

// Mirrors `visit::walk_generic_args`, but tracks relevant state.
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
ast::ForeignItemKind::MacCall(..) => {}
}

visit::walk_foreign_item(self, i)
visit::walk_item(self, i)
}

fn visit_ty(&mut self, ty: &'a ast::Ty) {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_ast_passes/src/node_count.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ impl<'ast> Visitor<'ast> for NodeCounter {
}
fn visit_foreign_item(&mut self, i: &ForeignItem) {
self.count += 1;
walk_foreign_item(self, i)
walk_item(self, i)
}
fn visit_item(&mut self, i: &Item) {
self.count += 1;
Expand Down
Loading

0 comments on commit db43ec7

Please sign in to comment.