rust/compiler/rustc_hir/src/intravisit.rs

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

1521 lines
58 KiB
Rust
Raw Permalink Normal View History

//! 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
2019-02-08 13:53:55 +00:00
//! notes on how to do so:
//!
//! Each overridden visit method has full control over what
2015-07-31 07:04:06 +00:00
//! 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
2015-07-31 07:04:06 +00:00
//! 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.
2015-07-31 07:04:06 +00:00
//!
//! 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
2023-10-19 21:46:28 +00:00
//! example coroutine inference, and possibly also HIR borrowck.
2015-07-31 07:04:06 +00:00
2024-10-16 23:14:01 +00:00
use rustc_ast::Label;
2024-02-24 20:22:42 +00:00
use rustc_ast::visit::{VisitorResult, try_visit, visit_opt, walk_list};
use rustc_span::def_id::LocalDefId;
use rustc_span::{Ident, Span, Symbol};
2015-07-31 07:04:06 +00:00
2020-01-07 16:30:29 +00:00
use crate::hir::*;
2020-01-02 03:18:51 +00:00
pub trait IntoVisitor<'hir> {
type Visitor: Visitor<'hir>;
fn into_visitor(&self) -> Self::Visitor;
}
#[derive(Copy, Clone, Debug)]
2015-07-31 07:04:06 +00:00
pub enum FnKind<'a> {
2019-01-03 19:28:20 +00:00
/// `#[xxx] pub async/const/extern "Abi" fn foo()`
2022-02-13 14:40:08 +00:00
ItemFn(Ident, &'a Generics<'a>, FnHeader),
2015-07-31 07:04:06 +00:00
2019-01-03 19:28:20 +00:00
/// `fn foo(&self)`
2022-02-13 14:40:08 +00:00
Method(Ident, &'a FnSig<'a>),
2015-07-31 07:04:06 +00:00
2019-01-03 19:28:20 +00:00
/// `|x, y| {}`
2020-11-27 08:24:42 +00:00
Closure,
}
impl<'a> FnKind<'a> {
pub fn header(&self) -> Option<&FnHeader> {
2019-04-18 17:44:55 +00:00
match *self {
2022-02-13 14:40:08 +00:00
FnKind::ItemFn(_, _, ref header) => Some(header),
FnKind::Method(_, ref sig) => Some(&sig.header),
2020-11-27 08:24:42 +00:00
FnKind::Closure => None,
2019-04-18 17:44:55 +00:00
}
}
2021-10-19 21:31:51 +00:00
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)
}
2015-07-31 07:04:06 +00:00
}
/// 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>;
2020-01-07 16:25:33 +00:00
}
// 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;
2020-03-11 11:05:32 +00:00
2022-04-30 17:27:01 +00:00
/// 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;
2020-11-11 20:57:54 +00:00
}
2020-03-11 11:05:32 +00:00
/// 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.
2016-11-28 19:51:19 +00:00
///
/// 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;
}
2016-10-28 20:58:32 +00:00
}
use nested_filter::NestedFilter;
2015-07-31 07:04:06 +00:00
/// Each method of the Visitor trait is a hook to be potentially
2019-02-08 13:53:55 +00:00
/// overridden. Each method's default implementation recursively visits
2015-07-31 07:04:06 +00:00
/// the substructure of the input via the corresponding `walk` method;
/// e.g., the `visit_mod` method by default calls `intravisit::walk_mod`.
2015-07-31 07:04:06 +00:00
///
/// 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.
///
2015-07-31 07:04:06 +00:00
/// If you want to ensure that your code handles every variant
2019-02-08 13:53:55 +00:00
/// explicitly, you need to override each method. (And you also need
2015-07-31 07:04:06 +00:00
/// 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;
2020-01-07 16:25:33 +00:00
///////////////////////////////////////////////////////////////////////////
// Nested items.
2022-04-30 17:27:01 +00:00
/// 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
2022-04-30 17:27:01 +00:00
/// `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 = ();
2022-04-30 17:27:01 +00:00
/// 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)"
);
}
2022-04-30 17:27:01 +00:00
/// 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
2022-04-30 17:27:01 +00:00
/// 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()
}
2020-11-26 18:11:43 +00:00
/// Like `visit_nested_item()`, but for foreign items. See
2020-11-11 20:57:54 +00:00
/// `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()
2020-11-11 20:57:54 +00:00
}
2016-10-28 20:58:32 +00:00
/// Invoked to visit the body of a function, method or closure. Like
2022-04-30 17:27:01 +00:00
/// `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()
2016-10-28 20:58:32 +00:00
}
fn visit_param(&mut self, param: &'v Param<'v>) -> Self::Result {
walk_param(self, param)
2019-07-26 22:52:37 +00:00
}
2019-02-08 13:53:55 +00:00
/// 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()
2015-07-31 07:04:06 +00:00
}
fn visit_ident(&mut self, ident: Ident) -> Self::Result {
2018-05-25 23:50:15 +00:00
walk_ident(self, ident)
}
fn visit_mod(&mut self, m: &'v Mod<'v>, _s: Span, _n: HirId) -> Self::Result {
walk_mod(self, m)
2015-09-27 19:23:31 +00:00
}
fn visit_foreign_item(&mut self, i: &'v ForeignItem<'v>) -> Self::Result {
2015-09-27 19:23:31 +00:00
walk_foreign_item(self, i)
}
fn visit_local(&mut self, l: &'v LetStmt<'v>) -> Self::Result {
walk_local(self, l)
2015-09-27 19:23:31 +00:00
}
fn visit_block(&mut self, b: &'v Block<'v>) -> Self::Result {
2015-09-27 19:23:31 +00:00
walk_block(self, b)
}
fn visit_stmt(&mut self, s: &'v Stmt<'v>) -> Self::Result {
2015-09-27 19:23:31 +00:00
walk_stmt(self, s)
}
fn visit_arm(&mut self, a: &'v Arm<'v>) -> Self::Result {
2015-09-27 19:23:31 +00:00
walk_arm(self, a)
}
fn visit_pat(&mut self, p: &'v Pat<'v>) -> Self::Result {
2015-09-27 19:23:31 +00:00
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: &'v 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.
///
/// See the doc comments on [`Ty`] for an explanation of what it means for a type to be
/// ambiguous.
///
/// 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)
}
/// 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.
///
/// See the doc comments on [`ConstArg`] for an explanation of what it means for a const to be
/// ambiguous.
///
/// 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_ambig_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 {
2015-09-27 19:23:31 +00:00
walk_expr(self, ex)
}
fn visit_expr_field(&mut self, field: &'v ExprField<'v>) -> Self::Result {
walk_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 {
2021-03-01 11:50:09 +00:00
walk_const_param_default(self, ct)
}
fn visit_generics(&mut self, g: &'v Generics<'v>) -> Self::Result {
2015-09-27 19:23:31 +00:00
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 {
2022-10-26 17:40:34 +00:00
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)
2015-07-31 07:04:06 +00:00
}
fn visit_use(&mut self, path: &'v UsePath<'v>, hir_id: HirId) -> Self::Result {
2019-02-06 13:16:11 +00:00
walk_use(self, path, hir_id)
}
fn visit_trait_item(&mut self, ti: &'v TraitItem<'v>) -> Self::Result {
2015-09-27 19:23:31 +00:00
walk_trait_item(self, ti)
}
fn visit_trait_item_ref(&mut self, ii: &'v TraitItemRef) -> Self::Result {
walk_trait_item_ref(self, ii)
}
fn visit_impl_item(&mut self, ii: &'v ImplItem<'v>) -> Self::Result {
2015-09-27 19:23:31 +00:00
walk_impl_item(self, ii)
}
fn visit_foreign_item_ref(&mut self, ii: &'v ForeignItemRef) -> Self::Result {
2020-11-11 20:57:54 +00:00
walk_foreign_item_ref(self, ii)
}
fn visit_impl_item_ref(&mut self, ii: &'v ImplItemRef) -> Self::Result {
walk_impl_item_ref(self, ii)
}
fn visit_trait_ref(&mut self, t: &'v TraitRef<'v>) -> Self::Result {
2015-09-27 19:23:31 +00:00
walk_trait_ref(self, t)
}
fn visit_param_bound(&mut self, bounds: &'v GenericBound<'v>) -> Self::Result {
walk_param_bound(self, bounds)
2015-07-31 07:04:06 +00:00
}
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)
2015-07-31 07:04:06 +00:00
}
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 {
2015-07-31 07:04:06 +00:00
walk_struct_def(self, s)
}
fn visit_field_def(&mut self, s: &'v FieldDef<'v>) -> Self::Result {
walk_field_def(self, s)
2015-09-27 19:23:31 +00:00
}
fn visit_enum_def(&mut self, enum_definition: &'v EnumDef<'v>) -> Self::Result {
walk_enum_def(self, enum_definition)
2015-07-31 07:04:06 +00:00
}
fn visit_variant(&mut self, v: &'v Variant<'v>) -> Self::Result {
walk_variant(self, v)
2015-09-27 19:23:31 +00:00
}
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 {
2015-07-31 07:04:06 +00:00
walk_path(self, path)
}
fn visit_path_segment(&mut self, path_segment: &'v PathSegment<'v>) -> Self::Result {
walk_path_segment(self, path_segment)
2015-07-31 07:04:06 +00:00
}
fn visit_generic_args(&mut self, generic_args: &'v GenericArgs<'v>) -> Self::Result {
walk_generic_args(self, generic_args)
2015-07-31 07:04:06 +00:00
}
fn visit_assoc_item_constraint(
&mut self,
constraint: &'v AssocItemConstraint<'v>,
) -> Self::Result {
walk_assoc_item_constraint(self, constraint)
2015-07-31 07:04:06 +00:00
}
fn visit_attribute(&mut self, _attr: &'v Attribute) -> Self::Result {
Self::Result::output()
}
fn visit_associated_item_kind(&mut self, kind: &'v AssocItemKind) -> Self::Result {
walk_associated_item_kind(self, kind)
}
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.
2025-01-19 00:19:42 +00:00
///
/// Named `visit_ty_unambig` instead of `visit_unambig_ty` to aid in discovery
/// by IDes when `v.visit_ty` is written.
2025-01-18 22:45:41 +00:00
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.
2025-01-19 00:19:42 +00:00
///
/// Named `visit_const_arg_unambig` instead of `visit_unambig_const_arg` to aid in
/// discovery by IDes when `v.visit_const_arg` is written.
2025-01-18 22:45:41 +00:00
fn visit_const_arg_unambig(&mut self, c: &'v ConstArg<'v>) -> Self::Result {
walk_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 {
2025-06-02 20:01:07 +00:00
let Param { hir_id, pat, ty_span: _, span: _ } = param;
try_visit!(visitor.visit_id(*hir_id));
visitor.visit_pat(pat)
2019-07-26 22:52:37 +00:00
}
pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::Result {
2025-06-02 20:01:07 +00:00
let Item { owner_id: _, kind, span: _, vis_span: _ } = item;
try_visit!(visitor.visit_id(item.hir_id()));
2025-06-02 20:01:07 +00:00
match *kind {
Move `hir::Item::ident` into `hir::ItemKind`. `hir::Item` has an `ident` field. - It's always non-empty for these item kinds: `ExternCrate`, `Static`, `Const`, `Fn`, `Macro`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`, Trait`, TraitAalis`. - It's always empty for these item kinds: `ForeignMod`, `GlobalAsm`, `Impl`. - For `Use`, it is non-empty for `UseKind::Single` and empty for `UseKind::{Glob,ListStem}`. All of this is quite non-obvious; the only documentation is a single comment saying "The name might be a dummy name in case of anonymous items". Some sites that handle items check for an empty ident, some don't. This is a very C-like way of doing things, but this is Rust, we have sum types, we can do this properly and never forget to check for the exceptional case and never YOLO possibly empty identifiers (or possibly dummy spans) around and hope that things will work out. The commit is large but it's mostly obvious plumbing work. Some notable things. - A similar transformation makes sense for `ast::Item`, but this is already a big change. That can be done later. - Lots of assertions are added to item lowering to ensure that identifiers are empty/non-empty as expected. These will be removable when `ast::Item` is done later. - `ItemKind::Use` doesn't get an `Ident`, but `UseKind::Single` does. - `lower_use_tree` is significantly simpler. No more confusing `&mut Ident` to deal with. - `ItemKind::ident` is a new method, it returns an `Option<Ident>`. It's used with `unwrap` in a few places; sometimes it's hard to tell exactly which item kinds might occur. None of these unwraps fail on the test suite. It's conceivable that some might fail on alternative input. We can deal with those if/when they happen. - In `trait_path` the `find_map`/`if let` is replaced with a loop, and things end up much clearer that way. - `named_span` no longer checks for an empty name; instead the call site now checks for a missing identifier if necessary. - `maybe_inline_local` doesn't need the `glob` argument, it can be computed in-function from the `renamed` argument. - `arbitrary_source_item_ordering::check_mod` had a big `if` statement that was just getting the ident from the item kinds that had one. It could be mostly replaced by a single call to the new `ItemKind::ident` method. - `ItemKind` grows from 56 to 64 bytes, but `Item` stays the same size, and that's what matters, because `ItemKind` only occurs within `Item`.
2025-03-06 08:07:36 +00:00
ItemKind::ExternCrate(orig_name, ident) => {
visit_opt!(visitor, visit_name, orig_name);
Move `hir::Item::ident` into `hir::ItemKind`. `hir::Item` has an `ident` field. - It's always non-empty for these item kinds: `ExternCrate`, `Static`, `Const`, `Fn`, `Macro`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`, Trait`, TraitAalis`. - It's always empty for these item kinds: `ForeignMod`, `GlobalAsm`, `Impl`. - For `Use`, it is non-empty for `UseKind::Single` and empty for `UseKind::{Glob,ListStem}`. All of this is quite non-obvious; the only documentation is a single comment saying "The name might be a dummy name in case of anonymous items". Some sites that handle items check for an empty ident, some don't. This is a very C-like way of doing things, but this is Rust, we have sum types, we can do this properly and never forget to check for the exceptional case and never YOLO possibly empty identifiers (or possibly dummy spans) around and hope that things will work out. The commit is large but it's mostly obvious plumbing work. Some notable things. - A similar transformation makes sense for `ast::Item`, but this is already a big change. That can be done later. - Lots of assertions are added to item lowering to ensure that identifiers are empty/non-empty as expected. These will be removable when `ast::Item` is done later. - `ItemKind::Use` doesn't get an `Ident`, but `UseKind::Single` does. - `lower_use_tree` is significantly simpler. No more confusing `&mut Ident` to deal with. - `ItemKind::ident` is a new method, it returns an `Option<Ident>`. It's used with `unwrap` in a few places; sometimes it's hard to tell exactly which item kinds might occur. None of these unwraps fail on the test suite. It's conceivable that some might fail on alternative input. We can deal with those if/when they happen. - In `trait_path` the `find_map`/`if let` is replaced with a loop, and things end up much clearer that way. - `named_span` no longer checks for an empty name; instead the call site now checks for a missing identifier if necessary. - `maybe_inline_local` doesn't need the `glob` argument, it can be computed in-function from the `renamed` argument. - `arbitrary_source_item_ordering::check_mod` had a big `if` statement that was just getting the ident from the item kinds that had one. It could be mostly replaced by a single call to the new `ItemKind::ident` method. - `ItemKind` grows from 56 to 64 bytes, but `Item` stays the same size, and that's what matters, because `ItemKind` only occurs within `Item`.
2025-03-06 08:07:36 +00:00
try_visit!(visitor.visit_ident(ident));
}
Move `hir::Item::ident` into `hir::ItemKind`. `hir::Item` has an `ident` field. - It's always non-empty for these item kinds: `ExternCrate`, `Static`, `Const`, `Fn`, `Macro`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`, Trait`, TraitAalis`. - It's always empty for these item kinds: `ForeignMod`, `GlobalAsm`, `Impl`. - For `Use`, it is non-empty for `UseKind::Single` and empty for `UseKind::{Glob,ListStem}`. All of this is quite non-obvious; the only documentation is a single comment saying "The name might be a dummy name in case of anonymous items". Some sites that handle items check for an empty ident, some don't. This is a very C-like way of doing things, but this is Rust, we have sum types, we can do this properly and never forget to check for the exceptional case and never YOLO possibly empty identifiers (or possibly dummy spans) around and hope that things will work out. The commit is large but it's mostly obvious plumbing work. Some notable things. - A similar transformation makes sense for `ast::Item`, but this is already a big change. That can be done later. - Lots of assertions are added to item lowering to ensure that identifiers are empty/non-empty as expected. These will be removable when `ast::Item` is done later. - `ItemKind::Use` doesn't get an `Ident`, but `UseKind::Single` does. - `lower_use_tree` is significantly simpler. No more confusing `&mut Ident` to deal with. - `ItemKind::ident` is a new method, it returns an `Option<Ident>`. It's used with `unwrap` in a few places; sometimes it's hard to tell exactly which item kinds might occur. None of these unwraps fail on the test suite. It's conceivable that some might fail on alternative input. We can deal with those if/when they happen. - In `trait_path` the `find_map`/`if let` is replaced with a loop, and things end up much clearer that way. - `named_span` no longer checks for an empty name; instead the call site now checks for a missing identifier if necessary. - `maybe_inline_local` doesn't need the `glob` argument, it can be computed in-function from the `renamed` argument. - `arbitrary_source_item_ordering::check_mod` had a big `if` statement that was just getting the ident from the item kinds that had one. It could be mostly replaced by a single call to the new `ItemKind::ident` method. - `ItemKind` grows from 56 to 64 bytes, but `Item` stays the same size, and that's what matters, because `ItemKind` only occurs within `Item`.
2025-03-06 08:07:36 +00:00
ItemKind::Use(ref path, kind) => {
try_visit!(visitor.visit_use(path, item.hir_id()));
Move `hir::Item::ident` into `hir::ItemKind`. `hir::Item` has an `ident` field. - It's always non-empty for these item kinds: `ExternCrate`, `Static`, `Const`, `Fn`, `Macro`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`, Trait`, TraitAalis`. - It's always empty for these item kinds: `ForeignMod`, `GlobalAsm`, `Impl`. - For `Use`, it is non-empty for `UseKind::Single` and empty for `UseKind::{Glob,ListStem}`. All of this is quite non-obvious; the only documentation is a single comment saying "The name might be a dummy name in case of anonymous items". Some sites that handle items check for an empty ident, some don't. This is a very C-like way of doing things, but this is Rust, we have sum types, we can do this properly and never forget to check for the exceptional case and never YOLO possibly empty identifiers (or possibly dummy spans) around and hope that things will work out. The commit is large but it's mostly obvious plumbing work. Some notable things. - A similar transformation makes sense for `ast::Item`, but this is already a big change. That can be done later. - Lots of assertions are added to item lowering to ensure that identifiers are empty/non-empty as expected. These will be removable when `ast::Item` is done later. - `ItemKind::Use` doesn't get an `Ident`, but `UseKind::Single` does. - `lower_use_tree` is significantly simpler. No more confusing `&mut Ident` to deal with. - `ItemKind::ident` is a new method, it returns an `Option<Ident>`. It's used with `unwrap` in a few places; sometimes it's hard to tell exactly which item kinds might occur. None of these unwraps fail on the test suite. It's conceivable that some might fail on alternative input. We can deal with those if/when they happen. - In `trait_path` the `find_map`/`if let` is replaced with a loop, and things end up much clearer that way. - `named_span` no longer checks for an empty name; instead the call site now checks for a missing identifier if necessary. - `maybe_inline_local` doesn't need the `glob` argument, it can be computed in-function from the `renamed` argument. - `arbitrary_source_item_ordering::check_mod` had a big `if` statement that was just getting the ident from the item kinds that had one. It could be mostly replaced by a single call to the new `ItemKind::ident` method. - `ItemKind` grows from 56 to 64 bytes, but `Item` stays the same size, and that's what matters, because `ItemKind` only occurs within `Item`.
2025-03-06 08:07:36 +00:00
match kind {
UseKind::Single(ident) => try_visit!(visitor.visit_ident(ident)),
UseKind::Glob | UseKind::ListStem => {}
}
2015-07-31 07:04:06 +00:00
}
ItemKind::Static(_, ident, ref typ, body) => {
Move `hir::Item::ident` into `hir::ItemKind`. `hir::Item` has an `ident` field. - It's always non-empty for these item kinds: `ExternCrate`, `Static`, `Const`, `Fn`, `Macro`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`, Trait`, TraitAalis`. - It's always empty for these item kinds: `ForeignMod`, `GlobalAsm`, `Impl`. - For `Use`, it is non-empty for `UseKind::Single` and empty for `UseKind::{Glob,ListStem}`. All of this is quite non-obvious; the only documentation is a single comment saying "The name might be a dummy name in case of anonymous items". Some sites that handle items check for an empty ident, some don't. This is a very C-like way of doing things, but this is Rust, we have sum types, we can do this properly and never forget to check for the exceptional case and never YOLO possibly empty identifiers (or possibly dummy spans) around and hope that things will work out. The commit is large but it's mostly obvious plumbing work. Some notable things. - A similar transformation makes sense for `ast::Item`, but this is already a big change. That can be done later. - Lots of assertions are added to item lowering to ensure that identifiers are empty/non-empty as expected. These will be removable when `ast::Item` is done later. - `ItemKind::Use` doesn't get an `Ident`, but `UseKind::Single` does. - `lower_use_tree` is significantly simpler. No more confusing `&mut Ident` to deal with. - `ItemKind::ident` is a new method, it returns an `Option<Ident>`. It's used with `unwrap` in a few places; sometimes it's hard to tell exactly which item kinds might occur. None of these unwraps fail on the test suite. It's conceivable that some might fail on alternative input. We can deal with those if/when they happen. - In `trait_path` the `find_map`/`if let` is replaced with a loop, and things end up much clearer that way. - `named_span` no longer checks for an empty name; instead the call site now checks for a missing identifier if necessary. - `maybe_inline_local` doesn't need the `glob` argument, it can be computed in-function from the `renamed` argument. - `arbitrary_source_item_ordering::check_mod` had a big `if` statement that was just getting the ident from the item kinds that had one. It could be mostly replaced by a single call to the new `ItemKind::ident` method. - `ItemKind` grows from 56 to 64 bytes, but `Item` stays the same size, and that's what matters, because `ItemKind` only occurs within `Item`.
2025-03-06 08:07:36 +00:00
try_visit!(visitor.visit_ident(ident));
2025-01-18 22:45:41 +00:00
try_visit!(visitor.visit_ty_unambig(typ));
try_visit!(visitor.visit_nested_body(body));
2015-07-31 07:04:06 +00:00
}
ItemKind::Const(ident, ref generics, ref typ, body) => {
Move `hir::Item::ident` into `hir::ItemKind`. `hir::Item` has an `ident` field. - It's always non-empty for these item kinds: `ExternCrate`, `Static`, `Const`, `Fn`, `Macro`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`, Trait`, TraitAalis`. - It's always empty for these item kinds: `ForeignMod`, `GlobalAsm`, `Impl`. - For `Use`, it is non-empty for `UseKind::Single` and empty for `UseKind::{Glob,ListStem}`. All of this is quite non-obvious; the only documentation is a single comment saying "The name might be a dummy name in case of anonymous items". Some sites that handle items check for an empty ident, some don't. This is a very C-like way of doing things, but this is Rust, we have sum types, we can do this properly and never forget to check for the exceptional case and never YOLO possibly empty identifiers (or possibly dummy spans) around and hope that things will work out. The commit is large but it's mostly obvious plumbing work. Some notable things. - A similar transformation makes sense for `ast::Item`, but this is already a big change. That can be done later. - Lots of assertions are added to item lowering to ensure that identifiers are empty/non-empty as expected. These will be removable when `ast::Item` is done later. - `ItemKind::Use` doesn't get an `Ident`, but `UseKind::Single` does. - `lower_use_tree` is significantly simpler. No more confusing `&mut Ident` to deal with. - `ItemKind::ident` is a new method, it returns an `Option<Ident>`. It's used with `unwrap` in a few places; sometimes it's hard to tell exactly which item kinds might occur. None of these unwraps fail on the test suite. It's conceivable that some might fail on alternative input. We can deal with those if/when they happen. - In `trait_path` the `find_map`/`if let` is replaced with a loop, and things end up much clearer that way. - `named_span` no longer checks for an empty name; instead the call site now checks for a missing identifier if necessary. - `maybe_inline_local` doesn't need the `glob` argument, it can be computed in-function from the `renamed` argument. - `arbitrary_source_item_ordering::check_mod` had a big `if` statement that was just getting the ident from the item kinds that had one. It could be mostly replaced by a single call to the new `ItemKind::ident` method. - `ItemKind` grows from 56 to 64 bytes, but `Item` stays the same size, and that's what matters, because `ItemKind` only occurs within `Item`.
2025-03-06 08:07:36 +00:00
try_visit!(visitor.visit_ident(ident));
try_visit!(visitor.visit_generics(generics));
try_visit!(visitor.visit_ty_unambig(typ));
try_visit!(visitor.visit_nested_body(body));
2023-05-04 14:40:57 +00:00
}
Move `hir::Item::ident` into `hir::ItemKind`. `hir::Item` has an `ident` field. - It's always non-empty for these item kinds: `ExternCrate`, `Static`, `Const`, `Fn`, `Macro`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`, Trait`, TraitAalis`. - It's always empty for these item kinds: `ForeignMod`, `GlobalAsm`, `Impl`. - For `Use`, it is non-empty for `UseKind::Single` and empty for `UseKind::{Glob,ListStem}`. All of this is quite non-obvious; the only documentation is a single comment saying "The name might be a dummy name in case of anonymous items". Some sites that handle items check for an empty ident, some don't. This is a very C-like way of doing things, but this is Rust, we have sum types, we can do this properly and never forget to check for the exceptional case and never YOLO possibly empty identifiers (or possibly dummy spans) around and hope that things will work out. The commit is large but it's mostly obvious plumbing work. Some notable things. - A similar transformation makes sense for `ast::Item`, but this is already a big change. That can be done later. - Lots of assertions are added to item lowering to ensure that identifiers are empty/non-empty as expected. These will be removable when `ast::Item` is done later. - `ItemKind::Use` doesn't get an `Ident`, but `UseKind::Single` does. - `lower_use_tree` is significantly simpler. No more confusing `&mut Ident` to deal with. - `ItemKind::ident` is a new method, it returns an `Option<Ident>`. It's used with `unwrap` in a few places; sometimes it's hard to tell exactly which item kinds might occur. None of these unwraps fail on the test suite. It's conceivable that some might fail on alternative input. We can deal with those if/when they happen. - In `trait_path` the `find_map`/`if let` is replaced with a loop, and things end up much clearer that way. - `named_span` no longer checks for an empty name; instead the call site now checks for a missing identifier if necessary. - `maybe_inline_local` doesn't need the `glob` argument, it can be computed in-function from the `renamed` argument. - `arbitrary_source_item_ordering::check_mod` had a big `if` statement that was just getting the ident from the item kinds that had one. It could be mostly replaced by a single call to the new `ItemKind::ident` method. - `ItemKind` grows from 56 to 64 bytes, but `Item` stays the same size, and that's what matters, because `ItemKind` only occurs within `Item`.
2025-03-06 08:07:36 +00:00
ItemKind::Fn { ident, sig, generics, body: body_id, .. } => {
try_visit!(visitor.visit_ident(ident));
try_visit!(visitor.visit_fn(
Move `hir::Item::ident` into `hir::ItemKind`. `hir::Item` has an `ident` field. - It's always non-empty for these item kinds: `ExternCrate`, `Static`, `Const`, `Fn`, `Macro`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`, Trait`, TraitAalis`. - It's always empty for these item kinds: `ForeignMod`, `GlobalAsm`, `Impl`. - For `Use`, it is non-empty for `UseKind::Single` and empty for `UseKind::{Glob,ListStem}`. All of this is quite non-obvious; the only documentation is a single comment saying "The name might be a dummy name in case of anonymous items". Some sites that handle items check for an empty ident, some don't. This is a very C-like way of doing things, but this is Rust, we have sum types, we can do this properly and never forget to check for the exceptional case and never YOLO possibly empty identifiers (or possibly dummy spans) around and hope that things will work out. The commit is large but it's mostly obvious plumbing work. Some notable things. - A similar transformation makes sense for `ast::Item`, but this is already a big change. That can be done later. - Lots of assertions are added to item lowering to ensure that identifiers are empty/non-empty as expected. These will be removable when `ast::Item` is done later. - `ItemKind::Use` doesn't get an `Ident`, but `UseKind::Single` does. - `lower_use_tree` is significantly simpler. No more confusing `&mut Ident` to deal with. - `ItemKind::ident` is a new method, it returns an `Option<Ident>`. It's used with `unwrap` in a few places; sometimes it's hard to tell exactly which item kinds might occur. None of these unwraps fail on the test suite. It's conceivable that some might fail on alternative input. We can deal with those if/when they happen. - In `trait_path` the `find_map`/`if let` is replaced with a loop, and things end up much clearer that way. - `named_span` no longer checks for an empty name; instead the call site now checks for a missing identifier if necessary. - `maybe_inline_local` doesn't need the `glob` argument, it can be computed in-function from the `renamed` argument. - `arbitrary_source_item_ordering::check_mod` had a big `if` statement that was just getting the ident from the item kinds that had one. It could be mostly replaced by a single call to the new `ItemKind::ident` method. - `ItemKind` grows from 56 to 64 bytes, but `Item` stays the same size, and that's what matters, because `ItemKind` only occurs within `Item`.
2025-03-06 08:07:36 +00:00
FnKind::ItemFn(ident, generics, sig.header),
sig.decl,
body_id,
item.span,
item.owner_id.def_id,
));
}
Move `hir::Item::ident` into `hir::ItemKind`. `hir::Item` has an `ident` field. - It's always non-empty for these item kinds: `ExternCrate`, `Static`, `Const`, `Fn`, `Macro`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`, Trait`, TraitAalis`. - It's always empty for these item kinds: `ForeignMod`, `GlobalAsm`, `Impl`. - For `Use`, it is non-empty for `UseKind::Single` and empty for `UseKind::{Glob,ListStem}`. All of this is quite non-obvious; the only documentation is a single comment saying "The name might be a dummy name in case of anonymous items". Some sites that handle items check for an empty ident, some don't. This is a very C-like way of doing things, but this is Rust, we have sum types, we can do this properly and never forget to check for the exceptional case and never YOLO possibly empty identifiers (or possibly dummy spans) around and hope that things will work out. The commit is large but it's mostly obvious plumbing work. Some notable things. - A similar transformation makes sense for `ast::Item`, but this is already a big change. That can be done later. - Lots of assertions are added to item lowering to ensure that identifiers are empty/non-empty as expected. These will be removable when `ast::Item` is done later. - `ItemKind::Use` doesn't get an `Ident`, but `UseKind::Single` does. - `lower_use_tree` is significantly simpler. No more confusing `&mut Ident` to deal with. - `ItemKind::ident` is a new method, it returns an `Option<Ident>`. It's used with `unwrap` in a few places; sometimes it's hard to tell exactly which item kinds might occur. None of these unwraps fail on the test suite. It's conceivable that some might fail on alternative input. We can deal with those if/when they happen. - In `trait_path` the `find_map`/`if let` is replaced with a loop, and things end up much clearer that way. - `named_span` no longer checks for an empty name; instead the call site now checks for a missing identifier if necessary. - `maybe_inline_local` doesn't need the `glob` argument, it can be computed in-function from the `renamed` argument. - `arbitrary_source_item_ordering::check_mod` had a big `if` statement that was just getting the ident from the item kinds that had one. It could be mostly replaced by a single call to the new `ItemKind::ident` method. - `ItemKind` grows from 56 to 64 bytes, but `Item` stays the same size, and that's what matters, because `ItemKind` only occurs within `Item`.
2025-03-06 08:07:36 +00:00
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()));
2015-07-31 07:04:06 +00:00
}
2020-11-11 21:40:09 +00:00
ItemKind::ForeignMod { abi: _, items } => {
walk_list!(visitor, visit_foreign_item_ref, items);
2015-07-31 07:04:06 +00:00
}
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) => {
Move `hir::Item::ident` into `hir::ItemKind`. `hir::Item` has an `ident` field. - It's always non-empty for these item kinds: `ExternCrate`, `Static`, `Const`, `Fn`, `Macro`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`, Trait`, TraitAalis`. - It's always empty for these item kinds: `ForeignMod`, `GlobalAsm`, `Impl`. - For `Use`, it is non-empty for `UseKind::Single` and empty for `UseKind::{Glob,ListStem}`. All of this is quite non-obvious; the only documentation is a single comment saying "The name might be a dummy name in case of anonymous items". Some sites that handle items check for an empty ident, some don't. This is a very C-like way of doing things, but this is Rust, we have sum types, we can do this properly and never forget to check for the exceptional case and never YOLO possibly empty identifiers (or possibly dummy spans) around and hope that things will work out. The commit is large but it's mostly obvious plumbing work. Some notable things. - A similar transformation makes sense for `ast::Item`, but this is already a big change. That can be done later. - Lots of assertions are added to item lowering to ensure that identifiers are empty/non-empty as expected. These will be removable when `ast::Item` is done later. - `ItemKind::Use` doesn't get an `Ident`, but `UseKind::Single` does. - `lower_use_tree` is significantly simpler. No more confusing `&mut Ident` to deal with. - `ItemKind::ident` is a new method, it returns an `Option<Ident>`. It's used with `unwrap` in a few places; sometimes it's hard to tell exactly which item kinds might occur. None of these unwraps fail on the test suite. It's conceivable that some might fail on alternative input. We can deal with those if/when they happen. - In `trait_path` the `find_map`/`if let` is replaced with a loop, and things end up much clearer that way. - `named_span` no longer checks for an empty name; instead the call site now checks for a missing identifier if necessary. - `maybe_inline_local` doesn't need the `glob` argument, it can be computed in-function from the `renamed` argument. - `arbitrary_source_item_ordering::check_mod` had a big `if` statement that was just getting the ident from the item kinds that had one. It could be mostly replaced by a single call to the new `ItemKind::ident` method. - `ItemKind` grows from 56 to 64 bytes, but `Item` stays the same size, and that's what matters, because `ItemKind` only occurs within `Item`.
2025-03-06 08:07:36 +00:00
try_visit!(visitor.visit_ident(ident));
try_visit!(visitor.visit_generics(generics));
try_visit!(visitor.visit_ty_unambig(ty));
2015-07-31 07:04:06 +00:00
}
ItemKind::Enum(ident, ref generics, ref enum_definition) => {
Move `hir::Item::ident` into `hir::ItemKind`. `hir::Item` has an `ident` field. - It's always non-empty for these item kinds: `ExternCrate`, `Static`, `Const`, `Fn`, `Macro`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`, Trait`, TraitAalis`. - It's always empty for these item kinds: `ForeignMod`, `GlobalAsm`, `Impl`. - For `Use`, it is non-empty for `UseKind::Single` and empty for `UseKind::{Glob,ListStem}`. All of this is quite non-obvious; the only documentation is a single comment saying "The name might be a dummy name in case of anonymous items". Some sites that handle items check for an empty ident, some don't. This is a very C-like way of doing things, but this is Rust, we have sum types, we can do this properly and never forget to check for the exceptional case and never YOLO possibly empty identifiers (or possibly dummy spans) around and hope that things will work out. The commit is large but it's mostly obvious plumbing work. Some notable things. - A similar transformation makes sense for `ast::Item`, but this is already a big change. That can be done later. - Lots of assertions are added to item lowering to ensure that identifiers are empty/non-empty as expected. These will be removable when `ast::Item` is done later. - `ItemKind::Use` doesn't get an `Ident`, but `UseKind::Single` does. - `lower_use_tree` is significantly simpler. No more confusing `&mut Ident` to deal with. - `ItemKind::ident` is a new method, it returns an `Option<Ident>`. It's used with `unwrap` in a few places; sometimes it's hard to tell exactly which item kinds might occur. None of these unwraps fail on the test suite. It's conceivable that some might fail on alternative input. We can deal with those if/when they happen. - In `trait_path` the `find_map`/`if let` is replaced with a loop, and things end up much clearer that way. - `named_span` no longer checks for an empty name; instead the call site now checks for a missing identifier if necessary. - `maybe_inline_local` doesn't need the `glob` argument, it can be computed in-function from the `renamed` argument. - `arbitrary_source_item_ordering::check_mod` had a big `if` statement that was just getting the ident from the item kinds that had one. It could be mostly replaced by a single call to the new `ItemKind::ident` method. - `ItemKind` grows from 56 to 64 bytes, but `Item` stays the same size, and that's what matters, because `ItemKind` only occurs within `Item`.
2025-03-06 08:07:36 +00:00
try_visit!(visitor.visit_ident(ident));
try_visit!(visitor.visit_generics(generics));
try_visit!(visitor.visit_enum_def(enum_definition));
2015-07-31 07:04:06 +00:00
}
ItemKind::Impl(Impl {
2024-06-14 12:16:15 +00:00
constness: _,
2024-05-17 17:17:48 +00:00
safety: _,
defaultness: _,
polarity: _,
defaultness_span: _,
2025-02-20 18:28:48 +00:00
generics,
of_trait,
self_ty,
items,
}) => {
try_visit!(visitor.visit_generics(generics));
visit_opt!(visitor, visit_trait_ref, of_trait);
2025-01-18 22:45:41 +00:00
try_visit!(visitor.visit_ty_unambig(self_ty));
2022-02-05 14:26:49 +00:00
walk_list!(visitor, visit_impl_item_ref, *items);
2015-07-31 07:04:06 +00:00
}
ItemKind::Struct(ident, ref generics, ref struct_definition)
| ItemKind::Union(ident, ref generics, ref struct_definition) => {
Move `hir::Item::ident` into `hir::ItemKind`. `hir::Item` has an `ident` field. - It's always non-empty for these item kinds: `ExternCrate`, `Static`, `Const`, `Fn`, `Macro`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`, Trait`, TraitAalis`. - It's always empty for these item kinds: `ForeignMod`, `GlobalAsm`, `Impl`. - For `Use`, it is non-empty for `UseKind::Single` and empty for `UseKind::{Glob,ListStem}`. All of this is quite non-obvious; the only documentation is a single comment saying "The name might be a dummy name in case of anonymous items". Some sites that handle items check for an empty ident, some don't. This is a very C-like way of doing things, but this is Rust, we have sum types, we can do this properly and never forget to check for the exceptional case and never YOLO possibly empty identifiers (or possibly dummy spans) around and hope that things will work out. The commit is large but it's mostly obvious plumbing work. Some notable things. - A similar transformation makes sense for `ast::Item`, but this is already a big change. That can be done later. - Lots of assertions are added to item lowering to ensure that identifiers are empty/non-empty as expected. These will be removable when `ast::Item` is done later. - `ItemKind::Use` doesn't get an `Ident`, but `UseKind::Single` does. - `lower_use_tree` is significantly simpler. No more confusing `&mut Ident` to deal with. - `ItemKind::ident` is a new method, it returns an `Option<Ident>`. It's used with `unwrap` in a few places; sometimes it's hard to tell exactly which item kinds might occur. None of these unwraps fail on the test suite. It's conceivable that some might fail on alternative input. We can deal with those if/when they happen. - In `trait_path` the `find_map`/`if let` is replaced with a loop, and things end up much clearer that way. - `named_span` no longer checks for an empty name; instead the call site now checks for a missing identifier if necessary. - `maybe_inline_local` doesn't need the `glob` argument, it can be computed in-function from the `renamed` argument. - `arbitrary_source_item_ordering::check_mod` had a big `if` statement that was just getting the ident from the item kinds that had one. It could be mostly replaced by a single call to the new `ItemKind::ident` method. - `ItemKind` grows from 56 to 64 bytes, but `Item` stays the same size, and that's what matters, because `ItemKind` only occurs within `Item`.
2025-03-06 08:07:36 +00:00
try_visit!(visitor.visit_ident(ident));
try_visit!(visitor.visit_generics(generics));
try_visit!(visitor.visit_variant_data(struct_definition));
2015-07-31 07:04:06 +00:00
}
Move `hir::Item::ident` into `hir::ItemKind`. `hir::Item` has an `ident` field. - It's always non-empty for these item kinds: `ExternCrate`, `Static`, `Const`, `Fn`, `Macro`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`, Trait`, TraitAalis`. - It's always empty for these item kinds: `ForeignMod`, `GlobalAsm`, `Impl`. - For `Use`, it is non-empty for `UseKind::Single` and empty for `UseKind::{Glob,ListStem}`. All of this is quite non-obvious; the only documentation is a single comment saying "The name might be a dummy name in case of anonymous items". Some sites that handle items check for an empty ident, some don't. This is a very C-like way of doing things, but this is Rust, we have sum types, we can do this properly and never forget to check for the exceptional case and never YOLO possibly empty identifiers (or possibly dummy spans) around and hope that things will work out. The commit is large but it's mostly obvious plumbing work. Some notable things. - A similar transformation makes sense for `ast::Item`, but this is already a big change. That can be done later. - Lots of assertions are added to item lowering to ensure that identifiers are empty/non-empty as expected. These will be removable when `ast::Item` is done later. - `ItemKind::Use` doesn't get an `Ident`, but `UseKind::Single` does. - `lower_use_tree` is significantly simpler. No more confusing `&mut Ident` to deal with. - `ItemKind::ident` is a new method, it returns an `Option<Ident>`. It's used with `unwrap` in a few places; sometimes it's hard to tell exactly which item kinds might occur. None of these unwraps fail on the test suite. It's conceivable that some might fail on alternative input. We can deal with those if/when they happen. - In `trait_path` the `find_map`/`if let` is replaced with a loop, and things end up much clearer that way. - `named_span` no longer checks for an empty name; instead the call site now checks for a missing identifier if necessary. - `maybe_inline_local` doesn't need the `glob` argument, it can be computed in-function from the `renamed` argument. - `arbitrary_source_item_ordering::check_mod` had a big `if` statement that was just getting the ident from the item kinds that had one. It could be mostly replaced by a single call to the new `ItemKind::ident` method. - `ItemKind` grows from 56 to 64 bytes, but `Item` stays the same size, and that's what matters, because `ItemKind` only occurs within `Item`.
2025-03-06 08:07:36 +00:00
ItemKind::Trait(_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);
2015-07-31 07:04:06 +00:00
}
Move `hir::Item::ident` into `hir::ItemKind`. `hir::Item` has an `ident` field. - It's always non-empty for these item kinds: `ExternCrate`, `Static`, `Const`, `Fn`, `Macro`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`, Trait`, TraitAalis`. - It's always empty for these item kinds: `ForeignMod`, `GlobalAsm`, `Impl`. - For `Use`, it is non-empty for `UseKind::Single` and empty for `UseKind::{Glob,ListStem}`. All of this is quite non-obvious; the only documentation is a single comment saying "The name might be a dummy name in case of anonymous items". Some sites that handle items check for an empty ident, some don't. This is a very C-like way of doing things, but this is Rust, we have sum types, we can do this properly and never forget to check for the exceptional case and never YOLO possibly empty identifiers (or possibly dummy spans) around and hope that things will work out. The commit is large but it's mostly obvious plumbing work. Some notable things. - A similar transformation makes sense for `ast::Item`, but this is already a big change. That can be done later. - Lots of assertions are added to item lowering to ensure that identifiers are empty/non-empty as expected. These will be removable when `ast::Item` is done later. - `ItemKind::Use` doesn't get an `Ident`, but `UseKind::Single` does. - `lower_use_tree` is significantly simpler. No more confusing `&mut Ident` to deal with. - `ItemKind::ident` is a new method, it returns an `Option<Ident>`. It's used with `unwrap` in a few places; sometimes it's hard to tell exactly which item kinds might occur. None of these unwraps fail on the test suite. It's conceivable that some might fail on alternative input. We can deal with those if/when they happen. - In `trait_path` the `find_map`/`if let` is replaced with a loop, and things end up much clearer that way. - `named_span` no longer checks for an empty name; instead the call site now checks for a missing identifier if necessary. - `maybe_inline_local` doesn't need the `glob` argument, it can be computed in-function from the `renamed` argument. - `arbitrary_source_item_ordering::check_mod` had a big `if` statement that was just getting the ident from the item kinds that had one. It could be mostly replaced by a single call to the new `ItemKind::ident` method. - `ItemKind` grows from 56 to 64 bytes, but `Item` stays the same size, and that's what matters, because `ItemKind` only occurs within `Item`.
2025-03-06 08:07:36 +00:00
ItemKind::TraitAlias(ident, ref generics, bounds) => {
try_visit!(visitor.visit_ident(ident));
try_visit!(visitor.visit_generics(generics));
walk_list!(visitor, visit_param_bound, bounds);
2017-10-02 12:28:16 +00:00
}
2015-07-31 07:04:06 +00:00
}
V::Result::output()
2015-07-31 07:04:06 +00:00
}
pub fn walk_body<'v, V: Visitor<'v>>(visitor: &mut V, body: &Body<'v>) -> V::Result {
2025-06-02 20:01:07 +00:00
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)
2015-07-31 07:04:06 +00:00
}
pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod<'v>) -> V::Result {
2025-06-02 20:01:07 +00:00
let Mod { spans: _, item_ids } = module;
walk_list!(visitor, visit_nested_item, item_ids.iter().copied());
V::Result::output()
2015-07-31 07:04:06 +00:00
}
pub fn walk_foreign_item<'v, V: Visitor<'v>>(
visitor: &mut V,
foreign_item: &'v ForeignItem<'v>,
) -> V::Result {
2025-06-02 20:01:07 +00:00
let ForeignItem { ident, kind, owner_id: _, span: _, vis_span: _ } = foreign_item;
try_visit!(visitor.visit_id(foreign_item.hir_id()));
2025-06-02 20:01:07 +00:00
try_visit!(visitor.visit_ident(*ident));
2025-06-02 20:01:07 +00:00
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);
}
2015-07-31 07:04:06 +00:00
}
ForeignItemKind::Static(ref typ, _, _) => {
2025-01-18 22:45:41 +00:00
try_visit!(visitor.visit_ty_unambig(typ));
}
ForeignItemKind::Type => (),
2015-07-31 07:04:06 +00:00
}
V::Result::output()
2015-07-31 07:04:06 +00:00
}
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.
2025-06-02 20:01:07 +00:00
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 {
2025-06-02 20:01:07 +00:00
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()
2015-07-31 07:04:06 +00:00
}
pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) -> V::Result {
2025-06-02 20:01:07 +00:00
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)
}
}
2015-07-31 07:04:06 +00:00
}
pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm<'v>) -> V::Result {
2025-06-02 20:01:07 +00:00
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)
2015-07-31 07:04:06 +00:00
}
pub fn walk_ty_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v TyPat<'v>) -> V::Result {
2025-06-02 20:01:07 +00:00
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));
}
2025-02-27 09:46:46 +00:00
TyPatKind::Or(patterns) => walk_list!(visitor, visit_pattern_type_pattern, patterns),
TyPatKind::Err(_) => (),
}
V::Result::output()
}
pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) -> V::Result {
2025-06-02 20:01:07 +00:00
let Pat { hir_id, kind, span, default_binding_modes: _ } = pattern;
try_visit!(visitor.visit_id(*hir_id));
match *kind {
2019-11-29 13:08:03 +00:00
PatKind::TupleStruct(ref qpath, children, _) => {
2025-06-02 20:01:07 +00:00
try_visit!(visitor.visit_qpath(qpath, *hir_id, *span));
walk_list!(visitor, visit_pat, children);
2015-07-31 07:04:06 +00:00
}
2019-11-29 13:08:03 +00:00
PatKind::Struct(ref qpath, fields, _) => {
2025-06-02 20:01:07 +00:00
try_visit!(visitor.visit_qpath(qpath, *hir_id, *span));
walk_list!(visitor, visit_pat_field, fields);
2015-07-31 07:04:06 +00:00
}
2019-11-29 13:08:03 +00:00
PatKind::Or(pats) => walk_list!(visitor, visit_pat, pats),
PatKind::Tuple(tuple_elements, _) => {
walk_list!(visitor, visit_pat, tuple_elements);
2015-07-31 07:04:06 +00:00
}
PatKind::Box(ref subpattern)
| PatKind::Deref(ref subpattern)
| PatKind::Ref(ref subpattern, _) => {
try_visit!(visitor.visit_pat(subpattern));
2015-07-31 07:04:06 +00:00
}
2019-03-07 11:18:59 +00:00
PatKind::Binding(_, _hir_id, ident, ref optional_subpattern) => {
try_visit!(visitor.visit_ident(ident));
visit_opt!(visitor, visit_pat, optional_subpattern);
2015-07-31 07:04:06 +00:00
}
2025-01-07 08:56:23 +00:00
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);
2015-07-31 07:04:06 +00:00
}
Add `{ast,hir,thir}::PatKind::Missing` variants. "Missing" patterns are possible in bare fn types (`fn f(u32)`) and similar places. Currently these are represented in the AST with `ast::PatKind::Ident` with no `by_ref`, no `mut`, an empty ident, and no sub-pattern. This flows through to `{hir,thir}::PatKind::Binding` for HIR and THIR. This is a bit nasty. It's very non-obvious, and easy to forget to check for the exceptional empty identifier case. This commit adds a new variant, `PatKind::Missing`, to do it properly. The process I followed: - Add a `Missing` variant to `{ast,hir,thir}::PatKind`. - Chang `parse_param_general` to produce `ast::PatKind::Missing` instead of `ast::PatKind::Missing`. - Look through `kw::Empty` occurrences to find functions where an existing empty ident check needs replacing with a `PatKind::Missing` check: `print_param`, `check_trait_item`, `is_named_param`. - Add a `PatKind::Missing => unreachable!(),` arm to every exhaustive match identified by the compiler. - Find which arms are actually reachable by running the test suite, changing them to something appropriate, usually by looking at what would happen to a `PatKind::Ident`/`PatKind::Binding` with no ref, no `mut`, an empty ident, and no subpattern. Quite a few of the `unreachable!()` arms were never reached. This makes sense because `PatKind::Missing` can't happen in every pattern, only in places like bare fn tys and trait fn decls. I also tried an alternative approach: modifying `ast::Param::pat` to hold an `Option<P<Pat>>` instead of a `P<Pat>`, but that quickly turned into a very large and painful change. Adding `PatKind::Missing` is much easier.
2025-03-26 22:33:02 +00:00
PatKind::Missing | PatKind::Never | PatKind::Wild | PatKind::Err(_) => (),
2019-11-29 13:08:03 +00:00
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);
2015-07-31 07:04:06 +00:00
}
PatKind::Guard(subpat, condition) => {
try_visit!(visitor.visit_pat(subpat));
try_visit!(visitor.visit_expr(condition));
}
2015-07-31 07:04:06 +00:00
}
V::Result::output()
2015-07-31 07:04:06 +00:00
}
pub fn walk_pat_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v PatField<'v>) -> V::Result {
2025-06-02 20:01:07 +00:00
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 {
2025-06-02 20:01:07 +00:00
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::ConstBlock(c) => visitor.visit_inline_const(c),
2025-06-02 20:01:07 +00:00
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 {
2025-06-02 20:01:07 +00:00
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 {
2025-06-02 20:01:07 +00:00
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 {
2025-06-02 20:01:07 +00:00
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);
2015-07-31 07:04:06 +00:00
}
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));
2025-01-18 22:45:41 +00:00
try_visit!(visitor.visit_const_arg_unambig(count));
}
ExprKind::Struct(ref qpath, fields, ref optional_base) => {
2025-06-02 20:01:07 +00:00
try_visit!(visitor.visit_qpath(qpath, *hir_id, *span));
walk_list!(visitor, visit_expr_field, fields);
Introduce `default_field_values` feature Initial implementation of `#[feature(default_field_values]`, proposed in https://github.com/rust-lang/rfcs/pull/3681. Support default fields in enum struct variant Allow default values in an enum struct variant definition: ```rust pub enum Bar { Foo { bar: S = S, baz: i32 = 42 + 3, } } ``` Allow using `..` without a base on an enum struct variant ```rust Bar::Foo { .. } ``` `#[derive(Default)]` doesn't account for these as it is still gating `#[default]` only being allowed on unit variants. Support `#[derive(Default)]` on enum struct variants with all defaulted fields ```rust pub enum Bar { #[default] Foo { bar: S = S, baz: i32 = 42 + 3, } } ``` Check for missing fields in typeck instead of mir_build. Expand test with `const` param case (needs `generic_const_exprs` enabled). Properly instantiate MIR const The following works: ```rust struct S<A> { a: Vec<A> = Vec::new(), } S::<i32> { .. } ``` Add lint for default fields that will always fail const-eval We *allow* this to happen for API writers that might want to rely on users' getting a compile error when using the default field, different to the error that they would get when the field isn't default. We could change this to *always* error instead of being a lint, if we wanted. This will *not* catch errors for partially evaluated consts, like when the expression relies on a const parameter. Suggestions when encountering `Foo { .. }` without `#[feature(default_field_values)]`: - Suggest adding a base expression if there are missing fields. - Suggest enabling the feature if all the missing fields have optional values. - Suggest removing `..` if there are no missing fields.
2024-08-24 17:22:48 +00:00
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));
2025-01-18 22:45:41 +00:00
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));
2025-01-18 22:45:41 +00:00
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: _,
2022-12-20 16:15:55 +00:00
constness: _,
}) => {
walk_list!(visitor, visit_generic_param, bound_generic_params);
2025-06-02 20:01:07 +00:00
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) => {
2025-06-02 20:01:07 +00:00
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) => {
2025-06-02 20:01:07 +00:00
try_visit!(visitor.visit_inline_asm(asm, *hir_id));
}
2022-09-11 07:37:49 +00:00
ExprKind::OffsetOf(ref container, ref fields) => {
2025-01-18 22:45:41 +00:00
try_visit!(visitor.visit_ty_unambig(container));
2022-09-11 07:37:49 +00:00
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));
2025-01-18 22:45:41 +00:00
visit_opt!(visitor, visit_ty_unambig, ty);
}
2025-06-02 20:01:07 +00:00
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 {
2025-06-02 20:01:07 +00:00
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)
}
2025-01-18 23:01:47 +00:00
/// 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),
2025-06-02 20:01:07 +00:00
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 => {
2025-06-02 20:01:07 +00:00
let Ty { hir_id, span, kind: _ } = typ;
try_visit!(visitor.visit_id(*hir_id));
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 {
2025-06-02 20:01:07 +00:00
let Ty { hir_id, span: _, kind } = typ;
try_visit!(visitor.visit_id(*hir_id));
2025-06-02 20:01:07 +00:00
match *kind {
2025-01-18 22:45:41 +00:00
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));
2025-01-18 22:45:41 +00:00
try_visit!(visitor.visit_ty_unambig(mutable_type.ty));
}
TyKind::Never => {}
TyKind::Tup(tuple_element_types) => {
2025-01-18 22:45:41 +00:00
walk_list!(visitor, visit_ty_unambig, tuple_element_types);
}
TyKind::BareFn(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);
2025-01-18 22:45:41 +00:00
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));
}
2024-12-11 22:18:39 +00:00
TyKind::TraitAscription(bounds) => {
walk_list!(visitor, visit_param_bound, bounds);
}
TyKind::Array(ref ty, ref length) => {
2025-01-18 22:45:41 +00:00
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::Typeof(ref expression) => try_visit!(visitor.visit_anon_const(expression)),
TyKind::InferDelegation(..) | TyKind::Err(_) => {}
2023-01-31 11:54:06 +00:00
TyKind::Pat(ty, pat) => {
2025-01-18 22:45:41 +00:00
try_visit!(visitor.visit_ty_unambig(ty));
try_visit!(visitor.visit_pattern_type_pattern(pat));
2023-01-31 11:54:06 +00:00
}
2015-07-31 07:04:06 +00:00
}
V::Result::output()
2015-07-31 07:04:06 +00:00
}
pub fn walk_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 => {
2025-06-02 20:01:07 +00:00
let ConstArg { hir_id, kind: _ } = const_arg;
try_visit!(visitor.visit_id(*hir_id));
visitor.visit_infer(*hir_id, const_arg.span(), InferKind::Const(const_arg))
}
}
}
pub fn walk_ambig_const_arg<'v, V: Visitor<'v>>(
visitor: &mut V,
const_arg: &'v ConstArg<'v, AmbigArg>,
) -> V::Result {
2025-06-02 20:01:07 +00:00
let ConstArg { hir_id, kind } = const_arg;
try_visit!(visitor.visit_id(*hir_id));
match kind {
ConstArgKind::Path(qpath) => visitor.visit_qpath(qpath, *hir_id, qpath.span()),
ConstArgKind::Anon(anon) => visitor.visit_anon_const(*anon),
}
}
pub fn walk_generic_param<'v, V: Visitor<'v>>(
visitor: &mut V,
param: &'v GenericParam<'v>,
) -> V::Result {
2025-06-02 20:01:07 +00:00
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 => {}
}
2025-06-02 20:01:07 +00:00
match *kind {
GenericParamKind::Lifetime { .. } => {}
GenericParamKind::Type { ref default, .. } => {
2025-01-18 22:45:41 +00:00
visit_opt!(visitor, visit_ty_unambig, default)
}
GenericParamKind::Const { ref ty, ref default, synthetic: _ } => {
2025-01-18 22:45:41 +00:00
try_visit!(visitor.visit_ty_unambig(ty));
2025-02-20 18:28:48 +00:00
if let Some(default) = default {
2025-06-02 20:01:07 +00:00
try_visit!(visitor.visit_const_param_default(*hir_id, default));
}
}
2015-07-31 07:04:06 +00:00
}
V::Result::output()
}
pub fn walk_const_param_default<'v, V: Visitor<'v>>(
visitor: &mut V,
ct: &'v ConstArg<'v>,
) -> V::Result {
2025-01-18 22:45:41 +00:00
visitor.visit_const_arg_unambig(ct)
2021-03-01 11:50:09 +00:00
}
pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics<'v>) -> V::Result {
2025-06-02 20:01:07 +00:00
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()
}
2019-11-30 16:46:46 +00:00
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,
2019-11-30 23:17:43 +00:00
bounds,
bound_generic_params,
origin: _,
}) => {
2025-01-18 22:45:41 +00:00
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 }) => {
2025-01-18 22:45:41 +00:00
try_visit!(visitor.visit_ty_unambig(lhs_ty));
try_visit!(visitor.visit_ty_unambig(rhs_ty));
2015-07-31 07:04:06 +00:00
}
}
V::Result::output()
2015-07-31 07:04:06 +00:00
}
pub fn walk_fn_decl<'v, V: Visitor<'v>>(
visitor: &mut V,
function_declaration: &'v FnDecl<'v>,
) -> V::Result {
2025-06-02 20:01:07 +00:00
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)
2015-07-31 07:04:06 +00:00
}
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 {
2025-01-18 22:45:41 +00:00
try_visit!(visitor.visit_ty_unambig(output_ty));
2015-07-31 07:04:06 +00:00
}
V::Result::output()
}
2015-07-31 07:04:06 +00:00
pub fn walk_fn<'v, V: Visitor<'v>>(
visitor: &mut V,
function_kind: FnKind<'v>,
2019-11-30 16:46:46 +00:00
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)
2015-07-31 07:04:06 +00:00
}
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;
Overhaul `UsePath`. `UsePath` contains a `SmallVec<[Res; 3]>`. This holds up to three `Res` results, one per namespace (type, value, or macro). `lower_import_res` takes a `PerNS<Option<Res<NodeId>>>` result and lowers it into the `SmallVec`. This is pretty weird. The input `PerNS` makes it clear which `Res` belongs to which namespace, but the `SmallVec` throws that information away. And code that operates on the `SmallVec` tends to use iteration (or even just grabbing the first entry!) without knowing which namespace the `Res` belongs to. Even weirder! Also, `SmallVec` is an overly flexible type to use here, because it can contain any number of elements (even though it's optimized for 3 in this case). This commit changes `UsePath` so it also contains a `PerNS<Option<Res<HirId>>>`. This type preserves more information and is more self-documenting. The commit also changes a lot of the use sites to access the result for a particular namespace. E.g. if you're looking up a trait, it will be in the `Res` for the type namespace if it's present; it's silly to look in the `Res` for the value namespace or macro namespace. Overall I find the new code much easier to understand. However, some use sites still iterate. These now use `present_items` because that filters out the `None` results. Also, `redundant_pub_crate.rs` gets a bigger change. A `UseKind:ListStem` item gets no `Res` results, which means the old `all` call in `is_not_macro_export` would succeed (because `all` succeeds on an empty iterator) and the `ListStem` would be ignored. This is what we want, but was more by luck than design. The new code detects `ListStem` explicitly. The commit generalizes the name of that function accordingly. Finally, the commit also removes the `use_path` arena, because `PerNS<Option<Res>>` impls `Copy` (unlike `SmallVec`) and it can be allocated in the arena shared by all `Copy` types.
2025-05-29 15:37:48 +00:00
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: _ } = *trait_item;
2022-08-01 17:46:10 +00:00
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));
2022-08-01 17:46:10 +00:00
match *kind {
TraitItemKind::Const(ref ty, default) => {
2025-01-18 22:45:41 +00:00
try_visit!(visitor.visit_ty_unambig(ty));
visit_opt!(visitor, visit_nested_body, default);
2015-07-31 07:04:06 +00:00
}
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);
}
2015-07-31 07:04:06 +00:00
}
2020-03-05 15:57:34 +00:00
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,
));
2015-07-31 07:04:06 +00:00
}
2019-11-30 23:17:43 +00:00
TraitItemKind::Type(bounds, ref default) => {
walk_list!(visitor, visit_param_bound, bounds);
2025-01-18 22:45:41 +00:00
visit_opt!(visitor, visit_ty_unambig, default);
2015-07-31 07:04:06 +00:00
}
}
V::Result::output()
2015-07-31 07:04:06 +00:00
}
pub fn walk_trait_item_ref<'v, V: Visitor<'v>>(
visitor: &mut V,
trait_item_ref: &'v TraitItemRef,
) -> V::Result {
let TraitItemRef { id, ident, ref kind, span: _ } = *trait_item_ref;
try_visit!(visitor.visit_nested_trait_item(id));
try_visit!(visitor.visit_ident(ident));
visitor.visit_associated_item_kind(kind)
}
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 kind,
ref defaultness,
span: _,
vis_span: _,
} = *impl_item;
try_visit!(visitor.visit_ident(ident));
try_visit!(visitor.visit_generics(generics));
try_visit!(visitor.visit_defaultness(defaultness));
try_visit!(visitor.visit_id(impl_item.hir_id()));
match *kind {
ImplItemKind::Const(ref ty, body) => {
2025-01-18 22:45:41 +00:00
try_visit!(visitor.visit_ty_unambig(ty));
visitor.visit_nested_body(body)
}
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,
),
2025-01-18 22:45:41 +00:00
ImplItemKind::Type(ref ty) => visitor.visit_ty_unambig(ty),
2015-07-31 07:04:06 +00:00
}
}
2020-11-11 20:57:54 +00:00
pub fn walk_foreign_item_ref<'v, V: Visitor<'v>>(
visitor: &mut V,
2021-07-15 20:19:39 +00:00
foreign_item_ref: &'v ForeignItemRef,
) -> V::Result {
2021-07-15 20:19:39 +00:00
let ForeignItemRef { id, ident, span: _ } = *foreign_item_ref;
try_visit!(visitor.visit_nested_foreign_item(id));
visitor.visit_ident(ident)
2020-11-11 20:57:54 +00:00
}
pub fn walk_impl_item_ref<'v, V: Visitor<'v>>(
visitor: &mut V,
impl_item_ref: &'v ImplItemRef,
) -> V::Result {
let ImplItemRef { id, ident, ref kind, span: _, trait_item_def_id: _ } = *impl_item_ref;
try_visit!(visitor.visit_nested_impl_item(id));
try_visit!(visitor.visit_ident(ident));
visitor.visit_associated_item_kind(kind)
}
pub fn walk_trait_ref<'v, V: Visitor<'v>>(
visitor: &mut V,
trait_ref: &'v TraitRef<'v>,
) -> V::Result {
2025-06-02 20:01:07 +00:00
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),
2024-06-05 20:18:52 +00:00
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),
2025-06-02 20:01:07 +00:00
PreciseCapturingArg::Param(param) => {
let PreciseCapturingNonLifetimeArg { hir_id, ident, res: _ } = param;
try_visit!(visitor.visit_id(hir_id));
visitor.visit_ident(ident)
2025-06-02 20:01:07 +00:00
}
}
}
pub fn walk_poly_trait_ref<'v, V: Visitor<'v>>(
visitor: &mut V,
trait_ref: &'v PolyTraitRef<'v>,
) -> V::Result {
2025-06-02 20:01:07 +00:00
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()
}
2019-12-01 11:49:54 +00:00
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()
2015-07-31 07:04:06 +00:00
}
Introduce `default_field_values` feature Initial implementation of `#[feature(default_field_values]`, proposed in https://github.com/rust-lang/rfcs/pull/3681. Support default fields in enum struct variant Allow default values in an enum struct variant definition: ```rust pub enum Bar { Foo { bar: S = S, baz: i32 = 42 + 3, } } ``` Allow using `..` without a base on an enum struct variant ```rust Bar::Foo { .. } ``` `#[derive(Default)]` doesn't account for these as it is still gating `#[default]` only being allowed on unit variants. Support `#[derive(Default)]` on enum struct variants with all defaulted fields ```rust pub enum Bar { #[default] Foo { bar: S = S, baz: i32 = 42 + 3, } } ``` Check for missing fields in typeck instead of mir_build. Expand test with `const` param case (needs `generic_const_exprs` enabled). Properly instantiate MIR const The following works: ```rust struct S<A> { a: Vec<A> = Vec::new(), } S::<i32> { .. } ``` Add lint for default fields that will always fail const-eval We *allow* this to happen for API writers that might want to rely on users' getting a compile error when using the default field, different to the error that they would get when the field isn't default. We could change this to *always* error instead of being a lint, if we wanted. This will *not* catch errors for partially evaluated consts, like when the expression relies on a const parameter. Suggestions when encountering `Foo { .. }` without `#[feature(default_field_values)]`: - Suggest adding a base expression if there are missing fields. - Suggest enabling the feature if all the missing fields have optional values. - Suggest removing `..` if there are no missing fields.
2024-08-24 17:22:48 +00:00
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);
2025-01-18 22:45:41 +00:00
visitor.visit_ty_unambig(*ty)
2015-07-31 07:04:06 +00:00
}
pub fn walk_enum_def<'v, V: Visitor<'v>>(
visitor: &mut V,
enum_definition: &'v EnumDef<'v>,
) -> V::Result {
2025-06-02 20:01:07 +00:00
let EnumDef { variants } = enum_definition;
walk_list!(visitor, visit_variant, *variants);
V::Result::output()
2015-07-31 07:04:06 +00:00
}
pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V, variant: &'v Variant<'v>) -> V::Result {
2025-06-02 20:01:07 +00:00
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()
2015-07-31 07:04:06 +00:00
}
pub fn walk_label<'v, V: Visitor<'v>>(visitor: &mut V, label: &'v Label) -> V::Result {
2025-06-02 20:01:07 +00:00
let Label { ident } = label;
visitor.visit_ident(*ident)
}
pub fn walk_inf<'v, V: Visitor<'v>>(visitor: &mut V, inf: &'v InferArg) -> V::Result {
2025-06-02 20:01:07 +00:00
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 {
2025-06-02 20:01:07 +00:00
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) => {
2025-01-18 22:45:41 +00:00
visit_opt!(visitor, visit_ty_unambig, maybe_qself);
visitor.visit_path(path, id)
2015-07-31 07:04:06 +00:00
}
QPath::TypeRelative(ref qself, ref segment) => {
2025-01-18 22:45:41 +00:00
try_visit!(visitor.visit_ty_unambig(qself));
visitor.visit_path_segment(segment)
2015-07-31 07:04:06 +00:00
}
QPath::LangItem(..) => V::Result::output(),
2015-07-31 07:04:06 +00:00
}
}
pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &Path<'v>) -> V::Result {
2025-06-02 20:01:07 +00:00
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 {
2025-06-02 20:01:07 +00:00
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 {
2025-06-02 20:01:07 +00:00
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 {
2025-06-02 20:01:07 +00:00
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 {
2025-02-20 18:28:48 +00:00
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)
}
2018-08-30 04:18:11 +00:00
}
V::Result::output()
2015-07-31 07:04:06 +00:00
}
pub fn walk_associated_item_kind<'v, V: Visitor<'v>>(_: &mut V, _: &'v AssocItemKind) -> 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_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));
}
2023-12-25 20:53:01 +00:00
InlineAsmOperand::Label { block } => try_visit!(visitor.visit_block(block)),
}
}
V::Result::output()
}