mod array_boundary;
pub mod cfg;
mod constant_folding;
mod constructor;
mod dead_storage;
pub(crate) mod dispatch;
pub(crate) mod encoding;
mod events;
mod expression;
pub(super) mod polkadot;
mod reaching_definitions;
pub mod revert;
mod solana_accounts;
mod solana_deploy;
mod statements;
mod storage;
mod strength_reduce;
pub(crate) mod subexpression_elimination;
mod tests;
mod undefined_variable;
mod unused_variable;
pub(crate) mod vartable;
mod vector_to_slice;
mod yul;
use self::{
cfg::{optimize_and_check_cfg, ControlFlowGraph, Instr},
dispatch::function_dispatch,
expression::expression,
solana_accounts::account_collection::collect_accounts_from_contract,
vartable::Vartable,
};
use crate::sema::ast::{
FormatArg, Function, Layout, Namespace, RetrieveType, StringLocation, Type,
};
use crate::{sema::ast, Target};
use std::cmp::Ordering;
use crate::codegen::cfg::ASTFunction;
use crate::codegen::solana_accounts::account_management::manage_contract_accounts;
use crate::codegen::yul::generate_yul_function_cfg;
use crate::sema::diagnostics::Diagnostics;
use crate::sema::eval::eval_const_number;
use crate::sema::Recurse;
#[cfg(feature = "wasm_opt")]
use contract_build::OptimizationPasses;
use encoding::soroban_encoding::soroban_encode_arg;
use num_bigint::{BigInt, Sign};
use num_rational::BigRational;
use num_traits::{FromPrimitive, Zero};
use solang_parser::diagnostics::Diagnostic;
use solang_parser::{pt, pt::CodeLocation};
pub const SOLANA_FIRST_OFFSET: u64 = 16;
pub const STORAGE_INITIALIZER: &str = "storage_initializer";
pub const MAXIMUM_ACCOUNT_SIZE: u64 = 10 * 1024 * 1024;
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum OptimizationLevel {
None = 0,
Less = 1,
Default = 2,
Aggressive = 3,
}
#[cfg(feature = "llvm")]
impl From<OptimizationLevel> for inkwell::OptimizationLevel {
fn from(level: OptimizationLevel) -> Self {
match level {
OptimizationLevel::None => inkwell::OptimizationLevel::None,
OptimizationLevel::Less => inkwell::OptimizationLevel::Less,
OptimizationLevel::Default => inkwell::OptimizationLevel::Default,
OptimizationLevel::Aggressive => inkwell::OptimizationLevel::Aggressive,
}
}
}
#[cfg(feature = "llvm")]
impl From<inkwell::OptimizationLevel> for OptimizationLevel {
fn from(level: inkwell::OptimizationLevel) -> Self {
match level {
inkwell::OptimizationLevel::None => OptimizationLevel::None,
inkwell::OptimizationLevel::Less => OptimizationLevel::Less,
inkwell::OptimizationLevel::Default => OptimizationLevel::Default,
inkwell::OptimizationLevel::Aggressive => OptimizationLevel::Aggressive,
}
}
}
pub enum HostFunctions {
PutContractData,
GetContractData,
HasContractData,
ExtendContractDataTtl,
ExtendCurrentContractInstanceAndCodeTtl,
LogFromLinearMemory,
SymbolNewFromLinearMemory,
VectorNew,
VectorNewFromLinearMemory,
MapNewFromLinearMemory,
Call,
ObjToU64,
ObjFromU64,
ObjToI128Lo64,
ObjToI128Hi64,
ObjToU128Lo64,
ObjToU128Hi64,
ObjFromI128Pieces,
ObjFromU128Pieces,
RequireAuth,
AuthAsCurrContract,
MapNew,
MapPut,
VecPushBack,
StringNewFromLinearMemory,
StrKeyToAddr,
GetCurrentContractAddress,
}
impl HostFunctions {
pub fn name(&self) -> &str {
match self {
HostFunctions::PutContractData => "l._",
HostFunctions::GetContractData => "l.1",
HostFunctions::HasContractData => "l.0",
HostFunctions::ExtendContractDataTtl => "l.7",
HostFunctions::ExtendCurrentContractInstanceAndCodeTtl => "l.8",
HostFunctions::LogFromLinearMemory => "x._",
HostFunctions::SymbolNewFromLinearMemory => "b.j",
HostFunctions::VectorNew => "v._",
HostFunctions::VectorNewFromLinearMemory => "v.g",
HostFunctions::Call => "d._",
HostFunctions::ObjToU64 => "i.0",
HostFunctions::ObjFromU64 => "i._",
HostFunctions::ObjToI128Lo64 => "i.7",
HostFunctions::ObjToI128Hi64 => "i.8",
HostFunctions::ObjToU128Lo64 => "i.4",
HostFunctions::ObjToU128Hi64 => "i.5",
HostFunctions::ObjFromI128Pieces => "i.6",
HostFunctions::ObjFromU128Pieces => "i.3",
HostFunctions::RequireAuth => "a.0",
HostFunctions::AuthAsCurrContract => "a.3",
HostFunctions::MapNewFromLinearMemory => "m.9",
HostFunctions::MapNew => "m._",
HostFunctions::MapPut => "m.0",
HostFunctions::VecPushBack => "v.6",
HostFunctions::StringNewFromLinearMemory => "b.i",
HostFunctions::StrKeyToAddr => "a.1",
HostFunctions::GetCurrentContractAddress => "x.7",
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Options {
pub dead_storage: bool,
pub constant_folding: bool,
pub strength_reduce: bool,
pub vector_to_slice: bool,
pub common_subexpression_elimination: bool,
pub generate_debug_information: bool,
pub opt_level: OptimizationLevel,
pub log_runtime_errors: bool,
pub log_prints: bool,
#[cfg(feature = "wasm_opt")]
pub wasm_opt: Option<OptimizationPasses>,
pub soroban_version: Option<u64>,
}
impl Default for Options {
fn default() -> Self {
Options {
dead_storage: true,
constant_folding: true,
strength_reduce: true,
vector_to_slice: true,
common_subexpression_elimination: true,
generate_debug_information: false,
opt_level: OptimizationLevel::Default,
log_runtime_errors: false,
log_prints: true,
#[cfg(feature = "wasm_opt")]
wasm_opt: None,
soroban_version: None,
}
}
}
pub fn codegen(ns: &mut Namespace, opt: &Options) {
if ns.diagnostics.any_errors() {
return;
}
let mut contracts_done = Vec::new();
contracts_done.resize(ns.contracts.len(), false);
while contracts_done.iter().any(|e| !*e) {
for contract_no in 0..ns.contracts.len() {
if contracts_done[contract_no] {
continue;
}
if !ns.contracts[contract_no].instantiable {
contracts_done[contract_no] = true;
continue;
}
if ns.contracts[contract_no]
.creates
.iter()
.any(|c| !contracts_done[*c])
{
continue;
}
contract(contract_no, ns, opt);
if ns.diagnostics.any_errors() {
return;
}
contracts_done[contract_no] = true;
}
}
if ns.target == Target::Solana {
for contract_no in 0..ns.contracts.len() {
if ns.contracts[contract_no].instantiable {
let diag = collect_accounts_from_contract(contract_no, ns);
ns.diagnostics.extend(diag);
}
}
for contract_no in 0..ns.contracts.len() {
if ns.contracts[contract_no].instantiable {
manage_contract_accounts(contract_no, ns);
}
}
}
ns.diagnostics.sort_and_dedup();
}
fn contract(contract_no: usize, ns: &mut Namespace, opt: &Options) {
if !ns.diagnostics.any_errors() && ns.contracts[contract_no].instantiable {
layout(contract_no, ns);
let mut cfg_no = 0;
let mut all_cfg = Vec::new();
for (_, func_cfg) in ns.contracts[contract_no].all_functions.iter_mut() {
*func_cfg = cfg_no;
cfg_no += 1;
}
for yul_fn_no in &ns.contracts[contract_no].yul_functions {
ns.yul_functions[*yul_fn_no].cfg_no = cfg_no;
cfg_no += 1;
}
all_cfg.resize(cfg_no, ControlFlowGraph::placeholder());
for (function_no, cfg_no) in ns.contracts[contract_no]
.all_functions
.iter()
.map(|(function_no, cfg_no)| (*function_no, *cfg_no))
.collect::<Vec<(usize, usize)>>()
.into_iter()
{
cfg::generate_cfg(
contract_no,
Some(function_no),
cfg_no,
&mut all_cfg,
ns,
opt,
)
}
for yul_func_no in ns.contracts[contract_no].yul_functions.clone() {
generate_yul_function_cfg(contract_no, yul_func_no, &mut all_cfg, ns, opt);
}
let cfg = storage_initializer(contract_no, ns, opt);
let pos = all_cfg.len();
all_cfg.push(cfg);
ns.contracts[contract_no].initializer = Some(pos);
if ns.contracts[contract_no].constructors(ns).is_empty() {
let func = ns.default_constructor(contract_no);
let cfg_no = all_cfg.len();
all_cfg.push(ControlFlowGraph::placeholder());
cfg::generate_cfg(contract_no, None, cfg_no, &mut all_cfg, ns, opt);
ns.contracts[contract_no].default_constructor = Some((func, cfg_no));
}
for mut dispatch_cfg in function_dispatch(contract_no, &mut all_cfg, ns, opt) {
optimize_and_check_cfg(&mut dispatch_cfg, ns, ASTFunction::None, opt);
all_cfg.push(dispatch_cfg);
}
ns.contracts[contract_no].cfg = all_cfg;
}
}
fn storage_initializer(contract_no: usize, ns: &mut Namespace, opt: &Options) -> ControlFlowGraph {
let mut cfg = ControlFlowGraph::new(STORAGE_INITIALIZER.to_string(), ASTFunction::None);
let mut vartab = Vartable::new(ns.next_id);
for layout in &ns.contracts[contract_no].layout {
let var = &ns.contracts[layout.contract_no].variables[layout.var_no];
if let Some(init) = &var.initializer {
let storage = ns.contracts[contract_no].get_storage_slot(
pt::Loc::Codegen,
layout.contract_no,
layout.var_no,
ns,
None,
);
let mut value = expression(init, &mut cfg, contract_no, None, ns, &mut vartab, opt);
if ns.target == Target::Soroban {
value = soroban_encode_arg(value, &mut cfg, &mut vartab, ns);
}
cfg.add(
&mut vartab,
Instr::SetStorage {
value,
ty: var.ty.clone(),
storage,
storage_type: var.storage_type.clone(),
},
);
}
}
cfg.add(&mut vartab, Instr::Return { value: Vec::new() });
vartab.finalize(ns, &mut cfg);
optimize_and_check_cfg(&mut cfg, ns, ASTFunction::None, opt);
cfg
}
fn layout(contract_no: usize, ns: &mut Namespace) {
let mut slot = if ns.target == Target::Solana {
BigInt::from(SOLANA_FIRST_OFFSET)
} else {
BigInt::zero()
};
for base_contract_no in ns.contract_bases(contract_no) {
for var_no in 0..ns.contracts[base_contract_no].variables.len() {
if !ns.contracts[base_contract_no].variables[var_no].constant {
let ty = ns.contracts[base_contract_no].variables[var_no].ty.clone();
if ns.target == Target::Solana {
let alignment = ty.align_of(ns);
let offset = slot.clone() % alignment;
if offset > BigInt::zero() {
slot += alignment - offset;
}
}
ns.contracts[contract_no].layout.push(Layout {
slot: slot.clone(),
contract_no: base_contract_no,
var_no,
ty: ty.clone(),
});
slot += ty.storage_slots(ns);
}
}
}
let constructors = ns.contracts[contract_no].constructors(ns);
if !constructors.is_empty() {
if let Some((_, exp)) = &ns.functions[constructors[0]].annotations.space {
assert_eq!(ns.target, Target::Solana);
if let Ok((_, value)) = eval_const_number(exp, ns, &mut Diagnostics::default()) {
if slot > value {
ns.diagnostics.push(Diagnostic::error(
exp.loc(),
format!("contract requires at least {} bytes of space", slot),
));
} else if value > BigInt::from(MAXIMUM_ACCOUNT_SIZE) {
ns.diagnostics.push(Diagnostic::error(
exp.loc(),
"Solana's runtime does not permit accounts larger than 10 MB".to_string(),
));
}
}
}
}
ns.contracts[contract_no].fixed_layout_size = slot;
}
trait LLVMName {
fn llvm_symbol(&self, ns: &Namespace) -> String;
}
impl LLVMName for Function {
fn llvm_symbol(&self, ns: &Namespace) -> String {
let mut sig = self.id.name.to_owned();
if !self.params.is_empty() {
sig.push_str("__");
for (i, p) in self.params.iter().enumerate() {
if i > 0 {
sig.push('_');
}
sig.push_str(&p.ty.to_llvm_string(ns));
}
}
sig
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Expression {
Add {
loc: pt::Loc,
ty: Type,
overflowing: bool,
left: Box<Expression>,
right: Box<Expression>,
},
AllocDynamicBytes {
loc: pt::Loc,
ty: Type,
size: Box<Expression>,
initializer: Option<Vec<u8>>,
},
ArrayLiteral {
loc: pt::Loc,
ty: Type,
dimensions: Vec<u32>,
values: Vec<Expression>,
},
BitwiseAnd {
loc: pt::Loc,
ty: Type,
left: Box<Expression>,
right: Box<Expression>,
},
BitwiseOr {
loc: pt::Loc,
ty: Type,
left: Box<Expression>,
right: Box<Expression>,
},
BitwiseXor {
loc: pt::Loc,
ty: Type,
left: Box<Expression>,
right: Box<Expression>,
},
BoolLiteral {
loc: pt::Loc,
value: bool,
},
Builtin {
loc: pt::Loc,
tys: Vec<Type>,
kind: Builtin,
args: Vec<Expression>,
},
BytesCast {
loc: pt::Loc,
ty: Type,
from: Type,
expr: Box<Expression>,
},
BytesLiteral {
loc: pt::Loc,
ty: Type,
value: Vec<u8>,
},
Cast {
loc: pt::Loc,
ty: Type,
expr: Box<Expression>,
},
BitwiseNot {
loc: pt::Loc,
ty: Type,
expr: Box<Expression>,
},
ConstArrayLiteral {
loc: pt::Loc,
ty: Type,
dimensions: Vec<u32>,
values: Vec<Expression>,
},
UnsignedDivide {
loc: pt::Loc,
ty: Type,
left: Box<Expression>,
right: Box<Expression>,
},
SignedDivide {
loc: pt::Loc,
ty: Type,
left: Box<Expression>,
right: Box<Expression>,
},
Equal {
loc: pt::Loc,
left: Box<Expression>,
right: Box<Expression>,
},
FormatString {
loc: pt::Loc,
args: Vec<(FormatArg, Expression)>,
},
FunctionArg {
loc: pt::Loc,
ty: Type,
arg_no: usize,
},
GetRef {
loc: pt::Loc,
ty: Type,
expr: Box<Expression>,
},
InternalFunctionCfg {
ty: Type,
cfg_no: usize,
},
Keccak256 {
loc: pt::Loc,
ty: Type,
exprs: Vec<Expression>,
},
Less {
loc: pt::Loc,
signed: bool,
left: Box<Expression>,
right: Box<Expression>,
},
LessEqual {
loc: pt::Loc,
signed: bool,
left: Box<Expression>,
right: Box<Expression>,
},
Load {
loc: pt::Loc,
ty: Type,
expr: Box<Expression>,
},
UnsignedModulo {
loc: pt::Loc,
ty: Type,
left: Box<Expression>,
right: Box<Expression>,
},
SignedModulo {
loc: pt::Loc,
ty: Type,
left: Box<Expression>,
right: Box<Expression>,
},
More {
loc: pt::Loc,
signed: bool,
left: Box<Expression>,
right: Box<Expression>,
},
MoreEqual {
loc: pt::Loc,
signed: bool,
left: Box<Expression>,
right: Box<Expression>,
},
Multiply {
loc: pt::Loc,
ty: Type,
overflowing: bool,
left: Box<Expression>,
right: Box<Expression>,
},
Not {
loc: pt::Loc,
expr: Box<Expression>,
},
NotEqual {
loc: pt::Loc,
left: Box<Expression>,
right: Box<Expression>,
},
NumberLiteral {
loc: pt::Loc,
ty: Type,
value: BigInt,
},
Poison,
Power {
loc: pt::Loc,
ty: Type,
overflowing: bool,
base: Box<Expression>,
exp: Box<Expression>,
},
RationalNumberLiteral {
loc: pt::Loc,
ty: Type,
rational: BigRational,
},
ReturnData {
loc: pt::Loc,
},
SignExt {
loc: pt::Loc,
ty: Type,
expr: Box<Expression>,
},
ShiftLeft {
loc: pt::Loc,
ty: Type,
left: Box<Expression>,
right: Box<Expression>,
},
ShiftRight {
loc: pt::Loc,
ty: Type,
left: Box<Expression>,
right: Box<Expression>,
signed: bool,
},
StorageArrayLength {
loc: pt::Loc,
ty: Type,
array: Box<Expression>,
elem_ty: Type,
},
StringCompare {
loc: pt::Loc,
left: StringLocation<Expression>,
right: StringLocation<Expression>,
},
StructLiteral {
loc: pt::Loc,
ty: Type,
values: Vec<Expression>,
},
StructMember {
loc: pt::Loc,
ty: Type,
expr: Box<Expression>,
member: usize,
},
Subscript {
loc: pt::Loc,
ty: Type,
array_ty: Type,
expr: Box<Expression>,
index: Box<Expression>,
},
Subtract {
loc: pt::Loc,
ty: Type,
overflowing: bool,
left: Box<Expression>,
right: Box<Expression>,
},
Trunc {
loc: pt::Loc,
ty: Type,
expr: Box<Expression>,
},
Negate {
loc: pt::Loc,
ty: Type,
overflowing: bool,
expr: Box<Expression>,
},
Undefined {
ty: Type,
},
Variable {
loc: pt::Loc,
ty: Type,
var_no: usize,
},
ZeroExt {
loc: pt::Loc,
ty: Type,
expr: Box<Expression>,
},
AdvancePointer {
pointer: Box<Expression>,
bytes_offset: Box<Expression>,
},
VectorData {
pointer: Box<Expression>,
},
}
impl CodeLocation for Expression {
fn loc(&self) -> pt::Loc {
match self {
Expression::StorageArrayLength { loc, .. }
| Expression::Builtin { loc, .. }
| Expression::Cast { loc, .. }
| Expression::NumberLiteral { loc, .. }
| Expression::Keccak256 { loc, .. }
| Expression::MoreEqual { loc, .. }
| Expression::ReturnData { loc }
| Expression::Subscript { loc, .. }
| Expression::Trunc { loc, .. }
| Expression::Variable { loc, .. }
| Expression::SignExt { loc, .. }
| Expression::GetRef { loc, .. }
| Expression::Load { loc, .. }
| Expression::BytesLiteral { loc, .. }
| Expression::Add { loc, .. }
| Expression::Multiply { loc, .. }
| Expression::Subtract { loc, .. }
| Expression::FormatString { loc, .. }
| Expression::LessEqual { loc, .. }
| Expression::BoolLiteral { loc, .. }
| Expression::UnsignedDivide { loc, .. }
| Expression::SignedDivide { loc, .. }
| Expression::UnsignedModulo { loc, .. }
| Expression::SignedModulo { loc, .. }
| Expression::Power { loc, .. }
| Expression::BitwiseOr { loc, .. }
| Expression::BitwiseAnd { loc, .. }
| Expression::BitwiseXor { loc, .. }
| Expression::Equal { loc, .. }
| Expression::NotEqual { loc, .. }
| Expression::BitwiseNot { loc, .. }
| Expression::Negate { loc, .. }
| Expression::Less { loc, .. }
| Expression::Not { loc, .. }
| Expression::StructLiteral { loc, .. }
| Expression::ArrayLiteral { loc, .. }
| Expression::ConstArrayLiteral { loc, .. }
| Expression::StructMember { loc, .. }
| Expression::StringCompare { loc, .. }
| Expression::FunctionArg { loc, .. }
| Expression::ShiftRight { loc, .. }
| Expression::ShiftLeft { loc, .. }
| Expression::RationalNumberLiteral { loc, .. }
| Expression::AllocDynamicBytes { loc, .. }
| Expression::BytesCast { loc, .. }
| Expression::More { loc, .. }
| Expression::ZeroExt { loc, .. } => *loc,
Expression::InternalFunctionCfg { .. }
| Expression::Poison
| Expression::Undefined { .. }
| Expression::AdvancePointer { .. }
| Expression::VectorData { .. } => pt::Loc::Codegen,
}
}
}
impl Recurse for Expression {
type ArgType = Expression;
fn recurse<T>(&self, cx: &mut T, f: fn(expr: &Expression, ctx: &mut T) -> bool) {
if !f(self, cx) {
return;
}
match self {
Expression::BitwiseAnd { left, right, .. }
| Expression::BitwiseOr { left, right, .. }
| Expression::UnsignedDivide { left, right, .. }
| Expression::SignedDivide { left, right, .. }
| Expression::Equal { left, right, .. }
| Expression::Less { left, right, .. }
| Expression::LessEqual { left, right, .. }
| Expression::BitwiseXor { left, right, .. }
| Expression::More { left, right, .. }
| Expression::MoreEqual { left, right, .. }
| Expression::Multiply { left, right, .. }
| Expression::NotEqual { left, right, .. }
| Expression::ShiftLeft { left, right, .. }
| Expression::ShiftRight { left, right, .. }
| Expression::Power {
base: left,
exp: right,
..
}
| Expression::Subscript {
expr: left,
index: right,
..
}
| Expression::Subtract { left, right, .. }
| Expression::AdvancePointer {
pointer: left,
bytes_offset: right,
..
}
| Expression::Add { left, right, .. } => {
left.recurse(cx, f);
right.recurse(cx, f);
}
Expression::BytesCast { expr, .. }
| Expression::Cast { expr, .. }
| Expression::GetRef { expr, .. }
| Expression::Not { expr, .. }
| Expression::Trunc { expr, .. }
| Expression::Negate { expr, .. }
| Expression::ZeroExt { expr, .. }
| Expression::SignExt { expr, .. }
| Expression::BitwiseNot { expr, .. }
| Expression::Load { expr, .. }
| Expression::StorageArrayLength { array: expr, .. }
| Expression::StructMember { expr, .. }
| Expression::AllocDynamicBytes { size: expr, .. } => {
expr.recurse(cx, f);
}
Expression::Builtin { args, .. }
| Expression::ConstArrayLiteral { values: args, .. }
| Expression::Keccak256 { exprs: args, .. }
| Expression::StructLiteral { values: args, .. }
| Expression::ArrayLiteral { values: args, .. } => {
for item in args {
item.recurse(cx, f);
}
}
Expression::FormatString { args, .. } => {
for item in args {
item.1.recurse(cx, f);
}
}
Expression::StringCompare { left, right, .. } => {
if let StringLocation::RunTime(exp) = left {
exp.recurse(cx, f);
}
if let StringLocation::RunTime(exp) = right {
exp.recurse(cx, f);
}
}
_ => (),
}
}
}
impl RetrieveType for Expression {
fn ty(&self) -> Type {
match self {
Expression::ReturnData { loc: _ } => Type::DynamicBytes,
Expression::Builtin { tys, .. } => {
assert_eq!(tys.len(), 1);
tys[0].clone()
}
Expression::Keccak256 { ty, .. }
| Expression::Undefined { ty }
| Expression::Variable { ty, .. }
| Expression::Trunc { ty, .. }
| Expression::ZeroExt { ty, .. }
| Expression::Cast { ty, .. }
| Expression::SignExt { ty, .. }
| Expression::GetRef { ty, .. }
| Expression::Load { ty, .. }
| Expression::BytesLiteral { ty, .. }
| Expression::Add { ty, .. }
| Expression::NumberLiteral { ty, .. }
| Expression::Multiply { ty, .. }
| Expression::Subtract { ty, .. }
| Expression::SignedDivide { ty, .. }
| Expression::UnsignedDivide { ty, .. }
| Expression::SignedModulo { ty, .. }
| Expression::UnsignedModulo { ty, .. }
| Expression::Power { ty, .. }
| Expression::BitwiseOr { ty, .. }
| Expression::BitwiseAnd { ty, .. }
| Expression::BitwiseXor { ty, .. }
| Expression::ShiftLeft { ty, .. }
| Expression::ShiftRight { ty, .. }
| Expression::BitwiseNot { ty, .. }
| Expression::StorageArrayLength { ty, .. }
| Expression::Negate { ty, .. }
| Expression::StructLiteral { ty, .. }
| Expression::ArrayLiteral { ty, .. }
| Expression::ConstArrayLiteral { ty, .. }
| Expression::StructMember { ty, .. }
| Expression::FunctionArg { ty, .. }
| Expression::AllocDynamicBytes { ty, .. }
| Expression::BytesCast { ty, .. }
| Expression::RationalNumberLiteral { ty, .. }
| Expression::Subscript { ty, .. }
| Expression::InternalFunctionCfg { ty, .. } => ty.clone(),
Expression::BoolLiteral { .. }
| Expression::MoreEqual { .. }
| Expression::More { .. }
| Expression::Not { .. }
| Expression::NotEqual { .. }
| Expression::Less { .. }
| Expression::Equal { .. }
| Expression::StringCompare { .. }
| Expression::LessEqual { .. } => Type::Bool,
Expression::AdvancePointer { .. } => Type::BufferPointer,
Expression::FormatString { .. } => Type::String,
Expression::VectorData { .. } => Type::Uint(64),
Expression::Poison => unreachable!("Expression does not have a type"),
}
}
}
impl Expression {
pub(crate) fn add_u32(self, other: Expression) -> Self {
Expression::Add {
loc: pt::Loc::Codegen,
ty: Type::Uint(32),
overflowing: false,
left: self.into(),
right: other.into(),
}
}
pub(crate) fn cast(&self, to: &Type, ns: &Namespace) -> Expression {
let from = self.ty();
if &from == to {
return self.clone();
}
let address_bits = ns.address_length as u16 * 8;
match (self, &from, to) {
(Expression::NumberLiteral { value, .. }, p, &Type::Uint(to_len))
if p.is_primitive() =>
{
return if value.sign() == Sign::Minus {
let mut bs = value.to_signed_bytes_le();
bs.resize(to_len as usize / 8, 0xff);
Expression::NumberLiteral {
loc: self.loc(),
ty: Type::Uint(to_len),
value: BigInt::from_bytes_le(Sign::Plus, &bs),
}
} else {
Expression::NumberLiteral {
loc: self.loc(),
ty: Type::Uint(to_len),
value: value.clone(),
}
}
}
(Expression::NumberLiteral { value, .. }, p, &Type::Int(to_len))
if p.is_primitive() =>
{
return Expression::NumberLiteral {
loc: self.loc(),
ty: Type::Int(to_len),
value: value.clone(),
};
}
(Expression::NumberLiteral { value, .. }, p, &Type::Bytes(to_len))
if p.is_primitive() =>
{
return Expression::NumberLiteral {
loc: self.loc(),
ty: Type::Bytes(to_len),
value: value.clone(),
};
}
(Expression::NumberLiteral { value, .. }, p, &Type::Address(payable))
if p.is_primitive() =>
{
return Expression::NumberLiteral {
loc: self.loc(),
ty: Type::Address(payable),
value: value.clone(),
};
}
(Expression::BytesLiteral { value: bs, .. }, p, &Type::Bytes(to_len))
if p.is_primitive() =>
{
let mut bs = bs.to_owned();
bs.resize(to_len as usize, 0);
return Expression::BytesLiteral {
loc: self.loc(),
ty: Type::Bytes(to_len),
value: bs,
};
}
(
Expression::BytesLiteral {
loc, value: init, ..
},
_,
&Type::DynamicBytes,
)
| (
Expression::BytesLiteral {
loc, value: init, ..
},
_,
&Type::String,
) => {
return Expression::AllocDynamicBytes {
loc: *loc,
ty: to.clone(),
size: Box::new(Expression::NumberLiteral {
loc: *loc,
ty: Type::Uint(32),
value: BigInt::from(init.len()),
}),
initializer: Some(init.clone()),
};
}
(Expression::NumberLiteral { value, .. }, _, &Type::Rational) => {
return Expression::RationalNumberLiteral {
loc: self.loc(),
ty: Type::Rational,
rational: BigRational::from(value.clone()),
};
}
_ => (),
}
let from = match (&from, to) {
(Type::Enum(enum_no), Type::Uint(_)) | (Type::Enum(enum_no), Type::Int(_)) => {
let enum_ty = &ns.enums[*enum_no];
let from_width = enum_ty.ty.bits(ns);
Type::Uint(from_width)
}
(Type::Value, Type::Uint(_)) | (Type::Value, Type::Int(_)) => {
let from_len = (ns.value_length as u16) * 8;
Type::Int(from_len)
}
_ => from,
};
match (&from, to) {
(Type::Uint(from_width), Type::Enum(enum_no))
| (Type::Int(from_width), Type::Enum(enum_no)) => {
let enum_ty = &ns.enums[*enum_no];
let to_width = enum_ty.ty.bits(ns);
match from_width.cmp(&to_width) {
Ordering::Greater => Expression::Trunc {
loc: self.loc(),
ty: to.clone(),
expr: Box::new(self.clone()),
},
Ordering::Less => Expression::ZeroExt {
loc: self.loc(),
ty: to.clone(),
expr: Box::new(self.clone()),
},
Ordering::Equal => Expression::Cast {
loc: self.loc(),
ty: to.clone(),
expr: Box::new(self.clone()),
},
}
}
(Type::Bytes(1), Type::Uint(8)) | (Type::Uint(8), Type::Bytes(1)) => self.clone(),
(Type::Uint(from_len), Type::Uint(to_len))
| (Type::Uint(from_len), Type::Int(to_len)) => match from_len.cmp(to_len) {
Ordering::Greater => Expression::Trunc {
loc: self.loc(),
ty: to.clone(),
expr: Box::new(self.clone()),
},
Ordering::Less => Expression::ZeroExt {
loc: self.loc(),
ty: to.clone(),
expr: Box::new(self.clone()),
},
Ordering::Equal => Expression::Cast {
loc: self.loc(),
ty: to.clone(),
expr: Box::new(self.clone()),
},
},
(Type::Int(from_len), Type::Uint(to_len))
| (Type::Int(from_len), Type::Int(to_len)) => match from_len.cmp(to_len) {
Ordering::Greater => Expression::Trunc {
loc: self.loc(),
ty: to.clone(),
expr: Box::new(self.clone()),
},
Ordering::Less => Expression::SignExt {
loc: self.loc(),
ty: to.clone(),
expr: Box::new(self.clone()),
},
Ordering::Equal => Expression::Cast {
loc: self.loc(),
ty: to.clone(),
expr: Box::new(self.clone()),
},
},
(Type::Uint(from_len), Type::Address(_)) | (Type::Int(from_len), Type::Address(_)) => {
let address_to_int = if from.is_signed_int(ns) {
Type::Int(address_bits)
} else {
Type::Uint(address_bits)
};
let expr = match from_len.cmp(&address_bits) {
Ordering::Greater => Expression::Trunc {
loc: self.loc(),
ty: address_to_int,
expr: Box::new(self.clone()),
},
Ordering::Less if from.is_signed_int(ns) => Expression::ZeroExt {
loc: self.loc(),
ty: to.clone(),
expr: Box::new(self.clone()),
},
Ordering::Less => Expression::SignExt {
loc: self.loc(),
ty: to.clone(),
expr: Box::new(self.clone()),
},
Ordering::Equal => self.clone(),
};
Expression::Cast {
loc: self.loc(),
ty: to.clone(),
expr: Box::new(expr),
}
}
(Type::Address(_), Type::Uint(to_len)) | (Type::Address(_), Type::Int(to_len)) => {
let address_to_int = if to.is_signed_int(ns) {
Type::Int(address_bits)
} else {
Type::Uint(address_bits)
};
let expr = Expression::Cast {
loc: self.loc(),
ty: address_to_int,
expr: Box::new(self.clone()),
};
match to_len.cmp(&address_bits) {
Ordering::Less => Expression::Trunc {
loc: self.loc(),
ty: to.clone(),
expr: Box::new(expr),
},
Ordering::Greater if to.is_signed_int(ns) => Expression::ZeroExt {
loc: self.loc(),
ty: to.clone(),
expr: Box::new(expr),
},
Ordering::Greater => Expression::SignExt {
loc: self.loc(),
ty: to.clone(),
expr: Box::new(expr),
},
Ordering::Equal => expr,
}
}
(Type::Bytes(from_len), Type::Bytes(to_len)) => {
if to_len > from_len {
let shift = (to_len - from_len) * 8;
Expression::ShiftLeft {
loc: self.loc(),
ty: to.clone(),
left: Box::new(Expression::ZeroExt {
loc: self.loc(),
ty: to.clone(),
expr: Box::new(self.clone()),
}),
right: Box::new(Expression::NumberLiteral {
loc: self.loc(),
ty: Type::Uint(*to_len as u16 * 8),
value: BigInt::from_u8(shift).unwrap(),
}),
}
} else {
let shift = (from_len - to_len) * 8;
Expression::Trunc {
loc: self.loc(),
ty: to.clone(),
expr: Box::new(Expression::ShiftRight {
loc: self.loc(),
ty: from.clone(),
left: Box::new(self.clone()),
right: Box::new(Expression::NumberLiteral {
loc: self.loc(),
ty: Type::Uint(*from_len as u16 * 8),
value: BigInt::from_u8(shift).unwrap(),
}),
signed: false,
}),
}
}
}
(Type::Uint(_) | Type::Int(_) | Type::Value, Type::Rational) => Expression::Cast {
loc: self.loc(),
ty: to.clone(),
expr: Box::new(self.clone()),
},
(Type::Bytes(_), Type::DynamicBytes) | (Type::DynamicBytes, Type::Bytes(_)) => {
Expression::BytesCast {
loc: self.loc(),
ty: from.clone(),
from: to.clone(),
expr: Box::new(self.clone()),
}
}
(Type::Bool, Type::Int(_) | Type::Uint(_)) => Expression::Cast {
loc: self.loc(),
ty: to.clone(),
expr: Box::new(self.clone()),
},
(Type::Int(_) | Type::Uint(_), Type::Bool) => Expression::NotEqual {
loc: self.loc(),
left: Box::new(Expression::NumberLiteral {
loc: self.loc(),
ty: self.ty(),
value: BigInt::zero(),
}),
right: Box::new(self.clone()),
},
(Type::Bytes(n), Type::Uint(bits) | Type::Int(bits)) => {
let num_bytes = (bits / 8) as u8;
match n.cmp(&num_bytes) {
Ordering::Greater => Expression::Trunc {
loc: self.loc(),
ty: to.clone(),
expr: Box::new(self.clone()),
},
Ordering::Less => Expression::ZeroExt {
loc: self.loc(),
ty: to.clone(),
expr: Box::new(self.clone()),
},
Ordering::Equal => Expression::Cast {
loc: self.loc(),
ty: to.clone(),
expr: Box::new(self.clone()),
},
}
}
(Type::FunctionSelector, _) => Expression::Cast {
loc: self.loc(),
ty: Type::Bytes(ns.target.selector_length()),
expr: self.clone().into(),
}
.cast(to, ns),
(_, Type::FunctionSelector) => self.cast(&Type::Bytes(ns.target.selector_length()), ns),
(Type::Uint(_), Type::Bytes(_))
| (Type::Int(_), Type::Bytes(_))
| (Type::Bytes(_), Type::Address(_))
| (Type::Address(false), Type::Address(true))
| (Type::Address(_), Type::Contract(_))
| (Type::Contract(_), Type::Address(_))
| (Type::Contract(_), Type::Contract(_))
| (Type::Address(true), Type::Address(false))
| (Type::Address(_), Type::Bytes(_))
| (Type::String, Type::DynamicBytes)
| (Type::DynamicBytes, Type::String)
| (Type::InternalFunction { .. }, Type::InternalFunction { .. })
| (Type::ExternalFunction { .. }, Type::ExternalFunction { .. }) => Expression::Cast {
loc: self.loc(),
ty: to.clone(),
expr: Box::new(self.clone()),
},
_ if !from.is_contract_storage()
&& !to.is_contract_storage()
&& from.is_reference_type(ns)
&& !to.is_reference_type(ns) =>
{
let expr = Expression::Cast {
loc: self.loc(),
ty: Type::Uint(ns.target.ptr_size()),
expr: self.clone().into(),
};
expr.cast(to, ns)
}
_ if !from.is_contract_storage()
&& !to.is_contract_storage()
&& !from.is_reference_type(ns)
&& to.is_reference_type(ns) =>
{
let ptr_ty = Type::Uint(ns.target.ptr_size());
Expression::Cast {
loc: self.loc(),
ty: to.clone(),
expr: self.cast(&ptr_ty, ns).into(),
}
}
_ if !from.is_contract_storage()
&& !to.is_contract_storage()
&& !from.is_reference_type(ns)
&& !to.is_reference_type(ns) =>
{
Expression::Cast {
loc: self.loc(),
ty: to.clone(),
expr: self.clone().into(),
}
}
_ => self.clone(),
}
}
#[must_use]
pub fn copy_filter<T, F>(&self, ctx: &mut T, filter: F) -> Expression
where
F: Fn(&Expression, &mut T) -> Expression,
{
filter(
&match self {
Expression::StructLiteral { loc, ty, values } => Expression::StructLiteral {
loc: *loc,
ty: ty.clone(),
values: values.iter().map(|e| filter(e, ctx)).collect(),
},
Expression::ArrayLiteral {
loc,
ty,
dimensions,
values,
} => Expression::ArrayLiteral {
loc: *loc,
ty: ty.clone(),
dimensions: dimensions.clone(),
values: values.iter().map(|e| filter(e, ctx)).collect(),
},
Expression::ConstArrayLiteral {
loc,
ty,
dimensions,
values,
} => Expression::ConstArrayLiteral {
loc: *loc,
ty: ty.clone(),
dimensions: dimensions.clone(),
values: values.iter().map(|e| filter(e, ctx)).collect(),
},
Expression::Add {
loc,
ty,
overflowing,
left,
right,
} => Expression::Add {
loc: *loc,
ty: ty.clone(),
overflowing: *overflowing,
left: Box::new(filter(left, ctx)),
right: Box::new(filter(right, ctx)),
},
Expression::Subtract {
loc,
ty,
overflowing,
left,
right,
} => Expression::Subtract {
loc: *loc,
ty: ty.clone(),
overflowing: *overflowing,
left: Box::new(filter(left, ctx)),
right: Box::new(filter(right, ctx)),
},
Expression::Multiply {
loc,
ty,
overflowing,
left,
right,
} => Expression::Multiply {
loc: *loc,
ty: ty.clone(),
overflowing: *overflowing,
left: Box::new(filter(left, ctx)),
right: Box::new(filter(right, ctx)),
},
Expression::UnsignedDivide {
loc,
ty,
left,
right,
} => Expression::UnsignedDivide {
loc: *loc,
ty: ty.clone(),
left: Box::new(filter(left, ctx)),
right: Box::new(filter(right, ctx)),
},
Expression::SignedDivide {
loc,
ty,
left,
right,
} => Expression::SignedDivide {
loc: *loc,
ty: ty.clone(),
left: Box::new(filter(left, ctx)),
right: Box::new(filter(right, ctx)),
},
Expression::Power {
loc,
ty,
overflowing,
base,
exp,
} => Expression::Power {
loc: *loc,
ty: ty.clone(),
overflowing: *overflowing,
base: Box::new(filter(base, ctx)),
exp: Box::new(filter(exp, ctx)),
},
Expression::BitwiseOr {
loc,
ty,
left,
right,
} => Expression::BitwiseOr {
loc: *loc,
ty: ty.clone(),
left: Box::new(filter(left, ctx)),
right: Box::new(filter(right, ctx)),
},
Expression::BitwiseAnd {
loc,
ty,
left,
right,
} => Expression::BitwiseAnd {
loc: *loc,
ty: ty.clone(),
left: Box::new(filter(left, ctx)),
right: Box::new(filter(right, ctx)),
},
Expression::BitwiseXor {
loc,
ty,
left,
right,
} => Expression::BitwiseXor {
loc: *loc,
ty: ty.clone(),
left: Box::new(filter(left, ctx)),
right: Box::new(filter(right, ctx)),
},
Expression::ShiftLeft {
loc,
ty,
left,
right,
} => Expression::ShiftLeft {
loc: *loc,
ty: ty.clone(),
left: Box::new(filter(left, ctx)),
right: Box::new(filter(right, ctx)),
},
Expression::ShiftRight {
loc,
ty,
left,
right,
signed: sign_extend,
} => Expression::ShiftRight {
loc: *loc,
ty: ty.clone(),
left: Box::new(filter(left, ctx)),
right: Box::new(filter(right, ctx)),
signed: *sign_extend,
},
Expression::Load { loc, ty, expr } => Expression::Load {
loc: *loc,
ty: ty.clone(),
expr: Box::new(filter(expr, ctx)),
},
Expression::ZeroExt { loc, ty, expr } => Expression::ZeroExt {
loc: *loc,
ty: ty.clone(),
expr: Box::new(filter(expr, ctx)),
},
Expression::SignExt { loc, ty, expr } => Expression::SignExt {
loc: *loc,
ty: ty.clone(),
expr: Box::new(filter(expr, ctx)),
},
Expression::Trunc { loc, ty, expr } => Expression::Trunc {
loc: *loc,
ty: ty.clone(),
expr: Box::new(filter(expr, ctx)),
},
Expression::Cast { loc, ty, expr } => Expression::Cast {
loc: *loc,
ty: ty.clone(),
expr: Box::new(filter(expr, ctx)),
},
Expression::BytesCast {
loc,
ty,
from,
expr,
} => Expression::BytesCast {
loc: *loc,
ty: ty.clone(),
from: from.clone(),
expr: Box::new(filter(expr, ctx)),
},
Expression::More {
loc,
signed,
left,
right,
} => Expression::More {
loc: *loc,
signed: *signed,
left: Box::new(filter(left, ctx)),
right: Box::new(filter(right, ctx)),
},
Expression::Less {
loc,
signed,
left,
right,
} => Expression::Less {
loc: *loc,
signed: *signed,
left: Box::new(filter(left, ctx)),
right: Box::new(filter(right, ctx)),
},
Expression::MoreEqual {
loc,
signed,
left,
right,
} => Expression::MoreEqual {
loc: *loc,
signed: *signed,
left: Box::new(filter(left, ctx)),
right: Box::new(filter(right, ctx)),
},
Expression::LessEqual {
loc,
signed,
left,
right,
} => Expression::LessEqual {
loc: *loc,
signed: *signed,
left: Box::new(filter(left, ctx)),
right: Box::new(filter(right, ctx)),
},
Expression::Equal { loc, left, right } => Expression::Equal {
loc: *loc,
left: Box::new(filter(left, ctx)),
right: Box::new(filter(right, ctx)),
},
Expression::NotEqual { loc, left, right } => Expression::NotEqual {
loc: *loc,
left: Box::new(filter(left, ctx)),
right: Box::new(filter(right, ctx)),
},
Expression::AdvancePointer {
pointer,
bytes_offset: offset,
} => Expression::AdvancePointer {
pointer: Box::new(filter(pointer, ctx)),
bytes_offset: Box::new(filter(offset, ctx)),
},
Expression::Not { loc, expr } => Expression::Not {
loc: *loc,
expr: Box::new(filter(expr, ctx)),
},
Expression::BitwiseNot { loc, ty, expr } => Expression::BitwiseNot {
loc: *loc,
ty: ty.clone(),
expr: Box::new(filter(expr, ctx)),
},
Expression::Negate {
loc,
ty,
overflowing,
expr,
} => Expression::Negate {
loc: *loc,
ty: ty.clone(),
overflowing: *overflowing,
expr: Box::new(filter(expr, ctx)),
},
Expression::Subscript {
loc,
ty: elem_ty,
array_ty,
expr,
index,
} => Expression::Subscript {
loc: *loc,
ty: elem_ty.clone(),
array_ty: array_ty.clone(),
expr: Box::new(filter(expr, ctx)),
index: Box::new(filter(index, ctx)),
},
Expression::StructMember {
loc,
ty,
expr,
member,
} => Expression::StructMember {
loc: *loc,
ty: ty.clone(),
expr: Box::new(filter(expr, ctx)),
member: *member,
},
Expression::AllocDynamicBytes {
loc,
ty,
size,
initializer,
} => Expression::AllocDynamicBytes {
loc: *loc,
ty: ty.clone(),
size: Box::new(filter(size, ctx)),
initializer: initializer.clone(),
},
Expression::StorageArrayLength {
loc,
ty,
array,
elem_ty,
} => Expression::StorageArrayLength {
loc: *loc,
ty: ty.clone(),
array: Box::new(filter(array, ctx)),
elem_ty: elem_ty.clone(),
},
Expression::StringCompare { loc, left, right } => Expression::StringCompare {
loc: *loc,
left: match left {
StringLocation::CompileTime(_) => left.clone(),
StringLocation::RunTime(expr) => {
StringLocation::RunTime(Box::new(filter(expr, ctx)))
}
},
right: match right {
StringLocation::CompileTime(_) => right.clone(),
StringLocation::RunTime(expr) => {
StringLocation::RunTime(Box::new(filter(expr, ctx)))
}
},
},
Expression::FormatString { loc, args } => {
let args = args.iter().map(|(f, e)| (*f, filter(e, ctx))).collect();
Expression::FormatString { loc: *loc, args }
}
Expression::Builtin {
loc,
tys,
kind: builtin,
args,
} => {
let args = args.iter().map(|e| filter(e, ctx)).collect();
Expression::Builtin {
loc: *loc,
tys: tys.clone(),
kind: *builtin,
args,
}
}
_ => self.clone(),
},
ctx,
)
}
fn external_function_selector(&self) -> Expression {
debug_assert!(
matches!(self.ty().deref_any(), Type::ExternalFunction { .. }),
"This is not an external function"
);
let loc = self.loc();
let struct_member = Expression::StructMember {
loc,
ty: Type::Ref(Box::new(Type::FunctionSelector)),
expr: Box::new(self.clone()),
member: 0,
};
Expression::Load {
loc,
ty: Type::FunctionSelector,
expr: Box::new(struct_member),
}
}
fn external_function_address(&self) -> Expression {
debug_assert!(
matches!(self.ty(), Type::ExternalFunction { .. }),
"This is not an external function"
);
let loc = self.loc();
let struct_member = Expression::StructMember {
loc,
ty: Type::Ref(Box::new(Type::Address(false))),
expr: Box::new(self.clone()),
member: 1,
};
Expression::Load {
loc,
ty: Type::Address(false),
expr: Box::new(struct_member),
}
}
}
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
pub enum Builtin {
Accounts,
AddMod,
ArrayLength,
Balance,
Blake2_128,
Blake2_256,
BlockCoinbase,
BlockDifficulty,
BlockHash,
BlockNumber,
Calldata,
ChainId,
ContractCode,
Gasleft,
GasLimit,
Gasprice,
BaseFee,
PrevRandao,
GetAddress,
ExtCodeSize,
MinimumBalance,
MulMod,
Keccak256,
Origin,
ReadFromBuffer,
Ripemd160,
Sender,
Slot,
Sha256,
Signature,
SignatureVerify,
Timestamp,
Value,
WriteAddress,
WriteInt8,
WriteInt16LE,
WriteInt32LE,
WriteInt64LE,
WriteInt128LE,
WriteInt256LE,
WriteUint16LE,
WriteUint32LE,
WriteUint64LE,
WriteUint128LE,
WriteUint256LE,
WriteBytes,
Concat,
RequireAuth,
AuthAsCurrContract,
ExtendTtl,
ExtendInstanceTtl,
AccessMapping,
}
impl From<&ast::Builtin> for Builtin {
fn from(ast_builtin: &ast::Builtin) -> Self {
match ast_builtin {
ast::Builtin::Accounts => Builtin::Accounts,
ast::Builtin::AddMod => Builtin::AddMod,
ast::Builtin::ArrayLength => Builtin::ArrayLength,
ast::Builtin::Balance => Builtin::Balance,
ast::Builtin::Blake2_128 => Builtin::Blake2_128,
ast::Builtin::Blake2_256 => Builtin::Blake2_256,
ast::Builtin::BlockCoinbase => Builtin::BlockCoinbase,
ast::Builtin::BlockDifficulty => Builtin::BlockDifficulty,
ast::Builtin::BlockHash => Builtin::BlockHash,
ast::Builtin::BlockNumber => Builtin::BlockNumber,
ast::Builtin::Calldata => Builtin::Calldata,
ast::Builtin::Gasleft => Builtin::Gasleft,
ast::Builtin::GasLimit => Builtin::GasLimit,
ast::Builtin::Gasprice => Builtin::Gasprice,
ast::Builtin::GetAddress => Builtin::GetAddress,
ast::Builtin::MinimumBalance => Builtin::MinimumBalance,
ast::Builtin::MulMod => Builtin::MulMod,
ast::Builtin::Keccak256 => Builtin::Keccak256,
ast::Builtin::Origin => Builtin::Origin,
ast::Builtin::ReadAddress
| ast::Builtin::ReadInt8
| ast::Builtin::ReadInt16LE
| ast::Builtin::ReadInt32LE
| ast::Builtin::ReadInt64LE
| ast::Builtin::ReadInt128LE
| ast::Builtin::ReadInt256LE
| ast::Builtin::ReadUint16LE
| ast::Builtin::ReadUint32LE
| ast::Builtin::ReadUint64LE
| ast::Builtin::ReadUint128LE
| ast::Builtin::ReadUint256LE => Builtin::ReadFromBuffer,
ast::Builtin::Ripemd160 => Builtin::Ripemd160,
ast::Builtin::Sender => Builtin::Sender,
ast::Builtin::Slot => Builtin::Slot,
ast::Builtin::Sha256 => Builtin::Sha256,
ast::Builtin::Signature => Builtin::Signature,
ast::Builtin::SignatureVerify => Builtin::SignatureVerify,
ast::Builtin::Timestamp => Builtin::Timestamp,
ast::Builtin::Value => Builtin::Value,
ast::Builtin::WriteAddress => Builtin::WriteAddress,
ast::Builtin::WriteInt8 => Builtin::WriteInt8,
ast::Builtin::WriteInt16LE => Builtin::WriteInt16LE,
ast::Builtin::WriteInt32LE => Builtin::WriteInt32LE,
ast::Builtin::WriteInt64LE => Builtin::WriteInt64LE,
ast::Builtin::WriteInt128LE => Builtin::WriteInt128LE,
ast::Builtin::WriteInt256LE => Builtin::WriteInt256LE,
ast::Builtin::WriteUint16LE => Builtin::WriteUint16LE,
ast::Builtin::WriteUint32LE => Builtin::WriteUint32LE,
ast::Builtin::WriteUint64LE => Builtin::WriteUint64LE,
ast::Builtin::WriteUint128LE => Builtin::WriteUint128LE,
ast::Builtin::WriteUint256LE => Builtin::WriteUint256LE,
ast::Builtin::WriteBytes | ast::Builtin::WriteString => Builtin::WriteBytes,
ast::Builtin::ChainId => Builtin::ChainId,
ast::Builtin::BaseFee => Builtin::BaseFee,
ast::Builtin::PrevRandao => Builtin::PrevRandao,
ast::Builtin::ContractCode => Builtin::ContractCode,
ast::Builtin::StringConcat | ast::Builtin::BytesConcat => Builtin::Concat,
ast::Builtin::RequireAuth => Builtin::RequireAuth,
ast::Builtin::AuthAsCurrContract => Builtin::AuthAsCurrContract,
ast::Builtin::ExtendTtl => Builtin::ExtendTtl,
ast::Builtin::ExtendInstanceTtl => Builtin::ExtendInstanceTtl,
_ => panic!("Builtin should not be in the cfg"),
}
}
}