use super::Options;
use crate::codegen::{cfg::ControlFlowGraph, vartable::Vartable, OptimizationLevel};
use crate::sema::ast::RetrieveType;
use crate::sema::ast::{Builtin, Expression, Function, Namespace};
use crate::sema::symtable::VariableUsage;
pub struct SideEffectsCheckParameters<'a> {
pub cfg: &'a mut ControlFlowGraph,
pub contract_no: usize,
pub func: Option<&'a Function>,
pub ns: &'a Namespace,
pub vartab: &'a mut Vartable,
pub opt: &'a Options,
}
pub fn should_remove_assignment(
exp: &Expression,
func: &Function,
opt: &Options,
ns: &Namespace,
) -> bool {
if opt.opt_level == OptimizationLevel::None {
return false;
}
match &exp {
Expression::Variable { var_no, .. } => should_remove_variable(*var_no, func, opt, ns),
Expression::StructMember { expr, .. } => should_remove_assignment(expr, func, opt, ns),
Expression::Subscript { array, .. } => should_remove_assignment(array, func, opt, ns),
Expression::StorageLoad { expr, .. }
| Expression::Load { expr, .. }
| Expression::Trunc { expr, .. }
| Expression::Cast { expr, .. }
| Expression::BytesCast { expr, .. } => should_remove_assignment(expr, func, opt, ns),
Expression::Builtin {
kind: Builtin::ArrayLength,
args,
..
} => should_remove_assignment(&args[0], func, opt, ns),
Expression::Builtin {
kind: Builtin::ArrayPop | Builtin::ArrayPush,
args,
..
} => {
if args[0].ty().is_contract_storage() {
return false;
}
should_remove_assignment(&args[0], func, opt, ns)
}
_ => false,
}
}
pub fn should_remove_variable(pos: usize, func: &Function, opt: &Options, ns: &Namespace) -> bool {
if opt.opt_level == OptimizationLevel::None {
return false;
}
let var = &func.symtable.vars[&pos];
if !var.read && !var.assigned {
return true;
}
if !var.read
&& var.assigned
&& matches!(
var.usage_type,
VariableUsage::DestructureVariable | VariableUsage::LocalVariable
)
{
return !var.is_reference(ns);
}
false
}