فهرست منبع

codegen::Expression should have named fields (#1258)

* codegen::Expression should have named fields

Co-authored-by: Lucas Steuernagel <38472950+LucasSte@users.noreply.github.com>
Signed-off-by: Sean Young <sean@mess.org>
Sean Young 2 سال پیش
والد
کامیت
c5e430461b
55فایلهای تغییر یافته به همراه5937 افزوده شده و 3194 حذف شده
  1. 36 16
      src/bin/languageserver/mod.rs
  2. 19 6
      src/codegen/array_boundary.rs
  3. 242 145
      src/codegen/cfg.rs
  4. 532 175
      src/codegen/constant_folding.rs
  5. 5 5
      src/codegen/constructor.rs
  6. 68 14
      src/codegen/dead_storage.rs
  7. 128 74
      src/codegen/dispatch/solana.rs
  8. 142 53
      src/codegen/dispatch/substrate.rs
  9. 78 56
      src/codegen/encoding/borsh_encoding.rs
  10. 23 19
      src/codegen/encoding/buffer_validator.rs
  11. 427 175
      src/codegen/encoding/mod.rs
  12. 218 88
      src/codegen/encoding/scale_encoding.rs
  13. 5 2
      src/codegen/events/solana.rs
  14. 46 21
      src/codegen/events/substrate.rs
  15. 408 259
      src/codegen/expression.rs
  16. 631 332
      src/codegen/mod.rs
  17. 3 3
      src/codegen/reaching_definitions.rs
  18. 14 15
      src/codegen/solana_accounts.rs
  19. 259 172
      src/codegen/solana_deploy.rs
  20. 126 63
      src/codegen/statements.rs
  21. 147 71
      src/codegen/storage.rs
  22. 33 23
      src/codegen/strength_reduce/expression_values.rs
  23. 142 86
      src/codegen/strength_reduce/mod.rs
  24. 437 218
      src/codegen/strength_reduce/tests.rs
  25. 2 2
      src/codegen/subexpression_elimination/available_expression.rs
  26. 25 22
      src/codegen/subexpression_elimination/available_expression_set.rs
  27. 9 9
      src/codegen/subexpression_elimination/common_subexpression_tracker.rs
  28. 249 163
      src/codegen/subexpression_elimination/expression.rs
  29. 38 26
      src/codegen/subexpression_elimination/operator.rs
  30. 569 364
      src/codegen/subexpression_elimination/tests.rs
  31. 10 7
      src/codegen/undefined_variable.rs
  32. 18 13
      src/codegen/vector_to_slice.rs
  33. 209 141
      src/codegen/yul/builtin.rs
  34. 59 28
      src/codegen/yul/expression.rs
  35. 4 6
      src/codegen/yul/mod.rs
  36. 30 26
      src/codegen/yul/statements.rs
  37. 114 61
      src/codegen/yul/tests/expression.rs
  38. 249 132
      src/emit/expression.rs
  39. 7 7
      src/emit/instructions.rs
  40. 4 4
      src/emit/math.rs
  41. 68 17
      src/emit/solana/target.rs
  42. 5 5
      src/emit/strings.rs
  43. 43 14
      src/emit/substrate/target.rs
  44. 2 2
      src/sema/yul/expression.rs
  45. 1 1
      src/sema/yul/switch.rs
  46. 1 1
      src/sema/yul/types.rs
  47. 2 2
      tests/codegen_testcases/solidity/anticipated_expressions.sol
  48. 4 4
      tests/codegen_testcases/solidity/dead_storage.sol
  49. 4 4
      tests/codegen_testcases/solidity/unchecked_cse.sol
  50. 1 1
      tests/codegen_testcases/solidity/unused_variable_elimination.sol
  51. 12 12
      tests/codegen_testcases/yul/binary_arithmetic_builtins.sol
  52. 1 1
      tests/codegen_testcases/yul/cse_switch.sol
  53. 5 5
      tests/codegen_testcases/yul/expression.sol
  54. 2 2
      tests/codegen_testcases/yul/functions.sol
  55. 21 21
      tests/codegen_testcases/yul/statements.sol

+ 36 - 16
src/bin/languageserver/mod.rs

@@ -180,16 +180,36 @@ impl<'a> Builder<'a> {
                 let mut val = format!("{} {}", self.expanded_ty(&param.ty), param.name_as_str());
                 if let Some(expr) = self.ns.var_constants.get(loc) {
                     match expr {
-                        codegen::Expression::BytesLiteral(_, ast::Type::Bytes(_), bs)
-                        | codegen::Expression::BytesLiteral(_, ast::Type::DynamicBytes, bs) => {
-                            write!(val, " = hex\"{}\"", hex::encode(bs)).unwrap();
+                        codegen::Expression::BytesLiteral {
+                            ty: ast::Type::Bytes(_),
+                            value,
+                            ..
                         }
-                        codegen::Expression::BytesLiteral(_, ast::Type::String, bs) => {
-                            write!(val, " = \"{}\"", String::from_utf8_lossy(bs)).unwrap();
+                        | codegen::Expression::BytesLiteral {
+                            ty: ast::Type::DynamicBytes,
+                            value,
+                            ..
+                        } => {
+                            write!(val, " = hex\"{}\"", hex::encode(value)).unwrap();
                         }
-                        codegen::Expression::NumberLiteral(_, ast::Type::Uint(_), n)
-                        | codegen::Expression::NumberLiteral(_, ast::Type::Int(_), n) => {
-                            write!(val, " = {n}").unwrap();
+                        codegen::Expression::BytesLiteral {
+                            ty: ast::Type::String,
+                            value,
+                            ..
+                        } => {
+                            write!(val, " = \"{}\"", String::from_utf8_lossy(value)).unwrap();
+                        }
+                        codegen::Expression::NumberLiteral {
+                            ty: ast::Type::Uint(_),
+                            value,
+                            ..
+                        }
+                        | codegen::Expression::NumberLiteral {
+                            ty: ast::Type::Int(_),
+                            value,
+                            ..
+                        } => {
+                            write!(val, " = {value}").unwrap();
                         }
                         _ => (),
                     }
@@ -525,16 +545,16 @@ impl<'a> Builder<'a> {
 
                 if let Some(expr) = self.ns.var_constants.get(loc) {
                     match expr {
-                        codegen::Expression::BytesLiteral(_, ast::Type::Bytes(_), bs)
-                        | codegen::Expression::BytesLiteral(_, ast::Type::DynamicBytes, bs) => {
-                            write!(val, " hex\"{}\"", hex::encode(bs)).unwrap();
+                        codegen::Expression::BytesLiteral{ ty: ast::Type::Bytes(_), value, .. }
+                        | codegen::Expression::BytesLiteral{ ty: ast::Type::DynamicBytes, value, ..} => {
+                            write!(val, " hex\"{}\"", hex::encode(value)).unwrap();
                         }
-                        codegen::Expression::BytesLiteral(_, ast::Type::String, bs) => {
-                            write!(val, " \"{}\"", String::from_utf8_lossy(bs)).unwrap();
+                        codegen::Expression::BytesLiteral{ ty: ast::Type::String, value, ..} => {
+                            write!(val, " \"{}\"", String::from_utf8_lossy(value)).unwrap();
                         }
-                        codegen::Expression::NumberLiteral(_, ast::Type::Uint(_), n)
-                        | codegen::Expression::NumberLiteral(_, ast::Type::Int(_), n) => {
-                            write!(val, " {n}").unwrap();
+                        codegen::Expression::NumberLiteral { ty: ast::Type::Uint(_), value, .. }
+                        | codegen::Expression::NumberLiteral { ty: ast::Type::Int(_), value, .. } => {
+                            write!(val, " {value}").unwrap();
                         }
                         _ => (),
                     }

+ 19 - 6
src/codegen/array_boundary.rs

@@ -18,7 +18,13 @@ pub(crate) fn handle_array_assign(
     vartab: &mut Vartable,
     pos: usize,
 ) -> Expression {
-    if let Expression::AllocDynamicBytes(loc, ty @ Type::Array(..), size, option) = right {
+    if let Expression::AllocDynamicBytes {
+        loc,
+        ty: ty @ Type::Array(..),
+        size,
+        initializer,
+    } = right
+    {
         // If we re-allocate the pointer, create a new temp variable to hold the new array length
         let temp_res = vartab.temp_name("array_length", &Type::Uint(32));
 
@@ -33,14 +39,21 @@ pub(crate) fn handle_array_assign(
 
         cfg.array_lengths_temps.insert(pos, temp_res);
 
-        Expression::AllocDynamicBytes(
+        Expression::AllocDynamicBytes {
             loc,
             ty,
-            Box::new(Expression::Variable(Loc::Codegen, Type::Uint(32), temp_res)),
-            option,
-        )
+            size: Box::new(Expression::Variable {
+                loc: Loc::Codegen,
+                ty: Type::Uint(32),
+                var_no: temp_res,
+            }),
+            initializer,
+        }
     } else {
-        if let Expression::Variable(_, _, right_res) = &right {
+        if let Expression::Variable {
+            var_no: right_res, ..
+        } = &right
+        {
             // If we have initialized a temp var for this var
             if cfg.array_lengths_temps.contains_key(right_res) {
                 let to_update = cfg.array_lengths_temps[right_res];

+ 242 - 145
src/codegen/cfg.rs

@@ -538,29 +538,37 @@ impl ControlFlowGraph {
         if self.array_lengths_temps.contains_key(&array_pos) {
             let to_add = self.array_lengths_temps[&array_pos];
             let add_expr = if minus {
-                Expression::Subtract(
+                Expression::Subtract {
                     loc,
-                    Type::Uint(32),
-                    false,
-                    Box::new(Expression::Variable(loc, Type::Uint(32), to_add)),
-                    Box::new(Expression::NumberLiteral(
+                    ty: Type::Uint(32),
+                    overflowing: false,
+                    left: Box::new(Expression::Variable {
                         loc,
-                        Type::Uint(32),
-                        BigInt::one(),
-                    )),
-                )
+                        ty: Type::Uint(32),
+                        var_no: to_add,
+                    }),
+                    right: Box::new(Expression::NumberLiteral {
+                        loc,
+                        ty: Type::Uint(32),
+                        value: BigInt::one(),
+                    }),
+                }
             } else {
-                Expression::Add(
+                Expression::Add {
                     loc,
-                    Type::Uint(32),
-                    false,
-                    Box::new(Expression::Variable(loc, Type::Uint(32), to_add)),
-                    Box::new(Expression::NumberLiteral(
+                    ty: Type::Uint(32),
+                    overflowing: false,
+                    left: Box::new(Expression::Variable {
                         loc,
-                        Type::Uint(32),
-                        BigInt::one(),
-                    )),
-                )
+                        ty: Type::Uint(32),
+                        var_no: to_add,
+                    }),
+                    right: Box::new(Expression::NumberLiteral {
+                        loc,
+                        ty: Type::Uint(32),
+                        value: BigInt::one(),
+                    }),
+                }
             };
 
             // Add instruction to the cfg
@@ -577,146 +585,185 @@ impl ControlFlowGraph {
 
     pub fn expr_to_string(&self, contract: &Contract, ns: &Namespace, expr: &Expression) -> String {
         match expr {
-            Expression::FunctionArg(_, _, pos) => format!("(arg #{pos})"),
-            Expression::BoolLiteral(_, false) => "false".to_string(),
-            Expression::BoolLiteral(_, true) => "true".to_string(),
-            Expression::BytesLiteral(_, Type::String, s) => {
-                format!("{}", String::from_utf8_lossy(s))
+            Expression::FunctionArg { arg_no, .. } => format!("(arg #{arg_no})"),
+            Expression::BoolLiteral { value: false, .. } => "false".to_string(),
+            Expression::BoolLiteral { value: true, .. } => "true".to_string(),
+            Expression::BytesLiteral {
+                ty: Type::String,
+                value,
+                ..
+            } => {
+                format!("{}", String::from_utf8_lossy(value))
             }
-            Expression::BytesLiteral(_, _, s) => format!("hex\"{}\"", hex::encode(s)),
-            Expression::NumberLiteral(_, ty @ Type::Address(_), n) => {
-                format!("{} {:#x}", ty.to_string(ns), n)
+            Expression::BytesLiteral { value, .. } => format!("hex\"{}\"", hex::encode(value)),
+            Expression::NumberLiteral {
+                ty: ty @ Type::Address(_),
+                value,
+                ..
+            } => {
+                format!("{} {:#x}", ty.to_string(ns), value)
             }
-            Expression::NumberLiteral(_, ty, n) => {
-                format!("{} {}", ty.to_string(ns), n)
+            Expression::NumberLiteral { ty, value, .. } => {
+                format!("{} {}", ty.to_string(ns), value)
             }
-            Expression::RationalNumberLiteral(_, ty, n) => {
-                format!("{} {}", ty.to_string(ns), n)
+            Expression::RationalNumberLiteral { ty, rational, .. } => {
+                format!("{} {}", ty.to_string(ns), rational)
             }
-            Expression::StructLiteral(_, _, expr) => format!(
+            Expression::StructLiteral { values, .. } => format!(
                 "struct {{ {} }}",
-                expr.iter()
+                values
+                    .iter()
                     .map(|e| self.expr_to_string(contract, ns, e))
                     .collect::<Vec<String>>()
                     .join(", ")
             ),
-            Expression::ConstArrayLiteral(_, _, dims, exprs) => format!(
+            Expression::ConstArrayLiteral {
+                dimensions, values, ..
+            } => format!(
                 "constant {} [ {} ]",
-                dims.iter().map(|d| format!("[{d}]")).collect::<String>(),
-                exprs
+                dimensions
+                    .iter()
+                    .map(|d| format!("[{d}]"))
+                    .collect::<String>(),
+                values
                     .iter()
                     .map(|e| self.expr_to_string(contract, ns, e))
                     .collect::<Vec<String>>()
                     .join(", ")
             ),
-            Expression::ArrayLiteral(_, _, dims, exprs) => format!(
+            Expression::ArrayLiteral {
+                dimensions, values, ..
+            } => format!(
                 "{} [ {} ]",
-                dims.iter().map(|d| format!("[{d}]")).collect::<String>(),
-                exprs
+                dimensions
+                    .iter()
+                    .map(|d| format!("[{d}]"))
+                    .collect::<String>(),
+                values
                     .iter()
                     .map(|e| self.expr_to_string(contract, ns, e))
                     .collect::<Vec<String>>()
                     .join(", ")
             ),
-            Expression::Add(_, _, unchecked, l, r) => format!(
+            Expression::Add {
+                overflowing,
+                left,
+                right,
+                ..
+            } => format!(
                 "({}{} + {})",
-                if *unchecked { "unchecked " } else { "" },
-                self.expr_to_string(contract, ns, l),
-                self.expr_to_string(contract, ns, r)
+                if *overflowing { "overflowing " } else { "" },
+                self.expr_to_string(contract, ns, left),
+                self.expr_to_string(contract, ns, right)
             ),
-            Expression::Subtract(_, _, unchecked, l, r) => format!(
+            Expression::Subtract {
+                overflowing,
+                left,
+                right,
+                ..
+            } => format!(
                 "({}{} - {})",
-                if *unchecked { "unchecked " } else { "" },
-                self.expr_to_string(contract, ns, l),
-                self.expr_to_string(contract, ns, r)
+                if *overflowing { "overflowing " } else { "" },
+                self.expr_to_string(contract, ns, left),
+                self.expr_to_string(contract, ns, right)
             ),
-            Expression::BitwiseOr(_, _, l, r) => format!(
+            Expression::BitwiseOr { left, right, .. } => format!(
                 "({} | {})",
-                self.expr_to_string(contract, ns, l),
-                self.expr_to_string(contract, ns, r)
+                self.expr_to_string(contract, ns, left),
+                self.expr_to_string(contract, ns, right)
             ),
-            Expression::BitwiseAnd(_, _, l, r) => format!(
+            Expression::BitwiseAnd { left, right, .. } => format!(
                 "({} & {})",
-                self.expr_to_string(contract, ns, l),
-                self.expr_to_string(contract, ns, r)
+                self.expr_to_string(contract, ns, left),
+                self.expr_to_string(contract, ns, right)
             ),
-            Expression::BitwiseXor(_, _, l, r) => format!(
+            Expression::BitwiseXor { left, right, .. } => format!(
                 "({} ^ {})",
-                self.expr_to_string(contract, ns, l),
-                self.expr_to_string(contract, ns, r)
+                self.expr_to_string(contract, ns, left),
+                self.expr_to_string(contract, ns, right)
             ),
-            Expression::ShiftLeft(_, _, l, r) => format!(
+            Expression::ShiftLeft { left, right, .. } => format!(
                 "({} << {})",
-                self.expr_to_string(contract, ns, l),
-                self.expr_to_string(contract, ns, r)
+                self.expr_to_string(contract, ns, left),
+                self.expr_to_string(contract, ns, right)
             ),
-            Expression::ShiftRight(_, _, l, r, _) => format!(
+            Expression::ShiftRight { left, right, .. } => format!(
                 "({} >> {})",
-                self.expr_to_string(contract, ns, l),
-                self.expr_to_string(contract, ns, r)
+                self.expr_to_string(contract, ns, left),
+                self.expr_to_string(contract, ns, right)
             ),
-            Expression::Multiply(_, _, unchecked, l, r) => format!(
+            Expression::Multiply {
+                overflowing,
+                left,
+                right,
+                ..
+            } => format!(
                 "({}{} * {})",
-                if *unchecked { "unchecked " } else { "" },
-                self.expr_to_string(contract, ns, l),
-                self.expr_to_string(contract, ns, r)
+                if *overflowing { "overflowing " } else { "" },
+                self.expr_to_string(contract, ns, left),
+                self.expr_to_string(contract, ns, right)
             ),
-            Expression::SignedDivide(_, _, l, r) => format!(
+            Expression::SignedDivide { left, right, .. } => format!(
                 "(signed divide {} / {})",
-                self.expr_to_string(contract, ns, l),
-                self.expr_to_string(contract, ns, r),
+                self.expr_to_string(contract, ns, left),
+                self.expr_to_string(contract, ns, right),
             ),
-            Expression::UnsignedDivide(_, _, l, r) => format!(
+            Expression::UnsignedDivide { left, right, .. } => format!(
                 "(unsigned divide {} / {})",
-                self.expr_to_string(contract, ns, l),
-                self.expr_to_string(contract, ns, r),
+                self.expr_to_string(contract, ns, left),
+                self.expr_to_string(contract, ns, right),
             ),
-            Expression::SignedModulo(_, _, l, r) => format!(
+            Expression::SignedModulo { left, right, .. } => format!(
                 "(signed modulo {} % {})",
-                self.expr_to_string(contract, ns, l),
-                self.expr_to_string(contract, ns, r)
+                self.expr_to_string(contract, ns, left),
+                self.expr_to_string(contract, ns, right)
             ),
-            Expression::UnsignedModulo(_, _, l, r) => format!(
+            Expression::UnsignedModulo { left, right, .. } => format!(
                 "(unsigned modulo {} % {})",
-                self.expr_to_string(contract, ns, l),
-                self.expr_to_string(contract, ns, r)
+                self.expr_to_string(contract, ns, left),
+                self.expr_to_string(contract, ns, right)
             ),
-            Expression::Power(_, _, unchecked, l, r) => format!(
+            Expression::Power {
+                overflowing,
+                base,
+                exp,
+                ..
+            } => format!(
                 "({}{} ** {})",
-                if *unchecked { "unchecked " } else { "" },
-                self.expr_to_string(contract, ns, l),
-                self.expr_to_string(contract, ns, r)
+                if *overflowing { "overflowing " } else { "" },
+                self.expr_to_string(contract, ns, base),
+                self.expr_to_string(contract, ns, exp)
             ),
-            Expression::Variable(_, _, res) => {
-                if let Some(var) = self.vars.get(res) {
+            Expression::Variable { var_no, .. } => {
+                if let Some(var) = self.vars.get(var_no) {
                     format!("%{}", var.id.name)
                 } else {
-                    panic!("error: non-existing variable {res} in CFG");
+                    panic!("error: non-existing variable {var_no} in CFG");
                 }
             }
-            Expression::Load(_, _, expr) => {
+            Expression::Load { expr, .. } => {
                 format!("(load {})", self.expr_to_string(contract, ns, expr))
             }
-            Expression::ZeroExt(_, ty, e) => format!(
+            Expression::ZeroExt { ty, expr, .. } => format!(
                 "(zext {} {})",
                 ty.to_string(ns),
-                self.expr_to_string(contract, ns, e)
+                self.expr_to_string(contract, ns, expr)
             ),
-            Expression::SignExt(_, ty, e) => format!(
+            Expression::SignExt { ty, expr, .. } => format!(
                 "(sext {} {})",
                 ty.to_string(ns),
-                self.expr_to_string(contract, ns, e)
+                self.expr_to_string(contract, ns, expr)
             ),
-            Expression::Trunc(_, ty, e) => format!(
+            Expression::Trunc { ty, expr, .. } => format!(
                 "(trunc {} {})",
                 ty.to_string(ns),
-                self.expr_to_string(contract, ns, e)
+                self.expr_to_string(contract, ns, expr)
             ),
             Expression::More {
-                loc: _,
                 signed,
                 left,
                 right,
+                ..
             } => format!(
                 "({} more {} > {})",
                 if *signed { "signed" } else { "unsigned" },
@@ -724,10 +771,10 @@ impl ControlFlowGraph {
                 self.expr_to_string(contract, ns, right)
             ),
             Expression::Less {
-                loc: _,
                 signed,
                 left,
                 right,
+                ..
             } => format!(
                 "({} less {} < {})",
                 if *signed { "signed" } else { "unsigned" },
@@ -735,10 +782,10 @@ impl ControlFlowGraph {
                 self.expr_to_string(contract, ns, right)
             ),
             Expression::MoreEqual {
-                loc: _,
                 signed,
                 left,
                 right,
+                ..
             } => format!(
                 "({} {} >= {})",
                 if *signed { "signed" } else { "unsigned" },
@@ -746,47 +793,63 @@ impl ControlFlowGraph {
                 self.expr_to_string(contract, ns, right)
             ),
             Expression::LessEqual {
-                loc: _,
                 signed,
                 left,
                 right,
+                ..
             } => format!(
                 "({} {} <= {})",
                 if *signed { "signed" } else { "unsigned" },
                 self.expr_to_string(contract, ns, left),
                 self.expr_to_string(contract, ns, right)
             ),
-            Expression::Equal(_, l, r) => format!(
+            Expression::Equal { left, right, .. } => format!(
                 "({} == {})",
-                self.expr_to_string(contract, ns, l),
-                self.expr_to_string(contract, ns, r)
+                self.expr_to_string(contract, ns, left),
+                self.expr_to_string(contract, ns, right)
             ),
-            Expression::NotEqual(_, l, r) => format!(
+            Expression::NotEqual { left, right, .. } => format!(
                 "({} != {})",
-                self.expr_to_string(contract, ns, l),
-                self.expr_to_string(contract, ns, r)
+                self.expr_to_string(contract, ns, left),
+                self.expr_to_string(contract, ns, right)
             ),
-            Expression::Subscript(_, _, ty, a, i) => format!(
+            Expression::Subscript {
+                array_ty: ty,
+                expr,
+                index,
+                ..
+            } => format!(
                 "(subscript {} {}[{}])",
                 ty.to_string(ns),
-                self.expr_to_string(contract, ns, a),
-                self.expr_to_string(contract, ns, i)
+                self.expr_to_string(contract, ns, expr),
+                self.expr_to_string(contract, ns, index)
             ),
             Expression::StorageArrayLength { array, elem_ty, .. } => format!(
                 "(storage array length {}[{}])",
                 self.expr_to_string(contract, ns, array),
                 elem_ty.to_string(ns),
             ),
-            Expression::StructMember(_, _, a, f) => format!(
+            Expression::StructMember { expr, member, .. } => format!(
                 "(struct {} field {})",
-                self.expr_to_string(contract, ns, a),
-                f
+                self.expr_to_string(contract, ns, expr),
+                member
             ),
-            Expression::Not(_, e) => format!("!{}", self.expr_to_string(contract, ns, e)),
-            Expression::BitwiseNot(_, _, e) => format!("~{}", self.expr_to_string(contract, ns, e)),
-            Expression::Negate(_, _, e) => format!("-{}", self.expr_to_string(contract, ns, e)),
+            Expression::Not { expr, .. } => {
+                format!("!{}", self.expr_to_string(contract, ns, expr))
+            }
+            Expression::BitwiseNot { expr, .. } => {
+                format!("~{}", self.expr_to_string(contract, ns, expr))
+            }
+            Expression::Negate { expr, .. } => {
+                format!("-{}", self.expr_to_string(contract, ns, expr))
+            }
             Expression::Poison => "☠".to_string(),
-            Expression::AllocDynamicBytes(_, ty, size, None) => {
+            Expression::AllocDynamicBytes {
+                ty,
+                size,
+                initializer: None,
+                ..
+            } => {
                 let ty = if let Type::Slice(ty) = ty {
                     format!("slice {}", ty.to_string(ns))
                 } else {
@@ -799,7 +862,12 @@ impl ControlFlowGraph {
                     self.expr_to_string(contract, ns, size)
                 )
             }
-            Expression::AllocDynamicBytes(_, ty, size, Some(init)) => {
+            Expression::AllocDynamicBytes {
+                ty,
+                size,
+                initializer: Some(init),
+                ..
+            } => {
                 let ty = if let Type::Slice(ty) = ty {
                     format!("slice {}", ty.to_string(ns))
                 } else {
@@ -816,17 +884,17 @@ impl ControlFlowGraph {
                     }
                 )
             }
-            Expression::StringCompare(_, l, r) => format!(
+            Expression::StringCompare { left, right, .. } => format!(
                 "(strcmp ({}) ({}))",
-                self.location_to_string(contract, ns, l),
-                self.location_to_string(contract, ns, r)
+                self.location_to_string(contract, ns, left),
+                self.location_to_string(contract, ns, right)
             ),
-            Expression::StringConcat(_, _, l, r) => format!(
+            Expression::StringConcat { left, right, .. } => format!(
                 "(concat ({}) ({}))",
-                self.location_to_string(contract, ns, l),
-                self.location_to_string(contract, ns, r)
+                self.location_to_string(contract, ns, left),
+                self.location_to_string(contract, ns, right)
             ),
-            Expression::Keccak256(_, _, exprs) => format!(
+            Expression::Keccak256 { exprs, .. } => format!(
                 "(keccak256 {})",
                 exprs
                     .iter()
@@ -834,22 +902,26 @@ impl ControlFlowGraph {
                     .collect::<Vec<String>>()
                     .join(", ")
             ),
-            Expression::InternalFunctionCfg(cfg_no) => {
+            Expression::InternalFunctionCfg { cfg_no } => {
                 format!("function {}", contract.cfg[*cfg_no].name)
             }
-            Expression::ReturnData(_) => "(external call return data)".to_string(),
-            Expression::Cast(_, ty, e) => format!(
+            Expression::ReturnData { .. } => "(external call return data)".to_string(),
+            Expression::Cast { ty, expr, .. } => format!(
                 "{}({})",
                 ty.to_string(ns),
-                self.expr_to_string(contract, ns, e)
+                self.expr_to_string(contract, ns, expr)
             ),
-            Expression::BytesCast(_, ty, from, e) => format!(
+            Expression::BytesCast { ty, from, expr, .. } => format!(
                 "{} from:{} ({})",
                 ty.to_string(ns),
                 from.to_string(ns),
-                self.expr_to_string(contract, ns, e)
+                self.expr_to_string(contract, ns, expr)
             ),
-            Expression::Builtin(_, _, builtin, args) => format!(
+            Expression::Builtin {
+                kind: builtin,
+                args,
+                ..
+            } => format!(
                 "(builtin {:?} ({}))",
                 builtin,
                 args.iter()
@@ -857,14 +929,15 @@ impl ControlFlowGraph {
                     .collect::<Vec<String>>()
                     .join(", ")
             ),
-            Expression::FormatString(_, args) => format!(
+            Expression::FormatString { args: fields, .. } => format!(
                 "(format string {})",
-                args.iter()
+                fields
+                    .iter()
                     .map(|(spec, a)| format!("({} {})", spec, self.expr_to_string(contract, ns, a)))
                     .collect::<Vec<String>>()
                     .join(", ")
             ),
-            Expression::Undefined(_) => "undef".to_string(),
+            Expression::Undefined { .. } => "undef".to_string(),
             Expression::AdvancePointer {
                 pointer,
                 bytes_offset,
@@ -875,7 +948,7 @@ impl ControlFlowGraph {
                     self.expr_to_string(contract, ns, bytes_offset)
                 )
             }
-            Expression::GetRef(_, _, expr) => {
+            Expression::GetRef { expr, .. } => {
                 format!("(deref {}", self.expr_to_string(contract, ns, expr))
             }
             _ => panic!("{expr:?}"),
@@ -1620,7 +1693,11 @@ fn function_cfg(
                                     expr,
                                 },
                             );
-                            Expression::Variable(loc, ty, *id)
+                            Expression::Variable {
+                                loc,
+                                ty,
+                                var_no: *id,
+                            }
                         } else {
                             Expression::Poison
                         }
@@ -1701,7 +1778,11 @@ fn function_cfg(
                     .symtable
                     .returns
                     .iter()
-                    .map(|pos| Expression::Variable(loc, func.symtable.vars[pos].ty.clone(), *pos))
+                    .map(|pos| Expression::Variable {
+                        loc,
+                        ty: func.symtable.vars[pos].ty.clone(),
+                        var_no: *pos,
+                    })
                     .collect::<Vec<_>>(),
             },
         );
@@ -1727,7 +1808,11 @@ pub(crate) fn populate_arguments<T: FunctionAttributes>(
                 Instr::Set {
                     loc: func.get_parameters()[i].loc,
                     res: *pos,
-                    expr: Expression::FunctionArg(var.id.loc, var.ty.clone(), i),
+                    expr: Expression::FunctionArg {
+                        loc: var.id.loc,
+                        ty: var.ty.clone(),
+                        arg_no: i,
+                    },
                 },
             );
         }
@@ -1800,7 +1885,11 @@ fn generate_modifier_dispatch(
                 Instr::Set {
                     loc: var.id.loc,
                     res: *pos,
-                    expr: Expression::FunctionArg(var.id.loc, var.ty.clone(), i),
+                    expr: Expression::FunctionArg {
+                        loc: var.id.loc,
+                        ty: var.ty.clone(),
+                        arg_no: i,
+                    },
                 },
             );
         }
@@ -1835,11 +1924,11 @@ fn generate_modifier_dispatch(
     let mut return_tys = Vec::new();
 
     for (i, arg) in func.returns.iter().enumerate() {
-        value.push(Expression::Variable(
-            arg.loc,
-            arg.ty.clone(),
-            func.symtable.returns[i],
-        ));
+        value.push(Expression::Variable {
+            loc: arg.loc,
+            ty: arg.ty.clone(),
+            var_no: func.symtable.returns[i],
+        });
         return_tys.push(arg.ty.clone());
     }
 
@@ -1854,7 +1943,11 @@ fn generate_modifier_dispatch(
             .params
             .iter()
             .enumerate()
-            .map(|(i, p)| Expression::FunctionArg(p.loc, p.ty.clone(), i))
+            .map(|(i, p)| Expression::FunctionArg {
+                loc: p.loc,
+                ty: p.ty.clone(),
+                arg_no: i,
+            })
             .collect(),
     };
 
@@ -1891,7 +1984,11 @@ fn generate_modifier_dispatch(
                     .symtable
                     .returns
                     .iter()
-                    .map(|pos| Expression::Variable(loc, func.symtable.vars[pos].ty.clone(), *pos))
+                    .map(|pos| Expression::Variable {
+                        loc,
+                        ty: func.symtable.vars[pos].ty.clone(),
+                        var_no: *pos,
+                    })
                     .collect::<Vec<_>>(),
             },
         );
@@ -1975,11 +2072,11 @@ impl Contract {
             .iter()
             .find(|l| l.contract_no == var_contract_no && l.var_no == var_no)
         {
-            Expression::NumberLiteral(
+            Expression::NumberLiteral {
                 loc,
-                ty.unwrap_or_else(|| ns.storage_type()),
-                layout.slot.clone(),
-            )
+                ty: ty.unwrap_or_else(|| ns.storage_type()),
+                value: layout.slot.clone(),
+            }
         } else {
             panic!("get_storage_slot called on non-storage variable");
         }

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 532 - 175
src/codegen/constant_folding.rs


+ 5 - 5
src/codegen/constructor.rs

@@ -68,11 +68,11 @@ pub(super) fn call_constructor(
             .selector(ns, &contract_no),
     };
 
-    let mut args = vec![Expression::BytesLiteral(
-        *loc,
-        Type::FunctionSelector,
-        selector,
-    )];
+    let mut args = vec![Expression::BytesLiteral {
+        loc: *loc,
+        ty: Type::FunctionSelector,
+        value: selector,
+    }];
 
     args.append(&mut constructor_args);
 

+ 68 - 14
src/codegen/dead_storage.rs

@@ -208,7 +208,7 @@ fn instr_transfers(block_no: usize, block: &BasicBlock) -> Vec<Vec<Transfer>> {
         transfers.push(match instr {
             Instr::Set {
                 res,
-                expr: Expression::Variable(_, _, src),
+                expr: Expression::Variable { var_no: src, .. },
                 ..
             } => {
                 vec![
@@ -312,8 +312,8 @@ fn instr_transfers(block_no: usize, block: &BasicBlock) -> Vec<Vec<Transfer>> {
 
 fn array_var(expr: &Expression) -> Option<usize> {
     match expr {
-        Expression::Variable(_, _, var_no) => Some(*var_no),
-        Expression::Subscript(_, _, _, expr, _) | Expression::StructMember(_, _, expr, _) => {
+        Expression::Variable { var_no, .. } => Some(*var_no),
+        Expression::Subscript { expr, .. } | Expression::StructMember { expr, .. } => {
             array_var(expr)
         }
         _ => None,
@@ -524,7 +524,11 @@ pub fn dead_storage(cfg: &mut ControlFlowGraph, _ns: &mut Namespace) {
                         cfg.blocks[block_no].instr[instr_no] = Instr::Set {
                             loc: Loc::Codegen,
                             res: *res,
-                            expr: Expression::Variable(Loc::Codegen, ty.clone(), *var_no),
+                            expr: Expression::Variable {
+                                loc: Loc::Codegen,
+                                ty: ty.clone(),
+                                var_no: *var_no,
+                            },
                         };
                     } else {
                         for (def, expr) in &vars.stores {
@@ -684,14 +688,17 @@ fn expression_compare(
     block_vars: &BlockVars,
 ) -> ExpressionCmp {
     let v = match (left, right) {
-        (Expression::NumberLiteral(_, _, left), Expression::NumberLiteral(_, _, right)) => {
+        (
+            Expression::NumberLiteral { value: left, .. },
+            Expression::NumberLiteral { value: right, .. },
+        ) => {
             if left == right {
                 ExpressionCmp::Equal
             } else {
                 ExpressionCmp::NotEqual
             }
         }
-        (Expression::Keccak256(_, _, left), Expression::Keccak256(_, _, right)) => {
+        (Expression::Keccak256 { exprs: left, .. }, Expression::Keccak256 { exprs: right, .. }) => {
             // This could be written with fold_first() rather than collect(), but that is an unstable feature.
             // Also fold first does not short circuit
             let cmps: Vec<ExpressionCmp> = left
@@ -710,11 +717,14 @@ fn expression_compare(
                 first
             }
         }
-        (Expression::ZeroExt(_, _, left), Expression::ZeroExt(_, _, right))
-        | (Expression::Trunc(_, _, left), Expression::Trunc(_, _, right)) => {
+        (Expression::ZeroExt { expr: left, .. }, Expression::ZeroExt { expr: right, .. })
+        | (Expression::Trunc { expr: left, .. }, Expression::Trunc { expr: right, .. }) => {
             expression_compare(left, left_vars, right, right_vars, cfg, block_vars)
         }
-        (Expression::FunctionArg(_, _, left), Expression::FunctionArg(_, _, right)) => {
+        (
+            Expression::FunctionArg { arg_no: left, .. },
+            Expression::FunctionArg { arg_no: right, .. },
+        ) => {
             if left == right {
                 ExpressionCmp::Equal
             } else {
@@ -722,10 +732,54 @@ fn expression_compare(
                 ExpressionCmp::Unknown
             }
         }
-        (Expression::Add(_, _, _, l1, r1), Expression::Add(_, _, _, l2, r2))
-        | (Expression::Multiply(_, _, _, l1, r1), Expression::Multiply(_, _, _, l2, r2))
-        | (Expression::Subtract(_, _, _, l1, r1), Expression::Subtract(_, _, _, l2, r2))
-        | (Expression::Subscript(_, _, _, l1, r1), Expression::Subscript(_, _, _, l2, r2)) => {
+        (
+            Expression::Add {
+                left: l1,
+                right: r1,
+                ..
+            },
+            Expression::Add {
+                left: l2,
+                right: r2,
+                ..
+            },
+        )
+        | (
+            Expression::Multiply {
+                left: l1,
+                right: r1,
+                ..
+            },
+            Expression::Multiply {
+                left: l2,
+                right: r2,
+                ..
+            },
+        )
+        | (
+            Expression::Subtract {
+                left: l1,
+                right: r1,
+                ..
+            },
+            Expression::Subtract {
+                left: l2,
+                right: r2,
+                ..
+            },
+        )
+        | (
+            Expression::Subscript {
+                expr: l1,
+                index: r1,
+                ..
+            },
+            Expression::Subscript {
+                expr: l2,
+                index: r2,
+                ..
+            },
+        ) => {
             let l = expression_compare(l1, left_vars, l2, right_vars, cfg, block_vars);
 
             let r = expression_compare(r1, left_vars, r2, right_vars, cfg, block_vars);
@@ -740,7 +794,7 @@ fn expression_compare(
                 ExpressionCmp::Unknown
             }
         }
-        (Expression::Variable(_, _, left), Expression::Variable(_, _, right)) => {
+        (Expression::Variable { var_no: left, .. }, Expression::Variable { var_no: right, .. }) => {
             // let's check that the variable left has the same reaching definitions as right
             let left = match left_vars.vars.get(left) {
                 Some(left) => left,

+ 128 - 74
src/codegen/dispatch/solana.rs

@@ -32,8 +32,11 @@ pub(crate) fn function_dispatch(
     let argsdata_var = vartab.temp_name("input", &Type::BufferPointer);
     let argslen_var = vartab.temp_name("input_len", &Type::Uint(64));
 
-    let sol_params =
-        Expression::FunctionArg(Loc::Codegen, Type::Struct(StructType::SolParameters), 0);
+    let sol_params = Expression::FunctionArg {
+        loc: Loc::Codegen,
+        ty: Type::Struct(StructType::SolParameters),
+        arg_no: 0,
+    };
 
     // ty:bufferptr argsdata_var = load ty:ref(ty:bufferptr) (structmember ty:ref(ty:bufferptr) (funcarg ty:struct(solparam), 2))
     cfg.add(
@@ -41,21 +44,25 @@ pub(crate) fn function_dispatch(
         Instr::Set {
             res: argsdata_var,
             loc: Loc::Codegen,
-            expr: Expression::Load(
-                Loc::Codegen,
-                Type::BufferPointer,
-                Expression::StructMember(
-                    Loc::Codegen,
-                    Type::Ref(Type::BufferPointer.into()),
-                    sol_params.clone().into(),
-                    2,
-                )
+            expr: Expression::Load {
+                loc: Loc::Codegen,
+                ty: Type::BufferPointer,
+                expr: Expression::StructMember {
+                    loc: Loc::Codegen,
+                    ty: Type::Ref(Type::BufferPointer.into()),
+                    expr: sol_params.clone().into(),
+                    member: 2,
+                }
                 .into(),
-            ),
+            },
         },
     );
 
-    let argsdata = Expression::Variable(Loc::Codegen, Type::BufferPointer, argsdata_var);
+    let argsdata = Expression::Variable {
+        loc: Loc::Codegen,
+        ty: Type::BufferPointer,
+        var_no: argsdata_var,
+    };
 
     // ty:uint64 argslen_var = load ref(ty:uint64) (structmember ref(ty:uin64) (funcarg ty:struct(solparam), 3))
     cfg.add(
@@ -63,27 +70,36 @@ pub(crate) fn function_dispatch(
         Instr::Set {
             res: argslen_var,
             loc: Loc::Codegen,
-            expr: Expression::Load(
-                Loc::Codegen,
-                Type::Uint(64),
-                Expression::StructMember(
-                    Loc::Codegen,
-                    Type::Ref(Type::Uint(64).into()),
-                    sol_params.into(),
-                    3,
-                )
+            expr: Expression::Load {
+                loc: Loc::Codegen,
+                ty: Type::Uint(64),
+                expr: Expression::StructMember {
+                    loc: Loc::Codegen,
+                    ty: Type::Ref(Type::Uint(64).into()),
+                    expr: sol_params.into(),
+                    member: 3,
+                }
                 .into(),
-            ),
+            },
         },
     );
 
-    let argslen = Expression::Variable(Loc::Codegen, Type::Uint(64), argslen_var);
+    let argslen = Expression::Variable {
+        loc: Loc::Codegen,
+        ty: Type::Uint(64),
+        var_no: argslen_var,
+    };
 
     let not_fallback = Expression::MoreEqual {
         loc: Loc::Codegen,
         signed: false,
         left: argslen.clone().into(),
-        right: Expression::NumberLiteral(Loc::Codegen, Type::Uint(64), BigInt::from(8u8)).into(),
+        right: Expression::NumberLiteral {
+            loc: Loc::Codegen,
+            ty: Type::Uint(64),
+            value: BigInt::from(8u8),
+        }
+        .into(),
     };
 
     cfg.add(
@@ -96,35 +112,39 @@ pub(crate) fn function_dispatch(
     );
     cfg.set_basic_block(switch_block);
 
-    let fid = Expression::Builtin(
-        Loc::Codegen,
-        vec![Type::Uint(64)],
-        Builtin::ReadFromBuffer,
-        vec![
+    let fid = Expression::Builtin {
+        loc: Loc::Codegen,
+        tys: vec![Type::Uint(64)],
+        kind: Builtin::ReadFromBuffer,
+        args: vec![
             argsdata.clone(),
-            Expression::NumberLiteral(Loc::Codegen, Type::Uint(64), BigInt::zero()),
+            Expression::NumberLiteral {
+                loc: Loc::Codegen,
+                ty: Type::Uint(64),
+                value: BigInt::zero(),
+            },
         ],
-    );
+    };
 
     let argsdata = Expression::AdvancePointer {
         pointer: Box::new(argsdata),
-        bytes_offset: Box::new(Expression::NumberLiteral(
-            Loc::Codegen,
-            Type::Uint(32),
-            BigInt::from(8u8),
-        )),
+        bytes_offset: Box::new(Expression::NumberLiteral {
+            loc: Loc::Codegen,
+            ty: Type::Uint(32),
+            value: BigInt::from(8u8),
+        }),
+    };
+    let argslen = Expression::Subtract {
+        loc: Loc::Codegen,
+        ty: Type::Uint(64),
+        overflowing: false,
+        left: Box::new(argslen),
+        right: Box::new(Expression::NumberLiteral {
+            loc: Loc::Codegen,
+            ty: Type::Uint(64),
+            value: BigInt::from(8u8),
+        }),
     };
-    let argslen = Expression::Subtract(
-        Loc::Codegen,
-        Type::Uint(64),
-        false,
-        Box::new(argslen),
-        Box::new(Expression::NumberLiteral(
-            Loc::Codegen,
-            Type::Uint(64),
-            BigInt::from(8u8),
-        )),
-    );
 
     let magic = vartab.temp_name("magic", &Type::Uint(32));
 
@@ -133,7 +153,11 @@ pub(crate) fn function_dispatch(
         Instr::LoadStorage {
             res: magic,
             ty: Type::Uint(32),
-            storage: Expression::NumberLiteral(Loc::Codegen, Type::Uint(32), 0.into()),
+            storage: Expression::NumberLiteral {
+                loc: Loc::Codegen,
+                ty: Type::Uint(32),
+                value: 0.into(),
+            },
         },
     );
 
@@ -173,11 +197,11 @@ pub(crate) fn function_dispatch(
         };
 
         cases.push((
-            Expression::NumberLiteral(
-                Loc::Codegen,
-                Type::Uint(64),
-                BigInt::from_bytes_le(Sign::Plus, &func_cfg.selector),
-            ),
+            Expression::NumberLiteral {
+                loc: Loc::Codegen,
+                ty: Type::Uint(64),
+                value: BigInt::from_bytes_le(Sign::Plus, &func_cfg.selector),
+            },
             entry,
         ));
     }
@@ -281,16 +305,21 @@ fn add_function_dispatch_case(
         cfg.add(
             vartab,
             Instr::BranchCond {
-                cond: Expression::Equal(
-                    Loc::Codegen,
-                    Expression::Variable(Loc::Codegen, Type::Uint(32), magic).into(),
-                    Expression::NumberLiteral(
-                        Loc::Codegen,
-                        Type::Uint(32),
-                        ns.contracts[contract_no].selector().into(),
-                    )
+                cond: Expression::Equal {
+                    loc: Loc::Codegen,
+                    left: Expression::Variable {
+                        loc: Loc::Codegen,
+                        ty: Type::Uint(32),
+                        var_no: magic,
+                    }
+                    .into(),
+                    right: Expression::NumberLiteral {
+                        loc: Loc::Codegen,
+                        ty: Type::Uint(32),
+                        value: ns.contracts[contract_no].selector().into(),
+                    }
                     .into(),
-                ),
+                },
                 true_block: magic_ok,
                 false_block: magic_bad,
             },
@@ -308,7 +337,11 @@ fn add_function_dispatch_case(
         cfg.set_basic_block(magic_ok);
     }
 
-    let truncated_len = Expression::Trunc(Loc::Codegen, Type::Uint(32), Box::new(argslen));
+    let truncated_len = Expression::Trunc {
+        loc: Loc::Codegen,
+        ty: Type::Uint(32),
+        expr: Box::new(argslen),
+    };
 
     let tys = func_cfg
         .params
@@ -332,7 +365,11 @@ fn add_function_dispatch_case(
         let new_var = vartab.temp_anonymous(&item.ty);
         returns.push(new_var);
         return_tys.push(item.ty.clone());
-        returns_expr.push(Expression::Variable(Loc::Codegen, item.ty.clone(), new_var));
+        returns_expr.push(Expression::Variable {
+            loc: Loc::Codegen,
+            ty: item.ty.clone(),
+            var_no: new_var,
+        });
     }
 
     cfg.add(
@@ -347,7 +384,11 @@ fn add_function_dispatch_case(
 
     if !func_cfg.returns.is_empty() {
         let (data, data_len) = abi_encode(&Loc::Codegen, returns_expr, ns, vartab, cfg, false);
-        let zext_len = Expression::ZeroExt(Loc::Codegen, Type::Uint(64), Box::new(data_len));
+        let zext_len = Expression::ZeroExt {
+            loc: Loc::Codegen,
+            ty: Type::Uint(64),
+            expr: Box::new(data_len),
+        };
         cfg.add(
             vartab,
             Instr::ReturnData {
@@ -365,13 +406,22 @@ fn add_function_dispatch_case(
         cfg.add(
             vartab,
             Instr::ReturnData {
-                data: Expression::AllocDynamicBytes(
-                    Loc::Codegen,
-                    Type::DynamicBytes,
-                    Expression::NumberLiteral(Loc::Codegen, Type::Uint(32), 0.into()).into(),
-                    None,
-                ),
-                data_len: Expression::NumberLiteral(Loc::Codegen, Type::Uint(64), 0.into()),
+                data: Expression::AllocDynamicBytes {
+                    loc: Loc::Codegen,
+                    ty: Type::DynamicBytes,
+                    size: Expression::NumberLiteral {
+                        loc: Loc::Codegen,
+                        ty: Type::Uint(32),
+                        value: 0.into(),
+                    }
+                    .into(),
+                    initializer: None,
+                },
+                data_len: Expression::NumberLiteral {
+                    loc: Loc::Codegen,
+                    ty: Type::Uint(64),
+                    value: 0.into(),
+                },
             },
         );
     }
@@ -403,7 +453,11 @@ fn add_constructor_dispatch_case(
             .iter()
             .map(|e| e.ty.clone())
             .collect::<Vec<Type>>();
-        let truncated_len = Expression::Trunc(Loc::Codegen, Type::Uint(32), Box::new(argslen));
+        let truncated_len = Expression::Trunc {
+            loc: Loc::Codegen,
+            ty: Type::Uint(32),
+            expr: Box::new(argslen),
+        };
         returns = abi_decode(
             &Loc::Codegen,
             argsdata,

+ 142 - 53
src/codegen/dispatch/substrate.rs

@@ -80,7 +80,11 @@ impl<'a> Dispatch<'a> {
             Instr::Set {
                 loc: Codegen,
                 res: input_len,
-                expr: Expression::FunctionArg(Codegen, Uint(32), 1),
+                expr: Expression::FunctionArg {
+                    loc: Codegen,
+                    ty: Uint(32),
+                    arg_no: 1,
+                },
             },
         );
 
@@ -91,7 +95,11 @@ impl<'a> Dispatch<'a> {
             Instr::Set {
                 loc: Codegen,
                 res: value,
-                expr: Expression::FunctionArg(Codegen, ns.value_type(), 2),
+                expr: Expression::FunctionArg {
+                    loc: Codegen,
+                    ty: ns.value_type(),
+                    arg_no: 2,
+                },
             },
         );
 
@@ -102,12 +110,24 @@ impl<'a> Dispatch<'a> {
             Instr::Set {
                 loc: Codegen,
                 res: input_ptr_var,
-                expr: Expression::FunctionArg(Codegen, Type::BufferPointer, 0),
+                expr: Expression::FunctionArg {
+                    loc: Codegen,
+                    ty: Type::BufferPointer,
+                    arg_no: 0,
+                },
             },
         );
-        let input_ptr = Expression::Variable(Codegen, Type::BufferPointer, input_ptr_var);
-        let selector_len: Box<Expression> =
-            Expression::NumberLiteral(Codegen, Uint(32), ns.target.selector_length().into()).into();
+        let input_ptr = Expression::Variable {
+            loc: Codegen,
+            ty: Type::BufferPointer,
+            var_no: input_ptr_var,
+        };
+        let selector_len: Box<Expression> = Expression::NumberLiteral {
+            loc: Codegen,
+            ty: Uint(32),
+            value: ns.target.selector_length().into(),
+        }
+        .into();
         let input_ptr = Expression::AdvancePointer {
             pointer: input_ptr.into(),
             bytes_offset: selector_len.clone(),
@@ -133,7 +153,12 @@ impl<'a> Dispatch<'a> {
         let cond = Expression::Less {
             loc: Codegen,
             signed: false,
-            left: Expression::Variable(Codegen, Uint(32), self.input_len).into(),
+            left: Expression::Variable {
+                loc: Codegen,
+                ty: Uint(32),
+                var_no: self.input_len,
+            }
+            .into(),
             right: self.selector_len.clone(),
         };
         let default = self.cfg.new_basic_block("fb_or_recv".into());
@@ -152,7 +177,11 @@ impl<'a> Dispatch<'a> {
             .filter_map(|(func_no, func_cfg)| match func_cfg.ty {
                 FunctionTy::Function | FunctionTy::Constructor if func_cfg.public => {
                     let selector = BigInt::from_bytes_le(Sign::Plus, &func_cfg.selector);
-                    let case = Expression::NumberLiteral(Codegen, selector_ty.clone(), selector);
+                    let case = Expression::NumberLiteral {
+                        loc: Codegen,
+                        ty: selector_ty.clone(),
+                        value: selector,
+                    };
                     Some((case, self.dispatch_case(func_no)))
                 }
                 _ => None,
@@ -165,19 +194,35 @@ impl<'a> Dispatch<'a> {
         self.add(Instr::Set {
             loc: Codegen,
             res: selector_var,
-            expr: Expression::Builtin(
-                Codegen,
-                vec![selector_ty.clone()],
-                Builtin::ReadFromBuffer,
-                vec![
-                    Expression::FunctionArg(Codegen, Type::BufferPointer, 0),
-                    Expression::NumberLiteral(Codegen, selector_ty.clone(), 0.into()),
+            expr: Expression::Builtin {
+                loc: Codegen,
+                tys: vec![selector_ty.clone()],
+                kind: Builtin::ReadFromBuffer,
+                args: vec![
+                    Expression::FunctionArg {
+                        loc: Codegen,
+                        ty: Type::BufferPointer,
+                        arg_no: 0,
+                    },
+                    Expression::NumberLiteral {
+                        loc: Codegen,
+                        ty: selector_ty.clone(),
+                        value: 0.into(),
+                    },
                 ],
-            ),
+            },
         });
-        let selector = Expression::Variable(Codegen, selector_ty.clone(), selector_var);
+        let selector = Expression::Variable {
+            loc: Codegen,
+            ty: selector_ty.clone(),
+            var_no: selector_var,
+        };
         self.add(Instr::Store {
-            dest: Expression::FunctionArg(Codegen, selector_ty.clone(), 3),
+            dest: Expression::FunctionArg {
+                loc: Codegen,
+                ty: selector_ty.clone(),
+                arg_no: 3,
+            },
             data: selector.clone(),
         });
         self.add(Instr::Switch {
@@ -205,14 +250,18 @@ impl<'a> Dispatch<'a> {
         let cfg = &self.all_cfg[func_no];
         let mut args = vec![];
         if !cfg.params.is_empty() {
-            let buf_len = Expression::Variable(Codegen, Uint(32), self.input_len);
-            let arg_len = Expression::Subtract(
-                Codegen,
-                Uint(32),
-                false,
-                buf_len.into(),
-                self.selector_len.clone(),
-            );
+            let buf_len = Expression::Variable {
+                loc: Codegen,
+                ty: Uint(32),
+                var_no: self.input_len,
+            };
+            let arg_len = Expression::Subtract {
+                loc: Codegen,
+                ty: Uint(32),
+                overflowing: false,
+                left: buf_len.into(),
+                right: self.selector_len.clone(),
+            };
             args = abi_decode(
                 &Codegen,
                 &self.input_ptr,
@@ -220,7 +269,11 @@ impl<'a> Dispatch<'a> {
                 self.ns,
                 &mut self.vartab,
                 &mut self.cfg,
-                Some(Expression::Trunc(Codegen, Uint(32), arg_len.into())),
+                Some(Expression::Trunc {
+                    loc: Codegen,
+                    ty: Uint(32),
+                    expr: arg_len.into(),
+                }),
             );
         }
 
@@ -231,7 +284,11 @@ impl<'a> Dispatch<'a> {
             let new_var = self.vartab.temp_anonymous(&item.ty);
             returns.push(new_var);
             return_tys.push(item.ty.clone());
-            returns_expr.push(Expression::Variable(Codegen, item.ty.clone(), new_var));
+            returns_expr.push(Expression::Variable {
+                loc: Codegen,
+                ty: item.ty.clone(),
+                var_no: new_var,
+            });
         }
 
         self.add(Instr::Call {
@@ -242,13 +299,17 @@ impl<'a> Dispatch<'a> {
         });
 
         if cfg.returns.is_empty() {
-            let data_len = Expression::NumberLiteral(Codegen, Uint(32), 0.into());
-            let data = Expression::AllocDynamicBytes(
-                Codegen,
-                Type::DynamicBytes,
-                data_len.clone().into(),
-                None,
-            );
+            let data_len = Expression::NumberLiteral {
+                loc: Codegen,
+                ty: Uint(32),
+                value: 0.into(),
+            };
+            let data = Expression::AllocDynamicBytes {
+                loc: Codegen,
+                ty: Type::DynamicBytes,
+                size: data_len.clone().into(),
+                initializer: None,
+            };
             self.add(Instr::ReturnData { data, data_len })
         } else {
             let (data, data_len) = abi_encode(
@@ -281,8 +342,18 @@ impl<'a> Dispatch<'a> {
             cond: Expression::More {
                 loc: Codegen,
                 signed: false,
-                left: Expression::Variable(Codegen, self.ns.value_type(), self.value).into(),
-                right: Expression::NumberLiteral(Codegen, self.ns.value_type(), 0.into()).into(),
+                left: Expression::Variable {
+                    loc: Codegen,
+                    ty: self.ns.value_type(),
+                    var_no: self.value,
+                }
+                .into(),
+                right: Expression::NumberLiteral {
+                    loc: Codegen,
+                    ty: self.ns.value_type(),
+                    value: 0.into(),
+                }
+                .into(),
             },
             true_block,
             false_block,
@@ -328,8 +399,18 @@ impl<'a> Dispatch<'a> {
             cond: Expression::More {
                 loc: Codegen,
                 signed: false,
-                left: Expression::Variable(Codegen, self.ns.value_type(), self.value).into(),
-                right: Expression::NumberLiteral(Codegen, self.ns.value_type(), 0.into()).into(),
+                left: Expression::Variable {
+                    loc: Codegen,
+                    ty: self.ns.value_type(),
+                    var_no: self.value,
+                }
+                .into(),
+                right: Expression::NumberLiteral {
+                    loc: Codegen,
+                    ty: self.ns.value_type(),
+                    value: 0.into(),
+                }
+                .into(),
             },
             true_block: receive_block,
             false_block: fallback_block,
@@ -343,13 +424,17 @@ impl<'a> Dispatch<'a> {
                 call: InternalCallTy::Static { cfg_no },
                 args: vec![],
             });
-            let data_len = Expression::NumberLiteral(Codegen, Uint(32), 0.into());
-            let data = Expression::AllocDynamicBytes(
-                Codegen,
-                Type::DynamicBytes,
-                data_len.clone().into(),
-                None,
-            );
+            let data_len = Expression::NumberLiteral {
+                loc: Codegen,
+                ty: Uint(32),
+                value: 0.into(),
+            };
+            let data = Expression::AllocDynamicBytes {
+                loc: Codegen,
+                ty: Type::DynamicBytes,
+                size: data_len.clone().into(),
+                initializer: None,
+            };
             self.add(Instr::ReturnData { data, data_len })
         } else {
             self.selector_invalid();
@@ -363,13 +448,17 @@ impl<'a> Dispatch<'a> {
                 call: InternalCallTy::Static { cfg_no },
                 args: vec![],
             });
-            let data_len = Expression::NumberLiteral(Codegen, Uint(32), 0.into());
-            let data = Expression::AllocDynamicBytes(
-                Codegen,
-                Type::DynamicBytes,
-                data_len.clone().into(),
-                None,
-            );
+            let data_len = Expression::NumberLiteral {
+                loc: Codegen,
+                ty: Uint(32),
+                value: 0.into(),
+            };
+            let data = Expression::AllocDynamicBytes {
+                loc: Codegen,
+                ty: Type::DynamicBytes,
+                size: data_len.clone().into(),
+                initializer: None,
+            };
             self.add(Instr::ReturnData { data, data_len })
         } else {
             self.selector_invalid()

+ 78 - 56
src/codegen/encoding/borsh_encoding.rs

@@ -27,7 +27,11 @@ impl AbiEncoding for BorshEncoding {
         _vartab: &mut Vartable,
         _cfg: &mut ControlFlowGraph,
     ) -> Expression {
-        Expression::NumberLiteral(Codegen, Uint(32), 4.into())
+        Expression::NumberLiteral {
+            loc: Codegen,
+            ty: Uint(32),
+            value: 4.into(),
+        }
     }
 
     fn encode_size(
@@ -60,13 +64,18 @@ impl AbiEncoding for BorshEncoding {
             },
         );
         let mut size = Type::FunctionSelector.memory_size_of(ns);
-        let offset = Expression::Add(
-            Codegen,
-            Uint(32),
-            false,
-            offset.clone().into(),
-            Expression::NumberLiteral(Codegen, Uint(32), size.clone()).into(),
-        );
+        let offset = Expression::Add {
+            loc: Codegen,
+            ty: Uint(32),
+            overflowing: false,
+            left: offset.clone().into(),
+            right: Expression::NumberLiteral {
+                loc: Codegen,
+                ty: Uint(32),
+                value: size.clone(),
+            }
+            .into(),
+        };
         cfg.add(
             vartab,
             Instr::WriteBuffer {
@@ -76,7 +85,11 @@ impl AbiEncoding for BorshEncoding {
             },
         );
         size.add_assign(BigInt::from(ns.address_length));
-        Expression::NumberLiteral(Codegen, Uint(32), size)
+        Expression::NumberLiteral {
+            loc: Codegen,
+            ty: Uint(32),
+            value: size,
+        }
     }
 
     fn retrieve_array_length(
@@ -92,17 +105,21 @@ impl AbiEncoding for BorshEncoding {
             Instr::Set {
                 loc: Codegen,
                 res: array_length,
-                expr: Expression::Builtin(
-                    Codegen,
-                    vec![Uint(32)],
-                    Builtin::ReadFromBuffer,
-                    vec![buffer.clone(), offset.clone()],
-                ),
+                expr: Expression::Builtin {
+                    loc: Codegen,
+                    tys: vec![Uint(32)],
+                    kind: Builtin::ReadFromBuffer,
+                    args: vec![buffer.clone(), offset.clone()],
+                },
             },
         );
         (
             array_length,
-            Expression::NumberLiteral(Codegen, Uint(32), 4.into()),
+            Expression::NumberLiteral {
+                loc: Codegen,
+                ty: Uint(32),
+                value: 4.into(),
+            },
         )
     }
 
@@ -118,41 +135,42 @@ impl AbiEncoding for BorshEncoding {
     ) -> (Expression, Expression) {
         let selector_size = Type::FunctionSelector.memory_size_of(ns);
         // External function has selector + address
-        let size = Expression::NumberLiteral(
-            Codegen,
-            Uint(32),
-            BigInt::from(ns.address_length) + &selector_size,
-        );
+        let size = Expression::NumberLiteral {
+            loc: Codegen,
+            ty: Uint(32),
+            value: BigInt::from(ns.address_length) + &selector_size,
+        };
         validator.validate_offset_plus_size(offset, &size, ns, vartab, cfg);
 
-        let selector = Expression::Builtin(
-            Codegen,
-            vec![Type::FunctionSelector],
-            Builtin::ReadFromBuffer,
-            vec![buffer.clone(), offset.clone()],
-        );
-
-        let new_offset =
-            offset
-                .clone()
-                .add_u32(Expression::NumberLiteral(Codegen, Uint(32), selector_size));
-
-        let address = Expression::Builtin(
-            Codegen,
-            vec![Type::Address(false)],
-            Builtin::ReadFromBuffer,
-            vec![buffer.clone(), new_offset],
-        );
-
-        let external_func = Expression::Cast(
-            Codegen,
-            ty.clone(),
-            Box::new(Expression::StructLiteral(
-                Codegen,
-                Type::Struct(StructType::ExternalFunction),
-                vec![selector, address],
-            )),
-        );
+        let selector = Expression::Builtin {
+            loc: Codegen,
+            tys: vec![Type::FunctionSelector],
+            kind: Builtin::ReadFromBuffer,
+            args: vec![buffer.clone(), offset.clone()],
+        };
+
+        let new_offset = offset.clone().add_u32(Expression::NumberLiteral {
+            loc: Codegen,
+            ty: Uint(32),
+            value: selector_size,
+        });
+
+        let address = Expression::Builtin {
+            loc: Codegen,
+            tys: vec![Type::Address(false)],
+            kind: Builtin::ReadFromBuffer,
+            args: vec![buffer.clone(), new_offset],
+        };
+
+        let external_func = Expression::Cast {
+            loc: Codegen,
+            ty: ty.clone(),
+            expr: Box::new(Expression::StructLiteral {
+                loc: Codegen,
+                ty: Type::Struct(StructType::ExternalFunction),
+                values: vec![selector, address],
+            }),
+        };
 
         (external_func, size)
     }
@@ -164,17 +182,21 @@ impl AbiEncoding for BorshEncoding {
         _cfg: &mut ControlFlowGraph,
     ) -> Expression {
         // When encoding a variable length array, the total size is "length (u32)" + elements
-        let length = Expression::Builtin(
-            Codegen,
-            vec![Uint(32)],
-            Builtin::ArrayLength,
-            vec![expr.clone()],
-        );
+        let length = Expression::Builtin {
+            loc: Codegen,
+            tys: vec![Uint(32)],
+            kind: Builtin::ArrayLength,
+            args: vec![expr.clone()],
+        };
 
         if self.is_packed() {
             length
         } else {
-            length.add_u32(Expression::NumberLiteral(Codegen, Uint(32), 4.into()))
+            length.add_u32(Expression::NumberLiteral {
+                loc: Codegen,
+                ty: Uint(32),
+                value: 4.into(),
+            })
         }
     }
 

+ 23 - 19
src/codegen/encoding/buffer_validator.rs

@@ -27,7 +27,11 @@ pub(crate) struct BufferValidator<'a> {
 impl BufferValidator<'_> {
     pub fn new(buffer_size_var: usize, types: &[Type]) -> BufferValidator {
         BufferValidator {
-            buffer_length: Expression::Variable(Loc::Codegen, Type::Uint(32), buffer_size_var),
+            buffer_length: Expression::Variable {
+                loc: Loc::Codegen,
+                ty: Type::Uint(32),
+                var_no: buffer_size_var,
+            },
             types,
             verified_until: None,
             current_arg: 0,
@@ -99,13 +103,13 @@ impl BufferValidator<'_> {
         cfg: &mut ControlFlowGraph,
     ) {
         if self.validation_necessary() {
-            let offset_to_validate = Expression::Add(
-                Loc::Codegen,
-                Type::Uint(32),
-                false,
-                Box::new(offset.clone()),
-                Box::new(size.clone()),
-            );
+            let offset_to_validate = Expression::Add {
+                loc: Loc::Codegen,
+                ty: Type::Uint(32),
+                overflowing: false,
+                left: Box::new(offset.clone()),
+                right: Box::new(size.clone()),
+            };
             self.validate_offset(offset_to_validate, ns, vartab, cfg);
         }
     }
@@ -173,17 +177,17 @@ impl BufferValidator<'_> {
             advance.add_assign(self.types[i].memory_size_of(ns));
         }
 
-        let reach = Expression::Add(
-            Loc::Codegen,
-            Type::Uint(32),
-            false,
-            Box::new(offset.clone()),
-            Box::new(Expression::NumberLiteral(
-                Loc::Codegen,
-                Type::Uint(32),
-                advance,
-            )),
-        );
+        let reach = Expression::Add {
+            loc: Loc::Codegen,
+            ty: Type::Uint(32),
+            overflowing: false,
+            left: Box::new(offset.clone()),
+            right: Box::new(Expression::NumberLiteral {
+                loc: Loc::Codegen,
+                ty: Type::Uint(32),
+                value: advance,
+            }),
+        };
 
         self.verified_until = Some(maximum_verifiable);
         self.build_out_of_bounds_fail_branch(reach, ns, vartab, cfg);

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 427 - 175
src/codegen/encoding/mod.rs


+ 218 - 88
src/codegen/encoding/scale_encoding.rs

@@ -37,35 +37,68 @@ fn decode_compact(
     let decoded_var = vartab.temp_anonymous(&Uint(32));
     let size_width_var = vartab.temp_anonymous(&Uint(32));
     vartab.new_dirty_tracker();
-    let read_byte = Expression::Builtin(
-        Codegen,
-        vec![Uint(8)],
-        Builtin::ReadFromBuffer,
-        vec![buffer.clone(), offset.clone()],
-    );
+    let read_byte = Expression::Builtin {
+        loc: Codegen,
+        tys: vec![Uint(8)],
+        kind: Builtin::ReadFromBuffer,
+        args: vec![buffer.clone(), offset.clone()],
+    };
     cfg.add(
         vartab,
         Instr::Set {
             loc: Codegen,
             res: size_width_var,
-            expr: Expression::ZeroExt(Codegen, Uint(32), read_byte.into()),
+            expr: Expression::ZeroExt {
+                loc: Codegen,
+                ty: Uint(32),
+                expr: read_byte.into(),
+            },
         },
     );
-    let size_width = Expression::Variable(Codegen, Uint(32), size_width_var);
-    let two = Expression::NumberLiteral(Codegen, Uint(32), 2.into());
-    let three = Expression::NumberLiteral(Codegen, Uint(32), 3.into());
-    let cond = Expression::BitwiseAnd(Codegen, Uint(32), size_width.clone().into(), three.into());
+    let size_width = Expression::Variable {
+        loc: Codegen,
+        ty: Uint(32),
+        var_no: size_width_var,
+    };
+    let two = Expression::NumberLiteral {
+        loc: Codegen,
+        ty: Uint(32),
+        value: 2.into(),
+    };
+    let three = Expression::NumberLiteral {
+        loc: Codegen,
+        ty: Uint(32),
+        value: 3.into(),
+    };
+    let cond = Expression::BitwiseAnd {
+        loc: Codegen,
+        ty: Uint(32),
+        left: size_width.clone().into(),
+        right: three.into(),
+    };
     let cases = &[
         (
-            Expression::NumberLiteral(Codegen, Uint(32), 0.into()),
+            Expression::NumberLiteral {
+                loc: Codegen,
+                ty: Uint(32),
+                value: 0.into(),
+            },
             cfg.new_basic_block("case_0".into()),
         ),
         (
-            Expression::NumberLiteral(Codegen, Uint(32), 1.into()),
+            Expression::NumberLiteral {
+                loc: Codegen,
+                ty: Uint(32),
+                value: 1.into(),
+            },
             cfg.new_basic_block("case_1".into()),
         ),
         (
-            Expression::NumberLiteral(Codegen, Uint(32), 2.into()),
+            Expression::NumberLiteral {
+                loc: Codegen,
+                ty: Uint(32),
+                value: 2.into(),
+            },
             cfg.new_basic_block("case_2".into()),
         ),
     ];
@@ -86,13 +119,13 @@ fn decode_compact(
     cfg.add(vartab, Instr::AssertFailure { encoded_args: None });
 
     cfg.set_basic_block(cases[0].1);
-    let expr = Expression::ShiftRight(
-        Codegen,
-        Uint(32),
-        size_width.clone().into(),
-        two.clone().into(),
-        false,
-    );
+    let expr = Expression::ShiftRight {
+        loc: Codegen,
+        ty: Uint(32),
+        left: size_width.clone().into(),
+        right: two.clone().into(),
+        signed: false,
+    };
     cfg.add(
         vartab,
         Instr::Set {
@@ -106,25 +139,34 @@ fn decode_compact(
         Instr::Set {
             loc: Codegen,
             res: size_width_var,
-            expr: Expression::NumberLiteral(Codegen, Uint(32), 1.into()),
+            expr: Expression::NumberLiteral {
+                loc: Codegen,
+                ty: Uint(32),
+                value: 1.into(),
+            },
         },
     );
     cfg.add(vartab, Instr::Branch { block: done });
 
     cfg.set_basic_block(cases[1].1);
-    let read_byte = Expression::Builtin(
-        Codegen,
-        vec![Uint(16)],
-        Builtin::ReadFromBuffer,
-        vec![buffer.clone(), offset.clone()],
-    );
-    let expr = Expression::ShiftRight(
-        Codegen,
-        Uint(32),
-        Expression::ZeroExt(Codegen, Uint(32), read_byte.into()).into(),
-        two.clone().into(),
-        false,
-    );
+    let read_byte = Expression::Builtin {
+        loc: Codegen,
+        tys: vec![Uint(16)],
+        kind: Builtin::ReadFromBuffer,
+        args: vec![buffer.clone(), offset.clone()],
+    };
+    let expr = Expression::ShiftRight {
+        loc: Codegen,
+        ty: Uint(32),
+        left: Expression::ZeroExt {
+            loc: Codegen,
+            ty: Uint(32),
+            expr: read_byte.into(),
+        }
+        .into(),
+        right: two.clone().into(),
+        signed: false,
+    };
     cfg.add(
         vartab,
         Instr::Set {
@@ -144,13 +186,19 @@ fn decode_compact(
     cfg.add(vartab, Instr::Branch { block: done });
 
     cfg.set_basic_block(cases[2].1);
-    let read_byte = Expression::Builtin(
-        Codegen,
-        vec![Uint(32)],
-        Builtin::ReadFromBuffer,
-        vec![buffer.clone(), offset.clone()],
-    );
-    let expr = Expression::ShiftRight(Codegen, Uint(32), read_byte.into(), two.into(), false);
+    let read_byte = Expression::Builtin {
+        loc: Codegen,
+        tys: vec![Uint(32)],
+        kind: Builtin::ReadFromBuffer,
+        args: vec![buffer.clone(), offset.clone()],
+    };
+    let expr = Expression::ShiftRight {
+        loc: Codegen,
+        ty: Uint(32),
+        left: read_byte.into(),
+        right: two.into(),
+        signed: false,
+    };
     cfg.add(
         vartab,
         Instr::Set {
@@ -164,7 +212,11 @@ fn decode_compact(
         Instr::Set {
             loc: Codegen,
             res: size_width_var,
-            expr: Expression::NumberLiteral(Codegen, Uint(32), 4.into()),
+            expr: Expression::NumberLiteral {
+                loc: Codegen,
+                ty: Uint(32),
+                value: 4.into(),
+            },
         },
     );
     cfg.add(vartab, Instr::Branch { block: done });
@@ -194,7 +246,11 @@ fn encode_compact(
     let done = cfg.new_basic_block("done".into());
     let fail = cfg.new_basic_block("fail".into());
     let prepare = cfg.new_basic_block("prepare".into());
-    let cmp_val = Expression::NumberLiteral(Codegen, Uint(32), (0x40000000 - 1).into());
+    let cmp_val = Expression::NumberLiteral {
+        loc: Codegen,
+        ty: Uint(32),
+        value: (0x40000000 - 1).into(),
+    };
     let compare = Expression::More {
         loc: Codegen,
         signed: false,
@@ -214,7 +270,11 @@ fn encode_compact(
     cfg.add(vartab, Instr::AssertFailure { encoded_args: None });
 
     cfg.set_basic_block(prepare);
-    let cmp_val = Expression::NumberLiteral(Codegen, Uint(32), (0x40 - 1).into());
+    let cmp_val = Expression::NumberLiteral {
+        loc: Codegen,
+        ty: Uint(32),
+        value: (0x40 - 1).into(),
+    };
     let compare = Expression::More {
         loc: Codegen,
         signed: false,
@@ -231,7 +291,11 @@ fn encode_compact(
     );
 
     cfg.set_basic_block(medium_or_big);
-    let cmp_val = Expression::NumberLiteral(Codegen, Uint(32), (0x4000 - 1).into());
+    let cmp_val = Expression::NumberLiteral {
+        loc: Codegen,
+        ty: Uint(32),
+        value: (0x4000 - 1).into(),
+    };
     let compare = Expression::More {
         loc: Codegen,
         signed: false,
@@ -248,8 +312,19 @@ fn encode_compact(
     );
     let size_variable = vartab.temp_anonymous(&Uint(32));
     vartab.new_dirty_tracker();
-    let four = Expression::NumberLiteral(Codegen, Uint(32), 4.into()).into();
-    let mul = Expression::Multiply(Codegen, Uint(32), false, expr.clone().into(), four);
+    let four = Expression::NumberLiteral {
+        loc: Codegen,
+        ty: Uint(32),
+        value: 4.into(),
+    }
+    .into();
+    let mul = Expression::Multiply {
+        loc: Codegen,
+        ty: Uint(32),
+        overflowing: false,
+        left: expr.clone().into(),
+        right: four,
+    };
 
     cfg.set_basic_block(small);
     if let (Some(buffer), Some(offset)) = (buffer, offset) {
@@ -258,11 +333,19 @@ fn encode_compact(
             Instr::WriteBuffer {
                 buf: buffer.clone(),
                 offset: offset.clone(),
-                value: Expression::Cast(Codegen, Uint(8), mul.clone().into()),
+                value: Expression::Cast {
+                    loc: Codegen,
+                    ty: Uint(8),
+                    expr: mul.clone().into(),
+                },
             },
         );
     }
-    let one = Expression::NumberLiteral(Codegen, Uint(32), 1.into());
+    let one = Expression::NumberLiteral {
+        loc: Codegen,
+        ty: Uint(32),
+        value: 1.into(),
+    };
     cfg.add(
         vartab,
         Instr::Set {
@@ -275,17 +358,30 @@ fn encode_compact(
 
     cfg.set_basic_block(medium);
     if let (Some(buffer), Some(offset)) = (buffer, offset) {
-        let mul = Expression::BitwiseOr(Codegen, Uint(32), mul.clone().into(), one.into());
+        let mul = Expression::BitwiseOr {
+            loc: Codegen,
+            ty: Uint(32),
+            left: mul.clone().into(),
+            right: one.into(),
+        };
         cfg.add(
             vartab,
             Instr::WriteBuffer {
                 buf: buffer.clone(),
                 offset: offset.clone(),
-                value: Expression::Cast(Codegen, Uint(16), mul.into()),
+                value: Expression::Cast {
+                    loc: Codegen,
+                    ty: Uint(16),
+                    expr: mul.into(),
+                },
             },
         );
     }
-    let two = Expression::NumberLiteral(Codegen, Uint(32), 2.into());
+    let two = Expression::NumberLiteral {
+        loc: Codegen,
+        ty: Uint(32),
+        value: 2.into(),
+    };
     cfg.add(
         vartab,
         Instr::Set {
@@ -303,7 +399,12 @@ fn encode_compact(
             Instr::WriteBuffer {
                 buf: buffer.clone(),
                 offset: offset.clone(),
-                value: Expression::BitwiseOr(Codegen, Uint(32), mul.into(), two.into()),
+                value: Expression::BitwiseOr {
+                    loc: Codegen,
+                    ty: Uint(32),
+                    left: mul.into(),
+                    right: two.into(),
+                },
             },
         );
     }
@@ -312,14 +413,22 @@ fn encode_compact(
         Instr::Set {
             loc: Codegen,
             res: size_variable,
-            expr: Expression::NumberLiteral(Codegen, Uint(32), 4.into()),
+            expr: Expression::NumberLiteral {
+                loc: Codegen,
+                ty: Uint(32),
+                value: 4.into(),
+            },
         },
     );
     cfg.add(vartab, Instr::Branch { block: done });
 
     cfg.set_basic_block(done);
     cfg.set_phis(done, vartab.pop_dirty_tracker());
-    Expression::Variable(Codegen, Uint(32), size_variable)
+    Expression::Variable {
+        loc: Codegen,
+        ty: Uint(32),
+        var_no: size_variable,
+    }
 }
 
 impl AbiEncoding for ScaleEncoding {
@@ -352,10 +461,20 @@ impl AbiEncoding for ScaleEncoding {
         let addr_len = ns.address_length.into();
         let address = expr.external_function_address();
         let size = self.encode_directly(&address, buffer, offset, vartab, cfg, addr_len);
-        let offset = Expression::Add(Codegen, Uint(32), false, offset.clone().into(), size.into());
+        let offset = Expression::Add {
+            loc: Codegen,
+            ty: Uint(32),
+            overflowing: false,
+            left: offset.clone().into(),
+            right: size.into(),
+        };
         let selector = expr.external_function_selector();
         self.encode_directly(&selector, buffer, &offset, vartab, cfg, 4.into());
-        Expression::NumberLiteral(Codegen, Uint(32), (ns.address_length + 4).into())
+        Expression::NumberLiteral {
+            loc: Codegen,
+            ty: Uint(32),
+            value: (ns.address_length + 4).into(),
+        }
     }
 
     fn encode_size(
@@ -380,31 +499,42 @@ impl AbiEncoding for ScaleEncoding {
         vartab: &mut Vartable,
         cfg: &mut ControlFlowGraph,
     ) -> (Expression, Expression) {
-        let size = Expression::NumberLiteral(Codegen, Uint(32), (ns.address_length + 4).into());
+        let size = Expression::NumberLiteral {
+            loc: Codegen,
+            ty: Uint(32),
+            value: (ns.address_length + 4).into(),
+        };
         validator.validate_offset_plus_size(offset, &size, ns, vartab, cfg);
-        let address = Expression::Builtin(
-            Codegen,
-            vec![Type::Address(false)],
-            Builtin::ReadFromBuffer,
-            vec![buffer.clone(), offset.clone()],
-        );
-        let new_offset = offset.clone().add_u32(Expression::NumberLiteral(
-            Codegen,
-            Uint(32),
-            ns.address_length.into(),
-        ));
-        let selector = Expression::Builtin(
-            Codegen,
-            vec![Type::FunctionSelector],
-            Builtin::ReadFromBuffer,
-            vec![buffer.clone(), new_offset],
-        );
-        let ext_func = Expression::StructLiteral(
-            Codegen,
-            Type::Struct(StructType::ExternalFunction),
-            vec![selector, address],
-        );
-        (Expression::Cast(Codegen, ty.clone(), ext_func.into()), size)
+        let address = Expression::Builtin {
+            loc: Codegen,
+            tys: vec![Type::Address(false)],
+            kind: Builtin::ReadFromBuffer,
+            args: vec![buffer.clone(), offset.clone()],
+        };
+        let new_offset = offset.clone().add_u32(Expression::NumberLiteral {
+            loc: Codegen,
+            ty: Uint(32),
+            value: ns.address_length.into(),
+        });
+        let selector = Expression::Builtin {
+            loc: Codegen,
+            tys: vec![Type::FunctionSelector],
+            kind: Builtin::ReadFromBuffer,
+            args: vec![buffer.clone(), new_offset],
+        };
+        let ext_func = Expression::StructLiteral {
+            loc: Codegen,
+            ty: Type::Struct(StructType::ExternalFunction),
+            values: vec![selector, address],
+        };
+        (
+            Expression::Cast {
+                loc: Codegen,
+                ty: ty.clone(),
+                expr: ext_func.into(),
+            },
+            size,
+        )
     }
 
     fn retrieve_array_length(
@@ -432,12 +562,12 @@ impl AbiEncoding for ScaleEncoding {
         cfg: &mut ControlFlowGraph,
     ) -> Expression {
         // When encoding a variable length array, the total size is "compact encoded array length + N elements"
-        let length = Expression::Builtin(
-            Codegen,
-            vec![Uint(32)],
-            Builtin::ArrayLength,
-            vec![expr.clone()],
-        );
+        let length = Expression::Builtin {
+            loc: Codegen,
+            tys: vec![Uint(32)],
+            kind: Builtin::ArrayLength,
+            args: vec![expr.clone()],
+        };
         if self.is_packed() {
             length
         } else {

+ 5 - 2
src/codegen/events/solana.rs

@@ -34,8 +34,11 @@ impl EventEmitter for SolanaEventEmitter<'_> {
         hasher.update(discriminator_image.as_bytes());
         let result = hasher.finalize();
 
-        let discriminator =
-            Expression::BytesLiteral(Loc::Codegen, Type::Bytes(8), result[..8].to_vec());
+        let discriminator = Expression::BytesLiteral {
+            loc: Loc::Codegen,
+            ty: Type::Bytes(8),
+            value: result[..8].to_vec(),
+        };
 
         let mut codegen_args = self
             .args

+ 46 - 21
src/codegen/events/substrate.rs

@@ -47,13 +47,21 @@ impl EventEmitter for SubstrateEventEmitter<'_> {
         let event = &self.ns.events[self.event_no];
         // For freestanding events the name of the emitting contract is used
         let contract_name = &self.ns.contracts[event.contract.unwrap_or(contract_no)].name;
-        let hash_len = Box::new(Expression::NumberLiteral(loc, Type::Uint(32), 32.into()));
+        let hash_len = Box::new(Expression::NumberLiteral {
+            loc,
+            ty: Type::Uint(32),
+            value: 32.into(),
+        });
         let id = self.ns.contracts[contract_no]
             .emits_events
             .iter()
             .position(|e| *e == self.event_no)
             .expect("contract emits this event");
-        let mut data = vec![Expression::NumberLiteral(loc, Type::Uint(8), id.into())];
+        let mut data = vec![Expression::NumberLiteral {
+            loc,
+            ty: Type::Uint(8),
+            value: id.into(),
+        }];
         let mut topics = vec![];
 
         // Events that are not anonymous always have themselves as a topic.
@@ -61,12 +69,12 @@ impl EventEmitter for SubstrateEventEmitter<'_> {
         if !event.anonymous {
             // First byte is 0 because there is no prefix for the event topic
             let encoded = format!("\0{}::{}", contract_name, &event.name);
-            topics.push(Expression::AllocDynamicBytes(
+            topics.push(Expression::AllocDynamicBytes {
                 loc,
-                Type::Slice(Type::Uint(8).into()),
-                hash_len.clone(),
-                Some(topic_hash(encoded.as_bytes())),
-            ));
+                ty: Type::Slice(Type::Uint(8).into()),
+                size: hash_len.clone(),
+                initializer: Some(topic_hash(encoded.as_bytes())),
+            });
         };
 
         // Topic prefixes are static and can be calculated at compile time.
@@ -89,7 +97,11 @@ impl EventEmitter for SubstrateEventEmitter<'_> {
         for (ast_exp, field) in self.args.iter().zip(event.fields.iter()) {
             let value_exp = expression(ast_exp, cfg, contract_no, Some(func), self.ns, vartab, opt);
             let value_var = vartab.temp_anonymous(&value_exp.ty());
-            let value = Expression::Variable(loc, value_exp.ty(), value_var);
+            let value = Expression::Variable {
+                loc,
+                ty: value_exp.ty(),
+                var_no: value_var,
+            };
             cfg.add(
                 vartab,
                 Instr::Set {
@@ -107,7 +119,12 @@ impl EventEmitter for SubstrateEventEmitter<'_> {
             let encoded = abi_encode(&loc, vec![value], self.ns, vartab, cfg, false).0;
             let prefix = StringLocation::CompileTime(topic_prefixes.pop_front().unwrap());
             let value = StringLocation::RunTime(encoded.into());
-            let concatenated = Expression::StringConcat(loc, Type::DynamicBytes, prefix, value);
+            let concatenated = Expression::StringConcat {
+                loc,
+                ty: Type::DynamicBytes,
+                left: prefix,
+                right: value,
+            };
 
             vartab.new_dirty_tracker();
             let var_buffer = vartab.temp_anonymous(&Type::DynamicBytes);
@@ -119,16 +136,20 @@ impl EventEmitter for SubstrateEventEmitter<'_> {
                     expr: concatenated,
                 },
             );
-            let buffer = Expression::Variable(loc, Type::DynamicBytes, var_buffer);
+            let buffer = Expression::Variable {
+                loc,
+                ty: Type::DynamicBytes,
+                var_no: var_buffer,
+            };
             let compare = Expression::More {
                 loc,
                 signed: false,
-                left: Expression::Builtin(
+                left: Expression::Builtin {
                     loc,
-                    vec![Type::Uint(32)],
-                    Builtin::ArrayLength,
-                    vec![buffer.clone()],
-                )
+                    tys: vec![Type::Uint(32)],
+                    kind: Builtin::ArrayLength,
+                    args: vec![buffer.clone()],
+                }
                 .into(),
                 right: hash_len.clone(),
             };
@@ -149,13 +170,17 @@ impl EventEmitter for SubstrateEventEmitter<'_> {
                 vartab,
                 Instr::WriteBuffer {
                     buf: buffer.clone(),
-                    offset: Expression::NumberLiteral(loc, Type::Uint(32), 0.into()),
-                    value: Expression::Builtin(
+                    offset: Expression::NumberLiteral {
+                        loc,
+                        ty: Type::Uint(32),
+                        value: 0.into(),
+                    },
+                    value: Expression::Builtin {
                         loc,
-                        vec![Type::Bytes(32)],
-                        Builtin::Blake2_256,
-                        vec![buffer.clone()],
-                    ),
+                        tys: vec![Type::Bytes(32)],
+                        kind: Builtin::Blake2_256,
+                        args: vec![buffer.clone()],
+                    },
                 },
             );
             vartab.set_dirty(var_buffer);

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 408 - 259
src/codegen/expression.rs


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 631 - 332
src/codegen/mod.rs


+ 3 - 3
src/codegen/reaching_definitions.rs

@@ -121,7 +121,7 @@ fn instr_transfers(block_no: usize, block: &BasicBlock) -> Vec<Vec<Transfer>> {
         transfers.push(match instr {
             Instr::Set {
                 res,
-                expr: Expression::Variable(_, _, src),
+                expr: Expression::Variable { var_no: src, .. },
                 ..
             } => {
                 vec![
@@ -181,8 +181,8 @@ fn instr_transfers(block_no: usize, block: &BasicBlock) -> Vec<Vec<Transfer>> {
 
 fn array_var(expr: &Expression) -> Option<usize> {
     match expr {
-        Expression::Variable(_, _, var_no) => Some(*var_no),
-        Expression::Subscript(_, _, _, expr, _) | Expression::StructMember(_, _, expr, _) => {
+        Expression::Variable { var_no, .. } => Some(*var_no),
+        Expression::Subscript { expr, .. } | Expression::StructMember { expr, .. } => {
             array_var(expr)
         }
         _ => None,

+ 14 - 15
src/codegen/solana_accounts.rs

@@ -405,9 +405,9 @@ fn check_instruction(instr: &Instr, data: &mut RecurseData) {
         } => {
             if let Some(address) = address {
                 address.recurse(data, check_expression);
-                if let Expression::NumberLiteral(_, _, num) = address {
+                if let Expression::NumberLiteral { value, .. } = address {
                     // Check if we can auto populate this account
-                    if let Some(account) = account_from_number(num) {
+                    if let Some(account) = account_from_number(value) {
                         data.add_account(
                             account.to_string(),
                             SolanaAccount {
@@ -465,12 +465,10 @@ fn check_instruction(instr: &Instr, data: &mut RecurseData) {
 /// Collect accounts from this expression
 fn check_expression(expr: &Expression, data: &mut RecurseData) -> bool {
     match expr {
-        Expression::Builtin(
-            _,
-            _,
-            Builtin::Timestamp | Builtin::BlockNumber | Builtin::Slot,
-            ..,
-        ) => {
+        Expression::Builtin {
+            kind: Builtin::Timestamp | Builtin::BlockNumber | Builtin::Slot,
+            ..
+        } => {
             data.add_account(
                 CLOCK_ACCOUNT.to_string(),
                 SolanaAccount {
@@ -479,7 +477,10 @@ fn check_expression(expr: &Expression, data: &mut RecurseData) -> bool {
                 },
             );
         }
-        Expression::Builtin(_, _, Builtin::SignatureVerify, ..) => {
+        Expression::Builtin {
+            kind: Builtin::SignatureVerify,
+            ..
+        } => {
             data.add_account(
                 INSTRUCTION_ACCOUNT.to_string(),
                 SolanaAccount {
@@ -488,12 +489,10 @@ fn check_expression(expr: &Expression, data: &mut RecurseData) -> bool {
                 },
             );
         }
-        Expression::Builtin(
-            _,
-            _,
-            Builtin::Ripemd160 | Builtin::Keccak256 | Builtin::Sha256,
-            ..,
-        ) => {
+        Expression::Builtin {
+            kind: Builtin::Ripemd160 | Builtin::Keccak256 | Builtin::Sha256,
+            ..
+        } => {
             data.add_system_account();
         }
 

+ 259 - 172
src/codegen/solana_deploy.rs

@@ -32,20 +32,20 @@ pub(super) fn solana_deploy(
 
     if let Some(program_id) = program_id {
         // emit code to check program_id == program_id
-        let cond = Expression::Equal(
-            Loc::Codegen,
-            Box::new(Expression::NumberLiteral(
-                Loc::Codegen,
-                Type::Address(false),
-                BigInt::from_bytes_be(Sign::Plus, program_id),
-            )),
-            Box::new(Expression::Builtin(
-                Loc::Codegen,
-                vec![Type::Address(false)],
-                Builtin::ProgramId,
-                Vec::new(),
-            )),
-        );
+        let cond = Expression::Equal {
+            loc: Loc::Codegen,
+            left: Box::new(Expression::NumberLiteral {
+                loc: Loc::Codegen,
+                ty: Type::Address(false),
+                value: BigInt::from_bytes_be(Sign::Plus, program_id),
+            }),
+            right: Box::new(Expression::Builtin {
+                loc: Loc::Codegen,
+                tys: vec![Type::Address(false)],
+                kind: Builtin::ProgramId,
+                args: Vec::new(),
+            }),
+        };
 
         let id_fail = cfg.new_basic_block("program_id_fail".to_string());
 
@@ -64,16 +64,16 @@ pub(super) fn solana_deploy(
 
         let message = format!("program_id should be {}", program_id.to_base58()).into_bytes();
 
-        let expr = Expression::AllocDynamicBytes(
-            Loc::Codegen,
-            Type::String,
-            Box::new(Expression::NumberLiteral(
-                Loc::Codegen,
-                Type::Uint(32),
-                BigInt::from(message.len()),
-            )),
-            Some(message),
-        );
+        let expr = Expression::AllocDynamicBytes {
+            loc: Loc::Codegen,
+            ty: Type::String,
+            size: Box::new(Expression::NumberLiteral {
+                loc: Loc::Codegen,
+                ty: Type::Uint(32),
+                value: BigInt::from(message.len()),
+            }),
+            initializer: Some(message),
+        };
 
         cfg.add(vartab, Instr::Print { expr });
 
@@ -91,38 +91,43 @@ pub(super) fn solana_deploy(
     // account via `tx.accounts[0].data.length`.
 
     // tx.accounts[0]
-    let tx_account_0 = Expression::Subscript(
-        Loc::Codegen,
-        Type::Struct(StructType::AccountInfo),
-        Type::Array(
+    let tx_account_0 = Expression::Subscript {
+        loc: Loc::Codegen,
+        ty: Type::Struct(StructType::AccountInfo),
+        array_ty: Type::Array(
             Type::Struct(StructType::AccountInfo).into(),
             vec![ArrayLength::Dynamic],
         ),
-        Expression::Builtin(
-            Loc::Codegen,
-            vec![Type::Array(
+        expr: Expression::Builtin {
+            loc: Loc::Codegen,
+            tys: vec![Type::Array(
                 Type::Struct(StructType::AccountInfo).into(),
                 vec![ArrayLength::Dynamic],
             )],
-            Builtin::Accounts,
-            vec![],
-        )
+            kind: Builtin::Accounts,
+            args: vec![],
+        }
         .into(),
-        Expression::NumberLiteral(Loc::Codegen, Type::Uint(32), BigInt::zero()).into(),
-    );
+        index: Expression::NumberLiteral {
+            loc: Loc::Codegen,
+            ty: Type::Uint(32),
+            value: BigInt::zero(),
+        }
+        .into(),
+    };
 
     // .data.length
-    let account_length = Expression::Builtin(
-        Loc::Codegen,
-        vec![Type::Uint(32)],
-        Builtin::ArrayLength,
-        vec![Expression::StructMember(
-            Loc::Codegen,
-            Type::DynamicBytes,
-            tx_account_0.into(),
-            2,
-        )],
-    );
+    let account_length = Expression::Builtin {
+        loc: Loc::Codegen,
+        tys: vec![Type::Uint(32)],
+        kind: Builtin::ArrayLength,
+        args: vec![Expression::StructMember {
+            loc: Loc::Codegen,
+            ty: Type::DynamicBytes,
+            expr: tx_account_0.into(),
+            member: 2,
+        }],
+    };
 
     let account_data_var = vartab.temp_name("data_length", &Type::Uint(32));
 
@@ -135,13 +140,22 @@ pub(super) fn solana_deploy(
         },
     );
 
-    let account_length = Expression::Variable(Loc::Codegen, Type::Uint(32), account_data_var);
+    let account_length = Expression::Variable {
+        loc: Loc::Codegen,
+        ty: Type::Uint(32),
+        var_no: account_data_var,
+    };
 
-    let account_no_data = Expression::Equal(
-        Loc::Codegen,
-        account_length.clone().into(),
-        Expression::NumberLiteral(Loc::Codegen, Type::Uint(32), 0.into()).into(),
-    );
+    let account_no_data = Expression::Equal {
+        loc: Loc::Codegen,
+        left: account_length.clone().into(),
+        right: Expression::NumberLiteral {
+            loc: Loc::Codegen,
+            ty: Type::Uint(32),
+            value: 0.into(),
+        }
+        .into(),
+    };
 
     let account_exists = cfg.new_basic_block("account_exists".into());
     let create_account = cfg.new_basic_block("create_account".into());
@@ -161,11 +175,11 @@ pub(super) fn solana_deploy(
         loc: Loc::Codegen,
         signed: false,
         left: account_length.into(),
-        right: Expression::NumberLiteral(
-            Loc::Codegen,
-            Type::Uint(32),
-            contract.fixed_layout_size.clone(),
-        )
+        right: Expression::NumberLiteral {
+            loc: Loc::Codegen,
+            ty: Type::Uint(32),
+            value: contract.fixed_layout_size.clone(),
+        }
         .into(),
     };
 
@@ -231,44 +245,56 @@ pub(super) fn solana_deploy(
             Instr::Set {
                 loc: Loc::Codegen,
                 res: metas,
-                expr: Expression::ArrayLiteral(
-                    Loc::Codegen,
-                    metas_ty.clone(),
-                    vec![2],
-                    vec![
-                        Expression::StructLiteral(
-                            Loc::Codegen,
-                            Type::Struct(StructType::AccountMeta),
-                            vec![
-                                Expression::GetRef(
-                                    Loc::Codegen,
-                                    Type::Address(false),
-                                    Box::new(payer),
-                                ),
-                                Expression::BoolLiteral(Loc::Codegen, true),
-                                Expression::BoolLiteral(Loc::Codegen, true),
+                expr: Expression::ArrayLiteral {
+                    loc: Loc::Codegen,
+                    ty: metas_ty.clone(),
+                    dimensions: vec![2],
+                    values: vec![
+                        Expression::StructLiteral {
+                            loc: Loc::Codegen,
+                            ty: Type::Struct(StructType::AccountMeta),
+                            values: vec![
+                                Expression::GetRef {
+                                    loc: Loc::Codegen,
+                                    ty: Type::Address(false),
+                                    expr: Box::new(payer),
+                                },
+                                Expression::BoolLiteral {
+                                    loc: Loc::Codegen,
+                                    value: true,
+                                },
+                                Expression::BoolLiteral {
+                                    loc: Loc::Codegen,
+                                    value: true,
+                                },
                             ],
-                        ),
-                        Expression::StructLiteral(
-                            Loc::Codegen,
-                            Type::Struct(StructType::AccountMeta),
-                            vec![
-                                Expression::GetRef(
-                                    Loc::Codegen,
-                                    Type::Address(false),
-                                    Box::new(Expression::Builtin(
-                                        Loc::Codegen,
-                                        vec![Type::Address(false)],
-                                        Builtin::GetAddress,
-                                        vec![],
-                                    )),
-                                ),
-                                Expression::BoolLiteral(Loc::Codegen, true),
-                                Expression::BoolLiteral(Loc::Codegen, true),
+                        },
+                        Expression::StructLiteral {
+                            loc: Loc::Codegen,
+                            ty: Type::Struct(StructType::AccountMeta),
+                            values: vec![
+                                Expression::GetRef {
+                                    loc: Loc::Codegen,
+                                    ty: Type::Address(false),
+                                    expr: Box::new(Expression::Builtin {
+                                        loc: Loc::Codegen,
+                                        tys: vec![Type::Address(false)],
+                                        kind: Builtin::GetAddress,
+                                        args: vec![],
+                                    }),
+                                },
+                                Expression::BoolLiteral {
+                                    loc: Loc::Codegen,
+                                    value: true,
+                                },
+                                Expression::BoolLiteral {
+                                    loc: Loc::Codegen,
+                                    value: true,
+                                },
                             ],
-                        ),
+                        },
                     ],
-                ),
+                },
             },
         );
 
@@ -290,24 +316,37 @@ pub(super) fn solana_deploy(
                 },
             );
 
-            let space = Expression::Variable(Loc::Codegen, Type::Uint(64), space_var);
+            let space = Expression::Variable {
+                loc: Loc::Codegen,
+                ty: Type::Uint(64),
+                var_no: space_var,
+            };
 
             // https://github.com/solana-labs/solana/blob/718f433206c124da85a8aa2476c0753f351f9a28/sdk/program/src/rent.rs#L78-L82
-            let lamports = Expression::Multiply(
-                Loc::Codegen,
-                Type::Uint(64),
-                false,
-                Expression::Add(
-                    Loc::Codegen,
-                    Type::Uint(64),
-                    false,
-                    space.clone().into(),
-                    Expression::NumberLiteral(Loc::Codegen, Type::Uint(64), 128.into()).into(),
-                )
-                .into(),
-                Expression::NumberLiteral(Loc::Codegen, Type::Uint(64), BigInt::from(3480 * 2))
+            let lamports = Expression::Multiply {
+                loc: Loc::Codegen,
+                ty: Type::Uint(64),
+                overflowing: false,
+                left: Expression::Add {
+                    loc: Loc::Codegen,
+                    ty: Type::Uint(64),
+                    overflowing: false,
+                    left: space.clone().into(),
+                    right: Expression::NumberLiteral {
+                        loc: Loc::Codegen,
+                        ty: Type::Uint(64),
+                        value: 128.into(),
+                    }
                     .into(),
-            );
+                }
+                .into(),
+                right: Expression::NumberLiteral {
+                    loc: Loc::Codegen,
+                    ty: Type::Uint(64),
+                    value: BigInt::from(3480 * 2),
+                }
+                .into(),
+            };
 
             (space, lamports)
         } else {
@@ -317,21 +356,25 @@ pub(super) fn solana_deploy(
             let lamports_runtime_constant = (128 + space_runtime_constant) * 3480 * 2;
 
             (
-                Expression::NumberLiteral(
-                    Loc::Codegen,
-                    Type::Uint(64),
-                    space_runtime_constant.into(),
-                ),
-                Expression::NumberLiteral(
-                    Loc::Codegen,
-                    Type::Uint(64),
-                    lamports_runtime_constant.into(),
-                ),
+                Expression::NumberLiteral {
+                    loc: Loc::Codegen,
+                    ty: Type::Uint(64),
+                    value: space_runtime_constant.into(),
+                },
+                Expression::NumberLiteral {
+                    loc: Loc::Codegen,
+                    ty: Type::Uint(64),
+                    value: lamports_runtime_constant.into(),
+                },
             )
         };
 
         let instruction_var = vartab.temp_name("instruction", &Type::DynamicBytes);
-        let instruction = Expression::Variable(Loc::Codegen, Type::DynamicBytes, instruction_var);
+        let instruction = Expression::Variable {
+            loc: Loc::Codegen,
+            ty: Type::DynamicBytes,
+            var_no: instruction_var,
+        };
 
         // The CreateAccount instruction is 52 bytes (4 + 8 + 8 + 32)
         let instruction_size = 52;
@@ -341,17 +384,17 @@ pub(super) fn solana_deploy(
             Instr::Set {
                 loc: Loc::Codegen,
                 res: instruction_var,
-                expr: Expression::AllocDynamicBytes(
-                    Loc::Codegen,
-                    Type::DynamicBytes,
-                    Expression::NumberLiteral(
-                        Loc::Codegen,
-                        Type::Uint(32),
-                        instruction_size.into(),
-                    )
+                expr: Expression::AllocDynamicBytes {
+                    loc: Loc::Codegen,
+                    ty: Type::DynamicBytes,
+                    size: Expression::NumberLiteral {
+                        loc: Loc::Codegen,
+                        ty: Type::Uint(32),
+                        value: instruction_size.into(),
+                    }
                     .into(),
-                    None,
-                ),
+                    initializer: None,
+                },
             },
         );
 
@@ -360,8 +403,16 @@ pub(super) fn solana_deploy(
             vartab,
             Instr::WriteBuffer {
                 buf: instruction.clone(),
-                value: Expression::NumberLiteral(Loc::Codegen, Type::Uint(32), BigInt::from(0)),
-                offset: Expression::NumberLiteral(Loc::Codegen, Type::Uint(32), BigInt::from(0)),
+                value: Expression::NumberLiteral {
+                    loc: Loc::Codegen,
+                    ty: Type::Uint(32),
+                    value: BigInt::from(0),
+                },
+                offset: Expression::NumberLiteral {
+                    loc: Loc::Codegen,
+                    ty: Type::Uint(32),
+                    value: BigInt::from(0),
+                },
             },
         );
 
@@ -371,7 +422,11 @@ pub(super) fn solana_deploy(
             Instr::WriteBuffer {
                 buf: instruction.clone(),
                 value: lamports,
-                offset: Expression::NumberLiteral(Loc::Codegen, Type::Uint(32), BigInt::from(4)),
+                offset: Expression::NumberLiteral {
+                    loc: Loc::Codegen,
+                    ty: Type::Uint(32),
+                    value: BigInt::from(4),
+                },
             },
         );
 
@@ -381,7 +436,11 @@ pub(super) fn solana_deploy(
             Instr::WriteBuffer {
                 buf: instruction.clone(),
                 value: space,
-                offset: Expression::NumberLiteral(Loc::Codegen, Type::Uint(32), BigInt::from(12)),
+                offset: Expression::NumberLiteral {
+                    loc: Loc::Codegen,
+                    ty: Type::Uint(32),
+                    value: BigInt::from(12),
+                },
             },
         );
 
@@ -391,20 +450,24 @@ pub(super) fn solana_deploy(
             Instr::WriteBuffer {
                 buf: instruction.clone(),
                 value: if let Some(program_id) = program_id {
-                    Expression::NumberLiteral(
-                        Loc::Codegen,
-                        Type::Address(false),
-                        BigInt::from_bytes_be(Sign::Plus, program_id),
-                    )
+                    Expression::NumberLiteral {
+                        loc: Loc::Codegen,
+                        ty: Type::Address(false),
+                        value: BigInt::from_bytes_be(Sign::Plus, program_id),
+                    }
                 } else {
-                    Expression::Builtin(
-                        Loc::Codegen,
-                        vec![Type::Address(false)],
-                        Builtin::ProgramId,
-                        vec![],
-                    )
+                    Expression::Builtin {
+                        loc: Loc::Codegen,
+                        tys: vec![Type::Address(false)],
+                        kind: Builtin::ProgramId,
+                        args: vec![],
+                    }
+                },
+                offset: Expression::NumberLiteral {
+                    loc: Loc::Codegen,
+                    ty: Type::Uint(32),
+                    value: BigInt::from(20),
                 },
-                offset: Expression::NumberLiteral(Loc::Codegen, Type::Uint(32), BigInt::from(20)),
             },
         );
 
@@ -441,20 +504,24 @@ pub(super) fn solana_deploy(
                 vec![ArrayLength::Fixed(seeds.len().into())],
             );
 
-            let address_seeds =
-                Expression::ArrayLiteral(Loc::Codegen, ty, vec![seeds.len() as u32], seeds);
+            let address_seeds = Expression::ArrayLiteral {
+                loc: Loc::Codegen,
+                ty,
+                dimensions: vec![seeds.len() as u32],
+                values: seeds,
+            };
 
             let ty = Type::Array(
                 Box::new(Type::Slice(Box::new(Type::Slice(Box::new(Type::Bytes(1)))))),
                 vec![ArrayLength::Fixed(1.into())],
             );
 
-            Some(Expression::ArrayLiteral(
-                Loc::Codegen,
+            Some(Expression::ArrayLiteral {
+                loc: Loc::Codegen,
                 ty,
-                vec![1],
-                vec![address_seeds],
-            ))
+                dimensions: vec![1],
+                values: vec![address_seeds],
+            })
         } else {
             None
         };
@@ -464,15 +531,27 @@ pub(super) fn solana_deploy(
             Instr::ExternalCall {
                 success: None,
                 seeds,
-                address: Some(Expression::NumberLiteral(
-                    Loc::Codegen,
-                    Type::Address(false),
-                    BigInt::from(0),
-                )), // SystemProgram 11111111111111111111111111111111
-                accounts: Some(Expression::Variable(Loc::Codegen, metas_ty, metas)),
+                address: Some(Expression::NumberLiteral {
+                    loc: Loc::Codegen,
+                    ty: Type::Address(false),
+                    value: BigInt::from(0),
+                }), // SystemProgram 11111111111111111111111111111111
+                accounts: Some(Expression::Variable {
+                    loc: Loc::Codegen,
+                    ty: metas_ty,
+                    var_no: metas,
+                }),
                 payload: instruction,
-                value: Expression::NumberLiteral(Loc::Codegen, Type::Uint(64), BigInt::from(0)),
-                gas: Expression::NumberLiteral(Loc::Codegen, Type::Uint(64), BigInt::from(0)),
+                value: Expression::NumberLiteral {
+                    loc: Loc::Codegen,
+                    ty: Type::Uint(64),
+                    value: BigInt::from(0),
+                },
+                gas: Expression::NumberLiteral {
+                    loc: Loc::Codegen,
+                    ty: Type::Uint(64),
+                    value: BigInt::from(0),
+                },
                 callty: CallTy::Regular,
                 contract_function_no: None,
             },
@@ -495,12 +574,16 @@ pub(super) fn solana_deploy(
         vartab,
         Instr::SetStorage {
             ty: Type::Uint(32),
-            value: Expression::NumberLiteral(
-                Loc::Codegen,
-                Type::Uint(64),
-                BigInt::from(contract.selector()),
-            ),
-            storage: Expression::NumberLiteral(Loc::Codegen, Type::Uint(64), BigInt::zero()),
+            value: Expression::NumberLiteral {
+                loc: Loc::Codegen,
+                ty: Type::Uint(64),
+                value: BigInt::from(contract.selector()),
+            },
+            storage: Expression::NumberLiteral {
+                loc: Loc::Codegen,
+                ty: Type::Uint(64),
+                value: BigInt::zero(),
+            },
         },
     );
 
@@ -515,12 +598,16 @@ pub(super) fn solana_deploy(
         vartab,
         Instr::SetStorage {
             ty: Type::Uint(32),
-            value: Expression::NumberLiteral(
-                Loc::Codegen,
-                Type::Uint(64),
-                BigInt::from(heap_offset),
-            ),
-            storage: Expression::NumberLiteral(Loc::Codegen, Type::Uint(64), BigInt::from(12)),
+            value: Expression::NumberLiteral {
+                loc: Loc::Codegen,
+                ty: Type::Uint(64),
+                value: BigInt::from(heap_offset),
+            },
+            storage: Expression::NumberLiteral {
+                loc: Loc::Codegen,
+                ty: Type::Uint(64),
+                value: BigInt::from(12),
+            },
         },
     );
 }

+ 126 - 63
src/codegen/statements.rs

@@ -72,12 +72,12 @@ pub(crate) fn statement(
             let mut expression = expression(init, cfg, contract_no, Some(func), ns, vartab, opt);
 
             // Let's check if the declaration is a declaration of a dynamic array
-            if let Expression::AllocDynamicBytes(
-                loc_dyn_arr,
-                ty_dyn_arr @ Type::Array(..),
+            if let Expression::AllocDynamicBytes {
+                loc: loc_dyn_arr,
+                ty: ty_dyn_arr @ Type::Array(..),
                 size,
-                opt,
-            ) = expression
+                initializer: opt,
+            } = expression
             {
                 let temp_res = vartab.temp_name("array_length", &Uint(32));
 
@@ -90,18 +90,22 @@ pub(crate) fn statement(
                     },
                 );
                 // If expression is an AllocDynamic array, replace the expression with AllocDynamicArray(_,_,tempvar,_) to avoid inserting size twice in the cfg
-                expression = Expression::AllocDynamicBytes(
-                    loc_dyn_arr,
-                    ty_dyn_arr,
-                    Box::new(Expression::Variable(*loc, Uint(32), temp_res)),
-                    opt,
-                );
+                expression = Expression::AllocDynamicBytes {
+                    loc: loc_dyn_arr,
+                    ty: ty_dyn_arr,
+                    size: Box::new(Expression::Variable {
+                        loc: *loc,
+                        ty: Uint(32),
+                        var_no: temp_res,
+                    }),
+                    initializer: opt,
+                };
                 cfg.array_lengths_temps.insert(*pos, temp_res);
-            } else if let Expression::Variable(_, _, res) = &expression {
+            } else if let Expression::Variable { var_no, .. } = &expression {
                 // If declaration happens with an existing array, check if the size of the array is known.
                 // If the size of the right hand side is known (is in the array_length_map), make the left hand side track it
                 // Now, we will have two keys in the map that point to the same temporary variable
-                if let Some(to_add) = cfg.array_lengths_temps.clone().get(res) {
+                if let Some(to_add) = cfg.array_lengths_temps.clone().get(var_no) {
                     cfg.array_lengths_temps.insert(*pos, *to_add);
                 }
             }
@@ -126,13 +130,19 @@ pub(crate) fn statement(
                 Instr::Set {
                     loc: *loc,
                     res: *pos,
-                    expr: Expression::Undefined(param.ty.clone()),
+                    expr: Expression::Undefined {
+                        ty: param.ty.clone(),
+                    },
                 },
             );
             // Handling arrays without size, defaulting the initial size with zero
 
             if matches!(param.ty, Type::Array(..)) {
-                let num = Expression::NumberLiteral(Codegen, Uint(32), BigInt::zero());
+                let num = Expression::NumberLiteral {
+                    loc: Codegen,
+                    ty: Uint(32),
+                    value: BigInt::zero(),
+                };
                 let temp_res = vartab.temp_name("array_length", &Uint(32));
                 cfg.add(
                     vartab,
@@ -895,7 +905,11 @@ fn destructure(
 
                 cfg.add(vartab, Instr::Set { loc, res, expr });
 
-                values.push(Expression::Variable(loc, ty, res));
+                values.push(Expression::Variable {
+                    loc,
+                    ty,
+                    var_no: res,
+                });
             }
 
             values
@@ -955,8 +969,8 @@ fn try_load_and_cast(
 ) -> Expression {
     match expr.ty() {
         Type::StorageRef(_, ty) => {
-            if let Expression::Subscript(_, _, ty, ..) = &expr {
-                if ty.is_storage_bytes() {
+            if let Expression::Subscript { array_ty, .. } = &expr {
+                if array_ty.is_storage_bytes() {
                     return expr.cast(to_ty, ns);
                 }
             }
@@ -976,11 +990,20 @@ fn try_load_and_cast(
                 },
             );
 
-            Expression::Variable(*loc, (*ty).clone(), anonymous_no)
+            Expression::Variable {
+                loc: *loc,
+                ty: (*ty).clone(),
+                var_no: anonymous_no,
+            }
         }
         Type::Ref(ty) => match *ty {
             Type::Array(_, _) => expr.cast(to_ty, ns),
-            _ => Expression::Load(pt::Loc::Builtin, *ty, expr.clone().into()).cast(to_ty, ns),
+            _ => Expression::Load {
+                loc: pt::Loc::Builtin,
+                ty: *ty,
+                expr: expr.clone().into(),
+            }
+            .cast(to_ty, ns),
         },
         _ => expr.cast(to_ty, ns),
     }
@@ -1027,7 +1050,11 @@ fn try_catch(
                 let value = if let Some(value) = &call_args.value {
                     expression(value, cfg, callee_contract_no, Some(func), ns, vartab, opt)
                 } else {
-                    Expression::NumberLiteral(Codegen, Type::Value, BigInt::zero())
+                    Expression::NumberLiteral {
+                        loc: Codegen,
+                        ty: Type::Value,
+                        value: BigInt::zero(),
+                    }
                 };
                 let gas = if let Some(gas) = &call_args.gas {
                     expression(gas, cfg, callee_contract_no, Some(func), ns, vartab, opt)
@@ -1074,7 +1101,11 @@ fn try_catch(
                 cfg.add(
                     vartab,
                     Instr::BranchCond {
-                        cond: Expression::Variable(try_stmt.expr.loc(), Type::Bool, success),
+                        cond: Expression::Variable {
+                            loc: try_stmt.expr.loc(),
+                            ty: Type::Bool,
+                            var_no: success,
+                        },
                         true_block: success_block,
                         false_block: catch_block,
                     },
@@ -1092,7 +1123,7 @@ fn try_catch(
                         });
                     }
 
-                    let buf = &Expression::ReturnData(Codegen);
+                    let buf = &Expression::ReturnData { loc: Codegen };
                     let decoded = abi_decode(&Codegen, buf, &func_returns, ns, vartab, cfg, None);
                     for instruction in res.iter().zip(decoded).map(|(var, expr)| Instr::Set {
                         loc: Codegen,
@@ -1139,7 +1170,11 @@ fn try_catch(
             cfg.add(
                 vartab,
                 Instr::BranchCond {
-                    cond: Expression::Variable(try_stmt.expr.loc(), Type::Bool, success),
+                    cond: Expression::Variable {
+                        loc: try_stmt.expr.loc(),
+                        ty: Type::Bool,
+                        var_no: success,
+                    },
                     true_block: success_block,
                     false_block: catch_block,
                 },
@@ -1191,11 +1226,20 @@ fn try_catch(
         };
 
         // Expect the returned data to match the 4 bytes function selector for "Error(string)"
-        let buf = &Expression::ReturnData(Codegen);
+        let buf = &Expression::ReturnData { loc: Codegen };
         let tys = &[Uint(32), error_param.ty.clone()];
         let decoded = abi_decode(&Codegen, buf, tys, ns, vartab, cfg, None);
-        let err_id = Expression::NumberLiteral(Codegen, Uint(32), 0x08c3_79a0.into()).into();
-        let cond = Expression::Equal(Codegen, decoded[0].clone().into(), err_id);
+        let err_id = Expression::NumberLiteral {
+            loc: Codegen,
+            ty: Uint(32),
+            value: 0x08c3_79a0.into(),
+        }
+        .into();
+        let cond = Expression::Equal {
+            loc: Codegen,
+            left: decoded[0].clone().into(),
+            right: err_id,
+        };
         let match_err_id = cfg.new_basic_block("match_err_id".into());
         let no_match_err_id = cfg.new_basic_block("no_match_err_id".into());
         let instruction = Instr::BranchCond {
@@ -1250,7 +1294,7 @@ fn try_catch(
         let instruction = Instr::Set {
             loc: Codegen,
             res,
-            expr: Expression::ReturnData(Codegen),
+            expr: Expression::ReturnData { loc: Codegen },
         };
         cfg.add(vartab, instruction);
     }
@@ -1334,16 +1378,23 @@ impl Type {
     /// for example a reference to a variable in storage.
     pub fn default(&self, ns: &Namespace) -> Option<Expression> {
         match self {
-            Type::Address(_) | Uint(_) | Type::Int(_) => Some(Expression::NumberLiteral(
-                Codegen,
-                self.clone(),
-                BigInt::from(0),
-            )),
-            Type::Bool => Some(Expression::BoolLiteral(Codegen, false)),
+            Type::Address(_) | Uint(_) | Type::Int(_) => Some(Expression::NumberLiteral {
+                loc: Codegen,
+                ty: self.clone(),
+                value: BigInt::from(0),
+            }),
+            Type::Bool => Some(Expression::BoolLiteral {
+                loc: Codegen,
+                value: false,
+            }),
             Type::Bytes(n) => {
                 let mut l = Vec::new();
                 l.resize(*n as usize, 0);
-                Some(Expression::BytesLiteral(Codegen, self.clone(), l))
+                Some(Expression::BytesLiteral {
+                    loc: Codegen,
+                    ty: self.clone(),
+                    value: l,
+                })
             }
             Type::Enum(e) => ns.enums[*e].ty.default(ns),
             Type::Struct(struct_ty) => {
@@ -1352,28 +1403,36 @@ impl Type {
                     field.ty.default(ns)?;
                 }
 
-                Some(Expression::StructLiteral(Codegen, self.clone(), Vec::new()))
+                Some(Expression::StructLiteral {
+                    loc: Codegen,
+                    ty: self.clone(),
+                    values: Vec::new(),
+                })
             }
             Type::Ref(ty) => {
                 assert!(matches!(ty.as_ref(), Type::Address(_)));
 
-                Some(Expression::GetRef(
-                    Codegen,
-                    Type::Ref(Box::new(ty.as_ref().clone())),
-                    Box::new(Expression::NumberLiteral(
-                        Codegen,
-                        ty.as_ref().clone(),
-                        BigInt::from(0),
-                    )),
-                ))
+                Some(Expression::GetRef {
+                    loc: Codegen,
+                    ty: Type::Ref(Box::new(ty.as_ref().clone())),
+                    expr: Box::new(Expression::NumberLiteral {
+                        loc: Codegen,
+                        ty: ty.as_ref().clone(),
+                        value: BigInt::from(0),
+                    }),
+                })
             }
             Type::StorageRef(..) => None,
-            Type::String | Type::DynamicBytes => Some(Expression::AllocDynamicBytes(
-                Codegen,
-                self.clone(),
-                Box::new(Expression::NumberLiteral(Codegen, Uint(32), BigInt::zero())),
-                None,
-            )),
+            Type::String | Type::DynamicBytes => Some(Expression::AllocDynamicBytes {
+                loc: Codegen,
+                ty: self.clone(),
+                size: Box::new(Expression::NumberLiteral {
+                    loc: Codegen,
+                    ty: Uint(32),
+                    value: BigInt::zero(),
+                }),
+                initializer: None,
+            }),
             Type::InternalFunction { .. } | Type::Contract(_) | Type::ExternalFunction { .. } => {
                 None
             }
@@ -1381,19 +1440,23 @@ impl Type {
                 ty.default(ns)?;
 
                 if dims.last() == Some(&ArrayLength::Dynamic) {
-                    Some(Expression::AllocDynamicBytes(
-                        Codegen,
-                        self.clone(),
-                        Box::new(Expression::NumberLiteral(Codegen, Uint(32), BigInt::zero())),
-                        None,
-                    ))
+                    Some(Expression::AllocDynamicBytes {
+                        loc: Codegen,
+                        ty: self.clone(),
+                        size: Box::new(Expression::NumberLiteral {
+                            loc: Codegen,
+                            ty: Uint(32),
+                            value: BigInt::zero(),
+                        }),
+                        initializer: None,
+                    })
                 } else {
-                    Some(Expression::ArrayLiteral(
-                        Codegen,
-                        self.clone(),
-                        Vec::new(),
-                        Vec::new(),
-                    ))
+                    Some(Expression::ArrayLiteral {
+                        loc: Codegen,
+                        ty: self.clone(),
+                        dimensions: Vec::new(),
+                        values: Vec::new(),
+                    })
                 }
             }
             _ => None,

+ 147 - 71
src/codegen/storage.rs

@@ -33,39 +33,49 @@ pub fn array_offset(
     // the index needs to be cast to i256 and multiplied by the number
     // of slots for each element
     if elem_size == BigInt::one() {
-        Expression::Add(*loc, slot_ty, true, Box::new(start), Box::new(index))
+        Expression::Add {
+            loc: *loc,
+            ty: slot_ty,
+            overflowing: true,
+            left: Box::new(start),
+            right: Box::new(index),
+        }
     } else if (elem_size.clone() & (elem_size.clone() - BigInt::one())) == BigInt::zero() {
         // elem_size is power of 2
-        Expression::Add(
-            *loc,
-            slot_ty.clone(),
-            true,
-            Box::new(start),
-            Box::new(Expression::ShiftLeft(
-                *loc,
-                slot_ty.clone(),
-                Box::new(index),
-                Box::new(Expression::NumberLiteral(
-                    *loc,
-                    slot_ty,
-                    BigInt::from_u64(elem_size.bits() - 1).unwrap(),
-                )),
-            )),
-        )
+        Expression::Add {
+            loc: *loc,
+            ty: slot_ty.clone(),
+            overflowing: true,
+            left: Box::new(start),
+            right: Box::new(Expression::ShiftLeft {
+                loc: *loc,
+                ty: slot_ty.clone(),
+                left: Box::new(index),
+                right: Box::new(Expression::NumberLiteral {
+                    loc: *loc,
+                    ty: slot_ty,
+                    value: BigInt::from_u64(elem_size.bits() - 1).unwrap(),
+                }),
+            }),
+        }
     } else {
-        Expression::Add(
-            *loc,
-            slot_ty.clone(),
-            true,
-            Box::new(start),
-            Box::new(Expression::Multiply(
-                *loc,
-                slot_ty.clone(),
-                true,
-                Box::new(index),
-                Box::new(Expression::NumberLiteral(*loc, slot_ty, elem_size)),
-            )),
-        )
+        Expression::Add {
+            loc: *loc,
+            ty: slot_ty.clone(),
+            overflowing: true,
+            left: Box::new(start),
+            right: Box::new(Expression::Multiply {
+                loc: *loc,
+                ty: slot_ty.clone(),
+                overflowing: true,
+                left: Box::new(index),
+                right: Box::new(Expression::NumberLiteral {
+                    loc: *loc,
+                    ty: slot_ty,
+                    value: elem_size,
+                }),
+            }),
+        }
     }
 }
 
@@ -108,8 +118,16 @@ pub fn storage_slots_array_push(
             res: entry_pos,
             expr: array_offset(
                 loc,
-                Expression::Keccak256(*loc, slot_ty.clone(), vec![var_expr.clone()]),
-                Expression::Variable(*loc, slot_ty.clone(), length_pos),
+                Expression::Keccak256 {
+                    loc: *loc,
+                    ty: slot_ty.clone(),
+                    exprs: vec![var_expr.clone()],
+                },
+                Expression::Variable {
+                    loc: *loc,
+                    ty: slot_ty.clone(),
+                    var_no: length_pos,
+                },
                 elem_ty.clone(),
                 ns,
             ),
@@ -124,23 +142,31 @@ pub fn storage_slots_array_push(
             Instr::SetStorage {
                 ty: elem_ty.clone(),
                 value,
-                storage: Expression::Variable(*loc, slot_ty.clone(), entry_pos),
+                storage: Expression::Variable {
+                    loc: *loc,
+                    ty: slot_ty.clone(),
+                    var_no: entry_pos,
+                },
             },
         );
     }
 
     // increase length
-    let new_length = Expression::Add(
-        *loc,
-        slot_ty.clone(),
-        true,
-        Box::new(Expression::Variable(*loc, slot_ty.clone(), length_pos)),
-        Box::new(Expression::NumberLiteral(
-            *loc,
-            slot_ty.clone(),
-            BigInt::one(),
-        )),
-    );
+    let new_length = Expression::Add {
+        loc: *loc,
+        ty: slot_ty.clone(),
+        overflowing: true,
+        left: Box::new(Expression::Variable {
+            loc: *loc,
+            ty: slot_ty.clone(),
+            var_no: length_pos,
+        }),
+        right: Box::new(Expression::NumberLiteral {
+            loc: *loc,
+            ty: slot_ty.clone(),
+            value: BigInt::one(),
+        }),
+    };
 
     cfg.add(
         vartab,
@@ -152,7 +178,11 @@ pub fn storage_slots_array_push(
     );
 
     if args.len() == 1 {
-        Expression::Variable(*loc, elem_ty, entry_pos)
+        Expression::Variable {
+            loc: *loc,
+            ty: elem_ty,
+            var_no: entry_pos,
+        }
     } else {
         Expression::Poison
     }
@@ -195,15 +225,19 @@ pub fn storage_slots_array_pop(
     cfg.add(
         vartab,
         Instr::BranchCond {
-            cond: Expression::Equal(
-                *loc,
-                Box::new(Expression::Variable(*loc, length_ty.clone(), length_pos)),
-                Box::new(Expression::NumberLiteral(
-                    *loc,
-                    length_ty.clone(),
-                    BigInt::zero(),
-                )),
-            ),
+            cond: Expression::Equal {
+                loc: *loc,
+                left: Box::new(Expression::Variable {
+                    loc: *loc,
+                    ty: length_ty.clone(),
+                    var_no: length_pos,
+                }),
+                right: Box::new(Expression::NumberLiteral {
+                    loc: *loc,
+                    ty: length_ty.clone(),
+                    value: BigInt::zero(),
+                }),
+            },
             true_block: empty_array,
             false_block: has_elements,
         },
@@ -228,13 +262,21 @@ pub fn storage_slots_array_pop(
         Instr::Set {
             loc: pt::Loc::Codegen,
             res: new_length,
-            expr: Expression::Subtract(
-                *loc,
-                length_ty.clone(),
-                true,
-                Box::new(Expression::Variable(*loc, length_ty.clone(), length_pos)),
-                Box::new(Expression::NumberLiteral(*loc, length_ty, BigInt::one())),
-            ),
+            expr: Expression::Subtract {
+                loc: *loc,
+                ty: length_ty.clone(),
+                overflowing: true,
+                left: Box::new(Expression::Variable {
+                    loc: *loc,
+                    ty: length_ty.clone(),
+                    var_no: length_pos,
+                }),
+                right: Box::new(Expression::NumberLiteral {
+                    loc: *loc,
+                    ty: length_ty,
+                    value: BigInt::one(),
+                }),
+            },
         },
     );
 
@@ -250,8 +292,16 @@ pub fn storage_slots_array_pop(
             res: entry_pos,
             expr: array_offset(
                 loc,
-                Expression::Keccak256(*loc, slot_ty.clone(), vec![var_expr.clone()]),
-                Expression::Variable(*loc, slot_ty.clone(), new_length),
+                Expression::Keccak256 {
+                    loc: *loc,
+                    ty: slot_ty.clone(),
+                    exprs: vec![var_expr.clone()],
+                },
+                Expression::Variable {
+                    loc: *loc,
+                    ty: slot_ty.clone(),
+                    var_no: new_length,
+                },
                 elem_ty.clone(),
                 ns,
             ),
@@ -264,7 +314,11 @@ pub fn storage_slots_array_pop(
         let expr = load_storage(
             loc,
             &elem_ty,
-            Expression::Variable(*loc, elem_ty.clone(), entry_pos),
+            Expression::Variable {
+                loc: *loc,
+                ty: elem_ty.clone(),
+                var_no: entry_pos,
+            },
             cfg,
             vartab,
         );
@@ -277,16 +331,26 @@ pub fn storage_slots_array_pop(
                 expr,
             },
         );
-        Expression::Variable(*loc, elem_ty.clone(), res_pos)
+        Expression::Variable {
+            loc: *loc,
+            ty: elem_ty.clone(),
+            var_no: res_pos,
+        }
     } else {
-        Expression::Undefined(elem_ty.clone())
+        Expression::Undefined {
+            ty: elem_ty.clone(),
+        }
     };
 
     cfg.add(
         vartab,
         Instr::ClearStorage {
             ty: elem_ty,
-            storage: Expression::Variable(*loc, slot_ty.clone(), entry_pos),
+            storage: Expression::Variable {
+                loc: *loc,
+                ty: slot_ty.clone(),
+                var_no: entry_pos,
+            },
         },
     );
 
@@ -295,7 +359,11 @@ pub fn storage_slots_array_pop(
         vartab,
         Instr::SetStorage {
             ty: slot_ty.clone(),
-            value: Expression::Variable(*loc, slot_ty, new_length),
+            value: Expression::Variable {
+                loc: *loc,
+                ty: slot_ty,
+                var_no: new_length,
+            },
             storage: var_expr,
         },
     );
@@ -348,7 +416,11 @@ pub fn array_push(
         },
     );
 
-    Expression::Variable(*loc, ty, res)
+    Expression::Variable {
+        loc: *loc,
+        ty,
+        var_no: res,
+    }
 }
 
 /// Pop() method on array or bytes in storage
@@ -383,8 +455,12 @@ pub fn array_pop(
     );
 
     if let Some(res) = res {
-        Expression::Variable(*loc, ty, res)
+        Expression::Variable {
+            loc: *loc,
+            ty,
+            var_no: res,
+        }
     } else {
-        Expression::Undefined(ty)
+        Expression::Undefined { ty }
     }
 }

+ 33 - 23
src/codegen/strength_reduce/expression_values.rs

@@ -16,17 +16,23 @@ pub(super) fn expression_values(
     ns: &Namespace,
 ) -> HashSet<Value> {
     match expr {
-        Expression::NumberLiteral(_, ty, v) => number_literal_values(ty, v, ns),
-        Expression::BoolLiteral(_, v) => bool_literal_values(*v),
-        Expression::ZeroExt(_, ty, expr) => zero_ext_values(ty, expr, vars, ns),
-        Expression::SignExt(_, ty, expr) => sign_ext_values(ty, expr, vars, ns),
-        Expression::Trunc(_, ty, expr) => trunc_values(ty, expr, vars, ns),
-        Expression::BitwiseOr(_, _, left, right) => bitwise_or_values(left, right, vars, ns),
-        Expression::BitwiseAnd(_, _, left, right) => bitwise_and_values(left, right, vars, ns),
-        Expression::BitwiseXor(_, _, left, right) => bitwise_xor_values(left, right, vars, ns),
-        Expression::Add(_, ty, _, left, right) => add_values(ty, left, right, vars, ns),
-        Expression::Subtract(_, ty, _, left, right) => subtract_values(ty, left, right, vars, ns),
-        Expression::Multiply(_, ty, _, left, right) => multiply_values(ty, left, right, vars, ns),
+        Expression::NumberLiteral { ty, value, .. } => number_literal_values(ty, value, ns),
+        Expression::BoolLiteral { value, .. } => bool_literal_values(*value),
+        Expression::ZeroExt { ty, expr, .. } => zero_ext_values(ty, expr, vars, ns),
+        Expression::SignExt { ty, expr, .. } => sign_ext_values(ty, expr, vars, ns),
+        Expression::Trunc { ty, expr, .. } => trunc_values(ty, expr, vars, ns),
+        Expression::BitwiseOr { left, right, .. } => bitwise_or_values(left, right, vars, ns),
+        Expression::BitwiseAnd { left, right, .. } => bitwise_and_values(left, right, vars, ns),
+        Expression::BitwiseXor { left, right, .. } => bitwise_xor_values(left, right, vars, ns),
+        Expression::Add {
+            ty, left, right, ..
+        } => add_values(ty, left, right, vars, ns),
+        Expression::Subtract {
+            ty, left, right, ..
+        } => subtract_values(ty, left, right, vars, ns),
+        Expression::Multiply {
+            ty, left, right, ..
+        } => multiply_values(ty, left, right, vars, ns),
         Expression::More {
             left,
             right,
@@ -51,22 +57,26 @@ pub(super) fn expression_values(
             signed,
             ..
         } => less_equal_values(left, right, *signed, vars, ns),
-        Expression::Equal(_, left_expr, right_expr) => {
-            equal_values(left_expr, right_expr, vars, ns)
-        }
-        Expression::NotEqual(_, left_expr, right_expr) => {
-            not_equal_values(left_expr, right_expr, vars, ns)
-        }
-        Expression::Not(_, expr) => not_values(expr, vars, ns),
-        Expression::BitwiseNot(_, _, expr) => complement_values(expr, vars, ns),
-        Expression::Variable(_, _, var_no) => variable_values(*var_no, vars),
-        Expression::InternalFunctionCfg(_) => {
+        Expression::Equal {
+            left: left_expr,
+            right: right_expr,
+            ..
+        } => equal_values(left_expr, right_expr, vars, ns),
+        Expression::NotEqual {
+            left: left_expr,
+            right: right_expr,
+            ..
+        } => not_equal_values(left_expr, right_expr, vars, ns),
+        Expression::Not { expr, .. } => not_values(expr, vars, ns),
+        Expression::BitwiseNot { expr, .. } => complement_values(expr, vars, ns),
+        Expression::Variable { var_no, .. } => variable_values(*var_no, vars),
+        Expression::InternalFunctionCfg { .. } => {
             // reference to a function; ignore
             HashSet::new()
         }
-        Expression::Undefined(expr_type) => {
+        Expression::Undefined { ty } => {
             // If the variable is undefined, we can return the default value to optimize operations
-            if let Some(default_expr) = expr_type.default(ns) {
+            if let Some(default_expr) = ty.default(ns) {
                 return expression_values(&default_expr, vars, ns);
             }
 

+ 142 - 86
src/codegen/strength_reduce/mod.rs

@@ -216,7 +216,13 @@ fn block_reduce(
 fn expression_reduce(expr: &Expression, vars: &Variables, ns: &mut Namespace) -> Expression {
     let filter = |expr: &Expression, ns: &mut Namespace| -> Expression {
         match expr {
-            Expression::Multiply(loc, ty, unchecked, left, right) => {
+            Expression::Multiply {
+                loc,
+                ty,
+                overflowing: unchecked,
+                left,
+                right,
+            } => {
                 let bits = ty.bits(ns) as usize;
                 if bits >= 128 {
                     let left_values = expression_values(left, vars, ns);
@@ -239,12 +245,16 @@ fn expression_reduce(expr: &Expression, vars: &Variables, ns: &mut Namespace) ->
                                     ),
                                 );
 
-                                return Expression::ShiftLeft(
-                                    *loc,
-                                    ty.clone(),
-                                    left.clone(),
-                                    Box::new(Expression::NumberLiteral(*loc, ty.clone(), shift)),
-                                );
+                                return Expression::ShiftLeft {
+                                    loc: *loc,
+                                    ty: ty.clone(),
+                                    left: left.clone(),
+                                    right: Box::new(Expression::NumberLiteral {
+                                        loc: *loc,
+                                        ty: ty.clone(),
+                                        value: shift,
+                                    }),
+                                };
                             }
 
                             cmp *= 2;
@@ -266,17 +276,21 @@ fn expression_reduce(expr: &Expression, vars: &Variables, ns: &mut Namespace) ->
                                     ),
                                 );
 
-                                return Expression::SignExt(
-                                    *loc,
-                                    ty.clone(),
-                                    Box::new(Expression::Multiply(
-                                        *loc,
-                                        Type::Int(64),
-                                        *unchecked,
-                                        Box::new(left.as_ref().clone().cast(&Type::Int(64), ns)),
-                                        Box::new(right.as_ref().clone().cast(&Type::Int(64), ns)),
-                                    )),
-                                );
+                                return Expression::SignExt {
+                                    loc: *loc,
+                                    ty: ty.clone(),
+                                    expr: Box::new(Expression::Multiply {
+                                        loc: *loc,
+                                        ty: Type::Int(64),
+                                        overflowing: *unchecked,
+                                        left: Box::new(
+                                            left.as_ref().clone().cast(&Type::Int(64), ns),
+                                        ),
+                                        right: Box::new(
+                                            right.as_ref().clone().cast(&Type::Int(64), ns),
+                                        ),
+                                    }),
+                                };
                             }
                         }
                     } else {
@@ -293,25 +307,37 @@ fn expression_reduce(expr: &Expression, vars: &Variables, ns: &mut Namespace) ->
                                 ),
                             );
 
-                            return Expression::ZeroExt(
-                                *loc,
-                                ty.clone(),
-                                Box::new(Expression::Multiply(
-                                    *loc,
-                                    Type::Uint(64),
-                                    *unchecked,
-                                    Box::new(left.as_ref().clone().cast(&Type::Uint(64), ns)),
-                                    Box::new(right.as_ref().clone().cast(&Type::Uint(64), ns)),
-                                )),
-                            );
+                            return Expression::ZeroExt {
+                                loc: *loc,
+                                ty: ty.clone(),
+                                expr: Box::new(Expression::Multiply {
+                                    loc: *loc,
+                                    ty: Type::Uint(64),
+                                    overflowing: *unchecked,
+                                    left: Box::new(left.as_ref().clone().cast(&Type::Uint(64), ns)),
+                                    right: Box::new(
+                                        right.as_ref().clone().cast(&Type::Uint(64), ns),
+                                    ),
+                                }),
+                            };
                         }
                     }
                 }
 
                 expr.clone()
             }
-            Expression::UnsignedDivide(loc, ty, left, right)
-            | Expression::SignedDivide(loc, ty, left, right) => {
+            Expression::UnsignedDivide {
+                loc,
+                ty,
+                left,
+                right,
+            }
+            | Expression::SignedDivide {
+                loc,
+                ty,
+                left,
+                right,
+            } => {
                 let bits = ty.bits(ns) as usize;
 
                 if bits >= 128 {
@@ -335,13 +361,17 @@ fn expression_reduce(expr: &Expression, vars: &Variables, ns: &mut Namespace) ->
                                     ),
                                 );
 
-                                return Expression::ShiftRight(
-                                    *loc,
-                                    ty.clone(),
-                                    left.clone(),
-                                    Box::new(Expression::NumberLiteral(*loc, ty.clone(), shift)),
-                                    ty.is_signed_int(ns),
-                                );
+                                return Expression::ShiftRight {
+                                    loc: *loc,
+                                    ty: ty.clone(),
+                                    left: left.clone(),
+                                    right: Box::new(Expression::NumberLiteral {
+                                        loc: *loc,
+                                        ty: ty.clone(),
+                                        value: shift,
+                                    }),
+                                    signed: ty.is_signed_int(ns),
+                                };
                             }
 
                             cmp *= 2;
@@ -362,16 +392,20 @@ fn expression_reduce(expr: &Expression, vars: &Variables, ns: &mut Namespace) ->
                                     ),
                                 );
 
-                                return Expression::SignExt(
-                                    *loc,
-                                    ty.clone(),
-                                    Box::new(Expression::UnsignedDivide(
-                                        *loc,
-                                        Type::Int(64),
-                                        Box::new(left.as_ref().clone().cast(&Type::Int(64), ns)),
-                                        Box::new(right.as_ref().clone().cast(&Type::Int(64), ns)),
-                                    )),
-                                );
+                                return Expression::SignExt {
+                                    loc: *loc,
+                                    ty: ty.clone(),
+                                    expr: Box::new(Expression::UnsignedDivide {
+                                        loc: *loc,
+                                        ty: Type::Int(64),
+                                        left: Box::new(
+                                            left.as_ref().clone().cast(&Type::Int(64), ns),
+                                        ),
+                                        right: Box::new(
+                                            right.as_ref().clone().cast(&Type::Int(64), ns),
+                                        ),
+                                    }),
+                                };
                             }
                         }
                     } else {
@@ -385,24 +419,36 @@ fn expression_reduce(expr: &Expression, vars: &Variables, ns: &mut Namespace) ->
                                 format!("{} divide optimized to uint64 divide", ty.to_string(ns),),
                             );
 
-                            return Expression::ZeroExt(
-                                *loc,
-                                ty.clone(),
-                                Box::new(Expression::UnsignedDivide(
-                                    *loc,
-                                    Type::Uint(64),
-                                    Box::new(left.as_ref().clone().cast(&Type::Uint(64), ns)),
-                                    Box::new(right.as_ref().clone().cast(&Type::Uint(64), ns)),
-                                )),
-                            );
+                            return Expression::ZeroExt {
+                                loc: *loc,
+                                ty: ty.clone(),
+                                expr: Box::new(Expression::UnsignedDivide {
+                                    loc: *loc,
+                                    ty: Type::Uint(64),
+                                    left: Box::new(left.as_ref().clone().cast(&Type::Uint(64), ns)),
+                                    right: Box::new(
+                                        right.as_ref().clone().cast(&Type::Uint(64), ns),
+                                    ),
+                                }),
+                            };
                         }
                     }
                 }
 
                 expr.clone()
             }
-            Expression::SignedModulo(loc, ty, left, right)
-            | Expression::UnsignedModulo(loc, ty, left, right) => {
+            Expression::SignedModulo {
+                loc,
+                ty,
+                left,
+                right,
+            }
+            | Expression::UnsignedModulo {
+                loc,
+                ty,
+                left,
+                right,
+            } => {
                 let bits = ty.bits(ns) as usize;
 
                 if bits >= 128 {
@@ -426,12 +472,16 @@ fn expression_reduce(expr: &Expression, vars: &Variables, ns: &mut Namespace) ->
                                     ),
                                 );
 
-                                return Expression::BitwiseAnd(
-                                    *loc,
-                                    ty.clone(),
-                                    left.clone(),
-                                    Box::new(Expression::NumberLiteral(*loc, ty.clone(), cmp - 1)),
-                                );
+                                return Expression::BitwiseAnd {
+                                    loc: *loc,
+                                    ty: ty.clone(),
+                                    left: left.clone(),
+                                    right: Box::new(Expression::NumberLiteral {
+                                        loc: *loc,
+                                        ty: ty.clone(),
+                                        value: cmp - 1,
+                                    }),
+                                };
                             }
 
                             cmp *= 2;
@@ -451,16 +501,20 @@ fn expression_reduce(expr: &Expression, vars: &Variables, ns: &mut Namespace) ->
                                     ),
                                 );
 
-                                return Expression::SignExt(
-                                    *loc,
-                                    ty.clone(),
-                                    Box::new(Expression::SignedModulo(
-                                        *loc,
-                                        Type::Int(64),
-                                        Box::new(left.as_ref().clone().cast(&Type::Int(64), ns)),
-                                        Box::new(right.as_ref().clone().cast(&Type::Int(64), ns)),
-                                    )),
-                                );
+                                return Expression::SignExt {
+                                    loc: *loc,
+                                    ty: ty.clone(),
+                                    expr: Box::new(Expression::SignedModulo {
+                                        loc: *loc,
+                                        ty: Type::Int(64),
+                                        left: Box::new(
+                                            left.as_ref().clone().cast(&Type::Int(64), ns),
+                                        ),
+                                        right: Box::new(
+                                            right.as_ref().clone().cast(&Type::Int(64), ns),
+                                        ),
+                                    }),
+                                };
                             }
                         }
                     } else {
@@ -474,16 +528,18 @@ fn expression_reduce(expr: &Expression, vars: &Variables, ns: &mut Namespace) ->
                                 format!("{} modulo optimized to uint64 modulo", ty.to_string(ns)),
                             );
 
-                            return Expression::ZeroExt(
-                                *loc,
-                                ty.clone(),
-                                Box::new(Expression::UnsignedModulo(
-                                    *loc,
-                                    Type::Uint(64),
-                                    Box::new(left.as_ref().clone().cast(&Type::Uint(64), ns)),
-                                    Box::new(right.as_ref().clone().cast(&Type::Uint(64), ns)),
-                                )),
-                            );
+                            return Expression::ZeroExt {
+                                loc: *loc,
+                                ty: ty.clone(),
+                                expr: Box::new(Expression::UnsignedModulo {
+                                    loc: *loc,
+                                    ty: Type::Uint(64),
+                                    left: Box::new(left.as_ref().clone().cast(&Type::Uint(64), ns)),
+                                    right: Box::new(
+                                        right.as_ref().clone().cast(&Type::Uint(64), ns),
+                                    ),
+                                }),
+                            };
                         }
                     }
                 }

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 437 - 218
src/codegen/strength_reduce/tests.rs


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

@@ -29,9 +29,9 @@ impl AvailableExpression {
         expr_set: &mut AvailableExpressionSet<'b>,
     ) -> NodeId {
         let expr_type = match expr {
-            Expression::Variable(_, _, pos) => ExpressionType::Variable(*pos),
+            Expression::Variable { var_no, .. } => ExpressionType::Variable(*var_no),
 
-            Expression::FunctionArg(_, _, pos) => ExpressionType::FunctionArg(*pos),
+            Expression::FunctionArg { arg_no, .. } => ExpressionType::FunctionArg(*arg_no),
 
             _ => unreachable!("This expression is not a variable or a function argument"),
         };

+ 25 - 22
src/codegen/subexpression_elimination/available_expression_set.rs

@@ -255,13 +255,13 @@ impl<'a, 'b: 'a> AvailableExpressionSet<'a> {
         }
 
         match exp {
-            Expression::Variable(..) | Expression::FunctionArg(..) => {
+            Expression::Variable { .. } | Expression::FunctionArg { .. } => {
                 return Some(ave.add_variable_node(exp, self));
             }
 
-            Expression::NumberLiteral(..)
-            | Expression::BoolLiteral(..)
-            | Expression::BytesLiteral(..) => {
+            Expression::NumberLiteral { .. }
+            | Expression::BoolLiteral { .. }
+            | Expression::BytesLiteral { .. } => {
                 let key = exp.get_constant_expression_type();
 
                 let exp_id = if let Some(id) = self.expr_map.get(&key) {
@@ -273,8 +273,8 @@ impl<'a, 'b: 'a> AvailableExpressionSet<'a> {
                 return Some(exp_id);
             }
 
-            Expression::StringCompare(_, left, right)
-            | Expression::StringConcat(_, _, left, right) => {
+            Expression::StringCompare { left, right, .. }
+            | Expression::StringConcat { left, right, .. } => {
                 return if let (
                     StringLocation::RunTime(operand_1),
                     StringLocation::RunTime(operand_2),
@@ -376,27 +376,30 @@ impl<'a, 'b: 'a> AvailableExpressionSet<'a> {
     /// Check if an expression is available
     pub fn find_expression(&self, exp: &Expression) -> Option<NodeId> {
         match exp {
-            Expression::FunctionArg(_, _, pos) => {
+            Expression::FunctionArg { arg_no, .. } => {
                 return self
                     .expr_map
-                    .get(&ExpressionType::FunctionArg(*pos))
+                    .get(&ExpressionType::FunctionArg(*arg_no))
                     .copied();
             }
 
-            Expression::Variable(_, _, pos) => {
-                return self.expr_map.get(&ExpressionType::Variable(*pos)).copied();
+            Expression::Variable { var_no, .. } => {
+                return self
+                    .expr_map
+                    .get(&ExpressionType::Variable(*var_no))
+                    .copied();
             }
 
             //Expression::ConstantVariable(..)
-            Expression::NumberLiteral(..)
-            | Expression::BoolLiteral(..)
-            | Expression::BytesLiteral(..) => {
+            Expression::NumberLiteral { .. }
+            | Expression::BoolLiteral { .. }
+            | Expression::BytesLiteral { .. } => {
                 let key = exp.get_constant_expression_type();
                 return self.expr_map.get(&key).copied();
             }
 
-            Expression::StringCompare(_, left, right)
-            | Expression::StringConcat(_, _, left, right) => {
+            Expression::StringCompare { left, right, .. }
+            | Expression::StringConcat { left, right, .. } => {
                 if let (StringLocation::RunTime(operand_1), StringLocation::RunTime(operand_2)) =
                     (left, right)
                 {
@@ -500,17 +503,17 @@ impl<'a, 'b: 'a> AvailableExpressionSet<'a> {
     ) -> (Option<NodeId>, Expression) {
         match exp {
             // Variables, constants and literals will never be substituted
-            Expression::FunctionArg(..)
-            | Expression::Variable(..)
+            Expression::FunctionArg { .. }
+            | Expression::Variable {  .. }
             //| Expression::ConstantVariable(..)
-            | Expression::NumberLiteral(..)
-            | Expression::BoolLiteral(..)
-            | Expression::BytesLiteral(..) => {
+            | Expression::NumberLiteral {  .. }
+            | Expression::BoolLiteral{..}
+            | Expression::BytesLiteral{..} => {
                 return (self.gen_expression(exp, ave, &mut Some(cst)), exp.clone());
             }
 
-            Expression::StringCompare(_, left, right)
-            | Expression::StringConcat(_, _, left, right) => {
+            Expression::StringCompare { loc: _, left, right }
+            | Expression::StringConcat {  left, right, .. } => {
                 if let (StringLocation::RunTime(operand_1), StringLocation::RunTime(operand_2)) =
                     (left, right)
                 {

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

@@ -59,10 +59,10 @@ impl<'a> CommonSubExpressionTracker<'a> {
         // as we are not supposed to exchange them by temporaries.
         if matches!(
             exp,
-            Expression::FunctionArg(..)
-                | Expression::Variable(..)
-                | Expression::BytesLiteral(..)
-                | Expression::NumberLiteral(..) //| Expression::ConstantVariable(..)
+            Expression::FunctionArg { .. }
+                | Expression::Variable { .. }
+                | Expression::BytesLiteral { .. }
+                | Expression::NumberLiteral { .. } //| Expression::ConstantVariable(..)
         ) {
             return;
         }
@@ -206,15 +206,15 @@ impl<'a> CommonSubExpressionTracker<'a> {
             common_expression.in_cfg = true;
         }
 
-        Some(Expression::Variable(
-            if common_expression.var_loc.is_some() {
+        Some(Expression::Variable {
+            loc: if common_expression.var_loc.is_some() {
                 common_expression.var_loc.unwrap()
             } else {
                 Loc::Codegen
             },
-            common_expression.var_type.clone(),
-            common_expression.var_no.unwrap(),
-        ))
+            ty: common_expression.var_type.clone(),
+            var_no: common_expression.var_no.unwrap(),
+        })
     }
 
     /// Add new instructions to the instruction vector

+ 249 - 163
src/codegen/subexpression_elimination/expression.rs

@@ -9,107 +9,153 @@ impl Expression {
     #[must_use]
     pub fn rebuild_binary_expression(&self, left: &Expression, right: &Expression) -> Expression {
         match self {
-            Expression::Add(loc, expr_type, check, ..) => Expression::Add(
-                *loc,
-                expr_type.clone(),
-                *check,
-                Box::new(left.clone()),
-                Box::new(right.clone()),
-            ),
-
-            Expression::Multiply(loc, expr_type, check, ..) => Expression::Multiply(
-                *loc,
-                expr_type.clone(),
-                *check,
-                Box::new(left.clone()),
-                Box::new(right.clone()),
-            ),
-
-            Expression::BitwiseOr(loc, expr_type, ..) => Expression::BitwiseOr(
-                *loc,
-                expr_type.clone(),
-                Box::new(left.clone()),
-                Box::new(right.clone()),
-            ),
-
-            Expression::BitwiseAnd(loc, expr_type, ..) => Expression::BitwiseAnd(
-                *loc,
-                expr_type.clone(),
-                Box::new(left.clone()),
-                Box::new(right.clone()),
-            ),
-
-            Expression::BitwiseXor(loc, expr_type, ..) => Expression::BitwiseXor(
-                *loc,
-                expr_type.clone(),
-                Box::new(left.clone()),
-                Box::new(right.clone()),
-            ),
-            Expression::Equal(loc, ..) => {
-                Expression::Equal(*loc, Box::new(left.clone()), Box::new(right.clone()))
-            }
+            Expression::Add {
+                loc,
+                ty: expr_type,
+                overflowing: check,
+                ..
+            } => Expression::Add {
+                loc: *loc,
+                ty: expr_type.clone(),
+                overflowing: *check,
+                left: Box::new(left.clone()),
+                right: Box::new(right.clone()),
+            },
 
-            Expression::NotEqual(loc, ..) => {
-                Expression::NotEqual(*loc, Box::new(left.clone()), Box::new(right.clone()))
-            }
+            Expression::Multiply {
+                loc,
+                ty: expr_type,
+                overflowing: check,
+                ..
+            } => Expression::Multiply {
+                loc: *loc,
+                ty: expr_type.clone(),
+                overflowing: *check,
+                left: Box::new(left.clone()),
+                right: Box::new(right.clone()),
+            },
+
+            Expression::BitwiseOr {
+                loc, ty: expr_type, ..
+            } => Expression::BitwiseOr {
+                loc: *loc,
+                ty: expr_type.clone(),
+                left: Box::new(left.clone()),
+                right: Box::new(right.clone()),
+            },
+
+            Expression::BitwiseAnd {
+                loc, ty: expr_type, ..
+            } => Expression::BitwiseAnd {
+                loc: *loc,
+                ty: expr_type.clone(),
+                left: Box::new(left.clone()),
+                right: Box::new(right.clone()),
+            },
+
+            Expression::BitwiseXor {
+                loc, ty: expr_type, ..
+            } => Expression::BitwiseXor {
+                loc: *loc,
+                ty: expr_type.clone(),
+                left: Box::new(left.clone()),
+                right: Box::new(right.clone()),
+            },
+            Expression::Equal { loc, .. } => Expression::Equal {
+                loc: *loc,
+                left: Box::new(left.clone()),
+                right: Box::new(right.clone()),
+            },
+
+            Expression::NotEqual { loc, .. } => Expression::NotEqual {
+                loc: *loc,
+                left: Box::new(left.clone()),
+                right: Box::new(right.clone()),
+            },
+
+            Expression::Subtract {
+                loc,
+                ty: expr_type,
+                overflowing: check,
+                ..
+            } => Expression::Subtract {
+                loc: *loc,
+                ty: expr_type.clone(),
+                overflowing: *check,
+                left: Box::new(left.clone()),
+                right: Box::new(right.clone()),
+            },
+            Expression::UnsignedDivide {
+                loc, ty: expr_type, ..
+            } => Expression::UnsignedDivide {
+                loc: *loc,
+                ty: expr_type.clone(),
+                left: Box::new(left.clone()),
+                right: Box::new(right.clone()),
+            },
 
-            Expression::Subtract(loc, expr_type, check, ..) => Expression::Subtract(
-                *loc,
-                expr_type.clone(),
-                *check,
-                Box::new(left.clone()),
-                Box::new(right.clone()),
-            ),
-            Expression::UnsignedDivide(loc, expr_type, ..) => Expression::UnsignedDivide(
-                *loc,
-                expr_type.clone(),
-                Box::new(left.clone()),
-                Box::new(right.clone()),
-            ),
-
-            Expression::SignedDivide(loc, expr_type, ..) => Expression::SignedDivide(
-                *loc,
-                expr_type.clone(),
-                Box::new(left.clone()),
-                Box::new(right.clone()),
-            ),
-
-            Expression::SignedModulo(loc, expr_type, ..) => Expression::SignedModulo(
-                *loc,
-                expr_type.clone(),
-                Box::new(left.clone()),
-                Box::new(right.clone()),
-            ),
-
-            Expression::UnsignedModulo(loc, expr_type, ..) => Expression::UnsignedModulo(
-                *loc,
-                expr_type.clone(),
-                Box::new(left.clone()),
-                Box::new(right.clone()),
-            ),
-
-            Expression::Power(loc, expr_type, check, ..) => Expression::Power(
-                *loc,
-                expr_type.clone(),
-                *check,
-                Box::new(left.clone()),
-                Box::new(right.clone()),
-            ),
-
-            Expression::ShiftLeft(loc, expr_type, ..) => Expression::ShiftLeft(
-                *loc,
-                expr_type.clone(),
-                Box::new(left.clone()),
-                Box::new(right.clone()),
-            ),
-
-            Expression::ShiftRight(loc, expr_type, _, _, check) => Expression::ShiftRight(
-                *loc,
-                expr_type.clone(),
-                Box::new(left.clone()),
-                Box::new(right.clone()),
-                *check,
-            ),
+            Expression::SignedDivide {
+                loc, ty: expr_type, ..
+            } => Expression::SignedDivide {
+                loc: *loc,
+                ty: expr_type.clone(),
+                left: Box::new(left.clone()),
+                right: Box::new(right.clone()),
+            },
+
+            Expression::SignedModulo {
+                loc, ty: expr_type, ..
+            } => Expression::SignedModulo {
+                loc: *loc,
+                ty: expr_type.clone(),
+                left: Box::new(left.clone()),
+                right: Box::new(right.clone()),
+            },
+
+            Expression::UnsignedModulo {
+                loc, ty: expr_type, ..
+            } => Expression::UnsignedModulo {
+                loc: *loc,
+                ty: expr_type.clone(),
+                left: Box::new(left.clone()),
+                right: Box::new(right.clone()),
+            },
+
+            Expression::Power {
+                loc,
+                ty: expr_type,
+                overflowing: check,
+                ..
+            } => Expression::Power {
+                loc: *loc,
+                ty: expr_type.clone(),
+                overflowing: *check,
+                base: Box::new(left.clone()),
+                exp: Box::new(right.clone()),
+            },
+
+            Expression::ShiftLeft {
+                loc, ty: expr_type, ..
+            } => Expression::ShiftLeft {
+                loc: *loc,
+                ty: expr_type.clone(),
+                left: Box::new(left.clone()),
+                right: Box::new(right.clone()),
+            },
+
+            Expression::ShiftRight {
+                loc,
+                ty: expr_type,
+                left: _,
+                right: _,
+                signed: check,
+            } => Expression::ShiftRight {
+                loc: *loc,
+                ty: expr_type.clone(),
+                left: Box::new(left.clone()),
+                right: Box::new(right.clone()),
+                signed: *check,
+            },
 
             Expression::More { loc, signed, .. } => Expression::More {
                 loc: *loc,
@@ -144,7 +190,11 @@ impl Expression {
                 bytes_offset: Box::new(right.clone()),
             },
 
-            Expression::StringCompare(loc, left_exp, right_exp) => {
+            Expression::StringCompare {
+                loc,
+                left: left_exp,
+                right: right_exp,
+            } => {
                 if !matches!(
                     (left_exp, right_exp),
                     (StringLocation::RunTime(_), StringLocation::RunTime(_))
@@ -152,14 +202,19 @@ impl Expression {
                     unreachable!("String compare operation does not contain runtime arguments");
                 }
 
-                Expression::StringCompare(
-                    *loc,
-                    StringLocation::RunTime(Box::new(left.clone())),
-                    StringLocation::RunTime(Box::new(right.clone())),
-                )
+                Expression::StringCompare {
+                    loc: *loc,
+                    left: StringLocation::RunTime(Box::new(left.clone())),
+                    right: StringLocation::RunTime(Box::new(right.clone())),
+                }
             }
 
-            Expression::StringConcat(loc, expr_type, left_exp, right_exp) => {
+            Expression::StringConcat {
+                loc,
+                ty: expr_type,
+                left: left_exp,
+                right: right_exp,
+            } => {
                 if !matches!(
                     (left_exp, right_exp),
                     (StringLocation::RunTime(_), StringLocation::RunTime(_))
@@ -167,12 +222,12 @@ impl Expression {
                     unreachable!("String concat operation does not contain runtime argumetns")
                 }
 
-                Expression::StringConcat(
-                    *loc,
-                    expr_type.clone(),
-                    StringLocation::RunTime(Box::new(left.clone())),
-                    StringLocation::RunTime(Box::new(right.clone())),
-                )
+                Expression::StringConcat {
+                    loc: *loc,
+                    ty: expr_type.clone(),
+                    left: StringLocation::RunTime(Box::new(left.clone())),
+                    right: StringLocation::RunTime(Box::new(right.clone())),
+                }
             }
 
             _ => unreachable!("Cannot rebuild this expression"),
@@ -183,38 +238,65 @@ impl Expression {
     #[must_use]
     pub fn rebuild_unary_expression(&self, operand: &Expression) -> Expression {
         match self {
-            Expression::ZeroExt(loc, expr_type, ..) => {
-                Expression::ZeroExt(*loc, expr_type.clone(), Box::new(operand.clone()))
-            }
+            Expression::ZeroExt {
+                loc, ty: expr_type, ..
+            } => Expression::ZeroExt {
+                loc: *loc,
+                ty: expr_type.clone(),
+                expr: Box::new(operand.clone()),
+            },
 
-            Expression::SignExt(loc, expr_type, ..) => {
-                Expression::SignExt(*loc, expr_type.clone(), Box::new(operand.clone()))
-            }
+            Expression::SignExt {
+                loc, ty: expr_type, ..
+            } => Expression::SignExt {
+                loc: *loc,
+                ty: expr_type.clone(),
+                expr: Box::new(operand.clone()),
+            },
 
-            Expression::Trunc(loc, expr_type, ..) => {
-                Expression::Trunc(*loc, expr_type.clone(), Box::new(operand.clone()))
-            }
+            Expression::Trunc {
+                loc, ty: expr_type, ..
+            } => Expression::Trunc {
+                loc: *loc,
+                ty: expr_type.clone(),
+                expr: Box::new(operand.clone()),
+            },
 
-            Expression::Cast(loc, expr_type, ..) => {
-                Expression::Cast(*loc, expr_type.clone(), Box::new(operand.clone()))
-            }
+            Expression::Cast {
+                loc, ty: expr_type, ..
+            } => Expression::Cast {
+                loc: *loc,
+                ty: expr_type.clone(),
+                expr: Box::new(operand.clone()),
+            },
 
-            Expression::BytesCast(loc, type_1, type_2, ..) => Expression::BytesCast(
-                *loc,
-                type_1.clone(),
-                type_2.clone(),
-                Box::new(operand.clone()),
-            ),
+            Expression::BytesCast { loc, ty, from, .. } => Expression::BytesCast {
+                loc: *loc,
+                ty: ty.clone(),
+                from: from.clone(),
+                expr: Box::new(operand.clone()),
+            },
 
-            Expression::Not(loc, ..) => Expression::Not(*loc, Box::new(operand.clone())),
+            Expression::Not { loc, .. } => Expression::Not {
+                loc: *loc,
+                expr: Box::new(operand.clone()),
+            },
 
-            Expression::BitwiseNot(loc, expr_type, ..) => {
-                Expression::BitwiseNot(*loc, expr_type.clone(), Box::new(operand.clone()))
-            }
+            Expression::BitwiseNot {
+                loc, ty: expr_type, ..
+            } => Expression::BitwiseNot {
+                loc: *loc,
+                ty: expr_type.clone(),
+                expr: Box::new(operand.clone()),
+            },
 
-            Expression::Negate(loc, expr_type, ..) => {
-                Expression::Negate(*loc, expr_type.clone(), Box::new(operand.clone()))
-            }
+            Expression::Negate {
+                loc, ty: expr_type, ..
+            } => Expression::Negate {
+                loc: *loc,
+                ty: expr_type.clone(),
+                expr: Box::new(operand.clone()),
+            },
 
             _ => unreachable!("Cannot rebuild this unary expression"),
         }
@@ -223,13 +305,13 @@ impl Expression {
     /// Retrieve the operands of a commutative expression
     pub fn get_commutative_operands(&self) -> Option<(&Expression, &Expression)> {
         match self {
-            Expression::Add(_, _, _, left, right)
-            | Expression::Multiply(_, _, _, left, right)
-            | Expression::BitwiseOr(_, _, left, right)
-            | Expression::BitwiseAnd(_, _, left, right)
-            | Expression::BitwiseXor(_, _, left, right)
-            | Expression::Equal(_, left, right)
-            | Expression::NotEqual(_, left, right) => Some((left, right)),
+            Expression::Add { left, right, .. }
+            | Expression::Multiply { left, right, .. }
+            | Expression::BitwiseOr { left, right, .. }
+            | Expression::BitwiseAnd { left, right, .. }
+            | Expression::BitwiseXor { left, right, .. }
+            | Expression::Equal { left, right, .. }
+            | Expression::NotEqual { left, right, .. } => Some((left, right)),
 
             _ => None,
         }
@@ -238,14 +320,18 @@ impl Expression {
     /// Retrieve the operands of a non-commutative expression
     pub fn get_non_commutative_operands(&self) -> Option<(&Expression, &Expression)> {
         match self {
-            Expression::Subtract(_, _, _, left, right)
-            | Expression::UnsignedDivide(_, _, left, right)
-            | Expression::SignedDivide(_, _, left, right)
-            | Expression::SignedModulo(_, _, left, right)
-            | Expression::UnsignedModulo(_, _, left, right)
-            | Expression::Power(_, _, _, left, right)
-            | Expression::ShiftLeft(_, _, left, right)
-            | Expression::ShiftRight(_, _, left, right, _)
+            Expression::Subtract { left, right, .. }
+            | Expression::UnsignedDivide { left, right, .. }
+            | Expression::SignedDivide { left, right, .. }
+            | Expression::SignedModulo { left, right, .. }
+            | Expression::UnsignedModulo { left, right, .. }
+            | Expression::Power {
+                base: left,
+                exp: right,
+                ..
+            }
+            | Expression::ShiftLeft { left, right, .. }
+            | Expression::ShiftRight { left, right, .. }
             | Expression::More { left, right, .. }
             | Expression::Less { left, right, .. }
             | Expression::MoreEqual { left, right, .. }
@@ -262,14 +348,14 @@ impl Expression {
     /// Retrieve the operands of a unary expression
     pub fn get_unary_operand(&self) -> Option<&Expression> {
         match self {
-            Expression::ZeroExt(_, _, operand)
-            | Expression::SignExt(_, _, operand)
-            | Expression::Trunc(_, _, operand)
-            | Expression::Cast(_, _, operand)
-            | Expression::BytesCast(_, _, _, operand)
-            | Expression::Not(_, operand)
-            | Expression::BitwiseNot(_, _, operand)
-            | Expression::Negate(_, _, operand) => Some(operand),
+            Expression::ZeroExt { expr, .. }
+            | Expression::SignExt { expr, .. }
+            | Expression::Trunc { expr, .. }
+            | Expression::Cast { expr, .. }
+            | Expression::BytesCast { expr, .. }
+            | Expression::Not { expr, .. }
+            | Expression::BitwiseNot { expr, .. }
+            | Expression::Negate { expr, .. } => Some(expr),
 
             _ => None,
         }
@@ -278,9 +364,9 @@ impl Expression {
     /// Get the expression type for a constant-like expression
     pub fn get_constant_expression_type(&self) -> ExpressionType {
         let cte_type = match self {
-            Expression::BoolLiteral(_, value) => ConstantType::Bool(*value),
-            Expression::NumberLiteral(_, _, value) => ConstantType::Number(value.clone()),
-            Expression::BytesLiteral(_, _, value) => ConstantType::Bytes(value.clone()),
+            Expression::BoolLiteral { value, .. } => ConstantType::Bool(*value),
+            Expression::NumberLiteral { value, .. } => ConstantType::Number(value.clone()),
+            Expression::BytesLiteral { value, .. } => ConstantType::Bytes(value.clone()),
             _ => unreachable!("Not a constant expression"),
         };
 

+ 38 - 26
src/codegen/subexpression_elimination/operator.rs

@@ -53,51 +53,63 @@ impl Expression {
     /// Get the respective Operator from an Expression
     pub fn get_ave_operator(&self) -> Operator {
         match self {
-            Expression::Add(_, _, unchecked, _, _) => {
+            Expression::Add {
+                overflowing: unchecked,
+                ..
+            } => {
                 if *unchecked {
                     Operator::UncheckedAdd
                 } else {
                     Operator::Add
                 }
             }
-            Expression::Subtract(_, _, unchecked, _, _) => {
+            Expression::Subtract {
+                overflowing: unchecked,
+                ..
+            } => {
                 if *unchecked {
                     Operator::UncheckedSubtract
                 } else {
                     Operator::Subtract
                 }
             }
-            Expression::Multiply(_, _, unchecked, _, _) => {
+            Expression::Multiply {
+                overflowing: unchecked,
+                ..
+            } => {
                 if *unchecked {
                     Operator::UncheckedMultiply
                 } else {
                     Operator::Multiply
                 }
             }
-            Expression::SignedDivide(..) => Operator::SignedDivide,
-            Expression::UnsignedDivide(..) => Operator::UnsignedDivide,
-            Expression::SignedModulo(..) => Operator::SignedModulo,
-            Expression::UnsignedModulo(..) => Operator::UnsignedModulo,
-            Expression::Power(_, _, unchecked, _, _) => {
+            Expression::SignedDivide { .. } => Operator::SignedDivide,
+            Expression::UnsignedDivide { .. } => Operator::UnsignedDivide,
+            Expression::SignedModulo { .. } => Operator::SignedModulo,
+            Expression::UnsignedModulo { .. } => Operator::UnsignedModulo,
+            Expression::Power {
+                overflowing: unchecked,
+                ..
+            } => {
                 if *unchecked {
                     Operator::UncheckedPower
                 } else {
                     Operator::Power
                 }
             }
-            Expression::BitwiseOr(..) => Operator::BitwiseOr,
-            Expression::BitwiseAnd(..) => Operator::BitwiseAnd,
-            Expression::BitwiseXor(..) => Operator::BitwiseXor,
-            Expression::ShiftLeft(..) => Operator::ShiftLeft,
-            Expression::ShiftRight(_, _, _, _, true) => Operator::SignedShiftRight,
-            Expression::ShiftRight(_, _, _, _, false) => Operator::UnsignedShiftRight,
-            Expression::Not(..) => Operator::Not,
-            Expression::ZeroExt(_, ty, ..) => Operator::ZeroExt(ty.clone()),
-            Expression::SignExt(_, ty, ..) => Operator::SignExt(ty.clone()),
-            Expression::Trunc(_, ty, ..) => Operator::Trunc(ty.clone()),
-            Expression::Cast(_, ty, ..) => Operator::Cast(ty.clone()),
-            Expression::BytesCast(..) => Operator::BytesCast,
-            Expression::Negate(..) => Operator::Negate,
+            Expression::BitwiseOr { .. } => Operator::BitwiseOr,
+            Expression::BitwiseAnd { .. } => Operator::BitwiseAnd,
+            Expression::BitwiseXor { .. } => Operator::BitwiseXor,
+            Expression::ShiftLeft { .. } => Operator::ShiftLeft,
+            Expression::ShiftRight { signed: true, .. } => Operator::SignedShiftRight,
+            Expression::ShiftRight { signed: false, .. } => Operator::UnsignedShiftRight,
+            Expression::Not { .. } => Operator::Not,
+            Expression::ZeroExt { ty, .. } => Operator::ZeroExt(ty.clone()),
+            Expression::SignExt { ty, .. } => Operator::SignExt(ty.clone()),
+            Expression::Trunc { ty, .. } => Operator::Trunc(ty.clone()),
+            Expression::Cast { ty, .. } => Operator::Cast(ty.clone()),
+            Expression::BytesCast { .. } => Operator::BytesCast,
+            Expression::Negate { .. } => Operator::Negate,
             Expression::More { signed: true, .. } => Operator::SignedMore,
             Expression::More { signed: false, .. } => Operator::UnsignedMore,
             Expression::Less { signed: true, .. } => Operator::SignedLess,
@@ -106,11 +118,11 @@ impl Expression {
             Expression::MoreEqual { signed: false, .. } => Operator::UnsignedMoreEqual,
             Expression::LessEqual { signed: true, .. } => Operator::SignedLessEqual,
             Expression::LessEqual { signed: false, .. } => Operator::UnsignedLessEqual,
-            Expression::Equal(..) => Operator::Equal,
-            Expression::NotEqual(..) => Operator::NotEqual,
-            Expression::BitwiseNot(..) => Operator::BitwiseNot,
-            Expression::StringCompare(..) => Operator::StringCompare,
-            Expression::StringConcat(..) => Operator::StringConcat,
+            Expression::Equal { .. } => Operator::Equal,
+            Expression::NotEqual { .. } => Operator::NotEqual,
+            Expression::BitwiseNot { .. } => Operator::BitwiseNot,
+            Expression::StringCompare { .. } => Operator::StringCompare,
+            Expression::StringConcat { .. } => Operator::StringConcat,
             Expression::AdvancePointer { .. } => Operator::AdvancePointer,
             _ => {
                 unreachable!("Expression does not represent an operator.")

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 569 - 364
src/codegen/subexpression_elimination/tests.rs


+ 10 - 7
src/codegen/undefined_variable.rs

@@ -77,19 +77,19 @@ pub fn find_undefined_variables_in_expression(
     ctx: &mut FindUndefinedVariablesParams,
 ) -> bool {
     match &exp {
-        Expression::Variable(_, _, pos) => {
+        Expression::Variable { var_no, .. } => {
             let variable = match ctx.func_no {
                 ASTFunction::YulFunction(func_no) => {
-                    ctx.ns.yul_functions[func_no].symtable.vars.get(pos)
+                    ctx.ns.yul_functions[func_no].symtable.vars.get(var_no)
                 }
                 ASTFunction::SolidityFunction(func_no) => {
-                    ctx.ns.functions[func_no].symtable.vars.get(pos)
+                    ctx.ns.functions[func_no].symtable.vars.get(var_no)
                 }
 
                 ASTFunction::None => None,
             };
 
-            if let (Some(def_map), Some(var)) = (ctx.defs.get(pos), variable) {
+            if let (Some(def_map), Some(var)) = (ctx.defs.get(var_no), variable) {
                 for (def, modified) in def_map {
                     if let Instr::Set {
                         expr: instr_expr, ..
@@ -97,11 +97,11 @@ pub fn find_undefined_variables_in_expression(
                     {
                         // If an undefined definition reaches this read and the variable
                         // has not been modified since its definition, it is undefined
-                        if matches!(instr_expr, Expression::Undefined(_))
+                        if matches!(instr_expr, Expression::Undefined { .. })
                             && !*modified
                             && !matches!(var.ty, Type::Array(..))
                         {
-                            add_diagnostic(var, *pos, &exp.loc(), ctx.diagnostics);
+                            add_diagnostic(var, *var_no, &exp.loc(), ctx.diagnostics);
                         }
                     }
                 }
@@ -110,7 +110,10 @@ pub fn find_undefined_variables_in_expression(
         }
 
         // This is a method call whose array will never be undefined
-        Expression::Builtin(_, _, Builtin::ArrayLength, _) => false,
+        Expression::Builtin {
+            kind: Builtin::ArrayLength,
+            ..
+        } => false,
 
         _ => true,
     }

+ 18 - 13
src/codegen/vector_to_slice.rs

@@ -40,7 +40,7 @@ fn find_writable_vectors(
         match &block.instr[instr_no] {
             Instr::Set {
                 res,
-                expr: Expression::Variable(_, _, var_no),
+                expr: Expression::Variable { var_no, .. },
                 ..
             } => {
                 // is this aliasing a vector var
@@ -57,7 +57,7 @@ fn find_writable_vectors(
             // Call and return do not take slices
             Instr::Return { value: args } | Instr::Call { args, .. } => {
                 for arg in args {
-                    if let Expression::Variable(_, _, var_no) = arg {
+                    if let Expression::Variable { var_no, .. } = arg {
                         if let Some(entry) = vars.get_mut(var_no) {
                             writable.extend(entry.keys());
                         }
@@ -67,7 +67,7 @@ fn find_writable_vectors(
                 apply_transfers(&block.transfers[instr_no], vars, writable);
             }
             Instr::PushMemory { value, .. } => {
-                if let Expression::Variable(_, _, var_no) = value.as_ref() {
+                if let Expression::Variable { var_no, .. } = value.as_ref() {
                     if let Some(entry) = vars.get_mut(var_no) {
                         writable.extend(entry.keys());
                     }
@@ -76,7 +76,7 @@ fn find_writable_vectors(
                 apply_transfers(&block.transfers[instr_no], vars, writable);
             }
             Instr::Store { data, .. } => {
-                if let Expression::Variable(_, _, var_no) = data {
+                if let Expression::Variable { var_no, .. } = data {
                     if let Some(entry) = vars.get_mut(var_no) {
                         writable.extend(entry.keys());
                     }
@@ -88,7 +88,7 @@ fn find_writable_vectors(
                 destination: buf, ..
             }
             | Instr::WriteBuffer { buf, .. } => {
-                if let Expression::Variable(_, _, var_no) = buf {
+                if let Expression::Variable { var_no, .. } = buf {
                     if let Some(entry) = vars.get_mut(var_no) {
                         writable.extend(entry.keys());
                     }
@@ -174,7 +174,7 @@ fn update_vectors_to_slice(
     for block_no in 0..cfg.blocks.len() {
         for instr_no in 0..cfg.blocks[block_no].instr.len() {
             if let Instr::Set {
-                expr: Expression::AllocDynamicBytes(..),
+                expr: Expression::AllocDynamicBytes { .. },
                 ..
             } = &cfg.blocks[block_no].instr[instr_no]
             {
@@ -214,19 +214,24 @@ fn update_vectors_to_slice(
         if let Instr::Set {
             loc,
             res,
-            expr: Expression::AllocDynamicBytes(_, _, len, Some(bs)),
+            expr:
+                Expression::AllocDynamicBytes {
+                    size: len,
+                    initializer: Some(bs),
+                    ..
+                },
         } = &cfg.blocks[def.block_no].instr[def.instr_no]
         {
             let res = *res;
             cfg.blocks[def.block_no].instr[def.instr_no] = Instr::Set {
                 loc: *loc,
                 res,
-                expr: Expression::AllocDynamicBytes(
-                    *loc,
-                    Type::Slice(Box::new(Type::Bytes(1))),
-                    len.clone(),
-                    Some(bs.clone()),
-                ),
+                expr: Expression::AllocDynamicBytes {
+                    loc: *loc,
+                    ty: Type::Slice(Box::new(Type::Bytes(1))),
+                    size: len.clone(),
+                    initializer: Some(bs.clone()),
+                },
             };
 
             if let ASTFunction::SolidityFunction(function_no) = cfg.function_no {

+ 209 - 141
src/codegen/yul/builtin.rs

@@ -20,13 +20,17 @@ use solang_parser::pt;
 impl Expression {
     fn to_number_literal(&self) -> Expression {
         match self {
-            Expression::BoolLiteral(loc, value) => {
+            Expression::BoolLiteral { loc, value } => {
                 let val = if *value {
                     BigInt::from(1)
                 } else {
                     BigInt::from(0)
                 };
-                Expression::NumberLiteral(*loc, Type::Uint(256), val)
+                Expression::NumberLiteral {
+                    loc: *loc,
+                    ty: Type::Uint(256),
+                    value: val,
+                }
             }
             _ => panic!("expression should not be converted into number literal"),
         }
@@ -47,14 +51,14 @@ pub(crate) fn process_builtin(
     match builtin_ty {
         YulBuiltInFunction::Not => {
             let exp = expression(&args[0], contract_no, ns, vartab, cfg, opt);
-            Expression::BitwiseNot(*loc, exp.ty(), Box::new(exp))
+            Expression::BitwiseNot { loc: *loc, ty: exp.ty(), expr: Box::new(exp) }
         }
 
         YulBuiltInFunction::IsZero => {
             let left = expression(&args[0], contract_no, ns, vartab, cfg, opt);
-            let right = Expression::NumberLiteral(pt::Loc::Codegen, left.ty(), BigInt::from(0));
+            let right = Expression::NumberLiteral { loc: pt::Loc::Codegen, ty: left.ty(), value: BigInt::from(0) };
 
-            Expression::Equal(*loc, Box::new(left), Box::new(right))
+            Expression::Equal { loc: *loc, left: Box::new(left), right: Box::new(right) }
         }
 
         YulBuiltInFunction::Add
@@ -136,29 +140,29 @@ pub(crate) fn process_builtin(
         }
 
         YulBuiltInFunction::Gas => {
-            Expression::Builtin(*loc, vec![Type::Uint(64)], Builtin::Gasleft, vec![])
+            Expression::Builtin { loc: *loc, tys: vec![Type::Uint(64)], kind: Builtin::Gasleft, args: vec![] }
         }
 
         YulBuiltInFunction::Address => {
-            Expression::Builtin(*loc, vec![Type::Address(false)], Builtin::GetAddress, vec![])
+            Expression::Builtin { loc: *loc, tys: vec![Type::Address(false)], kind: Builtin::GetAddress, args: vec![] }
         }
 
         YulBuiltInFunction::Balance => {
             let addr = expression(&args[0], contract_no, ns, vartab, cfg, opt).cast(&Type::Address(false), ns);
-            Expression::Builtin(*loc, vec![Type::Value], Builtin::Balance,vec![addr])
+            Expression::Builtin { loc: *loc, tys: vec![Type::Value], kind: Builtin::Balance, args: vec![addr] }
         }
 
         YulBuiltInFunction::SelfBalance => {
-            let addr = Expression::Builtin(*loc, vec![Type::Contract(contract_no)], Builtin::GetAddress,vec![]);
-            Expression::Builtin(*loc, vec![Type::Value], Builtin::Balance, vec![addr])
+            let addr = Expression::Builtin { loc: *loc, tys: vec![Type::Contract(contract_no)], kind: Builtin::GetAddress, args: vec![] };
+            Expression::Builtin { loc: *loc, tys: vec![Type::Value], kind: Builtin::Balance, args: vec![addr] }
         }
 
         YulBuiltInFunction::Caller => {
-            Expression::Builtin(*loc, vec![Type::Address(true)], Builtin::Sender, vec![])
+            Expression::Builtin { loc: *loc, tys: vec![Type::Address(true)], kind: Builtin::Sender, args: vec![] }
         }
 
         YulBuiltInFunction::CallValue => {
-            Expression::Builtin(*loc, vec![Type::Value], Builtin::Value, vec![])
+            Expression::Builtin { loc: *loc, tys: vec![Type::Value], kind: Builtin::Value, args: vec![] }
         }
 
         YulBuiltInFunction::SelfDestruct => {
@@ -176,37 +180,37 @@ pub(crate) fn process_builtin(
         }
 
         YulBuiltInFunction::GasPrice => {
-            Expression::Builtin(*loc, vec![Type::Uint(64)], Builtin::Gasprice, vec![])
+            Expression::Builtin { loc: *loc, tys: vec![Type::Uint(64)], kind: Builtin::Gasprice, args: vec![] }
         }
 
         YulBuiltInFunction::ExtCodeSize => {
             let address = expression(&args[0], contract_no, ns, vartab, cfg, opt).cast(&Type::Address(false), ns);
-            Expression::Builtin(*loc, vec![Type::Uint(32)], Builtin::ExtCodeSize, vec![address])
+            Expression::Builtin { loc: *loc, tys: vec![Type::Uint(32)], kind: Builtin::ExtCodeSize, args: vec![address] }
         }
 
         YulBuiltInFunction::BlockHash => {
             let arg = expression(&args[0], contract_no, ns, vartab, cfg, opt).cast(&Type::Uint(64), ns);
-            Expression::Builtin(*loc, vec![Type::Uint(256)], Builtin::BlockHash, vec![arg])
+            Expression::Builtin { loc: *loc, tys: vec![Type::Uint(256)], kind: Builtin::BlockHash, args: vec![arg] }
         }
 
         YulBuiltInFunction::CoinBase => {
-            Expression::Builtin(*loc, vec![Type::Address(false)], Builtin::BlockCoinbase, vec![])
+            Expression::Builtin { loc: *loc, tys: vec![Type::Address(false)], kind: Builtin::BlockCoinbase, args: vec![] }
         }
 
         YulBuiltInFunction::Timestamp => {
-            Expression::Builtin(*loc, vec![Type::Uint(64)], Builtin::Timestamp, vec![])
+            Expression::Builtin { loc: *loc, tys: vec![Type::Uint(64)], kind: Builtin::Timestamp, args: vec![] }
         }
 
         YulBuiltInFunction::Number => {
-            Expression::Builtin(*loc, vec![Type::Uint(64)], Builtin::BlockNumber, vec![])
+            Expression::Builtin { loc: *loc, tys: vec![Type::Uint(64)], kind: Builtin::BlockNumber, args: vec![] }
         }
 
         YulBuiltInFunction::Difficulty => {
-            Expression::Builtin(*loc, vec![Type::Uint(256)], Builtin::BlockDifficulty, vec![])
+            Expression::Builtin { loc: *loc, tys: vec![Type::Uint(256)], kind: Builtin::BlockDifficulty, args: vec![] }
         }
 
         YulBuiltInFunction::GasLimit => {
-            Expression::Builtin(*loc, vec![Type::Uint(64)], Builtin::GasLimit, vec![])
+            Expression::Builtin { loc: *loc, tys: vec![Type::Uint(64)], kind: Builtin::GasLimit, args: vec![] }
         }
     }
 }
@@ -231,46 +235,70 @@ fn process_arithmetic(
     let (left, right) = equalize_types(left, right, ns);
 
     match builtin_ty {
-        YulBuiltInFunction::Add => {
-            Expression::Add(*loc, left.ty(), true, Box::new(left), Box::new(right))
-        }
-        YulBuiltInFunction::Sub => {
-            Expression::Subtract(*loc, left.ty(), true, Box::new(left), Box::new(right))
-        }
-        YulBuiltInFunction::Mul => {
-            Expression::Multiply(*loc, left.ty(), true, Box::new(left), Box::new(right))
-        }
+        YulBuiltInFunction::Add => Expression::Add {
+            loc: *loc,
+            ty: left.ty(),
+            overflowing: true,
+            left: Box::new(left),
+            right: Box::new(right),
+        },
+        YulBuiltInFunction::Sub => Expression::Subtract {
+            loc: *loc,
+            ty: left.ty(),
+            overflowing: true,
+            left: Box::new(left),
+            right: Box::new(right),
+        },
+        YulBuiltInFunction::Mul => Expression::Multiply {
+            loc: *loc,
+            ty: left.ty(),
+            overflowing: true,
+            left: Box::new(left),
+            right: Box::new(right),
+        },
         YulBuiltInFunction::Div => {
-            let expr = Expression::UnsignedDivide(
-                *loc,
-                left.ty(),
-                Box::new(left),
-                Box::new(right.clone()),
-            );
+            let expr = Expression::UnsignedDivide {
+                loc: *loc,
+                ty: left.ty(),
+                left: Box::new(left),
+                right: Box::new(right.clone()),
+            };
             branch_if_zero(right, expr, cfg, vartab)
         }
         YulBuiltInFunction::SDiv => {
-            let expr =
-                Expression::SignedDivide(*loc, left.ty(), Box::new(left), Box::new(right.clone()));
+            let expr = Expression::SignedDivide {
+                loc: *loc,
+                ty: left.ty(),
+                left: Box::new(left),
+                right: Box::new(right.clone()),
+            };
             branch_if_zero(right, expr, cfg, vartab)
         }
         YulBuiltInFunction::Mod => {
-            let expr = Expression::UnsignedModulo(
-                *loc,
-                left.ty(),
-                Box::new(left),
-                Box::new(right.clone()),
-            );
+            let expr = Expression::UnsignedModulo {
+                loc: *loc,
+                ty: left.ty(),
+                left: Box::new(left),
+                right: Box::new(right.clone()),
+            };
             branch_if_zero(right, expr, cfg, vartab)
         }
         YulBuiltInFunction::SMod => {
-            let expr =
-                Expression::SignedModulo(*loc, left.ty(), Box::new(left), Box::new(right.clone()));
+            let expr = Expression::SignedModulo {
+                loc: *loc,
+                ty: left.ty(),
+                left: Box::new(left),
+                right: Box::new(right.clone()),
+            };
             branch_if_zero(right, expr, cfg, vartab)
         }
-        YulBuiltInFunction::Exp => {
-            Expression::Power(*loc, left.ty(), true, Box::new(left), Box::new(right))
-        }
+        YulBuiltInFunction::Exp => Expression::Power {
+            loc: *loc,
+            ty: left.ty(),
+            overflowing: true,
+            base: Box::new(left),
+            exp: Box::new(right),
+        },
         YulBuiltInFunction::Lt => Expression::Less {
             loc: *loc,
             signed: false,
@@ -295,26 +323,50 @@ fn process_arithmetic(
             left: Box::new(left),
             right: Box::new(right),
         },
-        YulBuiltInFunction::Eq => Expression::Equal(*loc, Box::new(left), Box::new(right)),
-        YulBuiltInFunction::And => {
-            Expression::BitwiseAnd(*loc, left.ty(), Box::new(left), Box::new(right))
-        }
-        YulBuiltInFunction::Or => {
-            Expression::BitwiseOr(*loc, left.ty(), Box::new(left), Box::new(right))
-        }
-        YulBuiltInFunction::Xor => {
-            Expression::BitwiseXor(*loc, left.ty(), Box::new(left), Box::new(right))
-        }
+        YulBuiltInFunction::Eq => Expression::Equal {
+            loc: *loc,
+            left: Box::new(left),
+            right: Box::new(right),
+        },
+        YulBuiltInFunction::And => Expression::BitwiseAnd {
+            loc: *loc,
+            ty: left.ty(),
+            left: Box::new(left),
+            right: Box::new(right),
+        },
+        YulBuiltInFunction::Or => Expression::BitwiseOr {
+            loc: *loc,
+            ty: left.ty(),
+            left: Box::new(left),
+            right: Box::new(right),
+        },
+        YulBuiltInFunction::Xor => Expression::BitwiseXor {
+            loc: *loc,
+            ty: left.ty(),
+            left: Box::new(left),
+            right: Box::new(right),
+        },
         // For bit shifting, the syntax is the following: shr(x, y) shifts right y by x bits.
-        YulBuiltInFunction::Shl => {
-            Expression::ShiftLeft(*loc, left.ty(), Box::new(right), Box::new(left))
-        }
-        YulBuiltInFunction::Shr => {
-            Expression::ShiftRight(*loc, left.ty(), Box::new(right), Box::new(left), false)
-        }
-        YulBuiltInFunction::Sar => {
-            Expression::ShiftRight(*loc, left.ty(), Box::new(right), Box::new(left), true)
-        }
+        YulBuiltInFunction::Shl => Expression::ShiftLeft {
+            loc: *loc,
+            ty: left.ty(),
+            left: Box::new(right),
+            right: Box::new(left),
+        },
+        YulBuiltInFunction::Shr => Expression::ShiftRight {
+            loc: *loc,
+            ty: left.ty(),
+            left: Box::new(right),
+            right: Box::new(left),
+            signed: false,
+        },
+        YulBuiltInFunction::Sar => Expression::ShiftRight {
+            loc: *loc,
+            ty: left.ty(),
+            left: Box::new(right),
+            right: Box::new(left),
+            signed: true,
+        },
 
         YulBuiltInFunction::AddMod | YulBuiltInFunction::MulMod => {
             let modulo_operand = expression(&args[2], contract_no, ns, vartab, cfg, opt);
@@ -324,12 +376,12 @@ fn process_arithmetic(
             } else {
                 Builtin::MulMod
             };
-            let codegen_expr = Expression::Builtin(
-                *loc,
-                vec![left.ty()],
-                builtin,
-                vec![right, left, equalized_modulo],
-            );
+            let codegen_expr = Expression::Builtin {
+                loc: *loc,
+                tys: vec![left.ty()],
+                kind: builtin,
+                args: vec![right, left, equalized_modulo],
+            };
             branch_if_zero(modulo_operand, codegen_expr, cfg, vartab)
         }
 
@@ -343,17 +395,17 @@ fn cast_to_number(expr: Expression, ns: &Namespace) -> Expression {
     let ty = expr.ty();
 
     if !ty.is_contract_storage() && ty.is_reference_type(ns) {
-        Expression::Cast(
-            pt::Loc::Codegen,
-            Type::Uint(ns.target.ptr_size()),
-            expr.into(),
-        )
+        Expression::Cast {
+            loc: pt::Loc::Codegen,
+            ty: Type::Uint(ns.target.ptr_size()),
+            expr: expr.into(),
+        }
     } else if ty.is_address() {
-        Expression::Cast(
-            pt::Loc::Codegen,
-            Type::Uint((ns.address_length * 8) as u16),
-            expr.into(),
-        )
+        Expression::Cast {
+            loc: pt::Loc::Codegen,
+            ty: Type::Uint((ns.address_length * 8) as u16),
+            expr: expr.into(),
+        }
     } else {
         expr
     }
@@ -367,14 +419,14 @@ fn equalize_types(
 ) -> (Expression, Expression) {
     if matches!(
         left,
-        Expression::BytesLiteral(..) | Expression::BoolLiteral(..)
+        Expression::BytesLiteral { .. } | Expression::BoolLiteral { .. }
     ) {
         left = left.to_number_literal();
     }
 
     if matches!(
         right,
-        Expression::BytesLiteral(..) | Expression::BoolLiteral(..)
+        Expression::BytesLiteral { .. } | Expression::BoolLiteral { .. }
     ) {
         right = right.to_number_literal();
     }
@@ -411,15 +463,15 @@ fn branch_if_zero(
     vartab: &mut Vartable,
 ) -> Expression {
     let temp = vartab.temp_anonymous(&Type::Uint(256));
-    let cond = Expression::Equal(
-        pt::Loc::Codegen,
-        Box::new(variable.clone()),
-        Box::new(Expression::NumberLiteral(
-            pt::Loc::Codegen,
-            variable.ty(),
-            BigInt::zero(),
-        )),
-    );
+    let cond = Expression::Equal {
+        loc: pt::Loc::Codegen,
+        left: Box::new(variable.clone()),
+        right: Box::new(Expression::NumberLiteral {
+            loc: pt::Loc::Codegen,
+            ty: variable.ty(),
+            value: BigInt::zero(),
+        }),
+    };
 
     let then = cfg.new_basic_block("then".to_string());
     let else_ = cfg.new_basic_block("else".to_string());
@@ -440,7 +492,11 @@ fn branch_if_zero(
         Instr::Set {
             loc: pt::Loc::Codegen,
             res: temp,
-            expr: Expression::NumberLiteral(pt::Loc::Codegen, Type::Uint(256), BigInt::from(0)),
+            expr: Expression::NumberLiteral {
+                loc: pt::Loc::Codegen,
+                ty: Type::Uint(256),
+                value: BigInt::from(0),
+            },
         },
     );
     cfg.add(vartab, Instr::Branch { block: endif });
@@ -458,7 +514,11 @@ fn branch_if_zero(
     cfg.set_phis(endif, vartab.pop_dirty_tracker());
     cfg.set_basic_block(endif);
 
-    Expression::Variable(pt::Loc::Codegen, Type::Uint(256), temp)
+    Expression::Variable {
+        loc: pt::Loc::Codegen,
+        ty: Type::Uint(256),
+        var_no: temp,
+    }
 }
 
 /// This function implements the byte builtin
@@ -476,11 +536,11 @@ fn byte_builtin(
         loc: *loc,
         signed: false,
         left: Box::new(offset.clone()),
-        right: Box::new(Expression::NumberLiteral(
-            *loc,
-            Type::Uint(256),
-            BigInt::from(32),
-        )),
+        right: Box::new(Expression::NumberLiteral {
+            loc: *loc,
+            ty: Type::Uint(256),
+            value: BigInt::from(32),
+        }),
     };
 
     let temp = vartab.temp_anonymous(&Type::Uint(256));
@@ -505,7 +565,11 @@ fn byte_builtin(
         Instr::Set {
             loc: pt::Loc::Codegen,
             res: temp,
-            expr: Expression::NumberLiteral(pt::Loc::Codegen, Type::Uint(256), BigInt::zero()),
+            expr: Expression::NumberLiteral {
+                loc: pt::Loc::Codegen,
+                ty: Type::Uint(256),
+                value: BigInt::zero(),
+            },
         },
     );
     cfg.add(vartab, Instr::Branch { block: endif });
@@ -513,46 +577,46 @@ fn byte_builtin(
     cfg.set_basic_block(else_);
 
     // The following implements the operation (arg[1] >> (8 * (31 - arg[0]))) & 0xff
-    let op_31_sub_arg0 = Expression::Subtract(
-        *loc,
-        Type::Uint(256),
-        false,
-        Box::new(Expression::NumberLiteral(
-            *loc,
-            Type::Uint(256),
-            BigInt::from(31),
-        )),
-        Box::new(offset),
-    );
-    let op_eight_times = Expression::ShiftLeft(
-        *loc,
-        Type::Uint(256),
-        Box::new(op_31_sub_arg0),
-        Box::new(Expression::NumberLiteral(
-            *loc,
-            Type::Uint(256),
-            BigInt::from(3),
-        )),
-    );
-    let op_shift_right = Expression::ShiftRight(
-        *loc,
-        Type::Uint(256),
-        Box::new(
+    let op_31_sub_arg0 = Expression::Subtract {
+        loc: *loc,
+        ty: Type::Uint(256),
+        overflowing: false,
+        left: Box::new(Expression::NumberLiteral {
+            loc: *loc,
+            ty: Type::Uint(256),
+            value: BigInt::from(31),
+        }),
+        right: Box::new(offset),
+    };
+    let op_eight_times = Expression::ShiftLeft {
+        loc: *loc,
+        ty: Type::Uint(256),
+        left: Box::new(op_31_sub_arg0),
+        right: Box::new(Expression::NumberLiteral {
+            loc: *loc,
+            ty: Type::Uint(256),
+            value: BigInt::from(3),
+        }),
+    };
+    let op_shift_right = Expression::ShiftRight {
+        loc: *loc,
+        ty: Type::Uint(256),
+        left: Box::new(
             expression(&args[1], contract_no, ns, vartab, cfg, opt).cast(&Type::Uint(256), ns),
         ),
-        Box::new(op_eight_times),
-        false,
-    );
-    let masked_result = Expression::BitwiseAnd(
-        *loc,
-        Type::Uint(256),
-        Box::new(op_shift_right),
-        Box::new(Expression::NumberLiteral(
-            *loc,
-            Type::Uint(256),
-            BigInt::from_u8(255).unwrap(),
-        )),
-    );
+        right: Box::new(op_eight_times),
+        signed: false,
+    };
+    let masked_result = Expression::BitwiseAnd {
+        loc: *loc,
+        ty: Type::Uint(256),
+        left: Box::new(op_shift_right),
+        right: Box::new(Expression::NumberLiteral {
+            loc: *loc,
+            ty: Type::Uint(256),
+            value: BigInt::from_u8(255).unwrap(),
+        }),
+    };
 
     cfg.add(
         vartab,
@@ -567,5 +631,9 @@ fn byte_builtin(
     cfg.set_phis(endif, vartab.pop_dirty_tracker());
     cfg.set_basic_block(endif);
 
-    Expression::Variable(pt::Loc::Codegen, Type::Uint(256), temp)
+    Expression::Variable {
+        loc: pt::Loc::Codegen,
+        ty: Type::Uint(256),
+        var_no: temp,
+    }
 }

+ 59 - 28
src/codegen/yul/expression.rs

@@ -24,7 +24,10 @@ pub(crate) fn expression(
     match expr {
         ast::YulExpression::BoolLiteral(loc, value, ty) => {
             if matches!(ty, Type::Bool) {
-                return Expression::BoolLiteral(*loc, *value);
+                return Expression::BoolLiteral {
+                    loc: *loc,
+                    value: *value,
+                };
             }
 
             // If the user has coerced a type for bool, it is a number literal.
@@ -34,17 +37,27 @@ pub(crate) fn expression(
                 BigInt::from(0)
             };
 
-            Expression::NumberLiteral(*loc, ty.clone(), num)
-        }
-        ast::YulExpression::NumberLiteral(loc, value, ty) => {
-            Expression::NumberLiteral(*loc, ty.clone(), value.clone())
-        }
-        ast::YulExpression::StringLiteral(loc, value, ty) => {
-            Expression::NumberLiteral(*loc, ty.clone(), BigInt::from_bytes_be(Sign::Plus, value))
-        }
-        ast::YulExpression::YulLocalVariable(loc, ty, var_no) => {
-            Expression::Variable(*loc, ty.clone(), *var_no)
+            Expression::NumberLiteral {
+                loc: *loc,
+                ty: ty.clone(),
+                value: num,
+            }
         }
+        ast::YulExpression::NumberLiteral(loc, value, ty) => Expression::NumberLiteral {
+            loc: *loc,
+            ty: ty.clone(),
+            value: value.clone(),
+        },
+        ast::YulExpression::StringLiteral(loc, value, ty) => Expression::NumberLiteral {
+            loc: *loc,
+            ty: ty.clone(),
+            value: BigInt::from_bytes_be(Sign::Plus, value),
+        },
+        ast::YulExpression::YulLocalVariable(loc, ty, var_no) => Expression::Variable {
+            loc: *loc,
+            ty: ty.clone(),
+            var_no: *var_no,
+        },
         ast::YulExpression::ConstantVariable(_, _, Some(var_contract_no), var_no) => {
             codegen::expression(
                 ns.contracts[*var_contract_no].variables[*var_no]
@@ -72,9 +85,11 @@ pub(crate) fn expression(
         | ast::YulExpression::SolidityLocalVariable(_, _, Some(StorageLocation::Storage(_)), ..) => {
             panic!("Storage variables cannot be accessed without suffixed in yul");
         }
-        ast::YulExpression::SolidityLocalVariable(loc, ty, _, var_no) => {
-            Expression::Variable(*loc, ty.clone(), *var_no)
-        }
+        ast::YulExpression::SolidityLocalVariable(loc, ty, _, var_no) => Expression::Variable {
+            loc: *loc,
+            ty: ty.clone(),
+            var_no: *var_no,
+        },
         ast::YulExpression::SuffixAccess(loc, expr, suffix) => {
             process_suffix_access(loc, expr, suffix, contract_no, vartab, cfg, ns, opt)
         }
@@ -119,7 +134,11 @@ fn process_suffix_access(
                 Some(StorageLocation::Storage(_)),
                 var_no,
             ) => {
-                return Expression::Variable(*loc, Type::Uint(256), *var_no);
+                return Expression::Variable {
+                    loc: *loc,
+                    ty: Type::Uint(256),
+                    var_no: *var_no,
+                };
             }
 
             _ => (),
@@ -132,7 +151,11 @@ fn process_suffix_access(
                 Some(StorageLocation::Storage(_)),
                 ..,
             ) => {
-                return Expression::NumberLiteral(Loc::Codegen, Type::Uint(256), BigInt::from(0));
+                return Expression::NumberLiteral {
+                    loc: Loc::Codegen,
+                    ty: Type::Uint(256),
+                    value: BigInt::from(0),
+                };
             }
 
             ast::YulExpression::SolidityLocalVariable(
@@ -142,11 +165,15 @@ fn process_suffix_access(
                 var_no,
             ) => {
                 if dims.last() == Some(&ArrayLength::Dynamic) {
-                    return Expression::Cast(
-                        *loc,
-                        Type::Uint(256),
-                        Box::new(Expression::Variable(*loc, ty.clone(), *var_no)),
-                    );
+                    return Expression::Cast {
+                        loc: *loc,
+                        ty: Type::Uint(256),
+                        expr: Box::new(Expression::Variable {
+                            loc: *loc,
+                            ty: ty.clone(),
+                            var_no: *var_no,
+                        }),
+                    };
                 }
             }
 
@@ -162,12 +189,12 @@ fn process_suffix_access(
             ) = expr
             {
                 if dims.last() == Some(&ArrayLength::Dynamic) {
-                    return Expression::Builtin(
-                        *loc,
-                        vec![Type::Uint(32)],
-                        Builtin::ArrayLength,
-                        vec![expression(expr, contract_no, ns, vartab, cfg, opt)],
-                    );
+                    return Expression::Builtin {
+                        loc: *loc,
+                        tys: vec![Type::Uint(32)],
+                        kind: Builtin::ArrayLength,
+                        args: vec![expression(expr, contract_no, ns, vartab, cfg, opt)],
+                    };
                 }
             }
         }
@@ -240,7 +267,11 @@ pub(crate) fn process_function_call(
         let temp_pos = vartab.temp(&id, &ret.ty);
         return_tys.push(ret.ty.clone());
         res.push(temp_pos);
-        returns.push(Expression::Variable(id.loc, ret.ty.clone(), temp_pos));
+        returns.push(Expression::Variable {
+            loc: id.loc,
+            ty: ret.ty.clone(),
+            var_no: temp_pos,
+        });
     }
 
     cfg.add(

+ 4 - 6
src/codegen/yul/mod.rs

@@ -86,12 +86,10 @@ fn yul_function_cfg(
                 .symtable
                 .returns
                 .iter()
-                .map(|pos| {
-                    Expression::Variable(
-                        pt::Loc::Codegen,
-                        yul_func.symtable.vars[pos].ty.clone(),
-                        *pos,
-                    )
+                .map(|pos| Expression::Variable {
+                    loc: pt::Loc::Codegen,
+                    ty: yul_func.symtable.vars[pos].ty.clone(),
+                    var_no: *pos,
                 })
                 .collect::<Vec<Expression>>(),
         }

+ 30 - 26
src/codegen/yul/statements.rs

@@ -155,7 +155,7 @@ fn process_variable_declaration(
     } else {
         let mut inits: Vec<Expression> = Vec::with_capacity(vars.len());
         for item in vars {
-            inits.push(Expression::Undefined(item.1.clone()));
+            inits.push(Expression::Undefined { ty: item.1.clone() });
         }
 
         inits
@@ -287,12 +287,16 @@ fn cfg_single_assigment(
                         _ => unreachable!(),
                     };
 
-                    let ptr = Expression::StructMember(
-                        *loc,
-                        Type::Ref(Box::new(member_ty)),
-                        Box::new(Expression::Variable(*loc, ty.clone(), *var_no)),
-                        member_no,
-                    );
+                    let ptr = Expression::StructMember {
+                        loc: *loc,
+                        ty: Type::Ref(Box::new(member_ty)),
+                        expr: Box::new(Expression::Variable {
+                            loc: *loc,
+                            ty: ty.clone(),
+                            var_no: *var_no,
+                        }),
+                        member: member_no,
+                    };
 
                     cfg.add(
                         vartab,
@@ -327,7 +331,7 @@ fn cfg_single_assigment(
             }
         }
 
-        ast::YulExpression::BoolLiteral(..)
+        ast::YulExpression::BoolLiteral { .. }
         | ast::YulExpression::NumberLiteral(..)
         | ast::YulExpression::StringLiteral(..)
         | ast::YulExpression::SolidityLocalVariable(..)
@@ -357,15 +361,15 @@ fn process_if_block(
     let bool_cond = if cond.ty() == Type::Bool {
         cond
     } else {
-        Expression::NotEqual(
-            block.loc,
-            Box::new(Expression::NumberLiteral(
-                pt::Loc::Codegen,
-                cond.ty(),
-                BigInt::from_u8(0).unwrap(),
-            )),
-            Box::new(cond),
-        )
+        Expression::NotEqual {
+            loc: block.loc,
+            left: Box::new(Expression::NumberLiteral {
+                loc: pt::Loc::Codegen,
+                ty: cond.ty(),
+                value: BigInt::from_u8(0).unwrap(),
+            }),
+            right: Box::new(cond),
+        }
     };
 
     let then = cfg.new_basic_block("then".to_string());
@@ -432,15 +436,15 @@ fn process_for_block(
     let cond_expr = if cond_expr.ty() == Type::Bool {
         cond_expr
     } else {
-        Expression::NotEqual(
-            *loc,
-            Box::new(Expression::NumberLiteral(
-                pt::Loc::Codegen,
-                cond_expr.ty(),
-                BigInt::from_u8(0).unwrap(),
-            )),
-            Box::new(cond_expr),
-        )
+        Expression::NotEqual {
+            loc: *loc,
+            left: Box::new(Expression::NumberLiteral {
+                loc: pt::Loc::Codegen,
+                ty: cond_expr.ty(),
+                value: BigInt::from_u8(0).unwrap(),
+            }),
+            right: Box::new(cond_expr),
+        }
     };
 
     cfg.add(

+ 114 - 61
src/codegen/yul/tests/expression.rs

@@ -25,20 +25,28 @@ fn bool_literal() {
 
     let expr = ast::YulExpression::BoolLiteral(loc, true, Type::Bool);
     let res = expression(&expr, 0, &ns, &mut vartab, &mut cfg, &opt);
-    assert_eq!(res, Expression::BoolLiteral(loc, true));
+    assert_eq!(res, Expression::BoolLiteral { loc, value: true });
 
     let expr = ast::YulExpression::BoolLiteral(loc, true, Type::Uint(32));
     let res = expression(&expr, 0, &ns, &mut vartab, &mut cfg, &opt);
     assert_eq!(
         res,
-        Expression::NumberLiteral(loc, Type::Uint(32), BigInt::from(1))
+        Expression::NumberLiteral {
+            loc,
+            ty: Type::Uint(32),
+            value: BigInt::from(1)
+        }
     );
 
     let expr = ast::YulExpression::BoolLiteral(loc, false, Type::Uint(32));
     let res = expression(&expr, 0, &ns, &mut vartab, &mut cfg, &opt);
     assert_eq!(
         res,
-        Expression::NumberLiteral(loc, Type::Uint(32), BigInt::from(0))
+        Expression::NumberLiteral {
+            loc,
+            ty: Type::Uint(32),
+            value: BigInt::from(0)
+        }
     );
 }
 
@@ -54,7 +62,11 @@ fn number_literal() {
     let res = expression(&expr, 0, &ns, &mut vartab, &mut cfg, &opt);
     assert_eq!(
         res,
-        Expression::NumberLiteral(loc, Type::Uint(256), BigInt::from(32))
+        Expression::NumberLiteral {
+            loc,
+            ty: Type::Uint(256),
+            value: BigInt::from(32)
+        }
     );
 }
 
@@ -70,11 +82,11 @@ fn string_literal() {
     let res = expression(&expr, 0, &ns, &mut vartab, &mut cfg, &opt);
     assert_eq!(
         res,
-        Expression::NumberLiteral(
+        Expression::NumberLiteral {
             loc,
-            Type::Uint(128),
-            BigInt::from_bytes_be(Sign::Plus, &[0, 3, 255, 127])
-        )
+            ty: Type::Uint(128),
+            value: BigInt::from_bytes_be(Sign::Plus, &[0, 3, 255, 127])
+        }
     );
 }
 
@@ -88,7 +100,14 @@ fn yul_local_variable() {
 
     let expr = ast::YulExpression::YulLocalVariable(loc, Type::Int(16), 5);
     let res = expression(&expr, 0, &ns, &mut vartab, &mut cfg, &opt);
-    assert_eq!(res, Expression::Variable(loc, Type::Int(16), 5));
+    assert_eq!(
+        res,
+        Expression::Variable {
+            loc,
+            ty: Type::Int(16),
+            var_no: 5
+        }
+    );
 }
 
 #[test]
@@ -146,7 +165,11 @@ fn contract_constant_variable() {
     let res = expression(&expr, 0, &ns, &mut vartab, &mut cfg, &opt);
     assert_eq!(
         res,
-        Expression::NumberLiteral(loc, Type::Uint(64), BigInt::from(64))
+        Expression::NumberLiteral {
+            loc,
+            ty: Type::Uint(64),
+            value: BigInt::from(64)
+        }
     );
 }
 
@@ -179,7 +202,11 @@ fn global_constant_variable() {
     let res = expression(&expr, 0, &ns, &mut vartab, &mut cfg, &opt);
     assert_eq!(
         res,
-        Expression::NumberLiteral(loc, Type::Uint(64), BigInt::from(64))
+        Expression::NumberLiteral {
+            loc,
+            ty: Type::Uint(64),
+            value: BigInt::from(64)
+        }
     );
 }
 
@@ -224,7 +251,14 @@ fn solidity_local_variable() {
 
     let expr = ast::YulExpression::SolidityLocalVariable(loc, Type::Uint(32), None, 7);
     let res = expression(&expr, 0, &ns, &mut vartab, &mut cfg, &opt);
-    assert_eq!(res, Expression::Variable(loc, Type::Uint(32), 7));
+    assert_eq!(
+        res,
+        Expression::Variable {
+            loc,
+            ty: Type::Uint(32),
+            var_no: 7
+        }
+    );
 }
 
 #[test]
@@ -280,7 +314,11 @@ fn slot_suffix() {
     let res = expression(&expr, 0, &ns, &mut vartab, &mut cfg, &opt);
     assert_eq!(
         res,
-        Expression::NumberLiteral(Loc::File(1, 2, 3), Type::Uint(256), BigInt::from(2))
+        Expression::NumberLiteral {
+            loc: Loc::File(1, 2, 3),
+            ty: Type::Uint(256),
+            value: BigInt::from(2)
+        }
     );
 
     let expr = ast::YulExpression::SuffixAccess(
@@ -294,7 +332,14 @@ fn slot_suffix() {
         YulSuffix::Slot,
     );
     let res = expression(&expr, 0, &ns, &mut vartab, &mut cfg, &opt);
-    assert_eq!(res, Expression::Variable(loc, Type::Uint(256), 0));
+    assert_eq!(
+        res,
+        Expression::Variable {
+            loc,
+            ty: Type::Uint(256),
+            var_no: 0
+        }
+    );
 }
 
 #[test]
@@ -342,7 +387,11 @@ fn offset_suffix() {
     let res = expression(&expr, 0, &ns, &mut vartab, &mut cfg, &opt);
     assert_eq!(
         res,
-        Expression::NumberLiteral(Loc::Codegen, Type::Uint(256), BigInt::from(0))
+        Expression::NumberLiteral {
+            loc: Loc::Codegen,
+            ty: Type::Uint(256),
+            value: BigInt::from(0)
+        }
     );
 
     let expr = ast::YulExpression::SuffixAccess(
@@ -358,7 +407,11 @@ fn offset_suffix() {
     let res = expression(&expr, 0, &ns, &mut vartab, &mut cfg, &opt);
     assert_eq!(
         res,
-        Expression::NumberLiteral(Loc::Codegen, Type::Uint(256), BigInt::from(0))
+        Expression::NumberLiteral {
+            loc: Loc::Codegen,
+            ty: Type::Uint(256),
+            value: BigInt::from(0)
+        }
     );
 
     let expr = ast::YulExpression::SuffixAccess(
@@ -374,15 +427,15 @@ fn offset_suffix() {
     let res = expression(&expr, 0, &ns, &mut vartab, &mut cfg, &opt);
     assert_eq!(
         res,
-        Expression::Cast(
+        Expression::Cast {
             loc,
-            Type::Uint(256),
-            Box::new(Expression::Variable(
+            ty: Type::Uint(256),
+            expr: Box::new(Expression::Variable {
                 loc,
-                Type::Array(Box::new(Type::Uint(256)), vec![ArrayLength::Dynamic]),
-                1
-            ))
-        )
+                ty: Type::Array(Box::new(Type::Uint(256)), vec![ArrayLength::Dynamic]),
+                var_no: 1
+            })
+        }
     );
 }
 
@@ -459,13 +512,13 @@ fn length_suffix() {
     let res = expression(&expr, 0, &ns, &mut vartab, &mut cfg, &opt);
     assert_eq!(
         res,
-        Expression::Builtin(
+        Expression::Builtin {
             loc,
-            vec![Type::Uint(32)],
-            Builtin::ArrayLength,
-            vec![Expression::Variable(
+            tys: vec![Type::Uint(32)],
+            kind: Builtin::ArrayLength,
+            args: vec![Expression::Variable {
                 loc,
-                Type::Array(
+                ty: Type::Array(
                     Box::new(Type::Uint(32)),
                     vec![
                         ArrayLength::Dynamic,
@@ -473,9 +526,9 @@ fn length_suffix() {
                         ArrayLength::Dynamic
                     ]
                 ),
-                3
-            )]
-        )
+                var_no: 3
+            }]
+        }
     );
 }
 
@@ -505,13 +558,13 @@ fn length_suffix_panic() {
     let res = expression(&expr, 0, &ns, &mut vartab, &mut cfg, &opt);
     assert_eq!(
         res,
-        Expression::Builtin(
+        Expression::Builtin {
             loc,
-            vec![Type::Uint(256)],
-            Builtin::ArrayLength,
-            vec![Expression::Variable(
+            tys: vec![Type::Uint(256)],
+            kind: Builtin::ArrayLength,
+            args: vec![Expression::Variable {
                 loc,
-                Type::Array(
+                ty: Type::Array(
                     Box::new(Type::Uint(32)),
                     vec![
                         ArrayLength::Dynamic,
@@ -519,9 +572,9 @@ fn length_suffix_panic() {
                         ArrayLength::Dynamic
                     ]
                 ),
-                3
-            )]
-        )
+                var_no: 3
+            }]
+        }
     );
 }
 
@@ -551,24 +604,24 @@ fn selector_suffix() {
 
     assert_eq!(
         res,
-        Expression::Load(
+        Expression::Load {
             loc,
-            Type::FunctionSelector,
-            Box::new(Expression::StructMember(
+            ty: Type::FunctionSelector,
+            expr: Box::new(Expression::StructMember {
                 loc,
-                Type::Ref(Box::new(Type::FunctionSelector)),
-                Box::new(Expression::Variable(
+                ty: Type::Ref(Box::new(Type::FunctionSelector)),
+                expr: Box::new(Expression::Variable {
                     loc,
-                    Type::ExternalFunction {
+                    ty: Type::ExternalFunction {
                         mutability: Mutability::Pure(loc),
                         params: vec![],
                         returns: vec![],
                     },
-                    4
-                )),
-                0
-            ))
-        )
+                    var_no: 4
+                }),
+                member: 0
+            })
+        }
     );
 }
 
@@ -620,24 +673,24 @@ fn address_suffix() {
 
     assert_eq!(
         res,
-        Expression::Load(
+        Expression::Load {
             loc,
-            Type::Address(false),
-            Box::new(Expression::StructMember(
+            ty: Type::Address(false),
+            expr: Box::new(Expression::StructMember {
                 loc,
-                Type::Ref(Box::new(Type::Address(false))),
-                Box::new(Expression::Variable(
+                ty: Type::Ref(Box::new(Type::Address(false))),
+                expr: Box::new(Expression::Variable {
                     loc,
-                    Type::ExternalFunction {
+                    ty: Type::ExternalFunction {
                         mutability: Mutability::Pure(loc),
                         params: vec![],
                         returns: vec![]
                     },
-                    4
-                )),
-                1
-            ))
-        )
+                    var_no: 4
+                }),
+                member: 1
+            })
+        }
     );
 }
 

+ 249 - 132
src/emit/expression.rs

@@ -29,13 +29,19 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
     ns: &Namespace,
 ) -> BasicValueEnum<'a> {
     match e {
-        Expression::FunctionArg(_, _, pos) => function.get_nth_param(*pos as u32).unwrap(),
-        Expression::BoolLiteral(_, val) => {
-            bin.context.bool_type().const_int(*val as u64, false).into()
-        }
-        Expression::NumberLiteral(_, Type::Address(_), val) => {
+        Expression::FunctionArg { arg_no, .. } => function.get_nth_param(*arg_no as u32).unwrap(),
+        Expression::BoolLiteral { value, .. } => bin
+            .context
+            .bool_type()
+            .const_int(*value as u64, false)
+            .into(),
+        Expression::NumberLiteral {
+            ty: Type::Address(_),
+            value,
+            ..
+        } => {
             // address can be negative; "address(-1)" is 0xffff...
-            let mut bs = val.to_signed_bytes_be();
+            let mut bs = value.to_signed_bytes_be();
 
             // make sure it's no more than 32
             if bs.len() > ns.address_length {
@@ -45,7 +51,7 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
                 }
             } else {
                 // insert leading bytes
-                let val = if val.sign() == Sign::Minus { 0xff } else { 0 };
+                let val = if value.sign() == Sign::Minus { 0xff } else { 0 };
 
                 for _ in 0..ns.address_length - bs.len() {
                     bs.insert(0, val);
@@ -59,8 +65,12 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
 
             bin.context.i8_type().const_array(&address).into()
         }
-        Expression::NumberLiteral(_, ty, n) => bin.number_literal(ty.bits(ns) as u32, n, ns).into(),
-        Expression::StructLiteral(_, ty, exprs) => {
+        Expression::NumberLiteral { ty, value, .. } => {
+            bin.number_literal(ty.bits(ns) as u32, value, ns).into()
+        }
+        Expression::StructLiteral {
+            ty, values: fields, ..
+        } => {
             let struct_ty = bin.llvm_type(ty, ns);
 
             let s = bin
@@ -79,7 +89,7 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
                 .unwrap()
                 .into_pointer_value();
 
-            for (i, expr) in exprs.iter().enumerate() {
+            for (i, expr) in fields.iter().enumerate() {
                 let elemptr = unsafe {
                     bin.builder.build_gep(
                         struct_ty,
@@ -107,7 +117,7 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
 
             s.into()
         }
-        Expression::BytesLiteral(_, _, bs) => {
+        Expression::BytesLiteral { value: bs, .. } => {
             let ty = bin.context.custom_width_int_type((bs.len() * 8) as u32);
 
             // hex"11223344" should become i32 0x11223344
@@ -117,12 +127,19 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
                 .unwrap()
                 .into()
         }
-        Expression::Add(loc, _, unchecked, l, r) => {
-            let left = expression(target, bin, l, vartab, function, ns).into_int_value();
-            let right = expression(target, bin, r, vartab, function, ns).into_int_value();
+        Expression::Add {
+            loc,
+            ty,
+            overflowing: unchecked,
+            left,
+            right,
+            ..
+        } => {
+            let left = expression(target, bin, left, vartab, function, ns).into_int_value();
+            let right = expression(target, bin, right, vartab, function, ns).into_int_value();
 
             if !unchecked {
-                let signed = l.ty().is_signed_int(ns);
+                let signed = ty.is_signed_int(ns);
                 build_binary_op_with_overflow_check(
                     target,
                     bin,
@@ -139,12 +156,18 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
                 bin.builder.build_int_add(left, right, "").into()
             }
         }
-        Expression::Subtract(loc, _, unchecked, l, r) => {
-            let left = expression(target, bin, l, vartab, function, ns).into_int_value();
-            let right = expression(target, bin, r, vartab, function, ns).into_int_value();
+        Expression::Subtract {
+            loc,
+            ty,
+            overflowing: unchecked,
+            left,
+            right,
+        } => {
+            let left = expression(target, bin, left, vartab, function, ns).into_int_value();
+            let right = expression(target, bin, right, vartab, function, ns).into_int_value();
 
             if !unchecked {
-                let signed = l.ty().is_signed_int(ns);
+                let signed = ty.is_signed_int(ns);
                 build_binary_op_with_overflow_check(
                     target,
                     bin,
@@ -161,9 +184,15 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
                 bin.builder.build_int_sub(left, right, "").into()
             }
         }
-        Expression::Multiply(loc, res_ty, unchecked, l, r) => {
-            let left = expression(target, bin, l, vartab, function, ns).into_int_value();
-            let right = expression(target, bin, r, vartab, function, ns).into_int_value();
+        Expression::Multiply {
+            loc,
+            ty: res_ty,
+            overflowing: unchecked,
+            left,
+            right,
+        } => {
+            let left = expression(target, bin, left, vartab, function, ns).into_int_value();
+            let right = expression(target, bin, right, vartab, function, ns).into_int_value();
 
             multiply(
                 target,
@@ -178,9 +207,11 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
             )
             .into()
         }
-        Expression::UnsignedDivide(loc, _, l, r) => {
-            let left = expression(target, bin, l, vartab, function, ns).into_int_value();
-            let right = expression(target, bin, r, vartab, function, ns).into_int_value();
+        Expression::UnsignedDivide {
+            loc, left, right, ..
+        } => {
+            let left = expression(target, bin, left, vartab, function, ns).into_int_value();
+            let right = expression(target, bin, right, vartab, function, ns).into_int_value();
 
             let bits = left.get_type().get_bit_width();
 
@@ -273,9 +304,11 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
                 bin.builder.build_int_unsigned_div(left, right, "").into()
             }
         }
-        Expression::SignedDivide(loc, _, l, r) => {
-            let left = expression(target, bin, l, vartab, function, ns).into_int_value();
-            let right = expression(target, bin, r, vartab, function, ns).into_int_value();
+        Expression::SignedDivide {
+            loc, left, right, ..
+        } => {
+            let left = expression(target, bin, left, vartab, function, ns).into_int_value();
+            let right = expression(target, bin, right, vartab, function, ns).into_int_value();
 
             let bits = left.get_type().get_bit_width();
 
@@ -416,9 +449,11 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
                 bin.builder.build_int_signed_div(left, right, "").into()
             }
         }
-        Expression::UnsignedModulo(loc, _, l, r) => {
-            let left = expression(target, bin, l, vartab, function, ns).into_int_value();
-            let right = expression(target, bin, r, vartab, function, ns).into_int_value();
+        Expression::UnsignedModulo {
+            loc, left, right, ..
+        } => {
+            let left = expression(target, bin, left, vartab, function, ns).into_int_value();
+            let right = expression(target, bin, right, vartab, function, ns).into_int_value();
 
             let bits = left.get_type().get_bit_width();
 
@@ -508,9 +543,11 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
                 bin.builder.build_int_unsigned_rem(left, right, "").into()
             }
         }
-        Expression::SignedModulo(loc, _, l, r) => {
-            let left = expression(target, bin, l, vartab, function, ns).into_int_value();
-            let right = expression(target, bin, r, vartab, function, ns).into_int_value();
+        Expression::SignedModulo {
+            loc, left, right, ..
+        } => {
+            let left = expression(target, bin, left, vartab, function, ns).into_int_value();
+            let right = expression(target, bin, right, vartab, function, ns).into_int_value();
 
             let bits = left.get_type().get_bit_width();
 
@@ -642,7 +679,13 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
                 bin.builder.build_int_signed_rem(left, right, "").into()
             }
         }
-        Expression::Power(loc, res_ty, unchecked, l, r) => {
+        Expression::Power {
+            loc,
+            ty: res_ty,
+            overflowing: unchecked,
+            base: l,
+            exp: r,
+        } => {
             let left = expression(target, bin, l, vartab, function, ns);
             let right = expression(target, bin, r, vartab, function, ns);
 
@@ -704,11 +747,11 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
                 res
             }
         }
-        Expression::Equal(_, l, r) => {
-            if l.ty().is_address() {
+        Expression::Equal { left, right, .. } => {
+            if left.ty().is_address() {
                 let mut res = bin.context.bool_type().const_int(1, false);
-                let left = expression(target, bin, l, vartab, function, ns).into_array_value();
-                let right = expression(target, bin, r, vartab, function, ns).into_array_value();
+                let left = expression(target, bin, left, vartab, function, ns).into_array_value();
+                let right = expression(target, bin, right, vartab, function, ns).into_array_value();
 
                 // TODO: Address should be passed around as pointer. Once this is done, we can replace
                 // this with a call to address_equal()
@@ -733,17 +776,17 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
 
                 res.into()
             } else {
-                let left = expression(target, bin, l, vartab, function, ns).into_int_value();
-                let right = expression(target, bin, r, vartab, function, ns).into_int_value();
+                let left = expression(target, bin, left, vartab, function, ns).into_int_value();
+                let right = expression(target, bin, right, vartab, function, ns).into_int_value();
 
                 bin.builder
                     .build_int_compare(IntPredicate::EQ, left, right, "")
                     .into()
             }
         }
-        Expression::NotEqual(_, l, r) => {
-            let left = expression(target, bin, l, vartab, function, ns).into_int_value();
-            let right = expression(target, bin, r, vartab, function, ns).into_int_value();
+        Expression::NotEqual { left, right, .. } => {
+            let left = expression(target, bin, left, vartab, function, ns).into_int_value();
+            let right = expression(target, bin, right, vartab, function, ns).into_int_value();
 
             bin.builder
                 .build_int_compare(IntPredicate::NE, left, right, "")
@@ -893,8 +936,8 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
                     .into()
             }
         }
-        Expression::Variable(_, _, s) => vartab[s].value,
-        Expression::GetRef(_, _, expr) => {
+        Expression::Variable { var_no, .. } => vartab[var_no].value,
+        Expression::GetRef { expr, .. } => {
             let address = expression(target, bin, expr, vartab, function, ns).into_array_value();
 
             let stack = bin.build_alloca(function, address.get_type(), "address");
@@ -903,8 +946,8 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
 
             stack.into()
         }
-        Expression::Load(_, ty, e) => {
-            let ptr = expression(target, bin, e, vartab, function, ns).into_pointer_value();
+        Expression::Load { ty, expr, .. } => {
+            let ptr = expression(target, bin, expr, vartab, function, ns).into_pointer_value();
 
             if ty.is_reference_type(ns) && !ty.is_fixed_reference_type(ns) {
                 let loaded_type = bin.llvm_type(ty, ns).ptr_type(AddressSpace::default());
@@ -930,7 +973,7 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
                 bin.builder.position_at_end(allocate);
 
                 // allocate a new struct
-                let ty = e.ty();
+                let ty = expr.ty();
 
                 let llvm_ty = bin.llvm_type(ty.deref_memory(), ns);
 
@@ -971,44 +1014,49 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
             }
         }
 
-        Expression::ZeroExt(_, t, e) => {
-            let e = expression(target, bin, e, vartab, function, ns).into_int_value();
-            let ty = bin.llvm_type(t, ns);
+        Expression::ZeroExt { ty, expr, .. } => {
+            let e = expression(target, bin, expr, vartab, function, ns).into_int_value();
+            let ty = bin.llvm_type(ty, ns);
 
             bin.builder
                 .build_int_z_extend(e, ty.into_int_type(), "")
                 .into()
         }
-        Expression::Negate(_, _, e) => {
-            let e = expression(target, bin, e, vartab, function, ns).into_int_value();
+        Expression::Negate { expr, .. } => {
+            let e = expression(target, bin, expr, vartab, function, ns).into_int_value();
 
             bin.builder.build_int_neg(e, "").into()
         }
-        Expression::SignExt(_, t, e) => {
-            let e = expression(target, bin, e, vartab, function, ns).into_int_value();
-            let ty = bin.llvm_type(t, ns);
+        Expression::SignExt { ty, expr, .. } => {
+            let e = expression(target, bin, expr, vartab, function, ns).into_int_value();
+            let ty = bin.llvm_type(ty, ns);
 
             bin.builder
                 .build_int_s_extend(e, ty.into_int_type(), "")
                 .into()
         }
-        Expression::Trunc(_, t, e) => {
-            let e = expression(target, bin, e, vartab, function, ns).into_int_value();
-            let ty = bin.llvm_type(t, ns);
+        Expression::Trunc { ty, expr, .. } => {
+            let e = expression(target, bin, expr, vartab, function, ns).into_int_value();
+            let ty = bin.llvm_type(ty, ns);
 
             bin.builder
                 .build_int_truncate(e, ty.into_int_type(), "")
                 .into()
         }
-        Expression::Cast(_, to, e) => {
-            let from = e.ty();
+        Expression::Cast { ty: to, expr, .. } => {
+            let from = expr.ty();
 
-            let e = expression(target, bin, e, vartab, function, ns);
+            let e = expression(target, bin, expr, vartab, function, ns);
 
             runtime_cast(bin, function, &from, to, e, ns)
         }
-        Expression::BytesCast(_, Type::DynamicBytes, Type::Bytes(_), e) => {
-            let e = expression(target, bin, e, vartab, function, ns).into_int_value();
+        Expression::BytesCast {
+            ty: Type::DynamicBytes,
+            from: Type::Bytes(_),
+            expr,
+            ..
+        } => {
+            let e = expression(target, bin, expr, vartab, function, ns).into_int_value();
 
             let size = e.get_type().get_bit_width() / 8;
             let size = bin.context.i32_type().const_int(size as u64, false);
@@ -1034,7 +1082,12 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
                 .left()
                 .unwrap()
         }
-        Expression::BytesCast(loc, Type::Bytes(n), Type::DynamicBytes, e) => {
+        Expression::BytesCast {
+            loc,
+            ty: Type::Bytes(n),
+            from: Type::DynamicBytes,
+            expr: e,
+        } => {
             let array = expression(target, bin, e, vartab, function, ns);
 
             let len = bin.vector_len(array);
@@ -1076,67 +1129,78 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
             );
             bin.builder.build_load(ty, le_bytes_ptr, "bytes")
         }
-        Expression::Not(_, e) => {
-            let e = expression(target, bin, e, vartab, function, ns).into_int_value();
+        Expression::Not { expr, .. } => {
+            let e = expression(target, bin, expr, vartab, function, ns).into_int_value();
 
             bin.builder
                 .build_int_compare(IntPredicate::EQ, e, e.get_type().const_zero(), "")
                 .into()
         }
-        Expression::BitwiseNot(_, _, e) => {
-            let e = expression(target, bin, e, vartab, function, ns).into_int_value();
+        Expression::BitwiseNot { expr, .. } => {
+            let e = expression(target, bin, expr, vartab, function, ns).into_int_value();
 
             bin.builder.build_not(e, "").into()
         }
-        Expression::BitwiseOr(_, _, l, r) => {
-            let left = expression(target, bin, l, vartab, function, ns).into_int_value();
+        Expression::BitwiseOr { left, right: r, .. } => {
+            let left = expression(target, bin, left, vartab, function, ns).into_int_value();
             let right = expression(target, bin, r, vartab, function, ns).into_int_value();
 
             bin.builder.build_or(left, right, "").into()
         }
-        Expression::BitwiseAnd(_, _, l, r) => {
-            let left = expression(target, bin, l, vartab, function, ns).into_int_value();
-            let right = expression(target, bin, r, vartab, function, ns).into_int_value();
+        Expression::BitwiseAnd { left, right, .. } => {
+            let left = expression(target, bin, left, vartab, function, ns).into_int_value();
+            let right = expression(target, bin, right, vartab, function, ns).into_int_value();
 
             bin.builder.build_and(left, right, "").into()
         }
-        Expression::BitwiseXor(_, _, l, r) => {
-            let left = expression(target, bin, l, vartab, function, ns).into_int_value();
-            let right = expression(target, bin, r, vartab, function, ns).into_int_value();
+        Expression::BitwiseXor { left, right, .. } => {
+            let left = expression(target, bin, left, vartab, function, ns).into_int_value();
+            let right = expression(target, bin, right, vartab, function, ns).into_int_value();
 
             bin.builder.build_xor(left, right, "").into()
         }
-        Expression::ShiftLeft(_, _, l, r) => {
-            let left = expression(target, bin, l, vartab, function, ns).into_int_value();
-            let right = expression(target, bin, r, vartab, function, ns).into_int_value();
+        Expression::ShiftLeft { left, right, .. } => {
+            let left = expression(target, bin, left, vartab, function, ns).into_int_value();
+            let right = expression(target, bin, right, vartab, function, ns).into_int_value();
 
             bin.builder.build_left_shift(left, right, "").into()
         }
-        Expression::ShiftRight(_, _, l, r, signed) => {
-            let left = expression(target, bin, l, vartab, function, ns).into_int_value();
-            let right = expression(target, bin, r, vartab, function, ns).into_int_value();
+        Expression::ShiftRight {
+            left,
+            right,
+            signed,
+            ..
+        } => {
+            let left = expression(target, bin, left, vartab, function, ns).into_int_value();
+            let right = expression(target, bin, right, vartab, function, ns).into_int_value();
 
             bin.builder
                 .build_right_shift(left, right, *signed, "")
                 .into()
         }
-        Expression::Subscript(loc, elem_ty, ty, a, i) => {
+        Expression::Subscript {
+            loc,
+            ty: elem_ty,
+            array_ty: ty,
+            expr: a,
+            index,
+        } => {
             if ty.is_storage_bytes() {
-                let index = expression(target, bin, i, vartab, function, ns).into_int_value();
+                let index = expression(target, bin, index, vartab, function, ns).into_int_value();
                 let slot = expression(target, bin, a, vartab, function, ns).into_int_value();
                 target
                     .get_storage_bytes_subscript(bin, function, slot, index, *loc, ns)
                     .into()
             } else if ty.is_contract_storage() {
                 let array = expression(target, bin, a, vartab, function, ns).into_int_value();
-                let index = expression(target, bin, i, vartab, function, ns);
+                let index = expression(target, bin, index, vartab, function, ns);
 
                 target
                     .storage_subscript(bin, function, ty, array, index, ns)
                     .into()
             } else if elem_ty.is_builtin_struct() == Some(StructType::AccountInfo) {
                 let array = expression(target, bin, a, vartab, function, ns).into_pointer_value();
-                let index = expression(target, bin, i, vartab, function, ns).into_int_value();
+                let index = expression(target, bin, index, vartab, function, ns).into_int_value();
 
                 let llvm_ty = bin.module.get_struct_type("struct.SolAccountInfo").unwrap();
                 unsafe {
@@ -1148,7 +1212,7 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
                 let array = expression(target, bin, a, vartab, function, ns);
 
                 let mut array_index =
-                    expression(target, bin, i, vartab, function, ns).into_int_value();
+                    expression(target, bin, index, vartab, function, ns).into_int_value();
 
                 // bounds checking already done; we can down-cast if necessary
                 if array_index.get_type().get_bit_width() > 32 {
@@ -1179,7 +1243,7 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
                 .into()
             } else {
                 let array = expression(target, bin, a, vartab, function, ns).into_pointer_value();
-                let index = expression(target, bin, i, vartab, function, ns).into_int_value();
+                let index = expression(target, bin, index, vartab, function, ns).into_int_value();
 
                 let llvm_ty = bin.llvm_type(ty.deref_memory(), ns);
                 unsafe {
@@ -1194,25 +1258,28 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
                 }
             }
         }
-        Expression::StructMember(_, _, a, _)
-            if a.ty().is_builtin_struct() == Some(StructType::AccountInfo) =>
+        Expression::StructMember { expr, .. }
+            if expr.ty().is_builtin_struct() == Some(StructType::AccountInfo) =>
         {
             target.builtin(bin, e, vartab, function, ns)
         }
-        Expression::StructMember(_, _, a, i) => {
-            let struct_ty = bin.llvm_type(a.ty().deref_memory(), ns);
-            let struct_ptr = expression(target, bin, a, vartab, function, ns).into_pointer_value();
+        Expression::StructMember { expr, member, .. } => {
+            let struct_ty = bin.llvm_type(expr.ty().deref_memory(), ns);
+            let struct_ptr =
+                expression(target, bin, expr, vartab, function, ns).into_pointer_value();
 
             bin.builder
-                .build_struct_gep(struct_ty, struct_ptr, *i as u32, "struct member")
+                .build_struct_gep(struct_ty, struct_ptr, *member as u32, "struct member")
                 .unwrap()
                 .into()
         }
-        Expression::ConstArrayLiteral(_, _, dims, exprs) => {
+        Expression::ConstArrayLiteral {
+            dimensions, values, ..
+        } => {
             // For const arrays (declared with "constant" keyword, we should create a global constant
-            let mut dims = dims.iter();
+            let mut dims = dimensions.iter();
 
-            let exprs = exprs
+            let exprs = values
                 .iter()
                 .map(|e| expression(target, bin, e, vartab, function, ns).into_int_value())
                 .collect::<Vec<IntValue>>();
@@ -1252,7 +1319,12 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
 
             gv.as_pointer_value().into()
         }
-        Expression::ArrayLiteral(_, ty, dims, exprs) => {
+        Expression::ArrayLiteral {
+            ty,
+            dimensions,
+            values,
+            ..
+        } => {
             // non-const array literals should alloca'ed and each element assigned
             let ty = bin.llvm_type(ty, ns);
 
@@ -1270,12 +1342,12 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
                 .left()
                 .unwrap();
 
-            for (i, expr) in exprs.iter().enumerate() {
+            for (i, expr) in values.iter().enumerate() {
                 let mut ind = vec![bin.context.i32_type().const_zero()];
 
                 let mut e = i as u32;
 
-                for d in dims {
+                for d in dimensions {
                     ind.insert(1, bin.context.i32_type().const_int((e % *d).into(), false));
 
                     e /= *d;
@@ -1301,9 +1373,14 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
 
             p
         }
-        Expression::AllocDynamicBytes(_, ty, size, init) => {
+        Expression::AllocDynamicBytes {
+            ty,
+            size,
+            initializer,
+            ..
+        } => {
             if matches!(ty, Type::Slice(_)) {
-                let init = init.as_ref().unwrap();
+                let init = initializer.as_ref().unwrap();
 
                 let data = bin.emit_global_string("const_string", init, true);
 
@@ -1331,17 +1408,24 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
                     .unwrap()
                     .const_cast(bin.context.i32_type(), false);
 
-                bin.vector_new(size, elem_size, init.as_ref()).into()
+                bin.vector_new(size, elem_size, initializer.as_ref()).into()
             }
         }
-        Expression::Builtin(_, _, Builtin::ArrayLength, args)
-            if args[0].ty().array_deref().is_builtin_struct().is_none() =>
-        {
+        Expression::Builtin {
+            kind: Builtin::ArrayLength,
+            args,
+            ..
+        } if args[0].ty().array_deref().is_builtin_struct().is_none() => {
             let array = expression(target, bin, &args[0], vartab, function, ns);
 
             bin.vector_len(array).into()
         }
-        Expression::Builtin(_, returns, Builtin::ReadFromBuffer, args) => {
+        Expression::Builtin {
+            tys: returns,
+            kind: Builtin::ReadFromBuffer,
+            args,
+            ..
+        } => {
             let v = expression(target, bin, &args[0], vartab, function, ns);
             let offset = expression(target, bin, &args[1], vartab, function, ns).into_int_value();
 
@@ -1377,7 +1461,7 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
                     .build_load(bin.llvm_type(&returns[0], ns), start, "value")
             }
         }
-        Expression::Keccak256(_, _, exprs) => {
+        Expression::Keccak256 { exprs, .. } => {
             let mut length = bin.context.i32_type().const_zero();
             let mut values: Vec<(BasicValueEnum, IntValue, Type)> = Vec::new();
 
@@ -1437,9 +1521,9 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
 
             bin.builder.build_load(dst_type, dst, "keccak256_hash")
         }
-        Expression::StringCompare(_, l, r) => {
-            let (left, left_len) = string_location(target, bin, l, vartab, function, ns);
-            let (right, right_len) = string_location(target, bin, r, vartab, function, ns);
+        Expression::StringCompare { left, right, .. } => {
+            let (left, left_len) = string_location(target, bin, left, vartab, function, ns);
+            let (right, right_len) = string_location(target, bin, right, vartab, function, ns);
 
             bin.builder
                 .build_call(
@@ -1451,9 +1535,9 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
                 .left()
                 .unwrap()
         }
-        Expression::StringConcat(_, _, l, r) => {
-            let (left, left_len) = string_location(target, bin, l, vartab, function, ns);
-            let (right, right_len) = string_location(target, bin, r, vartab, function, ns);
+        Expression::StringConcat { left, right, .. } => {
+            let (left, left_len) = string_location(target, bin, left, vartab, function, ns);
+            let (right, right_len) = string_location(target, bin, right, vartab, function, ns);
 
             bin.builder
                 .build_call(
@@ -1465,7 +1549,7 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
                 .left()
                 .unwrap()
         }
-        Expression::ReturnData(_) => target.return_data(bin, function).into(),
+        Expression::ReturnData { .. } => target.return_data(bin, function).into(),
         Expression::StorageArrayLength { array, elem_ty, .. } => {
             let slot = expression(target, bin, array, vartab, function, ns).into_int_value();
 
@@ -1473,7 +1557,10 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
                 .storage_array_length(bin, function, slot, elem_ty, ns)
                 .into()
         }
-        Expression::Builtin(_, _, Builtin::Signature, _) if ns.target != Target::Solana => {
+        Expression::Builtin {
+            kind: Builtin::Signature,
+            ..
+        } if ns.target != Target::Solana => {
             // need to byte-reverse selector
             let selector_type = bin.context.i32_type();
             let selector = bin.build_alloca(function, selector_type, "selector");
@@ -1491,7 +1578,11 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
 
             bin.builder.build_load(selector_type, selector, "selector")
         }
-        Expression::Builtin(_, _, Builtin::AddMod, args) => {
+        Expression::Builtin {
+            kind: Builtin::AddMod,
+            args,
+            ..
+        } => {
             let arith_ty = bin.context.custom_width_int_type(512);
             let res_ty = bin.context.custom_width_int_type(256);
 
@@ -1567,7 +1658,11 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
                 .build_int_truncate(remainder, res_ty, "quotient")
                 .into()
         }
-        Expression::Builtin(_, _, Builtin::MulMod, args) => {
+        Expression::Builtin {
+            kind: Builtin::MulMod,
+            args,
+            ..
+        } => {
             let arith_ty = bin.context.custom_width_int_type(512);
             let res_ty = bin.context.custom_width_int_type(256);
 
@@ -1659,11 +1754,31 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
                 .build_int_truncate(remainder, res_ty, "quotient")
                 .into()
         }
-        Expression::Builtin(_, _, hash @ Builtin::Ripemd160, args)
-        | Expression::Builtin(_, _, hash @ Builtin::Keccak256, args)
-        | Expression::Builtin(_, _, hash @ Builtin::Blake2_128, args)
-        | Expression::Builtin(_, _, hash @ Builtin::Blake2_256, args)
-        | Expression::Builtin(_, _, hash @ Builtin::Sha256, args) => {
+        Expression::Builtin {
+            kind: hash @ Builtin::Ripemd160,
+            args,
+            ..
+        }
+        | Expression::Builtin {
+            kind: hash @ Builtin::Keccak256,
+            args,
+            ..
+        }
+        | Expression::Builtin {
+            kind: hash @ Builtin::Blake2_128,
+            args,
+            ..
+        }
+        | Expression::Builtin {
+            kind: hash @ Builtin::Blake2_256,
+            args,
+            ..
+        }
+        | Expression::Builtin {
+            kind: hash @ Builtin::Sha256,
+            args,
+            ..
+        } => {
             let v = expression(target, bin, &args[0], vartab, function, ns);
 
             let hash = match hash {
@@ -1686,12 +1801,14 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
                 )
                 .into()
         }
-        Expression::Builtin(..) => target.builtin(bin, e, vartab, function, ns),
-        Expression::InternalFunctionCfg(cfg_no) => bin.functions[cfg_no]
+        Expression::Builtin { .. } => target.builtin(bin, e, vartab, function, ns),
+        Expression::InternalFunctionCfg { cfg_no } => bin.functions[cfg_no]
             .as_global_value()
             .as_pointer_value()
             .into(),
-        Expression::FormatString(_, args) => format_string(target, bin, args, vartab, function, ns),
+        Expression::FormatString { args: fields, .. } => {
+            format_string(target, bin, fields, vartab, function, ns)
+        }
 
         Expression::AdvancePointer {
             pointer,
@@ -1712,11 +1829,11 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
             advanced.into()
         }
 
-        Expression::RationalNumberLiteral(..)
-        | Expression::List(..)
-        | Expression::Undefined(..)
+        Expression::RationalNumberLiteral { .. }
+        | Expression::List { .. }
+        | Expression::Undefined { .. }
         | Expression::Poison
-        | Expression::BytesCast(..) => {
+        | Expression::BytesCast { .. } => {
             unreachable!("should not exist in cfg")
         }
     }

+ 7 - 7
src/emit/instructions.rs

@@ -48,7 +48,7 @@ pub(super) fn process_instruction<'a, T: TargetRuntime<'a> + ?Sized>(
                 .build_return(Some(&bin.return_values[&ReturnCode::Success]));
         }
         Instr::Set { res, expr, .. } => {
-            if let Expression::Undefined(expr_type) = expr {
+            if let Expression::Undefined { ty: expr_type } = expr {
                 // If the variable has been declared as undefined, but we can
                 // initialize it with a default value
                 if let Some(default_expr) = expr_type.default(ns) {
@@ -703,12 +703,12 @@ pub(super) fn process_instruction<'a, T: TargetRuntime<'a> + ?Sized>(
                     "seeds",
                 );
 
-                if let Expression::ArrayLiteral(_, _, _, exprs) = seeds {
+                if let Expression::ArrayLiteral { values, .. } = seeds {
                     for i in 0..len {
                         let val =
-                            expression(target, bin, &exprs[i as usize], &w.vars, function, ns);
+                            expression(target, bin, &values[i as usize], &w.vars, function, ns);
 
-                        let seed_count = exprs[i as usize]
+                        let seed_count = values[i as usize]
                             .ty()
                             .deref_memory()
                             .array_length()
@@ -859,12 +859,12 @@ pub(super) fn process_instruction<'a, T: TargetRuntime<'a> + ?Sized>(
                     "seeds",
                 );
 
-                if let Expression::ArrayLiteral(_, _, _, exprs) = seeds {
+                if let Expression::ArrayLiteral { values, .. } = seeds {
                     for i in 0..len {
                         let val =
-                            expression(target, bin, &exprs[i as usize], &w.vars, function, ns);
+                            expression(target, bin, &values[i as usize], &w.vars, function, ns);
 
-                        let seed_count = exprs[i as usize]
+                        let seed_count = values[i as usize]
                             .ty()
                             .deref_any()
                             .array_length()

+ 4 - 4
src/emit/math.rs

@@ -395,7 +395,7 @@ pub(super) fn multiply<'a, T: TargetRuntime<'a> + ?Sized>(
 pub(super) fn power<'a, T: TargetRuntime<'a> + ?Sized>(
     target: &T,
     bin: &Binary<'a>,
-    unchecked: bool,
+    overflowing: bool,
     bits: u32,
     signed: bool,
     o: PointerValue<'a>,
@@ -422,7 +422,7 @@ pub(super) fn power<'a, T: TargetRuntime<'a> + ?Sized>(
         "__{}power{}{}",
         if signed { 's' } else { 'u' },
         bits,
-        if unchecked { "unchecked" } else { "" }
+        if overflowing { "overflowing" } else { "" }
     );
     let ty = bin.context.custom_width_int_type(bits);
 
@@ -477,7 +477,7 @@ pub(super) fn power<'a, T: TargetRuntime<'a> + ?Sized>(
         target,
         bin,
         function,
-        unchecked,
+        overflowing,
         result.as_basic_value().into_int_value(),
         base.as_basic_value().into_int_value(),
         signed,
@@ -523,7 +523,7 @@ pub(super) fn power<'a, T: TargetRuntime<'a> + ?Sized>(
         target,
         bin,
         function,
-        unchecked,
+        overflowing,
         base.as_basic_value().into_int_value(),
         base.as_basic_value().into_int_value(),
         signed,

+ 68 - 17
src/emit/solana/target.rs

@@ -1875,7 +1875,13 @@ impl<'a> TargetRuntime<'a> for SolanaTarget {
         ns: &ast::Namespace,
     ) -> BasicValueEnum<'b> {
         match expr {
-            codegen::Expression::Builtin(_, _, codegen::Builtin::Timestamp, _) => {
+            codegen::Expression::Builtin {
+                kind: codegen::Builtin::Timestamp,
+                args,
+                ..
+            } => {
+                assert_eq!(args.len(), 0);
+
                 let parameters = self.sol_parameters(binary);
 
                 let sol_clock = binary.module.get_function("sol_clock").unwrap();
@@ -1901,12 +1907,13 @@ impl<'a> TargetRuntime<'a> for SolanaTarget {
                     .builder
                     .build_load(binary.context.i64_type(), timestamp, "timestamp")
             }
-            codegen::Expression::Builtin(
-                _,
-                _,
-                codegen::Builtin::BlockNumber | codegen::Builtin::Slot,
-                _,
-            ) => {
+            codegen::Expression::Builtin {
+                kind: codegen::Builtin::BlockNumber | codegen::Builtin::Slot,
+                args,
+                ..
+            } => {
+                assert_eq!(args.len(), 0);
+
                 let parameters = self.sol_parameters(binary);
 
                 let sol_clock = binary.module.get_function("sol_clock").unwrap();
@@ -1932,7 +1939,13 @@ impl<'a> TargetRuntime<'a> for SolanaTarget {
                     .builder
                     .build_load(binary.context.i64_type(), slot, "timestamp")
             }
-            codegen::Expression::Builtin(_, _, codegen::Builtin::GetAddress, _) => {
+            codegen::Expression::Builtin {
+                kind: codegen::Builtin::GetAddress,
+                args,
+                ..
+            } => {
+                assert_eq!(args.len(), 0);
+
                 let parameters = self.sol_parameters(binary);
 
                 let key = unsafe {
@@ -1964,7 +1977,13 @@ impl<'a> TargetRuntime<'a> for SolanaTarget {
                     "key",
                 )
             }
-            codegen::Expression::Builtin(_, _, codegen::Builtin::ProgramId, _) => {
+            codegen::Expression::Builtin {
+                kind: codegen::Builtin::ProgramId,
+                args,
+                ..
+            } => {
+                assert_eq!(args.len(), 0);
+
                 let parameters = self.sol_parameters(binary);
 
                 let sol_pubkey_type = binary.module.get_struct_type("struct.SolPubkey").unwrap();
@@ -1992,7 +2011,13 @@ impl<'a> TargetRuntime<'a> for SolanaTarget {
                     .builder
                     .build_load(binary.address_type(ns), account_id, "program_id")
             }
-            codegen::Expression::Builtin(_, _, codegen::Builtin::Calldata, _) => {
+            codegen::Expression::Builtin {
+                kind: codegen::Builtin::Calldata,
+                args,
+                ..
+            } => {
+                assert_eq!(args.len(), 0);
+
                 let sol_params = self.sol_parameters(binary);
 
                 let input = binary
@@ -2056,7 +2081,13 @@ impl<'a> TargetRuntime<'a> for SolanaTarget {
                     .left()
                     .unwrap()
             }
-            codegen::Expression::Builtin(_, _, codegen::Builtin::Signature, _) => {
+            codegen::Expression::Builtin {
+                kind: codegen::Builtin::Signature,
+                args,
+                ..
+            } => {
+                assert_eq!(args.len(), 0);
+
                 let sol_params = self.sol_parameters(binary);
 
                 let input = binary
@@ -2093,7 +2124,11 @@ impl<'a> TargetRuntime<'a> for SolanaTarget {
                     .left()
                     .unwrap()
             }
-            codegen::Expression::Builtin(_, _, codegen::Builtin::SignatureVerify, args) => {
+            codegen::Expression::Builtin {
+                kind: codegen::Builtin::SignatureVerify,
+                args,
+                ..
+            } => {
                 assert_eq!(args.len(), 3);
 
                 let address = binary.build_alloca(function, binary.address_type(ns), "address");
@@ -2135,7 +2170,11 @@ impl<'a> TargetRuntime<'a> for SolanaTarget {
                     )
                     .into()
             }
-            codegen::Expression::Builtin(_, _, codegen::Builtin::Balance, args) => {
+            codegen::Expression::Builtin {
+                kind: codegen::Builtin::Balance,
+                args,
+                ..
+            } => {
                 assert_eq!(args.len(), 1);
 
                 let address = binary.build_alloca(function, binary.address_type(ns), "address");
@@ -2161,7 +2200,13 @@ impl<'a> TargetRuntime<'a> for SolanaTarget {
                     .builder
                     .build_load(binary.context.i64_type(), lamport, "lamport")
             }
-            codegen::Expression::Builtin(_, _, codegen::Builtin::Accounts, _) => {
+            codegen::Expression::Builtin {
+                kind: codegen::Builtin::Accounts,
+                args,
+                ..
+            } => {
+                assert_eq!(args.len(), 0);
+
                 let parameters = self.sol_parameters(binary);
 
                 unsafe {
@@ -2181,7 +2226,13 @@ impl<'a> TargetRuntime<'a> for SolanaTarget {
                 }
                 .into()
             }
-            codegen::Expression::Builtin(_, _, codegen::Builtin::ArrayLength, _) => {
+            codegen::Expression::Builtin {
+                kind: codegen::Builtin::ArrayLength,
+                args,
+                ..
+            } => {
+                assert_eq!(args.len(), 1);
+
                 let parameters = self.sol_parameters(binary);
 
                 let ka_num = binary
@@ -2207,9 +2258,9 @@ impl<'a> TargetRuntime<'a> for SolanaTarget {
                     .build_int_truncate(ka_num, binary.context.i32_type(), "ka_num_32bits")
                     .into()
             }
-            codegen::Expression::StructMember(_, _, a, member) => {
+            codegen::Expression::StructMember { expr, member, .. } => {
                 let account_info =
-                    expression(self, binary, a, vartab, function, ns).into_pointer_value();
+                    expression(self, binary, expr, vartab, function, ns).into_pointer_value();
 
                 self.account_info_member(binary, function, account_info, *member, ns)
             }

+ 5 - 5
src/emit/strings.rs

@@ -27,8 +27,8 @@ pub(super) fn format_string<'a, T: TargetRuntime<'a> + ?Sized>(
 
     for (i, (spec, arg)) in args.iter().enumerate() {
         let len = if *spec == FormatArg::StringLiteral {
-            if let Expression::BytesLiteral(_, _, bs) = arg {
-                bin.context.i32_type().const_int(bs.len() as u64, false)
+            if let Expression::BytesLiteral { value, .. } = arg {
+                bin.context.i32_type().const_int(value.len() as u64, false)
             } else {
                 unreachable!();
             }
@@ -100,9 +100,9 @@ pub(super) fn format_string<'a, T: TargetRuntime<'a> + ?Sized>(
     // format it
     for (i, (spec, arg)) in args.iter().enumerate() {
         if *spec == FormatArg::StringLiteral {
-            if let Expression::BytesLiteral(_, _, bs) = arg {
-                let s = bin.emit_global_string("format_arg", bs, true);
-                let len = bin.context.i32_type().const_int(bs.len() as u64, false);
+            if let Expression::BytesLiteral { value, .. } = arg {
+                let s = bin.emit_global_string("format_arg", value, true);
+                let len = bin.context.i32_type().const_int(value.len() as u64, false);
 
                 bin.builder.build_call(
                     bin.module.get_function("__memcpy").unwrap(),

+ 43 - 14
src/emit/substrate/target.rs

@@ -1333,7 +1333,10 @@ impl<'a> TargetRuntime<'a> for SubstrateTarget {
         }
 
         match expr {
-            codegen::Expression::Builtin(_, _, codegen::Builtin::Calldata, _) => {
+            codegen::Expression::Builtin {
+                kind: codegen::Builtin::Calldata,
+                ..
+            } => {
                 // allocate vector for input
                 let v = call!(
                     "vector_new",
@@ -1382,7 +1385,10 @@ impl<'a> TargetRuntime<'a> for SubstrateTarget {
 
                 v
             }
-            codegen::Expression::Builtin(_, _, codegen::Builtin::BlockNumber, _) => {
+            codegen::Expression::Builtin {
+                kind: codegen::Builtin::BlockNumber,
+                ..
+            } => {
                 let block_number =
                     get_seal_value!("block_number", "seal_block_number", 32).into_int_value();
 
@@ -1396,7 +1402,10 @@ impl<'a> TargetRuntime<'a> for SubstrateTarget {
                     )
                     .into()
             }
-            codegen::Expression::Builtin(_, _, codegen::Builtin::Timestamp, _) => {
+            codegen::Expression::Builtin {
+                kind: codegen::Builtin::Timestamp,
+                ..
+            } => {
                 let milliseconds = get_seal_value!("timestamp", "seal_now", 64).into_int_value();
 
                 // Solidity expects the timestamp in seconds, not milliseconds
@@ -1409,16 +1418,23 @@ impl<'a> TargetRuntime<'a> for SubstrateTarget {
                     )
                     .into()
             }
-            codegen::Expression::Builtin(_, _, codegen::Builtin::Gasleft, _) => {
+            codegen::Expression::Builtin {
+                kind: codegen::Builtin::Gasleft,
+                ..
+            } => {
                 get_seal_value!("gas_left", "seal_gas_left", 64)
             }
-            codegen::Expression::Builtin(_, _, codegen::Builtin::Gasprice, expr) => {
+            codegen::Expression::Builtin {
+                kind: codegen::Builtin::Gasprice,
+                args,
+                ..
+            } => {
                 // 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
-                let gas = if expr.is_empty() {
+                let gas = if args.is_empty() {
                     binary.context.i64_type().const_int(1, false)
                 } else {
-                    expression(self, binary, &expr[0], vartab, function, ns).into_int_value()
+                    expression(self, binary, &args[0], vartab, function, ns).into_int_value()
                 };
 
                 let (scratch_buf, scratch_len) = scratch_buf!();
@@ -1441,7 +1457,10 @@ impl<'a> TargetRuntime<'a> for SubstrateTarget {
                     "price",
                 )
             }
-            codegen::Expression::Builtin(_, _, codegen::Builtin::Sender, _) => {
+            codegen::Expression::Builtin {
+                kind: codegen::Builtin::Sender,
+                ..
+            } => {
                 let (scratch_buf, scratch_len) = scratch_buf!();
 
                 binary
@@ -1458,17 +1477,24 @@ impl<'a> TargetRuntime<'a> for SubstrateTarget {
                     .builder
                     .build_load(binary.address_type(ns), scratch_buf, "caller")
             }
-            codegen::Expression::Builtin(_, _, codegen::Builtin::Value, _) => {
-                self.value_transferred(binary, ns).into()
-            }
-            codegen::Expression::Builtin(_, _, codegen::Builtin::MinimumBalance, _) => {
+            codegen::Expression::Builtin {
+                kind: codegen::Builtin::Value,
+                ..
+            } => self.value_transferred(binary, ns).into(),
+            codegen::Expression::Builtin {
+                kind: codegen::Builtin::MinimumBalance,
+                ..
+            } => {
                 get_seal_value!(
                     "minimum_balance",
                     "seal_minimum_balance",
                     ns.value_length as u32 * 8
                 )
             }
-            codegen::Expression::Builtin(_, _, codegen::Builtin::GetAddress, _) => {
+            codegen::Expression::Builtin {
+                kind: codegen::Builtin::GetAddress,
+                ..
+            } => {
                 let (scratch_buf, scratch_len) = scratch_buf!();
 
                 binary
@@ -1485,7 +1511,10 @@ impl<'a> TargetRuntime<'a> for SubstrateTarget {
                     .builder
                     .build_load(binary.address_type(ns), scratch_buf, "self_address")
             }
-            codegen::Expression::Builtin(_, _, codegen::Builtin::Balance, _) => {
+            codegen::Expression::Builtin {
+                kind: codegen::Builtin::Balance,
+                ..
+            } => {
                 let (scratch_buf, scratch_len) = scratch_buf!();
 
                 binary

+ 2 - 2
src/sema/yul/expression.rs

@@ -620,7 +620,7 @@ fn resolve_suffix_access(
             return Err(());
         }
 
-        YulExpression::BoolLiteral(..)
+        YulExpression::BoolLiteral { .. }
         | YulExpression::NumberLiteral(..)
         | YulExpression::StringLiteral(..)
         | YulExpression::YulLocalVariable(..)
@@ -668,7 +668,7 @@ pub(crate) fn check_type(
 
             YulExpression::StringLiteral(..)
             | YulExpression::NumberLiteral(..)
-            | YulExpression::BoolLiteral(..)
+            | YulExpression::BoolLiteral { .. }
             | YulExpression::ConstantVariable(..) => {
                 return Some(Diagnostic::error(
                     expr.loc(),

+ 1 - 1
src/sema/yul/switch.rs

@@ -202,7 +202,7 @@ fn resolve_case_block(
     match resolved_condition {
         YulExpression::NumberLiteral(..)
         | YulExpression::StringLiteral(..)
-        | YulExpression::BoolLiteral(..) => (),
+        | YulExpression::BoolLiteral { .. } => (),
 
         _ => {
             ns.diagnostics.push(Diagnostic::error(

+ 1 - 1
src/sema/yul/types.rs

@@ -51,7 +51,7 @@ pub(crate) fn verify_type_from_expression(
     function_table: &FunctionsTable,
 ) -> Result<Type, Diagnostic> {
     match expr {
-        YulExpression::BoolLiteral(..) => Ok(Type::Bool),
+        YulExpression::BoolLiteral { .. } => Ok(Type::Bool),
 
         YulExpression::NumberLiteral(_, _, ty)
         | YulExpression::StringLiteral(_, _, ty)

+ 2 - 2
tests/codegen_testcases/solidity/anticipated_expressions.sol

@@ -116,12 +116,12 @@ contract Test {
         int k=0;
         int l=0;
         int m=0;
-        // CHECK: ty:int256 %1.cse_temp = (unchecked (arg #0) * (arg #1))
+        // CHECK: ty:int256 %1.cse_temp = (overflowing (arg #0) * (arg #1))
         // CHECK: block1: # end_switch
 	    // CHECK: ty:int256 %m = %1.cse_temp
 	    // CHECK: return (%l + %1.cse_temp)
         assembly {
-            switch y 
+            switch y
                 case 1 {
                     // CHECK: block2: # case_0
 	                // CHECK: ty:int256 %j = %1.cse_temp

+ 4 - 4
tests/codegen_testcases/solidity/dead_storage.sol

@@ -137,8 +137,8 @@ contract deadstorage {
         return test11var[index] + test11var[index2];
     }
 
-// CHECK: load storage slot((unchecked uint256 8
-// CHECK: load storage slot((unchecked uint256 8
+// CHECK: load storage slot((overflowing uint256 8
+// CHECK: load storage slot((overflowing uint256 8
 
 // BEGIN-CHECK: deadstorage::function::test12
     // one load needed for this
@@ -147,8 +147,8 @@ contract deadstorage {
         return test12var[index] + test12var[index];
 
     }
-// CHECK: load storage slot((unchecked uint256 19
-// NOT-CHECK: load storage slot((unchecked uint256 19
+// CHECK: load storage slot((overflowing uint256 19
+// NOT-CHECK: load storage slot((overflowing uint256 19
 }
 
 contract foo {

+ 4 - 4
tests/codegen_testcases/solidity/unchecked_cse.sol

@@ -7,7 +7,7 @@ contract foo {
 //BEGIN-CHECK: foo::foo::function::mul__int64_int64
     function mul(int64 a, int64 b) public returns (int64) {
         unchecked {
-            // CHECK: ty:int64 storage %temp.14 = (unchecked (arg #0) * (arg #1))
+            // CHECK: ty:int64 storage %temp.14 = (overflowing (arg #0) * (arg #1))
             var = a * b;
         }
 
@@ -18,7 +18,7 @@ contract foo {
 //BEGIN-CHECK: foo::foo::function::add__int64_int64
     function add(int64 a, int64 b) public returns (int64) {
         unchecked {
-            // CHECK: ty:int64 storage %temp.15 = (unchecked (arg #0) + (arg #1))
+            // CHECK: ty:int64 storage %temp.15 = (overflowing (arg #0) + (arg #1))
             var = a + b;
         }
         // CHECK: return ((arg #0) + (arg #1))
@@ -28,7 +28,7 @@ contract foo {
 //BEGIN-CHECK: foo::foo::function::sub__int64_int64
     function sub(int64 a, int64 b) public returns (int64) {
         unchecked {
-            // CHECK: ty:int64 storage %temp.16 = (unchecked (arg #0) - (arg #1))
+            // CHECK: ty:int64 storage %temp.16 = (overflowing (arg #0) - (arg #1))
             var = a - b;
         }
         // CHECK: return ((arg #0) - (arg #1))
@@ -38,7 +38,7 @@ contract foo {
 //BEGIN-CHECK: foo::foo::function::power__uint64_uint64
     function power(uint64 a, uint64 b) public returns (uint64) {
         unchecked {
-            // CHECK: ty:uint64 storage %temp.17 = (unchecked (arg #0) ** (arg #1))
+            // CHECK: ty:uint64 storage %temp.17 = (overflowing (arg #0) ** (arg #1))
             var2 = a ** b;
         }
 

+ 1 - 1
tests/codegen_testcases/solidity/unused_variable_elimination.sol

@@ -115,7 +115,7 @@ return 3;
         it2 = 1;
 
         return 2;
-// CHECK: store storage slot((unchecked %t2 + uint256 0)) ty:int256 =
+// CHECK: store storage slot((overflowing %t2 + uint256 0)) ty:int256 =
 // CHECK: store storage slot(uint256 2) ty:int256 =
 // NOT-CHECK: ty:struct c1.testStruct %t3 = struct { int256 1, int256 2 }
 // NOT-CHECK: alloc int256[] len uint32 5

+ 12 - 12
tests/codegen_testcases/yul/binary_arithmetic_builtins.sol

@@ -4,31 +4,31 @@ contract testing {
 // BEGIN-CHECK: testing::testing::function::add_sub_mul__int16_int32_uint256_uint128
     function add_sub_mul(int16 a, int32 b, uint256 c, uint128 d) public pure {
         assembly {
-            // CHECK: ty:uint256 %e = (sext uint256 (unchecked (sext int32 (arg #0)) + (arg #1)))
+            // CHECK: ty:uint256 %e = (sext uint256 (overflowing (sext int32 (arg #0)) + (arg #1)))
             let e := add(a, b)
 
-            // CHECK: ty:uint256 %f = uint256((unchecked (sext int256 (arg #1)) + int256((arg #2))))
+            // CHECK: ty:uint256 %f = uint256((overflowing (sext int256 (arg #1)) + int256((arg #2))))
             let f := add(b, c)
 
-            // CHECK: ty:uint256 %g = (unchecked (arg #2) + (zext uint256 (arg #3)))
+            // CHECK: ty:uint256 %g = (overflowing (arg #2) + (zext uint256 (arg #3)))
             let g := add(c, d)
 
-            // CHECK: ty:uint256 %h = (sext uint256 (unchecked (sext int136 (arg #0)) + (zext int136 (arg #3))))
+            // CHECK: ty:uint256 %h = (sext uint256 (overflowing (sext int136 (arg #0)) + (zext int136 (arg #3))))
             let h := add(a, d)
 
-            // CHECK: ty:uint256 %i = uint256((unchecked (sext int256 (arg #0)) + int256((arg #2))))
+            // CHECK: ty:uint256 %i = uint256((overflowing (sext int256 (arg #0)) + int256((arg #2))))
             let i := add(a, c)
 
-            // CHECK: ty:uint256 %j = (sext uint256 (unchecked (sext int136 (arg #1)) + (zext int136 (arg #3))))
+            // CHECK: ty:uint256 %j = (sext uint256 (overflowing (sext int136 (arg #1)) + (zext int136 (arg #3))))
             let j := add(b, d)
 
-            // CHECK: ty:int32 %k = (unchecked (sext int32 (arg #0)) - (arg #1))
+            // CHECK: ty:int32 %k = (overflowing (sext int32 (arg #0)) - (arg #1))
             let k : s32 := sub(a, b)
 
-            // CHECK: ty:int256 %l = int256((unchecked (arg #2) - (zext uint256 (arg #3))))
+            // CHECK: ty:int256 %l = int256((overflowing (arg #2) - (zext uint256 (arg #3))))
             let l : s256 := sub(c, d)
 
-            // CHECK: ty:uint256 %m = (unchecked (arg #2) * (zext uint256 (arg #3)))
+            // CHECK: ty:uint256 %m = (overflowing (arg #2) * (zext uint256 (arg #3)))
             let m := mul(c, d)
 
             // CHECK: ty:uint256 %n = uint256 43981
@@ -49,13 +49,13 @@ contract testing {
             // CHECK: ty:bool %s = true
             let s : bool := true
 
-            // CHECK: ty:uint256 %t = (unchecked uint256 22193982385802470 + uint256(false))
+            // CHECK: ty:uint256 %t = (overflowing uint256 22193982385802470 + uint256(false))
             let t := add(q, r)
 
             // CHECK: ty:uint256 %u = uint256 -1
             let u := sub(false, true)
 
-            // CHECK: ty:uint256 %v = uint256((unchecked true + false))
+            // CHECK: ty:uint256 %v = uint256((overflowing true + false))
             let v := add(s, r)
         }
     }
@@ -117,7 +117,7 @@ contract testing {
 // BEGIN-CHECK: testing::testing::function::exponential__int128_int8
     function exponential(int128 a, int8 b) public pure {
         assembly {
-            // CHECK: ty:uint256 %x = (sext uint256 (unchecked (arg #0) ** (sext int128 (arg #1))))
+            // CHECK: ty:uint256 %x = (sext uint256 (overflowing (arg #0) ** (sext int128 (arg #1))))
             let x := exp(a, b)
         }
     }

+ 1 - 1
tests/codegen_testcases/yul/cse_switch.sol

@@ -25,7 +25,7 @@ contract foo {
                 }
 
             // CHECK: block1: # end_switch
-	        // CHECK: ty:uint256 %1.cse_temp = (unchecked %x + %y)
+	        // CHECK: ty:uint256 %1.cse_temp = (overflowing %x + %y)
 	        // CHECK: branchcond (%1.cse_temp == uint256 90), block5, block6
             if eq(add(x, y), 90) {
                 yy := 9

+ 5 - 5
tests/codegen_testcases/yul/expression.sol

@@ -58,10 +58,10 @@ contract testing {
 // BEGIN-CHECK: testing::testing::function::yulLocalVariable__uint256
     function yulLocalVariable(uint256 a) public pure {
         assembly {
-            // CHECK: ty:uint256 %x = (unchecked uint256 2 + (arg #0))
+            // CHECK: ty:uint256 %x = (overflowing uint256 2 + (arg #0))
             let x := add(2, a)
 
-            // CHECK: ty:uint256 %y = (unchecked uint256 2 + (arg #0))
+            // CHECK: ty:uint256 %y = (overflowing uint256 2 + (arg #0))
             let y := x
         }
     }
@@ -166,14 +166,14 @@ contract testing {
                 let y := 9
             }
 
-            // CHECK: ty:int32 %k = (trunc int32 (unchecked (zext uint256 (arg #0)) + uint256 2))
+            // CHECK: ty:int32 %k = (trunc int32 (overflowing (zext uint256 (arg #0)) + uint256 2))
             let k : s32 := add(a, 2)
 
-            // CHECK: %ret.temp.58 = call testing::yul_function_0::get (sext uint256 (trunc int32 (unchecked (zext uint256 (arg #0)) + uint256 2)))
+            // CHECK: %ret.temp.58 = call testing::yul_function_0::get (sext uint256 (trunc int32 (overflowing (zext uint256 (arg #0)) + uint256 2)))
             let x := get(k)
             // CHECK: ty:uint256 %x = %ret.temp.58
 
-            // CHECK: %ret1.temp.59, %ret2.temp.60 = call testing::yul_function_2::multipleReturns %x, (trunc int32 (unchecked (zext uint256 (arg #0)) + uint256 2))
+            // CHECK: %ret1.temp.59, %ret2.temp.60 = call testing::yul_function_2::multipleReturns %x, (trunc int32 (overflowing (zext uint256 (arg #0)) + uint256 2))
             let l, m := multipleReturns(x, k)
             // CHECK: ty:uint256 %l = (zext uint256 %ret1.temp.59)
             // CHECK: ty:uint256 %m = (sext uint256 %ret2.temp.60)

+ 2 - 2
tests/codegen_testcases/yul/functions.sol

@@ -13,7 +13,7 @@ contract testing {
                 if lt(x, 2) {
                     // CHECK: block1: # then
                     x := sub(a, b)
-                    // CHECK: ty:uint256 %x = (unchecked (arg #0) - (arg #1))
+                    // CHECK: ty:uint256 %x = (overflowing (arg #0) - (arg #1))
                     leave
                     // CHECK: return
                 }
@@ -30,7 +30,7 @@ contract testing {
                 if lt(a, 2) {
                     // CHECK: block1: # then
                     ret1 := add(sub(a,b), mul(shr(a, 2), 3))
-                    // CHECK: ty:uint256 %ret1 = uint256((unchecked (unchecked int256((arg #0)) - (sext int256 (arg #1))) + int256((unchecked (uint256 2 >> (arg #0)) * uint256 3))))
+                    // CHECK: ty:uint256 %ret1 = uint256((overflowing (overflowing int256((arg #0)) - (sext int256 (arg #1))) + int256((overflowing (uint256 2 >> (arg #0)) * uint256 3))))
                     leave
                     // CHECK: return %ret1
                 }

+ 21 - 21
tests/codegen_testcases/yul/statements.sol

@@ -26,10 +26,10 @@ contract testing {
             // CHECK: ty:uint256 %x = (sext uint256 ((sext int24 (arg #1)) >> (zext int24 (arg #0))))
             let x := shr(a, b)
             {
-                // CHECK: ty:uint256 %y = (unchecked (sext uint256 ((sext int24 (arg #1)) >> (zext int24 (arg #0)))) * (zext uint256 (arg #0)))
+                // CHECK: ty:uint256 %y = (overflowing (sext uint256 ((sext int24 (arg #1)) >> (zext int24 (arg #0)))) * (zext uint256 (arg #0)))
                 let y := mul(x, a)
 
-                // CHECK: ty:uint8 %g = uint8((unsigned less int256((unchecked (sext uint256 ((sext int24 (arg #1)) >> (zext int24 (arg #0)))) * (zext uint256 (arg #0)))) < (sext int256 (arg #1))))
+                // CHECK: ty:uint8 %g = uint8((unsigned less int256((overflowing (sext uint256 ((sext int24 (arg #1)) >> (zext int24 (arg #0)))) * (zext uint256 (arg #0)))) < (sext int256 (arg #1))))
                 let g : u8 := lt(y, b)
             }
         }
@@ -74,7 +74,7 @@ contract testing {
             // CHECK: branchcond (arg #0), block1, block2
             if a {
             // CHECK: block1: # then
-            // CHECK: ty:uint256 %x = (unchecked uint256((arg #0)) + uint256 5)
+            // CHECK: ty:uint256 %x = (overflowing uint256((arg #0)) + uint256 5)
                 x := add(a, x)
 
                 // CHECK: ty:bool %a = false
@@ -135,10 +135,10 @@ contract testing {
                 let i := 1
             // CHECK: branch block1
             // CHECK: block1: # cond
-            // CHECK: branchcond (uint256 0 != (unchecked %i + uint256 1)), block3, block4
+            // CHECK: branchcond (uint256 0 != (overflowing %i + uint256 1)), block3, block4
             } add(i, 1) {
                 // CHECK: block2: # next
-                // CHECK: ty:uint256 %i = (unchecked %i - uint256 1)
+                // CHECK: ty:uint256 %i = (overflowing %i - uint256 1)
                 i := sub(i, 1)
                 // CHECK: branch block1
             } {
@@ -158,7 +158,7 @@ contract testing {
             } lt(i, 10) {
                 // CHECK: block6: # next
                 i := add(i, 1)
-                // CHECK: ty:uint256 %i.27 = (unchecked %i.27 + uint256 1)
+                // CHECK: ty:uint256 %i.27 = (overflowing %i.27 + uint256 1)
                 // CHECK: branch block5
             } {
                 // CHECK: block7: # body
@@ -176,13 +176,13 @@ contract testing {
                 // CHECK: branchcond %a, block11, block12
             } a {
                 // CHECK: block10: # next
-                // CHECK: ty:uint256 %i.28 = (unchecked uint256(%a) + uint256 1)
+                // CHECK: ty:uint256 %i.28 = (overflowing uint256(%a) + uint256 1)
                 i := add(a, 1)
                 // CHECK: ty:bool %a = false
                 a := false
             } {
                 // CHECK: block11: # body
-                // CHECK: ty:bool %a = (uint256 0 != (unchecked %i.28 + uint256 2))
+                // CHECK: ty:bool %a = (uint256 0 != (overflowing %i.28 + uint256 2))
                 a := add(i, 2)
                 // CHECK: branch block10
             }
@@ -236,7 +236,7 @@ contract testing {
             } lt(i, 10) {
                 // CHECK: block22: # next
                 i := add(i, 1)
-                // CHECK: ty:uint256 %i.31 = (unchecked %i.31 + uint256 1)
+                // CHECK: ty:uint256 %i.31 = (overflowing %i.31 + uint256 1)
                 // CHECK: branch block21
             } {
                 // CHECK: block23: # body
@@ -253,12 +253,12 @@ contract testing {
                     // CHECK: block25: # cond
                     // CHECK: branchcond (unsigned less %j.32 < uint256 10), block27, block28
                 } lt(j, 10) {
-                    // CHECK: ty:uint256 %j.32 = (unchecked %j.32 + uint256 1)
+                    // CHECK: ty:uint256 %j.32 = (overflowing %j.32 + uint256 1)
                     j := add(j, 1)
                     // CHECK: branch block25
                 } {
                     // CHECK: block27: # body
-                    // CHECK: ty:bool %a = (uint256 0 != (unchecked %i.31 + %j.32))
+                    // CHECK: ty:bool %a = (uint256 0 != (overflowing %i.31 + %j.32))
                     a := add(i, j)
                     // CHECK: branch block26
                 }
@@ -288,7 +288,7 @@ contract testing {
             // CHECK: branchcond (unsigned less %i < uint256 10), block3, block4
             } lt(i, 10) {i := add(i, 1)
             // CHECK: block2: # next
-            // CHECK: ty:uint256 %i = (unchecked %i + uint256 1)
+            // CHECK: ty:uint256 %i = (overflowing %i + uint256 1)
             // CHECK: branch block1
             } {
                 // CHECK: block3: # body
@@ -323,7 +323,7 @@ contract testing {
             } lt(i, 10) {
                 // CHECK: block2: # next
                 i := add(i, 1)
-                // CHECK: ty:uint256 %i = (unchecked %i + uint256 1)
+                // CHECK: ty:uint256 %i = (overflowing %i + uint256 1)
                 // CHECK: branch block1
             } {
                 for {
@@ -340,7 +340,7 @@ contract testing {
                     // CHECK: block5: # cond
                     // CHECK: branchcond (unsigned less %j < uint256 10), block7, block8
                     // CHECK: block6: # next
-                    // CHECK: ty:uint256 %j = (unchecked %j + uint256 1)
+                    // CHECK: ty:uint256 %j = (overflowing %j + uint256 1)
                     // CHECK: branch block5
                     j := add(j, 1)
                 } {
@@ -359,7 +359,7 @@ contract testing {
 
                     // After inner if:
                     // CHECK: block10: # endif
-                    // CHECK: ty:uint256 %j = (unchecked %i - uint256 2)
+                    // CHECK: ty:uint256 %j = (overflowing %i - uint256 2)
                     j := sub(i, 2)
                     // CHECK: branch block6
                 }
@@ -369,7 +369,7 @@ contract testing {
                     // CHECK: branch block4
                 }
                 // CHECK: block12: # endif
-                // CHECK: ty:uint256 %i = (unchecked %i - uint256 4)
+                // CHECK: ty:uint256 %i = (overflowing %i - uint256 4)
                 i := sub(i, 4)
                 // CHECK: branch block2
             }
@@ -386,7 +386,7 @@ contract testing {
             // CHECK: branchcond (unsigned less %i < uint256 10), block3, block4
             } lt(i, 10) {i := add(i, 1)
             // CHECK: block2: # next
-            // CHECK: ty:uint256 %i = (unchecked %i + uint256 1)
+            // CHECK: ty:uint256 %i = (overflowing %i + uint256 1)
             // CHECK: branch block1
             } {
                 // CHECK: block3: # body
@@ -421,7 +421,7 @@ contract testing {
             } lt(i, 10) {
                 // CHECK: block2: # next
                 i := add(i, 1)
-                // CHECK: ty:uint256 %i = (unchecked %i + uint256 1)
+                // CHECK: ty:uint256 %i = (overflowing %i + uint256 1)
                 // CHECK: branch block1
             } {
                 for {
@@ -438,7 +438,7 @@ contract testing {
                     // CHECK: block5: # cond
                     // CHECK: branchcond (unsigned less %j < uint256 10), block7, block8
                     // CHECK: block6: # next
-                    // CHECK: ty:uint256 %j = (unchecked %j + uint256 1)
+                    // CHECK: ty:uint256 %j = (overflowing %j + uint256 1)
                     // CHECK: branch block5
                     j := add(j, 1)
                 } {
@@ -457,7 +457,7 @@ contract testing {
 
                     // After inner if:
                     // CHECK: block10: # endif
-                    // CHECK: ty:uint256 %j = (unchecked %i - uint256 2)
+                    // CHECK: ty:uint256 %j = (overflowing %i - uint256 2)
                     j := sub(i, 2)
                     // CHECK: branch block6
                 }
@@ -467,7 +467,7 @@ contract testing {
                     // CHECK: branch block2
                 }
                 // CHECK: block12: # endif
-                // CHECK: ty:uint256 %i = (unchecked %i - uint256 4)
+                // CHECK: ty:uint256 %i = (overflowing %i - uint256 4)
                 i := sub(i, 4)
                 // CHECK: branch block2
             }

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است