| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378 |
- use super::storage::{
- array_offset, array_pop, array_push, storage_slots_array_pop, storage_slots_array_push,
- };
- use super::Options;
- use super::{
- cfg::{ControlFlowGraph, Instr, InternalCallTy},
- vartable::Vartable,
- };
- use crate::codegen::unused_variable::should_remove_assignment;
- use crate::parser::pt;
- use crate::sema::ast::{
- Builtin, CallTy, Expression, FormatArg, Function, Namespace, Parameter, StringLocation, Type,
- };
- use crate::sema::eval::{eval_const_number, eval_const_rational};
- use crate::sema::expression::{bigint_to_expression, cast, cast_shift_arg, ResolveTo};
- use crate::Target;
- use num_bigint::BigInt;
- use num_traits::{FromPrimitive, One, ToPrimitive, Zero};
- use std::ops::Mul;
- pub fn expression(
- expr: &Expression,
- cfg: &mut ControlFlowGraph,
- contract_no: usize,
- func: Option<&Function>,
- ns: &Namespace,
- vartab: &mut Vartable,
- opt: &Options,
- ) -> Expression {
- match expr {
- Expression::StorageVariable(_, _, var_contract_no, var_no) => {
- // base storage variables should precede contract variables, not overlap
- ns.contracts[contract_no].get_storage_slot(*var_contract_no, *var_no, ns)
- }
- Expression::StorageLoad(loc, ty, expr) => {
- let storage = expression(expr, cfg, contract_no, func, ns, vartab, opt);
- load_storage(loc, ty, storage, cfg, vartab, opt)
- }
- Expression::Add(loc, ty, unchecked, left, right) => add(
- loc,
- ty,
- unchecked,
- left,
- cfg,
- contract_no,
- func,
- ns,
- vartab,
- right,
- opt,
- ),
- Expression::Subtract(loc, ty, unchecked, left, right) => substract(
- loc,
- ty,
- unchecked,
- left,
- cfg,
- contract_no,
- func,
- ns,
- vartab,
- right,
- opt,
- ),
- Expression::Multiply(loc, ty, unchecked, left, right) => {
- if ty.is_rational() {
- let (_, r) = eval_const_rational(expr, Some(contract_no), ns).unwrap();
- Expression::NumberLiteral(*loc, ty.clone(), r.to_integer())
- } else {
- Expression::Multiply(
- *loc,
- ty.clone(),
- *unchecked,
- Box::new(expression(left, cfg, contract_no, func, ns, vartab, opt)),
- Box::new(expression(right, cfg, contract_no, func, ns, vartab, opt)),
- )
- }
- }
- Expression::Divide(loc, ty, left, right) => Expression::Divide(
- *loc,
- ty.clone(),
- Box::new(expression(left, cfg, contract_no, func, ns, vartab, opt)),
- Box::new(expression(right, cfg, contract_no, func, ns, vartab, opt)),
- ),
- Expression::Modulo(loc, ty, left, right) => Expression::Modulo(
- *loc,
- ty.clone(),
- Box::new(expression(left, cfg, contract_no, func, ns, vartab, opt)),
- Box::new(expression(right, cfg, contract_no, func, ns, vartab, opt)),
- ),
- Expression::Power(loc, ty, unchecked, left, right) => Expression::Power(
- *loc,
- ty.clone(),
- *unchecked,
- Box::new(expression(left, cfg, contract_no, func, ns, vartab, opt)),
- Box::new(expression(right, cfg, contract_no, func, ns, vartab, opt)),
- ),
- Expression::BitwiseOr(loc, ty, left, right) => Expression::BitwiseOr(
- *loc,
- ty.clone(),
- Box::new(expression(left, cfg, contract_no, func, ns, vartab, opt)),
- Box::new(expression(right, cfg, contract_no, func, ns, vartab, opt)),
- ),
- Expression::BitwiseAnd(loc, ty, left, right) => Expression::BitwiseAnd(
- *loc,
- ty.clone(),
- Box::new(expression(left, cfg, contract_no, func, ns, vartab, opt)),
- Box::new(expression(right, cfg, contract_no, func, ns, vartab, opt)),
- ),
- Expression::BitwiseXor(loc, ty, left, right) => Expression::BitwiseXor(
- *loc,
- ty.clone(),
- Box::new(expression(left, cfg, contract_no, func, ns, vartab, opt)),
- Box::new(expression(right, cfg, contract_no, func, ns, vartab, opt)),
- ),
- Expression::ShiftLeft(loc, ty, left, right) => Expression::ShiftLeft(
- *loc,
- ty.clone(),
- Box::new(expression(left, cfg, contract_no, func, ns, vartab, opt)),
- Box::new(expression(right, cfg, contract_no, func, ns, vartab, opt)),
- ),
- Expression::ShiftRight(loc, ty, left, right, sign) => Expression::ShiftRight(
- *loc,
- ty.clone(),
- Box::new(expression(left, cfg, contract_no, func, ns, vartab, opt)),
- Box::new(expression(right, cfg, contract_no, func, ns, vartab, opt)),
- *sign,
- ),
- Expression::Equal(loc, left, right) => Expression::Equal(
- *loc,
- Box::new(expression(left, cfg, contract_no, func, ns, vartab, opt)),
- Box::new(expression(right, cfg, contract_no, func, ns, vartab, opt)),
- ),
- Expression::NotEqual(loc, left, right) => Expression::NotEqual(
- *loc,
- Box::new(expression(left, cfg, contract_no, func, ns, vartab, opt)),
- Box::new(expression(right, cfg, contract_no, func, ns, vartab, opt)),
- ),
- Expression::More(loc, left, right) => Expression::More(
- *loc,
- Box::new(expression(left, cfg, contract_no, func, ns, vartab, opt)),
- Box::new(expression(right, cfg, contract_no, func, ns, vartab, opt)),
- ),
- Expression::MoreEqual(loc, left, right) => Expression::MoreEqual(
- *loc,
- Box::new(expression(left, cfg, contract_no, func, ns, vartab, opt)),
- Box::new(expression(right, cfg, contract_no, func, ns, vartab, opt)),
- ),
- Expression::Less(loc, left, right) => Expression::Less(
- *loc,
- Box::new(expression(left, cfg, contract_no, func, ns, vartab, opt)),
- Box::new(expression(right, cfg, contract_no, func, ns, vartab, opt)),
- ),
- Expression::LessEqual(loc, left, right) => Expression::LessEqual(
- *loc,
- Box::new(expression(left, cfg, contract_no, func, ns, vartab, opt)),
- Box::new(expression(right, cfg, contract_no, func, ns, vartab, opt)),
- ),
- Expression::ConstantVariable(_, _, Some(var_contract_no), var_no) => expression(
- ns.contracts[*var_contract_no].variables[*var_no]
- .initializer
- .as_ref()
- .unwrap(),
- cfg,
- contract_no,
- func,
- ns,
- vartab,
- opt,
- ),
- Expression::ConstantVariable(_, _, None, var_no) => expression(
- ns.constants[*var_no].initializer.as_ref().unwrap(),
- cfg,
- contract_no,
- func,
- ns,
- vartab,
- opt,
- ),
- Expression::Not(loc, expr) => Expression::Not(
- *loc,
- Box::new(expression(expr, cfg, contract_no, func, ns, vartab, opt)),
- ),
- Expression::Complement(loc, ty, expr) => Expression::Complement(
- *loc,
- ty.clone(),
- Box::new(expression(expr, cfg, contract_no, func, ns, vartab, opt)),
- ),
- Expression::UnaryMinus(loc, ty, expr) => Expression::UnaryMinus(
- *loc,
- ty.clone(),
- Box::new(expression(expr, cfg, contract_no, func, ns, vartab, opt)),
- ),
- Expression::StructLiteral(loc, ty, exprs) => Expression::StructLiteral(
- *loc,
- ty.clone(),
- exprs
- .iter()
- .map(|e| expression(e, cfg, contract_no, func, ns, vartab, opt))
- .collect(),
- ),
- Expression::ArrayLiteral(loc, ty, lengths, args) => Expression::ArrayLiteral(
- *loc,
- ty.clone(),
- lengths.clone(),
- args.iter()
- .map(|e| expression(e, cfg, contract_no, func, ns, vartab, opt))
- .collect(),
- ),
- Expression::ConstArrayLiteral(loc, ty, lengths, args) => Expression::ConstArrayLiteral(
- *loc,
- ty.clone(),
- lengths.clone(),
- args.iter()
- .map(|e| expression(e, cfg, contract_no, func, ns, vartab, opt))
- .collect(),
- ),
- Expression::Assign(_, _, left, right) => {
- // If we reach this condition, the assignment is inside an expression.
- if let Some(function) = func {
- if should_remove_assignment(ns, left, function, opt) {
- return expression(right, cfg, contract_no, func, ns, vartab, opt);
- }
- }
- assign_single(left, right, cfg, contract_no, func, ns, vartab, opt)
- }
- Expression::PreDecrement(loc, ty, unchecked, var)
- | Expression::PreIncrement(loc, ty, unchecked, var) => pre_incdec(
- vartab,
- ty,
- var,
- cfg,
- contract_no,
- func,
- ns,
- loc,
- expr,
- unchecked,
- opt,
- ),
- Expression::PostDecrement(loc, ty, unchecked, var)
- | Expression::PostIncrement(loc, ty, unchecked, var) => post_incdec(
- vartab,
- ty,
- var,
- cfg,
- contract_no,
- func,
- ns,
- loc,
- expr,
- unchecked,
- opt,
- ),
- Expression::Constructor {
- loc,
- contract_no,
- constructor_no,
- args,
- value,
- gas,
- salt,
- space,
- } => {
- let address_res = vartab.temp_anonymous(&Type::Contract(*contract_no));
- let args = args
- .iter()
- .map(|v| expression(v, cfg, *contract_no, func, ns, vartab, opt))
- .collect();
- let gas = if let Some(gas) = gas {
- expression(gas, cfg, *contract_no, func, ns, vartab, opt)
- } else {
- default_gas(ns)
- };
- let value = value
- .as_ref()
- .map(|value| expression(value, cfg, *contract_no, func, ns, vartab, opt));
- let salt = salt
- .as_ref()
- .map(|salt| expression(salt, cfg, *contract_no, func, ns, vartab, opt));
- let space = space
- .as_ref()
- .map(|space| expression(space, cfg, *contract_no, func, ns, vartab, opt));
- cfg.add(
- vartab,
- Instr::Constructor {
- success: None,
- res: address_res,
- contract_no: *contract_no,
- constructor_no: *constructor_no,
- args,
- value,
- gas,
- salt,
- space,
- },
- );
- Expression::Variable(*loc, Type::Contract(*contract_no), address_res)
- }
- Expression::InternalFunction {
- function_no,
- signature,
- ..
- } => {
- let function_no = if let Some(signature) = signature {
- &ns.contracts[contract_no].virtual_functions[signature]
- } else {
- function_no
- };
- Expression::InternalFunctionCfg(ns.contracts[contract_no].all_functions[function_no])
- }
- Expression::StorageArrayLength {
- loc,
- ty,
- array,
- elem_ty,
- } => {
- let array_ty = array.ty().deref_into();
- let array = expression(array, cfg, contract_no, func, ns, vartab, opt);
- match array_ty {
- Type::Bytes(length) => bigint_to_expression(
- loc,
- &BigInt::from_u8(length).unwrap(),
- ns,
- &mut Vec::new(),
- ResolveTo::Type(ty),
- )
- .unwrap(),
- Type::DynamicBytes => Expression::StorageArrayLength {
- loc: *loc,
- ty: ty.clone(),
- array: Box::new(array),
- elem_ty: elem_ty.clone(),
- },
- Type::Array(_, dim) => match dim.last().unwrap() {
- None => {
- if ns.target == Target::Solana {
- Expression::StorageArrayLength {
- loc: *loc,
- ty: ty.clone(),
- array: Box::new(array),
- elem_ty: elem_ty.clone(),
- }
- } else {
- load_storage(loc, &ns.storage_type(), array, cfg, vartab, opt)
- }
- }
- Some(length) => {
- bigint_to_expression(loc, length, ns, &mut Vec::new(), ResolveTo::Type(ty))
- .unwrap()
- }
- },
- _ => unreachable!(),
- }
- }
- Expression::Builtin(loc, returns, Builtin::ExternalFunctionAddress, func_expr) => {
- if let Expression::ExternalFunction { address, .. } = &func_expr[0] {
- expression(address, cfg, contract_no, func, ns, vartab, opt)
- } else {
- let func_expr = expression(&func_expr[0], cfg, contract_no, func, ns, vartab, opt);
- Expression::Builtin(
- *loc,
- returns.clone(),
- Builtin::ExternalFunctionAddress,
- vec![func_expr],
- )
- }
- }
- Expression::Builtin(loc, returns, Builtin::FunctionSelector, func_expr) => match &func_expr
- [0]
- {
- Expression::ExternalFunction { function_no, .. }
- | Expression::InternalFunction { function_no, .. } => {
- let selector = ns.functions[*function_no].selector();
- Expression::NumberLiteral(*loc, Type::Bytes(4), BigInt::from(selector))
- }
- _ => {
- let func_expr = expression(&func_expr[0], cfg, contract_no, func, ns, vartab, opt);
- Expression::Builtin(
- *loc,
- returns.clone(),
- Builtin::FunctionSelector,
- vec![func_expr],
- )
- }
- },
- Expression::InternalFunctionCall { .. }
- | Expression::ExternalFunctionCall { .. }
- | Expression::Builtin(_, _, Builtin::AbiDecode, _) => {
- let mut returns = emit_function_call(expr, contract_no, cfg, func, ns, vartab, opt);
- assert_eq!(returns.len(), 1);
- returns.remove(0)
- }
- Expression::ExternalFunction {
- loc,
- ty,
- address,
- function_no,
- } => {
- let address = expression(address, cfg, contract_no, func, ns, vartab, opt);
- Expression::ExternalFunction {
- loc: *loc,
- ty: ty.clone(),
- address: Box::new(address),
- function_no: *function_no,
- }
- }
- Expression::Subscript(loc, ty, array, index) => array_subscript(
- loc,
- ty,
- array,
- index,
- cfg,
- contract_no,
- func,
- ns,
- vartab,
- opt,
- ),
- Expression::StructMember(loc, ty, var, field_no) if ty.is_contract_storage() => {
- if let Type::Struct(struct_no) = var.ty().deref_any() {
- let offset = if ns.target == Target::Solana {
- ns.structs[*struct_no].storage_offsets[*field_no].clone()
- } else {
- ns.structs[*struct_no].fields[..*field_no]
- .iter()
- .map(|field| field.ty.storage_slots(ns))
- .sum()
- };
- Expression::Add(
- *loc,
- ty.clone(),
- true,
- Box::new(expression(var, cfg, contract_no, func, ns, vartab, opt)),
- Box::new(Expression::NumberLiteral(*loc, ns.storage_type(), offset)),
- )
- } else {
- unreachable!();
- }
- }
- Expression::StructMember(loc, ty, var, member) => Expression::StructMember(
- *loc,
- ty.clone(),
- Box::new(expression(var, cfg, contract_no, func, ns, vartab, opt)),
- *member,
- ),
- Expression::StorageBytesSubscript(loc, var, index) => Expression::StorageBytesSubscript(
- *loc,
- Box::new(expression(var, cfg, contract_no, func, ns, vartab, opt)),
- Box::new(expression(index, cfg, contract_no, func, ns, vartab, opt)),
- ),
- Expression::StringCompare(loc, left, right) => Expression::StringCompare(
- *loc,
- string_location(left, cfg, contract_no, func, ns, vartab, opt),
- string_location(right, cfg, contract_no, func, ns, vartab, opt),
- ),
- Expression::StringConcat(loc, ty, left, right) => Expression::StringConcat(
- *loc,
- ty.clone(),
- string_location(left, cfg, contract_no, func, ns, vartab, opt),
- string_location(right, cfg, contract_no, func, ns, vartab, opt),
- ),
- Expression::Or(loc, left, right) => {
- expr_or(left, cfg, contract_no, func, ns, vartab, loc, right, opt)
- }
- Expression::And(loc, left, right) => {
- and(left, cfg, contract_no, func, ns, vartab, loc, right, opt)
- }
- Expression::Trunc(loc, ty, e) => Expression::Trunc(
- *loc,
- ty.clone(),
- Box::new(expression(e, cfg, contract_no, func, ns, vartab, opt)),
- ),
- Expression::ZeroExt(loc, ty, e) => Expression::ZeroExt(
- *loc,
- ty.clone(),
- Box::new(expression(e, cfg, contract_no, func, ns, vartab, opt)),
- ),
- Expression::SignExt(loc, ty, e) => Expression::SignExt(
- *loc,
- ty.clone(),
- Box::new(expression(e, cfg, contract_no, func, ns, vartab, opt)),
- ),
- Expression::Cast(loc, ty @ Type::Address(_), e) => {
- if let Ok((_, address)) = eval_const_number(e, Some(contract_no), ns) {
- Expression::NumberLiteral(*loc, ty.clone(), address)
- } else {
- Expression::Cast(
- *loc,
- ty.clone(),
- Box::new(expression(e, cfg, contract_no, func, ns, vartab, opt)),
- )
- }
- }
- Expression::Cast(loc, ty, e) => {
- if matches!(ty, Type::String | Type::DynamicBytes)
- && matches!(expr.ty(), Type::String | Type::DynamicBytes)
- {
- expression(e, cfg, contract_no, func, ns, vartab, opt)
- } else {
- Expression::Cast(
- *loc,
- ty.clone(),
- Box::new(expression(e, cfg, contract_no, func, ns, vartab, opt)),
- )
- }
- }
- Expression::BytesCast(loc, ty, from, e) => Expression::BytesCast(
- *loc,
- ty.clone(),
- from.clone(),
- Box::new(expression(e, cfg, contract_no, func, ns, vartab, opt)),
- ),
- Expression::Load(loc, ty, e) => Expression::Load(
- *loc,
- ty.clone(),
- Box::new(expression(e, cfg, contract_no, func, ns, vartab, opt)),
- ),
- // for some built-ins, we have to inline special case code
- Expression::Builtin(loc, ty, Builtin::ArrayPush, args) => {
- if args[0].ty().is_contract_storage() {
- if ns.target == Target::Solana || args[0].ty().is_storage_bytes() {
- array_push(loc, args, cfg, contract_no, func, ns, vartab, opt)
- } else {
- storage_slots_array_push(loc, args, cfg, contract_no, func, ns, vartab, opt)
- }
- } else {
- memory_array_push(
- &ty[0],
- vartab,
- &args[0],
- cfg,
- contract_no,
- func,
- ns,
- &args[1],
- loc,
- opt,
- )
- }
- }
- Expression::Builtin(loc, ty, Builtin::ArrayPop, args) => {
- if args[0].ty().is_contract_storage() {
- if ns.target == Target::Solana || args[0].ty().is_storage_bytes() {
- array_pop(loc, args, &ty[0], cfg, contract_no, func, ns, vartab, opt)
- } else {
- storage_slots_array_pop(
- loc,
- args,
- &ty[0],
- cfg,
- contract_no,
- func,
- ns,
- vartab,
- opt,
- )
- }
- } else {
- let address_res = vartab.temp_anonymous(&ty[0]);
- let address_arr =
- match expression(&args[0], cfg, contract_no, func, ns, vartab, opt) {
- Expression::Variable(_, _, pos) => pos,
- _ => unreachable!(),
- };
- cfg.add(
- vartab,
- Instr::PopMemory {
- res: address_res,
- ty: args[0].ty(),
- array: address_arr,
- },
- );
- Expression::Variable(*loc, ty[0].clone(), address_res)
- }
- }
- Expression::Builtin(_, _, Builtin::Assert, args) => {
- expr_assert(cfg, &args[0], contract_no, func, ns, vartab, opt)
- }
- Expression::Builtin(_, _, Builtin::Print, args) => {
- let expr = expression(&args[0], cfg, contract_no, func, ns, vartab, opt);
- cfg.add(vartab, Instr::Print { expr });
- Expression::Poison
- }
- Expression::Builtin(_, _, Builtin::Require, args) => {
- require(cfg, args, contract_no, func, ns, vartab, opt)
- }
- Expression::Builtin(_, _, Builtin::Revert, args) => {
- revert(args, cfg, contract_no, func, ns, vartab, opt)
- }
- Expression::Builtin(_, _, Builtin::SelfDestruct, args) => {
- self_destruct(args, cfg, contract_no, func, ns, vartab, opt)
- }
- Expression::Builtin(loc, _, Builtin::PayableSend, args) => {
- payable_send(args, cfg, contract_no, func, ns, vartab, loc, opt)
- }
- Expression::Builtin(loc, _, Builtin::PayableTransfer, args) => {
- payable_transfer(args, cfg, contract_no, func, ns, vartab, loc, opt)
- }
- Expression::Builtin(loc, _, Builtin::AbiEncode, args) => {
- abi_encode(args, cfg, contract_no, func, ns, vartab, loc, opt)
- }
- Expression::Builtin(loc, _, Builtin::AbiEncodePacked, args) => {
- abi_encode_packed(args, cfg, contract_no, func, ns, vartab, loc, opt)
- }
- Expression::Builtin(loc, _, Builtin::AbiEncodeWithSelector, args) => {
- abi_encode_with_selector(args, cfg, contract_no, func, ns, vartab, loc, opt)
- }
- Expression::Builtin(loc, _, Builtin::AbiEncodeWithSignature, args) => {
- abi_encode_with_signature(args, loc, cfg, contract_no, func, ns, vartab, opt)
- }
- // The Substrate gas price builtin takes an argument; the others do not
- Expression::Builtin(loc, _, Builtin::Gasprice, expr)
- if expr.len() == 1 && ns.target == Target::Ewasm =>
- {
- builtin_ewasm_gasprice(loc, expr, cfg, contract_no, func, ns, vartab, opt)
- }
- Expression::Builtin(loc, tys, builtin, args) => expr_builtin(
- args,
- cfg,
- contract_no,
- func,
- ns,
- vartab,
- loc,
- tys,
- builtin,
- opt,
- ),
- Expression::FormatString(loc, args) => {
- format_string(args, cfg, contract_no, func, ns, vartab, loc, opt)
- }
- Expression::AllocDynamicArray(loc, ty, size, init) => {
- alloc_dynamic_array(size, cfg, contract_no, func, ns, vartab, loc, ty, init, opt)
- }
- Expression::Ternary(loc, ty, cond, left, right) => ternary(
- loc,
- ty,
- cond,
- cfg,
- contract_no,
- func,
- ns,
- vartab,
- left,
- right,
- opt,
- ),
- Expression::InterfaceId(loc, contract_no) => interfaceid(ns, contract_no, loc),
- _ => expr.clone(),
- }
- }
- fn memory_array_push(
- ty: &Type,
- vartab: &mut Vartable,
- array: &Expression,
- cfg: &mut ControlFlowGraph,
- contract_no: usize,
- func: Option<&Function>,
- ns: &Namespace,
- value: &Expression,
- loc: &pt::Loc,
- opt: &Options,
- ) -> Expression {
- let address_res = vartab.temp_anonymous(ty);
- let address_arr = match expression(array, cfg, contract_no, func, ns, vartab, opt) {
- Expression::Variable(_, _, pos) => pos,
- _ => unreachable!(),
- };
- let value = expression(value, cfg, contract_no, func, ns, vartab, opt);
- cfg.add(
- vartab,
- Instr::PushMemory {
- res: address_res,
- ty: array.ty(),
- array: address_arr,
- value: Box::new(value),
- },
- );
- Expression::Variable(*loc, ty.clone(), address_res)
- }
- fn post_incdec(
- vartab: &mut Vartable,
- ty: &Type,
- var: &Expression,
- cfg: &mut ControlFlowGraph,
- contract_no: usize,
- func: Option<&Function>,
- ns: &Namespace,
- loc: &pt::Loc,
- expr: &Expression,
- unchecked: &bool,
- opt: &Options,
- ) -> Expression {
- let res = vartab.temp_anonymous(ty);
- let v = expression(var, cfg, contract_no, func, ns, vartab, opt);
- let v = match var.ty() {
- Type::Ref(ty) => Expression::Load(var.loc(), ty.as_ref().clone(), Box::new(v)),
- Type::StorageRef(_, ty) => load_storage(&var.loc(), ty.as_ref(), v, cfg, vartab, opt),
- _ => v,
- };
- cfg.add(
- vartab,
- Instr::Set {
- loc: pt::Loc(0, 0, 0),
- res,
- expr: v,
- },
- );
- let one = Box::new(Expression::NumberLiteral(*loc, ty.clone(), BigInt::one()));
- let expr = match expr {
- Expression::PostDecrement(..) => Expression::Subtract(
- *loc,
- ty.clone(),
- *unchecked,
- Box::new(Expression::Variable(*loc, ty.clone(), res)),
- one,
- ),
- Expression::PostIncrement(..) => Expression::Add(
- *loc,
- ty.clone(),
- *unchecked,
- Box::new(Expression::Variable(*loc, ty.clone(), res)),
- one,
- ),
- _ => unreachable!(),
- };
- match var {
- Expression::Variable(loc, _, pos) => {
- cfg.add(
- vartab,
- Instr::Set {
- loc: *loc,
- res: *pos,
- expr,
- },
- );
- }
- _ => {
- let dest = expression(var, cfg, contract_no, func, ns, vartab, opt);
- let res = vartab.temp_anonymous(ty);
- cfg.add(
- vartab,
- Instr::Set {
- loc: pt::Loc(0, 0, 0),
- res,
- expr,
- },
- );
- match var.ty() {
- Type::StorageRef(_, _) => {
- cfg.add(
- vartab,
- Instr::SetStorage {
- value: Expression::Variable(*loc, ty.clone(), res),
- ty: ty.clone(),
- storage: dest,
- },
- );
- }
- Type::Ref(_) => {
- cfg.add(vartab, Instr::Store { pos: res, dest });
- }
- _ => unreachable!(),
- }
- }
- }
- Expression::Variable(*loc, ty.clone(), res)
- }
- fn pre_incdec(
- vartab: &mut Vartable,
- ty: &Type,
- var: &Expression,
- cfg: &mut ControlFlowGraph,
- contract_no: usize,
- func: Option<&Function>,
- ns: &Namespace,
- loc: &pt::Loc,
- expr: &Expression,
- unchecked: &bool,
- opt: &Options,
- ) -> Expression {
- let res = vartab.temp_anonymous(ty);
- let v = expression(var, cfg, contract_no, func, ns, vartab, opt);
- let v = match var.ty() {
- Type::Ref(ty) => Expression::Load(var.loc(), ty.as_ref().clone(), Box::new(v)),
- Type::StorageRef(_, ty) => load_storage(&var.loc(), ty.as_ref(), v, cfg, vartab, opt),
- _ => v,
- };
- let one = Box::new(Expression::NumberLiteral(*loc, ty.clone(), BigInt::one()));
- let expr = match expr {
- Expression::PreDecrement(..) => {
- Expression::Subtract(*loc, ty.clone(), *unchecked, Box::new(v), one)
- }
- Expression::PreIncrement(..) => {
- Expression::Add(*loc, ty.clone(), *unchecked, Box::new(v), one)
- }
- _ => unreachable!(),
- };
- cfg.add(
- vartab,
- Instr::Set {
- loc: pt::Loc(0, 0, 0),
- res,
- expr,
- },
- );
- match var {
- Expression::Variable(loc, _, pos) => {
- cfg.add(
- vartab,
- Instr::Set {
- loc: *loc,
- res: *pos,
- expr: Expression::Variable(*loc, ty.clone(), res),
- },
- );
- }
- _ => {
- let dest = expression(var, cfg, contract_no, func, ns, vartab, opt);
- match var.ty() {
- Type::StorageRef(_, _) => {
- cfg.add(
- vartab,
- Instr::SetStorage {
- value: Expression::Variable(*loc, ty.clone(), res),
- ty: ty.clone(),
- storage: dest,
- },
- );
- }
- Type::Ref(_) => {
- cfg.add(vartab, Instr::Store { pos: res, dest });
- }
- _ => unreachable!(),
- }
- }
- }
- Expression::Variable(*loc, ty.clone(), res)
- }
- fn expr_or(
- left: &Expression,
- cfg: &mut ControlFlowGraph,
- contract_no: usize,
- func: Option<&Function>,
- ns: &Namespace,
- vartab: &mut Vartable,
- loc: &pt::Loc,
- right: &Expression,
- opt: &Options,
- ) -> Expression {
- let boolty = Type::Bool;
- let l = expression(left, cfg, contract_no, func, ns, vartab, opt);
- vartab.new_dirty_tracker(ns.next_id);
- let pos = vartab.temp(
- &pt::Identifier {
- name: "or".to_owned(),
- loc: *loc,
- },
- &Type::Bool,
- );
- let right_side = cfg.new_basic_block("or_right_side".to_string());
- let end_or = cfg.new_basic_block("or_end".to_string());
- cfg.add(
- vartab,
- Instr::Set {
- loc: pt::Loc(0, 0, 0),
- res: pos,
- expr: Expression::BoolLiteral(*loc, true),
- },
- );
- cfg.add(
- vartab,
- Instr::BranchCond {
- cond: l,
- true_block: end_or,
- false_block: right_side,
- },
- );
- cfg.set_basic_block(right_side);
- let r = expression(right, cfg, contract_no, func, ns, vartab, opt);
- cfg.add(
- vartab,
- Instr::Set {
- loc: pt::Loc(0, 0, 0),
- res: pos,
- expr: r,
- },
- );
- let mut phis = vartab.pop_dirty_tracker();
- phis.insert(pos);
- cfg.set_phis(end_or, phis);
- cfg.add(vartab, Instr::Branch { block: end_or });
- cfg.set_basic_block(end_or);
- Expression::Variable(*loc, boolty, pos)
- }
- fn and(
- left: &Expression,
- cfg: &mut ControlFlowGraph,
- contract_no: usize,
- func: Option<&Function>,
- ns: &Namespace,
- vartab: &mut Vartable,
- loc: &pt::Loc,
- right: &Expression,
- opt: &Options,
- ) -> Expression {
- let boolty = Type::Bool;
- let l = expression(left, cfg, contract_no, func, ns, vartab, opt);
- vartab.new_dirty_tracker(ns.next_id);
- let pos = vartab.temp(
- &pt::Identifier {
- name: "and".to_owned(),
- loc: *loc,
- },
- &Type::Bool,
- );
- let right_side = cfg.new_basic_block("and_right_side".to_string());
- let end_and = cfg.new_basic_block("and_end".to_string());
- cfg.add(
- vartab,
- Instr::Set {
- loc: pt::Loc(0, 0, 0),
- res: pos,
- expr: Expression::BoolLiteral(*loc, false),
- },
- );
- cfg.add(
- vartab,
- Instr::BranchCond {
- cond: l,
- true_block: right_side,
- false_block: end_and,
- },
- );
- cfg.set_basic_block(right_side);
- let r = expression(right, cfg, contract_no, func, ns, vartab, opt);
- cfg.add(
- vartab,
- Instr::Set {
- loc: pt::Loc(0, 0, 0),
- res: pos,
- expr: r,
- },
- );
- let mut phis = vartab.pop_dirty_tracker();
- phis.insert(pos);
- cfg.set_phis(end_and, phis);
- cfg.add(vartab, Instr::Branch { block: end_and });
- cfg.set_basic_block(end_and);
- Expression::Variable(*loc, boolty, pos)
- }
- fn expr_assert(
- cfg: &mut ControlFlowGraph,
- args: &Expression,
- contract_no: usize,
- func: Option<&Function>,
- ns: &Namespace,
- vartab: &mut Vartable,
- opt: &Options,
- ) -> Expression {
- let true_ = cfg.new_basic_block("noassert".to_owned());
- let false_ = cfg.new_basic_block("doassert".to_owned());
- let cond = expression(args, cfg, contract_no, func, ns, vartab, opt);
- cfg.add(
- vartab,
- Instr::BranchCond {
- cond,
- true_block: true_,
- false_block: false_,
- },
- );
- cfg.set_basic_block(false_);
- cfg.add(vartab, Instr::AssertFailure { expr: None });
- cfg.set_basic_block(true_);
- Expression::Poison
- }
- fn require(
- cfg: &mut ControlFlowGraph,
- args: &[Expression],
- contract_no: usize,
- func: Option<&Function>,
- ns: &Namespace,
- vartab: &mut Vartable,
- opt: &Options,
- ) -> Expression {
- let true_ = cfg.new_basic_block("noassert".to_owned());
- let false_ = cfg.new_basic_block("doassert".to_owned());
- let cond = expression(&args[0], cfg, contract_no, func, ns, vartab, opt);
- cfg.add(
- vartab,
- Instr::BranchCond {
- cond,
- true_block: true_,
- false_block: false_,
- },
- );
- cfg.set_basic_block(false_);
- let expr = args
- .get(1)
- .map(|s| expression(s, cfg, contract_no, func, ns, vartab, opt));
- if ns.target == Target::Solana {
- // On Solana, print the reason, do not abi encoding it
- if let Some(expr) = expr {
- cfg.add(vartab, Instr::Print { expr });
- }
- cfg.add(vartab, Instr::AssertFailure { expr: None });
- } else {
- cfg.add(vartab, Instr::AssertFailure { expr });
- }
- cfg.set_basic_block(true_);
- Expression::Poison
- }
- fn revert(
- args: &[Expression],
- cfg: &mut ControlFlowGraph,
- contract_no: usize,
- func: Option<&Function>,
- ns: &Namespace,
- vartab: &mut Vartable,
- opt: &Options,
- ) -> Expression {
- let expr = args
- .get(0)
- .map(|s| expression(s, cfg, contract_no, func, ns, vartab, opt));
- cfg.add(vartab, Instr::AssertFailure { expr });
- Expression::Poison
- }
- fn self_destruct(
- args: &[Expression],
- cfg: &mut ControlFlowGraph,
- contract_no: usize,
- func: Option<&Function>,
- ns: &Namespace,
- vartab: &mut Vartable,
- opt: &Options,
- ) -> Expression {
- let recipient = expression(&args[0], cfg, contract_no, func, ns, vartab, opt);
- cfg.add(vartab, Instr::SelfDestruct { recipient });
- Expression::Poison
- }
- fn payable_send(
- args: &[Expression],
- cfg: &mut ControlFlowGraph,
- contract_no: usize,
- func: Option<&Function>,
- ns: &Namespace,
- vartab: &mut Vartable,
- loc: &pt::Loc,
- opt: &Options,
- ) -> Expression {
- let address = expression(&args[0], cfg, contract_no, func, ns, vartab, opt);
- let value = expression(&args[1], cfg, contract_no, func, ns, vartab, opt);
- let success = vartab.temp(
- &pt::Identifier {
- loc: *loc,
- name: "success".to_owned(),
- },
- &Type::Bool,
- );
- if ns.target != Target::Ewasm {
- cfg.add(
- vartab,
- Instr::ValueTransfer {
- success: Some(success),
- address,
- value,
- },
- );
- } else {
- // Ethereum can only transfer via external call
- cfg.add(
- vartab,
- Instr::ExternalCall {
- success: Some(success),
- address: Some(address),
- payload: Expression::BytesLiteral(*loc, Type::DynamicBytes, vec![]),
- value,
- gas: Expression::NumberLiteral(*loc, Type::Uint(64), BigInt::from(i64::MAX)),
- callty: CallTy::Regular,
- },
- );
- }
- Expression::Variable(*loc, Type::Bool, success)
- }
- fn payable_transfer(
- args: &[Expression],
- cfg: &mut ControlFlowGraph,
- contract_no: usize,
- func: Option<&Function>,
- ns: &Namespace,
- vartab: &mut Vartable,
- loc: &pt::Loc,
- opt: &Options,
- ) -> Expression {
- let address = expression(&args[0], cfg, contract_no, func, ns, vartab, opt);
- let value = expression(&args[1], cfg, contract_no, func, ns, vartab, opt);
- if ns.target != Target::Ewasm {
- cfg.add(
- vartab,
- Instr::ValueTransfer {
- success: None,
- address,
- value,
- },
- );
- } else {
- // Ethereum can only transfer via external call
- cfg.add(
- vartab,
- Instr::ExternalCall {
- success: None,
- address: Some(address),
- payload: Expression::BytesLiteral(*loc, Type::DynamicBytes, vec![]),
- value,
- gas: Expression::NumberLiteral(*loc, Type::Uint(64), BigInt::from(i64::MAX)),
- callty: CallTy::Regular,
- },
- );
- }
- Expression::Poison
- }
- fn abi_encode(
- args: &[Expression],
- cfg: &mut ControlFlowGraph,
- contract_no: usize,
- func: Option<&Function>,
- ns: &Namespace,
- vartab: &mut Vartable,
- loc: &pt::Loc,
- opt: &Options,
- ) -> Expression {
- let tys = args.iter().map(|a| a.ty()).collect();
- let args = args
- .iter()
- .map(|v| expression(v, cfg, contract_no, func, ns, vartab, opt))
- .collect();
- let res = vartab.temp(
- &pt::Identifier {
- loc: *loc,
- name: "encoded".to_owned(),
- },
- &Type::DynamicBytes,
- );
- cfg.add(
- vartab,
- Instr::Set {
- loc: *loc,
- res,
- expr: Expression::AbiEncode {
- loc: *loc,
- tys,
- packed: vec![],
- args,
- },
- },
- );
- Expression::Variable(*loc, Type::DynamicBytes, res)
- }
- fn abi_encode_packed(
- args: &[Expression],
- cfg: &mut ControlFlowGraph,
- contract_no: usize,
- func: Option<&Function>,
- ns: &Namespace,
- vartab: &mut Vartable,
- loc: &pt::Loc,
- opt: &Options,
- ) -> Expression {
- let tys = args.iter().map(|a| a.ty()).collect();
- let packed = args
- .iter()
- .map(|v| expression(v, cfg, contract_no, func, ns, vartab, opt))
- .collect();
- let res = vartab.temp(
- &pt::Identifier {
- loc: *loc,
- name: "encoded".to_owned(),
- },
- &Type::DynamicBytes,
- );
- cfg.add(
- vartab,
- Instr::Set {
- loc: *loc,
- res,
- expr: Expression::AbiEncode {
- loc: *loc,
- tys,
- packed,
- args: vec![],
- },
- },
- );
- Expression::Variable(*loc, Type::DynamicBytes, res)
- }
- fn abi_encode_with_selector(
- args: &[Expression],
- cfg: &mut ControlFlowGraph,
- contract_no: usize,
- func: Option<&Function>,
- ns: &Namespace,
- vartab: &mut Vartable,
- loc: &pt::Loc,
- opt: &Options,
- ) -> Expression {
- let mut tys: Vec<Type> = args.iter().skip(1).map(|a| a.ty()).collect();
- let mut args_iter = args.iter();
- let selector = expression(
- args_iter.next().unwrap(),
- cfg,
- contract_no,
- func,
- ns,
- vartab,
- opt,
- );
- let args = args_iter
- .map(|v| expression(v, cfg, contract_no, func, ns, vartab, opt))
- .collect();
- let res = vartab.temp(
- &pt::Identifier {
- loc: *loc,
- name: "encoded".to_owned(),
- },
- &Type::DynamicBytes,
- );
- tys.insert(0, Type::Bytes(4));
- cfg.add(
- vartab,
- Instr::Set {
- loc: *loc,
- res,
- expr: Expression::AbiEncode {
- loc: *loc,
- tys,
- packed: vec![selector],
- args,
- },
- },
- );
- Expression::Variable(*loc, Type::DynamicBytes, res)
- }
- fn abi_encode_with_signature(
- args: &[Expression],
- loc: &pt::Loc,
- cfg: &mut ControlFlowGraph,
- contract_no: usize,
- func: Option<&Function>,
- ns: &Namespace,
- vartab: &mut Vartable,
- opt: &Options,
- ) -> Expression {
- let mut tys: Vec<Type> = args.iter().skip(1).map(|a| a.ty()).collect();
- let mut args_iter = args.iter();
- let hash = Expression::Builtin(
- *loc,
- vec![Type::Bytes(32)],
- Builtin::Keccak256,
- vec![args_iter.next().unwrap().clone()],
- );
- let hash = expression(&hash, cfg, contract_no, func, ns, vartab, opt);
- let selector = cast(loc, hash, &Type::Bytes(4), false, ns, &mut Vec::new()).unwrap();
- let args = args_iter
- .map(|v| expression(v, cfg, contract_no, func, ns, vartab, opt))
- .collect();
- let res = vartab.temp(
- &pt::Identifier {
- loc: *loc,
- name: "encoded".to_owned(),
- },
- &Type::DynamicBytes,
- );
- tys.insert(0, Type::Bytes(4));
- cfg.add(
- vartab,
- Instr::Set {
- loc: *loc,
- res,
- expr: Expression::AbiEncode {
- loc: *loc,
- tys,
- packed: vec![selector],
- args,
- },
- },
- );
- Expression::Variable(*loc, Type::DynamicBytes, res)
- }
- fn builtin_ewasm_gasprice(
- loc: &pt::Loc,
- expr: &[Expression],
- cfg: &mut ControlFlowGraph,
- contract_no: usize,
- func: Option<&Function>,
- ns: &Namespace,
- vartab: &mut Vartable,
- opt: &Options,
- ) -> Expression {
- let ty = Type::Value;
- let gasprice = Expression::Builtin(*loc, vec![ty.clone()], Builtin::Gasprice, vec![]);
- let units = expression(&expr[0], cfg, contract_no, func, ns, vartab, opt);
- Expression::Multiply(*loc, ty, true, Box::new(units), Box::new(gasprice))
- }
- fn expr_builtin(
- args: &[Expression],
- cfg: &mut ControlFlowGraph,
- contract_no: usize,
- func: Option<&Function>,
- ns: &Namespace,
- vartab: &mut Vartable,
- loc: &pt::Loc,
- tys: &[Type],
- builtin: &Builtin,
- opt: &Options,
- ) -> Expression {
- let args = args
- .iter()
- .map(|v| expression(v, cfg, contract_no, func, ns, vartab, opt))
- .collect();
- Expression::Builtin(*loc, tys.to_vec(), *builtin, args)
- }
- fn format_string(
- args: &[(FormatArg, Expression)],
- cfg: &mut ControlFlowGraph,
- contract_no: usize,
- func: Option<&Function>,
- ns: &Namespace,
- vartab: &mut Vartable,
- loc: &pt::Loc,
- opt: &Options,
- ) -> Expression {
- let args = args
- .iter()
- .map(|(spec, arg)| {
- (
- *spec,
- expression(arg, cfg, contract_no, func, ns, vartab, opt),
- )
- })
- .collect();
- Expression::FormatString(*loc, args)
- }
- fn alloc_dynamic_array(
- size: &Expression,
- cfg: &mut ControlFlowGraph,
- contract_no: usize,
- func: Option<&Function>,
- ns: &Namespace,
- vartab: &mut Vartable,
- loc: &pt::Loc,
- ty: &Type,
- init: &Option<Vec<u8>>,
- opt: &Options,
- ) -> Expression {
- let size = expression(size, cfg, contract_no, func, ns, vartab, opt);
- Expression::AllocDynamicArray(*loc, ty.clone(), Box::new(size), init.clone())
- }
- fn ternary(
- loc: &pt::Loc,
- ty: &Type,
- cond: &Expression,
- cfg: &mut ControlFlowGraph,
- contract_no: usize,
- func: Option<&Function>,
- ns: &Namespace,
- vartab: &mut Vartable,
- left: &Expression,
- right: &Expression,
- opt: &Options,
- ) -> Expression {
- Expression::Ternary(
- *loc,
- ty.clone(),
- Box::new(expression(cond, cfg, contract_no, func, ns, vartab, opt)),
- Box::new(expression(left, cfg, contract_no, func, ns, vartab, opt)),
- Box::new(expression(right, cfg, contract_no, func, ns, vartab, opt)),
- )
- }
- fn interfaceid(ns: &Namespace, contract_no: &usize, loc: &pt::Loc) -> Expression {
- let mut id: u32 = 0;
- for func_no in &ns.contracts[*contract_no].functions {
- let func = &ns.functions[*func_no];
- if func.ty == pt::FunctionTy::Function {
- id ^= func.selector();
- }
- }
- Expression::NumberLiteral(*loc, Type::Bytes(4), BigInt::from(id))
- }
- fn add(
- loc: &pt::Loc,
- ty: &Type,
- unchecked: &bool,
- left: &Expression,
- cfg: &mut ControlFlowGraph,
- contract_no: usize,
- func: Option<&Function>,
- ns: &Namespace,
- vartab: &mut Vartable,
- right: &Expression,
- opt: &Options,
- ) -> Expression {
- Expression::Add(
- *loc,
- ty.clone(),
- *unchecked,
- Box::new(expression(left, cfg, contract_no, func, ns, vartab, opt)),
- Box::new(expression(right, cfg, contract_no, func, ns, vartab, opt)),
- )
- }
- fn substract(
- loc: &pt::Loc,
- ty: &Type,
- unchecked: &bool,
- left: &Expression,
- cfg: &mut ControlFlowGraph,
- contract_no: usize,
- func: Option<&Function>,
- ns: &Namespace,
- vartab: &mut Vartable,
- right: &Expression,
- opt: &Options,
- ) -> Expression {
- Expression::Subtract(
- *loc,
- ty.clone(),
- *unchecked,
- Box::new(expression(left, cfg, contract_no, func, ns, vartab, opt)),
- Box::new(expression(right, cfg, contract_no, func, ns, vartab, opt)),
- )
- }
- pub fn assign_single(
- left: &Expression,
- right: &Expression,
- cfg: &mut ControlFlowGraph,
- contract_no: usize,
- func: Option<&Function>,
- ns: &Namespace,
- vartab: &mut Vartable,
- opt: &Options,
- ) -> Expression {
- match left {
- Expression::Variable(loc, _, pos) => {
- let expr = expression(right, cfg, contract_no, func, ns, vartab, opt);
- cfg.add(
- vartab,
- Instr::Set {
- loc: *loc,
- res: *pos,
- expr,
- },
- );
- left.clone()
- }
- _ => {
- let left_ty = left.ty();
- let ty = left_ty.deref_memory();
- let pos = vartab.temp_anonymous(ty);
- let dest = expression(left, cfg, contract_no, func, ns, vartab, opt);
- let right = expression(right, cfg, contract_no, func, ns, vartab, opt);
- cfg.add(
- vartab,
- Instr::Set {
- loc: pt::Loc(0, 0, 0),
- res: pos,
- expr: right,
- },
- );
- match left_ty {
- Type::StorageRef(_, _) => {
- if let Expression::StorageBytesSubscript(_, array, index) = dest {
- // Set a byte in a byte array
- cfg.add(
- vartab,
- Instr::SetStorageBytes {
- value: Expression::Variable(left.loc(), ty.clone(), pos),
- storage: *array,
- offset: *index,
- },
- );
- } else {
- cfg.add(
- vartab,
- Instr::SetStorage {
- value: Expression::Variable(left.loc(), ty.clone(), pos),
- ty: ty.deref_any().clone(),
- storage: dest,
- },
- );
- }
- }
- Type::Ref(_) => {
- cfg.add(vartab, Instr::Store { pos, dest });
- }
- _ => unreachable!(),
- }
- Expression::Variable(left.loc(), ty.clone(), pos)
- }
- }
- }
- /// Convert a function call expression to CFG in expression context
- pub fn emit_function_call(
- expr: &Expression,
- callee_contract_no: usize,
- cfg: &mut ControlFlowGraph,
- func: Option<&Function>,
- ns: &Namespace,
- vartab: &mut Vartable,
- opt: &Options,
- ) -> Vec<Expression> {
- match expr {
- Expression::InternalFunctionCall { function, args, .. } => {
- if let Expression::InternalFunction {
- function_no,
- signature,
- ..
- } = function.as_ref()
- {
- let args = args
- .iter()
- .map(|a| expression(a, cfg, callee_contract_no, func, ns, vartab, opt))
- .collect();
- let function_no = if let Some(signature) = signature {
- &ns.contracts[callee_contract_no].virtual_functions[signature]
- } else {
- function_no
- };
- let cfg_no = ns.contracts[callee_contract_no].all_functions[function_no];
- let ftype = &ns.functions[*function_no];
- if !ftype.returns.is_empty() {
- let mut res = Vec::new();
- let mut returns = Vec::new();
- let mut return_tys = Vec::new();
- for ret in &ftype.returns {
- let id = pt::Identifier {
- loc: ret.loc,
- name: ret.name.to_owned(),
- };
- let temp_pos = vartab.temp(&id, &ret.ty);
- return_tys.push(ret.ty.clone());
- res.push(temp_pos);
- returns.push(Expression::Variable(id.loc, ret.ty.clone(), temp_pos));
- }
- cfg.add(
- vartab,
- Instr::Call {
- res,
- call: InternalCallTy::Static(cfg_no),
- args,
- return_tys,
- },
- );
- returns
- } else {
- cfg.add(
- vartab,
- Instr::Call {
- res: Vec::new(),
- return_tys: Vec::new(),
- call: InternalCallTy::Static(cfg_no),
- args,
- },
- );
- vec![Expression::Poison]
- }
- } else if let Type::InternalFunction { returns, .. } = function.ty().deref_any() {
- let cfg_expr = expression(function, cfg, callee_contract_no, func, ns, vartab, opt);
- let args = args
- .iter()
- .map(|a| expression(a, cfg, callee_contract_no, func, ns, vartab, opt))
- .collect();
- if !returns.is_empty() {
- let mut res = Vec::new();
- let mut return_values = Vec::new();
- let mut return_tys = Vec::new();
- for ty in returns {
- let id = pt::Identifier {
- loc: pt::Loc(0, 0, 0),
- name: String::new(),
- };
- let temp_pos = vartab.temp(&id, ty);
- res.push(temp_pos);
- return_tys.push(ty.clone());
- return_values.push(Expression::Variable(id.loc, ty.clone(), temp_pos));
- }
- cfg.add(
- vartab,
- Instr::Call {
- res,
- call: InternalCallTy::Dynamic(cfg_expr),
- return_tys,
- args,
- },
- );
- return_values
- } else {
- cfg.add(
- vartab,
- Instr::Call {
- res: Vec::new(),
- return_tys: Vec::new(),
- call: InternalCallTy::Dynamic(cfg_expr),
- args,
- },
- );
- vec![Expression::Poison]
- }
- } else {
- unreachable!();
- }
- }
- Expression::ExternalFunctionCallRaw {
- loc,
- address,
- args,
- value,
- gas,
- ty,
- } => {
- let args = expression(args, cfg, callee_contract_no, func, ns, vartab, opt);
- let address = expression(address, cfg, callee_contract_no, func, ns, vartab, opt);
- let gas = if let Some(gas) = gas {
- expression(gas, cfg, callee_contract_no, func, ns, vartab, opt)
- } else {
- default_gas(ns)
- };
- let value = if let Some(value) = value {
- expression(value, cfg, callee_contract_no, func, ns, vartab, opt)
- } else {
- Expression::NumberLiteral(pt::Loc(0, 0, 0), Type::Value, BigInt::zero())
- };
- let success = vartab.temp_name("success", &Type::Bool);
- let (payload, address) = if ns.target == Target::Solana {
- (
- Expression::AbiEncode {
- loc: *loc,
- packed: vec![
- address,
- Expression::Builtin(
- *loc,
- vec![Type::Address(false)],
- Builtin::GetAddress,
- Vec::new(),
- ),
- value.clone(),
- Expression::NumberLiteral(*loc, Type::Bytes(4), BigInt::zero()),
- Expression::NumberLiteral(*loc, Type::Bytes(1), BigInt::zero()),
- args,
- ],
- args: Vec::new(),
- tys: vec![
- Type::Address(false),
- Type::Address(false),
- Type::Uint(64),
- Type::Bytes(4),
- Type::Bytes(1),
- Type::DynamicBytes,
- ],
- },
- None,
- )
- } else {
- (args, Some(address))
- };
- cfg.add(
- vartab,
- Instr::ExternalCall {
- success: Some(success),
- address,
- payload,
- value,
- gas,
- callty: ty.clone(),
- },
- );
- vec![
- Expression::Variable(*loc, Type::Bool, success),
- Expression::ReturnData(*loc),
- ]
- }
- Expression::ExternalFunctionCall {
- loc,
- function,
- args,
- value,
- gas,
- ..
- } => {
- if let Expression::ExternalFunction {
- function_no,
- address,
- ..
- } = function.as_ref()
- {
- let ftype = &ns.functions[*function_no];
- let mut tys: Vec<Type> = args.iter().map(|a| a.ty()).collect();
- let args = args
- .iter()
- .map(|a| expression(a, cfg, callee_contract_no, func, ns, vartab, opt))
- .collect();
- let address = expression(address, cfg, callee_contract_no, func, ns, vartab, opt);
- let gas = if let Some(gas) = gas {
- expression(gas, cfg, callee_contract_no, func, ns, vartab, opt)
- } else {
- default_gas(ns)
- };
- let value = if let Some(value) = value {
- expression(value, cfg, callee_contract_no, func, ns, vartab, opt)
- } else {
- Expression::NumberLiteral(pt::Loc(0, 0, 0), Type::Value, BigInt::zero())
- };
- let dest_func = &ns.functions[*function_no];
- tys.insert(0, Type::Bytes(4));
- let (payload, address) = if ns.target == Target::Solana {
- tys.insert(0, Type::Address(false));
- tys.insert(1, Type::Address(false));
- tys.insert(2, Type::Uint(64));
- tys.insert(3, Type::Bytes(4));
- tys.insert(4, Type::Bytes(1));
- (
- Expression::AbiEncode {
- loc: *loc,
- tys,
- packed: vec![
- address,
- Expression::Builtin(
- *loc,
- vec![Type::Address(false)],
- Builtin::GetAddress,
- Vec::new(),
- ),
- value.clone(),
- Expression::NumberLiteral(*loc, Type::Bytes(4), BigInt::zero()),
- Expression::NumberLiteral(*loc, Type::Bytes(1), BigInt::zero()),
- Expression::NumberLiteral(
- *loc,
- Type::Bytes(4),
- BigInt::from(dest_func.selector()),
- ),
- ],
- args,
- },
- None,
- )
- } else {
- (
- Expression::AbiEncode {
- loc: *loc,
- tys,
- packed: vec![Expression::NumberLiteral(
- *loc,
- Type::Bytes(4),
- BigInt::from(dest_func.selector()),
- )],
- args,
- },
- Some(address),
- )
- };
- cfg.add(
- vartab,
- Instr::ExternalCall {
- success: None,
- address,
- payload,
- value,
- gas,
- callty: CallTy::Regular,
- },
- );
- if !ftype.returns.is_empty() {
- let mut returns = Vec::new();
- let mut res = Vec::new();
- for ret in &ftype.returns {
- let id = pt::Identifier {
- loc: ret.loc,
- name: ret.name.to_owned(),
- };
- let temp_pos = vartab.temp(&id, &ret.ty);
- res.push(temp_pos);
- returns.push(Expression::Variable(id.loc, ret.ty.clone(), temp_pos));
- }
- cfg.add(
- vartab,
- Instr::AbiDecode {
- res,
- selector: None,
- exception_block: None,
- tys: ftype.returns.clone(),
- data: Expression::ReturnData(*loc),
- },
- );
- returns
- } else {
- vec![Expression::Poison]
- }
- } else if let Type::ExternalFunction {
- returns: func_returns,
- ..
- } = function.ty()
- {
- let mut tys: Vec<Type> = args.iter().map(|a| a.ty()).collect();
- let args = args
- .iter()
- .map(|a| expression(a, cfg, callee_contract_no, func, ns, vartab, opt))
- .collect();
- let function = expression(function, cfg, callee_contract_no, func, ns, vartab, opt);
- let gas = if let Some(gas) = gas {
- expression(gas, cfg, callee_contract_no, func, ns, vartab, opt)
- } else {
- default_gas(ns)
- };
- let value = if let Some(value) = value {
- expression(value, cfg, callee_contract_no, func, ns, vartab, opt)
- } else {
- Expression::NumberLiteral(pt::Loc(0, 0, 0), Type::Value, BigInt::zero())
- };
- let selector = Expression::Builtin(
- *loc,
- vec![Type::Bytes(4)],
- Builtin::FunctionSelector,
- vec![function.clone()],
- );
- let address = Expression::Builtin(
- *loc,
- vec![Type::Address(false)],
- Builtin::ExternalFunctionAddress,
- vec![function],
- );
- tys.insert(0, Type::Bytes(4));
- let payload = Expression::AbiEncode {
- loc: *loc,
- tys,
- packed: vec![selector],
- args,
- };
- cfg.add(
- vartab,
- Instr::ExternalCall {
- success: None,
- address: Some(address),
- payload,
- value,
- gas,
- callty: CallTy::Regular,
- },
- );
- if !func_returns.is_empty() {
- let mut returns = Vec::new();
- let mut res = Vec::new();
- let mut tys = Vec::new();
- for ty in func_returns {
- let temp_pos = vartab.temp_anonymous(&ty);
- res.push(temp_pos);
- returns.push(Expression::Variable(pt::Loc(0, 0, 0), ty.clone(), temp_pos));
- tys.push(Parameter {
- loc: pt::Loc(0, 0, 0),
- ty,
- ty_loc: pt::Loc(0, 0, 0),
- name: String::new(),
- name_loc: None,
- indexed: false,
- });
- }
- cfg.add(
- vartab,
- Instr::AbiDecode {
- res,
- selector: None,
- exception_block: None,
- tys,
- data: Expression::ReturnData(*loc),
- },
- );
- returns
- } else {
- vec![Expression::Poison]
- }
- } else {
- unreachable!();
- }
- }
- Expression::Builtin(loc, tys, Builtin::AbiDecode, args) => {
- let data = expression(&args[0], cfg, callee_contract_no, func, ns, vartab, opt);
- let mut returns = Vec::new();
- let mut res = Vec::new();
- for ret in tys {
- let temp_pos = vartab.temp_anonymous(ret);
- res.push(temp_pos);
- returns.push(Expression::Variable(*loc, ret.clone(), temp_pos));
- }
- cfg.add(
- vartab,
- Instr::AbiDecode {
- res,
- selector: None,
- exception_block: None,
- tys: tys
- .iter()
- .map(|ty| Parameter {
- name: "".to_owned(),
- name_loc: None,
- loc: *loc,
- ty: ty.clone(),
- ty_loc: *loc,
- indexed: false,
- })
- .collect(),
- data,
- },
- );
- returns
- }
- _ => unreachable!(),
- }
- }
- pub fn default_gas(ns: &Namespace) -> Expression {
- Expression::NumberLiteral(
- pt::Loc(0, 0, 0),
- Type::Uint(64),
- // See EIP150
- if ns.target == Target::Ewasm {
- BigInt::from(i64::MAX)
- } else {
- BigInt::zero()
- },
- )
- }
- /// Codegen for an array subscript expression
- fn array_subscript(
- loc: &pt::Loc,
- array_ty: &Type,
- array: &Expression,
- index: &Expression,
- cfg: &mut ControlFlowGraph,
- contract_no: usize,
- func: Option<&Function>,
- ns: &Namespace,
- vartab: &mut Vartable,
- opt: &Options,
- ) -> Expression {
- if array_ty.is_mapping() {
- let array = expression(array, cfg, contract_no, func, ns, vartab, opt);
- let index = expression(index, cfg, contract_no, func, ns, vartab, opt);
- return if ns.target == Target::Solana {
- Expression::Subscript(*loc, array_ty.clone(), Box::new(array), Box::new(index))
- } else {
- Expression::Keccak256(*loc, array_ty.clone(), vec![array, index])
- };
- }
- let mut array = expression(array, cfg, contract_no, func, ns, vartab, opt);
- let index_ty = index.ty();
- let index = expression(index, cfg, contract_no, func, ns, vartab, opt);
- let index_loc = index.loc();
- let index_width = index_ty.bits(ns);
- let array_length = match array_ty.deref_any() {
- Type::Bytes(n) => bigint_to_expression(
- &array.loc(),
- &BigInt::from(*n),
- ns,
- &mut Vec::new(),
- ResolveTo::Unknown,
- )
- .unwrap(),
- Type::Array(_, _) => match array_ty.array_length() {
- None => {
- if let Type::StorageRef(_, _) = array_ty {
- if ns.target == Target::Solana {
- Expression::StorageArrayLength {
- loc: *loc,
- ty: ns.storage_type(),
- array: Box::new(array.clone()),
- elem_ty: array_ty.storage_array_elem().deref_into(),
- }
- } else {
- let array_length =
- load_storage(loc, &Type::Uint(256), array.clone(), cfg, vartab, opt);
- array = Expression::Keccak256(*loc, Type::Uint(256), vec![array]);
- array_length
- }
- } else {
- Expression::Builtin(
- *loc,
- vec![Type::Uint(32)],
- Builtin::ArrayLength,
- vec![array.clone()],
- )
- }
- }
- Some(l) => {
- bigint_to_expression(loc, l, ns, &mut Vec::new(), ResolveTo::Unknown).unwrap()
- }
- },
- Type::DynamicBytes => Expression::Builtin(
- *loc,
- vec![Type::Uint(32)],
- Builtin::ArrayLength,
- vec![array.clone()],
- ),
- _ => {
- unreachable!();
- }
- };
- let array_width = array_length.ty().bits(ns);
- let width = std::cmp::max(array_width, index_width);
- let coerced_ty = Type::Uint(width);
- let pos = vartab.temp(
- &pt::Identifier {
- name: "index".to_owned(),
- loc: *loc,
- },
- &coerced_ty,
- );
- cfg.add(
- vartab,
- Instr::Set {
- loc: pt::Loc(0, 0, 0),
- res: pos,
- expr: cast(&index.loc(), index, &coerced_ty, false, ns, &mut Vec::new()).unwrap(),
- },
- );
- // If the array is fixed length and the index also constant, the
- // branch will be optimized away.
- let out_of_bounds = cfg.new_basic_block("out_of_bounds".to_string());
- let in_bounds = cfg.new_basic_block("in_bounds".to_string());
- cfg.add(
- vartab,
- Instr::BranchCond {
- cond: Expression::MoreEqual(
- *loc,
- Box::new(Expression::Variable(index_loc, coerced_ty.clone(), pos)),
- Box::new(
- cast(
- &array.loc(),
- array_length.clone(),
- &coerced_ty,
- false,
- ns,
- &mut Vec::new(),
- )
- .unwrap(),
- ),
- ),
- true_block: out_of_bounds,
- false_block: in_bounds,
- },
- );
- cfg.set_basic_block(out_of_bounds);
- cfg.add(vartab, Instr::AssertFailure { expr: None });
- cfg.set_basic_block(in_bounds);
- if let Type::StorageRef(_, ty) = &array_ty {
- let elem_ty = ty.storage_array_elem();
- let slot_ty = ns.storage_type();
- if ns.target == Target::Solana {
- if ty.array_length().is_some() && ty.is_sparse_solana(ns) {
- let index = cast(
- &index_loc,
- Expression::Variable(index_loc, coerced_ty, pos),
- &Type::Uint(256),
- false,
- ns,
- &mut Vec::new(),
- )
- .unwrap();
- Expression::Subscript(*loc, array_ty.clone(), Box::new(array), Box::new(index))
- } else {
- let index = cast(
- &index_loc,
- Expression::Variable(index_loc, coerced_ty, pos),
- &slot_ty,
- false,
- ns,
- &mut Vec::new(),
- )
- .unwrap();
- if ty.array_length().is_some() {
- // fixed length array
- let elem_size = elem_ty.deref_any().size_of(ns);
- Expression::Add(
- *loc,
- elem_ty,
- true,
- Box::new(array),
- Box::new(Expression::Multiply(
- *loc,
- slot_ty.clone(),
- true,
- Box::new(index),
- Box::new(Expression::NumberLiteral(*loc, slot_ty, elem_size)),
- )),
- )
- } else {
- Expression::Subscript(*loc, array_ty.clone(), Box::new(array), Box::new(index))
- }
- }
- } else {
- let elem_size = elem_ty.storage_slots(ns);
- if let Ok(array_length) = eval_const_number(&array_length, Some(contract_no), ns) {
- if array_length.1.mul(elem_size.clone()).to_u64().is_some() {
- // we need to calculate the storage offset. If this can be done with 64 bit
- // arithmetic it will be much more efficient on wasm
- return Expression::Add(
- *loc,
- elem_ty,
- true,
- Box::new(array),
- Box::new(Expression::ZeroExt(
- *loc,
- slot_ty,
- Box::new(Expression::Multiply(
- *loc,
- Type::Uint(64),
- true,
- Box::new(
- cast(
- &index_loc,
- Expression::Variable(index_loc, coerced_ty, pos),
- &Type::Uint(64),
- false,
- ns,
- &mut Vec::new(),
- )
- .unwrap(),
- ),
- Box::new(Expression::NumberLiteral(
- *loc,
- Type::Uint(64),
- elem_size,
- )),
- )),
- )),
- );
- }
- }
- array_offset(
- loc,
- array,
- cast(
- &index_loc,
- Expression::Variable(index_loc, coerced_ty, pos),
- &ns.storage_type(),
- false,
- ns,
- &mut Vec::new(),
- )
- .unwrap(),
- elem_ty,
- ns,
- )
- }
- } else {
- match array_ty.deref_memory() {
- Type::Bytes(array_length) => {
- let res_ty = Type::Bytes(1);
- let from_ty = Type::Bytes(*array_length);
- let index_ty = Type::Uint(*array_length as u16 * 8);
- Expression::Trunc(
- *loc,
- res_ty,
- Box::new(Expression::ShiftRight(
- *loc,
- from_ty,
- Box::new(array),
- // shift by (array_length - 1 - index) * 8
- Box::new(Expression::ShiftLeft(
- *loc,
- index_ty.clone(),
- Box::new(Expression::Subtract(
- *loc,
- index_ty.clone(),
- true,
- Box::new(Expression::NumberLiteral(
- *loc,
- index_ty.clone(),
- BigInt::from_u8(array_length - 1).unwrap(),
- )),
- Box::new(cast_shift_arg(
- loc,
- Expression::Variable(index_loc, coerced_ty, pos),
- index_width,
- array_ty,
- ns,
- )),
- )),
- Box::new(Expression::NumberLiteral(
- *loc,
- index_ty,
- BigInt::from_u8(3).unwrap(),
- )),
- )),
- false,
- )),
- )
- }
- Type::Array(_, dim) if dim.last().unwrap().is_some() => Expression::Subscript(
- *loc,
- array_ty.clone(),
- Box::new(array),
- Box::new(Expression::Variable(index_loc, coerced_ty, pos)),
- ),
- Type::DynamicBytes | Type::Array(_, _) => Expression::Subscript(
- *loc,
- array_ty.clone(),
- Box::new(array),
- Box::new(Expression::Variable(index_loc, coerced_ty, pos)),
- ),
- _ => {
- // should not happen as type-checking already done
- unreachable!();
- }
- }
- }
- }
- fn string_location(
- loc: &StringLocation,
- cfg: &mut ControlFlowGraph,
- contract_no: usize,
- func: Option<&Function>,
- ns: &Namespace,
- vartab: &mut Vartable,
- opt: &Options,
- ) -> StringLocation {
- match loc {
- StringLocation::RunTime(s) => StringLocation::RunTime(Box::new(expression(
- s,
- cfg,
- contract_no,
- func,
- ns,
- vartab,
- opt,
- ))),
- _ => loc.clone(),
- }
- }
- // Generate a load from storage instruction
- pub fn load_storage(
- loc: &pt::Loc,
- ty: &Type,
- storage: Expression,
- cfg: &mut ControlFlowGraph,
- vartab: &mut Vartable,
- _opt: &Options,
- ) -> Expression {
- let res = vartab.temp_anonymous(ty);
- cfg.add(
- vartab,
- Instr::LoadStorage {
- res,
- ty: ty.clone(),
- storage,
- },
- );
- Expression::Variable(*loc, ty.clone(), res)
- }
|