rust/compiler/rustc_hir/src/intravisit.rs
Keith-Cancel 73a991fb9d Allow provisional mgca syntax of type const <IDENT> = <EXPR> to be reconized.
Revert, but without type const.

Update symbol for feature err, then update suggestion output, and lastly update tests that change because of those.

Update these new tests with the correct syntax, and few existing tests with the new outputs the merge with main added.

Fix for tidyfmt and some errors when manually resolving a merge conflicts.

Update these tests to use update error messages and type const syntax.

Update comments and error message to use new syntax instead of old type_const attribute.

Remove the type_const attribute

update some more tests to use the new syntax.

Update these test cases.

update feature gate test

Change gate logic for `mgca_type_const_syntax` to work also if `min_generic_const_args` is enabled.

Create a new feature gate that checks for the feature before expansion.

Make rustfmt handle the `type const` syntax correctly.

Add a convience method to check if a RhsKind is type const.

Rename `Const` discriminant to `Body` for `ConstItemRhsKind`

Give the `TraitItemKind` flag an enum instead of a simple bool to better describe what the flag is for.

Update formatting for these match statements.

Update clippy test to use type const syntax.

Update test to use type const syntax.

update rustfmt to match ast items.

Update clippy to match ast and hir items.

Few more test cases that used old attribute, instead of 'type const'

Update to match the output from the feature gate checks.

tidyfmt adjustments.

Update the is_type_const, so I can constrain record!(..) in encoder.rs

Update conditional compilation test.

Move the feature gate to after expansion to allow for cfg(...) to work.

Update some more tests to use the new syntax.

Update type const tests in associated-const-bindings to use new syntax.

Don't check based off the attribute, but the item here.

Update some tests outside of the const_generics folder that were using #[type_const]

update the tests in associated consts that use #[type_const] to use type const

Update these mgca tests with the type const syntax.

Add a flag to TraitItemKind for detecting type const for now. Maybe later change ItemConstRhs to have optional consts but that touches a lot more lines of code.

Don't need into for these now that it's a query.

Add is_type_const query to handle foreign def ids.

update this test to use type const syntax.

Fix logic here, we only want to lower if there is expression in this case.

Update built-in macros to use ConstItemRhsKind

Update more instance of the old ConstItemRhs.

Rename ConstItemKind to ConstItemRhsKind, I noticed there is a typed called ConstantItemKind, so add the Rhs to the name to avoid confusion.

Update lower to use ConstItemKind

Add an other helper method to check if the rhs kinda has an expr.

Update item parse to use ConstItemKind enum.

Felt the field name could a be little clear when editing a few other things.

Change the ConstItem struct see know if we have a type const or regular const.

Make sure this syntax is properly feature gated.
2026-02-09 07:59:24 -08:00

1559 lines
59 KiB
Rust

