| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912 |
- // SPDX-License-Identifier: Apache-2.0
- 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};
- // The sizeof(struct account_data_header)
- pub const SOLANA_FIRST_OFFSET: u64 = 16;
- /// Name of the storage initializer function
- pub const STORAGE_INITIALIZER: &str = "storage_initializer";
- /// Maximum permitted size of account data (10 MiB).
- /// https://github.com/solana-labs/solana/blob/08aba38d3507c8cb66f85074d8f1249d43e64a75/sdk/program/src/system_instruction.rs#L85
- 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,
- }
- }
- }
- /// The contracts are fully resolved but they do not have any CFGs which is needed for
- /// the llvm code emitter. This will also do additional code checks.
- 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);
- // codegen all the contracts; some additional errors/warnings will be detected here
- 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;
- }
- // does this contract create any contract which are not done
- 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();
- // all the functions should have a cfg_no assigned, so we can generate call instructions to the correct function
- for (_, func_cfg) in ns.contracts[contract_no].all_functions.iter_mut() {
- *func_cfg = cfg_no;
- cfg_no += 1;
- }
- // create a cfg number for yul functions
- 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());
- // clone all_functions so we can pass a mutable reference to generate_cfg
- 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,
- )
- }
- // generate the cfg for yul functions
- 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);
- }
- // Generate cfg for storage initializers
- 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() {
- // generate the default constructor
- 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;
- }
- }
- /// This function will set all contract storage initializers and should be called from the constructor
- fn storage_initializer(contract_no: usize, ns: &mut Namespace, opt: &Options) -> ControlFlowGraph {
- // note the single `:` to prevent a name clash with user-declared functions
- 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
- }
- /// Layout the contract. We determine the layout of variables and deal with overriding variables
- 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 {
- // elements need to be aligned on 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 {
- // This code path is only reachable on Solana
- 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 {
- /// Return a unique string for this function which is a valid llvm symbol
- 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 {
- /// Increment an expression by some value.
- 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;
- // When converting from literals, there is not need to trunc or extend.
- 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];
- // Not checking eval const number
- 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()),
- };
- // now resize int to request size with sign extension etc
- 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,
- }),
- }
- }
- }
- // Conversion from rational will never happen in codegen
- (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) =>
- {
- // cast non-pointer to pointer
- 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) =>
- {
- // cast pointer to different pointer
- Expression::Cast {
- loc: self.loc(),
- ty: to.clone(),
- expr: self.clone().into(),
- }
- }
- _ => self.clone(),
- }
- }
- /// Recurse over expression and copy each element through a filter. This allows the optimizer passes to create
- /// copies of expressions while modifying the results slightly
- #[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 returns a pointer to the address. On Polkadot, this pointer points to the
- /// scratch buffer, to which many syscall write. We strongly recommend loading the pointer
- /// before using on Polkadot. This is not the case for Solana, though.
- 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"),
- }
- }
- }
|