|  | use super::{ | 
|  | AdtExpr, AdtExprBase, Arm, Block, ClosureExpr, Expr, ExprKind, InlineAsmExpr, InlineAsmOperand, | 
|  | Pat, PatKind, Stmt, StmtKind, Thir, | 
|  | }; | 
|  | use crate::thir::LoopMatchMatchData; | 
|  |  | 
|  | /// 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<'thir, 'tcx: 'thir>: Sized { | 
|  | fn thir(&self) -> &'thir Thir<'tcx>; | 
|  |  | 
|  | fn visit_expr(&mut self, expr: &'thir Expr<'tcx>) { | 
|  | walk_expr(self, expr); | 
|  | } | 
|  |  | 
|  | fn visit_stmt(&mut self, stmt: &'thir Stmt<'tcx>) { | 
|  | walk_stmt(self, stmt); | 
|  | } | 
|  |  | 
|  | fn visit_block(&mut self, block: &'thir Block) { | 
|  | walk_block(self, block); | 
|  | } | 
|  |  | 
|  | fn visit_arm(&mut self, arm: &'thir Arm<'tcx>) { | 
|  | walk_arm(self, arm); | 
|  | } | 
|  |  | 
|  | fn visit_pat(&mut self, pat: &'thir Pat<'tcx>) { | 
|  | walk_pat(self, pat); | 
|  | } | 
|  |  | 
|  | // Note: We don't have visitors for `ty::Const` and `mir::Const` | 
|  | // (even though these types occur in THIR) for consistency and to reduce confusion, | 
|  | // since the lazy creation of constants during thir construction causes most | 
|  | // 'constants' to not be of type `ty::Const` or `mir::Const` at that | 
|  | // stage (they are mostly still identified by `DefId` or `hir::Lit`, see | 
|  | // the variants `Literal`, `NonHirLiteral` and `NamedConst` in `thir::ExprKind`). | 
|  | // You have to manually visit `ty::Const` and `mir::Const` through the | 
|  | // other `visit*` functions. | 
|  | } | 
|  |  | 
|  | pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( | 
|  | visitor: &mut V, | 
|  | expr: &'thir Expr<'tcx>, | 
|  | ) { | 
|  | use ExprKind::*; | 
|  | let Expr { kind, ty: _, temp_lifetime: _, span: _ } = expr; | 
|  | match *kind { | 
|  | Scope { value, region_scope: _, lint_level: _ } => { | 
|  | visitor.visit_expr(&visitor.thir()[value]) | 
|  | } | 
|  | Box { value } => visitor.visit_expr(&visitor.thir()[value]), | 
|  | If { cond, then, else_opt, if_then_scope: _ } => { | 
|  | visitor.visit_expr(&visitor.thir()[cond]); | 
|  | visitor.visit_expr(&visitor.thir()[then]); | 
|  | if let Some(else_expr) = else_opt { | 
|  | visitor.visit_expr(&visitor.thir()[else_expr]); | 
|  | } | 
|  | } | 
|  | Call { fun, ref args, ty: _, from_hir_call: _, fn_span: _ } => { | 
|  | visitor.visit_expr(&visitor.thir()[fun]); | 
|  | for &arg in &**args { | 
|  | visitor.visit_expr(&visitor.thir()[arg]); | 
|  | } | 
|  | } | 
|  | ByUse { expr, span: _ } => { | 
|  | visitor.visit_expr(&visitor.thir()[expr]); | 
|  | } | 
|  | Deref { arg } => visitor.visit_expr(&visitor.thir()[arg]), | 
|  | Binary { lhs, rhs, op: _ } | LogicalOp { lhs, rhs, op: _ } => { | 
|  | visitor.visit_expr(&visitor.thir()[lhs]); | 
|  | visitor.visit_expr(&visitor.thir()[rhs]); | 
|  | } | 
|  | Unary { arg, op: _ } => visitor.visit_expr(&visitor.thir()[arg]), | 
|  | Cast { source } => visitor.visit_expr(&visitor.thir()[source]), | 
|  | Use { source } => visitor.visit_expr(&visitor.thir()[source]), | 
|  | NeverToAny { source } => visitor.visit_expr(&visitor.thir()[source]), | 
|  | PointerCoercion { source, cast: _, is_from_as_cast: _ } => { | 
|  | visitor.visit_expr(&visitor.thir()[source]) | 
|  | } | 
|  | Let { expr, ref pat } => { | 
|  | visitor.visit_expr(&visitor.thir()[expr]); | 
|  | visitor.visit_pat(pat); | 
|  | } | 
|  | Loop { body } => visitor.visit_expr(&visitor.thir()[body]), | 
|  | LoopMatch { match_data: box LoopMatchMatchData { scrutinee, ref arms, .. }, .. } | 
|  | | Match { scrutinee, ref arms, .. } => { | 
|  | visitor.visit_expr(&visitor.thir()[scrutinee]); | 
|  | for &arm in &**arms { | 
|  | visitor.visit_arm(&visitor.thir()[arm]); | 
|  | } | 
|  | } | 
|  | Block { block } => visitor.visit_block(&visitor.thir()[block]), | 
|  | Assign { lhs, rhs } | AssignOp { lhs, rhs, op: _ } => { | 
|  | visitor.visit_expr(&visitor.thir()[lhs]); | 
|  | visitor.visit_expr(&visitor.thir()[rhs]); | 
|  | } | 
|  | Field { lhs, variant_index: _, name: _ } => visitor.visit_expr(&visitor.thir()[lhs]), | 
|  | Index { lhs, index } => { | 
|  | visitor.visit_expr(&visitor.thir()[lhs]); | 
|  | visitor.visit_expr(&visitor.thir()[index]); | 
|  | } | 
|  | VarRef { id: _ } | UpvarRef { closure_def_id: _, var_hir_id: _ } => {} | 
|  | Borrow { arg, borrow_kind: _ } => visitor.visit_expr(&visitor.thir()[arg]), | 
|  | RawBorrow { arg, mutability: _ } => visitor.visit_expr(&visitor.thir()[arg]), | 
|  | Break { value, label: _ } => { | 
|  | if let Some(value) = value { | 
|  | visitor.visit_expr(&visitor.thir()[value]) | 
|  | } | 
|  | } | 
|  | Continue { label: _ } => {} | 
|  | ConstContinue { value, label: _ } => visitor.visit_expr(&visitor.thir()[value]), | 
|  | Return { value } => { | 
|  | if let Some(value) = value { | 
|  | visitor.visit_expr(&visitor.thir()[value]) | 
|  | } | 
|  | } | 
|  | Become { value } => visitor.visit_expr(&visitor.thir()[value]), | 
|  | ConstBlock { did: _, args: _ } => {} | 
|  | Repeat { value, count: _ } => { | 
|  | visitor.visit_expr(&visitor.thir()[value]); | 
|  | } | 
|  | Array { ref fields } | Tuple { ref fields } => { | 
|  | for &field in &**fields { | 
|  | visitor.visit_expr(&visitor.thir()[field]); | 
|  | } | 
|  | } | 
|  | Adt(box AdtExpr { | 
|  | ref fields, | 
|  | ref base, | 
|  | adt_def: _, | 
|  | variant_index: _, | 
|  | args: _, | 
|  | user_ty: _, | 
|  | }) => { | 
|  | for field in &**fields { | 
|  | visitor.visit_expr(&visitor.thir()[field.expr]); | 
|  | } | 
|  | if let AdtExprBase::Base(base) = base { | 
|  | visitor.visit_expr(&visitor.thir()[base.base]); | 
|  | } | 
|  | } | 
|  | PlaceTypeAscription { source, user_ty: _, user_ty_span: _ } | 
|  | | ValueTypeAscription { source, user_ty: _, user_ty_span: _ } => { | 
|  | visitor.visit_expr(&visitor.thir()[source]) | 
|  | } | 
|  | PlaceUnwrapUnsafeBinder { source } | 
|  | | ValueUnwrapUnsafeBinder { source } | 
|  | | WrapUnsafeBinder { source } => visitor.visit_expr(&visitor.thir()[source]), | 
|  | Closure(box ClosureExpr { | 
|  | closure_id: _, | 
|  | args: _, | 
|  | upvars: _, | 
|  | movability: _, | 
|  | fake_reads: _, | 
|  | }) => {} | 
|  | Literal { lit: _, neg: _ } => {} | 
|  | NonHirLiteral { lit: _, user_ty: _ } => {} | 
|  | ZstLiteral { user_ty: _ } => {} | 
|  | NamedConst { def_id: _, args: _, user_ty: _ } => {} | 
|  | ConstParam { param: _, def_id: _ } => {} | 
|  | StaticRef { alloc_id: _, ty: _, def_id: _ } => {} | 
|  | InlineAsm(box InlineAsmExpr { | 
|  | asm_macro: _, | 
|  | ref operands, | 
|  | template: _, | 
|  | options: _, | 
|  | line_spans: _, | 
|  | }) => { | 
|  | for op in &**operands { | 
|  | use InlineAsmOperand::*; | 
|  | match op { | 
|  | In { expr, reg: _ } | 
|  | | Out { expr: Some(expr), reg: _, late: _ } | 
|  | | InOut { expr, reg: _, late: _ } => visitor.visit_expr(&visitor.thir()[*expr]), | 
|  | SplitInOut { in_expr, out_expr, reg: _, late: _ } => { | 
|  | visitor.visit_expr(&visitor.thir()[*in_expr]); | 
|  | if let Some(out_expr) = out_expr { | 
|  | visitor.visit_expr(&visitor.thir()[*out_expr]); | 
|  | } | 
|  | } | 
|  | Out { expr: None, reg: _, late: _ } | 
|  | | Const { value: _, span: _ } | 
|  | | SymFn { value: _ } | 
|  | | SymStatic { def_id: _ } => {} | 
|  | Label { block } => visitor.visit_block(&visitor.thir()[*block]), | 
|  | } | 
|  | } | 
|  | } | 
|  | OffsetOf { container: _, fields: _ } => {} | 
|  | ThreadLocalRef(_) => {} | 
|  | Yield { value } => visitor.visit_expr(&visitor.thir()[value]), | 
|  | } | 
|  | } | 
|  |  | 
|  | pub fn walk_stmt<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( | 
|  | visitor: &mut V, | 
|  | stmt: &'thir Stmt<'tcx>, | 
|  | ) { | 
|  | let Stmt { kind } = stmt; | 
|  | match kind { | 
|  | StmtKind::Expr { expr, scope: _ } => visitor.visit_expr(&visitor.thir()[*expr]), | 
|  | StmtKind::Let { | 
|  | initializer, | 
|  | remainder_scope: _, | 
|  | init_scope: _, | 
|  | pattern, | 
|  | lint_level: _, | 
|  | else_block, | 
|  | span: _, | 
|  | } => { | 
|  | if let Some(init) = initializer { | 
|  | visitor.visit_expr(&visitor.thir()[*init]); | 
|  | } | 
|  | visitor.visit_pat(pattern); | 
|  | if let Some(block) = else_block { | 
|  | visitor.visit_block(&visitor.thir()[*block]) | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | pub fn walk_block<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( | 
|  | visitor: &mut V, | 
|  | block: &'thir Block, | 
|  | ) { | 
|  | let Block { stmts, expr, targeted_by_break: _, region_scope: _, span: _, safety_mode: _ } = | 
|  | block; | 
|  | for &stmt in &*stmts { | 
|  | visitor.visit_stmt(&visitor.thir()[stmt]); | 
|  | } | 
|  | if let Some(expr) = expr { | 
|  | visitor.visit_expr(&visitor.thir()[*expr]); | 
|  | } | 
|  | } | 
|  |  | 
|  | pub fn walk_arm<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( | 
|  | visitor: &mut V, | 
|  | arm: &'thir Arm<'tcx>, | 
|  | ) { | 
|  | let Arm { guard, pattern, body, lint_level: _, span: _, scope: _ } = arm; | 
|  | if let Some(expr) = guard { | 
|  | visitor.visit_expr(&visitor.thir()[*expr]) | 
|  | } | 
|  | visitor.visit_pat(pattern); | 
|  | visitor.visit_expr(&visitor.thir()[*body]); | 
|  | } | 
|  |  | 
|  | pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( | 
|  | visitor: &mut V, | 
|  | pat: &'thir Pat<'tcx>, | 
|  | ) { | 
|  | for_each_immediate_subpat(pat, |p| visitor.visit_pat(p)); | 
|  | } | 
|  |  | 
|  | /// Invokes `callback` on each immediate subpattern of `pat`, if any. | 
|  | /// A building block for assembling THIR pattern visitors. | 
|  | pub(crate) fn for_each_immediate_subpat<'a, 'tcx>( | 
|  | pat: &'a Pat<'tcx>, | 
|  | mut callback: impl FnMut(&'a Pat<'tcx>), | 
|  | ) { | 
|  | let Pat { kind, ty: _, span: _ } = pat; | 
|  | match kind { | 
|  | PatKind::Missing | 
|  | | PatKind::Wild | 
|  | | PatKind::Binding { subpattern: None, .. } | 
|  | | PatKind::Constant { value: _ } | 
|  | | PatKind::Range(_) | 
|  | | PatKind::Never | 
|  | | PatKind::Error(_) => {} | 
|  |  | 
|  | PatKind::AscribeUserType { subpattern, .. } | 
|  | | PatKind::Binding { subpattern: Some(subpattern), .. } | 
|  | | PatKind::Deref { subpattern } | 
|  | | PatKind::DerefPattern { subpattern, .. } | 
|  | | PatKind::ExpandedConstant { subpattern, .. } => callback(subpattern), | 
|  |  | 
|  | PatKind::Variant { subpatterns, .. } | PatKind::Leaf { subpatterns } => { | 
|  | for field_pat in subpatterns { | 
|  | callback(&field_pat.pattern); | 
|  | } | 
|  | } | 
|  |  | 
|  | PatKind::Slice { prefix, slice, suffix } | PatKind::Array { prefix, slice, suffix } => { | 
|  | for pat in prefix.iter().chain(slice.as_deref()).chain(suffix) { | 
|  | callback(pat); | 
|  | } | 
|  | } | 
|  |  | 
|  | PatKind::Or { pats } => { | 
|  | for pat in pats { | 
|  | callback(pat); | 
|  | } | 
|  | } | 
|  | } | 
|  | } |