Ver Fonte

Move LoopScopes into ExprContext (#1596)

This simplifies the code, and makes it to use ExprContext for other
purposes (for example variable scoping).

Signed-off-by: Sean Young <sean@mess.org>
Sean Young há 2 anos atrás
pai
commit
592bd911db

+ 1 - 0
Cargo.toml

@@ -66,6 +66,7 @@ contract-build = { version = "3.0.1", optional = true }
 primitive-types = { version = "0.12", features = ["codec"] }
 primitive-types = { version = "0.12", features = ["codec"] }
 normalize-path = "0.2.1"
 normalize-path = "0.2.1"
 bitflags = "2.3.3"
 bitflags = "2.3.3"
+scopeguard = "1.2.0"
 forge-fmt = { version = "0.2.0", optional = true }
 forge-fmt = { version = "0.2.0", optional = true }
 # We don't use ethers-core directly, but need the correct version for the
 # We don't use ethers-core directly, but need the correct version for the
 # build to work.
 # build to work.

+ 3 - 3
src/sema/builtin.rs

@@ -943,7 +943,7 @@ pub(super) fn resolve_call(
     namespace: Option<&str>,
     namespace: Option<&str>,
     id: &str,
     id: &str,
     args: &[pt::Expression],
     args: &[pt::Expression],
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -1061,7 +1061,7 @@ pub(super) fn resolve_namespace_call(
     namespace: &str,
     namespace: &str,
     name: &str,
     name: &str,
     args: &[pt::Expression],
     args: &[pt::Expression],
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -1402,7 +1402,7 @@ pub(super) fn resolve_method_call(
     expr: &Expression,
     expr: &Expression,
     id: &pt::Identifier,
     id: &pt::Identifier,
     args: &[pt::Expression],
     args: &[pt::Expression],
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,

+ 2 - 3
src/sema/contracts.rs

@@ -200,7 +200,7 @@ fn resolve_base_args(contracts: &[ContractDefinition], file_no: usize, ns: &mut
 
 
     // for every contract, if we have a base which resolved successfully, resolve any constructor args
     // for every contract, if we have a base which resolved successfully, resolve any constructor args
     for contract in contracts {
     for contract in contracts {
-        let context = ExprContext {
+        let mut context = ExprContext {
             file_no,
             file_no,
             contract_no: Some(contract.contract_no),
             contract_no: Some(contract.contract_no),
             ..Default::default()
             ..Default::default()
@@ -223,7 +223,7 @@ fn resolve_base_args(contracts: &[ContractDefinition], file_no: usize, ns: &mut
                             &base.loc,
                             &base.loc,
                             args,
                             args,
                             base_no,
                             base_no,
-                            &context,
+                            &mut context,
                             ns,
                             ns,
                             &mut symtable,
                             &mut symtable,
                             &mut diagnostics,
                             &mut diagnostics,
@@ -235,7 +235,6 @@ fn resolve_base_args(contracts: &[ContractDefinition], file_no: usize, ns: &mut
                 }
                 }
             }
             }
         }
         }
-        context.drop();
     }
     }
 
 
     ns.diagnostics.extend(diagnostics);
     ns.diagnostics.extend(diagnostics);

+ 34 - 23
src/sema/expression/arithmetic.rs

@@ -16,7 +16,7 @@ pub(super) fn subtract(
     loc: &pt::Loc,
     loc: &pt::Loc,
     l: &pt::Expression,
     l: &pt::Expression,
     r: &pt::Expression,
     r: &pt::Expression,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -79,7 +79,7 @@ pub(super) fn bitwise_or(
     loc: &pt::Loc,
     loc: &pt::Loc,
     l: &pt::Expression,
     l: &pt::Expression,
     r: &pt::Expression,
     r: &pt::Expression,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -123,7 +123,7 @@ pub(super) fn bitwise_and(
     loc: &pt::Loc,
     loc: &pt::Loc,
     l: &pt::Expression,
     l: &pt::Expression,
     r: &pt::Expression,
     r: &pt::Expression,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -167,7 +167,7 @@ pub(super) fn bitwise_xor(
     loc: &pt::Loc,
     loc: &pt::Loc,
     l: &pt::Expression,
     l: &pt::Expression,
     r: &pt::Expression,
     r: &pt::Expression,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -211,7 +211,7 @@ pub(super) fn shift_left(
     loc: &pt::Loc,
     loc: &pt::Loc,
     l: &pt::Expression,
     l: &pt::Expression,
     r: &pt::Expression,
     r: &pt::Expression,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -240,7 +240,7 @@ pub(super) fn shift_right(
     loc: &pt::Loc,
     loc: &pt::Loc,
     l: &pt::Expression,
     l: &pt::Expression,
     r: &pt::Expression,
     r: &pt::Expression,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -270,7 +270,7 @@ pub(super) fn multiply(
     loc: &pt::Loc,
     loc: &pt::Loc,
     l: &pt::Expression,
     l: &pt::Expression,
     r: &pt::Expression,
     r: &pt::Expression,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -362,7 +362,7 @@ pub(super) fn divide(
     loc: &pt::Loc,
     loc: &pt::Loc,
     l: &pt::Expression,
     l: &pt::Expression,
     r: &pt::Expression,
     r: &pt::Expression,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -406,7 +406,7 @@ pub(super) fn modulo(
     loc: &pt::Loc,
     loc: &pt::Loc,
     l: &pt::Expression,
     l: &pt::Expression,
     r: &pt::Expression,
     r: &pt::Expression,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -450,7 +450,7 @@ pub(super) fn power(
     loc: &pt::Loc,
     loc: &pt::Loc,
     b: &pt::Expression,
     b: &pt::Expression,
     e: &pt::Expression,
     e: &pt::Expression,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -523,7 +523,7 @@ pub(super) fn equal(
     loc: &pt::Loc,
     loc: &pt::Loc,
     l: &pt::Expression,
     l: &pt::Expression,
     r: &pt::Expression,
     r: &pt::Expression,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -585,7 +585,7 @@ pub(super) fn not_equal(
     loc: &pt::Loc,
     loc: &pt::Loc,
     l: &pt::Expression,
     l: &pt::Expression,
     r: &pt::Expression,
     r: &pt::Expression,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -726,7 +726,7 @@ pub(super) fn addition(
     loc: &pt::Loc,
     loc: &pt::Loc,
     l: &pt::Expression,
     l: &pt::Expression,
     r: &pt::Expression,
     r: &pt::Expression,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -839,46 +839,57 @@ pub(super) fn addition(
 pub(super) fn incr_decr(
 pub(super) fn incr_decr(
     v: &pt::Expression,
     v: &pt::Expression,
     expr: &pt::Expression,
     expr: &pt::Expression,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
 ) -> Result<Expression, ()> {
 ) -> Result<Expression, ()> {
+    let prev_lvalue = context.lvalue;
+    context.lvalue = true;
+
+    let mut context = scopeguard::guard(context, |context| {
+        context.lvalue = prev_lvalue;
+    });
+    let unchecked = context.unchecked;
+
     let op = |e: Expression, ty: Type| -> Expression {
     let op = |e: Expression, ty: Type| -> Expression {
         match expr {
         match expr {
             pt::Expression::PreIncrement(loc, _) => Expression::PreIncrement {
             pt::Expression::PreIncrement(loc, _) => Expression::PreIncrement {
                 loc: *loc,
                 loc: *loc,
                 ty,
                 ty,
-                unchecked: context.unchecked,
+                unchecked,
                 expr: Box::new(e),
                 expr: Box::new(e),
             },
             },
             pt::Expression::PreDecrement(loc, _) => Expression::PreDecrement {
             pt::Expression::PreDecrement(loc, _) => Expression::PreDecrement {
                 loc: *loc,
                 loc: *loc,
                 ty,
                 ty,
-                unchecked: context.unchecked,
+                unchecked,
                 expr: Box::new(e),
                 expr: Box::new(e),
             },
             },
             pt::Expression::PostIncrement(loc, _) => Expression::PostIncrement {
             pt::Expression::PostIncrement(loc, _) => Expression::PostIncrement {
                 loc: *loc,
                 loc: *loc,
                 ty,
                 ty,
-                unchecked: context.unchecked,
+                unchecked,
                 expr: Box::new(e),
                 expr: Box::new(e),
             },
             },
             pt::Expression::PostDecrement(loc, _) => Expression::PostDecrement {
             pt::Expression::PostDecrement(loc, _) => Expression::PostDecrement {
                 loc: *loc,
                 loc: *loc,
                 ty,
                 ty,
-                unchecked: context.unchecked,
+                unchecked,
                 expr: Box::new(e),
                 expr: Box::new(e),
             },
             },
             _ => unreachable!(),
             _ => unreachable!(),
         }
         }
     };
     };
 
 
-    let mut context = context.clone();
-
-    context.lvalue = true;
-
-    let var = expression(v, &context, ns, symtable, diagnostics, ResolveTo::Unknown)?;
+    let var = expression(
+        v,
+        &mut context,
+        ns,
+        symtable,
+        diagnostics,
+        ResolveTo::Unknown,
+    )?;
     used_variable(ns, &var, symtable);
     used_variable(ns, &var, symtable);
     let var_ty = var.ty();
     let var_ty = var.ty();
 
 

+ 20 - 10
src/sema/expression/assign.rs

@@ -16,17 +16,21 @@ pub(super) fn assign_single(
     loc: &pt::Loc,
     loc: &pt::Loc,
     left: &pt::Expression,
     left: &pt::Expression,
     right: &pt::Expression,
     right: &pt::Expression,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
 ) -> Result<Expression, ()> {
 ) -> Result<Expression, ()> {
-    let mut lcontext = context.clone();
-    lcontext.lvalue = true;
+    let prev_lvalue = context.lvalue;
+    context.lvalue = true;
+
+    let mut context = scopeguard::guard(context, |context| {
+        context.lvalue = prev_lvalue;
+    });
 
 
     let var = expression(
     let var = expression(
         left,
         left,
-        &lcontext,
+        &mut context,
         ns,
         ns,
         symtable,
         symtable,
         diagnostics,
         diagnostics,
@@ -34,10 +38,11 @@ pub(super) fn assign_single(
     )?;
     )?;
     assigned_variable(ns, &var, symtable);
     assigned_variable(ns, &var, symtable);
 
 
+    context.lvalue = false;
     let var_ty = var.ty();
     let var_ty = var.ty();
     let val = expression(
     let val = expression(
         right,
         right,
-        context,
+        &mut context,
         ns,
         ns,
         symtable,
         symtable,
         diagnostics,
         diagnostics,
@@ -170,17 +175,21 @@ pub(super) fn assign_expr(
     left: &pt::Expression,
     left: &pt::Expression,
     expr: &pt::Expression,
     expr: &pt::Expression,
     right: &pt::Expression,
     right: &pt::Expression,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
 ) -> Result<Expression, ()> {
 ) -> Result<Expression, ()> {
-    let mut lcontext = context.clone();
-    lcontext.lvalue = true;
+    let prev_lvalue = context.lvalue;
+    context.lvalue = true;
+
+    let mut context = scopeguard::guard(context, |context| {
+        context.lvalue = prev_lvalue;
+    });
 
 
     let var = expression(
     let var = expression(
         left,
         left,
-        &lcontext,
+        &mut context,
         ns,
         ns,
         symtable,
         symtable,
         diagnostics,
         diagnostics,
@@ -198,7 +207,8 @@ pub(super) fn assign_expr(
         ResolveTo::Type(var_ty.deref_any().deref_any())
         ResolveTo::Type(var_ty.deref_any().deref_any())
     };
     };
 
 
-    let set = expression(right, context, ns, symtable, diagnostics, resolve_to)?;
+    context.lvalue = false;
+    let set = expression(right, &mut context, ns, symtable, diagnostics, resolve_to)?;
     used_variable(ns, &set, symtable);
     used_variable(ns, &set, symtable);
     let set_type = set.ty();
     let set_type = set.ty();
 
 

+ 6 - 6
src/sema/expression/constructor.rs

@@ -19,7 +19,7 @@ fn constructor(
     no: usize,
     no: usize,
     args: &[pt::Expression],
     args: &[pt::Expression],
     call_args: CallArgs,
     call_args: CallArgs,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -93,7 +93,7 @@ pub fn match_constructor_to_args(
     loc: &pt::Loc,
     loc: &pt::Loc,
     args: &[pt::Expression],
     args: &[pt::Expression],
     contract_no: usize,
     contract_no: usize,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -205,7 +205,7 @@ pub fn constructor_named_args(
     loc: &pt::Loc,
     loc: &pt::Loc,
     ty: &pt::Expression,
     ty: &pt::Expression,
     args: &[pt::NamedArgument],
     args: &[pt::NamedArgument],
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -434,7 +434,7 @@ pub fn new(
     loc: &pt::Loc,
     loc: &pt::Loc,
     ty: &pt::Expression,
     ty: &pt::Expression,
     args: &[pt::Expression],
     args: &[pt::Expression],
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -606,7 +606,7 @@ pub(super) fn solana_constructor_check(
     loc: &pt::Loc,
     loc: &pt::Loc,
     constructor_contract_no: usize,
     constructor_contract_no: usize,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
-    context: &ExprContext,
+    context: &mut ExprContext,
     call_args: &CallArgs,
     call_args: &CallArgs,
     ns: &mut Namespace,
     ns: &mut Namespace,
 ) {
 ) {
@@ -646,7 +646,7 @@ pub(super) fn solana_constructor_check(
         ));
         ));
     }
     }
 
 
-    if !context.in_a_loop() || !call_args.accounts.is_absent() {
+    if !context.loops.in_a_loop() || !call_args.accounts.is_absent() {
         return;
         return;
     }
     }
 
 

+ 19 - 19
src/sema/expression/function_call.rs

@@ -32,7 +32,7 @@ pub(super) fn call_function_type(
     args: &[pt::Expression],
     args: &[pt::Expression],
     call_args: &[&pt::NamedArgument],
     call_args: &[&pt::NamedArgument],
     call_args_loc: Option<pt::Loc>,
     call_args_loc: Option<pt::Loc>,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -254,7 +254,7 @@ pub fn function_call_pos_args(
     args: &[pt::Expression],
     args: &[pt::Expression],
     function_nos: Vec<usize>,
     function_nos: Vec<usize>,
     virtual_call: bool,
     virtual_call: bool,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     resolve_to: ResolveTo,
     resolve_to: ResolveTo,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
@@ -365,7 +365,7 @@ pub(super) fn function_call_named_args(
     args: &[pt::NamedArgument],
     args: &[pt::NamedArgument],
     function_nos: Vec<usize>,
     function_nos: Vec<usize>,
     virtual_call: bool,
     virtual_call: bool,
-    context: &ExprContext,
+    context: &mut ExprContext,
     resolve_to: ResolveTo,
     resolve_to: ResolveTo,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
@@ -514,7 +514,7 @@ fn try_namespace(
     args: &[pt::Expression],
     args: &[pt::Expression],
     call_args: &[&pt::NamedArgument],
     call_args: &[&pt::NamedArgument],
     call_args_loc: Option<pt::Loc>,
     call_args_loc: Option<pt::Loc>,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -711,7 +711,7 @@ fn try_storage_reference(
     var_expr: &Expression,
     var_expr: &Expression,
     func: &pt::Identifier,
     func: &pt::Identifier,
     args: &[pt::Expression],
     args: &[pt::Expression],
-    context: &ExprContext,
+    context: &mut ExprContext,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
     call_args_loc: Option<pt::Loc>,
     call_args_loc: Option<pt::Loc>,
     ns: &mut Namespace,
     ns: &mut Namespace,
@@ -934,7 +934,7 @@ fn try_user_type(
     func: &pt::Identifier,
     func: &pt::Identifier,
     args: &[pt::Expression],
     args: &[pt::Expression],
     call_args_loc: Option<pt::Loc>,
     call_args_loc: Option<pt::Loc>,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -1023,7 +1023,7 @@ fn try_type_method(
     args: &[pt::Expression],
     args: &[pt::Expression],
     call_args: &[&pt::NamedArgument],
     call_args: &[&pt::NamedArgument],
     call_args_loc: Option<pt::Loc>,
     call_args_loc: Option<pt::Loc>,
-    context: &ExprContext,
+    context: &mut ExprContext,
     var_expr: &Expression,
     var_expr: &Expression,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
@@ -1339,7 +1339,7 @@ pub(super) fn method_call_pos_args(
     args: &[pt::Expression],
     args: &[pt::Expression],
     call_args: &[&pt::NamedArgument],
     call_args: &[&pt::NamedArgument],
     call_args_loc: Option<pt::Loc>,
     call_args_loc: Option<pt::Loc>,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -1531,7 +1531,7 @@ pub(super) fn method_call_named_args(
     args: &[pt::NamedArgument],
     args: &[pt::NamedArgument],
     call_args: &[&pt::NamedArgument],
     call_args: &[&pt::NamedArgument],
     call_args_loc: Option<pt::Loc>,
     call_args_loc: Option<pt::Loc>,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -1812,7 +1812,7 @@ pub(super) fn parse_call_args(
     call_args: &[&pt::NamedArgument],
     call_args: &[&pt::NamedArgument],
     callee_contract: Option<usize>,
     callee_contract: Option<usize>,
     external_call: bool,
     external_call: bool,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -2124,7 +2124,7 @@ pub fn named_call_expr(
     ty: &pt::Expression,
     ty: &pt::Expression,
     args: &[pt::NamedArgument],
     args: &[pt::NamedArgument],
     is_destructible: bool,
     is_destructible: bool,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -2201,7 +2201,7 @@ pub fn call_expr(
     ty: &pt::Expression,
     ty: &pt::Expression,
     args: &[pt::Expression],
     args: &[pt::Expression],
     is_destructible: bool,
     is_destructible: bool,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -2291,7 +2291,7 @@ pub fn function_call_expr(
     loc: &pt::Loc,
     loc: &pt::Loc,
     ty: &pt::Expression,
     ty: &pt::Expression,
     args: &[pt::Expression],
     args: &[pt::Expression],
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -2416,7 +2416,7 @@ pub fn named_function_call_expr(
     loc: &pt::Loc,
     loc: &pt::Loc,
     ty: &pt::Expression,
     ty: &pt::Expression,
     args: &[pt::NamedArgument],
     args: &[pt::NamedArgument],
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -2516,7 +2516,7 @@ pub(crate) fn function_type(func: &Function, external: bool, resolve_to: Resolve
 /// named arguments.
 /// named arguments.
 fn evaluate_argument(
 fn evaluate_argument(
     arg: &pt::Expression,
     arg: &pt::Expression,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     arg_ty: &Type,
     arg_ty: &Type,
@@ -2535,7 +2535,7 @@ fn resolve_internal_call(
     loc: &Loc,
     loc: &Loc,
     id: &pt::IdentifierPath,
     id: &pt::IdentifierPath,
     function_no: usize,
     function_no: usize,
-    context: &ExprContext,
+    context: &mut ExprContext,
     resolve_to: ResolveTo,
     resolve_to: ResolveTo,
     virtual_call: bool,
     virtual_call: bool,
     cast_args: Vec<Expression>,
     cast_args: Vec<Expression>,
@@ -2604,7 +2604,7 @@ fn contract_call_named_args(
     args: &[pt::NamedArgument],
     args: &[pt::NamedArgument],
     call_args: &[&pt::NamedArgument],
     call_args: &[&pt::NamedArgument],
     external_contract_no: usize,
     external_contract_no: usize,
-    context: &ExprContext,
+    context: &mut ExprContext,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     ns: &mut Namespace,
     ns: &mut Namespace,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -2780,7 +2780,7 @@ fn contract_call_pos_args(
     var_expr: Option<&Expression>,
     var_expr: Option<&Expression>,
     args: &[pt::Expression],
     args: &[pt::Expression],
     call_args: &[&pt::NamedArgument],
     call_args: &[&pt::NamedArgument],
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -2948,7 +2948,7 @@ fn preprocess_contract_call<T>(
     external_contract_no: usize,
     external_contract_no: usize,
     func: &pt::Identifier,
     func: &pt::Identifier,
     args: &[T],
     args: &[T],
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,

+ 3 - 3
src/sema/expression/literals.rs

@@ -461,7 +461,7 @@ pub(super) fn struct_literal(
     id: pt::IdentifierPath,
     id: pt::IdentifierPath,
     struct_ty: &StructType,
     struct_ty: &StructType,
     args: &[pt::Expression],
     args: &[pt::Expression],
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -571,7 +571,7 @@ pub(super) fn named_struct_literal(
     id: pt::IdentifierPath,
     id: pt::IdentifierPath,
     str_ty: &StructType,
     str_ty: &StructType,
     args: &[pt::NamedArgument],
     args: &[pt::NamedArgument],
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -654,7 +654,7 @@ pub(super) fn named_struct_literal(
 pub(super) fn array_literal(
 pub(super) fn array_literal(
     loc: &pt::Loc,
     loc: &pt::Loc,
     exprs: &[pt::Expression],
     exprs: &[pt::Expression],
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,

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

@@ -27,7 +27,7 @@ pub(super) fn member_access(
     loc: &pt::Loc,
     loc: &pt::Loc,
     e: &pt::Expression,
     e: &pt::Expression,
     id: &pt::Identifier,
     id: &pt::Identifier,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -726,7 +726,7 @@ fn type_name_expr(
     loc: &pt::Loc,
     loc: &pt::Loc,
     args: &[pt::Expression],
     args: &[pt::Expression],
     field: &pt::Identifier,
     field: &pt::Identifier,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
     resolve_to: ResolveTo,
     resolve_to: ResolveTo,

+ 4 - 22
src/sema/expression/mod.rs

@@ -19,7 +19,7 @@ use super::diagnostics::Diagnostics;
 use super::eval::eval_const_rational;
 use super::eval::eval_const_rational;
 use crate::sema::contracts::is_base;
 use crate::sema::contracts::is_base;
 use crate::sema::eval::eval_const_number;
 use crate::sema::eval::eval_const_number;
-use crate::sema::using::user_defined_operator_binding;
+use crate::sema::{symtable::LoopScopes, using::user_defined_operator_binding};
 use num_bigint::{BigInt, Sign};
 use num_bigint::{BigInt, Sign};
 use num_rational::BigRational;
 use num_rational::BigRational;
 use num_traits::{FromPrimitive, ToPrimitive, Zero};
 use num_traits::{FromPrimitive, ToPrimitive, Zero};
@@ -50,7 +50,7 @@ pub enum ResolveTo<'a> {
     Type(&'a Type), // We will be wanting this type please, e.g. `int64 x = 1;`
     Type(&'a Type), // We will be wanting this type please, e.g. `int64 x = 1;`
 }
 }
 
 
-#[derive(Clone, Default)]
+#[derive(Default)]
 pub struct ExprContext {
 pub struct ExprContext {
     /// What source file are we in
     /// What source file are we in
     pub file_no: usize,
     pub file_no: usize,
@@ -66,26 +66,8 @@ pub struct ExprContext {
     pub lvalue: bool,
     pub lvalue: bool,
     /// Are we resolving a yul function (it cannot have external dependencies)
     /// Are we resolving a yul function (it cannot have external dependencies)
     pub yul_function: bool,
     pub yul_function: bool,
-    /// How many loops are we in? (i.e how many nested loops de we have?)
-    pub loop_nesting_level: usize,
-}
-
-impl ExprContext {
-    pub fn enter_loop(&mut self) {
-        self.loop_nesting_level += 1;
-    }
-
-    pub fn exit_loop(&mut self) {
-        self.loop_nesting_level -= 1;
-    }
-
-    pub fn in_a_loop(&self) -> bool {
-        self.loop_nesting_level > 0
-    }
-
-    pub fn drop(&self) {
-        assert_eq!(self.loop_nesting_level, 0);
-    }
+    /// Loops nesting
+    pub loops: LoopScopes,
 }
 }
 
 
 impl Expression {
 impl Expression {

+ 7 - 7
src/sema/expression/resolve_expression.rs

@@ -34,7 +34,7 @@ use solang_parser::{diagnostics::Diagnostic, pt, pt::CodeLocation};
 /// type the result should be.
 /// type the result should be.
 pub fn expression(
 pub fn expression(
     expr: &pt::Expression,
     expr: &pt::Expression,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -433,7 +433,7 @@ pub fn expression(
 
 
 fn bitwise_not(
 fn bitwise_not(
     expr: &pt::Expression,
     expr: &pt::Expression,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -472,7 +472,7 @@ fn negate(
     ns: &mut Namespace,
     ns: &mut Namespace,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
     resolve_to: ResolveTo,
     resolve_to: ResolveTo,
-    context: &ExprContext,
+    context: &mut ExprContext,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
 ) -> Result<Expression, ()> {
 ) -> Result<Expression, ()> {
     match expr {
     match expr {
@@ -559,7 +559,7 @@ fn negate(
 fn less_equal(
 fn less_equal(
     l: &pt::Expression,
     l: &pt::Expression,
     r: &pt::Expression,
     r: &pt::Expression,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -613,7 +613,7 @@ fn less_equal(
 fn more_equal(
 fn more_equal(
     l: &pt::Expression,
     l: &pt::Expression,
     r: &pt::Expression,
     r: &pt::Expression,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -667,7 +667,7 @@ fn more_equal(
 fn less(
 fn less(
     l: &pt::Expression,
     l: &pt::Expression,
     r: &pt::Expression,
     r: &pt::Expression,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -722,7 +722,7 @@ fn less(
 fn more(
 fn more(
     l: &pt::Expression,
     l: &pt::Expression,
     r: &pt::Expression,
     r: &pt::Expression,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,

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

@@ -14,7 +14,7 @@ pub(super) fn array_subscript(
     loc: &pt::Loc,
     loc: &pt::Loc,
     array: &pt::Expression,
     array: &pt::Expression,
     index: &pt::Expression,
     index: &pt::Expression,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -144,7 +144,7 @@ fn mapping_subscript(
     loc: &pt::Loc,
     loc: &pt::Loc,
     mapping: Expression,
     mapping: Expression,
     index: &pt::Expression,
     index: &pt::Expression,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,

+ 1 - 1
src/sema/expression/variable.rs

@@ -11,7 +11,7 @@ use solang_parser::pt;
 
 
 pub(super) fn variable(
 pub(super) fn variable(
     id: &pt::Identifier,
     id: &pt::Identifier,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &Namespace,
     ns: &Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,

+ 1 - 1
src/sema/format.rs

@@ -20,7 +20,7 @@ pub fn string_format(
     loc: &pt::Loc,
     loc: &pt::Loc,
     literals: &[pt::StringLiteral],
     literals: &[pt::StringLiteral],
     args: &[pt::Expression],
     args: &[pt::Expression],
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,

+ 2 - 2
src/sema/function_annotation.rs

@@ -195,7 +195,7 @@ pub(super) fn function_body_annotations(
     body_annotations: &[&pt::Annotation],
     body_annotations: &[&pt::Annotation],
     parameter_annotations: &[UnresolvedAnnotation],
     parameter_annotations: &[UnresolvedAnnotation],
     symtable: &mut Symtable,
     symtable: &mut Symtable,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
 ) {
 ) {
     let mut diagnostics = Diagnostics::default();
     let mut diagnostics = Diagnostics::default();
@@ -392,7 +392,7 @@ fn body_annotation(
     resolved_annotation: &mut Option<(pt::Loc, Expression)>,
     resolved_annotation: &mut Option<(pt::Loc, Expression)>,
     annotation: &Annotation,
     annotation: &Annotation,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     has_annotation: &mut bool,
     has_annotation: &mut bool,

+ 3 - 5
src/sema/namespace.rs

@@ -1525,20 +1525,18 @@ impl Namespace {
         diagnostics: &mut Diagnostics,
         diagnostics: &mut Diagnostics,
     ) -> Result<ArrayDimension, ()> {
     ) -> Result<ArrayDimension, ()> {
         let mut symtable = Symtable::new();
         let mut symtable = Symtable::new();
-        let context = ExprContext {
+        let mut context = ExprContext {
             file_no,
             file_no,
             unchecked: true,
             unchecked: true,
             contract_no,
             contract_no,
             function_no,
             function_no,
             constant: true,
             constant: true,
-            lvalue: false,
-            yul_function: false,
-            loop_nesting_level: 0,
+            ..Default::default()
         };
         };
 
 
         let size_expr = expression(
         let size_expr = expression(
             expr,
             expr,
-            &context,
+            &mut context,
             self,
             self,
             &mut symtable,
             &mut symtable,
             diagnostics,
             diagnostics,

+ 58 - 130
src/sema/statements.rs

@@ -7,7 +7,7 @@ use super::expression::{
     function_call::{available_functions, call_expr, named_call_expr},
     function_call::{available_functions, call_expr, named_call_expr},
     ExprContext, ResolveTo,
     ExprContext, ResolveTo,
 };
 };
-use super::symtable::{LoopScopes, Symtable};
+use super::symtable::Symtable;
 use crate::sema::expression::constructor::{
 use crate::sema::expression::constructor::{
     constructor_named_args, match_constructor_to_args, new,
     constructor_named_args, match_constructor_to_args, new,
 };
 };
@@ -39,17 +39,12 @@ pub fn resolve_function_body(
     ns: &mut Namespace,
     ns: &mut Namespace,
 ) -> Result<(), ()> {
 ) -> Result<(), ()> {
     let mut symtable = Symtable::new();
     let mut symtable = Symtable::new();
-    let mut loops = LoopScopes::new();
     let mut res = Vec::new();
     let mut res = Vec::new();
     let mut context = ExprContext {
     let mut context = ExprContext {
         file_no,
         file_no,
         contract_no,
         contract_no,
         function_no: Some(function_no),
         function_no: Some(function_no),
-        unchecked: false,
-        constant: false,
-        lvalue: false,
-        yul_function: false,
-        loop_nesting_level: 0,
+        ..Default::default()
     };
     };
 
 
     let mut unresolved_annotation: Vec<UnresolvedAnnotation> = Vec::new();
     let mut unresolved_annotation: Vec<UnresolvedAnnotation> = Vec::new();
@@ -84,7 +79,7 @@ pub fn resolve_function_body(
         annotations,
         annotations,
         &unresolved_annotation,
         &unresolved_annotation,
         &mut symtable,
         &mut symtable,
-        &context,
+        &mut context,
         ns,
         ns,
     );
     );
 
 
@@ -125,7 +120,7 @@ pub fn resolve_function_body(
                                 &base.loc,
                                 &base.loc,
                                 args,
                                 args,
                                 base_no,
                                 base_no,
-                                &context,
+                                &mut context,
                                 ns,
                                 ns,
                                 &mut symtable,
                                 &mut symtable,
                                 &mut diagnostics,
                                 &mut diagnostics,
@@ -209,7 +204,7 @@ pub fn resolve_function_body(
                             ns,
                             ns,
                         ),
                         ),
                         true,
                         true,
-                        &context,
+                        &mut context,
                         ns,
                         ns,
                         ResolveTo::Unknown,
                         ResolveTo::Unknown,
                         &mut symtable,
                         &mut symtable,
@@ -221,7 +216,6 @@ pub fn resolve_function_body(
             }
             }
         }
         }
 
 
-        context.drop();
         ns.diagnostics.extend(diagnostics);
         ns.diagnostics.extend(diagnostics);
         ns.functions[function_no].modifiers = modifiers;
         ns.functions[function_no].modifiers = modifiers;
     }
     }
@@ -289,7 +283,6 @@ pub fn resolve_function_body(
         &mut res,
         &mut res,
         &mut context,
         &mut context,
         &mut symtable,
         &mut symtable,
-        &mut loops,
         ns,
         ns,
         &mut diagnostics,
         &mut diagnostics,
     );
     );
@@ -346,7 +339,6 @@ fn statement(
     res: &mut Vec<Statement>,
     res: &mut Vec<Statement>,
     context: &mut ExprContext,
     context: &mut ExprContext,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
-    loops: &mut LoopScopes,
     ns: &mut Namespace,
     ns: &mut Namespace,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
 ) -> Result<bool, ()> {
 ) -> Result<bool, ()> {
@@ -425,9 +417,13 @@ fn statement(
             let mut reachable = true;
             let mut reachable = true;
             let mut already_unreachable = false;
             let mut already_unreachable = false;
 
 
-            let mut context = context.clone();
+            let prev_unchecked = context.unchecked;
             context.unchecked |= *unchecked;
             context.unchecked |= *unchecked;
 
 
+            let mut context = scopeguard::guard(context, |context| {
+                context.unchecked = prev_unchecked;
+            });
+
             let mut resolved_stmts = Vec::new();
             let mut resolved_stmts = Vec::new();
 
 
             for stmt in statements {
             for stmt in statements {
@@ -443,7 +439,6 @@ fn statement(
                     &mut resolved_stmts,
                     &mut resolved_stmts,
                     &mut context,
                     &mut context,
                     symtable,
                     symtable,
-                    loops,
                     ns,
                     ns,
                     diagnostics,
                     diagnostics,
                 )?;
                 )?;
@@ -460,7 +455,7 @@ fn statement(
             Ok(reachable)
             Ok(reachable)
         }
         }
         pt::Statement::Break(loc) => {
         pt::Statement::Break(loc) => {
-            if loops.do_break() {
+            if context.loops.do_break() {
                 res.push(Statement::Break(*loc));
                 res.push(Statement::Break(*loc));
                 Ok(false)
                 Ok(false)
             } else {
             } else {
@@ -472,7 +467,7 @@ fn statement(
             }
             }
         }
         }
         pt::Statement::Continue(loc) => {
         pt::Statement::Continue(loc) => {
-            if loops.do_continue() {
+            if context.loops.do_continue() {
                 res.push(Statement::Continue(*loc));
                 res.push(Statement::Continue(*loc));
                 Ok(false)
                 Ok(false)
             } else {
             } else {
@@ -484,7 +479,6 @@ fn statement(
             }
             }
         }
         }
         pt::Statement::While(loc, cond_expr, body) => {
         pt::Statement::While(loc, cond_expr, body) => {
-            context.enter_loop();
             let expr = expression(
             let expr = expression(
                 cond_expr,
                 cond_expr,
                 context,
                 context,
@@ -498,25 +492,15 @@ fn statement(
 
 
             symtable.enter_scope();
             symtable.enter_scope();
             let mut body_stmts = Vec::new();
             let mut body_stmts = Vec::new();
-            loops.enter_scope();
-            statement(
-                body,
-                &mut body_stmts,
-                context,
-                symtable,
-                loops,
-                ns,
-                diagnostics,
-            )?;
+            context.loops.enter_scope();
+            statement(body, &mut body_stmts, context, symtable, ns, diagnostics)?;
             symtable.leave_scope();
             symtable.leave_scope();
-            loops.leave_scope();
+            context.loops.leave_scope();
 
 
             res.push(Statement::While(*loc, true, cond, body_stmts));
             res.push(Statement::While(*loc, true, cond, body_stmts));
-            context.exit_loop();
             Ok(true)
             Ok(true)
         }
         }
         pt::Statement::DoWhile(loc, body, cond_expr) => {
         pt::Statement::DoWhile(loc, body, cond_expr) => {
-            context.enter_loop();
             let expr = expression(
             let expr = expression(
                 cond_expr,
                 cond_expr,
                 context,
                 context,
@@ -530,21 +514,12 @@ fn statement(
 
 
             symtable.enter_scope();
             symtable.enter_scope();
             let mut body_stmts = Vec::new();
             let mut body_stmts = Vec::new();
-            loops.enter_scope();
-            statement(
-                body,
-                &mut body_stmts,
-                context,
-                symtable,
-                loops,
-                ns,
-                diagnostics,
-            )?;
+            context.loops.enter_scope();
+            statement(body, &mut body_stmts, context, symtable, ns, diagnostics)?;
             symtable.leave_scope();
             symtable.leave_scope();
-            loops.leave_scope();
+            context.loops.leave_scope();
 
 
             res.push(Statement::DoWhile(*loc, true, body_stmts, cond));
             res.push(Statement::DoWhile(*loc, true, body_stmts, cond));
-            context.exit_loop();
             Ok(true)
             Ok(true)
         }
         }
         pt::Statement::If(loc, cond_expr, then, else_) => {
         pt::Statement::If(loc, cond_expr, then, else_) => {
@@ -562,29 +537,14 @@ fn statement(
 
 
             symtable.enter_scope();
             symtable.enter_scope();
             let mut then_stmts = Vec::new();
             let mut then_stmts = Vec::new();
-            let mut reachable = statement(
-                then,
-                &mut then_stmts,
-                context,
-                symtable,
-                loops,
-                ns,
-                diagnostics,
-            )?;
+            let mut reachable =
+                statement(then, &mut then_stmts, context, symtable, ns, diagnostics)?;
             symtable.leave_scope();
             symtable.leave_scope();
 
 
             let mut else_stmts = Vec::new();
             let mut else_stmts = Vec::new();
             if let Some(stmts) = else_ {
             if let Some(stmts) = else_ {
                 symtable.enter_scope();
                 symtable.enter_scope();
-                reachable |= statement(
-                    stmts,
-                    &mut else_stmts,
-                    context,
-                    symtable,
-                    loops,
-                    ns,
-                    diagnostics,
-                )?;
+                reachable |= statement(stmts, &mut else_stmts, context, symtable, ns, diagnostics)?;
 
 
                 symtable.leave_scope();
                 symtable.leave_scope();
             } else {
             } else {
@@ -608,35 +568,18 @@ fn statement(
             let mut init = Vec::new();
             let mut init = Vec::new();
 
 
             if let Some(init_stmt) = init_stmt {
             if let Some(init_stmt) = init_stmt {
-                statement(
-                    init_stmt,
-                    &mut init,
-                    context,
-                    symtable,
-                    loops,
-                    ns,
-                    diagnostics,
-                )?;
+                statement(init_stmt, &mut init, context, symtable, ns, diagnostics)?;
             }
             }
 
 
-            loops.enter_scope();
-            context.enter_loop();
+            context.loops.enter_scope();
 
 
             let mut body = Vec::new();
             let mut body = Vec::new();
 
 
             if let Some(body_stmt) = body_stmt {
             if let Some(body_stmt) = body_stmt {
-                statement(
-                    body_stmt,
-                    &mut body,
-                    context,
-                    symtable,
-                    loops,
-                    ns,
-                    diagnostics,
-                )?;
+                statement(body_stmt, &mut body, context, symtable, ns, diagnostics)?;
             }
             }
 
 
-            let control = loops.leave_scope();
+            let control = context.loops.leave_scope();
             let reachable = control.no_breaks > 0;
             let reachable = control.no_breaks > 0;
             let mut next = None;
             let mut next = None;
 
 
@@ -661,7 +604,6 @@ fn statement(
                 cond: None,
                 cond: None,
                 body,
                 body,
             });
             });
-            context.exit_loop();
             Ok(reachable)
             Ok(reachable)
         }
         }
         pt::Statement::For(loc, init_stmt, Some(cond_expr), next_expr, body_stmt) => {
         pt::Statement::For(loc, init_stmt, Some(cond_expr), next_expr, body_stmt) => {
@@ -672,18 +614,9 @@ fn statement(
             let mut next = None;
             let mut next = None;
 
 
             if let Some(init_stmt) = init_stmt {
             if let Some(init_stmt) = init_stmt {
-                statement(
-                    init_stmt,
-                    &mut init,
-                    context,
-                    symtable,
-                    loops,
-                    ns,
-                    diagnostics,
-                )?;
+                statement(init_stmt, &mut init, context, symtable, ns, diagnostics)?;
             }
             }
 
 
-            context.enter_loop();
             let cond = expression(
             let cond = expression(
                 cond_expr,
                 cond_expr,
                 context,
                 context,
@@ -696,22 +629,16 @@ fn statement(
             let cond = cond.cast(&cond_expr.loc(), &Type::Bool, true, ns, diagnostics)?;
             let cond = cond.cast(&cond_expr.loc(), &Type::Bool, true, ns, diagnostics)?;
 
 
             // continue goes to next, and if that does exist, cond
             // continue goes to next, and if that does exist, cond
-            loops.enter_scope();
+            context.loops.enter_scope();
 
 
             let mut body_reachable = match body_stmt {
             let mut body_reachable = match body_stmt {
-                Some(body_stmt) => statement(
-                    body_stmt,
-                    &mut body,
-                    context,
-                    symtable,
-                    loops,
-                    ns,
-                    diagnostics,
-                )?,
+                Some(body_stmt) => {
+                    statement(body_stmt, &mut body, context, symtable, ns, diagnostics)?
+                }
                 None => true,
                 None => true,
             };
             };
 
 
-            let control = loops.leave_scope();
+            let control = context.loops.leave_scope();
 
 
             if control.no_continues > 0 {
             if control.no_continues > 0 {
                 body_reachable = true;
                 body_reachable = true;
@@ -741,7 +668,6 @@ fn statement(
                 body,
                 body,
             });
             });
 
 
-            context.exit_loop();
             Ok(true)
             Ok(true)
         }
         }
         pt::Statement::Return(loc, None) => {
         pt::Statement::Return(loc, None) => {
@@ -877,7 +803,6 @@ fn statement(
                 clause_stmts,
                 clause_stmts,
                 context,
                 context,
                 symtable,
                 symtable,
-                loops,
                 ns,
                 ns,
                 diagnostics,
                 diagnostics,
             )?;
             )?;
@@ -969,7 +894,7 @@ fn revert_pos_arg(
     loc: &pt::Loc,
     loc: &pt::Loc,
     path: &Option<pt::IdentifierPath>,
     path: &Option<pt::IdentifierPath>,
     args: &[pt::Expression],
     args: &[pt::Expression],
-    context: &ExprContext,
+    context: &mut ExprContext,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
     ns: &mut Namespace,
     ns: &mut Namespace,
@@ -1098,7 +1023,7 @@ fn revert_named_arg(
     loc: &pt::Loc,
     loc: &pt::Loc,
     path: &Option<pt::IdentifierPath>,
     path: &Option<pt::IdentifierPath>,
     args: &[pt::NamedArgument],
     args: &[pt::NamedArgument],
-    context: &ExprContext,
+    context: &mut ExprContext,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
     ns: &mut Namespace,
     ns: &mut Namespace,
@@ -1247,7 +1172,7 @@ fn revert_named_arg(
 fn emit_event(
 fn emit_event(
     loc: &pt::Loc,
     loc: &pt::Loc,
     ty: &pt::Expression,
     ty: &pt::Expression,
-    context: &ExprContext,
+    context: &mut ExprContext,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     ns: &mut Namespace,
     ns: &mut Namespace,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -1522,7 +1447,7 @@ fn destructure(
     loc: &pt::Loc,
     loc: &pt::Loc,
     vars: &[(pt::Loc, Option<pt::Parameter>)],
     vars: &[(pt::Loc, Option<pt::Parameter>)],
     expr: &pt::Expression,
     expr: &pt::Expression,
-    context: &ExprContext,
+    context: &mut ExprContext,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     ns: &mut Namespace,
     ns: &mut Namespace,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -1531,8 +1456,12 @@ fn destructure(
     let mut fields = Vec::new();
     let mut fields = Vec::new();
     let mut left_tys = Vec::new();
     let mut left_tys = Vec::new();
 
 
-    let mut lcontext = context.clone();
-    lcontext.lvalue = true;
+    let prev_lvalue = context.lvalue;
+    context.lvalue = true;
+
+    let mut context = scopeguard::guard(context, |context| {
+        context.lvalue = prev_lvalue;
+    });
 
 
     for (_, param) in vars {
     for (_, param) in vars {
         match param {
         match param {
@@ -1560,7 +1489,14 @@ fn destructure(
                 }
                 }
 
 
                 // ty will just be a normal expression, not a type
                 // ty will just be a normal expression, not a type
-                let e = expression(ty, &lcontext, ns, symtable, diagnostics, ResolveTo::Unknown)?;
+                let e = expression(
+                    ty,
+                    &mut context,
+                    ns,
+                    symtable,
+                    diagnostics,
+                    ResolveTo::Unknown,
+                )?;
 
 
                 match &e {
                 match &e {
                     Expression::ConstantVariable {
                     Expression::ConstantVariable {
@@ -1635,7 +1571,7 @@ fn destructure(
                 // The grammar does not allow annotation in destructures, so this assertion shall
                 // The grammar does not allow annotation in destructures, so this assertion shall
                 // always be true.
                 // always be true.
                 assert!(annotation.is_none());
                 assert!(annotation.is_none());
-                let (ty, ty_loc) = resolve_var_decl_ty(ty, storage, context, ns, diagnostics)?;
+                let (ty, ty_loc) = resolve_var_decl_ty(ty, storage, &mut context, ns, diagnostics)?;
 
 
                 if let Some(pos) = symtable.add(
                 if let Some(pos) = symtable.add(
                     name,
                     name,
@@ -1668,12 +1604,14 @@ fn destructure(
         }
         }
     }
     }
 
 
+    context.lvalue = false;
+
     let expr = destructure_values(
     let expr = destructure_values(
         loc,
         loc,
         expr,
         expr,
         &left_tys,
         &left_tys,
         &fields,
         &fields,
-        context,
+        &mut context,
         symtable,
         symtable,
         ns,
         ns,
         diagnostics,
         diagnostics,
@@ -1687,7 +1625,7 @@ fn destructure_values(
     expr: &pt::Expression,
     expr: &pt::Expression,
     left_tys: &[Option<Type>],
     left_tys: &[Option<Type>],
     fields: &[DestructureField],
     fields: &[DestructureField],
-    context: &ExprContext,
+    context: &mut ExprContext,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     ns: &mut Namespace,
     ns: &mut Namespace,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -1851,7 +1789,7 @@ fn destructure_values(
 fn resolve_var_decl_ty(
 fn resolve_var_decl_ty(
     ty: &pt::Expression,
     ty: &pt::Expression,
     storage: &Option<pt::StorageLocation>,
     storage: &Option<pt::StorageLocation>,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
 ) -> Result<(Type, pt::Loc), ()> {
 ) -> Result<(Type, pt::Loc), ()> {
@@ -1905,7 +1843,7 @@ fn resolve_var_decl_ty(
 fn return_with_values(
 fn return_with_values(
     returns: &pt::Expression,
     returns: &pt::Expression,
     loc: &pt::Loc,
     loc: &pt::Loc,
-    context: &ExprContext,
+    context: &mut ExprContext,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     ns: &mut Namespace,
     ns: &mut Namespace,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
@@ -2165,7 +2103,6 @@ fn try_catch(
     clause_stmts: &[pt::CatchClause],
     clause_stmts: &[pt::CatchClause],
     context: &mut ExprContext,
     context: &mut ExprContext,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
-    loops: &mut LoopScopes,
     ns: &mut Namespace,
     ns: &mut Namespace,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,
 ) -> Result<(Statement, bool), ()> {
 ) -> Result<(Statement, bool), ()> {
@@ -2450,15 +2387,8 @@ fn try_catch(
 
 
     let mut ok_resolved = Vec::new();
     let mut ok_resolved = Vec::new();
 
 
-    let mut finally_reachable = statement(
-        ok,
-        &mut ok_resolved,
-        context,
-        symtable,
-        loops,
-        ns,
-        diagnostics,
-    )?;
+    let mut finally_reachable =
+        statement(ok, &mut ok_resolved, context, symtable, ns, diagnostics)?;
 
 
     symtable.leave_scope();
     symtable.leave_scope();
 
 
@@ -2544,7 +2474,6 @@ fn try_catch(
                     &mut catch_stmt_resolved,
                     &mut catch_stmt_resolved,
                     context,
                     context,
                     symtable,
                     symtable,
-                    loops,
                     ns,
                     ns,
                     diagnostics,
                     diagnostics,
                 )?;
                 )?;
@@ -2634,7 +2563,6 @@ fn try_catch(
                     &mut error_stmt_resolved,
                     &mut error_stmt_resolved,
                     context,
                     context,
                     symtable,
                     symtable,
-                    loops,
                     ns,
                     ns,
                     diagnostics,
                     diagnostics,
                 )?;
                 )?;

+ 4 - 0
src/sema/symtable.rs

@@ -235,6 +235,10 @@ impl LoopScopes {
         }
         }
     }
     }
 
 
+    pub fn in_a_loop(&self) -> bool {
+        !self.0.is_empty()
+    }
+
     pub fn do_continue(&mut self) -> bool {
     pub fn do_continue(&mut self) -> bool {
         match self.0.last_mut() {
         match self.0.last_mut() {
             Some(scope) => {
             Some(scope) => {

+ 1 - 1
src/sema/using.rs

@@ -421,7 +421,7 @@ pub(super) fn try_resolve_using_call(
     loc: &pt::Loc,
     loc: &pt::Loc,
     func: &pt::Identifier,
     func: &pt::Identifier,
     self_expr: &Expression,
     self_expr: &Expression,
-    context: &ExprContext,
+    context: &mut ExprContext,
     args: &[pt::Expression],
     args: &[pt::Expression],
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     diagnostics: &mut Diagnostics,
     diagnostics: &mut Diagnostics,

+ 6 - 12
src/sema/variables.rs

@@ -9,8 +9,7 @@ use super::{
     contracts::is_base,
     contracts::is_base,
     diagnostics::Diagnostics,
     diagnostics::Diagnostics,
     expression::{ExprContext, ResolveTo},
     expression::{ExprContext, ResolveTo},
-    symtable::Symtable,
-    symtable::{VariableInitializer, VariableUsage},
+    symtable::{Symtable, VariableInitializer, VariableUsage},
     tags::resolve_tags,
     tags::resolve_tags,
     ContractDefinition,
     ContractDefinition,
 };
 };
@@ -324,19 +323,15 @@ pub fn variable_decl<'a>(
 
 
     let initializer = if constant {
     let initializer = if constant {
         if let Some(initializer) = &def.initializer {
         if let Some(initializer) = &def.initializer {
-            let context = ExprContext {
+            let mut context = ExprContext {
                 file_no,
                 file_no,
-                unchecked: false,
                 contract_no,
                 contract_no,
-                function_no: None,
                 constant,
                 constant,
-                lvalue: false,
-                yul_function: false,
-                loop_nesting_level: 0,
+                ..Default::default()
             };
             };
             match expression(
             match expression(
                 initializer,
                 initializer,
-                &context,
+                &mut context,
                 ns,
                 ns,
                 symtable,
                 symtable,
                 &mut diagnostics,
                 &mut diagnostics,
@@ -783,7 +778,7 @@ pub fn resolve_initializers(
         let var = &ns.contracts[*contract_no].variables[*var_no];
         let var = &ns.contracts[*contract_no].variables[*var_no];
         let ty = var.ty.clone();
         let ty = var.ty.clone();
 
 
-        let context = ExprContext {
+        let mut context = ExprContext {
             file_no,
             file_no,
             contract_no: Some(*contract_no),
             contract_no: Some(*contract_no),
             ..Default::default()
             ..Default::default()
@@ -791,7 +786,7 @@ pub fn resolve_initializers(
 
 
         if let Ok(res) = expression(
         if let Ok(res) = expression(
             initializer,
             initializer,
-            &context,
+            &mut context,
             ns,
             ns,
             &mut symtable,
             &mut symtable,
             &mut diagnostics,
             &mut diagnostics,
@@ -802,7 +797,6 @@ pub fn resolve_initializers(
                 ns.contracts[*contract_no].variables[*var_no].initializer = Some(res);
                 ns.contracts[*contract_no].variables[*var_no].initializer = Some(res);
             }
             }
         }
         }
-        context.drop();
     }
     }
 
 
     ns.diagnostics.extend(diagnostics);
     ns.diagnostics.extend(diagnostics);

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

@@ -18,7 +18,7 @@ use solang_parser::{
 pub fn resolve_yul_block(
 pub fn resolve_yul_block(
     loc: &pt::Loc,
     loc: &pt::Loc,
     statements: &[pt::YulStatement],
     statements: &[pt::YulStatement],
-    context: &ExprContext,
+    context: &mut ExprContext,
     reachable: bool,
     reachable: bool,
     loop_scope: &mut LoopScopes,
     loop_scope: &mut LoopScopes,
     function_table: &mut FunctionsTable,
     function_table: &mut FunctionsTable,
@@ -58,7 +58,7 @@ pub fn resolve_yul_block(
 /// next statement is reachable
 /// next statement is reachable
 pub(crate) fn process_statements(
 pub(crate) fn process_statements(
     statements: &[pt::YulStatement],
     statements: &[pt::YulStatement],
-    context: &ExprContext,
+    context: &mut ExprContext,
     mut reachable: bool,
     mut reachable: bool,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     loop_scope: &mut LoopScopes,
     loop_scope: &mut LoopScopes,

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

@@ -34,7 +34,7 @@ fn get_suffix_from_string(suffix_name: &str) -> Option<YulSuffix> {
 /// Resolve an yul expression.
 /// Resolve an yul expression.
 pub(crate) fn resolve_yul_expression(
 pub(crate) fn resolve_yul_expression(
     expr: &pt::YulExpression,
     expr: &pt::YulExpression,
-    context: &ExprContext,
+    context: &mut ExprContext,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     function_table: &mut FunctionsTable,
     function_table: &mut FunctionsTable,
     ns: &mut Namespace,
     ns: &mut Namespace,
@@ -267,7 +267,7 @@ fn resolve_variable_reference(
     id: &pt::Identifier,
     id: &pt::Identifier,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &Symtable,
     symtable: &Symtable,
-    context: &ExprContext,
+    context: &mut ExprContext,
 ) -> Result<YulExpression, ()> {
 ) -> Result<YulExpression, ()> {
     if let Some(v) = symtable.find(&id.name) {
     if let Some(v) = symtable.find(&id.name) {
         match &v.usage_type {
         match &v.usage_type {
@@ -354,7 +354,7 @@ fn resolve_variable_reference(
 pub(crate) fn resolve_function_call(
 pub(crate) fn resolve_function_call(
     function_table: &mut FunctionsTable,
     function_table: &mut FunctionsTable,
     func_call: &YulFunctionCall,
     func_call: &YulFunctionCall,
-    context: &ExprContext,
+    context: &mut ExprContext,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     ns: &mut Namespace,
     ns: &mut Namespace,
 ) -> Result<YulExpression, ()> {
 ) -> Result<YulExpression, ()> {
@@ -529,7 +529,7 @@ fn resolve_suffix_access(
     loc: &pt::Loc,
     loc: &pt::Loc,
     expr: &pt::YulExpression,
     expr: &pt::YulExpression,
     id: &Identifier,
     id: &Identifier,
-    context: &ExprContext,
+    context: &mut ExprContext,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     function_table: &mut FunctionsTable,
     function_table: &mut FunctionsTable,
     ns: &mut Namespace,
     ns: &mut Namespace,
@@ -653,7 +653,7 @@ fn resolve_suffix_access(
 /// has a valid expression given the context.
 /// has a valid expression given the context.
 pub(crate) fn check_type(
 pub(crate) fn check_type(
     expr: &YulExpression,
     expr: &YulExpression,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
 ) -> Option<Diagnostic> {
 ) -> Option<Diagnostic> {

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

@@ -16,7 +16,7 @@ use solang_parser::{
 /// Returns the resolved block and a bool to indicate if the next statement is reachable.
 /// Returns the resolved block and a bool to indicate if the next statement is reachable.
 pub(crate) fn resolve_for_loop(
 pub(crate) fn resolve_for_loop(
     yul_for: &pt::YulFor,
     yul_for: &pt::YulFor,
-    context: &ExprContext,
+    context: &mut ExprContext,
     reachable: bool,
     reachable: bool,
     loop_scope: &mut LoopScopes,
     loop_scope: &mut LoopScopes,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
@@ -87,7 +87,7 @@ pub(crate) fn resolve_for_loop(
 /// Returns the resolved block and a bool to indicate if the next statement is reachable.
 /// Returns the resolved block and a bool to indicate if the next statement is reachable.
 fn resolve_for_init_block(
 fn resolve_for_init_block(
     init_block: &pt::YulBlock,
     init_block: &pt::YulBlock,
-    context: &ExprContext,
+    context: &mut ExprContext,
     reachable: bool,
     reachable: bool,
     loop_scope: &mut LoopScopes,
     loop_scope: &mut LoopScopes,
     symtable: &mut Symtable,
     symtable: &mut Symtable,

+ 9 - 4
src/sema/yul/functions.rs

@@ -236,12 +236,17 @@ pub(crate) fn process_function_header(
 pub(crate) fn resolve_function_definition(
 pub(crate) fn resolve_function_definition(
     func_def: &pt::YulFunctionDefinition,
     func_def: &pt::YulFunctionDefinition,
     functions_table: &mut FunctionsTable,
     functions_table: &mut FunctionsTable,
-    context: &ExprContext,
+    context: &mut ExprContext,
     ns: &mut Namespace,
     ns: &mut Namespace,
 ) -> Result<YulFunction, ()> {
 ) -> Result<YulFunction, ()> {
     let mut symtable = Symtable::new();
     let mut symtable = Symtable::new();
-    let mut local_ctx = context.clone();
-    local_ctx.yul_function = true;
+
+    let prev_yul_function = context.yul_function;
+    context.yul_function = true;
+
+    let mut context = scopeguard::guard(context, |context| {
+        context.yul_function = prev_yul_function;
+    });
 
 
     let (params, returns, func_no) = functions_table.get_params_returns_func_no(&func_def.id.name);
     let (params, returns, func_no) = functions_table.get_params_returns_func_no(&func_def.id.name);
 
 
@@ -276,7 +281,7 @@ pub(crate) fn resolve_function_definition(
     let (body_block, _) = resolve_yul_block(
     let (body_block, _) = resolve_yul_block(
         &func_def.body.loc,
         &func_def.body.loc,
         &func_def.body.statements,
         &func_def.body.statements,
-        &local_ctx,
+        &mut context,
         true,
         true,
         &mut loop_scope,
         &mut loop_scope,
         functions_table,
         functions_table,

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

@@ -26,7 +26,7 @@ pub fn resolve_inline_assembly(
     loc: &pt::Loc,
     loc: &pt::Loc,
     memory_safe: bool,
     memory_safe: bool,
     statements: &[pt::YulStatement],
     statements: &[pt::YulStatement],
-    context: &ExprContext,
+    context: &mut ExprContext,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     ns: &mut Namespace,
     ns: &mut Namespace,
 ) -> (InlineAssembly, bool) {
 ) -> (InlineAssembly, bool) {

+ 18 - 13
src/sema/yul/statements.rs

@@ -18,7 +18,7 @@ use solang_parser::{diagnostics::Diagnostic, pt};
 /// Resolves an yul statement. Returns a boolean that indicates if the next statement is reachable.
 /// Resolves an yul statement. Returns a boolean that indicates if the next statement is reachable.
 pub(crate) fn resolve_yul_statement(
 pub(crate) fn resolve_yul_statement(
     statement: &pt::YulStatement,
     statement: &pt::YulStatement,
-    context: &ExprContext,
+    context: &mut ExprContext,
     reachable: bool,
     reachable: bool,
     loop_scope: &mut LoopScopes,
     loop_scope: &mut LoopScopes,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
@@ -173,7 +173,7 @@ fn resolve_top_level_function_call(
     func_call: &pt::YulFunctionCall,
     func_call: &pt::YulFunctionCall,
     reachable: bool,
     reachable: bool,
     function_table: &mut FunctionsTable,
     function_table: &mut FunctionsTable,
-    context: &ExprContext,
+    context: &mut ExprContext,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     ns: &mut Namespace,
     ns: &mut Namespace,
 ) -> Result<(YulStatement, bool), ()> {
 ) -> Result<(YulStatement, bool), ()> {
@@ -220,7 +220,7 @@ fn resolve_variable_declaration(
     initializer: &Option<pt::YulExpression>,
     initializer: &Option<pt::YulExpression>,
     reachable: bool,
     reachable: bool,
     function_table: &mut FunctionsTable,
     function_table: &mut FunctionsTable,
-    context: &ExprContext,
+    context: &mut ExprContext,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     ns: &mut Namespace,
     ns: &mut Namespace,
 ) -> Result<YulStatement, ()> {
 ) -> Result<YulStatement, ()> {
@@ -302,31 +302,36 @@ fn resolve_assignment(
     loc: &pt::Loc,
     loc: &pt::Loc,
     lhs: &[pt::YulExpression],
     lhs: &[pt::YulExpression],
     rhs: &pt::YulExpression,
     rhs: &pt::YulExpression,
-    context: &ExprContext,
+    context: &mut ExprContext,
     reachable: bool,
     reachable: bool,
     function_table: &mut FunctionsTable,
     function_table: &mut FunctionsTable,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     ns: &mut Namespace,
     ns: &mut Namespace,
 ) -> Result<YulStatement, ()> {
 ) -> Result<YulStatement, ()> {
     let mut resolved_lhs: Vec<YulExpression> = Vec::with_capacity(lhs.len());
     let mut resolved_lhs: Vec<YulExpression> = Vec::with_capacity(lhs.len());
-    let mut local_ctx = context.clone();
-    local_ctx.lvalue = true;
+    let prev_lvalue = context.lvalue;
+    context.lvalue = true;
+
+    let mut context = scopeguard::guard(context, |context| {
+        context.lvalue = prev_lvalue;
+    });
+
     for item in lhs {
     for item in lhs {
-        let resolved = resolve_yul_expression(item, &local_ctx, symtable, function_table, ns)?;
-        if let Some(diagnostic) = check_type(&resolved, &local_ctx, ns, symtable) {
+        let resolved = resolve_yul_expression(item, &mut context, symtable, function_table, ns)?;
+        if let Some(diagnostic) = check_type(&resolved, &mut context, ns, symtable) {
             ns.diagnostics.push(diagnostic);
             ns.diagnostics.push(diagnostic);
             return Err(());
             return Err(());
         }
         }
         resolved_lhs.push(resolved);
         resolved_lhs.push(resolved);
     }
     }
 
 
-    local_ctx.lvalue = false;
-    let resolved_rhs = resolve_yul_expression(rhs, &local_ctx, symtable, function_table, ns)?;
+    context.lvalue = false;
+    let resolved_rhs = resolve_yul_expression(rhs, &mut context, symtable, function_table, ns)?;
     check_assignment_compatibility(
     check_assignment_compatibility(
         loc,
         loc,
         &resolved_lhs,
         &resolved_lhs,
         &resolved_rhs,
         &resolved_rhs,
-        context,
+        &mut context,
         function_table,
         function_table,
         symtable,
         symtable,
         ns,
         ns,
@@ -345,7 +350,7 @@ fn check_assignment_compatibility<T>(
     loc: &pt::Loc,
     loc: &pt::Loc,
     lhs: &[T],
     lhs: &[T],
     rhs: &YulExpression,
     rhs: &YulExpression,
-    context: &ExprContext,
+    context: &mut ExprContext,
     function_table: &FunctionsTable,
     function_table: &FunctionsTable,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     ns: &mut Namespace,
     ns: &mut Namespace,
@@ -396,7 +401,7 @@ fn resolve_if_block(
     loc: &pt::Loc,
     loc: &pt::Loc,
     condition: &pt::YulExpression,
     condition: &pt::YulExpression,
     if_block: &[pt::YulStatement],
     if_block: &[pt::YulStatement],
-    context: &ExprContext,
+    context: &mut ExprContext,
     reachable: bool,
     reachable: bool,
     loop_scope: &mut LoopScopes,
     loop_scope: &mut LoopScopes,
     function_table: &mut FunctionsTable,
     function_table: &mut FunctionsTable,

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

@@ -18,7 +18,7 @@ use std::collections::HashMap;
 /// Returns the resolved block and a bool to indicate if the next statement is reachable.
 /// Returns the resolved block and a bool to indicate if the next statement is reachable.
 pub(crate) fn resolve_switch(
 pub(crate) fn resolve_switch(
     yul_switch: &pt::YulSwitch,
     yul_switch: &pt::YulSwitch,
-    context: &ExprContext,
+    context: &mut ExprContext,
     reachable: bool,
     reachable: bool,
     function_table: &mut FunctionsTable,
     function_table: &mut FunctionsTable,
     loop_scope: &mut LoopScopes,
     loop_scope: &mut LoopScopes,
@@ -112,7 +112,7 @@ pub(crate) fn resolve_switch(
 /// Resolves condition statements for either if-statement and switch-statements
 /// Resolves condition statements for either if-statement and switch-statements
 pub(crate) fn resolve_condition(
 pub(crate) fn resolve_condition(
     condition: &pt::YulExpression,
     condition: &pt::YulExpression,
-    context: &ExprContext,
+    context: &mut ExprContext,
     symtable: &mut Symtable,
     symtable: &mut Symtable,
     function_table: &mut FunctionsTable,
     function_table: &mut FunctionsTable,
     ns: &mut Namespace,
     ns: &mut Namespace,
@@ -135,7 +135,7 @@ fn resolve_case_or_default(
     switch_case: &pt::YulSwitchOptions,
     switch_case: &pt::YulSwitchOptions,
     default_block: &mut Option<YulBlock>,
     default_block: &mut Option<YulBlock>,
     case_blocks: &mut Vec<CaseBlock>,
     case_blocks: &mut Vec<CaseBlock>,
-    context: &ExprContext,
+    context: &mut ExprContext,
     reachable: bool,
     reachable: bool,
     function_table: &mut FunctionsTable,
     function_table: &mut FunctionsTable,
     loop_scope: &mut LoopScopes,
     loop_scope: &mut LoopScopes,
@@ -183,7 +183,7 @@ fn resolve_case_block(
     has_default: bool,
     has_default: bool,
     condition: &pt::YulExpression,
     condition: &pt::YulExpression,
     block: &[pt::YulStatement],
     block: &[pt::YulStatement],
-    context: &ExprContext,
+    context: &mut ExprContext,
     reachable: bool,
     reachable: bool,
     function_table: &mut FunctionsTable,
     function_table: &mut FunctionsTable,
     loop_scope: &mut LoopScopes,
     loop_scope: &mut LoopScopes,

+ 173 - 60
src/sema/yul/tests/expression.rs

@@ -23,7 +23,7 @@ use std::sync::Arc;
 
 
 #[test]
 #[test]
 fn resolve_bool_literal() {
 fn resolve_bool_literal() {
-    let ctx = ExprContext::default();
+    let mut ctx = ExprContext::default();
     let mut symtable = Symtable::new();
     let mut symtable = Symtable::new();
     let mut function_table = FunctionsTable::new(0);
     let mut function_table = FunctionsTable::new(0);
 
 
@@ -38,7 +38,7 @@ fn resolve_bool_literal() {
     );
     );
 
 
     let resolved_type =
     let resolved_type =
-        resolve_yul_expression(&expr, &ctx, &mut symtable, &mut function_table, &mut ns);
+        resolve_yul_expression(&expr, &mut ctx, &mut symtable, &mut function_table, &mut ns);
     assert!(resolved_type.is_ok());
     assert!(resolved_type.is_ok());
     assert!(ns.diagnostics.is_empty());
     assert!(ns.diagnostics.is_empty());
     let unwrapped = resolved_type.unwrap();
     let unwrapped = resolved_type.unwrap();
@@ -50,7 +50,7 @@ fn resolve_bool_literal() {
 
 
     let expr = pt::YulExpression::BoolLiteral(Loc::File(0, 3, 5), true, None);
     let expr = pt::YulExpression::BoolLiteral(Loc::File(0, 3, 5), true, None);
     let resolved_type =
     let resolved_type =
-        resolve_yul_expression(&expr, &ctx, &mut symtable, &mut function_table, &mut ns);
+        resolve_yul_expression(&expr, &mut ctx, &mut symtable, &mut function_table, &mut ns);
 
 
     assert!(resolved_type.is_ok());
     assert!(resolved_type.is_ok());
     assert!(ns.diagnostics.is_empty());
     assert!(ns.diagnostics.is_empty());
@@ -63,7 +63,7 @@ fn resolve_bool_literal() {
 
 
 #[test]
 #[test]
 fn resolve_number_literal() {
 fn resolve_number_literal() {
-    let ctx = ExprContext::default();
+    let mut ctx = ExprContext::default();
     let mut symtable = Symtable::new();
     let mut symtable = Symtable::new();
     let mut function_table = FunctionsTable::new(0);
     let mut function_table = FunctionsTable::new(0);
 
 
@@ -78,7 +78,8 @@ fn resolve_number_literal() {
             name: "u64".to_string(),
             name: "u64".to_string(),
         }),
         }),
     );
     );
-    let parsed = resolve_yul_expression(&expr, &ctx, &mut symtable, &mut function_table, &mut ns);
+    let parsed =
+        resolve_yul_expression(&expr, &mut ctx, &mut symtable, &mut function_table, &mut ns);
     assert!(parsed.is_ok());
     assert!(parsed.is_ok());
     assert_eq!(ns.diagnostics.len(), 1);
     assert_eq!(ns.diagnostics.len(), 1);
     assert_eq!(
     assert_eq!(
@@ -96,7 +97,8 @@ fn resolve_number_literal() {
             name: "u128".to_string(),
             name: "u128".to_string(),
         }),
         }),
     );
     );
-    let parsed = resolve_yul_expression(&expr, &ctx, &mut symtable, &mut function_table, &mut ns);
+    let parsed =
+        resolve_yul_expression(&expr, &mut ctx, &mut symtable, &mut function_table, &mut ns);
     assert!(parsed.is_err());
     assert!(parsed.is_err());
     assert_eq!(ns.diagnostics.len(), 1);
     assert_eq!(ns.diagnostics.len(), 1);
     assert_eq!(
     assert_eq!(
@@ -106,7 +108,8 @@ fn resolve_number_literal() {
 
 
     ns.diagnostics = Diagnostics::default();
     ns.diagnostics = Diagnostics::default();
     let expr = pt::YulExpression::NumberLiteral(loc, "20".to_string(), "".to_string(), None);
     let expr = pt::YulExpression::NumberLiteral(loc, "20".to_string(), "".to_string(), None);
-    let parsed = resolve_yul_expression(&expr, &ctx, &mut symtable, &mut function_table, &mut ns);
+    let parsed =
+        resolve_yul_expression(&expr, &mut ctx, &mut symtable, &mut function_table, &mut ns);
     assert!(parsed.is_ok());
     assert!(parsed.is_ok());
     assert!(ns.diagnostics.is_empty());
     assert!(ns.diagnostics.is_empty());
     assert_eq!(
     assert_eq!(
@@ -117,7 +120,7 @@ fn resolve_number_literal() {
 
 
 #[test]
 #[test]
 fn resolve_hex_number_literal() {
 fn resolve_hex_number_literal() {
-    let ctx = ExprContext::default();
+    let mut ctx = ExprContext::default();
     let mut symtable = Symtable::new();
     let mut symtable = Symtable::new();
     let mut function_table = FunctionsTable::new(0);
     let mut function_table = FunctionsTable::new(0);
 
 
@@ -132,7 +135,8 @@ fn resolve_hex_number_literal() {
         }),
         }),
     );
     );
 
 
-    let resolved = resolve_yul_expression(&expr, &ctx, &mut symtable, &mut function_table, &mut ns);
+    let resolved =
+        resolve_yul_expression(&expr, &mut ctx, &mut symtable, &mut function_table, &mut ns);
     assert!(resolved.is_ok());
     assert!(resolved.is_ok());
     assert_eq!(ns.diagnostics.len(), 1);
     assert_eq!(ns.diagnostics.len(), 1);
     assert_eq!(
     assert_eq!(
@@ -149,7 +153,8 @@ fn resolve_hex_number_literal() {
             name: "s64".to_string(),
             name: "s64".to_string(),
         }),
         }),
     );
     );
-    let resolved = resolve_yul_expression(&expr, &ctx, &mut symtable, &mut function_table, &mut ns);
+    let resolved =
+        resolve_yul_expression(&expr, &mut ctx, &mut symtable, &mut function_table, &mut ns);
     assert!(resolved.is_ok());
     assert!(resolved.is_ok());
     assert!(ns.diagnostics.is_empty());
     assert!(ns.diagnostics.is_empty());
     assert_eq!(
     assert_eq!(
@@ -160,7 +165,7 @@ fn resolve_hex_number_literal() {
 
 
 #[test]
 #[test]
 fn resolve_hex_string_literal() {
 fn resolve_hex_string_literal() {
-    let ctx = ExprContext::default();
+    let mut ctx = ExprContext::default();
     let mut symtable = Symtable::new();
     let mut symtable = Symtable::new();
     let mut function_table = FunctionsTable::new(0);
     let mut function_table = FunctionsTable::new(0);
 
 
@@ -174,7 +179,8 @@ fn resolve_hex_string_literal() {
         None,
         None,
     );
     );
 
 
-    let resolved = resolve_yul_expression(&expr, &ctx, &mut symtable, &mut function_table, &mut ns);
+    let resolved =
+        resolve_yul_expression(&expr, &mut ctx, &mut symtable, &mut function_table, &mut ns);
     assert!(resolved.is_err());
     assert!(resolved.is_err());
     assert_eq!(ns.diagnostics.len(), 1);
     assert_eq!(ns.diagnostics.len(), 1);
     assert_eq!(
     assert_eq!(
@@ -193,7 +199,8 @@ fn resolve_hex_string_literal() {
             name: "myType".to_string(),
             name: "myType".to_string(),
         }),
         }),
     );
     );
-    let resolved = resolve_yul_expression(&expr, &ctx, &mut symtable, &mut function_table, &mut ns);
+    let resolved =
+        resolve_yul_expression(&expr, &mut ctx, &mut symtable, &mut function_table, &mut ns);
     assert!(resolved.is_err());
     assert!(resolved.is_err());
     assert_eq!(ns.diagnostics.len(), 1);
     assert_eq!(ns.diagnostics.len(), 1);
     assert_eq!(
     assert_eq!(
@@ -212,7 +219,8 @@ fn resolve_hex_string_literal() {
             name: "u256".to_string(),
             name: "u256".to_string(),
         }),
         }),
     );
     );
-    let resolved = resolve_yul_expression(&expr, &ctx, &mut symtable, &mut function_table, &mut ns);
+    let resolved =
+        resolve_yul_expression(&expr, &mut ctx, &mut symtable, &mut function_table, &mut ns);
     assert!(resolved.is_ok());
     assert!(resolved.is_ok());
     assert!(ns.diagnostics.is_empty());
     assert!(ns.diagnostics.is_empty());
     assert_eq!(
     assert_eq!(
@@ -223,7 +231,7 @@ fn resolve_hex_string_literal() {
 
 
 #[test]
 #[test]
 fn resolve_string_literal() {
 fn resolve_string_literal() {
-    let ctx = ExprContext::default();
+    let mut ctx = ExprContext::default();
     let mut symtable = Symtable::new();
     let mut symtable = Symtable::new();
     let mut function_table = FunctionsTable::new(0);
     let mut function_table = FunctionsTable::new(0);
 
 
@@ -241,7 +249,8 @@ fn resolve_string_literal() {
         }),
         }),
     );
     );
 
 
-    let resolved = resolve_yul_expression(&expr, &ctx, &mut symtable, &mut function_table, &mut ns);
+    let resolved =
+        resolve_yul_expression(&expr, &mut ctx, &mut symtable, &mut function_table, &mut ns);
     assert!(resolved.is_ok());
     assert!(resolved.is_ok());
     assert!(ns.diagnostics.is_empty());
     assert!(ns.diagnostics.is_empty());
     assert_eq!(
     assert_eq!(
@@ -252,7 +261,7 @@ fn resolve_string_literal() {
 
 
 #[test]
 #[test]
 fn resolve_variable_local() {
 fn resolve_variable_local() {
-    let context = ExprContext::default();
+    let mut context = ExprContext::default();
     let mut symtable = Symtable::new();
     let mut symtable = Symtable::new();
     let mut function_table = FunctionsTable::new(0);
     let mut function_table = FunctionsTable::new(0);
     let mut ns = Namespace::new(Target::EVM);
     let mut ns = Namespace::new(Target::EVM);
@@ -299,14 +308,14 @@ fn resolve_variable_local() {
 
 
     let res1 = resolve_yul_expression(
     let res1 = resolve_yul_expression(
         &expr1,
         &expr1,
-        &context,
+        &mut context,
         &mut symtable,
         &mut symtable,
         &mut function_table,
         &mut function_table,
         &mut ns,
         &mut ns,
     );
     );
     let res2 = resolve_yul_expression(
     let res2 = resolve_yul_expression(
         &expr2,
         &expr2,
-        &context,
+        &mut context,
         &mut symtable,
         &mut symtable,
         &mut function_table,
         &mut function_table,
         &mut ns,
         &mut ns,
@@ -322,15 +331,10 @@ fn resolve_variable_local() {
 
 
 #[test]
 #[test]
 fn resolve_variable_contract() {
 fn resolve_variable_contract() {
-    let context = ExprContext {
-        file_no: 0,
+    let mut context = ExprContext {
         contract_no: Some(0),
         contract_no: Some(0),
         function_no: Some(0),
         function_no: Some(0),
-        unchecked: false,
-        constant: false,
-        lvalue: false,
-        yul_function: false,
-        loop_nesting_level: 0,
+        ..Default::default()
     };
     };
     let mut symtable = Symtable::new();
     let mut symtable = Symtable::new();
     let mut function_table = FunctionsTable::new(0);
     let mut function_table = FunctionsTable::new(0);
@@ -421,7 +425,13 @@ fn resolve_variable_contract() {
         loc,
         loc,
         name: "var1".to_string(),
         name: "var1".to_string(),
     });
     });
-    let res = resolve_yul_expression(&expr, &context, &mut symtable, &mut function_table, &mut ns);
+    let res = resolve_yul_expression(
+        &expr,
+        &mut context,
+        &mut symtable,
+        &mut function_table,
+        &mut ns,
+    );
     assert!(res.is_ok());
     assert!(res.is_ok());
     assert_eq!(
     assert_eq!(
         YulExpression::ConstantVariable(loc, Type::Bool, Some(0), 0),
         YulExpression::ConstantVariable(loc, Type::Bool, Some(0), 0),
@@ -432,7 +442,13 @@ fn resolve_variable_contract() {
         loc,
         loc,
         name: "var2".to_string(),
         name: "var2".to_string(),
     });
     });
-    let res = resolve_yul_expression(&expr, &context, &mut symtable, &mut function_table, &mut ns);
+    let res = resolve_yul_expression(
+        &expr,
+        &mut context,
+        &mut symtable,
+        &mut function_table,
+        &mut ns,
+    );
     assert!(res.is_ok());
     assert!(res.is_ok());
     assert_eq!(
     assert_eq!(
         YulExpression::StorageVariable(loc, Type::Int(128), 0, 1),
         YulExpression::StorageVariable(loc, Type::Int(128), 0, 1),
@@ -443,7 +459,13 @@ fn resolve_variable_contract() {
         loc,
         loc,
         name: "var3".to_string(),
         name: "var3".to_string(),
     });
     });
-    let res = resolve_yul_expression(&expr, &context, &mut symtable, &mut function_table, &mut ns);
+    let res = resolve_yul_expression(
+        &expr,
+        &mut context,
+        &mut symtable,
+        &mut function_table,
+        &mut ns,
+    );
     assert!(res.is_ok());
     assert!(res.is_ok());
     assert_eq!(
     assert_eq!(
         YulExpression::ConstantVariable(loc, Type::Uint(32), None, 0),
         YulExpression::ConstantVariable(loc, Type::Uint(32), None, 0),
@@ -454,7 +476,13 @@ fn resolve_variable_contract() {
         loc,
         loc,
         name: "func".to_string(),
         name: "func".to_string(),
     });
     });
-    let res = resolve_yul_expression(&expr, &context, &mut symtable, &mut function_table, &mut ns);
+    let res = resolve_yul_expression(
+        &expr,
+        &mut context,
+        &mut symtable,
+        &mut function_table,
+        &mut ns,
+    );
     assert!(res.is_err());
     assert!(res.is_err());
     assert_eq!(ns.diagnostics.len(), 1);
     assert_eq!(ns.diagnostics.len(), 1);
     assert_eq!(
     assert_eq!(
@@ -467,7 +495,13 @@ fn resolve_variable_contract() {
         loc,
         loc,
         name: "none".to_string(),
         name: "none".to_string(),
     });
     });
-    let res = resolve_yul_expression(&expr, &context, &mut symtable, &mut function_table, &mut ns);
+    let res = resolve_yul_expression(
+        &expr,
+        &mut context,
+        &mut symtable,
+        &mut function_table,
+        &mut ns,
+    );
     assert!(res.is_err());
     assert!(res.is_err());
     assert_eq!(ns.diagnostics.len(), 1);
     assert_eq!(ns.diagnostics.len(), 1);
     assert_eq!(
     assert_eq!(
@@ -480,7 +514,13 @@ fn resolve_variable_contract() {
         loc,
         loc,
         name: "imut".to_string(),
         name: "imut".to_string(),
     });
     });
-    let res = resolve_yul_expression(&expr, &context, &mut symtable, &mut function_table, &mut ns);
+    let res = resolve_yul_expression(
+        &expr,
+        &mut context,
+        &mut symtable,
+        &mut function_table,
+        &mut ns,
+    );
     assert!(res.is_err());
     assert!(res.is_err());
     assert_eq!(ns.diagnostics.len(), 1);
     assert_eq!(ns.diagnostics.len(), 1);
     assert_eq!(
     assert_eq!(
@@ -491,7 +531,7 @@ fn resolve_variable_contract() {
 
 
 #[test]
 #[test]
 fn function_call() {
 fn function_call() {
-    let context = ExprContext::default();
+    let mut context = ExprContext::default();
     let mut symtable = Symtable::new();
     let mut symtable = Symtable::new();
     let mut function_table = FunctionsTable::new(0);
     let mut function_table = FunctionsTable::new(0);
     function_table.enter_scope();
     function_table.enter_scope();
@@ -506,7 +546,13 @@ fn function_call() {
         },
         },
         arguments: vec![],
         arguments: vec![],
     }));
     }));
-    let res = resolve_yul_expression(&expr, &context, &mut symtable, &mut function_table, &mut ns);
+    let res = resolve_yul_expression(
+        &expr,
+        &mut context,
+        &mut symtable,
+        &mut function_table,
+        &mut ns,
+    );
     assert!(res.is_err());
     assert!(res.is_err());
     assert_eq!(ns.diagnostics.len(), 1);
     assert_eq!(ns.diagnostics.len(), 1);
     assert_eq!(
     assert_eq!(
@@ -523,7 +569,13 @@ fn function_call() {
         },
         },
         arguments: vec![],
         arguments: vec![],
     }));
     }));
-    let res = resolve_yul_expression(&expr, &context, &mut symtable, &mut function_table, &mut ns);
+    let res = resolve_yul_expression(
+        &expr,
+        &mut context,
+        &mut symtable,
+        &mut function_table,
+        &mut ns,
+    );
     assert!(res.is_err());
     assert!(res.is_err());
     assert_eq!(ns.diagnostics.len(), 1);
     assert_eq!(ns.diagnostics.len(), 1);
     assert_eq!(
     assert_eq!(
@@ -549,7 +601,13 @@ fn function_call() {
         },
         },
         arguments: vec![arg.clone()],
         arguments: vec![arg.clone()],
     }));
     }));
-    let res = resolve_yul_expression(&expr, &context, &mut symtable, &mut function_table, &mut ns);
+    let res = resolve_yul_expression(
+        &expr,
+        &mut context,
+        &mut symtable,
+        &mut function_table,
+        &mut ns,
+    );
     assert!(res.is_err());
     assert!(res.is_err());
     assert_eq!(ns.diagnostics.len(), 1);
     assert_eq!(ns.diagnostics.len(), 1);
     assert_eq!(
     assert_eq!(
@@ -566,7 +624,13 @@ fn function_call() {
         },
         },
         arguments: vec![arg.clone()],
         arguments: vec![arg.clone()],
     }));
     }));
-    let res = resolve_yul_expression(&expr, &context, &mut symtable, &mut function_table, &mut ns);
+    let res = resolve_yul_expression(
+        &expr,
+        &mut context,
+        &mut symtable,
+        &mut function_table,
+        &mut ns,
+    );
     assert!(res.is_ok());
     assert!(res.is_ok());
     assert_eq!(
     assert_eq!(
         YulExpression::BuiltInCall(
         YulExpression::BuiltInCall(
@@ -574,7 +638,7 @@ fn function_call() {
             YulBuiltInFunction::Not,
             YulBuiltInFunction::Not,
             vec![resolve_yul_expression(
             vec![resolve_yul_expression(
                 &arg,
                 &arg,
-                &context,
+                &mut context,
                 &mut symtable,
                 &mut symtable,
                 &mut function_table,
                 &mut function_table,
                 &mut ns
                 &mut ns
@@ -601,7 +665,13 @@ fn function_call() {
         },
         },
         arguments: vec![arg.clone()],
         arguments: vec![arg.clone()],
     }));
     }));
-    let res = resolve_yul_expression(&expr, &context, &mut symtable, &mut function_table, &mut ns);
+    let res = resolve_yul_expression(
+        &expr,
+        &mut context,
+        &mut symtable,
+        &mut function_table,
+        &mut ns,
+    );
     assert!(res.is_err());
     assert!(res.is_err());
     assert_eq!(ns.diagnostics.len(), 1);
     assert_eq!(ns.diagnostics.len(), 1);
     assert_eq!(
     assert_eq!(
@@ -618,7 +688,13 @@ fn function_call() {
         },
         },
         arguments: vec![],
         arguments: vec![],
     }));
     }));
-    let res = resolve_yul_expression(&expr, &context, &mut symtable, &mut function_table, &mut ns);
+    let res = resolve_yul_expression(
+        &expr,
+        &mut context,
+        &mut symtable,
+        &mut function_table,
+        &mut ns,
+    );
     assert!(res.is_ok());
     assert!(res.is_ok());
     assert_eq!(
     assert_eq!(
         YulExpression::FunctionCall(loc, 0, vec![], Arc::new(vec![])),
         YulExpression::FunctionCall(loc, 0, vec![], Arc::new(vec![])),
@@ -633,7 +709,13 @@ fn function_call() {
         },
         },
         arguments: vec![],
         arguments: vec![],
     }));
     }));
-    let res = resolve_yul_expression(&expr, &context, &mut symtable, &mut function_table, &mut ns);
+    let res = resolve_yul_expression(
+        &expr,
+        &mut context,
+        &mut symtable,
+        &mut function_table,
+        &mut ns,
+    );
     assert!(res.is_err());
     assert!(res.is_err());
     assert_eq!(ns.diagnostics.len(), 1);
     assert_eq!(ns.diagnostics.len(), 1);
     assert_eq!(
     assert_eq!(
@@ -644,7 +726,7 @@ fn function_call() {
 
 
 #[test]
 #[test]
 fn check_arguments() {
 fn check_arguments() {
-    let context = ExprContext::default();
+    let mut context = ExprContext::default();
     let mut symtable = Symtable::new();
     let mut symtable = Symtable::new();
     let mut function_table = FunctionsTable::new(0);
     let mut function_table = FunctionsTable::new(0);
     function_table.enter_scope();
     function_table.enter_scope();
@@ -719,7 +801,13 @@ fn check_arguments() {
         }))],
         }))],
     }));
     }));
 
 
-    let _ = resolve_yul_expression(&expr, &context, &mut symtable, &mut function_table, &mut ns);
+    let _ = resolve_yul_expression(
+        &expr,
+        &mut context,
+        &mut symtable,
+        &mut function_table,
+        &mut ns,
+    );
     assert!(!ns.diagnostics.is_empty());
     assert!(!ns.diagnostics.is_empty());
     assert_eq!(
     assert_eq!(
         ns.diagnostics.iter().next().unwrap().message,
         ns.diagnostics.iter().next().unwrap().message,
@@ -743,7 +831,13 @@ fn check_arguments() {
         }))],
         }))],
     }));
     }));
 
 
-    let _ = resolve_yul_expression(&expr, &context, &mut symtable, &mut function_table, &mut ns);
+    let _ = resolve_yul_expression(
+        &expr,
+        &mut context,
+        &mut symtable,
+        &mut function_table,
+        &mut ns,
+    );
     assert!(!ns.diagnostics.is_empty());
     assert!(!ns.diagnostics.is_empty());
     assert_eq!(
     assert_eq!(
         ns.diagnostics.iter().next().unwrap().message,
         ns.diagnostics.iter().next().unwrap().message,
@@ -767,7 +861,13 @@ fn check_arguments() {
         }))],
         }))],
     }));
     }));
 
 
-    let _ = resolve_yul_expression(&expr, &context, &mut symtable, &mut function_table, &mut ns);
+    let _ = resolve_yul_expression(
+        &expr,
+        &mut context,
+        &mut symtable,
+        &mut function_table,
+        &mut ns,
+    );
     assert!(!ns.diagnostics.is_empty());
     assert!(!ns.diagnostics.is_empty());
     assert_eq!(
     assert_eq!(
         ns.diagnostics.iter().next().unwrap().message,
         ns.diagnostics.iter().next().unwrap().message,
@@ -777,15 +877,10 @@ fn check_arguments() {
 
 
 #[test]
 #[test]
 fn test_member_access() {
 fn test_member_access() {
-    let context = ExprContext {
-        file_no: 0,
+    let mut context = ExprContext {
         contract_no: Some(0),
         contract_no: Some(0),
         function_no: Some(0),
         function_no: Some(0),
-        unchecked: false,
-        constant: false,
-        lvalue: false,
-        yul_function: false,
-        loop_nesting_level: 0,
+        ..Default::default()
     };
     };
 
 
     let mut symtable = Symtable::new();
     let mut symtable = Symtable::new();
@@ -831,7 +926,13 @@ fn test_member_access() {
         },
         },
     );
     );
 
 
-    let res = resolve_yul_expression(&expr, &context, &mut symtable, &mut function_table, &mut ns);
+    let res = resolve_yul_expression(
+        &expr,
+        &mut context,
+        &mut symtable,
+        &mut function_table,
+        &mut ns,
+    );
     assert!(res.is_err());
     assert!(res.is_err());
     assert_eq!(ns.diagnostics.len(), 1);
     assert_eq!(ns.diagnostics.len(), 1);
     assert_eq!(
     assert_eq!(
@@ -849,7 +950,13 @@ fn test_member_access() {
         },
         },
     );
     );
 
 
-    let res = resolve_yul_expression(&expr, &context, &mut symtable, &mut function_table, &mut ns);
+    let res = resolve_yul_expression(
+        &expr,
+        &mut context,
+        &mut symtable,
+        &mut function_table,
+        &mut ns,
+    );
     assert!(res.is_err());
     assert!(res.is_err());
     assert_eq!(ns.diagnostics.len(), 1);
     assert_eq!(ns.diagnostics.len(), 1);
     assert_eq!(
     assert_eq!(
@@ -870,7 +977,13 @@ fn test_member_access() {
         },
         },
     );
     );
 
 
-    let res = resolve_yul_expression(&expr, &context, &mut symtable, &mut function_table, &mut ns);
+    let res = resolve_yul_expression(
+        &expr,
+        &mut context,
+        &mut symtable,
+        &mut function_table,
+        &mut ns,
+    );
     assert!(res.is_ok());
     assert!(res.is_ok());
     assert!(ns.diagnostics.is_empty());
     assert!(ns.diagnostics.is_empty());
     assert_eq!(
     assert_eq!(
@@ -893,7 +1006,7 @@ fn test_check_types() {
         0,
         0,
     );
     );
 
 
-    let context = ExprContext::default();
+    let mut context = ExprContext::default();
 
 
     let mut ns = Namespace::new(Target::EVM);
     let mut ns = Namespace::new(Target::EVM);
     let mut contract = ast::Contract::new(
     let mut contract = ast::Contract::new(
@@ -930,7 +1043,7 @@ fn test_check_types() {
         VariableUsage::YulLocalVariable,
         VariableUsage::YulLocalVariable,
         None,
         None,
     );
     );
-    let res = check_type(&expr, &context, &mut ns, &mut symtable);
+    let res = check_type(&expr, &mut context, &mut ns, &mut symtable);
     assert!(res.is_some());
     assert!(res.is_some());
     assert_eq!(
     assert_eq!(
         res.unwrap().message,
         res.unwrap().message,
@@ -938,7 +1051,7 @@ fn test_check_types() {
     );
     );
 
 
     let expr = YulExpression::StorageVariable(loc, Type::Int(16), 0, 0);
     let expr = YulExpression::StorageVariable(loc, Type::Int(16), 0, 0);
-    let res = check_type(&expr, &context, &mut ns, &mut symtable);
+    let res = check_type(&expr, &mut context, &mut ns, &mut symtable);
     assert!(res.is_some());
     assert!(res.is_some());
     assert_eq!(
     assert_eq!(
         res.unwrap().message,
         res.unwrap().message,
@@ -951,12 +1064,12 @@ fn test_check_types() {
         Some(StorageLocation::Calldata(loc)),
         Some(StorageLocation::Calldata(loc)),
         0,
         0,
     );
     );
-    let res = check_type(&expr, &context, &mut ns, &mut symtable);
+    let res = check_type(&expr, &mut context, &mut ns, &mut symtable);
     assert!(res.is_some());
     assert!(res.is_some());
     assert_eq!(res.unwrap().message, "Calldata arrays must be accessed with '.offset', '.length' and the 'calldatacopy' function");
     assert_eq!(res.unwrap().message, "Calldata arrays must be accessed with '.offset', '.length' and the 'calldatacopy' function");
 
 
     let expr = YulExpression::StringLiteral(loc, vec![0, 255, 20], Type::Uint(256));
     let expr = YulExpression::StringLiteral(loc, vec![0, 255, 20], Type::Uint(256));
-    let res = check_type(&expr, &context, &mut ns, &mut symtable);
+    let res = check_type(&expr, &mut context, &mut ns, &mut symtable);
     assert!(res.is_none());
     assert!(res.is_none());
 }
 }