Procházet zdrojové kódy

Refactor codegen (#741)

Signed-off-by: Lucas Steuernagel <lucas.tnagel@gmail.com>
Lucas Steuernagel před 3 roky
rodič
revize
04a4eb2f9e
37 změnil soubory, kde provedl 1943 přidání a 1969 odebrání
  1. 11 23
      src/bin/languageserver/mod.rs
  2. 11 114
      src/codegen/cfg.rs
  3. 3 25
      src/codegen/constant_folding.rs
  4. 2 1
      src/codegen/dead_storage.rs
  5. 268 158
      src/codegen/expression.rs
  6. 1 0
      src/codegen/external_functions.rs
  7. 796 3
      src/codegen/mod.rs
  8. 1 1
      src/codegen/reaching_definitions.rs
  9. 83 55
      src/codegen/statements.rs
  10. 10 8
      src/codegen/storage.rs
  11. 15 260
      src/codegen/strength_reduce.rs
  12. 1 1
      src/codegen/subexpression_elimination/available_expression.rs
  13. 7 6
      src/codegen/subexpression_elimination/available_expression_set.rs
  14. 4 4
      src/codegen/subexpression_elimination/common_subexpression_tracker.rs
  15. 2 16
      src/codegen/subexpression_elimination/expression.rs
  16. 1 1
      src/codegen/subexpression_elimination/instruction.rs
  17. 0 1
      src/codegen/subexpression_elimination/mod.rs
  18. 1 5
      src/codegen/subexpression_elimination/operator.rs
  19. 24 10
      src/codegen/subexpression_elimination/tests.rs
  20. 4 2
      src/codegen/undefined_variable.rs
  21. 2 1
      src/codegen/vector_to_slice.rs
  22. 16 15
      src/emit/ewasm.rs
  23. 7 44
      src/emit/mod.rs
  24. 19 14
      src/emit/solana.rs
  25. 20 17
      src/emit/substrate.rs
  26. 2 0
      src/lib.rs
  27. 31 414
      src/sema/ast.rs
  28. 17 50
      src/sema/builtin.rs
  29. 1 10
      src/sema/dotgraphviz.rs
  30. 543 675
      src/sema/expression.rs
  31. 6 2
      src/sema/format.rs
  32. 7 0
      src/sema/mod.rs
  33. 2 0
      src/sema/mutability.rs
  34. 12 21
      src/sema/statements.rs
  35. 7 7
      src/sema/tests/mod.rs
  36. 2 2
      src/sema/variables.rs
  37. 4 3
      src/sema/yul/ast.rs

+ 11 - 23
src/bin/languageserver/mod.rs

@@ -1,6 +1,7 @@
 use clap::ArgMatches;
 use clap::ArgMatches;
 use serde_json::Value;
 use serde_json::Value;
 use solang::{
 use solang::{
+    codegen,
     codegen::codegen,
     codegen::codegen,
     file_resolver::FileResolver,
     file_resolver::FileResolver,
     parse_and_resolve,
     parse_and_resolve,
@@ -209,15 +210,15 @@ impl SolangServer {
                 msg = format!("{} {}", msg, _param.name_as_str());
                 msg = format!("{} {}", msg, _param.name_as_str());
                 if let Some(expr) = ns.var_constants.get(loc) {
                 if let Some(expr) = ns.var_constants.get(loc) {
                     match expr {
                     match expr {
-                        ast::Expression::BytesLiteral(_, ast::Type::Bytes(_), bs)
-                        | ast::Expression::BytesLiteral(_, ast::Type::DynamicBytes, bs) => {
+                        codegen::Expression::BytesLiteral(_, ast::Type::Bytes(_), bs)
+                        | codegen::Expression::BytesLiteral(_, ast::Type::DynamicBytes, bs) => {
                             msg.push_str(&format!(" = hex\"{}\"", hex::encode(&bs)));
                             msg.push_str(&format!(" = hex\"{}\"", hex::encode(&bs)));
                         }
                         }
-                        ast::Expression::BytesLiteral(_, ast::Type::String, bs) => {
+                        codegen::Expression::BytesLiteral(_, ast::Type::String, bs) => {
                             msg.push_str(&format!(" = \"{}\"", String::from_utf8_lossy(bs)));
                             msg.push_str(&format!(" = \"{}\"", String::from_utf8_lossy(bs)));
                         }
                         }
-                        ast::Expression::NumberLiteral(_, ast::Type::Uint(_), n)
-                        | ast::Expression::NumberLiteral(_, ast::Type::Int(_), n) => {
+                        codegen::Expression::NumberLiteral(_, ast::Type::Uint(_), n)
+                        | codegen::Expression::NumberLiteral(_, ast::Type::Int(_), n) => {
                             msg.push_str(&format!(" = {}", n));
                             msg.push_str(&format!(" = {}", n));
                         }
                         }
                         _ => (),
                         _ => (),
@@ -506,15 +507,15 @@ impl SolangServer {
 
 
                 if let Some(expr) = ns.var_constants.get(loc) {
                 if let Some(expr) = ns.var_constants.get(loc) {
                     match expr {
                     match expr {
-                        ast::Expression::BytesLiteral(_, ast::Type::Bytes(_), bs)
-                        | ast::Expression::BytesLiteral(_, ast::Type::DynamicBytes, bs) => {
+                        codegen::Expression::BytesLiteral(_, ast::Type::Bytes(_), bs)
+                        | codegen::Expression::BytesLiteral(_, ast::Type::DynamicBytes, bs) => {
                             msg.push_str(&format!(" hex\"{}\"", hex::encode(&bs)));
                             msg.push_str(&format!(" hex\"{}\"", hex::encode(&bs)));
                         }
                         }
-                        ast::Expression::BytesLiteral(_, ast::Type::String, bs) => {
+                        codegen::Expression::BytesLiteral(_, ast::Type::String, bs) => {
                             msg.push_str(&format!(" \"{}\"", String::from_utf8_lossy(bs)));
                             msg.push_str(&format!(" \"{}\"", String::from_utf8_lossy(bs)));
                         }
                         }
-                        ast::Expression::NumberLiteral(_, ast::Type::Uint(_), n)
-                        | ast::Expression::NumberLiteral(_, ast::Type::Int(_), n) => {
+                        codegen::Expression::NumberLiteral(_, ast::Type::Uint(_), n)
+                        | codegen::Expression::NumberLiteral(_, ast::Type::Int(_), n) => {
                             msg.push_str(&format!(" {}", n));
                             msg.push_str(&format!(" {}", n));
                         }
                         }
                         _ => (),
                         _ => (),
@@ -803,19 +804,6 @@ impl SolangServer {
                     SolangServer::construct_expr(space, lookup_tbl, symtab, fnc_map, ns);
                     SolangServer::construct_expr(space, lookup_tbl, symtab, fnc_map, ns);
                 }
                 }
             }
             }
-
-            // Hash table operation expression
-            ast::Expression::Keccak256(_locs, _typ, expr) => {
-                for expp in expr {
-                    SolangServer::construct_expr(expp, lookup_tbl, symtab, fnc_map, ns);
-                }
-                lookup_tbl.push((_locs.start(), _locs.end(), String::from("Keccak256 hash")));
-            }
-
-            ast::Expression::ReturnData(locs) => {
-                let msg = String::from("Return");
-                lookup_tbl.push((locs.start(), locs.end(), msg));
-            }
             ast::Expression::Builtin(_locs, _typ, _builtin, expr) => {
             ast::Expression::Builtin(_locs, _typ, _builtin, expr) => {
                 let msg = SolangServer::construct_builtins(_builtin, ns);
                 let msg = SolangServer::construct_builtins(_builtin, ns);
                 lookup_tbl.push((_locs.start(), _locs.end(), msg));
                 lookup_tbl.push((_locs.start(), _locs.end(), msg));

+ 11 - 114
src/codegen/cfg.rs

@@ -13,14 +13,14 @@ use super::{
     vector_to_slice, Options,
     vector_to_slice, Options,
 };
 };
 use crate::codegen::subexpression_elimination::common_sub_expression_elimination;
 use crate::codegen::subexpression_elimination::common_sub_expression_elimination;
-use crate::codegen::{undefined_variable, LLVMName};
+use crate::codegen::{undefined_variable, Expression, LLVMName};
 use crate::parser::pt;
 use crate::parser::pt;
 use crate::parser::pt::CodeLocation;
 use crate::parser::pt::CodeLocation;
-use crate::sema::ast::{
-    CallTy, Contract, Expression, Function, Namespace, Parameter, StringLocation, Type,
-};
+use crate::sema::ast::RetrieveType;
+use crate::sema::ast::{CallTy, Contract, Function, Namespace, Parameter, StringLocation, Type};
 use crate::sema::contracts::{collect_base_args, visit_bases};
 use crate::sema::contracts::{collect_base_args, visit_bases};
-use crate::Target;
+use crate::sema::Recurse;
+use crate::{ast, Target};
 
 
 #[derive(Clone)]
 #[derive(Clone)]
 #[allow(clippy::large_enum_variant)]
 #[allow(clippy::large_enum_variant)]
@@ -518,23 +518,9 @@ impl ControlFlowGraph {
                 self.expr_to_string(contract, ns, r)
                 self.expr_to_string(contract, ns, r)
             ),
             ),
             Expression::Variable(_, _, res) => format!("%{}", self.vars[res].id.name),
             Expression::Variable(_, _, res) => format!("%{}", self.vars[res].id.name),
-            Expression::ConstantVariable(_, _, Some(var_contract_no), var_no)
-            | Expression::StorageVariable(_, _, var_contract_no, var_no) => format!(
-                "${}.{}",
-                ns.contracts[*var_contract_no].name,
-                ns.contracts[*var_contract_no].variables[*var_no].name
-            ),
-            Expression::ConstantVariable(_, _, None, var_no) => {
-                format!("${}", ns.constants[*var_no].name)
-            }
             Expression::Load(_, _, expr) => {
             Expression::Load(_, _, expr) => {
                 format!("(load {})", self.expr_to_string(contract, ns, expr))
                 format!("(load {})", self.expr_to_string(contract, ns, expr))
             }
             }
-            Expression::StorageLoad(_, ty, expr) => format!(
-                "(loadstorage ty:{} {})",
-                ty.to_string(ns),
-                self.expr_to_string(contract, ns, expr)
-            ),
             Expression::ZeroExt(_, ty, e) => format!(
             Expression::ZeroExt(_, ty, e) => format!(
                 "(zext {} {})",
                 "(zext {} {})",
                 ty.to_string(ns),
                 ty.to_string(ns),
@@ -596,22 +582,6 @@ impl ControlFlowGraph {
                 self.expr_to_string(contract, ns, a),
                 self.expr_to_string(contract, ns, a),
                 f
                 f
             ),
             ),
-            Expression::Or(_, l, r) => format!(
-                "({} || {})",
-                self.expr_to_string(contract, ns, l),
-                self.expr_to_string(contract, ns, r)
-            ),
-            Expression::And(_, l, r) => format!(
-                "({} && {})",
-                self.expr_to_string(contract, ns, l),
-                self.expr_to_string(contract, ns, r)
-            ),
-            Expression::Ternary(_, _, c, l, r) => format!(
-                "({} ? {} : {})",
-                self.expr_to_string(contract, ns, c),
-                self.expr_to_string(contract, ns, l),
-                self.expr_to_string(contract, ns, r)
-            ),
             Expression::Not(_, e) => format!("!{}", self.expr_to_string(contract, ns, e)),
             Expression::Not(_, e) => format!("!{}", self.expr_to_string(contract, ns, e)),
             Expression::Complement(_, _, e) => format!("~{}", self.expr_to_string(contract, ns, e)),
             Expression::Complement(_, _, e) => format!("~{}", self.expr_to_string(contract, ns, e)),
             Expression::UnaryMinus(_, _, e) => format!("-{}", self.expr_to_string(contract, ns, e)),
             Expression::UnaryMinus(_, _, e) => format!("-{}", self.expr_to_string(contract, ns, e)),
@@ -648,19 +618,6 @@ impl ControlFlowGraph {
                     .collect::<Vec<String>>()
                     .collect::<Vec<String>>()
                     .join(", ")
                     .join(", ")
             ),
             ),
-            Expression::InternalFunction {
-                function_no,
-                signature,
-                ..
-            } => {
-                let function_no = if let Some(signature) = signature {
-                    contract.virtual_functions[signature]
-                } else {
-                    *function_no
-                };
-
-                ns.functions[function_no].print_name(ns)
-            }
             Expression::ExternalFunction {
             Expression::ExternalFunction {
                 address,
                 address,
                 function_no,
                 function_no,
@@ -673,41 +630,6 @@ impl ControlFlowGraph {
             Expression::InternalFunctionCfg(cfg_no) => {
             Expression::InternalFunctionCfg(cfg_no) => {
                 format!("function {}", contract.cfg[*cfg_no].name)
                 format!("function {}", contract.cfg[*cfg_no].name)
             }
             }
-            Expression::InternalFunctionCall { function, args, .. } => format!(
-                "(call {} ({})",
-                self.expr_to_string(contract, ns, function),
-                args.iter()
-                    .map(|a| self.expr_to_string(contract, ns, a))
-                    .collect::<Vec<String>>()
-                    .join(", ")
-            ),
-            Expression::Constructor {
-                contract_no,
-                constructor_no: Some(constructor_no),
-                args,
-                ..
-            } => format!(
-                "(constructor:{} ({}) ({})",
-                ns.contracts[*contract_no].name,
-                ns.functions[*constructor_no].signature,
-                args.iter()
-                    .map(|a| self.expr_to_string(contract, ns, a))
-                    .collect::<Vec<String>>()
-                    .join(", ")
-            ),
-            Expression::Constructor {
-                contract_no,
-                constructor_no: None,
-                args,
-                ..
-            } => format!(
-                "(constructor:{} ({})",
-                ns.contracts[*contract_no].name,
-                args.iter()
-                    .map(|a| self.expr_to_string(contract, ns, a))
-                    .collect::<Vec<String>>()
-                    .join(", ")
-            ),
             Expression::CodeLiteral(_, contract_no, runtime) => format!(
             Expression::CodeLiteral(_, contract_no, runtime) => format!(
                 "({} code contract {})",
                 "({} code contract {})",
                 if *runtime {
                 if *runtime {
@@ -717,32 +639,7 @@ impl ControlFlowGraph {
                 },
                 },
                 ns.contracts[*contract_no].name,
                 ns.contracts[*contract_no].name,
             ),
             ),
-            Expression::ExternalFunctionCall { function, args, .. } => format!(
-                "(external call {} ({})",
-                self.expr_to_string(contract, ns, function),
-                args.iter()
-                    .map(|a| self.expr_to_string(contract, ns, a))
-                    .collect::<Vec<String>>()
-                    .join(", ")
-            ),
             Expression::ReturnData(_) => "(external call return data)".to_string(),
             Expression::ReturnData(_) => "(external call return data)".to_string(),
-            Expression::Assign(_, _, l, r) => format!(
-                "{} = {}",
-                self.expr_to_string(contract, ns, l),
-                self.expr_to_string(contract, ns, r)
-            ),
-            Expression::PostDecrement(_, _, _, e) => {
-                format!("{}--", self.expr_to_string(contract, ns, e),)
-            }
-            Expression::PostIncrement(_, _, _, e) => {
-                format!("{}++", self.expr_to_string(contract, ns, e),)
-            }
-            Expression::PreDecrement(_, _, _, e) => {
-                format!("--{}", self.expr_to_string(contract, ns, e),)
-            }
-            Expression::PreIncrement(_, _, _, e) => {
-                format!("++{}", self.expr_to_string(contract, ns, e),)
-            }
             Expression::Cast(_, ty, e) => format!(
             Expression::Cast(_, ty, e) => format!(
                 "{}({})",
                 "{}({})",
                 ty.to_string(ns),
                 ty.to_string(ns),
@@ -793,7 +690,7 @@ impl ControlFlowGraph {
         &self,
         &self,
         contract: &Contract,
         contract: &Contract,
         ns: &Namespace,
         ns: &Namespace,
-        l: &StringLocation,
+        l: &StringLocation<Expression>,
     ) -> String {
     ) -> String {
         match l {
         match l {
             StringLocation::RunTime(e) => self.expr_to_string(contract, ns, e),
             StringLocation::RunTime(e) => self.expr_to_string(contract, ns, e),
@@ -1254,11 +1151,11 @@ pub fn generate_cfg(
 
 
 /// resolve modifier call
 /// resolve modifier call
 fn resolve_modifier_call<'a>(
 fn resolve_modifier_call<'a>(
-    call: &'a Expression,
+    call: &'a ast::Expression,
     contract: &Contract,
     contract: &Contract,
-) -> (usize, &'a Vec<Expression>) {
-    if let Expression::InternalFunctionCall { function, args, .. } = call {
-        if let Expression::InternalFunction {
+) -> (usize, &'a Vec<ast::Expression>) {
+    if let ast::Expression::InternalFunctionCall { function, args, .. } = call {
+        if let ast::Expression::InternalFunction {
             function_no,
             function_no,
             signature,
             signature,
             ..
             ..
@@ -1596,7 +1493,7 @@ pub fn generate_modifier_dispatch(
     modifier: &Function,
     modifier: &Function,
     cfg_no: usize,
     cfg_no: usize,
     chain_no: usize,
     chain_no: usize,
-    args: &[Expression],
+    args: &[ast::Expression],
     ns: &Namespace,
     ns: &Namespace,
     opt: &Options,
     opt: &Options,
 ) -> (ControlFlowGraph, usize) {
 ) -> (ControlFlowGraph, usize) {

+ 3 - 25
src/codegen/constant_folding.rs

@@ -1,7 +1,9 @@
 use super::cfg::{ControlFlowGraph, Instr};
 use super::cfg::{ControlFlowGraph, Instr};
 use super::reaching_definitions;
 use super::reaching_definitions;
+use crate::codegen::Expression;
 use crate::parser::pt::Loc;
 use crate::parser::pt::Loc;
-use crate::sema::ast::{Builtin, Diagnostic, Expression, Namespace, StringLocation, Type};
+use crate::sema::ast::RetrieveType;
+use crate::sema::ast::{Builtin, Diagnostic, Namespace, StringLocation, Type};
 use num_bigint::{BigInt, Sign};
 use num_bigint::{BigInt, Sign};
 use num_traits::{ToPrimitive, Zero};
 use num_traits::{ToPrimitive, Zero};
 use ripemd::Ripemd160;
 use ripemd::Ripemd160;
@@ -820,14 +822,6 @@ fn expression(
 
 
             (Expression::Load(*loc, ty.clone(), Box::new(expr)), false)
             (Expression::Load(*loc, ty.clone(), Box::new(expr)), false)
         }
         }
-        Expression::StorageLoad(loc, ty, expr) => {
-            let (expr, _) = expression(expr, vars, cfg, ns);
-
-            (
-                Expression::StorageLoad(*loc, ty.clone(), Box::new(expr)),
-                false,
-            )
-        }
         Expression::Cast(loc, ty, expr) => {
         Expression::Cast(loc, ty, expr) => {
             let (expr, _) = expression(expr, vars, cfg, ns);
             let (expr, _) = expression(expr, vars, cfg, ns);
 
 
@@ -895,22 +889,6 @@ fn expression(
                 false,
                 false,
             )
             )
         }
         }
-        Expression::Ternary(loc, ty, cond, left, right) => {
-            let cond = expression(cond, vars, cfg, ns);
-            let left = expression(left, vars, cfg, ns);
-            let right = expression(right, vars, cfg, ns);
-
-            (
-                Expression::Ternary(
-                    *loc,
-                    ty.clone(),
-                    Box::new(cond.0),
-                    Box::new(left.0),
-                    Box::new(right.0),
-                ),
-                false,
-            )
-        }
         Expression::Not(loc, expr) => {
         Expression::Not(loc, expr) => {
             let expr = expression(expr, vars, cfg, ns);
             let expr = expression(expr, vars, cfg, ns);
 
 

+ 2 - 1
src/codegen/dead_storage.rs

@@ -1,6 +1,7 @@
 use super::cfg::{BasicBlock, ControlFlowGraph, Instr};
 use super::cfg::{BasicBlock, ControlFlowGraph, Instr};
+use crate::codegen::Expression;
 use crate::parser::pt::Loc;
 use crate::parser::pt::Loc;
-use crate::sema::ast::{Expression, Namespace};
+use crate::sema::ast::Namespace;
 use std::collections::{HashMap, HashSet};
 use std::collections::{HashMap, HashSet};
 use std::fmt;
 use std::fmt;
 
 

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 268 - 158
src/codegen/expression.rs


+ 1 - 0
src/codegen/external_functions.rs

@@ -1,4 +1,5 @@
 use crate::sema::ast::{DestructureField, Expression, Namespace, Statement};
 use crate::sema::ast::{DestructureField, Expression, Namespace, Statement};
+use crate::sema::Recurse;
 use indexmap::IndexSet;
 use indexmap::IndexSet;
 
 
 #[derive(Default)]
 #[derive(Default)]

+ 796 - 3
src/codegen/mod.rs

@@ -1,4 +1,4 @@
-pub(crate) mod cfg;
+pub mod cfg;
 mod constant_folding;
 mod constant_folding;
 mod dead_storage;
 mod dead_storage;
 mod expression;
 mod expression;
@@ -24,11 +24,17 @@ use crate::sema::ast::{Layout, Namespace};
 use crate::sema::contracts::visit_bases;
 use crate::sema::contracts::visit_bases;
 use crate::sema::diagnostics::any_errors;
 use crate::sema::diagnostics::any_errors;
 use crate::Target;
 use crate::Target;
+use std::cmp::Ordering;
 
 
 use crate::ast::Function;
 use crate::ast::Function;
+use crate::ast::{Builtin, FormatArg, RetrieveType, StringLocation, Type};
 use crate::codegen::cfg::ASTFunction;
 use crate::codegen::cfg::ASTFunction;
-use num_bigint::BigInt;
-use num_traits::Zero;
+use crate::sema::Recurse;
+use num_bigint::{BigInt, Sign};
+use num_rational::BigRational;
+use num_traits::{FromPrimitive, Zero};
+use solang_parser::pt;
+use solang_parser::pt::{CodeLocation, Loc};
 
 
 // The sizeof(struct account_data_header)
 // The sizeof(struct account_data_header)
 pub const SOLANA_FIRST_OFFSET: u64 = 16;
 pub const SOLANA_FIRST_OFFSET: u64 = 16;
@@ -327,3 +333,790 @@ impl LLVMName for Function {
         sig
         sig
     }
     }
 }
 }
+
+#[derive(Clone, Debug, PartialEq)]
+pub enum Expression {
+    AbiEncode {
+        loc: pt::Loc,
+        tys: Vec<Type>,
+        packed: Vec<Expression>,
+        args: Vec<Expression>,
+    },
+    Add(pt::Loc, Type, bool, Box<Expression>, Box<Expression>),
+    AllocDynamicArray(pt::Loc, Type, Box<Expression>, Option<Vec<u8>>),
+    ArrayLiteral(pt::Loc, Type, Vec<u32>, Vec<Expression>),
+    BitwiseAnd(pt::Loc, Type, Box<Expression>, Box<Expression>),
+    BitwiseOr(pt::Loc, Type, Box<Expression>, Box<Expression>),
+    BitwiseXor(pt::Loc, Type, Box<Expression>, Box<Expression>),
+    BoolLiteral(pt::Loc, bool),
+    Builtin(pt::Loc, Vec<Type>, Builtin, Vec<Expression>),
+    BytesCast(pt::Loc, Type, Type, Box<Expression>),
+    BytesLiteral(pt::Loc, Type, Vec<u8>),
+    Cast(pt::Loc, Type, Box<Expression>),
+    CodeLiteral(pt::Loc, usize, bool),
+    Complement(pt::Loc, Type, Box<Expression>),
+    ConstArrayLiteral(pt::Loc, Type, Vec<u32>, Vec<Expression>),
+    Divide(pt::Loc, Type, Box<Expression>, Box<Expression>),
+    Equal(pt::Loc, Box<Expression>, Box<Expression>),
+    ExternalFunction {
+        loc: pt::Loc,
+        ty: Type,
+        address: Box<Expression>,
+        function_no: usize,
+    },
+    FormatString(pt::Loc, Vec<(FormatArg, Expression)>),
+    FunctionArg(pt::Loc, Type, usize),
+    GetRef(pt::Loc, Type, Box<Expression>),
+    InternalFunctionCfg(usize),
+    Keccak256(pt::Loc, Type, Vec<Expression>),
+    List(pt::Loc, Vec<Expression>),
+    Less(pt::Loc, Box<Expression>, Box<Expression>),
+    LessEqual(pt::Loc, Box<Expression>, Box<Expression>),
+    Load(pt::Loc, Type, Box<Expression>),
+    Modulo(pt::Loc, Type, Box<Expression>, Box<Expression>),
+    More(pt::Loc, Box<Expression>, Box<Expression>),
+    MoreEqual(pt::Loc, Box<Expression>, Box<Expression>),
+    Multiply(pt::Loc, Type, bool, Box<Expression>, Box<Expression>),
+    Not(pt::Loc, Box<Expression>),
+    NotEqual(pt::Loc, Box<Expression>, Box<Expression>),
+    NumberLiteral(pt::Loc, Type, BigInt),
+    Poison,
+    Power(pt::Loc, Type, bool, Box<Expression>, Box<Expression>),
+    RationalNumberLiteral(pt::Loc, Type, BigRational),
+    ReturnData(pt::Loc),
+    SignExt(pt::Loc, Type, Box<Expression>),
+    ShiftLeft(pt::Loc, Type, Box<Expression>, Box<Expression>),
+    ShiftRight(pt::Loc, Type, Box<Expression>, Box<Expression>, bool),
+    StorageArrayLength {
+        loc: pt::Loc,
+        ty: Type,
+        array: Box<Expression>,
+        elem_ty: Type,
+    },
+    StringCompare(
+        pt::Loc,
+        StringLocation<Expression>,
+        StringLocation<Expression>,
+    ),
+    StringConcat(
+        pt::Loc,
+        Type,
+        StringLocation<Expression>,
+        StringLocation<Expression>,
+    ),
+    StructLiteral(pt::Loc, Type, Vec<Expression>),
+    StructMember(pt::Loc, Type, Box<Expression>, usize),
+    Subscript(pt::Loc, Type, Type, Box<Expression>, Box<Expression>),
+    Subtract(pt::Loc, Type, bool, Box<Expression>, Box<Expression>),
+    Trunc(pt::Loc, Type, Box<Expression>),
+    UnaryMinus(pt::Loc, Type, Box<Expression>),
+    Undefined(Type),
+    Variable(pt::Loc, Type, usize),
+    ZeroExt(pt::Loc, Type, Box<Expression>),
+}
+
+impl CodeLocation for Expression {
+    fn loc(&self) -> Loc {
+        match self {
+            Expression::AbiEncode { loc, .. }
+            | Expression::StorageArrayLength { loc, .. }
+            | Expression::ExternalFunction { 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::Divide(loc, ..)
+            | Expression::Modulo(loc, ..)
+            | Expression::Power(loc, ..)
+            | Expression::BitwiseOr(loc, ..)
+            | Expression::BitwiseAnd(loc, ..)
+            | Expression::BitwiseXor(loc, ..)
+            | Expression::Equal(loc, ..)
+            | Expression::NotEqual(loc, ..)
+            | Expression::Complement(loc, ..)
+            | Expression::UnaryMinus(loc, ..)
+            | Expression::Less(loc, ..)
+            | Expression::Not(loc, ..)
+            | Expression::StructLiteral(loc, ..)
+            | Expression::ArrayLiteral(loc, ..)
+            | Expression::ConstArrayLiteral(loc, ..)
+            | Expression::StructMember(loc, ..)
+            | Expression::StringCompare(loc, ..)
+            | Expression::StringConcat(loc, ..)
+            | Expression::FunctionArg(loc, ..)
+            | Expression::CodeLiteral(loc, ..)
+            | Expression::List(loc, ..)
+            | Expression::ShiftRight(loc, ..)
+            | Expression::ShiftLeft(loc, ..)
+            | Expression::RationalNumberLiteral(loc, ..)
+            | Expression::AllocDynamicArray(loc, ..)
+            | Expression::BytesCast(loc, ..)
+            | Expression::More(loc, ..)
+            | Expression::ZeroExt(loc, ..) => *loc,
+
+            Expression::InternalFunctionCfg(_) | Expression::Poison | Expression::Undefined(_) => {
+                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::AbiEncode { packed, args, .. } => {
+                for item in packed {
+                    item.recurse(cx, f);
+                }
+
+                for arg in args {
+                    arg.recurse(cx, f);
+                }
+            }
+
+            Expression::BitwiseAnd(_, _, left, right)
+            | Expression::BitwiseOr(_, _, left, right)
+            | Expression::Divide(_, _, 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(_, _, _, left, right)
+            | Expression::Subscript(_, _, _, left, right)
+            | Expression::Subtract(_, _, _, left, right)
+            | Expression::Add(_, _, _, left, right) => {
+                left.recurse(cx, f);
+                right.recurse(cx, f);
+            }
+
+            Expression::BytesCast(_, _, _, exp)
+            | Expression::Cast(_, _, exp)
+            | Expression::GetRef(_, _, exp)
+            | Expression::Not(_, exp)
+            | Expression::Trunc(_, _, exp)
+            | Expression::UnaryMinus(_, _, exp)
+            | Expression::ZeroExt(_, _, exp)
+            | Expression::SignExt(_, _, exp)
+            | Expression::Complement(_, _, exp)
+            | Expression::ExternalFunction { address: exp, .. }
+            | Expression::Load(_, _, exp)
+            | Expression::StorageArrayLength { array: exp, .. }
+            | Expression::StructMember(_, _, exp, _)
+            | Expression::AllocDynamicArray(_, _, exp, _) => {
+                exp.recurse(cx, f);
+            }
+
+            Expression::Builtin(_, _, _, vec)
+            | Expression::ConstArrayLiteral(_, _, _, vec)
+            | Expression::Keccak256(_, _, vec)
+            | Expression::StructLiteral(_, _, vec)
+            | Expression::ArrayLiteral(_, _, _, vec) => {
+                for item in vec {
+                    item.recurse(cx, f);
+                }
+            }
+
+            Expression::FormatString(_, vec) => {
+                for item in vec {
+                    item.1.recurse(cx, f);
+                }
+            }
+
+            Expression::StringCompare(_, left, right)
+            | Expression::StringConcat(_, _, 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::AbiEncode { .. }
+            | Expression::CodeLiteral(..)
+            | Expression::ReturnData(_) => Type::DynamicBytes,
+            Expression::Builtin(_, returns, ..) => {
+                assert_eq!(returns.len(), 1);
+                returns[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::Divide(_, ty, ..)
+            | Expression::Modulo(_, ty, ..)
+            | Expression::Power(_, ty, ..)
+            | Expression::BitwiseOr(_, ty, ..)
+            | Expression::BitwiseAnd(_, ty, ..)
+            | Expression::BitwiseXor(_, ty, ..)
+            | Expression::ShiftLeft(_, ty, ..)
+            | Expression::ShiftRight(_, ty, ..)
+            | Expression::Complement(_, ty, ..)
+            | Expression::StorageArrayLength { ty, .. }
+            | Expression::UnaryMinus(_, ty, ..)
+            | Expression::StructLiteral(_, ty, ..)
+            | Expression::ArrayLiteral(_, ty, ..)
+            | Expression::ConstArrayLiteral(_, ty, ..)
+            | Expression::ExternalFunction { ty, .. }
+            | Expression::StructMember(_, ty, ..)
+            | Expression::StringConcat(_, ty, ..)
+            | Expression::FunctionArg(_, ty, ..)
+            | Expression::AllocDynamicArray(_, ty, ..)
+            | Expression::BytesCast(_, ty, ..)
+            | Expression::RationalNumberLiteral(_, ty, ..)
+            | Expression::Subscript(_, ty, ..) => ty.clone(),
+
+            Expression::BoolLiteral(..)
+            | Expression::MoreEqual(..)
+            | Expression::More(..)
+            | Expression::Not(..)
+            | Expression::NotEqual(..)
+            | Expression::Less(..)
+            | Expression::Equal(..)
+            | Expression::StringCompare(..)
+            | Expression::LessEqual(..) => Type::Bool,
+
+            Expression::List(_, list) => {
+                assert_eq!(list.len(), 1);
+
+                list[0].ty()
+            }
+
+            Expression::FormatString(..) => Type::String,
+            Expression::InternalFunctionCfg(_) => Type::Unreachable,
+            Expression::Poison => unreachable!("Expression does not have a type"),
+        }
+    }
+}
+
+impl Expression {
+    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(_, _, ref n), p, &Type::Uint(to_len))
+                if p.is_primitive() =>
+            {
+                return if n.sign() == Sign::Minus {
+                    let mut bs = n.to_signed_bytes_le();
+                    bs.resize(to_len as usize / 8, 0xff);
+                    Expression::NumberLiteral(
+                        self.loc(),
+                        Type::Uint(to_len),
+                        BigInt::from_bytes_le(Sign::Plus, &bs),
+                    )
+                } else {
+                    Expression::NumberLiteral(self.loc(), Type::Uint(to_len), n.clone())
+                }
+            }
+            (&Expression::NumberLiteral(_, _, ref n), p, &Type::Int(to_len))
+                if p.is_primitive() =>
+            {
+                return Expression::NumberLiteral(self.loc(), Type::Int(to_len), n.clone());
+            }
+            (&Expression::NumberLiteral(_, _, ref n), p, &Type::Bytes(to_len))
+                if p.is_primitive() =>
+            {
+                return Expression::NumberLiteral(self.loc(), Type::Bytes(to_len), n.clone());
+            }
+            (&Expression::NumberLiteral(_, _, ref n), p, &Type::Address(payable))
+                if p.is_primitive() =>
+            {
+                return Expression::NumberLiteral(self.loc(), Type::Address(payable), n.clone());
+            }
+
+            (&Expression::BytesLiteral(_, _, ref 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(self.loc(), Type::Bytes(to_len), bs);
+            }
+            (&Expression::BytesLiteral(loc, _, ref init), _, &Type::DynamicBytes)
+            | (&Expression::BytesLiteral(loc, _, ref init), _, &Type::String) => {
+                return Expression::AllocDynamicArray(
+                    loc,
+                    to.clone(),
+                    Box::new(Expression::NumberLiteral(
+                        loc,
+                        Type::Uint(32),
+                        BigInt::from(init.len()),
+                    )),
+                    Some(init.clone()),
+                );
+            }
+            (&Expression::NumberLiteral(_, _, ref n), _, &Type::Rational) => {
+                return Expression::RationalNumberLiteral(
+                    self.loc(),
+                    Type::Rational,
+                    BigRational::from(n.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,
+        };
+
+        #[allow(clippy::comparison_chain)]
+        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(self.loc(), to.clone(), Box::new(self.clone()))
+                    }
+                    Ordering::Less => {
+                        Expression::ZeroExt(self.loc(), to.clone(), Box::new(self.clone()))
+                    }
+                    Ordering::Equal => {
+                        Expression::Cast(self.loc(), to.clone(), 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(self.loc(), to.clone(), Box::new(self.clone()))
+                }
+                Ordering::Less => {
+                    Expression::ZeroExt(self.loc(), to.clone(), Box::new(self.clone()))
+                }
+                Ordering::Equal => Expression::Cast(self.loc(), to.clone(), 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(self.loc(), to.clone(), Box::new(self.clone()))
+                }
+                Ordering::Less => {
+                    Expression::SignExt(self.loc(), to.clone(), Box::new(self.clone()))
+                }
+                Ordering::Equal => Expression::Cast(self.loc(), to.clone(), 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() {
+                    Type::Int(address_bits)
+                } else {
+                    Type::Uint(address_bits)
+                };
+
+                let expr = if *from_len > address_bits {
+                    Expression::Trunc(self.loc(), address_to_int, Box::new(self.clone()))
+                } else if *from_len < address_bits {
+                    if from.is_signed_int() {
+                        Expression::ZeroExt(self.loc(), to.clone(), Box::new(self.clone()))
+                    } else {
+                        Expression::SignExt(self.loc(), to.clone(), Box::new(self.clone()))
+                    }
+                } else {
+                    self.clone()
+                };
+
+                Expression::Cast(self.loc(), to.clone(), Box::new(expr))
+            }
+            (Type::Address(_), Type::Uint(to_len)) | (Type::Address(_), Type::Int(to_len)) => {
+                let address_to_int = if to.is_signed_int() {
+                    Type::Int(address_bits)
+                } else {
+                    Type::Uint(address_bits)
+                };
+
+                let expr = Expression::Cast(self.loc(), address_to_int, Box::new(self.clone()));
+
+                // now resize int to request size with sign extension etc
+                if *to_len < address_bits {
+                    Expression::Trunc(self.loc(), to.clone(), Box::new(expr))
+                } else if *to_len > address_bits {
+                    if to.is_signed_int() {
+                        Expression::ZeroExt(self.loc(), to.clone(), Box::new(expr))
+                    } else {
+                        Expression::SignExt(self.loc(), to.clone(), Box::new(expr))
+                    }
+                } else {
+                    expr
+                }
+            }
+            (Type::Bytes(from_len), Type::Bytes(to_len)) => {
+                if to_len > from_len {
+                    let shift = (to_len - from_len) * 8;
+
+                    Expression::ShiftLeft(
+                        self.loc(),
+                        to.clone(),
+                        Box::new(Expression::ZeroExt(
+                            self.loc(),
+                            to.clone(),
+                            Box::new(self.clone()),
+                        )),
+                        Box::new(Expression::NumberLiteral(
+                            self.loc(),
+                            Type::Uint(*to_len as u16 * 8),
+                            BigInt::from_u8(shift).unwrap(),
+                        )),
+                    )
+                } else {
+                    let shift = (from_len - to_len) * 8;
+
+                    Expression::Trunc(
+                        self.loc(),
+                        to.clone(),
+                        Box::new(Expression::ShiftRight(
+                            self.loc(),
+                            from.clone(),
+                            Box::new(self.clone()),
+                            Box::new(Expression::NumberLiteral(
+                                self.loc(),
+                                Type::Uint(*from_len as u16 * 8),
+                                BigInt::from_u8(shift).unwrap(),
+                            )),
+                            false,
+                        )),
+                    )
+                }
+            }
+            // Conversion from rational will never happen in codegen
+            (Type::Uint(_) | Type::Int(_) | Type::Value, Type::Rational) => {
+                Expression::Cast(self.loc(), to.clone(), Box::new(self.clone()))
+            }
+
+            (Type::Bytes(_), Type::DynamicBytes) | (Type::DynamicBytes, Type::Bytes(_)) => {
+                Expression::BytesCast(self.loc(), from.clone(), to.clone(), Box::new(self.clone()))
+            }
+
+            (Type::Bytes(_), Type::Uint(_))
+            | (Type::Bytes(_), Type::Int(_))
+            | (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(self.loc(), to.clone(), Box::new(self.clone()))
+            }
+
+            _ => 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, args) => Expression::StructLiteral(
+                    *loc,
+                    ty.clone(),
+                    args.iter().map(|e| filter(e, ctx)).collect(),
+                ),
+                Expression::ArrayLiteral(loc, ty, lengths, args) => Expression::ArrayLiteral(
+                    *loc,
+                    ty.clone(),
+                    lengths.clone(),
+                    args.iter().map(|e| filter(e, ctx)).collect(),
+                ),
+                Expression::ConstArrayLiteral(loc, ty, lengths, args) => {
+                    Expression::ConstArrayLiteral(
+                        *loc,
+                        ty.clone(),
+                        lengths.clone(),
+                        args.iter().map(|e| filter(e, ctx)).collect(),
+                    )
+                }
+                Expression::Add(loc, ty, unchecked, left, right) => Expression::Add(
+                    *loc,
+                    ty.clone(),
+                    *unchecked,
+                    Box::new(filter(left, ctx)),
+                    Box::new(filter(right, ctx)),
+                ),
+                Expression::Subtract(loc, ty, unchecked, left, right) => Expression::Subtract(
+                    *loc,
+                    ty.clone(),
+                    *unchecked,
+                    Box::new(filter(left, ctx)),
+                    Box::new(filter(right, ctx)),
+                ),
+                Expression::Multiply(loc, ty, unchecked, left, right) => Expression::Multiply(
+                    *loc,
+                    ty.clone(),
+                    *unchecked,
+                    Box::new(filter(left, ctx)),
+                    Box::new(filter(right, ctx)),
+                ),
+                Expression::Divide(loc, ty, left, right) => Expression::Divide(
+                    *loc,
+                    ty.clone(),
+                    Box::new(filter(left, ctx)),
+                    Box::new(filter(right, ctx)),
+                ),
+                Expression::Power(loc, ty, unchecked, left, right) => Expression::Power(
+                    *loc,
+                    ty.clone(),
+                    *unchecked,
+                    Box::new(filter(left, ctx)),
+                    Box::new(filter(right, ctx)),
+                ),
+                Expression::BitwiseOr(loc, ty, left, right) => Expression::BitwiseOr(
+                    *loc,
+                    ty.clone(),
+                    Box::new(filter(left, ctx)),
+                    Box::new(filter(right, ctx)),
+                ),
+                Expression::BitwiseAnd(loc, ty, left, right) => Expression::BitwiseAnd(
+                    *loc,
+                    ty.clone(),
+                    Box::new(filter(left, ctx)),
+                    Box::new(filter(right, ctx)),
+                ),
+                Expression::BitwiseXor(loc, ty, left, right) => Expression::BitwiseXor(
+                    *loc,
+                    ty.clone(),
+                    Box::new(filter(left, ctx)),
+                    Box::new(filter(right, ctx)),
+                ),
+                Expression::ShiftLeft(loc, ty, left, right) => Expression::ShiftLeft(
+                    *loc,
+                    ty.clone(),
+                    Box::new(filter(left, ctx)),
+                    Box::new(filter(right, ctx)),
+                ),
+                Expression::ShiftRight(loc, ty, left, right, sign_extend) => {
+                    Expression::ShiftRight(
+                        *loc,
+                        ty.clone(),
+                        Box::new(filter(left, ctx)),
+                        Box::new(filter(right, ctx)),
+                        *sign_extend,
+                    )
+                }
+                Expression::Load(loc, ty, expr) => {
+                    Expression::Load(*loc, ty.clone(), Box::new(filter(expr, ctx)))
+                }
+                Expression::ZeroExt(loc, ty, expr) => {
+                    Expression::ZeroExt(*loc, ty.clone(), Box::new(filter(expr, ctx)))
+                }
+                Expression::SignExt(loc, ty, expr) => {
+                    Expression::SignExt(*loc, ty.clone(), Box::new(filter(expr, ctx)))
+                }
+                Expression::Trunc(loc, ty, expr) => {
+                    Expression::Trunc(*loc, ty.clone(), Box::new(filter(expr, ctx)))
+                }
+                Expression::Cast(loc, ty, expr) => {
+                    Expression::Cast(*loc, ty.clone(), Box::new(filter(expr, ctx)))
+                }
+                Expression::BytesCast(loc, ty, from, expr) => Expression::BytesCast(
+                    *loc,
+                    ty.clone(),
+                    from.clone(),
+                    Box::new(filter(expr, ctx)),
+                ),
+                Expression::More(loc, left, right) => Expression::More(
+                    *loc,
+                    Box::new(filter(left, ctx)),
+                    Box::new(filter(right, ctx)),
+                ),
+                Expression::Less(loc, left, right) => Expression::Less(
+                    *loc,
+                    Box::new(filter(left, ctx)),
+                    Box::new(filter(right, ctx)),
+                ),
+                Expression::MoreEqual(loc, left, right) => Expression::MoreEqual(
+                    *loc,
+                    Box::new(filter(left, ctx)),
+                    Box::new(filter(right, ctx)),
+                ),
+                Expression::LessEqual(loc, left, right) => Expression::LessEqual(
+                    *loc,
+                    Box::new(filter(left, ctx)),
+                    Box::new(filter(right, ctx)),
+                ),
+                Expression::Equal(loc, left, right) => Expression::Equal(
+                    *loc,
+                    Box::new(filter(left, ctx)),
+                    Box::new(filter(right, ctx)),
+                ),
+                Expression::NotEqual(loc, left, right) => Expression::NotEqual(
+                    *loc,
+                    Box::new(filter(left, ctx)),
+                    Box::new(filter(right, ctx)),
+                ),
+                Expression::Not(loc, expr) => Expression::Not(*loc, Box::new(filter(expr, ctx))),
+                Expression::Complement(loc, ty, expr) => {
+                    Expression::Complement(*loc, ty.clone(), Box::new(filter(expr, ctx)))
+                }
+                Expression::UnaryMinus(loc, ty, expr) => {
+                    Expression::UnaryMinus(*loc, ty.clone(), Box::new(filter(expr, ctx)))
+                }
+                Expression::Subscript(loc, elem_ty, array_ty, left, right) => {
+                    Expression::Subscript(
+                        *loc,
+                        elem_ty.clone(),
+                        array_ty.clone(),
+                        Box::new(filter(left, ctx)),
+                        Box::new(filter(right, ctx)),
+                    )
+                }
+                Expression::StructMember(loc, ty, expr, field) => {
+                    Expression::StructMember(*loc, ty.clone(), Box::new(filter(expr, ctx)), *field)
+                }
+                Expression::AllocDynamicArray(loc, ty, expr, initializer) => {
+                    Expression::AllocDynamicArray(
+                        *loc,
+                        ty.clone(),
+                        Box::new(filter(expr, ctx)),
+                        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,
+                    match left {
+                        StringLocation::CompileTime(_) => left.clone(),
+                        StringLocation::RunTime(expr) => {
+                            StringLocation::RunTime(Box::new(filter(expr, ctx)))
+                        }
+                    },
+                    match right {
+                        StringLocation::CompileTime(_) => right.clone(),
+                        StringLocation::RunTime(expr) => {
+                            StringLocation::RunTime(Box::new(filter(expr, ctx)))
+                        }
+                    },
+                ),
+                Expression::StringConcat(loc, ty, left, right) => Expression::StringConcat(
+                    *loc,
+                    ty.clone(),
+                    match left {
+                        StringLocation::CompileTime(_) => left.clone(),
+                        StringLocation::RunTime(expr) => {
+                            StringLocation::RunTime(Box::new(filter(expr, ctx)))
+                        }
+                    },
+                    match right {
+                        StringLocation::CompileTime(_) => right.clone(),
+                        StringLocation::RunTime(expr) => {
+                            StringLocation::RunTime(Box::new(filter(expr, ctx)))
+                        }
+                    },
+                ),
+                Expression::ExternalFunction {
+                    loc,
+                    ty,
+                    address,
+                    function_no,
+                } => Expression::ExternalFunction {
+                    loc: *loc,
+                    ty: ty.clone(),
+                    address: Box::new(filter(address, ctx)),
+                    function_no: *function_no,
+                },
+                Expression::FormatString(loc, args) => {
+                    let args = args.iter().map(|(f, e)| (*f, filter(e, ctx))).collect();
+
+                    Expression::FormatString(*loc, args)
+                }
+                Expression::Builtin(loc, tys, builtin, args) => {
+                    let args = args.iter().map(|e| filter(e, ctx)).collect();
+
+                    Expression::Builtin(*loc, tys.clone(), *builtin, args)
+                }
+                _ => self.clone(),
+            },
+            ctx,
+        )
+    }
+}

+ 1 - 1
src/codegen/reaching_definitions.rs

@@ -1,5 +1,5 @@
 use super::cfg::{BasicBlock, ControlFlowGraph, Instr};
 use super::cfg::{BasicBlock, ControlFlowGraph, Instr};
-use crate::sema::ast::Expression;
+use crate::codegen::Expression;
 use indexmap::IndexMap;
 use indexmap::IndexMap;
 use std::collections::HashSet;
 use std::collections::HashSet;
 use std::fmt;
 use std::fmt;

+ 83 - 55
src/codegen/statements.rs

@@ -7,16 +7,18 @@ use super::{
     cfg::{ControlFlowGraph, Instr},
     cfg::{ControlFlowGraph, Instr},
     vartable::Vartable,
     vartable::Vartable,
 };
 };
+use crate::ast;
 use crate::codegen::unused_variable::{
 use crate::codegen::unused_variable::{
     should_remove_assignment, should_remove_variable, SideEffectsCheckParameters,
     should_remove_assignment, should_remove_variable, SideEffectsCheckParameters,
 };
 };
+use crate::codegen::Expression;
 use crate::parser::pt;
 use crate::parser::pt;
 use crate::parser::pt::CodeLocation;
 use crate::parser::pt::CodeLocation;
+use crate::sema::ast::RetrieveType;
 use crate::sema::ast::{
 use crate::sema::ast::{
-    Builtin, CallTy, DestructureField, Expression, Function, Namespace, Parameter, Statement,
-    TryCatch, Type,
+    Builtin, CallTy, DestructureField, Function, Namespace, Parameter, Statement, TryCatch, Type,
 };
 };
-use crate::sema::expression::cast;
+use crate::sema::Recurse;
 use num_traits::Zero;
 use num_traits::Zero;
 use tiny_keccak::{Hasher, Keccak};
 use tiny_keccak::{Hasher, Keccak};
 
 
@@ -102,7 +104,7 @@ pub fn statement(
             }
             }
         }
         }
         Statement::Expression(_, reachable, expr) => {
         Statement::Expression(_, reachable, expr) => {
-            if let Expression::Assign(_, _, left, right) = &expr {
+            if let ast::Expression::Assign(_, _, left, right) = &expr {
                 if should_remove_assignment(ns, left, func, opt) {
                 if should_remove_assignment(ns, left, func, opt) {
                     let mut params = SideEffectsCheckParameters {
                     let mut params = SideEffectsCheckParameters {
                         cfg,
                         cfg,
@@ -542,7 +544,7 @@ pub fn statement(
                     match ty {
                     match ty {
                         Type::String | Type::DynamicBytes => {
                         Type::String | Type::DynamicBytes => {
                             let e = expression(
                             let e = expression(
-                                &Expression::Builtin(
+                                &ast::Expression::Builtin(
                                     pt::Loc::Codegen,
                                     pt::Loc::Codegen,
                                     vec![Type::Bytes(32)],
                                     vec![Type::Bytes(32)],
                                     Builtin::Keccak256,
                                     Builtin::Keccak256,
@@ -562,11 +564,11 @@ pub fn statement(
                         Type::Struct(_) | Type::Array(..) => {
                         Type::Struct(_) | Type::Array(..) => {
                             // We should have an AbiEncodePackedPad
                             // We should have an AbiEncodePackedPad
                             let e = expression(
                             let e = expression(
-                                &Expression::Builtin(
+                                &ast::Expression::Builtin(
                                     pt::Loc::Codegen,
                                     pt::Loc::Codegen,
                                     vec![Type::Bytes(32)],
                                     vec![Type::Bytes(32)],
                                     Builtin::Keccak256,
                                     Builtin::Keccak256,
-                                    vec![Expression::Builtin(
+                                    vec![ast::Expression::Builtin(
                                         pt::Loc::Codegen,
                                         pt::Loc::Codegen,
                                         vec![Type::DynamicBytes],
                                         vec![Type::DynamicBytes],
                                         Builtin::AbiEncodePacked,
                                         Builtin::AbiEncodePacked,
@@ -631,7 +633,7 @@ pub fn statement(
 
 
 /// Generate if-then-no-else
 /// Generate if-then-no-else
 fn if_then(
 fn if_then(
-    cond: &Expression,
+    cond: &ast::Expression,
     then_stmt: &[Statement],
     then_stmt: &[Statement],
     func: &Function,
     func: &Function,
     cfg: &mut ControlFlowGraph,
     cfg: &mut ControlFlowGraph,
@@ -691,7 +693,7 @@ fn if_then(
 
 
 /// Generate if-then-else
 /// Generate if-then-else
 fn if_then_else(
 fn if_then_else(
-    cond: &Expression,
+    cond: &ast::Expression,
     then_stmt: &[Statement],
     then_stmt: &[Statement],
     else_stmt: &[Statement],
     else_stmt: &[Statement],
     func: &Function,
     func: &Function,
@@ -779,7 +781,7 @@ fn if_then_else(
 }
 }
 
 
 fn returns(
 fn returns(
-    expr: &Expression,
+    expr: &ast::Expression,
     cfg: &mut ControlFlowGraph,
     cfg: &mut ControlFlowGraph,
     contract_no: usize,
     contract_no: usize,
     func: &Function,
     func: &Function,
@@ -791,7 +793,7 @@ fn returns(
     let uncast_values = match expr {
     let uncast_values = match expr {
         // Explicitly recurse for ternary expressions.
         // Explicitly recurse for ternary expressions.
         // `return a ? b : c` is transformed into pseudo code `a ? return b : return c`
         // `return a ? b : c` is transformed into pseudo code `a ? return b : return c`
-        Expression::Ternary(_, _, cond, left, right) => {
+        ast::Expression::Ternary(_, _, cond, left, right) => {
             let cond = expression(cond, cfg, contract_no, Some(func), ns, vartab, opt);
             let cond = expression(cond, cfg, contract_no, Some(func), ns, vartab, opt);
 
 
             let left_block = cfg.new_basic_block("left".to_string());
             let left_block = cfg.new_basic_block("left".to_string());
@@ -817,18 +819,29 @@ fn returns(
             return;
             return;
         }
         }
 
 
-        Expression::Builtin(_, _, Builtin::AbiDecode, _)
-        | Expression::InternalFunctionCall { .. }
-        | Expression::ExternalFunctionCall { .. }
-        | Expression::ExternalFunctionCallRaw { .. } => {
+        ast::Expression::Builtin(_, _, Builtin::AbiDecode, _)
+        | ast::Expression::InternalFunctionCall { .. }
+        | ast::Expression::ExternalFunctionCall { .. }
+        | ast::Expression::ExternalFunctionCallRaw { .. } => {
             emit_function_call(expr, contract_no, cfg, Some(func), ns, vartab, opt)
             emit_function_call(expr, contract_no, cfg, Some(func), ns, vartab, opt)
         }
         }
 
 
-        Expression::List(_, exprs) => exprs.clone(),
+        ast::Expression::List(_, exprs) => exprs
+            .iter()
+            .map(|e| expression(e, cfg, contract_no, Some(func), ns, vartab, opt))
+            .collect::<Vec<Expression>>(),
 
 
         // Can be any other expression
         // Can be any other expression
         _ => {
         _ => {
-            vec![expr.clone()]
+            vec![expression(
+                expr,
+                cfg,
+                contract_no,
+                Some(func),
+                ns,
+                vartab,
+                opt,
+            )]
         }
         }
     };
     };
 
 
@@ -836,12 +849,7 @@ fn returns(
         .returns
         .returns
         .iter()
         .iter()
         .zip(uncast_values.into_iter())
         .zip(uncast_values.into_iter())
-        .map(|(left, right)| {
-            let right = cast(&left.loc, right, &left.ty, true, ns, &mut Vec::new())
-                .expect("sema should have checked cast");
-            // casts to StorageLoad generate LoadStorage instructions
-            expression(&right, cfg, contract_no, Some(func), ns, vartab, opt)
-        })
+        .map(|(left, right)| destructure_load(&right.loc(), &right.cast(&left.ty, ns), cfg, vartab))
         .collect();
         .collect();
 
 
     cfg.add(vartab, Instr::Return { value: cast_values });
     cfg.add(vartab, Instr::Return { value: cast_values });
@@ -849,7 +857,7 @@ fn returns(
 
 
 fn destructure(
 fn destructure(
     fields: &[DestructureField],
     fields: &[DestructureField],
-    expr: &Expression,
+    expr: &ast::Expression,
     cfg: &mut ControlFlowGraph,
     cfg: &mut ControlFlowGraph,
     contract_no: usize,
     contract_no: usize,
     func: &Function,
     func: &Function,
@@ -857,7 +865,7 @@ fn destructure(
     vartab: &mut Vartable,
     vartab: &mut Vartable,
     opt: &Options,
     opt: &Options,
 ) {
 ) {
-    if let Expression::Ternary(_, _, cond, left, right) = expr {
+    if let ast::Expression::Ternary(_, _, cond, left, right) = expr {
         let cond = expression(cond, cfg, contract_no, Some(func), ns, vartab, opt);
         let cond = expression(cond, cfg, contract_no, Some(func), ns, vartab, opt);
 
 
         let left_block = cfg.new_basic_block("left".to_string());
         let left_block = cfg.new_basic_block("left".to_string());
@@ -895,7 +903,7 @@ fn destructure(
     }
     }
 
 
     let mut values = match expr {
     let mut values = match expr {
-        Expression::List(_, exprs) => {
+        ast::Expression::List(_, exprs) => {
             let mut values = Vec::new();
             let mut values = Vec::new();
 
 
             for expr in exprs {
             for expr in exprs {
@@ -926,11 +934,7 @@ fn destructure(
                 // nothing to do
                 // nothing to do
             }
             }
             DestructureField::VariableDecl(res, param) => {
             DestructureField::VariableDecl(res, param) => {
-                // the resolver did not cast the expression
-                let expr = cast(&param.loc, right, &param.ty, true, ns, &mut Vec::new())
-                    .expect("sema should have checked cast");
-                // casts to StorageLoad generate LoadStorage instructions
-                let expr = expression(&expr, cfg, contract_no, Some(func), ns, vartab, opt);
+                let expr = destructure_load(&param.loc, &right.cast(&param.ty, ns), cfg, vartab);
 
 
                 if should_remove_variable(res, func, opt) {
                 if should_remove_variable(res, func, opt) {
                     continue;
                     continue;
@@ -946,31 +950,55 @@ fn destructure(
                 );
                 );
             }
             }
             DestructureField::Expression(left) => {
             DestructureField::Expression(left) => {
-                // the resolver did not cast the expression
-                let loc = left.loc();
-
-                let expr = cast(
-                    &loc,
-                    right,
-                    left.ty().deref_any(),
-                    true,
-                    ns,
-                    &mut Vec::new(),
-                )
-                .expect("sema should have checked cast");
-                // casts to StorageLoad generate LoadStorage instructions
-                let expr = expression(&expr, cfg, contract_no, Some(func), ns, vartab, opt);
+                let expr = destructure_load(
+                    &left.loc(),
+                    &right.cast(left.ty().deref_any(), ns),
+                    cfg,
+                    vartab,
+                );
 
 
                 if should_remove_assignment(ns, left, func, opt) {
                 if should_remove_assignment(ns, left, func, opt) {
                     continue;
                     continue;
                 }
                 }
 
 
-                assign_single(left, &expr, cfg, contract_no, Some(func), ns, vartab, opt);
+                assign_single(left, expr, cfg, contract_no, Some(func), ns, vartab, opt);
             }
             }
         }
         }
     }
     }
 }
 }
 
 
+/// During a destructure statement, sema only checks if the cast is possible. During codegen, we
+/// perform the cast to a StorageRef if that is the case. The cast function, however, does not add
+/// instructions to the CFG. Here, we add a load instruction to fetch the variables from storage.
+fn destructure_load(
+    loc: &pt::Loc,
+    expr: &Expression,
+    cfg: &mut ControlFlowGraph,
+    vartab: &mut Vartable,
+) -> Expression {
+    if let Type::StorageRef(_, ty) = expr.ty() {
+        if let Expression::Subscript(_, _, ty, ..) = &expr {
+            if ty.is_storage_bytes() {
+                return expr.clone();
+            }
+        }
+
+        let anonymous_no = vartab.temp_anonymous(&*ty);
+        cfg.add(
+            vartab,
+            Instr::LoadStorage {
+                res: anonymous_no,
+                ty: (*ty).clone(),
+                storage: expr.clone(),
+            },
+        );
+
+        return Expression::Variable(*loc, (*ty).clone(), anonymous_no);
+    }
+
+    expr.clone()
+}
+
 /// Resolve try catch statement
 /// Resolve try catch statement
 fn try_catch(
 fn try_catch(
     try_stmt: &TryCatch,
     try_stmt: &TryCatch,
@@ -997,7 +1025,7 @@ fn try_catch(
     let finally_block = cfg.new_basic_block("finally".to_string());
     let finally_block = cfg.new_basic_block("finally".to_string());
 
 
     match &try_stmt.expr {
     match &try_stmt.expr {
-        Expression::ExternalFunctionCall {
+        ast::Expression::ExternalFunctionCall {
             loc,
             loc,
             function,
             function,
             args,
             args,
@@ -1121,7 +1149,7 @@ fn try_catch(
                 unimplemented!();
                 unimplemented!();
             }
             }
         }
         }
-        Expression::Constructor {
+        ast::Expression::Constructor {
             contract_no,
             contract_no,
             constructor_no,
             constructor_no,
             args,
             args,
@@ -1463,15 +1491,15 @@ impl Namespace {
 /// processes them.
 /// processes them.
 /// They must be added to the cfg event if we remove the assignment
 /// They must be added to the cfg event if we remove the assignment
 pub fn process_side_effects_expressions(
 pub fn process_side_effects_expressions(
-    exp: &Expression,
+    exp: &ast::Expression,
     ctx: &mut SideEffectsCheckParameters,
     ctx: &mut SideEffectsCheckParameters,
 ) -> bool {
 ) -> bool {
     match &exp {
     match &exp {
-        Expression::InternalFunctionCall { .. }
-        | Expression::ExternalFunctionCall { .. }
-        | Expression::ExternalFunctionCallRaw { .. }
-        | Expression::Constructor { .. }
-        | Expression::Assign(..) => {
+        ast::Expression::InternalFunctionCall { .. }
+        | ast::Expression::ExternalFunctionCall { .. }
+        | ast::Expression::ExternalFunctionCallRaw { .. }
+        | ast::Expression::Constructor { .. }
+        | ast::Expression::Assign(..) => {
             let _ = expression(
             let _ = expression(
                 exp,
                 exp,
                 ctx.cfg,
                 ctx.cfg,
@@ -1484,7 +1512,7 @@ pub fn process_side_effects_expressions(
             false
             false
         }
         }
 
 
-        Expression::Builtin(_, _, builtin_type, _) => match &builtin_type {
+        ast::Expression::Builtin(_, _, builtin_type, _) => match &builtin_type {
             Builtin::PayableSend
             Builtin::PayableSend
             | Builtin::ArrayPush
             | Builtin::ArrayPush
             | Builtin::ArrayPop
             | Builtin::ArrayPop

+ 10 - 8
src/codegen/storage.rs

@@ -1,3 +1,5 @@
+use crate::ast;
+use crate::codegen::Expression;
 use num_bigint::BigInt;
 use num_bigint::BigInt;
 use num_traits::FromPrimitive;
 use num_traits::FromPrimitive;
 use num_traits::One;
 use num_traits::One;
@@ -10,7 +12,8 @@ use super::{
     vartable::Vartable,
     vartable::Vartable,
 };
 };
 use crate::parser::pt;
 use crate::parser::pt;
-use crate::sema::ast::{Expression, Function, Namespace, Type};
+use crate::sema::ast::RetrieveType;
+use crate::sema::ast::{Function, Namespace, Type};
 
 
 /// Given a storage slot which is the start of the array, calculate the
 /// Given a storage slot which is the start of the array, calculate the
 /// offset of the array element. This function exists to avoid doing
 /// offset of the array element. This function exists to avoid doing
@@ -67,7 +70,7 @@ pub fn array_offset(
 /// Push() method on dynamic array in storage
 /// Push() method on dynamic array in storage
 pub fn storage_slots_array_push(
 pub fn storage_slots_array_push(
     loc: &pt::Loc,
     loc: &pt::Loc,
-    args: &[Expression],
+    args: &[ast::Expression],
     cfg: &mut ControlFlowGraph,
     cfg: &mut ControlFlowGraph,
     contract_no: usize,
     contract_no: usize,
     func: Option<&Function>,
     func: Option<&Function>,
@@ -81,7 +84,7 @@ pub fn storage_slots_array_push(
 
 
     let var_expr = expression(&args[0], cfg, contract_no, func, ns, vartab, opt);
     let var_expr = expression(&args[0], cfg, contract_no, func, ns, vartab, opt);
 
 
-    let expr = load_storage(loc, &slot_ty, var_expr.clone(), cfg, vartab, opt);
+    let expr = load_storage(loc, &slot_ty, var_expr.clone(), cfg, vartab);
 
 
     cfg.add(
     cfg.add(
         vartab,
         vartab,
@@ -156,7 +159,7 @@ pub fn storage_slots_array_push(
 /// Pop() method on dynamic array in storage
 /// Pop() method on dynamic array in storage
 pub fn storage_slots_array_pop(
 pub fn storage_slots_array_pop(
     loc: &pt::Loc,
     loc: &pt::Loc,
-    args: &[Expression],
+    args: &[ast::Expression],
     return_ty: &Type,
     return_ty: &Type,
     cfg: &mut ControlFlowGraph,
     cfg: &mut ControlFlowGraph,
     contract_no: usize,
     contract_no: usize,
@@ -173,7 +176,7 @@ pub fn storage_slots_array_pop(
     let ty = args[0].ty();
     let ty = args[0].ty();
     let var_expr = expression(&args[0], cfg, contract_no, func, ns, vartab, opt);
     let var_expr = expression(&args[0], cfg, contract_no, func, ns, vartab, opt);
 
 
-    let expr = load_storage(loc, &length_ty, var_expr.clone(), cfg, vartab, opt);
+    let expr = load_storage(loc, &length_ty, var_expr.clone(), cfg, vartab);
 
 
     cfg.add(
     cfg.add(
         vartab,
         vartab,
@@ -254,7 +257,6 @@ pub fn storage_slots_array_pop(
             Expression::Variable(*loc, elem_ty.clone(), entry_pos),
             Expression::Variable(*loc, elem_ty.clone(), entry_pos),
             cfg,
             cfg,
             vartab,
             vartab,
-            opt,
         );
         );
 
 
         cfg.add(
         cfg.add(
@@ -294,7 +296,7 @@ pub fn storage_slots_array_pop(
 /// Push() method on array or bytes in storage
 /// Push() method on array or bytes in storage
 pub fn array_push(
 pub fn array_push(
     loc: &pt::Loc,
     loc: &pt::Loc,
-    args: &[Expression],
+    args: &[ast::Expression],
     cfg: &mut ControlFlowGraph,
     cfg: &mut ControlFlowGraph,
     contract_no: usize,
     contract_no: usize,
     func: Option<&Function>,
     func: Option<&Function>,
@@ -342,7 +344,7 @@ pub fn array_push(
 /// Pop() method on array or bytes in storage
 /// Pop() method on array or bytes in storage
 pub fn array_pop(
 pub fn array_pop(
     loc: &pt::Loc,
     loc: &pt::Loc,
-    args: &[Expression],
+    args: &[ast::Expression],
     return_ty: &Type,
     return_ty: &Type,
     cfg: &mut ControlFlowGraph,
     cfg: &mut ControlFlowGraph,
     contract_no: usize,
     contract_no: usize,

+ 15 - 260
src/codegen/strength_reduce.rs

@@ -1,6 +1,7 @@
 use super::cfg::{ControlFlowGraph, Instr};
 use super::cfg::{ControlFlowGraph, Instr};
-use crate::sema::ast::{Expression, Namespace, Type};
-use crate::sema::expression::cast;
+use crate::codegen::Expression;
+use crate::sema::ast::RetrieveType;
+use crate::sema::ast::{Namespace, Type};
 use bitvec::prelude::*;
 use bitvec::prelude::*;
 use itertools::Itertools;
 use itertools::Itertools;
 use num_bigint::{BigInt, Sign};
 use num_bigint::{BigInt, Sign};
@@ -205,7 +206,6 @@ fn expression_reduce(expr: &Expression, vars: &Variables, ns: &mut Namespace) ->
         match expr {
         match expr {
             Expression::Multiply(loc, ty, unchecked, left, right) => {
             Expression::Multiply(loc, ty, unchecked, left, right) => {
                 let bits = ty.bits(ns) as usize;
                 let bits = ty.bits(ns) as usize;
-
                 if bits >= 128 {
                 if bits >= 128 {
                     let left_values = expression_values(left, vars, ns);
                     let left_values = expression_values(left, vars, ns);
                     let right_values = expression_values(right, vars, ns);
                     let right_values = expression_values(right, vars, ns);
@@ -261,28 +261,8 @@ fn expression_reduce(expr: &Expression, vars: &Variables, ns: &mut Namespace) ->
                                         *loc,
                                         *loc,
                                         Type::Int(64),
                                         Type::Int(64),
                                         *unchecked,
                                         *unchecked,
-                                        Box::new(
-                                            cast(
-                                                loc,
-                                                left.as_ref().clone(),
-                                                &Type::Int(64),
-                                                false,
-                                                ns,
-                                                &mut Vec::new(),
-                                            )
-                                            .unwrap(),
-                                        ),
-                                        Box::new(
-                                            cast(
-                                                loc,
-                                                right.as_ref().clone(),
-                                                &Type::Int(64),
-                                                false,
-                                                ns,
-                                                &mut Vec::new(),
-                                            )
-                                            .unwrap(),
-                                        ),
+                                        Box::new(left.as_ref().clone().cast(&Type::Int(64), ns)),
+                                        Box::new(right.as_ref().clone().cast(&Type::Int(64), ns)),
                                     )),
                                     )),
                                 );
                                 );
                             }
                             }
@@ -308,28 +288,8 @@ fn expression_reduce(expr: &Expression, vars: &Variables, ns: &mut Namespace) ->
                                     *loc,
                                     *loc,
                                     Type::Uint(64),
                                     Type::Uint(64),
                                     *unchecked,
                                     *unchecked,
-                                    Box::new(
-                                        cast(
-                                            loc,
-                                            left.as_ref().clone(),
-                                            &Type::Uint(64),
-                                            false,
-                                            ns,
-                                            &mut Vec::new(),
-                                        )
-                                        .unwrap(),
-                                    ),
-                                    Box::new(
-                                        cast(
-                                            loc,
-                                            right.as_ref().clone(),
-                                            &Type::Uint(64),
-                                            false,
-                                            ns,
-                                            &mut Vec::new(),
-                                        )
-                                        .unwrap(),
-                                    ),
+                                    Box::new(left.as_ref().clone().cast(&Type::Uint(64), ns)),
+                                    Box::new(right.as_ref().clone().cast(&Type::Uint(64), ns)),
                                 )),
                                 )),
                             );
                             );
                         }
                         }
@@ -395,28 +355,8 @@ fn expression_reduce(expr: &Expression, vars: &Variables, ns: &mut Namespace) ->
                                     Box::new(Expression::Divide(
                                     Box::new(Expression::Divide(
                                         *loc,
                                         *loc,
                                         Type::Int(64),
                                         Type::Int(64),
-                                        Box::new(
-                                            cast(
-                                                loc,
-                                                left.as_ref().clone(),
-                                                &Type::Int(64),
-                                                false,
-                                                ns,
-                                                &mut Vec::new(),
-                                            )
-                                            .unwrap(),
-                                        ),
-                                        Box::new(
-                                            cast(
-                                                loc,
-                                                right.as_ref().clone(),
-                                                &Type::Int(64),
-                                                false,
-                                                ns,
-                                                &mut Vec::new(),
-                                            )
-                                            .unwrap(),
-                                        ),
+                                        Box::new(left.as_ref().clone().cast(&Type::Int(64), ns)),
+                                        Box::new(right.as_ref().clone().cast(&Type::Int(64), ns)),
                                     )),
                                     )),
                                 );
                                 );
                             }
                             }
@@ -438,28 +378,8 @@ fn expression_reduce(expr: &Expression, vars: &Variables, ns: &mut Namespace) ->
                                 Box::new(Expression::Divide(
                                 Box::new(Expression::Divide(
                                     *loc,
                                     *loc,
                                     Type::Uint(64),
                                     Type::Uint(64),
-                                    Box::new(
-                                        cast(
-                                            loc,
-                                            left.as_ref().clone(),
-                                            &Type::Uint(64),
-                                            false,
-                                            ns,
-                                            &mut Vec::new(),
-                                        )
-                                        .unwrap(),
-                                    ),
-                                    Box::new(
-                                        cast(
-                                            loc,
-                                            right.as_ref().clone(),
-                                            &Type::Uint(64),
-                                            false,
-                                            ns,
-                                            &mut Vec::new(),
-                                        )
-                                        .unwrap(),
-                                    ),
+                                    Box::new(left.as_ref().clone().cast(&Type::Uint(64), ns)),
+                                    Box::new(right.as_ref().clone().cast(&Type::Uint(64), ns)),
                                 )),
                                 )),
                             );
                             );
                         }
                         }
@@ -523,28 +443,8 @@ fn expression_reduce(expr: &Expression, vars: &Variables, ns: &mut Namespace) ->
                                     Box::new(Expression::Modulo(
                                     Box::new(Expression::Modulo(
                                         *loc,
                                         *loc,
                                         Type::Int(64),
                                         Type::Int(64),
-                                        Box::new(
-                                            cast(
-                                                loc,
-                                                left.as_ref().clone(),
-                                                &Type::Int(64),
-                                                false,
-                                                ns,
-                                                &mut Vec::new(),
-                                            )
-                                            .unwrap(),
-                                        ),
-                                        Box::new(
-                                            cast(
-                                                loc,
-                                                right.as_ref().clone(),
-                                                &Type::Int(64),
-                                                false,
-                                                ns,
-                                                &mut Vec::new(),
-                                            )
-                                            .unwrap(),
-                                        ),
+                                        Box::new(left.as_ref().clone().cast(&Type::Int(64), ns)),
+                                        Box::new(right.as_ref().clone().cast(&Type::Int(64), ns)),
                                     )),
                                     )),
                                 );
                                 );
                             }
                             }
@@ -566,28 +466,8 @@ fn expression_reduce(expr: &Expression, vars: &Variables, ns: &mut Namespace) ->
                                 Box::new(Expression::Modulo(
                                 Box::new(Expression::Modulo(
                                     *loc,
                                     *loc,
                                     Type::Uint(64),
                                     Type::Uint(64),
-                                    Box::new(
-                                        cast(
-                                            loc,
-                                            left.as_ref().clone(),
-                                            &Type::Uint(64),
-                                            false,
-                                            ns,
-                                            &mut Vec::new(),
-                                        )
-                                        .unwrap(),
-                                    ),
-                                    Box::new(
-                                        cast(
-                                            loc,
-                                            right.as_ref().clone(),
-                                            &Type::Uint(64),
-                                            false,
-                                            ns,
-                                            &mut Vec::new(),
-                                        )
-                                        .unwrap(),
-                                    ),
+                                    Box::new(left.as_ref().clone().cast(&Type::Uint(64), ns)),
+                                    Box::new(right.as_ref().clone().cast(&Type::Uint(64), ns)),
                                 )),
                                 )),
                             );
                             );
                         }
                         }
@@ -1617,57 +1497,6 @@ fn expression_values(expr: &Expression, vars: &Variables, ns: &Namespace) -> Has
                 })
                 })
                 .collect()
                 .collect()
         }
         }
-        Expression::Or(_, left, right) => {
-            let left = expression_values(left, vars, ns);
-            let right = expression_values(right, vars, ns);
-
-            left.iter()
-                .cartesian_product(right.iter())
-                .map(|(l, r)| {
-                    let mut known_bits = BitArray::new([0u8; 32]);
-                    let mut value = BitArray::new([0u8; 32]);
-
-                    if l.known_bits[0] && r.known_bits[0] {
-                        known_bits.set(0, true);
-                        value.set(0, l.value[0] || r.value[0]);
-                    } else if (l.known_bits[0] && l.value[0]) || (r.known_bits[0] && r.value[0]) {
-                        known_bits.set(0, true);
-                        value.set(0, true);
-                    }
-
-                    Value {
-                        value,
-                        known_bits,
-                        bits: 1,
-                    }
-                })
-                .collect()
-        }
-        Expression::And(_, left, right) => {
-            let left = expression_values(left, vars, ns);
-            let right = expression_values(right, vars, ns);
-
-            left.iter()
-                .cartesian_product(right.iter())
-                .map(|(l, r)| {
-                    let mut known_bits = BitArray::new([0u8; 32]);
-                    let mut value = BitArray::new([0u8; 32]);
-
-                    if l.known_bits[0] && r.known_bits[0] {
-                        known_bits.set(0, true);
-                        value.set(0, l.value[0] && r.value[0]);
-                    } else if (l.known_bits[0] && !l.value[0]) || (r.known_bits[0] && !r.value[0]) {
-                        known_bits.set(0, true);
-                    }
-
-                    Value {
-                        value,
-                        known_bits,
-                        bits: 1,
-                    }
-                })
-                .collect()
-        }
         Expression::Complement(_, _, expr) => {
         Expression::Complement(_, _, expr) => {
             let vals = expression_values(expr, vars, ns);
             let vals = expression_values(expr, vars, ns);
 
 
@@ -2628,78 +2457,4 @@ fn expresson_known_bits() {
 
 
     assert!(v.known_bits[0]);
     assert!(v.known_bits[0]);
     assert!(v.value[0]);
     assert!(v.value[0]);
-
-    /////////////
-    // test: or
-    /////////////
-    let vars = HashMap::new();
-
-    // true or unknown => true
-    let res = expression_values(
-        &Expression::Or(
-            loc,
-            Box::new(Expression::BoolLiteral(loc, true)),
-            Box::new(Expression::FunctionArg(loc, Type::Bool, 0)),
-        ),
-        &vars,
-        &ns,
-    );
-
-    assert_eq!(res.len(), 1);
-    let v = res.iter().next().unwrap();
-
-    assert!(v.known_bits[0]);
-    assert!(v.value[0]);
-
-    // false or unknown => unknown
-    let res = expression_values(
-        &Expression::Or(
-            loc,
-            Box::new(Expression::BoolLiteral(loc, false)),
-            Box::new(Expression::FunctionArg(loc, Type::Bool, 0)),
-        ),
-        &vars,
-        &ns,
-    );
-
-    assert_eq!(res.len(), 1);
-    let v = res.iter().next().unwrap();
-
-    assert!(!v.known_bits[0]);
-
-    /////////////
-    // test: and
-    /////////////
-    let vars = HashMap::new();
-
-    // true and unknown => unknown
-    let res = expression_values(
-        &Expression::And(
-            loc,
-            Box::new(Expression::BoolLiteral(loc, true)),
-            Box::new(Expression::FunctionArg(loc, Type::Bool, 0)),
-        ),
-        &vars,
-        &ns,
-    );
-
-    assert_eq!(res.len(), 1);
-    let v = res.iter().next().unwrap();
-    assert!(!v.known_bits[0]);
-
-    // false and unknown => false
-    let res = expression_values(
-        &Expression::And(
-            loc,
-            Box::new(Expression::BoolLiteral(loc, false)),
-            Box::new(Expression::FunctionArg(loc, Type::Bool, 0)),
-        ),
-        &vars,
-        &ns,
-    );
-
-    assert_eq!(res.len(), 1);
-    let v = res.iter().next().unwrap();
-    assert!(v.known_bits[0]);
-    assert!(!v.value[0]);
 }
 }

+ 1 - 1
src/codegen/subexpression_elimination/available_expression.rs

@@ -2,7 +2,7 @@ use crate::codegen::subexpression_elimination::{
     AvailableExpression, AvailableExpressionSet, AvailableVariable, BasicExpression,
     AvailableExpression, AvailableExpressionSet, AvailableVariable, BasicExpression,
     ExpressionType, NodeId,
     ExpressionType, NodeId,
 };
 };
-use crate::sema::ast::Expression;
+use crate::codegen::Expression;
 use std::cell::RefCell;
 use std::cell::RefCell;
 use std::rc::Rc;
 use std::rc::Rc;
 
 

+ 7 - 6
src/codegen/subexpression_elimination/available_expression_set.rs

@@ -4,7 +4,8 @@ use crate::codegen::subexpression_elimination::AvailableExpression;
 use crate::codegen::subexpression_elimination::{
 use crate::codegen::subexpression_elimination::{
     AvailableExpressionSet, BasicExpression, ExpressionType, NodeId,
     AvailableExpressionSet, BasicExpression, ExpressionType, NodeId,
 };
 };
-use crate::sema::ast::{Expression, StringLocation};
+use crate::codegen::Expression;
+use crate::sema::ast::StringLocation;
 use std::cell::RefCell;
 use std::cell::RefCell;
 use std::collections::{HashMap, HashSet};
 use std::collections::{HashMap, HashSet};
 use std::rc::Rc;
 use std::rc::Rc;
@@ -193,8 +194,8 @@ impl AvailableExpressionSet {
                 return Some(ave.add_variable_node(exp, self));
                 return Some(ave.add_variable_node(exp, self));
             }
             }
 
 
-            Expression::ConstantVariable(..)
-            | Expression::NumberLiteral(..)
+            //Expression::ConstantVariable(..)
+            Expression::NumberLiteral(..)
             | Expression::BoolLiteral(..)
             | Expression::BoolLiteral(..)
             | Expression::BytesLiteral(..) => {
             | Expression::BytesLiteral(..) => {
                 let key = exp.get_constant_expression_type();
                 let key = exp.get_constant_expression_type();
@@ -304,8 +305,8 @@ impl AvailableExpressionSet {
                 return self.expr_map.get(&ExpressionType::Variable(*pos)).copied();
                 return self.expr_map.get(&ExpressionType::Variable(*pos)).copied();
             }
             }
 
 
-            Expression::ConstantVariable(..)
-            | Expression::NumberLiteral(..)
+            //Expression::ConstantVariable(..)
+            Expression::NumberLiteral(..)
             | Expression::BoolLiteral(..)
             | Expression::BoolLiteral(..)
             | Expression::BytesLiteral(..) => {
             | Expression::BytesLiteral(..) => {
                 let key = exp.get_constant_expression_type();
                 let key = exp.get_constant_expression_type();
@@ -419,7 +420,7 @@ impl AvailableExpressionSet {
             // Variables, constants and literals will never be substituted
             // Variables, constants and literals will never be substituted
             Expression::FunctionArg(..)
             Expression::FunctionArg(..)
             | Expression::Variable(..)
             | Expression::Variable(..)
-            | Expression::ConstantVariable(..)
+            //| Expression::ConstantVariable(..)
             | Expression::NumberLiteral(..)
             | Expression::NumberLiteral(..)
             | Expression::BoolLiteral(..)
             | Expression::BoolLiteral(..)
             | Expression::BytesLiteral(..) => {
             | Expression::BytesLiteral(..) => {

+ 4 - 4
src/codegen/subexpression_elimination/common_subexpression_tracker.rs

@@ -1,11 +1,12 @@
 use crate::codegen::subexpression_elimination::{BasicExpression, ExpressionType};
 use crate::codegen::subexpression_elimination::{BasicExpression, ExpressionType};
 use crate::codegen::{
 use crate::codegen::{
     vartable::{Storage, Variable},
     vartable::{Storage, Variable},
-    ControlFlowGraph, Instr,
+    ControlFlowGraph, Expression, Instr,
 };
 };
 use crate::parser::pt::OptionalCodeLocation;
 use crate::parser::pt::OptionalCodeLocation;
 use crate::parser::pt::{Identifier, Loc};
 use crate::parser::pt::{Identifier, Loc};
-use crate::sema::ast::{Expression, Namespace, Type};
+use crate::sema::ast::RetrieveType;
+use crate::sema::ast::{Namespace, Type};
 use std::collections::HashMap;
 use std::collections::HashMap;
 
 
 #[derive(Clone)]
 #[derive(Clone)]
@@ -45,8 +46,7 @@ impl CommonSubExpressionTracker {
             Expression::FunctionArg(..)
             Expression::FunctionArg(..)
                 | Expression::Variable(..)
                 | Expression::Variable(..)
                 | Expression::BytesLiteral(..)
                 | Expression::BytesLiteral(..)
-                | Expression::NumberLiteral(..)
-                | Expression::ConstantVariable(..)
+                | Expression::NumberLiteral(..) //| Expression::ConstantVariable(..)
         ) {
         ) {
             return;
             return;
         }
         }

+ 2 - 16
src/codegen/subexpression_elimination/expression.rs

@@ -1,5 +1,6 @@
 use crate::codegen::subexpression_elimination::{ConstantType, ExpressionType};
 use crate::codegen::subexpression_elimination::{ConstantType, ExpressionType};
-use crate::sema::ast::{Expression, StringLocation};
+use crate::codegen::Expression;
+use crate::sema::ast::StringLocation;
 
 
 impl Expression {
 impl Expression {
     /// Rebuild a binary expression given the new left and right subexpressions
     /// Rebuild a binary expression given the new left and right subexpressions
@@ -42,15 +43,6 @@ impl Expression {
                 Box::new(left.clone()),
                 Box::new(left.clone()),
                 Box::new(right.clone()),
                 Box::new(right.clone()),
             ),
             ),
-
-            Expression::Or(loc, ..) => {
-                Expression::Or(*loc, Box::new(left.clone()), Box::new(right.clone()))
-            }
-
-            Expression::And(loc, ..) => {
-                Expression::And(*loc, Box::new(left.clone()), Box::new(right.clone()))
-            }
-
             Expression::Equal(loc, ..) => {
             Expression::Equal(loc, ..) => {
                 Expression::Equal(*loc, Box::new(left.clone()), Box::new(right.clone()))
                 Expression::Equal(*loc, Box::new(left.clone()), Box::new(right.clone()))
             }
             }
@@ -206,8 +198,6 @@ impl Expression {
             | Expression::BitwiseOr(_, _, left, right)
             | Expression::BitwiseOr(_, _, left, right)
             | Expression::BitwiseAnd(_, _, left, right)
             | Expression::BitwiseAnd(_, _, left, right)
             | Expression::BitwiseXor(_, _, left, right)
             | Expression::BitwiseXor(_, _, left, right)
-            | Expression::Or(_, left, right)
-            | Expression::And(_, left, right)
             | Expression::Equal(_, left, right)
             | Expression::Equal(_, left, right)
             | Expression::NotEqual(_, left, right) => Some((left, right)),
             | Expression::NotEqual(_, left, right) => Some((left, right)),
 
 
@@ -255,10 +245,6 @@ impl Expression {
             Expression::BoolLiteral(_, value) => ConstantType::Bool(*value),
             Expression::BoolLiteral(_, value) => ConstantType::Bool(*value),
             Expression::NumberLiteral(_, _, value) => ConstantType::Number(value.clone()),
             Expression::NumberLiteral(_, _, value) => ConstantType::Number(value.clone()),
             Expression::BytesLiteral(_, _, value) => ConstantType::Bytes(value.clone()),
             Expression::BytesLiteral(_, _, value) => ConstantType::Bytes(value.clone()),
-            Expression::ConstantVariable(_, _, contract_no, var_no) => {
-                ConstantType::ConstantVariable(*contract_no, *var_no)
-            }
-
             _ => unreachable!("Not a constant expression"),
             _ => unreachable!("Not a constant expression"),
         };
         };
 
 

+ 1 - 1
src/codegen/subexpression_elimination/instruction.rs

@@ -2,7 +2,7 @@ use crate::codegen::cfg::Instr;
 use crate::codegen::subexpression_elimination::common_subexpression_tracker::CommonSubExpressionTracker;
 use crate::codegen::subexpression_elimination::common_subexpression_tracker::CommonSubExpressionTracker;
 use crate::codegen::subexpression_elimination::AvailableExpression;
 use crate::codegen::subexpression_elimination::AvailableExpression;
 use crate::codegen::subexpression_elimination::{AvailableExpressionSet, AvailableVariable};
 use crate::codegen::subexpression_elimination::{AvailableExpressionSet, AvailableVariable};
-use crate::sema::ast::Expression;
+use crate::codegen::Expression;
 
 
 impl AvailableExpressionSet {
 impl AvailableExpressionSet {
     /// Check if we can add the expressions of an instruction to the graph
     /// Check if we can add the expressions of an instruction to the graph

+ 0 - 1
src/codegen/subexpression_elimination/mod.rs

@@ -62,7 +62,6 @@ pub enum ConstantType {
     Bool(bool),
     Bool(bool),
     Bytes(Vec<u8>),
     Bytes(Vec<u8>),
     Number(BigInt),
     Number(BigInt),
-    ConstantVariable(Option<usize>, usize),
 }
 }
 
 
 /// The type of expression that a node represents
 /// The type of expression that a node represents

+ 1 - 5
src/codegen/subexpression_elimination/operator.rs

@@ -1,4 +1,4 @@
-use crate::sema::ast::Expression;
+use crate::codegen::Expression;
 
 
 /// This enum defines operator types for the graph
 /// This enum defines operator types for the graph
 #[derive(PartialEq, Eq, Hash, Copy, Clone)]
 #[derive(PartialEq, Eq, Hash, Copy, Clone)]
@@ -14,8 +14,6 @@ pub enum Operator {
     BitwiseXor,
     BitwiseXor,
     ShiftLeft,
     ShiftLeft,
     ShiftRight,
     ShiftRight,
-    Or,
-    And,
     More,
     More,
     Less,
     Less,
     MoreEqual,
     MoreEqual,
@@ -50,8 +48,6 @@ impl Expression {
             Expression::BitwiseXor(..) => Operator::BitwiseXor,
             Expression::BitwiseXor(..) => Operator::BitwiseXor,
             Expression::ShiftLeft(..) => Operator::ShiftLeft,
             Expression::ShiftLeft(..) => Operator::ShiftLeft,
             Expression::ShiftRight(..) => Operator::ShiftRight,
             Expression::ShiftRight(..) => Operator::ShiftRight,
-            Expression::Or(..) => Operator::Or,
-            Expression::And(..) => Operator::And,
             Expression::Not(..) => Operator::Not,
             Expression::Not(..) => Operator::Not,
             Expression::ZeroExt(..) => Operator::ZeroExt,
             Expression::ZeroExt(..) => Operator::ZeroExt,
             Expression::SignExt(..) => Operator::SignExt,
             Expression::SignExt(..) => Operator::SignExt,

+ 24 - 10
src/codegen/subexpression_elimination/tests.rs

@@ -3,8 +3,9 @@
 use crate::codegen::cfg::Instr;
 use crate::codegen::cfg::Instr;
 use crate::codegen::subexpression_elimination::common_subexpression_tracker::CommonSubExpressionTracker;
 use crate::codegen::subexpression_elimination::common_subexpression_tracker::CommonSubExpressionTracker;
 use crate::codegen::subexpression_elimination::{AvailableExpression, AvailableExpressionSet};
 use crate::codegen::subexpression_elimination::{AvailableExpression, AvailableExpressionSet};
+use crate::codegen::Expression;
 use crate::parser::pt::Loc;
 use crate::parser::pt::Loc;
-use crate::sema::ast::{Expression, StringLocation, Type};
+use crate::sema::ast::{StringLocation, Type};
 use num_bigint::{BigInt, Sign};
 use num_bigint::{BigInt, Sign};
 
 
 #[test]
 #[test]
@@ -37,7 +38,8 @@ fn add_variable_function_arg() {
 
 
 #[test]
 #[test]
 fn add_constants() {
 fn add_constants() {
-    let var = Expression::ConstantVariable(Loc::Codegen, Type::Int(2), None, 1);
+    let var =
+        Expression::NumberLiteral(Loc::Codegen, Type::Int(2), BigInt::new(Sign::Plus, vec![3]));
     let num =
     let num =
         Expression::NumberLiteral(Loc::Codegen, Type::Int(1), BigInt::new(Sign::Plus, vec![2]));
         Expression::NumberLiteral(Loc::Codegen, Type::Int(1), BigInt::new(Sign::Plus, vec![2]));
     let sub = Expression::Subtract(
     let sub = Expression::Subtract(
@@ -62,9 +64,15 @@ fn add_constants() {
 
 
 #[test]
 #[test]
 fn add_commutative() {
 fn add_commutative() {
-    let cte = Expression::BoolLiteral(Loc::Codegen, false);
-    let var = Expression::Variable(Loc::Codegen, Type::Bool, 3);
-    let expr = Expression::Or(Loc::Codegen, Box::new(cte.clone()), Box::new(var.clone()));
+    let cte = Expression::NumberLiteral(Loc::Codegen, Type::Int(32), BigInt::from(20));
+    let var = Expression::Variable(Loc::Codegen, Type::Int(32), 3);
+    let expr = Expression::Add(
+        Loc::Codegen,
+        Type::Int(32),
+        true,
+        Box::new(cte.clone()),
+        Box::new(var.clone()),
+    );
 
 
     let instr = Instr::ValueTransfer {
     let instr = Instr::ValueTransfer {
         success: None,
         success: None,
@@ -72,7 +80,13 @@ fn add_commutative() {
         value: expr.clone(),
         value: expr.clone(),
     };
     };
 
 
-    let expr_other = Expression::Or(Loc::Codegen, Box::new(var), Box::new(cte));
+    let expr_other = Expression::Add(
+        Loc::Codegen,
+        Type::Int(32),
+        true,
+        Box::new(var),
+        Box::new(cte),
+    );
 
 
     let mut ave = AvailableExpression::default();
     let mut ave = AvailableExpression::default();
     let mut set = AvailableExpressionSet::default();
     let mut set = AvailableExpressionSet::default();
@@ -205,7 +219,7 @@ fn invalid() {
 #[test]
 #[test]
 fn complex_expression() {
 fn complex_expression() {
     let var = Expression::Variable(Loc::Codegen, Type::Int(8), 2);
     let var = Expression::Variable(Loc::Codegen, Type::Int(8), 2);
-    let cte = Expression::ConstantVariable(Loc::Codegen, Type::Int(8), Some(2), 3);
+    let cte = Expression::NumberLiteral(Loc::Codegen, Type::Int(8), BigInt::from(3));
     let arg = Expression::FunctionArg(Loc::Codegen, Type::Int(9), 5);
     let arg = Expression::FunctionArg(Loc::Codegen, Type::Int(9), 5);
 
 
     let sum = Expression::Add(
     let sum = Expression::Add(
@@ -343,7 +357,7 @@ fn string() {
 #[test]
 #[test]
 fn kill() {
 fn kill() {
     let var = Expression::Variable(Loc::Codegen, Type::Int(8), 2);
     let var = Expression::Variable(Loc::Codegen, Type::Int(8), 2);
-    let cte = Expression::ConstantVariable(Loc::Codegen, Type::Int(8), Some(2), 3);
+    let cte = Expression::NumberLiteral(Loc::Codegen, Type::Int(8), BigInt::from(3));
     let arg = Expression::FunctionArg(Loc::Codegen, Type::Int(9), 5);
     let arg = Expression::FunctionArg(Loc::Codegen, Type::Int(9), 5);
 
 
     let sum = Expression::Add(
     let sum = Expression::Add(
@@ -432,7 +446,7 @@ fn kill() {
 #[test]
 #[test]
 fn clone() {
 fn clone() {
     let var = Expression::Variable(Loc::Codegen, Type::Int(8), 2);
     let var = Expression::Variable(Loc::Codegen, Type::Int(8), 2);
-    let cte = Expression::ConstantVariable(Loc::Codegen, Type::Int(8), Some(2), 3);
+    let cte = Expression::NumberLiteral(Loc::Codegen, Type::Int(8), BigInt::from(3));
     let arg = Expression::FunctionArg(Loc::Codegen, Type::Int(9), 5);
     let arg = Expression::FunctionArg(Loc::Codegen, Type::Int(9), 5);
 
 
     let sum = Expression::Add(
     let sum = Expression::Add(
@@ -519,7 +533,7 @@ fn clone() {
 #[test]
 #[test]
 fn intersect() {
 fn intersect() {
     let var = Expression::Variable(Loc::Codegen, Type::Int(8), 1);
     let var = Expression::Variable(Loc::Codegen, Type::Int(8), 1);
-    let cte = Expression::ConstantVariable(Loc::Codegen, Type::Int(8), Some(2), 3);
+    let cte = Expression::NumberLiteral(Loc::Codegen, Type::Int(8), BigInt::from(3));
     let arg = Expression::FunctionArg(Loc::Codegen, Type::Int(9), 5);
     let arg = Expression::FunctionArg(Loc::Codegen, Type::Int(9), 5);
 
 
     let sum = Expression::Add(
     let sum = Expression::Add(

+ 4 - 2
src/codegen/undefined_variable.rs

@@ -1,8 +1,10 @@
 use crate::codegen::cfg::{ControlFlowGraph, Instr};
 use crate::codegen::cfg::{ControlFlowGraph, Instr};
 use crate::codegen::reaching_definitions::{apply_transfers, VarDefs};
 use crate::codegen::reaching_definitions::{apply_transfers, VarDefs};
-use crate::parser::pt::{CodeLocation, Loc, StorageLocation};
-use crate::sema::ast::{Builtin, Diagnostic, ErrorType, Expression, Level, Namespace, Note};
+use crate::codegen::Expression;
+use crate::parser::pt::{Loc, StorageLocation};
+use crate::sema::ast::{Builtin, Diagnostic, ErrorType, Level, Namespace, Note};
 use crate::sema::symtable;
 use crate::sema::symtable;
+use solang_parser::pt::CodeLocation;
 use std::collections::HashMap;
 use std::collections::HashMap;
 
 
 /// We use this struct in expression.recurse function to provide all the
 /// We use this struct in expression.recurse function to provide all the

+ 2 - 1
src/codegen/vector_to_slice.rs

@@ -1,7 +1,8 @@
 use super::cfg::{BasicBlock, ControlFlowGraph, Instr};
 use super::cfg::{BasicBlock, ControlFlowGraph, Instr};
 use super::reaching_definitions::{Def, Transfer};
 use super::reaching_definitions::{Def, Transfer};
 use crate::codegen::cfg::ASTFunction;
 use crate::codegen::cfg::ASTFunction;
-use crate::sema::ast::{Expression, Namespace, Type};
+use crate::codegen::Expression;
+use crate::sema::ast::{Namespace, Type};
 use indexmap::IndexMap;
 use indexmap::IndexMap;
 use std::collections::HashSet;
 use std::collections::HashSet;
 
 

+ 16 - 15
src/emit/ewasm.rs

@@ -1,3 +1,4 @@
+use crate::codegen;
 use crate::codegen::cfg::HashTy;
 use crate::codegen::cfg::HashTy;
 use crate::parser::pt;
 use crate::parser::pt;
 use crate::sema::ast;
 use crate::sema::ast;
@@ -1850,7 +1851,7 @@ impl<'a> TargetRuntime<'a> for EwasmTarget {
     fn builtin<'b>(
     fn builtin<'b>(
         &self,
         &self,
         binary: &Binary<'b>,
         binary: &Binary<'b>,
-        expr: &ast::Expression,
+        expr: &codegen::Expression,
         vartab: &HashMap<usize, Variable<'b>>,
         vartab: &HashMap<usize, Variable<'b>>,
         function: FunctionValue<'b>,
         function: FunctionValue<'b>,
         ns: &ast::Namespace,
         ns: &ast::Namespace,
@@ -1911,37 +1912,37 @@ impl<'a> TargetRuntime<'a> for EwasmTarget {
         }
         }
 
 
         match expr {
         match expr {
-            ast::Expression::Builtin(_, _, ast::Builtin::BlockNumber, _) => {
+            codegen::Expression::Builtin(_, _, ast::Builtin::BlockNumber, _) => {
                 straight_call!("block_number", "getBlockNumber")
                 straight_call!("block_number", "getBlockNumber")
             }
             }
-            ast::Expression::Builtin(_, _, ast::Builtin::Gasleft, _) => {
+            codegen::Expression::Builtin(_, _, ast::Builtin::Gasleft, _) => {
                 straight_call!("gas_left", "getGasLeft")
                 straight_call!("gas_left", "getGasLeft")
             }
             }
-            ast::Expression::Builtin(_, _, ast::Builtin::GasLimit, _) => {
+            codegen::Expression::Builtin(_, _, ast::Builtin::GasLimit, _) => {
                 straight_call!("gas_limit", "getBlockGasLimit")
                 straight_call!("gas_limit", "getBlockGasLimit")
             }
             }
-            ast::Expression::Builtin(_, _, ast::Builtin::Timestamp, _) => {
+            codegen::Expression::Builtin(_, _, ast::Builtin::Timestamp, _) => {
                 straight_call!("time_stamp", "getBlockTimestamp")
                 straight_call!("time_stamp", "getBlockTimestamp")
             }
             }
-            ast::Expression::Builtin(_, _, ast::Builtin::BlockDifficulty, _) => {
+            codegen::Expression::Builtin(_, _, ast::Builtin::BlockDifficulty, _) => {
                 single_int_stack!("block_difficulty", "getBlockDifficulty", 256)
                 single_int_stack!("block_difficulty", "getBlockDifficulty", 256)
             }
             }
-            ast::Expression::Builtin(_, _, ast::Builtin::Origin, _) => {
+            codegen::Expression::Builtin(_, _, ast::Builtin::Origin, _) => {
                 single_address_stack!("origin", "getTxOrigin")
                 single_address_stack!("origin", "getTxOrigin")
             }
             }
-            ast::Expression::Builtin(_, _, ast::Builtin::Sender, _) => {
+            codegen::Expression::Builtin(_, _, ast::Builtin::Sender, _) => {
                 single_address_stack!("caller", "getCaller")
                 single_address_stack!("caller", "getCaller")
             }
             }
-            ast::Expression::Builtin(_, _, ast::Builtin::BlockCoinbase, _) => {
+            codegen::Expression::Builtin(_, _, ast::Builtin::BlockCoinbase, _) => {
                 single_address_stack!("coinbase", "getBlockCoinbase")
                 single_address_stack!("coinbase", "getBlockCoinbase")
             }
             }
-            ast::Expression::Builtin(_, _, ast::Builtin::Gasprice, _) => {
+            codegen::Expression::Builtin(_, _, ast::Builtin::Gasprice, _) => {
                 single_int_stack!("gas_price", "getTxGasPrice", ns.value_length as u32 * 8)
                 single_int_stack!("gas_price", "getTxGasPrice", ns.value_length as u32 * 8)
             }
             }
-            ast::Expression::Builtin(_, _, ast::Builtin::Value, _) => {
+            codegen::Expression::Builtin(_, _, ast::Builtin::Value, _) => {
                 single_int_stack!("value", "getCallValue", ns.value_length as u32 * 8)
                 single_int_stack!("value", "getCallValue", ns.value_length as u32 * 8)
             }
             }
-            ast::Expression::Builtin(_, _, ast::Builtin::Calldata, _) => binary
+            codegen::Expression::Builtin(_, _, ast::Builtin::Calldata, _) => binary
                 .builder
                 .builder
                 .build_call(
                 .build_call(
                     binary.module.get_function("vector_new").unwrap(),
                     binary.module.get_function("vector_new").unwrap(),
@@ -1961,7 +1962,7 @@ impl<'a> TargetRuntime<'a> for EwasmTarget {
                 .try_as_basic_value()
                 .try_as_basic_value()
                 .left()
                 .left()
                 .unwrap(),
                 .unwrap(),
-            ast::Expression::Builtin(_, _, ast::Builtin::BlockHash, args) => {
+            codegen::Expression::Builtin(_, _, ast::Builtin::BlockHash, args) => {
                 let block_number = self.expression(binary, &args[0], vartab, function, ns);
                 let block_number = self.expression(binary, &args[0], vartab, function, ns);
 
 
                 let value = binary
                 let value = binary
@@ -1986,7 +1987,7 @@ impl<'a> TargetRuntime<'a> for EwasmTarget {
 
 
                 binary.builder.build_load(value, "block_hash")
                 binary.builder.build_load(value, "block_hash")
             }
             }
-            ast::Expression::Builtin(_, _, ast::Builtin::GetAddress, _) => {
+            codegen::Expression::Builtin(_, _, ast::Builtin::GetAddress, _) => {
                 let value = binary
                 let value = binary
                     .builder
                     .builder
                     .build_alloca(binary.address_type(ns), "self_address");
                     .build_alloca(binary.address_type(ns), "self_address");
@@ -2006,7 +2007,7 @@ impl<'a> TargetRuntime<'a> for EwasmTarget {
 
 
                 binary.builder.build_load(value, "self_address")
                 binary.builder.build_load(value, "self_address")
             }
             }
-            ast::Expression::Builtin(_, _, ast::Builtin::Balance, addr) => {
+            codegen::Expression::Builtin(_, _, ast::Builtin::Balance, addr) => {
                 let addr = self
                 let addr = self
                     .expression(binary, &addr[0], vartab, function, ns)
                     .expression(binary, &addr[0], vartab, function, ns)
                     .into_array_value();
                     .into_array_value();

+ 7 - 44
src/emit/mod.rs

@@ -1,7 +1,8 @@
+use crate::codegen::Expression;
 use crate::parser::pt;
 use crate::parser::pt;
+use crate::sema::ast::RetrieveType;
 use crate::sema::ast::{
 use crate::sema::ast::{
-    Builtin, BuiltinStruct, CallTy, Contract, Expression, FormatArg, Namespace, Parameter,
-    StringLocation, Type,
+    Builtin, BuiltinStruct, CallTy, Contract, FormatArg, Namespace, Parameter, StringLocation, Type,
 };
 };
 use std::cell::RefCell;
 use std::cell::RefCell;
 use std::convert::TryFrom;
 use std::convert::TryFrom;
@@ -2089,11 +2090,7 @@ pub trait TargetRuntime<'a> {
                     value
                     value
                 }
                 }
             }
             }
-            Expression::StorageLoad(..) => {
-                // this should be covered by the Instr::LoadStorage instruction; if we reach this
-                // point the code generation is broken.
-                unreachable!();
-            }
+
             Expression::ZeroExt(_, t, e) => {
             Expression::ZeroExt(_, t, e) => {
                 let e = self
                 let e = self
                     .expression(bin, e, vartab, function, ns)
                     .expression(bin, e, vartab, function, ns)
@@ -2254,26 +2251,6 @@ pub trait TargetRuntime<'a> {
 
 
                 bin.builder.build_not(e, "").into()
                 bin.builder.build_not(e, "").into()
             }
             }
-            Expression::Or(_, l, r) => {
-                let left = self
-                    .expression(bin, l, vartab, function, ns)
-                    .into_int_value();
-                let right = self
-                    .expression(bin, r, vartab, function, ns)
-                    .into_int_value();
-
-                bin.builder.build_or(left, right, "").into()
-            }
-            Expression::And(_, l, r) => {
-                let left = self
-                    .expression(bin, l, vartab, function, ns)
-                    .into_int_value();
-                let right = self
-                    .expression(bin, r, vartab, function, ns)
-                    .into_int_value();
-
-                bin.builder.build_and(left, right, "").into()
-            }
             Expression::BitwiseOr(_, _, l, r) => {
             Expression::BitwiseOr(_, _, l, r) => {
                 let left = self
                 let left = self
                     .expression(bin, l, vartab, function, ns)
                     .expression(bin, l, vartab, function, ns)
@@ -3108,22 +3085,8 @@ pub trait TargetRuntime<'a> {
             Expression::FormatString(_, args) => {
             Expression::FormatString(_, args) => {
                 self.format_string(bin, args, vartab, function, ns)
                 self.format_string(bin, args, vartab, function, ns)
             }
             }
-            Expression::Ternary(..)
-            | Expression::CheckingTrunc(..)
-            | Expression::RationalNumberLiteral(..)
-            | Expression::ConstantVariable(..)
-            | Expression::StorageVariable(..)
-            | Expression::PreDecrement(..)
-            | Expression::PostDecrement(..)
-            | Expression::PreIncrement(..)
-            | Expression::PostIncrement(..)
-            | Expression::Assign(..)
-            | Expression::InternalFunction { .. }
-            | Expression::InternalFunctionCall { .. }
-            | Expression::ExternalFunctionCall { .. }
-            | Expression::ExternalFunctionCallRaw { .. }
-            | Expression::Constructor { .. }
-            | Expression::InterfaceId(..)
+
+            Expression::RationalNumberLiteral(..)
             | Expression::List(..)
             | Expression::List(..)
             | Expression::Undefined(..)
             | Expression::Undefined(..)
             | Expression::Poison
             | Expression::Poison
@@ -3199,7 +3162,7 @@ pub trait TargetRuntime<'a> {
     fn string_location(
     fn string_location(
         &self,
         &self,
         bin: &Binary<'a>,
         bin: &Binary<'a>,
-        location: &StringLocation,
+        location: &StringLocation<Expression>,
         vartab: &HashMap<usize, Variable<'a>>,
         vartab: &HashMap<usize, Variable<'a>>,
         function: FunctionValue<'a>,
         function: FunctionValue<'a>,
         ns: &Namespace,
         ns: &Namespace,

+ 19 - 14
src/emit/solana.rs

@@ -1,7 +1,7 @@
 use crate::codegen::cfg::HashTy;
 use crate::codegen::cfg::HashTy;
 use crate::parser::pt;
 use crate::parser::pt;
 use crate::sema::ast;
 use crate::sema::ast;
-use crate::Target;
+use crate::{codegen, Target};
 use std::collections::HashMap;
 use std::collections::HashMap;
 use std::str;
 use std::str;
 
 
@@ -3322,13 +3322,13 @@ impl<'a> TargetRuntime<'a> for SolanaTarget {
     fn builtin<'b>(
     fn builtin<'b>(
         &self,
         &self,
         binary: &Binary<'b>,
         binary: &Binary<'b>,
-        expr: &ast::Expression,
+        expr: &codegen::Expression,
         vartab: &HashMap<usize, Variable<'b>>,
         vartab: &HashMap<usize, Variable<'b>>,
         function: FunctionValue<'b>,
         function: FunctionValue<'b>,
         ns: &ast::Namespace,
         ns: &ast::Namespace,
     ) -> BasicValueEnum<'b> {
     ) -> BasicValueEnum<'b> {
         match expr {
         match expr {
-            ast::Expression::Builtin(_, _, ast::Builtin::Timestamp, _) => {
+            codegen::Expression::Builtin(_, _, ast::Builtin::Timestamp, _) => {
                 let parameters = self.sol_parameters(binary);
                 let parameters = self.sol_parameters(binary);
 
 
                 let sol_clock = binary.module.get_function("sol_clock").unwrap();
                 let sol_clock = binary.module.get_function("sol_clock").unwrap();
@@ -3354,7 +3354,12 @@ impl<'a> TargetRuntime<'a> for SolanaTarget {
 
 
                 binary.builder.build_load(timestamp, "timestamp")
                 binary.builder.build_load(timestamp, "timestamp")
             }
             }
-            ast::Expression::Builtin(_, _, ast::Builtin::BlockNumber | ast::Builtin::Slot, _) => {
+            codegen::Expression::Builtin(
+                _,
+                _,
+                ast::Builtin::BlockNumber | ast::Builtin::Slot,
+                _,
+            ) => {
                 let parameters = self.sol_parameters(binary);
                 let parameters = self.sol_parameters(binary);
 
 
                 let sol_clock = binary.module.get_function("sol_clock").unwrap();
                 let sol_clock = binary.module.get_function("sol_clock").unwrap();
@@ -3377,7 +3382,7 @@ impl<'a> TargetRuntime<'a> for SolanaTarget {
 
 
                 binary.builder.build_load(slot, "timestamp")
                 binary.builder.build_load(slot, "timestamp")
             }
             }
-            ast::Expression::Builtin(_, _, ast::Builtin::Sender, _) => {
+            codegen::Expression::Builtin(_, _, ast::Builtin::Sender, _) => {
                 let parameters = self.sol_parameters(binary);
                 let parameters = self.sol_parameters(binary);
 
 
                 let sender = binary
                 let sender = binary
@@ -3399,10 +3404,10 @@ impl<'a> TargetRuntime<'a> for SolanaTarget {
 
 
                 binary.builder.build_load(sender_address, "sender_address")
                 binary.builder.build_load(sender_address, "sender_address")
             }
             }
-            ast::Expression::Builtin(_, _, ast::Builtin::Value, _) => {
+            codegen::Expression::Builtin(_, _, ast::Builtin::Value, _) => {
                 self.value_transferred(binary, ns).into()
                 self.value_transferred(binary, ns).into()
             }
             }
-            ast::Expression::Builtin(_, _, ast::Builtin::GetAddress, _) => {
+            codegen::Expression::Builtin(_, _, ast::Builtin::GetAddress, _) => {
                 let parameters = self.sol_parameters(binary);
                 let parameters = self.sol_parameters(binary);
 
 
                 let account_id = binary
                 let account_id = binary
@@ -3424,7 +3429,7 @@ impl<'a> TargetRuntime<'a> for SolanaTarget {
 
 
                 binary.builder.build_load(value, "self_address")
                 binary.builder.build_load(value, "self_address")
             }
             }
-            ast::Expression::Builtin(_, _, ast::Builtin::Calldata, _) => {
+            codegen::Expression::Builtin(_, _, ast::Builtin::Calldata, _) => {
                 let sol_params = self.sol_parameters(binary);
                 let sol_params = self.sol_parameters(binary);
 
 
                 let input = binary
                 let input = binary
@@ -3470,7 +3475,7 @@ impl<'a> TargetRuntime<'a> for SolanaTarget {
                     .left()
                     .left()
                     .unwrap()
                     .unwrap()
             }
             }
-            ast::Expression::Builtin(_, _, ast::Builtin::Signature, _) => {
+            codegen::Expression::Builtin(_, _, ast::Builtin::Signature, _) => {
                 let sol_params = self.sol_parameters(binary);
                 let sol_params = self.sol_parameters(binary);
 
 
                 let input = binary
                 let input = binary
@@ -3502,7 +3507,7 @@ impl<'a> TargetRuntime<'a> for SolanaTarget {
                     .left()
                     .left()
                     .unwrap()
                     .unwrap()
             }
             }
-            ast::Expression::Builtin(_, _, ast::Builtin::SignatureVerify, args) => {
+            codegen::Expression::Builtin(_, _, ast::Builtin::SignatureVerify, args) => {
                 assert_eq!(args.len(), 3);
                 assert_eq!(args.len(), 3);
 
 
                 let address = binary.build_alloca(function, binary.address_type(ns), "address");
                 let address = binary.build_alloca(function, binary.address_type(ns), "address");
@@ -3564,7 +3569,7 @@ impl<'a> TargetRuntime<'a> for SolanaTarget {
                     )
                     )
                     .into()
                     .into()
             }
             }
-            ast::Expression::Builtin(_, _, ast::Builtin::Balance, args) => {
+            codegen::Expression::Builtin(_, _, ast::Builtin::Balance, args) => {
                 assert_eq!(args.len(), 1);
                 assert_eq!(args.len(), 1);
 
 
                 let address = binary.build_alloca(function, binary.address_type(ns), "address");
                 let address = binary.build_alloca(function, binary.address_type(ns), "address");
@@ -3604,7 +3609,7 @@ impl<'a> TargetRuntime<'a> for SolanaTarget {
 
 
                 binary.builder.build_load(lamport, "lamport")
                 binary.builder.build_load(lamport, "lamport")
             }
             }
-            ast::Expression::Builtin(_, _, ast::Builtin::Accounts, _) => {
+            codegen::Expression::Builtin(_, _, ast::Builtin::Accounts, _) => {
                 let parameters = self.sol_parameters(binary);
                 let parameters = self.sol_parameters(binary);
 
 
                 unsafe {
                 unsafe {
@@ -3620,7 +3625,7 @@ impl<'a> TargetRuntime<'a> for SolanaTarget {
                 }
                 }
                 .into()
                 .into()
             }
             }
-            ast::Expression::Builtin(_, _, ast::Builtin::ArrayLength, _) => {
+            codegen::Expression::Builtin(_, _, ast::Builtin::ArrayLength, _) => {
                 let parameters = self.sol_parameters(binary);
                 let parameters = self.sol_parameters(binary);
 
 
                 let ka_num = binary
                 let ka_num = binary
@@ -3635,7 +3640,7 @@ impl<'a> TargetRuntime<'a> for SolanaTarget {
                     .build_int_truncate(ka_num, binary.context.i32_type(), "ka_num_32bits")
                     .build_int_truncate(ka_num, binary.context.i32_type(), "ka_num_32bits")
                     .into()
                     .into()
             }
             }
-            ast::Expression::StructMember(_, _, a, member) => {
+            codegen::Expression::StructMember(_, _, a, member) => {
                 let account_info = self
                 let account_info = self
                     .expression(binary, a, vartab, function, ns)
                     .expression(binary, a, vartab, function, ns)
                     .into_pointer_value();
                     .into_pointer_value();

+ 20 - 17
src/emit/substrate.rs

@@ -1,3 +1,4 @@
+use crate::codegen;
 use crate::codegen::cfg::HashTy;
 use crate::codegen::cfg::HashTy;
 use crate::parser::pt;
 use crate::parser::pt;
 use crate::sema::ast;
 use crate::sema::ast;
@@ -4114,7 +4115,7 @@ impl<'a> TargetRuntime<'a> for SubstrateTarget {
     fn builtin<'b>(
     fn builtin<'b>(
         &self,
         &self,
         binary: &Binary<'b>,
         binary: &Binary<'b>,
-        expr: &ast::Expression,
+        expr: &codegen::Expression,
         vartab: &HashMap<usize, Variable<'b>>,
         vartab: &HashMap<usize, Variable<'b>>,
         function: FunctionValue<'b>,
         function: FunctionValue<'b>,
         ns: &ast::Namespace,
         ns: &ast::Namespace,
@@ -4157,7 +4158,7 @@ impl<'a> TargetRuntime<'a> for SubstrateTarget {
         }
         }
 
 
         match expr {
         match expr {
-            ast::Expression::Builtin(_, _, ast::Builtin::Calldata, _) => {
+            codegen::Expression::Builtin(_, _, ast::Builtin::Calldata, _) => {
                 // allocate vector for input
                 // allocate vector for input
                 let v = binary
                 let v = binary
                     .builder
                     .builder
@@ -4236,7 +4237,7 @@ impl<'a> TargetRuntime<'a> for SubstrateTarget {
 
 
                 v.into()
                 v.into()
             }
             }
-            ast::Expression::Builtin(_, _, ast::Builtin::BlockNumber, _) => {
+            codegen::Expression::Builtin(_, _, ast::Builtin::BlockNumber, _) => {
                 let block_number =
                 let block_number =
                     get_seal_value!("block_number", "seal_block_number", 32).into_int_value();
                     get_seal_value!("block_number", "seal_block_number", 32).into_int_value();
 
 
@@ -4250,7 +4251,7 @@ impl<'a> TargetRuntime<'a> for SubstrateTarget {
                     )
                     )
                     .into()
                     .into()
             }
             }
-            ast::Expression::Builtin(_, _, ast::Builtin::Timestamp, _) => {
+            codegen::Expression::Builtin(_, _, ast::Builtin::Timestamp, _) => {
                 let milliseconds = get_seal_value!("timestamp", "seal_now", 64).into_int_value();
                 let milliseconds = get_seal_value!("timestamp", "seal_now", 64).into_int_value();
 
 
                 // Solidity expects the timestamp in seconds, not milliseconds
                 // Solidity expects the timestamp in seconds, not milliseconds
@@ -4263,10 +4264,10 @@ impl<'a> TargetRuntime<'a> for SubstrateTarget {
                     )
                     )
                     .into()
                     .into()
             }
             }
-            ast::Expression::Builtin(_, _, ast::Builtin::Gasleft, _) => {
+            codegen::Expression::Builtin(_, _, ast::Builtin::Gasleft, _) => {
                 get_seal_value!("gas_left", "seal_gas_left", 64)
                 get_seal_value!("gas_left", "seal_gas_left", 64)
             }
             }
-            ast::Expression::Builtin(_, _, ast::Builtin::Gasprice, expr) => {
+            codegen::Expression::Builtin(_, _, ast::Builtin::Gasprice, expr) => {
                 // gasprice is available as "tx.gasprice" which will give you the price for one unit
                 // gasprice is available as "tx.gasprice" which will give you the price for one unit
                 // of gas, or "tx.gasprice(uint64)" which will give you the price of N gas units
                 // of gas, or "tx.gasprice(uint64)" which will give you the price of N gas units
                 let gas = if expr.is_empty() {
                 let gas = if expr.is_empty() {
@@ -4309,7 +4310,7 @@ impl<'a> TargetRuntime<'a> for SubstrateTarget {
                     "price",
                     "price",
                 )
                 )
             }
             }
-            ast::Expression::Builtin(_, _, ast::Builtin::Sender, _) => {
+            codegen::Expression::Builtin(_, _, ast::Builtin::Sender, _) => {
                 let scratch_buf = binary.builder.build_pointer_cast(
                 let scratch_buf = binary.builder.build_pointer_cast(
                     binary.scratch.unwrap().as_pointer_value(),
                     binary.scratch.unwrap().as_pointer_value(),
                     binary.context.i8_type().ptr_type(AddressSpace::Generic),
                     binary.context.i8_type().ptr_type(AddressSpace::Generic),
@@ -4340,20 +4341,22 @@ impl<'a> TargetRuntime<'a> for SubstrateTarget {
                     "caller",
                     "caller",
                 )
                 )
             }
             }
-            ast::Expression::Builtin(_, _, ast::Builtin::Value, _) => {
+            codegen::Expression::Builtin(_, _, ast::Builtin::Value, _) => {
                 self.value_transferred(binary, ns).into()
                 self.value_transferred(binary, ns).into()
             }
             }
-            ast::Expression::Builtin(_, _, ast::Builtin::MinimumBalance, _) => get_seal_value!(
+            codegen::Expression::Builtin(_, _, ast::Builtin::MinimumBalance, _) => get_seal_value!(
                 "minimum_balance",
                 "minimum_balance",
                 "seal_minimum_balance",
                 "seal_minimum_balance",
                 ns.value_length as u32 * 8
                 ns.value_length as u32 * 8
             ),
             ),
-            ast::Expression::Builtin(_, _, ast::Builtin::TombstoneDeposit, _) => get_seal_value!(
-                "tombstone_deposit",
-                "seal_tombstone_deposit",
-                ns.value_length as u32 * 8
-            ),
-            ast::Expression::Builtin(_, _, ast::Builtin::Random, args) => {
+            codegen::Expression::Builtin(_, _, ast::Builtin::TombstoneDeposit, _) => {
+                get_seal_value!(
+                    "tombstone_deposit",
+                    "seal_tombstone_deposit",
+                    ns.value_length as u32 * 8
+                )
+            }
+            codegen::Expression::Builtin(_, _, ast::Builtin::Random, args) => {
                 let subject = self
                 let subject = self
                     .expression(binary, &args[0], vartab, function, ns)
                     .expression(binary, &args[0], vartab, function, ns)
                     .into_pointer_value();
                     .into_pointer_value();
@@ -4421,7 +4424,7 @@ impl<'a> TargetRuntime<'a> for SubstrateTarget {
                     "hash",
                     "hash",
                 )
                 )
             }
             }
-            ast::Expression::Builtin(_, _, ast::Builtin::GetAddress, _) => {
+            codegen::Expression::Builtin(_, _, ast::Builtin::GetAddress, _) => {
                 let scratch_buf = binary.builder.build_pointer_cast(
                 let scratch_buf = binary.builder.build_pointer_cast(
                     binary.scratch.unwrap().as_pointer_value(),
                     binary.scratch.unwrap().as_pointer_value(),
                     binary.context.i8_type().ptr_type(AddressSpace::Generic),
                     binary.context.i8_type().ptr_type(AddressSpace::Generic),
@@ -4452,7 +4455,7 @@ impl<'a> TargetRuntime<'a> for SubstrateTarget {
                     "self_address",
                     "self_address",
                 )
                 )
             }
             }
-            ast::Expression::Builtin(_, _, ast::Builtin::Balance, _) => {
+            codegen::Expression::Builtin(_, _, ast::Builtin::Balance, _) => {
                 let scratch_buf = binary.builder.build_pointer_cast(
                 let scratch_buf = binary.builder.build_pointer_cast(
                     binary.scratch.unwrap().as_pointer_value(),
                     binary.scratch.unwrap().as_pointer_value(),
                     binary.context.i8_type().ptr_type(AddressSpace::Generic),
                     binary.context.i8_type().ptr_type(AddressSpace::Generic),

+ 2 - 0
src/lib.rs

@@ -1,3 +1,5 @@
+extern crate core;
+
 pub mod abi;
 pub mod abi;
 pub mod codegen;
 pub mod codegen;
 #[cfg(feature = "llvm")]
 #[cfg(feature = "llvm")]

+ 31 - 414
src/sema/ast.rs

@@ -4,7 +4,8 @@ pub use crate::parser::diagnostics::*;
 use crate::parser::pt;
 use crate::parser::pt;
 use crate::parser::pt::{CodeLocation, OptionalCodeLocation};
 use crate::parser::pt::{CodeLocation, OptionalCodeLocation};
 use crate::sema::yul::ast::{InlineAssembly, YulFunction};
 use crate::sema::yul::ast::{InlineAssembly, YulFunction};
-use crate::Target;
+use crate::sema::Recurse;
+use crate::{codegen, Target};
 use num_bigint::BigInt;
 use num_bigint::BigInt;
 use num_rational::BigRational;
 use num_rational::BigRational;
 use std::sync::Arc;
 use std::sync::Arc;
@@ -51,6 +52,12 @@ pub enum Type {
     Slice,
     Slice,
 }
 }
 
 
+pub trait RetrieveType {
+    /// Return the type for this expression. This assumes the expression has a single value,
+    /// panics will occur otherwise
+    fn ty(&self) -> Type;
+}
+
 impl Type {
 impl Type {
     pub fn get_type_size(&self) -> u16 {
     pub fn get_type_size(&self) -> u16 {
         match self {
         match self {
@@ -422,7 +429,7 @@ pub struct Namespace {
     pub next_id: usize,
     pub next_id: usize,
     /// For a variable reference at a location, give the constant value
     /// For a variable reference at a location, give the constant value
     /// This for use by the language server to show the value of a variable at a location
     /// This for use by the language server to show the value of a variable at a location
-    pub var_constants: HashMap<pt::Loc, Expression>,
+    pub var_constants: HashMap<pt::Loc, codegen::Expression>,
     /// Overrides for hover in the language server
     /// Overrides for hover in the language server
     pub hover_overrides: HashMap<pt::Loc, String>,
     pub hover_overrides: HashMap<pt::Loc, String>,
 }
 }
@@ -574,8 +581,17 @@ pub enum Expression {
         array: Box<Expression>,
         array: Box<Expression>,
         elem_ty: Type,
         elem_ty: Type,
     },
     },
-    StringCompare(pt::Loc, StringLocation, StringLocation),
-    StringConcat(pt::Loc, Type, StringLocation, StringLocation),
+    StringCompare(
+        pt::Loc,
+        StringLocation<Expression>,
+        StringLocation<Expression>,
+    ),
+    StringConcat(
+        pt::Loc,
+        Type,
+        StringLocation<Expression>,
+        StringLocation<Expression>,
+    ),
 
 
     Or(pt::Loc, Box<Expression>, Box<Expression>),
     Or(pt::Loc, Box<Expression>, Box<Expression>),
     And(pt::Loc, Box<Expression>, Box<Expression>),
     And(pt::Loc, Box<Expression>, Box<Expression>),
@@ -627,396 +643,11 @@ pub enum Expression {
     Builtin(pt::Loc, Vec<Type>, Builtin, Vec<Expression>),
     Builtin(pt::Loc, Vec<Type>, Builtin, Vec<Expression>),
     InterfaceId(pt::Loc, usize),
     InterfaceId(pt::Loc, usize),
     List(pt::Loc, Vec<Expression>),
     List(pt::Loc, Vec<Expression>),
-    // The remaining types are only generated during codegen
-    Keccak256(pt::Loc, Type, Vec<Expression>),
-    ReturnData(pt::Loc),
-    AbiEncode {
-        loc: pt::Loc,
-        tys: Vec<Type>,
-        packed: Vec<Expression>,
-        args: Vec<Expression>,
-    },
-    InternalFunctionCfg(usize),
-    Undefined(Type),
-    Poison,
 }
 }
 
 
-impl Expression {
-    /// 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, args) => Expression::StructLiteral(
-                    *loc,
-                    ty.clone(),
-                    args.iter().map(|e| filter(e, ctx)).collect(),
-                ),
-                Expression::ArrayLiteral(loc, ty, lengths, args) => Expression::ArrayLiteral(
-                    *loc,
-                    ty.clone(),
-                    lengths.clone(),
-                    args.iter().map(|e| filter(e, ctx)).collect(),
-                ),
-                Expression::ConstArrayLiteral(loc, ty, lengths, args) => {
-                    Expression::ConstArrayLiteral(
-                        *loc,
-                        ty.clone(),
-                        lengths.clone(),
-                        args.iter().map(|e| filter(e, ctx)).collect(),
-                    )
-                }
-                Expression::Add(loc, ty, unchecked, left, right) => Expression::Add(
-                    *loc,
-                    ty.clone(),
-                    *unchecked,
-                    Box::new(filter(left, ctx)),
-                    Box::new(filter(right, ctx)),
-                ),
-                Expression::Subtract(loc, ty, unchecked, left, right) => Expression::Subtract(
-                    *loc,
-                    ty.clone(),
-                    *unchecked,
-                    Box::new(filter(left, ctx)),
-                    Box::new(filter(right, ctx)),
-                ),
-                Expression::Multiply(loc, ty, unchecked, left, right) => Expression::Multiply(
-                    *loc,
-                    ty.clone(),
-                    *unchecked,
-                    Box::new(filter(left, ctx)),
-                    Box::new(filter(right, ctx)),
-                ),
-                Expression::Divide(loc, ty, left, right) => Expression::Divide(
-                    *loc,
-                    ty.clone(),
-                    Box::new(filter(left, ctx)),
-                    Box::new(filter(right, ctx)),
-                ),
-                Expression::Power(loc, ty, unchecked, left, right) => Expression::Power(
-                    *loc,
-                    ty.clone(),
-                    *unchecked,
-                    Box::new(filter(left, ctx)),
-                    Box::new(filter(right, ctx)),
-                ),
-                Expression::BitwiseOr(loc, ty, left, right) => Expression::BitwiseOr(
-                    *loc,
-                    ty.clone(),
-                    Box::new(filter(left, ctx)),
-                    Box::new(filter(right, ctx)),
-                ),
-                Expression::BitwiseAnd(loc, ty, left, right) => Expression::BitwiseAnd(
-                    *loc,
-                    ty.clone(),
-                    Box::new(filter(left, ctx)),
-                    Box::new(filter(right, ctx)),
-                ),
-                Expression::BitwiseXor(loc, ty, left, right) => Expression::BitwiseXor(
-                    *loc,
-                    ty.clone(),
-                    Box::new(filter(left, ctx)),
-                    Box::new(filter(right, ctx)),
-                ),
-                Expression::ShiftLeft(loc, ty, left, right) => Expression::ShiftLeft(
-                    *loc,
-                    ty.clone(),
-                    Box::new(filter(left, ctx)),
-                    Box::new(filter(right, ctx)),
-                ),
-                Expression::ShiftRight(loc, ty, left, right, sign_extend) => {
-                    Expression::ShiftRight(
-                        *loc,
-                        ty.clone(),
-                        Box::new(filter(left, ctx)),
-                        Box::new(filter(right, ctx)),
-                        *sign_extend,
-                    )
-                }
-                Expression::Load(loc, ty, expr) => {
-                    Expression::Load(*loc, ty.clone(), Box::new(filter(expr, ctx)))
-                }
-                Expression::StorageLoad(loc, ty, expr) => {
-                    Expression::StorageLoad(*loc, ty.clone(), Box::new(filter(expr, ctx)))
-                }
-                Expression::ZeroExt(loc, ty, expr) => {
-                    Expression::ZeroExt(*loc, ty.clone(), Box::new(filter(expr, ctx)))
-                }
-                Expression::SignExt(loc, ty, expr) => {
-                    Expression::SignExt(*loc, ty.clone(), Box::new(filter(expr, ctx)))
-                }
-                Expression::Trunc(loc, ty, expr) => {
-                    Expression::Trunc(*loc, ty.clone(), Box::new(filter(expr, ctx)))
-                }
-                Expression::Cast(loc, ty, expr) => {
-                    Expression::Cast(*loc, ty.clone(), Box::new(filter(expr, ctx)))
-                }
-                Expression::BytesCast(loc, ty, from, expr) => Expression::BytesCast(
-                    *loc,
-                    ty.clone(),
-                    from.clone(),
-                    Box::new(filter(expr, ctx)),
-                ),
-                Expression::PreIncrement(loc, ty, unchecked, expr) => Expression::PreIncrement(
-                    *loc,
-                    ty.clone(),
-                    *unchecked,
-                    Box::new(filter(expr, ctx)),
-                ),
-                Expression::PreDecrement(loc, ty, unchecked, expr) => Expression::PreDecrement(
-                    *loc,
-                    ty.clone(),
-                    *unchecked,
-                    Box::new(filter(expr, ctx)),
-                ),
-                Expression::PostIncrement(loc, ty, unchecked, expr) => Expression::PostIncrement(
-                    *loc,
-                    ty.clone(),
-                    *unchecked,
-                    Box::new(filter(expr, ctx)),
-                ),
-                Expression::PostDecrement(loc, ty, unchecked, expr) => Expression::PostDecrement(
-                    *loc,
-                    ty.clone(),
-                    *unchecked,
-                    Box::new(filter(expr, ctx)),
-                ),
-                Expression::Assign(loc, ty, left, right) => Expression::Assign(
-                    *loc,
-                    ty.clone(),
-                    Box::new(filter(left, ctx)),
-                    Box::new(filter(right, ctx)),
-                ),
-                Expression::More(loc, left, right) => Expression::More(
-                    *loc,
-                    Box::new(filter(left, ctx)),
-                    Box::new(filter(right, ctx)),
-                ),
-                Expression::Less(loc, left, right) => Expression::Less(
-                    *loc,
-                    Box::new(filter(left, ctx)),
-                    Box::new(filter(right, ctx)),
-                ),
-                Expression::MoreEqual(loc, left, right) => Expression::MoreEqual(
-                    *loc,
-                    Box::new(filter(left, ctx)),
-                    Box::new(filter(right, ctx)),
-                ),
-                Expression::LessEqual(loc, left, right) => Expression::LessEqual(
-                    *loc,
-                    Box::new(filter(left, ctx)),
-                    Box::new(filter(right, ctx)),
-                ),
-                Expression::Equal(loc, left, right) => Expression::Equal(
-                    *loc,
-                    Box::new(filter(left, ctx)),
-                    Box::new(filter(right, ctx)),
-                ),
-                Expression::NotEqual(loc, left, right) => Expression::NotEqual(
-                    *loc,
-                    Box::new(filter(left, ctx)),
-                    Box::new(filter(right, ctx)),
-                ),
-                Expression::Not(loc, expr) => Expression::Not(*loc, Box::new(filter(expr, ctx))),
-                Expression::Complement(loc, ty, expr) => {
-                    Expression::Complement(*loc, ty.clone(), Box::new(filter(expr, ctx)))
-                }
-                Expression::UnaryMinus(loc, ty, expr) => {
-                    Expression::UnaryMinus(*loc, ty.clone(), Box::new(filter(expr, ctx)))
-                }
-                Expression::Ternary(loc, ty, cond, left, right) => Expression::Ternary(
-                    *loc,
-                    ty.clone(),
-                    Box::new(filter(cond, ctx)),
-                    Box::new(filter(left, ctx)),
-                    Box::new(filter(right, ctx)),
-                ),
-                Expression::Subscript(loc, elem_ty, array_ty, left, right) => {
-                    Expression::Subscript(
-                        *loc,
-                        elem_ty.clone(),
-                        array_ty.clone(),
-                        Box::new(filter(left, ctx)),
-                        Box::new(filter(right, ctx)),
-                    )
-                }
-                Expression::StructMember(loc, ty, expr, field) => {
-                    Expression::StructMember(*loc, ty.clone(), Box::new(filter(expr, ctx)), *field)
-                }
-                Expression::AllocDynamicArray(loc, ty, expr, initializer) => {
-                    Expression::AllocDynamicArray(
-                        *loc,
-                        ty.clone(),
-                        Box::new(filter(expr, ctx)),
-                        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,
-                    match left {
-                        StringLocation::CompileTime(_) => left.clone(),
-                        StringLocation::RunTime(expr) => {
-                            StringLocation::RunTime(Box::new(filter(expr, ctx)))
-                        }
-                    },
-                    match right {
-                        StringLocation::CompileTime(_) => right.clone(),
-                        StringLocation::RunTime(expr) => {
-                            StringLocation::RunTime(Box::new(filter(expr, ctx)))
-                        }
-                    },
-                ),
-                Expression::StringConcat(loc, ty, left, right) => Expression::StringConcat(
-                    *loc,
-                    ty.clone(),
-                    match left {
-                        StringLocation::CompileTime(_) => left.clone(),
-                        StringLocation::RunTime(expr) => {
-                            StringLocation::RunTime(Box::new(filter(expr, ctx)))
-                        }
-                    },
-                    match right {
-                        StringLocation::CompileTime(_) => right.clone(),
-                        StringLocation::RunTime(expr) => {
-                            StringLocation::RunTime(Box::new(filter(expr, ctx)))
-                        }
-                    },
-                ),
-                Expression::Or(loc, left, right) => Expression::Or(
-                    *loc,
-                    Box::new(filter(left, ctx)),
-                    Box::new(filter(right, ctx)),
-                ),
-                Expression::And(loc, left, right) => Expression::And(
-                    *loc,
-                    Box::new(filter(left, ctx)),
-                    Box::new(filter(right, ctx)),
-                ),
-                Expression::ExternalFunction {
-                    loc,
-                    ty,
-                    address,
-                    function_no,
-                } => Expression::ExternalFunction {
-                    loc: *loc,
-                    ty: ty.clone(),
-                    address: Box::new(filter(address, ctx)),
-                    function_no: *function_no,
-                },
-                Expression::InternalFunctionCall {
-                    loc,
-                    returns,
-                    function,
-                    args,
-                } => Expression::InternalFunctionCall {
-                    loc: *loc,
-                    returns: returns.clone(),
-                    function: Box::new(filter(function, ctx)),
-                    args: args.iter().map(|e| filter(e, ctx)).collect(),
-                },
-                Expression::ExternalFunctionCall {
-                    loc,
-                    returns,
-                    function,
-                    args,
-                    value,
-                    gas,
-                } => Expression::ExternalFunctionCall {
-                    loc: *loc,
-                    returns: returns.clone(),
-                    function: Box::new(filter(function, ctx)),
-                    args: args.iter().map(|e| filter(e, ctx)).collect(),
-                    value: value.as_ref().map(|value| Box::new(filter(value, ctx))),
-                    gas: gas.as_ref().map(|gas| Box::new(filter(gas, ctx))),
-                },
-                Expression::ExternalFunctionCallRaw {
-                    loc,
-                    ty,
-                    address,
-                    args,
-                    value,
-                    gas,
-                } => Expression::ExternalFunctionCallRaw {
-                    loc: *loc,
-                    ty: ty.clone(),
-                    address: Box::new(filter(address, ctx)),
-                    args: Box::new(filter(args, ctx)),
-                    value: value.as_ref().map(|value| Box::new(filter(value, ctx))),
-                    gas: gas.as_ref().map(|gas| Box::new(filter(gas, ctx))),
-                },
-                Expression::Constructor {
-                    loc,
-                    contract_no,
-                    constructor_no,
-                    args,
-                    gas,
-                    value,
-                    salt,
-                    space,
-                } => Expression::Constructor {
-                    loc: *loc,
-                    contract_no: *contract_no,
-                    constructor_no: *constructor_no,
-                    args: args.iter().map(|e| filter(e, ctx)).collect(),
-                    value: value.as_ref().map(|e| Box::new(filter(e, ctx))),
-                    gas: gas.as_ref().map(|e| Box::new(filter(e, ctx))),
-                    salt: salt.as_ref().map(|e| Box::new(filter(e, ctx))),
-                    space: space.as_ref().map(|e| Box::new(filter(e, ctx))),
-                },
-                Expression::Keccak256(loc, ty, args) => {
-                    let args = args.iter().map(|e| filter(e, ctx)).collect();
-
-                    Expression::Keccak256(*loc, ty.clone(), args)
-                }
-                Expression::FormatString(loc, args) => {
-                    let args = args.iter().map(|(f, e)| (*f, filter(e, ctx))).collect();
-
-                    Expression::FormatString(*loc, args)
-                }
-                Expression::Builtin(loc, tys, builtin, args) => {
-                    let args = args.iter().map(|e| filter(e, ctx)).collect();
-
-                    Expression::Builtin(*loc, tys.clone(), *builtin, args)
-                }
-                Expression::AbiEncode {
-                    loc,
-                    tys,
-                    packed,
-                    args,
-                } => {
-                    let packed = packed.iter().map(|e| filter(e, ctx)).collect();
-                    let args = args.iter().map(|e| filter(e, ctx)).collect();
-
-                    Expression::AbiEncode {
-                        loc: *loc,
-                        tys: tys.clone(),
-                        packed,
-                        args,
-                    }
-                }
-                _ => self.clone(),
-            },
-            ctx,
-        )
-    }
-
-    /// recurse over the expression
-    pub fn recurse<T>(&self, cx: &mut T, f: fn(expr: &Expression, ctx: &mut T) -> bool) {
+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) {
         if f(self, cx) {
             match self {
             match self {
                 Expression::StructLiteral(_, _, exprs)
                 Expression::StructLiteral(_, _, exprs)
@@ -1156,21 +787,11 @@ impl Expression {
                         salt.recurse(cx, f);
                         salt.recurse(cx, f);
                     }
                     }
                 }
                 }
-                Expression::Builtin(_, _, _, exprs)
-                | Expression::List(_, exprs)
-                | Expression::Keccak256(_, _, exprs) => {
+                Expression::Builtin(_, _, _, exprs) | Expression::List(_, exprs) => {
                     for e in exprs {
                     for e in exprs {
                         e.recurse(cx, f);
                         e.recurse(cx, f);
                     }
                     }
                 }
                 }
-                Expression::AbiEncode { packed, args, .. } => {
-                    for e in packed {
-                        e.recurse(cx, f);
-                    }
-                    for e in args {
-                        e.recurse(cx, f);
-                    }
-                }
                 _ => (),
                 _ => (),
             }
             }
         }
         }
@@ -1229,8 +850,6 @@ impl CodeLocation for Expression {
             | Expression::StorageArrayLength { loc, .. }
             | Expression::StorageArrayLength { loc, .. }
             | Expression::StringCompare(loc, ..)
             | Expression::StringCompare(loc, ..)
             | Expression::StringConcat(loc, ..)
             | Expression::StringConcat(loc, ..)
-            | Expression::Keccak256(loc, ..)
-            | Expression::ReturnData(loc)
             | Expression::InternalFunction { loc, .. }
             | Expression::InternalFunction { loc, .. }
             | Expression::ExternalFunction { loc, .. }
             | Expression::ExternalFunction { loc, .. }
             | Expression::InternalFunctionCall { loc, .. }
             | Expression::InternalFunctionCall { loc, .. }
@@ -1245,12 +864,8 @@ impl CodeLocation for Expression {
             | Expression::Assign(loc, ..)
             | Expression::Assign(loc, ..)
             | Expression::List(loc, _)
             | Expression::List(loc, _)
             | Expression::FormatString(loc, _)
             | Expression::FormatString(loc, _)
-            | Expression::AbiEncode { loc, .. }
             | Expression::InterfaceId(loc, ..)
             | Expression::InterfaceId(loc, ..)
             | Expression::And(loc, ..) => *loc,
             | Expression::And(loc, ..) => *loc,
-            Expression::InternalFunctionCfg(_) | Expression::Undefined(_) | Expression::Poison => {
-                unreachable!()
-            }
         }
         }
     }
     }
 }
 }
@@ -1275,9 +890,9 @@ impl fmt::Display for FormatArg {
 }
 }
 
 
 #[derive(PartialEq, Clone, Debug)]
 #[derive(PartialEq, Clone, Debug)]
-pub enum StringLocation {
+pub enum StringLocation<T> {
     CompileTime(Vec<u8>),
     CompileTime(Vec<u8>),
-    RunTime(Box<Expression>),
+    RunTime(Box<T>),
 }
 }
 
 
 #[derive(PartialEq, Clone, Copy, Debug)]
 #[derive(PartialEq, Clone, Copy, Debug)]
@@ -1439,9 +1054,9 @@ impl OptionalCodeLocation for DestructureField {
     }
     }
 }
 }
 
 
-impl Statement {
-    /// recurse over the statement
-    pub fn recurse<T>(&self, cx: &mut T, f: fn(stmt: &Statement, ctx: &mut T) -> bool) {
+impl Recurse for Statement {
+    type ArgType = Statement;
+    fn recurse<T>(&self, cx: &mut T, f: fn(stmt: &Statement, ctx: &mut T) -> bool) {
         if f(self, cx) {
         if f(self, cx) {
             match self {
             match self {
                 Statement::Block { statements, .. } => {
                 Statement::Block { statements, .. } => {
@@ -1502,7 +1117,9 @@ impl Statement {
             }
             }
         }
         }
     }
     }
+}
 
 
+impl Statement {
     /// Shorthand for checking underscore
     /// Shorthand for checking underscore
     pub fn is_underscore(&self) -> bool {
     pub fn is_underscore(&self) -> bool {
         matches!(&self, Statement::Underscore(_))
         matches!(&self, Statement::Underscore(_))

+ 17 - 50
src/sema/builtin.rs

@@ -2,10 +2,11 @@ use super::ast::{
     Builtin, BuiltinStruct, Diagnostic, Expression, Namespace, Parameter, StructDecl, Symbol, Type,
     Builtin, BuiltinStruct, Diagnostic, Expression, Namespace, Parameter, StructDecl, Symbol, Type,
 };
 };
 use super::eval::eval_const_number;
 use super::eval::eval_const_number;
-use super::expression::{cast, expression, ExprContext, ResolveTo};
+use super::expression::{expression, ExprContext, ResolveTo};
 use super::symtable::Symtable;
 use super::symtable::Symtable;
 use crate::parser::pt;
 use crate::parser::pt;
 use crate::parser::pt::CodeLocation;
 use crate::parser::pt::CodeLocation;
+use crate::sema::ast::RetrieveType;
 use crate::Target;
 use crate::Target;
 use num_bigint::BigInt;
 use num_bigint::BigInt;
 use num_traits::One;
 use num_traits::One;
@@ -902,14 +903,7 @@ pub fn resolve_call(
                 }
                 }
             };
             };
 
 
-            match cast(
-                &arg.loc(),
-                arg.clone(),
-                &func.args[i],
-                true,
-                ns,
-                diagnostics,
-            ) {
+            match arg.cast(&arg.loc(), &func.args[i], true, ns, diagnostics) {
                 Ok(expr) => cast_args.push(expr),
                 Ok(expr) => cast_args.push(expr),
                 Err(()) => {
                 Err(()) => {
                     matches = false;
                     matches = false;
@@ -1004,21 +998,15 @@ pub fn resolve_namespace_call(
         }
         }
 
 
         // first args
         // first args
-        let data = cast(
-            &args[0].loc(),
-            expression(
-                &args[0],
-                context,
-                ns,
-                symtable,
-                diagnostics,
-                ResolveTo::Type(&Type::DynamicBytes),
-            )?,
-            &Type::DynamicBytes,
-            true,
+        let data = expression(
+            &args[0],
+            context,
             ns,
             ns,
+            symtable,
             diagnostics,
             diagnostics,
-        )?;
+            ResolveTo::Type(&Type::DynamicBytes),
+        )?
+        .cast(&args[0].loc(), &Type::DynamicBytes, true, ns, diagnostics)?;
 
 
         let mut tys = Vec::new();
         let mut tys = Vec::new();
         let mut broken = false;
         let mut broken = false;
@@ -1118,14 +1106,7 @@ pub fn resolve_namespace_call(
 
 
                 resolved_args.insert(
                 resolved_args.insert(
                     0,
                     0,
-                    cast(
-                        &selector.loc(),
-                        selector,
-                        &Type::Bytes(4),
-                        true,
-                        ns,
-                        diagnostics,
-                    )?,
+                    selector.cast(&selector.loc(), &Type::Bytes(4), true, ns, diagnostics)?,
                 );
                 );
             } else {
             } else {
                 diagnostics.push(Diagnostic::error(
                 diagnostics.push(Diagnostic::error(
@@ -1176,12 +1157,12 @@ pub fn resolve_namespace_call(
                                 ResolveTo::Type(&params[arg_no]),
                                 ResolveTo::Type(&params[arg_no]),
                             )?;
                             )?;
 
 
-                            expr = cast(&arg.loc(), expr, &params[arg_no], true, ns, diagnostics)?;
+                            expr = expr.cast(&arg.loc(), &params[arg_no], true, ns, diagnostics)?;
 
 
                             // A string or hex literal should be encoded as a string
                             // A string or hex literal should be encoded as a string
                             if let Expression::BytesLiteral(..) = &expr {
                             if let Expression::BytesLiteral(..) = &expr {
                                 expr =
                                 expr =
-                                    cast(&arg.loc(), expr, &Type::String, true, ns, diagnostics)?;
+                                    expr.cast(&arg.loc(), &Type::String, true, ns, diagnostics)?;
                             }
                             }
 
 
                             resolved_args.push(expr);
                             resolved_args.push(expr);
@@ -1229,14 +1210,7 @@ pub fn resolve_namespace_call(
 
 
                 resolved_args.insert(
                 resolved_args.insert(
                     0,
                     0,
-                    cast(
-                        &signature.loc(),
-                        signature,
-                        &Type::String,
-                        true,
-                        ns,
-                        diagnostics,
-                    )?,
+                    signature.cast(&signature.loc(), &Type::String, true, ns, diagnostics)?,
                 );
                 );
             } else {
             } else {
                 diagnostics.push(Diagnostic::error(
                 diagnostics.push(Diagnostic::error(
@@ -1263,11 +1237,11 @@ pub fn resolve_namespace_call(
             return Err(());
             return Err(());
         }
         }
 
 
-        expr = cast(&arg.loc(), expr, ty.deref_any(), true, ns, diagnostics)?;
+        expr = expr.cast(&arg.loc(), ty.deref_any(), true, ns, diagnostics)?;
 
 
         // A string or hex literal should be encoded as a string
         // A string or hex literal should be encoded as a string
         if let Expression::BytesLiteral(..) = &expr {
         if let Expression::BytesLiteral(..) = &expr {
-            expr = cast(&arg.loc(), expr, &Type::String, true, ns, diagnostics)?;
+            expr = expr.cast(&arg.loc(), &Type::String, true, ns, diagnostics)?;
         }
         }
 
 
         resolved_args.push(expr);
         resolved_args.push(expr);
@@ -1343,14 +1317,7 @@ pub fn resolve_method_call(
                 }
                 }
             };
             };
 
 
-            match cast(
-                &arg.loc(),
-                arg.clone(),
-                &func.args[i],
-                true,
-                ns,
-                diagnostics,
-            ) {
+            match arg.cast(&arg.loc(), &func.args[i], true, ns, diagnostics) {
                 Ok(expr) => cast_args.push(expr),
                 Ok(expr) => cast_args.push(expr),
                 Err(()) => {
                 Err(()) => {
                     matches = false;
                     matches = false;

+ 1 - 10
src/sema/dotgraphviz.rs

@@ -1195,21 +1195,12 @@ impl Dot {
                     self.add_expression(expr, func, ns, node, format!("entry #{}", no));
                     self.add_expression(expr, func, ns, node, format!("entry #{}", no));
                 }
                 }
             }
             }
-
-            Expression::InternalFunctionCfg(..)
-            | Expression::ReturnData(..)
-            | Expression::Poison
-            | Expression::AbiEncode { .. }
-            | Expression::Undefined(..)
-            | Expression::Keccak256(..) => {
-                panic!("should not present in ast");
-            }
         }
         }
     }
     }
 
 
     fn add_string_location(
     fn add_string_location(
         &mut self,
         &mut self,
-        loc: &StringLocation,
+        loc: &StringLocation<Expression>,
         func: Option<&Function>,
         func: Option<&Function>,
         ns: &Namespace,
         ns: &Namespace,
         parent: usize,
         parent: usize,

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 543 - 675
src/sema/expression.rs


+ 6 - 2
src/sema/format.rs

@@ -1,8 +1,9 @@
 use super::ast::{Diagnostic, Expression, FormatArg, Namespace, Type};
 use super::ast::{Diagnostic, Expression, FormatArg, Namespace, Type};
-use super::expression::{cast, expression, ExprContext, ResolveTo};
+use super::expression::{expression, ExprContext, ResolveTo};
 use super::symtable::Symtable;
 use super::symtable::Symtable;
 use crate::parser::pt;
 use crate::parser::pt;
 use crate::parser::pt::CodeLocation;
 use crate::parser::pt::CodeLocation;
+use crate::sema::ast::RetrieveType;
 
 
 use std::iter::Peekable;
 use std::iter::Peekable;
 use std::slice::Iter;
 use std::slice::Iter;
@@ -29,7 +30,10 @@ pub fn string_format(
 
 
         let ty = expr.ty();
         let ty = expr.ty();
 
 
-        resolved_args.push(cast(&arg.loc(), expr, ty.deref_any(), true, ns, diagnostics).unwrap());
+        resolved_args.push(
+            expr.cast(&arg.loc(), ty.deref_any(), true, ns, diagnostics)
+                .unwrap(),
+        );
     }
     }
 
 
     let mut format_iterator = FormatIterator::new(literals).peekable();
     let mut format_iterator = FormatIterator::new(literals).peekable();

+ 7 - 0
src/sema/mod.rs

@@ -1,4 +1,5 @@
 use crate::parser::{parse, pt};
 use crate::parser::{parse, pt};
+use crate::sema::ast::RetrieveType;
 use crate::Target;
 use crate::Target;
 use ast::{Diagnostic, Mutability};
 use ast::{Diagnostic, Mutability};
 use num_bigint::BigInt;
 use num_bigint::BigInt;
@@ -1591,3 +1592,9 @@ impl ast::Symbol {
         }
         }
     }
     }
 }
 }
+
+pub trait Recurse {
+    type ArgType;
+    /// recurse over a structure
+    fn recurse<T>(&self, cx: &mut T, f: fn(expr: &Self::ArgType, ctx: &mut T) -> bool);
+}

+ 2 - 0
src/sema/mutability.rs

@@ -4,7 +4,9 @@ use super::ast::{
 };
 };
 use super::diagnostics;
 use super::diagnostics;
 use crate::parser::pt;
 use crate::parser::pt;
+use crate::sema::ast::RetrieveType;
 use crate::sema::yul::ast::{YulExpression, YulStatement};
 use crate::sema::yul::ast::{YulExpression, YulStatement};
+use crate::sema::Recurse;
 
 
 /// check state mutability
 /// check state mutability
 pub fn mutability(file_no: usize, ns: &mut Namespace) {
 pub fn mutability(file_no: usize, ns: &mut Namespace) {

+ 12 - 21
src/sema/statements.rs

@@ -1,7 +1,7 @@
 use super::ast::*;
 use super::ast::*;
 use super::contracts::is_base;
 use super::contracts::is_base;
 use super::expression::{
 use super::expression::{
-    available_functions, call_expr, call_position_args, cast, constructor_named_args, expression,
+    available_functions, call_expr, call_position_args, constructor_named_args, expression,
     function_call_expr, match_constructor_to_args, named_call_expr, named_function_call_expr, new,
     function_call_expr, match_constructor_to_args, named_call_expr, named_function_call_expr, new,
     ExprContext, ResolveTo,
     ExprContext, ResolveTo,
 };
 };
@@ -14,6 +14,7 @@ use crate::sema::builtin;
 use crate::sema::symtable::{VariableInitializer, VariableUsage};
 use crate::sema::symtable::{VariableInitializer, VariableUsage};
 use crate::sema::unused_variable::{assigned_variable, check_function_call, used_variable};
 use crate::sema::unused_variable::{assigned_variable, check_function_call, used_variable};
 use crate::sema::yul::resolve_inline_assembly;
 use crate::sema::yul::resolve_inline_assembly;
+use crate::sema::Recurse;
 use std::collections::{BTreeMap, HashMap, HashSet};
 use std::collections::{BTreeMap, HashMap, HashSet};
 use std::sync::Arc;
 use std::sync::Arc;
 
 
@@ -328,9 +329,8 @@ fn statement(
 
 
                 used_variable(ns, &expr, symtable);
                 used_variable(ns, &expr, symtable);
 
 
-                Some(Arc::new(cast(
+                Some(Arc::new(expr.cast(
                     &expr.loc(),
                     &expr.loc(),
-                    expr,
                     &var_ty,
                     &var_ty,
                     true,
                     true,
                     ns,
                     ns,
@@ -427,7 +427,7 @@ fn statement(
                 ResolveTo::Type(&Type::Bool),
                 ResolveTo::Type(&Type::Bool),
             )?;
             )?;
             used_variable(ns, &expr, symtable);
             used_variable(ns, &expr, symtable);
-            let cond = cast(&expr.loc(), expr, &Type::Bool, true, ns, diagnostics)?;
+            let cond = expr.cast(&expr.loc(), &Type::Bool, true, ns, diagnostics)?;
 
 
             symtable.new_scope();
             symtable.new_scope();
             let mut body_stmts = Vec::new();
             let mut body_stmts = Vec::new();
@@ -458,7 +458,7 @@ fn statement(
                 ResolveTo::Type(&Type::Bool),
                 ResolveTo::Type(&Type::Bool),
             )?;
             )?;
             used_variable(ns, &expr, symtable);
             used_variable(ns, &expr, symtable);
-            let cond = cast(&expr.loc(), expr, &Type::Bool, true, ns, diagnostics)?;
+            let cond = expr.cast(&expr.loc(), &Type::Bool, true, ns, diagnostics)?;
 
 
             symtable.new_scope();
             symtable.new_scope();
             let mut body_stmts = Vec::new();
             let mut body_stmts = Vec::new();
@@ -489,7 +489,7 @@ fn statement(
             )?;
             )?;
             used_variable(ns, &expr, symtable);
             used_variable(ns, &expr, symtable);
 
 
-            let cond = cast(&expr.loc(), expr, &Type::Bool, true, ns, diagnostics)?;
+            let cond = expr.cast(&expr.loc(), &Type::Bool, true, ns, diagnostics)?;
 
 
             symtable.new_scope();
             symtable.new_scope();
             let mut then_stmts = Vec::new();
             let mut then_stmts = Vec::new();
@@ -623,7 +623,7 @@ fn statement(
                 ResolveTo::Type(&Type::Bool),
                 ResolveTo::Type(&Type::Bool),
             )?;
             )?;
 
 
-            let cond = cast(&cond_expr.loc(), expr, &Type::Bool, true, ns, diagnostics)?;
+            let cond = expr.cast(&cond_expr.loc(), &Type::Bool, true, ns, diagnostics)?;
 
 
             // continue goes to next, and if that does exist, cond
             // continue goes to next, and if that does exist, cond
             loops.new_scope();
             loops.new_scope();
@@ -937,14 +937,7 @@ fn emit_event(
                     };
                     };
                     used_variable(ns, &arg, symtable);
                     used_variable(ns, &arg, symtable);
 
 
-                    match cast(
-                        &arg.loc(),
-                        arg.clone(),
-                        &ty,
-                        true,
-                        ns,
-                        &mut temp_diagnostics,
-                    ) {
+                    match arg.cast(&arg.loc(), &ty, true, ns, &mut temp_diagnostics) {
                         Ok(expr) => cast_args.push(expr),
                         Ok(expr) => cast_args.push(expr),
                         Err(_) => {
                         Err(_) => {
                             matches = false;
                             matches = false;
@@ -1087,7 +1080,7 @@ fn emit_event(
 
 
                     used_variable(ns, &arg, symtable);
                     used_variable(ns, &arg, symtable);
 
 
-                    match cast(&arg.loc(), arg, &param.ty, true, ns, &mut temp_diagnostics) {
+                    match arg.cast(&arg.loc(), &param.ty, true, ns, &mut temp_diagnostics) {
                         Ok(expr) => cast_args.push(expr),
                         Ok(expr) => cast_args.push(expr),
                         Err(_) => {
                         Err(_) => {
                             matches = false;
                             matches = false;
@@ -1418,9 +1411,8 @@ fn destructure_values(
     for (i, field) in fields.iter().enumerate() {
     for (i, field) in fields.iter().enumerate() {
         if let Some(left_ty) = &left_tys[i] {
         if let Some(left_ty) = &left_tys[i] {
             let loc = field.loc().unwrap();
             let loc = field.loc().unwrap();
-            let _ = cast(
+            let _ = Expression::FunctionArg(loc, right_tys[i].clone(), i).cast(
                 &loc,
                 &loc,
-                Expression::FunctionArg(loc, right_tys[i].clone(), i),
                 left_ty,
                 left_ty,
                 true,
                 true,
                 ns,
                 ns,
@@ -1593,7 +1585,7 @@ fn return_with_values(
                     diagnostics,
                     diagnostics,
                     ResolveTo::Type(&return_ty),
                     ResolveTo::Type(&return_ty),
                 )?;
                 )?;
-                let expr = cast(loc, expr, &return_ty, true, ns, diagnostics)?;
+                let expr = expr.cast(loc, &return_ty, true, ns, diagnostics)?;
                 used_variable(ns, &expr, symtable);
                 used_variable(ns, &expr, symtable);
                 exprs.push(expr);
                 exprs.push(expr);
             }
             }
@@ -1657,9 +1649,8 @@ fn return_with_values(
         .zip(func_returns_tys)
         .zip(func_returns_tys)
         .enumerate()
         .enumerate()
         .map(|(i, (expr_return_ty, func_return_ty))| {
         .map(|(i, (expr_return_ty, func_return_ty))| {
-            cast(
+            Expression::FunctionArg(expr_returns.loc(), expr_return_ty, i).cast(
                 &expr_returns.loc(),
                 &expr_returns.loc(),
-                Expression::FunctionArg(expr_returns.loc(), expr_return_ty, i),
                 &func_return_ty,
                 &func_return_ty,
                 true,
                 true,
                 ns,
                 ns,

+ 7 - 7
src/sema/tests/mod.rs

@@ -24,7 +24,7 @@ fn test_statement_reachable() {
     let test_cases: Vec<(Statement, bool)> = vec![
     let test_cases: Vec<(Statement, bool)> = vec![
         (Statement::Underscore(loc), true),
         (Statement::Underscore(loc), true),
         (
         (
-            Statement::Destructure(loc, vec![], Expression::Undefined(Type::Bool)),
+            Statement::Destructure(loc, vec![], Expression::BoolLiteral(loc, true)),
             true,
             true,
         ),
         ),
         (
         (
@@ -53,7 +53,7 @@ fn test_statement_reachable() {
             true,
             true,
         ),
         ),
         (
         (
-            Statement::Delete(loc, Type::Bool, Expression::Undefined(Type::Bool)),
+            Statement::Delete(loc, Type::Bool, Expression::BoolLiteral(loc, true)),
             true,
             true,
         ),
         ),
         (Statement::Continue(loc), false),
         (Statement::Continue(loc), false),
@@ -63,22 +63,22 @@ fn test_statement_reachable() {
             Statement::If(
             Statement::If(
                 loc,
                 loc,
                 false,
                 false,
-                Expression::Undefined(Type::Bool),
+                Expression::BoolLiteral(loc, false),
                 vec![],
                 vec![],
                 vec![],
                 vec![],
             ),
             ),
             false,
             false,
         ),
         ),
         (
         (
-            Statement::While(loc, true, Expression::Undefined(Type::Bool), vec![]),
+            Statement::While(loc, true, Expression::BoolLiteral(loc, false), vec![]),
             true,
             true,
         ),
         ),
         (
         (
-            Statement::DoWhile(loc, false, vec![], Expression::Undefined(Type::Bool)),
+            Statement::DoWhile(loc, false, vec![], Expression::BoolLiteral(loc, true)),
             false,
             false,
         ),
         ),
         (
         (
-            Statement::Expression(loc, true, Expression::Undefined(Type::Bool)),
+            Statement::Expression(loc, true, Expression::BoolLiteral(loc, false)),
             true,
             true,
         ),
         ),
         (
         (
@@ -97,7 +97,7 @@ fn test_statement_reachable() {
                 loc,
                 loc,
                 true,
                 true,
                 TryCatch {
                 TryCatch {
-                    expr: Expression::Poison,
+                    expr: Expression::BoolLiteral(loc, false),
                     returns: vec![],
                     returns: vec![],
                     ok_stmt: vec![],
                     ok_stmt: vec![],
                     errors: vec![],
                     errors: vec![],

+ 2 - 2
src/sema/variables.rs

@@ -2,7 +2,7 @@ use super::ast::{
     BuiltinStruct, Diagnostic, Expression, Function, Namespace, Parameter, Statement, Symbol, Type,
     BuiltinStruct, Diagnostic, Expression, Function, Namespace, Parameter, Statement, Symbol, Type,
     Variable,
     Variable,
 };
 };
-use super::expression::{cast, expression, ExprContext, ResolveTo};
+use super::expression::{expression, ExprContext, ResolveTo};
 use super::symtable::Symtable;
 use super::symtable::Symtable;
 use super::tags::resolve_tags;
 use super::tags::resolve_tags;
 use crate::parser::pt;
 use crate::parser::pt;
@@ -259,7 +259,7 @@ pub fn var_decl(
         ) {
         ) {
             Ok(res) => {
             Ok(res) => {
                 // implicitly conversion to correct ty
                 // implicitly conversion to correct ty
-                match cast(&s.loc, res, &ty, true, ns, &mut diagnostics) {
+                match res.cast(&s.loc, &ty, true, ns, &mut diagnostics) {
                     Ok(res) => Some(res),
                     Ok(res) => Some(res),
                     Err(_) => {
                     Err(_) => {
                         ns.diagnostics.extend(diagnostics);
                         ns.diagnostics.extend(diagnostics);

+ 4 - 3
src/sema/yul/ast.rs

@@ -1,6 +1,7 @@
 use crate::ast::{Parameter, Type};
 use crate::ast::{Parameter, Type};
 use crate::sema::symtable::Symtable;
 use crate::sema::symtable::Symtable;
 use crate::sema::yul::builtin::YulBuiltInFunction;
 use crate::sema::yul::builtin::YulBuiltInFunction;
+use crate::sema::Recurse;
 use num_bigint::BigInt;
 use num_bigint::BigInt;
 use solang_parser::pt;
 use solang_parser::pt;
 use solang_parser::pt::{CodeLocation, StorageLocation};
 use solang_parser::pt::{CodeLocation, StorageLocation};
@@ -124,9 +125,9 @@ pub struct CaseBlock {
     pub block: YulBlock,
     pub block: YulBlock,
 }
 }
 
 
-impl YulExpression {
-    /// Recurse over the expressions
-    pub fn recurse<T>(&self, cx: &mut T, f: fn(expr: &YulExpression, ctx: &mut T) -> bool) {
+impl Recurse for YulExpression {
+    type ArgType = YulExpression;
+    fn recurse<T>(&self, cx: &mut T, f: fn(expr: &YulExpression, ctx: &mut T) -> bool) {
         if !f(self, cx) {
         if !f(self, cx) {
             return;
             return;
         }
         }

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů