blob: 1a60b1de7fd984e44237ccc53cffdbf1f1230cf6 [file] [log] [blame]
use rustc_middle::thir::*;
use rustc_middle::ty::Const;
pub trait Visitor<'a, 'tcx: 'a>: Sized {
fn thir(&self) -> &'a Thir<'tcx>;
fn visit_expr(&mut self, expr: &Expr<'tcx>) {
walk_expr(self, expr);
}
fn visit_stmt(&mut self, stmt: &Stmt<'tcx>) {
walk_stmt(self, stmt);
}
fn visit_block(&mut self, block: &Block) {
walk_block(self, block);
}
fn visit_arm(&mut self, arm: &Arm<'tcx>) {
walk_arm(self, arm);
}
fn visit_const(&mut self, _cnst: &'tcx Const<'tcx>) {}
}
pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Expr<'tcx>) {
use ExprKind::*;
match expr.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 } => {
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]);
}
}
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]),
Pointer { source, cast: _ } => visitor.visit_expr(&visitor.thir()[source]),
Loop { body } => visitor.visit_expr(&visitor.thir()[body]),
Match { scrutinee, ref arms } => {
visitor.visit_expr(&visitor.thir()[scrutinee]);
for &arm in &**arms {
visitor.visit_arm(&visitor.thir()[arm]);
}
}
Block { ref body } => visitor.visit_block(body),
Assign { lhs, rhs } | AssignOp { lhs, rhs, op: _ } => {
visitor.visit_expr(&visitor.thir()[lhs]);
visitor.visit_expr(&visitor.thir()[rhs]);
}
Field { lhs, 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]),
AddressOf { arg, mutability: _ } => visitor.visit_expr(&visitor.thir()[arg]),
Break { value, label: _ } => {
if let Some(value) = value {
visitor.visit_expr(&visitor.thir()[value])
}
}
Continue { label: _ } => {}
Return { value } => {
if let Some(value) = value {
visitor.visit_expr(&visitor.thir()[value])
}
}
ConstBlock { value } => visitor.visit_const(value),
Repeat { value, count } => {
visitor.visit_expr(&visitor.thir()[value]);
visitor.visit_const(count);
}
Array { ref fields } | Tuple { ref fields } => {
for &field in &**fields {
visitor.visit_expr(&visitor.thir()[field]);
}
}
Adt { ref fields, ref base, adt_def: _, variant_index: _, substs: _, user_ty: _ } => {
for field in &**fields {
visitor.visit_expr(&visitor.thir()[field.expr]);
}
if let Some(base) = base {
visitor.visit_expr(&visitor.thir()[base.base]);
}
}
PlaceTypeAscription { source, user_ty: _ } | ValueTypeAscription { source, user_ty: _ } => {
visitor.visit_expr(&visitor.thir()[source])
}
Closure { closure_id: _, substs: _, upvars: _, movability: _, fake_reads: _ } => {}
Literal { literal, user_ty: _, const_id: _ } => visitor.visit_const(literal),
StaticRef { literal, def_id: _ } => visitor.visit_const(literal),
InlineAsm { 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: _ }
| SymFn { expr } => 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: _ }
| SymStatic { def_id: _ } => {}
}
}
}
ThreadLocalRef(_) => {}
LlvmInlineAsm { ref outputs, ref inputs, asm: _ } => {
for &out_expr in &**outputs {
visitor.visit_expr(&visitor.thir()[out_expr]);
}
for &in_expr in &**inputs {
visitor.visit_expr(&visitor.thir()[in_expr]);
}
}
Yield { value } => visitor.visit_expr(&visitor.thir()[value]),
}
}
pub fn walk_stmt<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, stmt: &Stmt<'tcx>) {
match stmt.kind {
StmtKind::Expr { expr, scope: _ } => visitor.visit_expr(&visitor.thir()[expr]),
StmtKind::Let {
initializer,
remainder_scope: _,
init_scope: _,
pattern: _,
lint_level: _,
} => {
if let Some(init) = initializer {
visitor.visit_expr(&visitor.thir()[init]);
}
}
}
}
pub fn walk_block<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, block: &Block) {
for &stmt in &*block.stmts {
visitor.visit_stmt(&visitor.thir()[stmt]);
}
if let Some(expr) = block.expr {
visitor.visit_expr(&visitor.thir()[expr]);
}
}
pub fn walk_arm<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, arm: &Arm<'tcx>) {
match arm.guard {
Some(Guard::If(expr)) => visitor.visit_expr(&visitor.thir()[expr]),
Some(Guard::IfLet(ref _pat, expr)) => {
visitor.visit_expr(&visitor.thir()[expr]);
}
None => {}
}
visitor.visit_expr(&visitor.thir()[arm.body]);
}