//! HIR walker for walking the contents of nodes.
//!
//! Here are the three available patterns for the visitor strategy,
//! in roughly the order of desirability:
//!
//! 1. **Shallow visit**: Get a simple callback for every item (or item-like thing) in the HIR.
//! - Example: find all items with a `#[foo]` attribute on them.
//! - How: Use the `hir_crate_items` or `hir_module_items` query to traverse over item-like ids
//! (ItemId, TraitItemId, etc.) and use tcx.def_kind and `tcx.hir_item*(id)` to filter and
//! access actual item-like thing, respectively.
//! - Pro: Efficient; just walks the lists of item ids and gives users control whether to access
//! the hir_owners themselves or not.
//! - Con: Don't get information about nesting
//! - Con: Don't have methods for specific bits of HIR, like "on
//! every expr, do this".
//! 2. **Deep visit**: Want to scan for specific kinds of HIR nodes within
//! an item, but don't care about how item-like things are nested
//! within one another.
//! - Example: Examine each expression to look for its type and do some check or other.
//! - How: Implement `intravisit::Visitor` and override the `NestedFilter` type to
//! `nested_filter::OnlyBodies` (and implement `maybe_tcx`), and use
//! `tcx.hir_visit_all_item_likes_in_crate(&mut visitor)`. Within your
//! `intravisit::Visitor` impl, implement methods like `visit_expr()` (don't forget to invoke
//! `intravisit::walk_expr()` to keep walking the subparts).
//! - Pro: Visitor methods for any kind of HIR node, not just item-like things.
//! - Pro: Integrates well into dependency tracking.
//! - Con: Don't get information about nesting between items
//! 3. **Nested visit**: Want to visit the whole HIR and you care about the nesting between
//! item-like things.
//! - Example: Lifetime resolution, which wants to bring lifetimes declared on the
//! impl into scope while visiting the impl-items, and then back out again.
//! - How: Implement `intravisit::Visitor` and override the `NestedFilter` type to
//! `nested_filter::All` (and implement `maybe_tcx`). Walk your crate with
//! `tcx.hir_walk_toplevel_module(visitor)`.
//! - Pro: Visitor methods for any kind of HIR node, not just item-like things.
//! - Pro: Preserves nesting information
//! - Con: Does not integrate well into dependency tracking.
//!
//! If you have decided to use this visitor, here are some general
//! notes on how to do so:
//!
//! Each overridden visit method has full control over what
//! happens with its node, it can do its own traversal of the node's children,
//! call `intravisit::walk_*` to apply the default traversal algorithm, or prevent
//! deeper traversal by doing nothing.
//!
//! When visiting the HIR, the contents of nested items are NOT visited
//! by default. This is different from the AST visitor, which does a deep walk.
//! Hence this module is called `intravisit`; see the method `visit_nested_item`
//! for more details.
//!
//! Note: it is an important invariant that the default visitor walks
//! the body of a function in "execution order" - more concretely, if
//! we consider the reverse post-order (RPO) of the CFG implied by the HIR,
//! then a pre-order traversal of the HIR is consistent with the CFG RPO
//! on the *initial CFG point* of each HIR node, while a post-order traversal
//! of the HIR is consistent with the CFG RPO on each *final CFG point* of
//! each CFG node.
//!
//! One thing that follows is that if HIR node A always starts/ends executing
//! before HIR node B, then A appears in traversal pre/postorder before B,
//! respectively. (This follows from RPO respecting CFG domination).
//!
//! This order consistency is required in a few places in rustc, for
//! example coroutine inference, and possibly also HIR borrowck.
use rustc_ast::Label;
use rustc_ast::visit::{VisitorResult, try_visit, visit_opt, walk_list};
use rustc_span::def_id::LocalDefId;
use rustc_span::{Ident, Span, Symbol};
use crate::hir::*;
pub trait IntoVisitor<'hir> {
type Visitor: Visitor<'hir>;
fn into_visitor(&self) -> Self::Visitor;
}
#[derive(Copy, Clone, Debug)]
pub enum FnKind<'a> {
/// `#[xxx] pub async/const/extern "Abi" fn foo()`
ItemFn(Ident, &'a Generics<'a>, FnHeader),
/// `fn foo(&self)`
Method(Ident, &'a FnSig<'a>),
/// `|x, y| {}`
Closure,
}
impl<'a> FnKind<'a> {
pub fn header(&self) -> Option<&FnHeader> {
match *self {
FnKind::ItemFn(_, _, ref header) => Some(header),
FnKind::Method(_, ref sig) => Some(&sig.header),
FnKind::Closure => None,
}
}
pub fn constness(self) -> Constness {
self.header().map_or(Constness::NotConst, |header| header.constness)
}
pub fn asyncness(self) -> IsAsync {
self.header().map_or(IsAsync::NotAsync, |header| header.asyncness)
}
}
/// HIR things retrievable from `TyCtxt`, avoiding an explicit dependence on
/// `TyCtxt`. The only impls are for `!` (where these functions are never
/// called) and `TyCtxt` (in `rustc_middle`).
pub trait HirTyCtxt<'hir> {
/// Retrieves the `Node` corresponding to `id`.
fn hir_node(&self, hir_id: HirId) -> Node<'hir>;
fn hir_body(&self, id: BodyId) -> &'hir Body<'hir>;
fn hir_item(&self, id: ItemId) -> &'hir Item<'hir>;
fn hir_trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir>;
fn hir_impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir>;
fn hir_foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir>;
}
// Used when no tcx is actually available, forcing manual implementation of nested visitors.
impl<'hir> HirTyCtxt<'hir> for ! {
fn hir_node(&self, _: HirId) -> Node<'hir> {
unreachable!();
}
fn hir_body(&self, _: BodyId) -> &'hir Body<'hir> {
unreachable!();
}
fn hir_item(&self, _: ItemId) -> &'hir Item<'hir> {
unreachable!();
}
fn hir_trait_item(&self, _: TraitItemId) -> &'hir TraitItem<'hir> {
unreachable!();
}
fn hir_impl_item(&self, _: ImplItemId) -> &'hir ImplItem<'hir> {
unreachable!();
}
fn hir_foreign_item(&self, _: ForeignItemId) -> &'hir ForeignItem<'hir> {
unreachable!();
}
}
pub mod nested_filter {
use super::HirTyCtxt;
/// Specifies what nested things a visitor wants to visit. By "nested
/// things", we are referring to bits of HIR that are not directly embedded
/// within one another but rather indirectly, through a table in the crate.
/// This is done to control dependencies during incremental compilation: the
/// non-inline bits of HIR can be tracked and hashed separately.
///
/// The most common choice is `OnlyBodies`, which will cause the visitor to
/// visit fn bodies for fns that it encounters, and closure bodies, but
/// skip over nested item-like things.
///
/// See the comments at [`rustc_hir::intravisit`] for more details on the overall
/// visit strategy.
pub trait NestedFilter<'hir> {
type MaybeTyCtxt: HirTyCtxt<'hir>;
/// Whether the visitor visits nested "item-like" things.
/// E.g., item, impl-item.
const INTER: bool;
/// Whether the visitor visits "intra item-like" things.
/// E.g., function body, closure, `AnonConst`
const INTRA: bool;
}
/// Do not visit any nested things. When you add a new
/// "non-nested" thing, you will want to audit such uses to see if
/// they remain valid.
///
/// Use this if you are only walking some particular kind of tree
/// (i.e., a type, or fn signature) and you don't want to thread a
/// `tcx` around.
pub struct None(());
impl NestedFilter<'_> for None {
type MaybeTyCtxt = !;
const INTER: bool = false;
const INTRA: bool = false;
}
}
use nested_filter::NestedFilter;
/// 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;
/// e.g., the `visit_mod` method by default calls `intravisit::walk_mod`.
///
/// Note that this visitor does NOT visit nested items by default
/// (this is why the module is called `intravisit`, to distinguish it
/// from the AST's `visit` module, which acts differently). If you
/// simply want to visit all items in the crate in some order, you
/// should call `tcx.hir_visit_all_item_likes_in_crate`. Otherwise, see the comment
/// on `visit_nested_item` for details on how to visit nested items.
///
/// If you want to ensure that your code handles every variant
/// explicitly, you need to override each method. (And you also need
/// to monitor future changes to `Visitor` in case a new method with a
/// new default implementation gets introduced.)
///
/// Every `walk_*` method uses deconstruction to access fields of structs and
/// enums. This will result in a compile error if a field is added, which makes
/// it more likely the appropriate visit call will be added for it.
pub trait Visitor<'v>: Sized {
// This type should not be overridden, it exists for convenient usage as `Self::MaybeTyCtxt`.
type MaybeTyCtxt: HirTyCtxt<'v> = <Self::NestedFilter as NestedFilter<'v>>::MaybeTyCtxt;
///////////////////////////////////////////////////////////////////////////
// Nested items.
/// Override this type to control which nested HIR are visited; see
/// [`NestedFilter`] for details. If you override this type, you
/// must also override [`maybe_tcx`](Self::maybe_tcx).
///
/// **If for some reason you want the nested behavior, but don't
/// have a `tcx` at your disposal:** then override the
/// `visit_nested_XXX` methods. If a new `visit_nested_XXX` variant is
/// added in the future, it will cause a panic which can be detected
/// and fixed appropriately.
type NestedFilter: NestedFilter<'v> = nested_filter::None;
/// The result type of the `visit_*` methods. Can be either `()`,
/// or `ControlFlow<T>`.
type Result: VisitorResult = ();
/// If `type NestedFilter` is set to visit nested items, this method
/// must also be overridden to provide a map to retrieve nested items.
fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
panic!(
"maybe_tcx must be implemented or consider using \
`type NestedFilter = nested_filter::None` (the default)"
);
}
/// Invoked when a nested item is encountered. By default, when
/// `Self::NestedFilter` is `nested_filter::None`, this method does
/// nothing. **You probably don't want to override this method** --
/// instead, override [`Self::NestedFilter`] or use the "shallow" or
/// "deep" visit patterns described at
/// [`rustc_hir::intravisit`]. The only reason to override
/// this method is if you want a nested pattern but cannot supply a
/// `TyCtxt`; see `maybe_tcx` for advice.
fn visit_nested_item(&mut self, id: ItemId) -> Self::Result {
if Self::NestedFilter::INTER {
let item = self.maybe_tcx().hir_item(id);
try_visit!(self.visit_item(item));
}
Self::Result::output()
}
/// Like `visit_nested_item()`, but for trait items. See
/// `visit_nested_item()` for advice on when to override this
/// method.
fn visit_nested_trait_item(&mut self, id: TraitItemId) -> Self::Result {
if Self::NestedFilter::INTER {
let item = self.maybe_tcx().hir_trait_item(id);
try_visit!(self.visit_trait_item(item));
}
Self::Result::output()
}
/// Like `visit_nested_item()`, but for impl items. See
/// `visit_nested_item()` for advice on when to override this
/// method.
fn visit_nested_impl_item(&mut self, id: ImplItemId) -> Self::Result {
if Self::NestedFilter::INTER {
let item = self.maybe_tcx().hir_impl_item(id);
try_visit!(self.visit_impl_item(item));
}
Self::Result::output()
}
/// Like `visit_nested_item()`, but for foreign items. See
/// `visit_nested_item()` for advice on when to override this
/// method.
fn visit_nested_foreign_item(&mut self, id: ForeignItemId) -> Self::Result {
if Self::NestedFilter::INTER {
let item = self.maybe_tcx().hir_foreign_item(id);
try_visit!(self.visit_foreign_item(item));
}
Self::Result::output()
}
/// Invoked to visit the body of a function, method or closure. Like
/// `visit_nested_item`, does nothing by default unless you override
/// `Self::NestedFilter`.
fn visit_nested_body(&mut self, id: BodyId) -> Self::Result {
if Self::NestedFilter::INTRA {
let body = self.maybe_tcx().hir_body(id);
try_visit!(self.visit_body(body));
}
Self::Result::output()
}
fn visit_param(&mut self, param: &'v Param<'v>) -> Self::Result {
walk_param(self, param)
}
/// Visits the top-level item and (optionally) nested items / impl items. See
/// `visit_nested_item` for details.
fn visit_item(&mut self, i: &'v Item<'v>) -> Self::Result {
walk_item(self, i)
}
fn visit_body(&mut self, b: &Body<'v>) -> Self::Result {
walk_body(self, b)
}
///////////////////////////////////////////////////////////////////////////
fn visit_id(&mut self, _hir_id: HirId) -> Self::Result {
Self::Result::output()
}
fn visit_name(&mut self, _name: Symbol) -> Self::Result {
Self::Result::output()
}
fn visit_ident(&mut self, ident: Ident) -> Self::Result {
walk_ident(self, ident)
}
fn visit_mod(&mut self, m: &'v Mod<'v>, _s: Span, _n: HirId) -> Self::Result {
walk_mod(self, m)
}
fn visit_foreign_item(&mut self, i: &'v ForeignItem<'v>) -> Self::Result {
walk_foreign_item(self, i)
}
fn visit_local(&mut self, l: &'v LetStmt<'v>) -> Self::Result {
walk_local(self, l)
}
fn visit_block(&mut self, b: &'v Block<'v>) -> Self::Result {
walk_block(self, b)
}
fn visit_stmt(&mut self, s: &'v Stmt<'v>) -> Self::Result {
walk_stmt(self, s)
}
fn visit_arm(&mut self, a: &'v Arm<'v>) -> Self::Result {
walk_arm(self, a)
}
fn visit_pat(&mut self, p: &'v Pat<'v>) -> Self::Result {
walk_pat(self, p)
}
fn visit_pat_field(&mut self, f: &'v PatField<'v>) -> Self::Result {
walk_pat_field(self, f)
}
fn visit_pat_expr(&mut self, expr: &'v PatExpr<'v>) -> Self::Result {
walk_pat_expr(self, expr)
}
fn visit_lit(&mut self, _hir_id: HirId, _lit: Lit, _negated: bool) -> Self::Result {
Self::Result::output()
}
fn visit_anon_const(&mut self, c: &'v AnonConst) -> Self::Result {
walk_anon_const(self, c)
}
fn visit_inline_const(&mut self, c: &'v ConstBlock) -> Self::Result {
walk_inline_const(self, c)
}
fn visit_generic_arg(&mut self, generic_arg: &'v GenericArg<'v>) -> Self::Result {
walk_generic_arg(self, generic_arg)
}
/// All types are treated as ambiguous types for the purposes of hir visiting in
/// order to ensure that visitors can handle infer vars without it being too error-prone.
///
/// The [`Visitor::visit_infer`] method should be overridden in order to handle infer vars.
fn visit_ty(&mut self, t: &'v Ty<'v, AmbigArg>) -> Self::Result {
walk_ty(self, t)
}
fn visit_const_item_rhs(&mut self, c: ConstItemRhs<'v>) -> Self::Result {
walk_const_item_rhs(self, c)
}
/// All consts are treated as ambiguous consts for the purposes of hir visiting in
/// order to ensure that visitors can handle infer vars without it being too error-prone.
///
/// The [`Visitor::visit_infer`] method should be overridden in order to handle infer vars.
fn visit_const_arg(&mut self, c: &'v ConstArg<'v, AmbigArg>) -> Self::Result {
walk_const_arg(self, c)
}
#[allow(unused_variables)]
fn visit_infer(&mut self, inf_id: HirId, inf_span: Span, kind: InferKind<'v>) -> Self::Result {
self.visit_id(inf_id)
}
fn visit_lifetime(&mut self, lifetime: &'v Lifetime) -> Self::Result {
walk_lifetime(self, lifetime)
}
fn visit_expr(&mut self, ex: &'v Expr<'v>) -> Self::Result {
walk_expr(self, ex)
}
fn visit_expr_field(&mut self, field: &'v ExprField<'v>) -> Self::Result {
walk_expr_field(self, field)
}
fn visit_const_arg_expr_field(&mut self, field: &'v ConstArgExprField<'v>) -> Self::Result {
walk_const_arg_expr_field(self, field)
}
fn visit_pattern_type_pattern(&mut self, p: &'v TyPat<'v>) -> Self::Result {
walk_ty_pat(self, p)
}
fn visit_generic_param(&mut self, p: &'v GenericParam<'v>) -> Self::Result {
walk_generic_param(self, p)
}
fn visit_const_param_default(&mut self, _param: HirId, ct: &'v ConstArg<'v>) -> Self::Result {
walk_const_param_default(self, ct)
}
fn visit_generics(&mut self, g: &'v Generics<'v>) -> Self::Result {
walk_generics(self, g)
}
fn visit_where_predicate(&mut self, predicate: &'v WherePredicate<'v>) -> Self::Result {
walk_where_predicate(self, predicate)
}
fn visit_fn_ret_ty(&mut self, ret_ty: &'v FnRetTy<'v>) -> Self::Result {
walk_fn_ret_ty(self, ret_ty)
}
fn visit_fn_decl(&mut self, fd: &'v FnDecl<'v>) -> Self::Result {
walk_fn_decl(self, fd)
}
fn visit_fn(
&mut self,
fk: FnKind<'v>,
fd: &'v FnDecl<'v>,
b: BodyId,
_: Span,
id: LocalDefId,
) -> Self::Result {
walk_fn(self, fk, fd, b, id)
}
fn visit_use(&mut self, path: &'v UsePath<'v>, hir_id: HirId) -> Self::Result {
walk_use(self, path, hir_id)
}
fn visit_trait_item(&mut self, ti: &'v TraitItem<'v>) -> Self::Result {
walk_trait_item(self, ti)
}
fn visit_trait_item_ref(&mut self, ii: &'v TraitItemId) -> Self::Result {
walk_trait_item_ref(self, *ii)
}
fn visit_impl_item(&mut self, ii: &'v ImplItem<'v>) -> Self::Result {
walk_impl_item(self, ii)
}
fn visit_foreign_item_ref(&mut self, ii: &'v ForeignItemId) -> Self::Result {
walk_foreign_item_ref(self, *ii)
}
fn visit_impl_item_ref(&mut self, ii: &'v ImplItemId) -> Self::Result {
walk_impl_item_ref(self, *ii)
}
fn visit_trait_ref(&mut self, t: &'v TraitRef<'v>) -> Self::Result {
walk_trait_ref(self, t)
}
fn visit_param_bound(&mut self, bounds: &'v GenericBound<'v>) -> Self::Result {
walk_param_bound(self, bounds)
}
fn visit_precise_capturing_arg(&mut self, arg: &'v PreciseCapturingArg<'v>) -> Self::Result {
walk_precise_capturing_arg(self, arg)
}
fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef<'v>) -> Self::Result {
walk_poly_trait_ref(self, t)
}
fn visit_opaque_ty(&mut self, opaque: &'v OpaqueTy<'v>) -> Self::Result {
walk_opaque_ty(self, opaque)
}
fn visit_variant_data(&mut self, s: &'v VariantData<'v>) -> Self::Result {
walk_struct_def(self, s)
}
fn visit_field_def(&mut self, s: &'v FieldDef<'v>) -> Self::Result {
walk_field_def(self, s)
}
fn visit_enum_def(&mut self, enum_definition: &'v EnumDef<'v>) -> Self::Result {
walk_enum_def(self, enum_definition)
}
fn visit_variant(&mut self, v: &'v Variant<'v>) -> Self::Result {
walk_variant(self, v)
}
fn visit_label(&mut self, label: &'v Label) -> Self::Result {
walk_label(self, label)
}
// The span is that of the surrounding type/pattern/expr/whatever.
fn visit_qpath(&mut self, qpath: &'v QPath<'v>, id: HirId, _span: Span) -> Self::Result {
walk_qpath(self, qpath, id)
}
fn visit_path(&mut self, path: &Path<'v>, _id: HirId) -> Self::Result {
walk_path(self, path)
}
fn visit_path_segment(&mut self, path_segment: &'v PathSegment<'v>) -> Self::Result {
walk_path_segment(self, path_segment)
}
fn visit_generic_args(&mut self, generic_args: &'v GenericArgs<'v>) -> Self::Result {
walk_generic_args(self, generic_args)
}
fn visit_assoc_item_constraint(
&mut self,
constraint: &'v AssocItemConstraint<'v>,
) -> Self::Result {
walk_assoc_item_constraint(self, constraint)
}
fn visit_attribute(&mut self, _attr: &'v Attribute) -> Self::Result {
Self::Result::output()
}
fn visit_defaultness(&mut self, defaultness: &'v Defaultness) -> Self::Result {
walk_defaultness(self, defaultness)
}
fn visit_inline_asm(&mut self, asm: &'v InlineAsm<'v>, id: HirId) -> Self::Result {
walk_inline_asm(self, asm, id)
}
}
pub trait VisitorExt<'v>: Visitor<'v> {
/// Extension trait method to visit types in unambiguous positions, this is not
/// directly on the [`Visitor`] trait as this method should never be overridden.
///
/// Named `visit_ty_unambig` instead of `visit_unambig_ty` to aid in discovery
/// by IDes when `v.visit_ty` is written.
fn visit_ty_unambig(&mut self, t: &'v Ty<'v>) -> Self::Result {
walk_unambig_ty(self, t)
}
/// Extension trait method to visit consts in unambiguous positions, this is not
/// directly on the [`Visitor`] trait as this method should never be overridden.
///
/// Named `visit_const_arg_unambig` instead of `visit_unambig_const_arg` to aid in
/// discovery by IDes when `v.visit_const_arg` is written.
fn visit_const_arg_unambig(&mut self, c: &'v ConstArg<'v>) -> Self::Result {
walk_unambig_const_arg(self, c)
}
}
impl<'v, V: Visitor<'v>> VisitorExt<'v> for V {}
pub fn walk_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Param<'v>) -> V::Result {
let Param { hir_id, pat, ty_span: _, span: _ } = param;
try_visit!(visitor.visit_id(*hir_id));
visitor.visit_pat(pat)
}
pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::Result {
let Item { owner_id: _, kind, span: _, vis_span: _, has_delayed_lints: _, eii: _ } = item;
try_visit!(visitor.visit_id(item.hir_id()));
match *kind {
ItemKind::ExternCrate(orig_name, ident) => {
visit_opt!(visitor, visit_name, orig_name);
try_visit!(visitor.visit_ident(ident));
}
ItemKind::Use(ref path, kind) => {
try_visit!(visitor.visit_use(path, item.hir_id()));
match kind {
UseKind::Single(ident) => try_visit!(visitor.visit_ident(ident)),
UseKind::Glob | UseKind::ListStem => {}
}
}
ItemKind::Static(_, ident, ref typ, body) => {
try_visit!(visitor.visit_ident(ident));
try_visit!(visitor.visit_ty_unambig(typ));
try_visit!(visitor.visit_nested_body(body));
}
ItemKind::Const(ident, ref generics, ref typ, rhs) => {
try_visit!(visitor.visit_ident(ident));
try_visit!(visitor.visit_generics(generics));
try_visit!(visitor.visit_ty_unambig(typ));
try_visit!(visitor.visit_const_item_rhs(rhs));
}
ItemKind::Fn { ident, sig, generics, body: body_id, .. } => {
try_visit!(visitor.visit_ident(ident));
try_visit!(visitor.visit_fn(
FnKind::ItemFn(ident, generics, sig.header),
sig.decl,
body_id,
item.span,
item.owner_id.def_id,
));
}
ItemKind::Macro(ident, _def, _kind) => {
try_visit!(visitor.visit_ident(ident));
}
ItemKind::Mod(ident, ref module) => {
try_visit!(visitor.visit_ident(ident));
try_visit!(visitor.visit_mod(module, item.span, item.hir_id()));
}
ItemKind::ForeignMod { abi: _, items } => {
walk_list!(visitor, visit_foreign_item_ref, items);
}
ItemKind::GlobalAsm { asm: _, fake_body } => {
// Visit the fake body, which contains the asm statement.
// Therefore we should not visit the asm statement again
// outside of the body, or some visitors won't have their
// typeck results set correctly.
try_visit!(visitor.visit_nested_body(fake_body));
}
ItemKind::TyAlias(ident, ref generics, ref ty) => {
try_visit!(visitor.visit_ident(ident));
try_visit!(visitor.visit_generics(generics));
try_visit!(visitor.visit_ty_unambig(ty));
}
ItemKind::Enum(ident, ref generics, ref enum_definition) => {
try_visit!(visitor.visit_ident(ident));
try_visit!(visitor.visit_generics(generics));
try_visit!(visitor.visit_enum_def(enum_definition));
}
ItemKind::Impl(Impl { generics, of_trait, self_ty, items, constness: _ }) => {
try_visit!(visitor.visit_generics(generics));
if let Some(TraitImplHeader {
safety: _,
polarity: _,
defaultness: _,
defaultness_span: _,
trait_ref,
}) = of_trait
{
try_visit!(visitor.visit_trait_ref(trait_ref));
}
try_visit!(visitor.visit_ty_unambig(self_ty));
walk_list!(visitor, visit_impl_item_ref, items);
}
ItemKind::Struct(ident, ref generics, ref struct_definition)
| ItemKind::Union(ident, ref generics, ref struct_definition) => {
try_visit!(visitor.visit_ident(ident));
try_visit!(visitor.visit_generics(generics));
try_visit!(visitor.visit_variant_data(struct_definition));
}
ItemKind::Trait(
_constness,
_is_auto,
_safety,
ident,
ref generics,
bounds,
trait_item_refs,
) => {
try_visit!(visitor.visit_ident(ident));
try_visit!(visitor.visit_generics(generics));
walk_list!(visitor, visit_param_bound, bounds);
walk_list!(visitor, visit_trait_item_ref, trait_item_refs);
}
ItemKind::TraitAlias(_constness, ident, ref generics, bounds) => {
try_visit!(visitor.visit_ident(ident));
try_visit!(visitor.visit_generics(generics));
walk_list!(visitor, visit_param_bound, bounds);
}
}
V::Result::output()
}
pub fn walk_body<'v, V: Visitor<'v>>(visitor: &mut V, body: &Body<'v>) -> V::Result {
let Body { params, value } = body;
walk_list!(visitor, visit_param, *params);
visitor.visit_expr(*value)
}
pub fn walk_ident<'v, V: Visitor<'v>>(visitor: &mut V, ident: Ident) -> V::Result {
visitor.visit_name(ident.name)
}
pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod<'v>) -> V::Result {
let Mod { spans: _, item_ids } = module;
walk_list!(visitor, visit_nested_item, item_ids.iter().copied());
V::Result::output()
}
pub fn walk_foreign_item<'v, V: Visitor<'v>>(
visitor: &mut V,
foreign_item: &'v ForeignItem<'v>,
) -> V::Result {
let ForeignItem { ident, kind, owner_id: _, span: _, vis_span: _, has_delayed_lints: _ } =
foreign_item;
try_visit!(visitor.visit_id(foreign_item.hir_id()));
try_visit!(visitor.visit_ident(*ident));
match *kind {
ForeignItemKind::Fn(ref sig, param_idents, ref generics) => {
try_visit!(visitor.visit_generics(generics));
try_visit!(visitor.visit_fn_decl(sig.decl));
for ident in param_idents.iter().copied() {
visit_opt!(visitor, visit_ident, ident);
}
}
ForeignItemKind::Static(ref typ, _, _) => {
try_visit!(visitor.visit_ty_unambig(typ));
}
ForeignItemKind::Type => (),
}
V::Result::output()
}
pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v LetStmt<'v>) -> V::Result {
// Intentionally visiting the expr first - the initialization expr
// dominates the local's definition.
let LetStmt { super_: _, pat, ty, init, els, hir_id, span: _, source: _ } = local;
visit_opt!(visitor, visit_expr, *init);
try_visit!(visitor.visit_id(*hir_id));
try_visit!(visitor.visit_pat(*pat));
visit_opt!(visitor, visit_block, *els);
visit_opt!(visitor, visit_ty_unambig, *ty);
V::Result::output()
}
pub fn walk_block<'v, V: Visitor<'v>>(visitor: &mut V, block: &'v Block<'v>) -> V::Result {
let Block { stmts, expr, hir_id, rules: _, span: _, targeted_by_break: _ } = block;
try_visit!(visitor.visit_id(*hir_id));
walk_list!(visitor, visit_stmt, *stmts);
visit_opt!(visitor, visit_expr, *expr);
V::Result::output()
}
pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) -> V::Result {
let Stmt { kind, hir_id, span: _ } = statement;
try_visit!(visitor.visit_id(*hir_id));
match *kind {
StmtKind::Let(ref local) => visitor.visit_local(local),
StmtKind::Item(item) => visitor.visit_nested_item(item),
StmtKind::Expr(ref expression) | StmtKind::Semi(ref expression) => {
visitor.visit_expr(expression)
}
}
}
pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm<'v>) -> V::Result {
let Arm { hir_id, span: _, pat, guard, body } = arm;
try_visit!(visitor.visit_id(*hir_id));
try_visit!(visitor.visit_pat(*pat));
visit_opt!(visitor, visit_expr, *guard);
visitor.visit_expr(*body)
}
pub fn walk_ty_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v TyPat<'v>) -> V::Result {
let TyPat { kind, hir_id, span: _ } = pattern;
try_visit!(visitor.visit_id(*hir_id));
match *kind {
TyPatKind::Range(lower_bound, upper_bound) => {
try_visit!(visitor.visit_const_arg_unambig(lower_bound));
try_visit!(visitor.visit_const_arg_unambig(upper_bound));
}
TyPatKind::Or(patterns) => walk_list!(visitor, visit_pattern_type_pattern, patterns),
TyPatKind::NotNull | TyPatKind::Err(_) => (),
}
V::Result::output()
}
pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) -> V::Result {
let Pat { hir_id, kind, span, default_binding_modes: _ } = pattern;
try_visit!(visitor.visit_id(*hir_id));
match *kind {
PatKind::TupleStruct(ref qpath, children, _) => {
try_visit!(visitor.visit_qpath(qpath, *hir_id, *span));
walk_list!(visitor, visit_pat, children);
}
PatKind::Struct(ref qpath, fields, _) => {
try_visit!(visitor.visit_qpath(qpath, *hir_id, *span));
walk_list!(visitor, visit_pat_field, fields);
}
PatKind::Or(pats) => walk_list!(visitor, visit_pat, pats),
PatKind::Tuple(tuple_elements, _) => {
walk_list!(visitor, visit_pat, tuple_elements);
}
PatKind::Box(ref subpattern)
| PatKind::Deref(ref subpattern)
| PatKind::Ref(ref subpattern, _, _) => {
try_visit!(visitor.visit_pat(subpattern));
}
PatKind::Binding(_, _hir_id, ident, ref optional_subpattern) => {
try_visit!(visitor.visit_ident(ident));
visit_opt!(visitor, visit_pat, optional_subpattern);
}
PatKind::Expr(ref expression) => try_visit!(visitor.visit_pat_expr(expression)),
PatKind::Range(ref lower_bound, ref upper_bound, _) => {
visit_opt!(visitor, visit_pat_expr, lower_bound);
visit_opt!(visitor, visit_pat_expr, upper_bound);
}
PatKind::Missing | PatKind::Never | PatKind::Wild | PatKind::Err(_) => (),
PatKind::Slice(prepatterns, ref slice_pattern, postpatterns) => {
walk_list!(visitor, visit_pat, prepatterns);
visit_opt!(visitor, visit_pat, slice_pattern);
walk_list!(visitor, visit_pat, postpatterns);
}
PatKind::Guard(subpat, condition) => {
try_visit!(visitor.visit_pat(subpat));
try_visit!(visitor.visit_expr(condition));
}
}
V::Result::output()
}
pub fn walk_pat_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v PatField<'v>) -> V::Result {
let PatField { hir_id, ident, pat, is_shorthand: _, span: _ } = field;
try_visit!(visitor.visit_id(*hir_id));
try_visit!(visitor.visit_ident(*ident));
visitor.visit_pat(*pat)
}
pub fn walk_pat_expr<'v, V: Visitor<'v>>(visitor: &mut V, expr: &'v PatExpr<'v>) -> V::Result {
let PatExpr { hir_id, span, kind } = expr;
try_visit!(visitor.visit_id(*hir_id));
match kind {
PatExprKind::Lit { lit, negated } => visitor.visit_lit(*hir_id, *lit, *negated),
PatExprKind::Path(qpath) => visitor.visit_qpath(qpath, *hir_id, *span),
}
}
pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonConst) -> V::Result {
let AnonConst { hir_id, def_id: _, body, span: _ } = constant;
try_visit!(visitor.visit_id(*hir_id));
visitor.visit_nested_body(*body)
}
pub fn walk_inline_const<'v, V: Visitor<'v>>(
visitor: &mut V,
constant: &'v ConstBlock,
) -> V::Result {
let ConstBlock { hir_id, def_id: _, body } = constant;
try_visit!(visitor.visit_id(*hir_id));
visitor.visit_nested_body(*body)
}
pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) -> V::Result {
let Expr { hir_id, kind, span } = expression;
try_visit!(visitor.visit_id(*hir_id));
match *kind {
ExprKind::Array(subexpressions) => {
walk_list!(visitor, visit_expr, subexpressions);
}
ExprKind::ConstBlock(ref const_block) => {
try_visit!(visitor.visit_inline_const(const_block))
}
ExprKind::Repeat(ref element, ref count) => {
try_visit!(visitor.visit_expr(element));
try_visit!(visitor.visit_const_arg_unambig(count));
}
ExprKind::Struct(ref qpath, fields, ref optional_base) => {
try_visit!(visitor.visit_qpath(qpath, *hir_id, *span));
walk_list!(visitor, visit_expr_field, fields);
match optional_base {
StructTailExpr::Base(base) => try_visit!(visitor.visit_expr(base)),
StructTailExpr::None | StructTailExpr::DefaultFields(_) => {}
}
}
ExprKind::Tup(subexpressions) => {
walk_list!(visitor, visit_expr, subexpressions);
}
ExprKind::Call(ref callee_expression, arguments) => {
try_visit!(visitor.visit_expr(callee_expression));
walk_list!(visitor, visit_expr, arguments);
}
ExprKind::MethodCall(ref segment, receiver, arguments, _) => {
try_visit!(visitor.visit_path_segment(segment));
try_visit!(visitor.visit_expr(receiver));
walk_list!(visitor, visit_expr, arguments);
}
ExprKind::Use(expr, _) => {
try_visit!(visitor.visit_expr(expr));
}
ExprKind::Binary(_, ref left_expression, ref right_expression) => {
try_visit!(visitor.visit_expr(left_expression));
try_visit!(visitor.visit_expr(right_expression));
}
ExprKind::AddrOf(_, _, ref subexpression) | ExprKind::Unary(_, ref subexpression) => {
try_visit!(visitor.visit_expr(subexpression));
}
ExprKind::Cast(ref subexpression, ref typ) | ExprKind::Type(ref subexpression, ref typ) => {
try_visit!(visitor.visit_expr(subexpression));
try_visit!(visitor.visit_ty_unambig(typ));
}
ExprKind::DropTemps(ref subexpression) => {
try_visit!(visitor.visit_expr(subexpression));
}
ExprKind::Let(LetExpr { span: _, pat, ty, init, recovered: _ }) => {
// match the visit order in walk_local
try_visit!(visitor.visit_expr(init));
try_visit!(visitor.visit_pat(pat));
visit_opt!(visitor, visit_ty_unambig, ty);
}
ExprKind::If(ref cond, ref then, ref else_opt) => {
try_visit!(visitor.visit_expr(cond));
try_visit!(visitor.visit_expr(then));
visit_opt!(visitor, visit_expr, else_opt);
}
ExprKind::Loop(ref block, ref opt_label, _, _) => {
visit_opt!(visitor, visit_label, opt_label);
try_visit!(visitor.visit_block(block));
}
ExprKind::Match(ref subexpression, arms, _) => {
try_visit!(visitor.visit_expr(subexpression));
walk_list!(visitor, visit_arm, arms);
}
ExprKind::Closure(&Closure {
def_id,
binder: _,
bound_generic_params,
fn_decl,
body,
capture_clause: _,
fn_decl_span: _,
fn_arg_span: _,
kind: _,
constness: _,
}) => {
walk_list!(visitor, visit_generic_param, bound_generic_params);
try_visit!(visitor.visit_fn(FnKind::Closure, fn_decl, body, *span, def_id));
}
ExprKind::Block(ref block, ref opt_label) => {
visit_opt!(visitor, visit_label, opt_label);
try_visit!(visitor.visit_block(block));
}
ExprKind::Assign(ref lhs, ref rhs, _) => {
try_visit!(visitor.visit_expr(rhs));
try_visit!(visitor.visit_expr(lhs));
}
ExprKind::AssignOp(_, ref left_expression, ref right_expression) => {
try_visit!(visitor.visit_expr(right_expression));
try_visit!(visitor.visit_expr(left_expression));
}
ExprKind::Field(ref subexpression, ident) => {
try_visit!(visitor.visit_expr(subexpression));
try_visit!(visitor.visit_ident(ident));
}
ExprKind::Index(ref main_expression, ref index_expression, _) => {
try_visit!(visitor.visit_expr(main_expression));
try_visit!(visitor.visit_expr(index_expression));
}
ExprKind::Path(ref qpath) => {
try_visit!(visitor.visit_qpath(qpath, *hir_id, *span));
}
ExprKind::Break(ref destination, ref opt_expr) => {
visit_opt!(visitor, visit_label, &destination.label);
visit_opt!(visitor, visit_expr, opt_expr);
}
ExprKind::Continue(ref destination) => {
visit_opt!(visitor, visit_label, &destination.label);
}
ExprKind::Ret(ref optional_expression) => {
visit_opt!(visitor, visit_expr, optional_expression);
}
ExprKind::Become(ref expr) => try_visit!(visitor.visit_expr(expr)),
ExprKind::InlineAsm(ref asm) => {
try_visit!(visitor.visit_inline_asm(asm, *hir_id));
}
ExprKind::OffsetOf(ref container, ref fields) => {
try_visit!(visitor.visit_ty_unambig(container));
walk_list!(visitor, visit_ident, fields.iter().copied());
}
ExprKind::Yield(ref subexpression, _) => {
try_visit!(visitor.visit_expr(subexpression));
}
ExprKind::UnsafeBinderCast(_kind, expr, ty) => {
try_visit!(visitor.visit_expr(expr));
visit_opt!(visitor, visit_ty_unambig, ty);
}
ExprKind::Lit(lit) => try_visit!(visitor.visit_lit(*hir_id, lit, false)),
ExprKind::Err(_) => {}
}
V::Result::output()
}
pub fn walk_expr_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v ExprField<'v>) -> V::Result {
let ExprField { hir_id, ident, expr, span: _, is_shorthand: _ } = field;
try_visit!(visitor.visit_id(*hir_id));
try_visit!(visitor.visit_ident(*ident));
visitor.visit_expr(*expr)
}
pub fn walk_const_arg_expr_field<'v, V: Visitor<'v>>(
visitor: &mut V,
field: &'v ConstArgExprField<'v>,
) -> V::Result {
let ConstArgExprField { hir_id, field, expr, span: _ } = field;
try_visit!(visitor.visit_id(*hir_id));
try_visit!(visitor.visit_ident(*field));
visitor.visit_const_arg_unambig(*expr)
}
/// We track whether an infer var is from a [`Ty`], [`ConstArg`], or [`GenericArg`] so that
/// HIR visitors overriding [`Visitor::visit_infer`] can determine what kind of infer is being visited
pub enum InferKind<'hir> {
Ty(&'hir Ty<'hir>),
Const(&'hir ConstArg<'hir>),
Ambig(&'hir InferArg),
}
pub fn walk_generic_arg<'v, V: Visitor<'v>>(
visitor: &mut V,
generic_arg: &'v GenericArg<'v>,
) -> V::Result {
match generic_arg {
GenericArg::Lifetime(lt) => visitor.visit_lifetime(lt),
GenericArg::Type(ty) => visitor.visit_ty(ty),
GenericArg::Const(ct) => visitor.visit_const_arg(ct),
GenericArg::Infer(inf) => {
let InferArg { hir_id, span } = inf;
visitor.visit_infer(*hir_id, *span, InferKind::Ambig(inf))
}
}
}
pub fn walk_unambig_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Result {
match typ.try_as_ambig_ty() {
Some(ambig_ty) => visitor.visit_ty(ambig_ty),
None => {
let Ty { hir_id, span, kind: _ } = typ;
visitor.visit_infer(*hir_id, *span, InferKind::Ty(typ))
}
}
}
pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v, AmbigArg>) -> V::Result {
let Ty { hir_id, span: _, kind } = typ;
try_visit!(visitor.visit_id(*hir_id));
match *kind {
TyKind::Slice(ref ty) => try_visit!(visitor.visit_ty_unambig(ty)),
TyKind::Ptr(ref mutable_type) => try_visit!(visitor.visit_ty_unambig(mutable_type.ty)),
TyKind::Ref(ref lifetime, ref mutable_type) => {
try_visit!(visitor.visit_lifetime(lifetime));
try_visit!(visitor.visit_ty_unambig(mutable_type.ty));
}
TyKind::Never => {}
TyKind::Tup(tuple_element_types) => {
walk_list!(visitor, visit_ty_unambig, tuple_element_types);
}
TyKind::FnPtr(ref function_declaration) => {
walk_list!(visitor, visit_generic_param, function_declaration.generic_params);
try_visit!(visitor.visit_fn_decl(function_declaration.decl));
}
TyKind::UnsafeBinder(ref unsafe_binder) => {
walk_list!(visitor, visit_generic_param, unsafe_binder.generic_params);
try_visit!(visitor.visit_ty_unambig(unsafe_binder.inner_ty));
}
TyKind::Path(ref qpath) => {
try_visit!(visitor.visit_qpath(qpath, typ.hir_id, typ.span));
}
TyKind::OpaqueDef(opaque) => {
try_visit!(visitor.visit_opaque_ty(opaque));
}
TyKind::TraitAscription(bounds) => {
walk_list!(visitor, visit_param_bound, bounds);
}
TyKind::Array(ref ty, ref length) => {
try_visit!(visitor.visit_ty_unambig(ty));
try_visit!(visitor.visit_const_arg_unambig(length));
}
TyKind::TraitObject(bounds, ref lifetime) => {
for bound in bounds {
try_visit!(visitor.visit_poly_trait_ref(bound));
}
try_visit!(visitor.visit_lifetime(lifetime));
}
TyKind::InferDelegation(..) | TyKind::Err(_) => {}
TyKind::Pat(ty, pat) => {
try_visit!(visitor.visit_ty_unambig(ty));
try_visit!(visitor.visit_pattern_type_pattern(pat));
}
}
V::Result::output()
}
pub fn walk_const_item_rhs<'v, V: Visitor<'v>>(
visitor: &mut V,
ct_rhs: ConstItemRhs<'v>,
) -> V::Result {
match ct_rhs {
ConstItemRhs::Body(body_id) => visitor.visit_nested_body(body_id),
ConstItemRhs::TypeConst(const_arg) => visitor.visit_const_arg_unambig(const_arg),
}
}
pub fn walk_unambig_const_arg<'v, V: Visitor<'v>>(
visitor: &mut V,
const_arg: &'v ConstArg<'v>,
) -> V::Result {
match const_arg.try_as_ambig_ct() {
Some(ambig_ct) => visitor.visit_const_arg(ambig_ct),
None => {
let ConstArg { hir_id, kind: _, span } = const_arg;
visitor.visit_infer(*hir_id, *span, InferKind::Const(const_arg))
}
}
}
pub fn walk_const_arg<'v, V: Visitor<'v>>(
visitor: &mut V,
const_arg: &'v ConstArg<'v, AmbigArg>,
) -> V::Result {
let ConstArg { hir_id, kind, span: _ } = const_arg;
try_visit!(visitor.visit_id(*hir_id));
match kind {
ConstArgKind::Tup(exprs) => {
walk_list!(visitor, visit_const_arg, *exprs);
V::Result::output()
}
ConstArgKind::Struct(qpath, field_exprs) => {
try_visit!(visitor.visit_qpath(qpath, *hir_id, qpath.span()));
for field_expr in *field_exprs {
try_visit!(visitor.visit_const_arg_expr_field(field_expr));
}
V::Result::output()
}
ConstArgKind::TupleCall(qpath, args) => {
try_visit!(visitor.visit_qpath(qpath, *hir_id, qpath.span()));
for arg in *args {
try_visit!(visitor.visit_const_arg_unambig(*arg));
}
V::Result::output()
}
ConstArgKind::Array(array_expr) => {
for arg in array_expr.elems {
try_visit!(visitor.visit_const_arg_unambig(*arg));
}
V::Result::output()
}
ConstArgKind::Path(qpath) => visitor.visit_qpath(qpath, *hir_id, qpath.span()),
ConstArgKind::Anon(anon) => visitor.visit_anon_const(*anon),
ConstArgKind::Error(_) => V::Result::output(), // errors and spans are not important
ConstArgKind::Literal { .. } => V::Result::output(), // FIXME(mcga)
}
}
pub fn walk_generic_param<'v, V: Visitor<'v>>(
visitor: &mut V,
param: &'v GenericParam<'v>,
) -> V::Result {
let GenericParam {
hir_id,
def_id: _,
name,
span: _,
pure_wrt_drop: _,
kind,
colon_span: _,
source: _,
} = param;
try_visit!(visitor.visit_id(*hir_id));
match *name {
ParamName::Plain(ident) | ParamName::Error(ident) => try_visit!(visitor.visit_ident(ident)),
ParamName::Fresh => {}
}
match *kind {
GenericParamKind::Lifetime { .. } => {}
GenericParamKind::Type { ref default, .. } => {
visit_opt!(visitor, visit_ty_unambig, default)
}
GenericParamKind::Const { ref ty, ref default } => {
try_visit!(visitor.visit_ty_unambig(ty));
if let Some(default) = default {
try_visit!(visitor.visit_const_param_default(*hir_id, default));
}
}
}
V::Result::output()
}
pub fn walk_const_param_default<'v, V: Visitor<'v>>(
visitor: &mut V,
ct: &'v ConstArg<'v>,
) -> V::Result {
visitor.visit_const_arg_unambig(ct)
}
pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics<'v>) -> V::Result {
let &Generics {
params,
predicates,
has_where_clause_predicates: _,
where_clause_span: _,
span: _,
} = generics;
walk_list!(visitor, visit_generic_param, params);
walk_list!(visitor, visit_where_predicate, predicates);
V::Result::output()
}
pub fn walk_where_predicate<'v, V: Visitor<'v>>(
visitor: &mut V,
predicate: &'v WherePredicate<'v>,
) -> V::Result {
let &WherePredicate { hir_id, kind, span: _ } = predicate;
try_visit!(visitor.visit_id(hir_id));
match *kind {
WherePredicateKind::BoundPredicate(WhereBoundPredicate {
ref bounded_ty,
bounds,
bound_generic_params,
origin: _,
}) => {
try_visit!(visitor.visit_ty_unambig(bounded_ty));
walk_list!(visitor, visit_param_bound, bounds);
walk_list!(visitor, visit_generic_param, bound_generic_params);
}
WherePredicateKind::RegionPredicate(WhereRegionPredicate {
ref lifetime,
bounds,
in_where_clause: _,
}) => {
try_visit!(visitor.visit_lifetime(lifetime));
walk_list!(visitor, visit_param_bound, bounds);
}
WherePredicateKind::EqPredicate(WhereEqPredicate { ref lhs_ty, ref rhs_ty }) => {
try_visit!(visitor.visit_ty_unambig(lhs_ty));
try_visit!(visitor.visit_ty_unambig(rhs_ty));
}
}
V::Result::output()
}
pub fn walk_fn_decl<'v, V: Visitor<'v>>(
visitor: &mut V,
function_declaration: &'v FnDecl<'v>,
) -> V::Result {
let FnDecl { inputs, output, c_variadic: _, implicit_self: _, lifetime_elision_allowed: _ } =
function_declaration;
walk_list!(visitor, visit_ty_unambig, *inputs);
visitor.visit_fn_ret_ty(output)
}
pub fn walk_fn_ret_ty<'v, V: Visitor<'v>>(visitor: &mut V, ret_ty: &'v FnRetTy<'v>) -> V::Result {
if let FnRetTy::Return(output_ty) = *ret_ty {
try_visit!(visitor.visit_ty_unambig(output_ty));
}
V::Result::output()
}
pub fn walk_fn<'v, V: Visitor<'v>>(
visitor: &mut V,
function_kind: FnKind<'v>,
function_declaration: &'v FnDecl<'v>,
body_id: BodyId,
_: LocalDefId,
) -> V::Result {
try_visit!(visitor.visit_fn_decl(function_declaration));
try_visit!(walk_fn_kind(visitor, function_kind));
visitor.visit_nested_body(body_id)
}
pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<'v>) -> V::Result {
match function_kind {
FnKind::ItemFn(_, generics, ..) => {
try_visit!(visitor.visit_generics(generics));
}
FnKind::Closure | FnKind::Method(..) => {}
}
V::Result::output()
}
pub fn walk_use<'v, V: Visitor<'v>>(
visitor: &mut V,
path: &'v UsePath<'v>,
hir_id: HirId,
) -> V::Result {
let UsePath { segments, ref res, span } = *path;
for res in res.present_items() {
try_visit!(visitor.visit_path(&Path { segments, res, span }, hir_id));
}
V::Result::output()
}
pub fn walk_trait_item<'v, V: Visitor<'v>>(
visitor: &mut V,
trait_item: &'v TraitItem<'v>,
) -> V::Result {
let TraitItem {
ident,
generics,
ref defaultness,
ref kind,
span,
owner_id: _,
has_delayed_lints: _,
} = *trait_item;
let hir_id = trait_item.hir_id();
try_visit!(visitor.visit_ident(ident));
try_visit!(visitor.visit_generics(&generics));
try_visit!(visitor.visit_defaultness(&defaultness));
try_visit!(visitor.visit_id(hir_id));
match *kind {
TraitItemKind::Const(ref ty, default, _) => {
try_visit!(visitor.visit_ty_unambig(ty));
visit_opt!(visitor, visit_const_item_rhs, default);
}
TraitItemKind::Fn(ref sig, TraitFn::Required(param_idents)) => {
try_visit!(visitor.visit_fn_decl(sig.decl));
for ident in param_idents.iter().copied() {
visit_opt!(visitor, visit_ident, ident);
}
}
TraitItemKind::Fn(ref sig, TraitFn::Provided(body_id)) => {
try_visit!(visitor.visit_fn(
FnKind::Method(ident, sig),
sig.decl,
body_id,
span,
trait_item.owner_id.def_id,
));
}
TraitItemKind::Type(bounds, ref default) => {
walk_list!(visitor, visit_param_bound, bounds);
visit_opt!(visitor, visit_ty_unambig, default);
}
}
V::Result::output()
}
pub fn walk_trait_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, id: TraitItemId) -> V::Result {
visitor.visit_nested_trait_item(id)
}
pub fn walk_impl_item<'v, V: Visitor<'v>>(
visitor: &mut V,
impl_item: &'v ImplItem<'v>,
) -> V::Result {
let ImplItem {
owner_id: _,
ident,
ref generics,
ref impl_kind,
ref kind,
span: _,
has_delayed_lints: _,
} = *impl_item;
try_visit!(visitor.visit_ident(ident));
try_visit!(visitor.visit_generics(generics));
try_visit!(visitor.visit_id(impl_item.hir_id()));
match impl_kind {
ImplItemImplKind::Inherent { vis_span: _ } => {}
ImplItemImplKind::Trait { defaultness, trait_item_def_id: _ } => {
try_visit!(visitor.visit_defaultness(defaultness));
}
}
match *kind {
ImplItemKind::Const(ref ty, rhs) => {
try_visit!(visitor.visit_ty_unambig(ty));
visitor.visit_const_item_rhs(rhs)
}
ImplItemKind::Fn(ref sig, body_id) => visitor.visit_fn(
FnKind::Method(impl_item.ident, sig),
sig.decl,
body_id,
impl_item.span,
impl_item.owner_id.def_id,
),
ImplItemKind::Type(ref ty) => visitor.visit_ty_unambig(ty),
}
}
pub fn walk_foreign_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, id: ForeignItemId) -> V::Result {
visitor.visit_nested_foreign_item(id)
}
pub fn walk_impl_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, id: ImplItemId) -> V::Result {
visitor.visit_nested_impl_item(id)
}
pub fn walk_trait_ref<'v, V: Visitor<'v>>(
visitor: &mut V,
trait_ref: &'v TraitRef<'v>,
) -> V::Result {
let TraitRef { hir_ref_id, path } = trait_ref;
try_visit!(visitor.visit_id(*hir_ref_id));
visitor.visit_path(*path, *hir_ref_id)
}
pub fn walk_param_bound<'v, V: Visitor<'v>>(
visitor: &mut V,
bound: &'v GenericBound<'v>,
) -> V::Result {
match *bound {
GenericBound::Trait(ref typ) => visitor.visit_poly_trait_ref(typ),
GenericBound::Outlives(ref lifetime) => visitor.visit_lifetime(lifetime),
GenericBound::Use(args, _) => {
walk_list!(visitor, visit_precise_capturing_arg, args);
V::Result::output()
}
}
}
pub fn walk_precise_capturing_arg<'v, V: Visitor<'v>>(
visitor: &mut V,
arg: &'v PreciseCapturingArg<'v>,
) -> V::Result {
match *arg {
PreciseCapturingArg::Lifetime(lt) => visitor.visit_lifetime(lt),
PreciseCapturingArg::Param(param) => {
let PreciseCapturingNonLifetimeArg { hir_id, ident, res: _ } = param;
try_visit!(visitor.visit_id(hir_id));
visitor.visit_ident(ident)
}
}
}
pub fn walk_poly_trait_ref<'v, V: Visitor<'v>>(
visitor: &mut V,
trait_ref: &'v PolyTraitRef<'v>,
) -> V::Result {
let PolyTraitRef { bound_generic_params, modifiers: _, trait_ref, span: _ } = trait_ref;
walk_list!(visitor, visit_generic_param, *bound_generic_params);
visitor.visit_trait_ref(trait_ref)
}
pub fn walk_opaque_ty<'v, V: Visitor<'v>>(visitor: &mut V, opaque: &'v OpaqueTy<'v>) -> V::Result {
let &OpaqueTy { hir_id, def_id: _, bounds, origin: _, span: _ } = opaque;
try_visit!(visitor.visit_id(hir_id));
walk_list!(visitor, visit_param_bound, bounds);
V::Result::output()
}
pub fn walk_struct_def<'v, V: Visitor<'v>>(
visitor: &mut V,
struct_definition: &'v VariantData<'v>,
) -> V::Result {
visit_opt!(visitor, visit_id, struct_definition.ctor_hir_id());
walk_list!(visitor, visit_field_def, struct_definition.fields());
V::Result::output()
}
pub fn walk_field_def<'v, V: Visitor<'v>>(
visitor: &mut V,
FieldDef { hir_id, ident, ty, default, span: _, vis_span: _, def_id: _, safety: _ }: &'v FieldDef<'v>,
) -> V::Result {
try_visit!(visitor.visit_id(*hir_id));
try_visit!(visitor.visit_ident(*ident));
visit_opt!(visitor, visit_anon_const, default);
visitor.visit_ty_unambig(*ty)
}
pub fn walk_enum_def<'v, V: Visitor<'v>>(
visitor: &mut V,
enum_definition: &'v EnumDef<'v>,
) -> V::Result {
let EnumDef { variants } = enum_definition;
walk_list!(visitor, visit_variant, *variants);
V::Result::output()
}
pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V, variant: &'v Variant<'v>) -> V::Result {
let Variant { ident, hir_id, def_id: _, data, disr_expr, span: _ } = variant;
try_visit!(visitor.visit_ident(*ident));
try_visit!(visitor.visit_id(*hir_id));
try_visit!(visitor.visit_variant_data(data));
visit_opt!(visitor, visit_anon_const, disr_expr);
V::Result::output()
}
pub fn walk_label<'v, V: Visitor<'v>>(visitor: &mut V, label: &'v Label) -> V::Result {
let Label { ident } = label;
visitor.visit_ident(*ident)
}
pub fn walk_inf<'v, V: Visitor<'v>>(visitor: &mut V, inf: &'v InferArg) -> V::Result {
let InferArg { hir_id, span: _ } = inf;
visitor.visit_id(*hir_id)
}
pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) -> V::Result {
let Lifetime { hir_id, ident, kind: _, source: _, syntax: _ } = lifetime;
try_visit!(visitor.visit_id(*hir_id));
visitor.visit_ident(*ident)
}
pub fn walk_qpath<'v, V: Visitor<'v>>(
visitor: &mut V,
qpath: &'v QPath<'v>,
id: HirId,
) -> V::Result {
match *qpath {
QPath::Resolved(ref maybe_qself, ref path) => {
visit_opt!(visitor, visit_ty_unambig, maybe_qself);
visitor.visit_path(path, id)
}
QPath::TypeRelative(ref qself, ref segment) => {
try_visit!(visitor.visit_ty_unambig(qself));
visitor.visit_path_segment(segment)
}
}
}
pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &Path<'v>) -> V::Result {
let Path { segments, span: _, res: _ } = path;
walk_list!(visitor, visit_path_segment, *segments);
V::Result::output()
}
pub fn walk_path_segment<'v, V: Visitor<'v>>(
visitor: &mut V,
segment: &'v PathSegment<'v>,
) -> V::Result {
let PathSegment { ident, hir_id, res: _, args, infer_args: _ } = segment;
try_visit!(visitor.visit_ident(*ident));
try_visit!(visitor.visit_id(*hir_id));
visit_opt!(visitor, visit_generic_args, *args);
V::Result::output()
}
pub fn walk_generic_args<'v, V: Visitor<'v>>(
visitor: &mut V,
generic_args: &'v GenericArgs<'v>,
) -> V::Result {
let GenericArgs { args, constraints, parenthesized: _, span_ext: _ } = generic_args;
walk_list!(visitor, visit_generic_arg, *args);
walk_list!(visitor, visit_assoc_item_constraint, *constraints);
V::Result::output()
}
pub fn walk_assoc_item_constraint<'v, V: Visitor<'v>>(
visitor: &mut V,
constraint: &'v AssocItemConstraint<'v>,
) -> V::Result {
let AssocItemConstraint { hir_id, ident, gen_args, kind: _, span: _ } = constraint;
try_visit!(visitor.visit_id(*hir_id));
try_visit!(visitor.visit_ident(*ident));
try_visit!(visitor.visit_generic_args(*gen_args));
match constraint.kind {
AssocItemConstraintKind::Equality { ref term } => match term {
Term::Ty(ty) => try_visit!(visitor.visit_ty_unambig(ty)),
Term::Const(c) => try_visit!(visitor.visit_const_arg_unambig(c)),
},
AssocItemConstraintKind::Bound { bounds } => {
walk_list!(visitor, visit_param_bound, bounds)
}
}
V::Result::output()
}
pub fn walk_defaultness<'v, V: Visitor<'v>>(_: &mut V, _: &'v Defaultness) -> V::Result {
// No visitable content here: this fn exists so you can call it if
// the right thing to do, should content be added in the future,
// would be to walk it.
V::Result::output()
}
pub fn walk_inline_asm<'v, V: Visitor<'v>>(
visitor: &mut V,
asm: &'v InlineAsm<'v>,
id: HirId,
) -> V::Result {
for (op, op_sp) in asm.operands {
match op {
InlineAsmOperand::In { expr, .. } | InlineAsmOperand::InOut { expr, .. } => {
try_visit!(visitor.visit_expr(expr));
}
InlineAsmOperand::Out { expr, .. } => {
visit_opt!(visitor, visit_expr, expr);
}
InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => {
try_visit!(visitor.visit_expr(in_expr));
visit_opt!(visitor, visit_expr, out_expr);
}
InlineAsmOperand::Const { anon_const, .. } => {
try_visit!(visitor.visit_inline_const(anon_const));
}
InlineAsmOperand::SymFn { expr, .. } => {
try_visit!(visitor.visit_expr(expr));
}
InlineAsmOperand::SymStatic { path, .. } => {
try_visit!(visitor.visit_qpath(path, id, *op_sp));
}
InlineAsmOperand::Label { block } => try_visit!(visitor.visit_block(block)),
}
}
V::Result::output()
}