Browse Source

Parse error definitions and revert with custom errors (#1259)

These are not supported on Solana or Substrate, however this will help
with testing sema with evm solidity contracts.

This changes revert() from an builtin expression to a statement type.

Signed-off-by: Sean Young <sean@mess.org>
Sean Young 2 years ago
parent
commit
a14139e916

+ 1 - 1
integration/solana/runtime_errors.spec.ts

@@ -68,7 +68,7 @@ describe('Runtime Errors', function () {
             let res = await program.methods.iWillRevert().accounts({ dataAccount: storage.publicKey }).simulate();
         } catch (e: any) {
             const logs = e.simulationResponse.logs;
-            expect(logs).toContain(`Program log: runtime_error: revert encountered in runtime_errors.sol:76:9-15,
+            expect(logs).toContain(`Program log: runtime_error: revert encountered in runtime_errors.sol:76:9-17,
 `)
         }
 

+ 1 - 1
integration/substrate/debug_buffer_format.spec.ts

@@ -37,7 +37,7 @@ call: seal_debug_message=0,
 call: seal_debug_message=0,
 print: I call seal_debug_message under the hood!,
 call: seal_debug_message=0,
-runtime_error: sesa!!! revert encountered in debug_buffer_format.sol:10:9-15,
+runtime_error: sesa!!! revert encountered in debug_buffer_format.sol:10:9-26,
 call: seal_debug_message=0,
 `)
 

+ 1 - 1
integration/substrate/runtime_errors.spec.ts

@@ -44,7 +44,7 @@ describe('Deploy runtime_errors.sol and test the debug buffer', () => {
         expect(res7).toContain(`runtime_error: assert failure in runtime_errors.sol:32:16-24`)
 
         let res8 = await debug_buffer(conn, contract, `i_will_revert`, [], 0);
-        expect(res8).toContain(`runtime_error: revert encountered in runtime_errors.sol:77:9-15`)
+        expect(res8).toContain(`runtime_error: revert encountered in runtime_errors.sol:77:9-17`)
 
         let res9 = await debug_buffer(conn, contract, `write_integer_failure`, [1], 0);
         expect(res9).toContain(`runtime_error: integer too large to write in buffer in runtime_errors.sol:82:18-31`)

+ 5 - 0
src/bin/languageserver/mod.rs

@@ -300,6 +300,11 @@ impl<'a> Builder<'a> {
             ast::Statement::Return(_, Some(expr)) => {
                 self.expression(expr, symtab);
             }
+            ast::Statement::Revert { args, .. } => {
+                for arg in args {
+                    self.expression(arg, symtab);
+                }
+            }
             ast::Statement::Emit {
                 event_no,
                 event_loc,

+ 0 - 65
src/codegen/expression.rs

@@ -896,11 +896,6 @@ pub fn expression(
             args,
             ..
         } => require(cfg, args, contract_no, func, ns, vartab, opt, expr.loc()),
-        ast::Expression::Builtin {
-            kind: ast::Builtin::Revert,
-            args,
-            ..
-        } => revert(args, cfg, contract_no, func, ns, vartab, opt, expr.loc()),
         ast::Expression::Builtin {
             kind: ast::Builtin::SelfDestruct,
             args,
@@ -1586,66 +1581,6 @@ fn require(
     Expression::Poison
 }
 
-fn revert(
-    args: &[ast::Expression],
-    cfg: &mut ControlFlowGraph,
-    contract_no: usize,
-    func: Option<&Function>,
-    ns: &Namespace,
-    vartab: &mut Vartable,
-    opt: &Options,
-    loc: Loc,
-) -> Expression {
-    let expr = args
-        .get(0)
-        .map(|s| expression(s, cfg, contract_no, func, ns, vartab, opt));
-
-    if opt.log_runtime_errors {
-        if expr.is_some() {
-            let prefix = b"runtime_error: ";
-            let error_string = format!(
-                " revert encountered in {},\n",
-                ns.loc_to_string(false, &loc)
-            );
-            let print_expr = Expression::FormatString {
-                loc: Loc::Codegen,
-                args: vec![
-                    (
-                        FormatArg::StringLiteral,
-                        Expression::BytesLiteral {
-                            loc: Loc::Codegen,
-                            ty: Type::Bytes(prefix.len() as u8),
-                            value: prefix.to_vec(),
-                        },
-                    ),
-                    (FormatArg::Default, expr.clone().unwrap()),
-                    (
-                        FormatArg::StringLiteral,
-                        Expression::BytesLiteral {
-                            loc: Loc::Codegen,
-                            ty: Type::Bytes(error_string.as_bytes().len() as u8),
-                            value: error_string.as_bytes().to_vec(),
-                        },
-                    ),
-                ],
-            };
-            cfg.add(vartab, Instr::Print { expr: print_expr });
-        } else {
-            log_runtime_error(
-                opt.log_runtime_errors,
-                "revert encountered",
-                loc,
-                cfg,
-                vartab,
-                ns,
-            )
-        }
-    }
-
-    assert_failure(&Loc::Codegen, expr, ns, cfg, vartab);
-    Expression::Poison
-}
-
 fn self_destruct(
     args: &[ast::Expression],
     cfg: &mut ControlFlowGraph,

+ 1 - 1
src/codegen/external_functions.rs

@@ -146,7 +146,7 @@ fn check_statement(stmt: &Statement, call_list: &mut CallList) -> bool {
         Statement::TryCatch(_, _, try_catch) => {
             try_catch.expr.recurse(call_list, check_expression);
         }
-        Statement::Emit { args, .. } => {
+        Statement::Revert { args, .. } | Statement::Emit { args, .. } => {
             for e in args {
                 e.recurse(call_list, check_expression);
             }

+ 71 - 4
src/codegen/statements.rs

@@ -3,7 +3,9 @@
 use num_bigint::BigInt;
 
 use super::encoding::{abi_decode, abi_encode};
-use super::expression::{assign_single, default_gas, emit_function_call, expression};
+use super::expression::{
+    assert_failure, assign_single, default_gas, emit_function_call, expression, log_runtime_error,
+};
 use super::Options;
 use super::{
     cfg::{ControlFlowGraph, Instr},
@@ -17,8 +19,8 @@ use crate::codegen::unused_variable::{
 use crate::codegen::yul::inline_assembly_cfg;
 use crate::codegen::Expression;
 use crate::sema::ast::{
-    self, ArrayLength, CallTy, DestructureField, Function, Namespace, RetrieveType, Statement,
-    TryCatch, Type, Type::Uint,
+    self, ArrayLength, CallTy, DestructureField, FormatArg, Function, Namespace, RetrieveType,
+    Statement, TryCatch, Type, Type::Uint,
 };
 use crate::sema::Recurse;
 use num_traits::Zero;
@@ -580,6 +582,15 @@ pub(crate) fn statement(
             let emitter = new_event_emitter(loc, *event_no, args, ns);
             emitter.emit(contract_no, func, cfg, vartab, opt);
         }
+        Statement::Revert {
+            loc,
+            error_no,
+            args,
+        } => {
+            assert!(error_no.is_none());
+
+            revert(args, cfg, contract_no, Some(func), ns, vartab, opt, loc);
+        }
         Statement::Underscore(_) => {
             // ensure we get phi nodes for the return values
             if let Some(instr @ Instr::Call { res, .. }) = placeholder {
@@ -599,6 +610,63 @@ pub(crate) fn statement(
     }
 }
 
+fn revert(
+    args: &[ast::Expression],
+    cfg: &mut ControlFlowGraph,
+    contract_no: usize,
+    func: Option<&Function>,
+    ns: &Namespace,
+    vartab: &mut Vartable,
+    opt: &Options,
+    loc: &pt::Loc,
+) {
+    let expr = args
+        .get(0)
+        .map(|s| expression(s, cfg, contract_no, func, ns, vartab, opt));
+
+    if opt.log_runtime_errors {
+        if expr.is_some() {
+            let prefix = b"runtime_error: ";
+            let error_string =
+                format!(" revert encountered in {},\n", ns.loc_to_string(false, loc));
+            let print_expr = Expression::FormatString {
+                loc: Codegen,
+                args: vec![
+                    (
+                        FormatArg::StringLiteral,
+                        Expression::BytesLiteral {
+                            loc: Codegen,
+                            ty: Type::Bytes(prefix.len() as u8),
+                            value: prefix.to_vec(),
+                        },
+                    ),
+                    (FormatArg::Default, expr.clone().unwrap()),
+                    (
+                        FormatArg::StringLiteral,
+                        Expression::BytesLiteral {
+                            loc: Codegen,
+                            ty: Type::Bytes(error_string.as_bytes().len() as u8),
+                            value: error_string.as_bytes().to_vec(),
+                        },
+                    ),
+                ],
+            };
+            cfg.add(vartab, Instr::Print { expr: print_expr });
+        } else {
+            log_runtime_error(
+                opt.log_runtime_errors,
+                "revert encountered",
+                *loc,
+                cfg,
+                vartab,
+                ns,
+            )
+        }
+    }
+
+    assert_failure(&Codegen, expr, ns, cfg, vartab);
+}
+
 /// Generate if-then-no-else
 fn if_then(
     cond: &ast::Expression,
@@ -1513,7 +1581,6 @@ pub fn process_side_effects_expressions(
             // PayableTransfer, Revert, Require and SelfDestruct do not occur inside an expression
             // for they return no value. They should not bother the unused variable elimination.
             | ast::Builtin::PayableTransfer
-            | ast::Builtin::Revert
             | ast::Builtin::Require
             | ast::Builtin::SelfDestruct
             | ast::Builtin::WriteInt8

+ 32 - 2
src/sema/ast.rs

@@ -186,6 +186,25 @@ impl EventDecl {
     }
 }
 
+#[derive(PartialEq, Eq, Clone, Debug)]
+pub struct ErrorDecl {
+    pub tags: Vec<Tag>,
+    pub name: String,
+    pub loc: pt::Loc,
+    pub contract: Option<usize>,
+    pub fields: Vec<Parameter>,
+    pub used: bool,
+}
+
+impl ErrorDecl {
+    pub fn symbol_name(&self, ns: &Namespace) -> String {
+        match &self.contract {
+            Some(c) => format!("{}.{}", ns.contracts[*c].name, self.name),
+            None => self.name.to_string(),
+        }
+    }
+}
+
 impl fmt::Display for StructDecl {
     /// Make the struct name into a string for printing. The struct can be declared either
     /// inside or outside a contract.
@@ -563,6 +582,7 @@ pub enum Symbol {
     Variable(pt::Loc, Option<usize>, usize),
     Struct(pt::Loc, StructType),
     Event(Vec<(pt::Loc, usize)>),
+    Error(pt::Loc, usize),
     Contract(pt::Loc, usize),
     Import(pt::Loc, usize),
     UserType(pt::Loc, usize),
@@ -576,6 +596,7 @@ impl CodeLocation for Symbol {
             | Symbol::Struct(loc, _)
             | Symbol::Contract(loc, _)
             | Symbol::Import(loc, _)
+            | Symbol::Error(loc, _)
             | Symbol::UserType(loc, _) => *loc,
             Symbol::Event(items) | Symbol::Function(items) => items[0].0,
         }
@@ -631,6 +652,7 @@ pub struct Namespace {
     pub enums: Vec<EnumDecl>,
     pub structs: Vec<StructDecl>,
     pub events: Vec<EventDecl>,
+    pub errors: Vec<ErrorDecl>,
     pub contracts: Vec<Contract>,
     /// Global using declarations
     pub using: Vec<Using>,
@@ -1402,6 +1424,7 @@ impl CodeLocation for Statement {
             | Statement::Destructure(loc, ..)
             | Statement::Continue(loc, ..)
             | Statement::Break(loc, ..)
+            | Statement::Revert { loc, .. }
             | Statement::Return(loc, ..)
             | Statement::Emit { loc, .. }
             | Statement::TryCatch(loc, ..)
@@ -1492,7 +1515,6 @@ pub enum Builtin {
     ArrayLength,
     Assert,
     Print,
-    Revert,
     Require,
     SelfDestruct,
     Keccak256,
@@ -1603,6 +1625,11 @@ pub enum Statement {
     Continue(pt::Loc),
     Break(pt::Loc),
     Return(pt::Loc, Option<Expression>),
+    Revert {
+        loc: pt::Loc,
+        error_no: Option<usize>,
+        args: Vec<Expression>,
+    },
     Emit {
         loc: pt::Loc,
         event_no: usize,
@@ -1723,7 +1750,10 @@ impl Statement {
             | Statement::Emit { .. }
             | Statement::Delete(..) => true,
 
-            Statement::Continue(_) | Statement::Break(_) | Statement::Return(..) => false,
+            Statement::Continue(_)
+            | Statement::Break(_)
+            | Statement::Return(..)
+            | Statement::Revert { .. } => false,
 
             Statement::If(_, reachable, ..)
             | Statement::While(_, reachable, ..)

+ 1 - 23
src/sema/builtin.rs

@@ -32,7 +32,7 @@ pub struct Prototype {
 }
 
 // A list of all Solidity builtins functions
-static BUILTIN_FUNCTIONS: Lazy<[Prototype; 26]> = Lazy::new(|| {
+static BUILTIN_FUNCTIONS: Lazy<[Prototype; 24]> = Lazy::new(|| {
     [
         Prototype {
             builtin: Builtin::Assert,
@@ -78,28 +78,6 @@ static BUILTIN_FUNCTIONS: Lazy<[Prototype; 26]> = Lazy::new(|| {
             doc: "Abort execution if argument evaulates to false. Report string when aborting",
             constant: false,
         },
-        Prototype {
-            builtin: Builtin::Revert,
-            namespace: None,
-            method: None,
-            name: "revert",
-            params: vec![],
-            ret: vec![Type::Unreachable],
-            target: vec![],
-            doc: "Revert execution",
-            constant: false,
-        },
-        Prototype {
-            builtin: Builtin::Revert,
-            namespace: None,
-            method: None,
-            name: "revert",
-            params: vec![Type::String],
-            ret: vec![Type::Unreachable],
-            target: vec![],
-            doc: "Revert execution and report string",
-            constant: false,
-        },
         Prototype {
             builtin: Builtin::SelfDestruct,
             namespace: None,

+ 52 - 8
src/sema/dotgraphviz.rs

@@ -1629,14 +1629,7 @@ impl Dot {
 
                     let event = &ns.events[*event_no];
 
-                    if let Some(contract) = event.contract {
-                        labels.insert(
-                            1,
-                            format!("event {}.{}", ns.contracts[contract].name, event.name),
-                        );
-                    } else {
-                        labels.insert(1, format!("event {}", event.name));
-                    }
+                    labels.insert(1, format!("event {}", event.symbol_name(ns)));
 
                     parent =
                         self.add_node(Node::new("emit", labels), Some(parent), Some(parent_rel));
@@ -1645,6 +1638,27 @@ impl Dot {
                         self.add_expression(arg, Some(func), ns, parent, format!("arg #{no}"));
                     }
                 }
+                Statement::Revert {
+                    loc,
+                    error_no,
+                    args,
+                    ..
+                } => {
+                    let mut labels = vec![String::from("revert"), ns.loc_to_string(true, loc)];
+
+                    if let Some(error_no) = error_no {
+                        let error = &ns.errors[*error_no];
+
+                        labels.insert(1, format!("error {}", error.symbol_name(ns)));
+                    }
+
+                    parent =
+                        self.add_node(Node::new("revert", labels), Some(parent), Some(parent_rel));
+
+                    for (no, arg) in args.iter().enumerate() {
+                        self.add_expression(arg, Some(func), ns, parent, format!("arg #{no}"));
+                    }
+                }
                 Statement::TryCatch(loc, _, try_catch) => {
                     let labels = vec![String::from("try"), ns.loc_to_string(true, loc)];
 
@@ -2371,6 +2385,36 @@ impl Namespace {
             }
         }
 
+        // errors
+        if !self.errors.is_empty() {
+            let errors = dot.add_node(Node::new("errors", Vec::new()), None, None);
+
+            for error in &self.errors {
+                let mut labels = vec![
+                    format!("name:{}", error.name),
+                    self.loc_to_string(true, &error.loc),
+                ];
+
+                if let Some(contract) = &error.contract {
+                    labels.insert(1, format!("contract: {contract}"));
+                }
+
+                for field in &error.fields {
+                    labels.push(format!(
+                        "field name:{} ty:{}",
+                        field.name_as_str(),
+                        field.ty.to_string(self),
+                    ));
+                }
+
+                let e = Node::new(&error.name, labels);
+
+                let node = dot.add_node(e, Some(errors), None);
+
+                dot.add_tags(&error.tags, node);
+            }
+        }
+
         // user types
         if self.user_types.iter().any(|t| t.loc != pt::Loc::Builtin) {
             let types = dot.add_node(Node::new("types", Vec::new()), None, None);

+ 2 - 0
src/sema/mod.rs

@@ -3,6 +3,7 @@
 use self::{
     functions::{resolve_params, resolve_returns},
     symtable::Symtable,
+    unused_variable::check_unused_errors,
     variables::variable_decl,
 };
 use crate::file_resolver::{FileResolver, ResolvedFile};
@@ -83,6 +84,7 @@ pub fn sema(file: &ResolvedFile, resolver: &mut FileResolver, ns: &mut ast::Name
         // Checks for unused variables
         check_unused_namespace_variables(ns);
         check_unused_events(ns);
+        check_unused_errors(ns);
     }
 }
 

+ 5 - 0
src/sema/mutability.rs

@@ -218,6 +218,11 @@ fn recurse_statements(stmts: &[Statement], ns: &Namespace, state: &mut StateChec
                 recurse_statements(&try_catch.catch_stmt, ns, state);
             }
             Statement::Emit { loc, .. } => state.write(loc),
+            Statement::Revert { args, .. } => {
+                for arg in args {
+                    arg.recurse(state, read_expression);
+                }
+            }
             Statement::Break(_) | Statement::Continue(_) | Statement::Underscore(_) => (),
             Statement::Assembly(inline_assembly, _) => {
                 for function_no in inline_assembly.functions.start..inline_assembly.functions.end {

+ 149 - 2
src/sema/namespace.rs

@@ -42,6 +42,7 @@ impl Namespace {
             enums: Vec::new(),
             structs: Vec::new(),
             events: Vec::new(),
+            errors: Vec::new(),
             using: Vec::new(),
             contracts: Vec::new(),
             user_types: Vec::new(),
@@ -142,6 +143,14 @@ impl Namespace {
                         "location of previous definition".to_string(),
                     ));
                 }
+                Symbol::Error(c, _) => {
+                    self.diagnostics.push(Diagnostic::error_with_note(
+                        id.loc,
+                        format!("{} is already defined as an error", id.name),
+                        *c,
+                        "location of previous definition".to_string(),
+                    ));
+                }
                 Symbol::Variable(c, _, _) => {
                     self.diagnostics.push(Diagnostic::error_with_note(
                         id.loc,
@@ -231,6 +240,14 @@ impl Namespace {
                             "location of previous definition".to_string(),
                         ));
                     }
+                    Symbol::Error(c, _) => {
+                        self.diagnostics.push(Diagnostic::warning_with_note(
+                            id.loc,
+                            format!("{} is already defined as an error", id.name),
+                            *c,
+                            "location of previous definition".to_string(),
+                        ));
+                    }
                     Symbol::Variable(c, _, _) => {
                         self.diagnostics.push(Diagnostic::warning_with_note(
                             id.loc,
@@ -395,8 +412,8 @@ impl Namespace {
             }
         };
 
-        // if we are resolving an event name without namespace (so no explicit contract name
-        // or import symbol), then we should look both in the current contract and global scope
+        // If we are resolving an event name without namespace (so no explicit contract name
+        // or import symbol), then we should search both the current contract and global scope.
         if namespace.is_empty() {
             let mut events = Vec::new();
 
@@ -490,6 +507,110 @@ impl Namespace {
         }
     }
 
+    /// Resolve an error definition with the given path. The error may be defined in a contract,
+    /// global level or it may have been imported via an import object. The return value is
+    /// an error definition number in the namespace.errors Vec, or an Err(()) if it could not be
+    /// resolved. A diagnostic will be added to the diagnostics.
+    pub(super) fn resolve_error(
+        &mut self,
+        file_no: usize,
+        contract_no: Option<usize>,
+        path: &pt::IdentifierPath,
+        diagnostics: &mut Diagnostics,
+    ) -> Result<usize, ()> {
+        // If we are resolving an error name without a namespace (so no explicit contract name
+        // or import symbol), then we should search both the current contract and global scope.
+        if path.identifiers.len() == 1 {
+            let id = &path.identifiers[0];
+
+            // If we're in a contract, error can be defined in current contract or its bases
+            if let Some(contract_no) = contract_no {
+                for contract_no in self.contract_bases(contract_no).into_iter().rev() {
+                    let file_no = self.contracts[contract_no].loc.file_no();
+
+                    match self.variable_symbols.get(&(
+                        file_no,
+                        Some(contract_no),
+                        id.name.to_owned(),
+                    )) {
+                        None => (),
+                        Some(Symbol::Error(_, error_no)) => {
+                            return Ok(*error_no);
+                        }
+                        sym => {
+                            let error = Namespace::wrong_symbol(sym, id);
+
+                            diagnostics.push(error);
+
+                            return Err(());
+                        }
+                    }
+
+                    if let Some(sym) =
+                        self.function_symbols
+                            .get(&(file_no, Some(contract_no), id.name.to_owned()))
+                    {
+                        let error = Namespace::wrong_symbol(Some(sym), id);
+
+                        diagnostics.push(error);
+
+                        return Err(());
+                    }
+                }
+            }
+
+            if let Some(sym) = self
+                .function_symbols
+                .get(&(file_no, None, id.name.to_owned()))
+            {
+                let error = Namespace::wrong_symbol(Some(sym), id);
+
+                diagnostics.push(error);
+
+                return Err(());
+            }
+
+            return match self
+                .variable_symbols
+                .get(&(file_no, None, id.name.to_owned()))
+            {
+                None => {
+                    diagnostics.push(Diagnostic::decl_error(
+                        id.loc,
+                        format!("error '{}' not found", id.name),
+                    ));
+                    Err(())
+                }
+                Some(Symbol::Error(_, error_no)) => Ok(*error_no),
+                sym => {
+                    let error = Namespace::wrong_symbol(sym, id);
+
+                    diagnostics.push(error);
+
+                    Err(())
+                }
+            };
+        }
+
+        let (id, namespace) = path
+            .identifiers
+            .split_last()
+            .map(|(id, namespace)| (id, namespace.iter().collect()))
+            .unwrap();
+
+        let s = self.resolve_namespace(namespace, file_no, contract_no, id, diagnostics)?;
+
+        if let Some(Symbol::Error(_, error_no)) = s {
+            Ok(*error_no)
+        } else {
+            let error = Namespace::wrong_symbol(s, id);
+
+            diagnostics.push(error);
+
+            Err(())
+        }
+    }
+
     pub fn wrong_symbol(sym: Option<&Symbol>, id: &pt::Identifier) -> Diagnostic {
         match sym {
             None => Diagnostic::decl_error(id.loc, format!("'{}' not found", id.name)),
@@ -502,6 +623,9 @@ impl Namespace {
             Some(Symbol::Event(_)) => {
                 Diagnostic::decl_error(id.loc, format!("'{}' is an event", id.name))
             }
+            Some(Symbol::Error(..)) => {
+                Diagnostic::decl_error(id.loc, format!("'{}' is an error", id.name))
+            }
             Some(Symbol::Function(_)) => {
                 Diagnostic::decl_error(id.loc, format!("'{}' is a function", id.name))
             }
@@ -699,6 +823,15 @@ impl Namespace {
                     notes,
                 ));
             }
+            Some(Symbol::Error(loc, _)) => {
+                let loc = *loc;
+                self.diagnostics.push(Diagnostic::warning_with_note(
+                    id.loc,
+                    format!("declaration of '{}' shadows error definition", id.name),
+                    loc,
+                    "previous definition of error".to_string(),
+                ));
+            }
             Some(Symbol::Function(v)) => {
                 let notes = v
                     .iter()
@@ -1090,6 +1223,13 @@ impl Namespace {
                 ));
                 Err(())
             }
+            Some(Symbol::Error(..)) => {
+                diagnostics.push(Diagnostic::decl_error(
+                    id.loc,
+                    format!("'{}' is an error", id.name),
+                ));
+                Err(())
+            }
             Some(Symbol::Function(_)) => {
                 diagnostics.push(Diagnostic::decl_error(
                     id.loc,
@@ -1186,6 +1326,13 @@ impl Namespace {
                     ));
                     return Err(());
                 }
+                Some(Symbol::Error(..)) => {
+                    diagnostics.push(Diagnostic::decl_error(
+                        contract_name.loc,
+                        format!("'{}' is an error", contract_name.name),
+                    ));
+                    return Err(());
+                }
                 Some(Symbol::Struct(..)) => {
                     diagnostics.push(Diagnostic::decl_error(
                         contract_name.loc,

+ 283 - 24
src/sema/statements.rs

@@ -9,7 +9,6 @@ use super::expression::{
     ExprContext, ResolveTo,
 };
 use super::symtable::{LoopScopes, Symtable};
-use crate::sema::builtin;
 use crate::sema::expression::constructor::{
     constructor_named_args, match_constructor_to_args, new,
 };
@@ -878,45 +877,305 @@ fn statement(
             res.push(Statement::Assembly(resolved_asm.0, resolved_asm.1));
             Ok(resolved_asm.1)
         }
-        pt::Statement::Revert(loc, error, args) => {
-            if let Some(error) = error {
-                ns.diagnostics.push(Diagnostic::error(
-                    error.loc,
-                    format!("revert with custom error '{error}' not supported yet"),
-                ));
-                return Err(());
+        pt::Statement::Revert(loc, path, args) => {
+            if let Ok(stmt) = revert_pos_arg(loc, path, args, context, symtable, diagnostics, ns) {
+                res.push(stmt);
             }
 
-            let id = pt::Identifier {
-                loc: pt::Loc::File(loc.file_no(), loc.start(), loc.start() + 6),
-                name: "revert".to_string(),
+            Ok(false)
+        }
+        pt::Statement::RevertNamedArgs(loc, path, args) => {
+            if let Ok(stmt) = revert_named_arg(loc, path, args, context, symtable, diagnostics, ns)
+            {
+                res.push(stmt);
+            }
+            Ok(false)
+        }
+        pt::Statement::Error(_) => unimplemented!(),
+    }
+}
+
+/// Resolve a revert statement with position arguments, and optional error, e.g.
+/// ```ignore
+/// revert();
+/// revert("the reason why");
+/// revert NotEnoughBalance(address);
+/// ```
+fn revert_pos_arg(
+    loc: &pt::Loc,
+    path: &Option<pt::IdentifierPath>,
+    args: &[pt::Expression],
+    context: &ExprContext,
+    symtable: &mut Symtable,
+    diagnostics: &mut Diagnostics,
+    ns: &mut Namespace,
+) -> Result<Statement, ()> {
+    if let Some(path) = path {
+        let error_no = ns.resolve_error(context.file_no, context.contract_no, path, diagnostics)?;
+
+        let mut arguments = Vec::new();
+
+        for (pos, arg) in args.iter().enumerate() {
+            let error = &ns.errors[error_no];
+
+            let ty = if let Some(field) = error.fields.get(pos) {
+                field.ty.clone()
+            } else {
+                let _ = expression(arg, context, ns, symtable, diagnostics, ResolveTo::Unknown);
+
+                continue;
             };
 
-            let expr = builtin::resolve_call(
-                &id.loc,
-                None,
-                &id.name,
-                args,
+            let arg = match expression(
+                arg,
                 context,
                 ns,
                 symtable,
                 diagnostics,
-            )?;
+                ResolveTo::Type(&ty),
+            ) {
+                Ok(e) => e,
+                Err(()) => {
+                    continue;
+                }
+            };
 
-            let reachable = expr.ty() != Type::Unreachable;
+            match arg.cast(&arg.loc(), &ty, true, ns, diagnostics) {
+                Ok(expr) => {
+                    arguments.push(expr);
+                }
+                Err(()) => {
+                    continue;
+                }
+            }
+        }
 
-            res.push(Statement::Expression(*loc, reachable, expr));
+        let error = &ns.errors[error_no];
+
+        if args.len() != error.fields.len() {
+            ns.diagnostics.push(Diagnostic::error_with_note(
+                path.loc,
+                format!(
+                    "error '{}' has {} fields, {} provided",
+                    error.name,
+                    error.fields.len(),
+                    args.len()
+                ),
+                error.loc,
+                format!("definition of '{}'", error.name),
+            ));
+        }
 
-            Ok(reachable)
+        if ns.target != Target::EVM {
+            ns.diagnostics.push(Diagnostic::error(
+                *loc,
+                format!("revert with custom errors not supported on {}", ns.target),
+            ));
         }
-        pt::Statement::RevertNamedArgs(loc, _, _) => {
+
+        ns.errors[error_no].used = true;
+
+        Ok(Statement::Revert {
+            loc: *loc,
+            error_no: Some(error_no),
+            args: arguments,
+        })
+    } else {
+        let mut arguments = Vec::new();
+
+        match args.len() {
+            0 => (),
+            1 => {
+                if let Ok(arg) = expression(
+                    &args[0],
+                    context,
+                    ns,
+                    symtable,
+                    diagnostics,
+                    ResolveTo::Type(&Type::String),
+                ) {
+                    if let Ok(expr) = arg.cast(&arg.loc(), &Type::String, true, ns, diagnostics) {
+                        arguments.push(expr);
+                    }
+                }
+            }
+            count => {
+                let loc = pt::Loc::File(loc.file_no(), loc.start(), loc.start() + 6);
+
+                ns.diagnostics.push(Diagnostic::error(
+                    loc,
+                    format!(
+                        "revert takes either no argument or a single reason string argument, {} provided",
+                        count
+                    ),
+                ));
+
+                for arg in args {
+                    let _ = expression(arg, context, ns, symtable, diagnostics, ResolveTo::Unknown);
+                }
+            }
+        }
+
+        Ok(Statement::Revert {
+            loc: *loc,
+            error_no: None,
+            args: arguments,
+        })
+    }
+}
+
+/// Resolve a revert statement with named arguments, and optional error, e.g.
+/// ```ignore
+/// revert({foo: 1}); // not allowed
+/// revert({reason:"the reason why"}); // not allowed
+/// revert NotEnoughBalance({user: address});
+/// ```
+fn revert_named_arg(
+    loc: &pt::Loc,
+    path: &Option<pt::IdentifierPath>,
+    args: &[pt::NamedArgument],
+    context: &ExprContext,
+    symtable: &mut Symtable,
+    diagnostics: &mut Diagnostics,
+    ns: &mut Namespace,
+) -> Result<Statement, ()> {
+    if let Some(path) = path {
+        let error_no = ns.resolve_error(context.file_no, context.contract_no, path, diagnostics)?;
+
+        let error = &ns.errors[error_no];
+
+        let unnamed_fields = error
+            .fields
+            .iter()
+            .filter(|param| param.id.is_none())
+            .count();
+
+        if unnamed_fields > 0 {
+            ns.diagnostics.push(Diagnostic::error_with_note(
+                path.loc,
+                format!(
+                    "error '{}' has {} unnamed fields",
+                    error.name, unnamed_fields
+                ),
+                error.loc,
+                format!("definition of '{}'", error.name),
+            ));
+        }
+
+        let fields: HashMap<String, (usize, Type)> = error
+            .fields
+            .iter()
+            .enumerate()
+            .filter_map(|(i, p)| {
+                p.id.as_ref()
+                    .map(|id| (id.name.to_owned(), (i, p.ty.clone())))
+            })
+            .collect();
+
+        let mut arguments = HashMap::new();
+
+        for arg in args {
+            let error = &ns.errors[error_no];
+
+            let name = arg.name.name.as_str();
+
+            if let Some((pos, ty)) = fields.get(name) {
+                if arguments.contains_key(pos) {
+                    diagnostics.push(Diagnostic::error(
+                        arg.name.loc,
+                        format!("duplicate argument with name '{}'", arg.name.name),
+                    ));
+
+                    let _ = expression(
+                        &arg.expr,
+                        context,
+                        ns,
+                        symtable,
+                        diagnostics,
+                        ResolveTo::Unknown,
+                    );
+
+                    continue;
+                }
+
+                let arg = match expression(
+                    &arg.expr,
+                    context,
+                    ns,
+                    symtable,
+                    diagnostics,
+                    ResolveTo::Type(ty),
+                ) {
+                    Ok(e) => e,
+                    Err(()) => {
+                        continue;
+                    }
+                };
+
+                match arg.cast(&arg.loc(), ty, true, ns, diagnostics) {
+                    Ok(expr) => {
+                        arguments.insert(*pos, expr);
+                    }
+                    Err(()) => {
+                        continue;
+                    }
+                }
+            } else {
+                ns.diagnostics.push(Diagnostic::error_with_note(
+                    arg.name.loc,
+                    format!("error '{}' has no field called '{}'", error.name, name),
+                    error.loc,
+                    format!("definition of '{}'", error.name),
+                ));
+
+                let _ = expression(
+                    &arg.expr,
+                    context,
+                    ns,
+                    symtable,
+                    diagnostics,
+                    ResolveTo::Unknown,
+                );
+            }
+        }
+
+        if ns.target != Target::EVM {
             ns.diagnostics.push(Diagnostic::error(
                 *loc,
-                "revert with custom errors or named arguments not supported yet".to_string(),
+                format!("revert with custom errors not supported on {}", ns.target),
             ));
-            Err(())
         }
-        pt::Statement::Error(_) => unimplemented!(),
+
+        let mut args = Vec::new();
+        let error = &ns.errors[error_no];
+
+        for pos in 0..error.fields.len() {
+            if let Some(arg) = arguments.remove(&pos) {
+                args.push(arg);
+            } else if let Some(id) = &error.fields[pos].id {
+                ns.diagnostics.push(Diagnostic::error_with_note(
+                    path.loc,
+                    format!("missing field '{}'", id.name),
+                    error.loc,
+                    format!("definition of '{}'", error.name),
+                ));
+            }
+        }
+
+        ns.errors[error_no].used = true;
+
+        Ok(Statement::Revert {
+            loc: *loc,
+            error_no: Some(error_no),
+            args,
+        })
+    } else {
+        ns.diagnostics.push(Diagnostic::error(
+            *loc,
+            "revert with named arguments requires error type".to_string(),
+        ));
+
+        Err(())
     }
 }
 

+ 206 - 4
src/sema/types.rs

@@ -4,8 +4,8 @@ use super::tags::resolve_tags;
 use super::{annotions_not_allowed, ast, SourceUnit, SOLANA_BUCKET_SIZE};
 use super::{
     ast::{
-        ArrayLength, Contract, Diagnostic, EnumDecl, EventDecl, Mapping, Namespace, Parameter,
-        StructDecl, StructType, Symbol, Tag, Type, UserTypeDecl,
+        ArrayLength, Contract, Diagnostic, EnumDecl, ErrorDecl, EventDecl, Mapping, Namespace,
+        Parameter, StructDecl, StructType, Symbol, Tag, Type, UserTypeDecl,
     },
     diagnostics::Diagnostics,
     ContractDefinition, SOLANA_SPARSE_ARRAY_SIZE,
@@ -30,13 +30,19 @@ type Graph = petgraph::Graph<(), usize, Directed, usize>;
 pub struct ResolveFields<'a> {
     structs: Vec<ResolveStructFields<'a>>,
     events: Vec<ResolveEventFields<'a>>,
+    errors: Vec<ResolveErrorFields<'a>>,
 }
 
 struct ResolveEventFields<'a> {
     event_no: usize,
     pt: &'a pt::EventDefinition,
     comments: Vec<DocComment>,
-    contract: Option<usize>,
+}
+
+struct ResolveErrorFields<'a> {
+    error_no: usize,
+    pt: &'a pt::ErrorDefinition,
+    comments: Vec<DocComment>,
 }
 
 struct ResolveStructFields<'a> {
@@ -56,6 +62,7 @@ pub fn resolve_typenames<'a>(
     let mut delay = ResolveFields {
         structs: Vec::new(),
         events: Vec::new(),
+        errors: Vec::new(),
     };
 
     for item in &tree.items {
@@ -132,7 +139,54 @@ pub fn resolve_typenames<'a>(
                     event_no,
                     pt: def,
                     comments: item.doccomments.clone(),
+                });
+            }
+            pt::SourceUnitPart::ErrorDefinition(def) => {
+                match &def.keyword {
+                    pt::Expression::Variable(id) if id.name == "error" => (),
+                    _ => {
+                        // This can be:
+                        //
+                        // int[2] var(bool);
+                        // S var2();
+                        // funtion var3(int x);
+                        // Event var4(bool f1);
+                        // Error var4(bool f1);
+                        // Feh.b1 var5();
+                        ns.diagnostics.push(Diagnostic::error(
+                            def.keyword.loc(),
+                            "'function', 'error', or 'event' expected".into(),
+                        ));
+                        continue;
+                    }
+                }
+
+                annotions_not_allowed(&item.annotations, "error", ns);
+
+                let error_no = ns.errors.len();
+
+                if !ns.add_symbol(
+                    file_no,
+                    None,
+                    def.name.as_ref().unwrap(),
+                    Symbol::Error(def.name.as_ref().unwrap().loc, error_no),
+                ) {
+                    continue;
+                }
+
+                ns.errors.push(ErrorDecl {
+                    tags: Vec::new(),
+                    name: def.name.as_ref().unwrap().name.to_owned(),
+                    loc: def.name.as_ref().unwrap().loc,
                     contract: None,
+                    fields: Vec::new(),
+                    used: false,
+                });
+
+                delay.errors.push(ResolveErrorFields {
+                    error_no,
+                    pt: def,
+                    comments: item.doccomments.clone(),
                 });
             }
             pt::SourceUnitPart::TypeDefinition(ty) => {
@@ -341,13 +395,25 @@ pub fn resolve_fields(delay: ResolveFields, file_no: usize, ns: &mut Namespace)
 
     // now we can resolve the fields for the events
     for event in delay.events {
-        let (tags, fields) = event_decl(event.pt, file_no, &event.comments, event.contract, ns);
+        let contract_no = ns.events[event.event_no].contract;
+
+        let (tags, fields) = event_decl(event.pt, file_no, &event.comments, contract_no, ns);
 
         ns.events[event.event_no].signature =
             ns.signature(&ns.events[event.event_no].name, &fields);
         ns.events[event.event_no].fields = fields;
         ns.events[event.event_no].tags = tags;
     }
+
+    // now we can resolve the fields for the errors
+    for error in delay.errors {
+        let contract_no = ns.errors[error.error_no].contract;
+
+        let (tags, fields) = error_decl(error.pt, file_no, &error.comments, contract_no, ns);
+
+        ns.errors[error.error_no].fields = fields;
+        ns.errors[error.error_no].tags = tags;
+    }
 }
 
 /// Resolve all the types in a contract
@@ -472,7 +538,56 @@ fn resolve_contract<'a>(
                     event_no,
                     pt,
                     comments: parts.doccomments.clone(),
+                });
+            }
+            pt::ContractPart::ErrorDefinition(def) => {
+                match &def.keyword {
+                    pt::Expression::Variable(id) if id.name == "error" => (),
+                    _ => {
+                        // this can be:
+                        //
+                        // contract c {
+                        //     int[2] var(bool);
+                        //     S var2();
+                        //     funtion var3(int x);
+                        //     Event var4(bool f1);
+                        //     Error var4(bool f1);
+                        //     Feh.b1 var5();
+                        //}
+                        ns.diagnostics.push(Diagnostic::error(
+                            def.keyword.loc(),
+                            "'function', 'error', or 'event' expected".into(),
+                        ));
+                        continue;
+                    }
+                }
+
+                annotions_not_allowed(&parts.annotations, "error", ns);
+
+                let error_no = ns.errors.len();
+
+                if !ns.add_symbol(
+                    file_no,
+                    Some(contract_no),
+                    def.name.as_ref().unwrap(),
+                    Symbol::Error(def.name.as_ref().unwrap().loc, error_no),
+                ) {
+                    continue;
+                }
+
+                ns.errors.push(ErrorDecl {
+                    tags: Vec::new(),
+                    name: def.name.as_ref().unwrap().name.to_owned(),
+                    loc: def.name.as_ref().unwrap().loc,
                     contract: Some(contract_no),
+                    fields: Vec::new(),
+                    used: false,
+                });
+
+                delay.errors.push(ResolveErrorFields {
+                    error_no,
+                    pt: def,
+                    comments: parts.doccomments.clone(),
                 });
             }
             pt::ContractPart::TypeDefinition(ty) => {
@@ -779,6 +894,93 @@ fn event_decl(
     (doc, fields)
 }
 
+/// Resolve an error definition which can be defined in a contract or outside, e.g:
+/// error Foo(int bar, bool foo);
+/// contract {
+///     error Bar(bytes4 selector);
+/// }
+fn error_decl(
+    def: &pt::ErrorDefinition,
+    file_no: usize,
+    tags: &[DocComment],
+    contract_no: Option<usize>,
+    ns: &mut Namespace,
+) -> (Vec<Tag>, Vec<Parameter>) {
+    let mut fields: Vec<Parameter> = Vec::new();
+
+    for field in &def.fields {
+        let mut diagnostics = Diagnostics::default();
+
+        let mut ty = match ns.resolve_type(file_no, contract_no, false, &field.ty, &mut diagnostics)
+        {
+            Ok(s) => s,
+            Err(()) => {
+                ns.diagnostics.extend(diagnostics);
+                Type::Unresolved
+            }
+        };
+
+        if ty.contains_mapping(ns) {
+            ns.diagnostics.push(Diagnostic::error(
+                field.loc,
+                "mapping type is not permitted as error field".to_string(),
+            ));
+            ty = Type::Unresolved;
+        }
+
+        let id = if let Some(name) = &field.name {
+            if let Some(other) = fields
+                .iter()
+                .find(|f| f.id.as_ref().map(|id| id.name.as_str()) == Some(name.name.as_str()))
+            {
+                ns.diagnostics.push(Diagnostic::error_with_note(
+                    name.loc,
+                    format!(
+                        "error '{}' has duplicate field name '{}'",
+                        def.name.as_ref().unwrap().name,
+                        name.name
+                    ),
+                    other.loc,
+                    format!(
+                        "location of previous declaration of '{}'",
+                        other.name_as_str()
+                    ),
+                ));
+                continue;
+            }
+            Some(pt::Identifier {
+                name: name.name.to_owned(),
+                loc: name.loc,
+            })
+        } else {
+            None
+        };
+
+        fields.push(Parameter {
+            loc: field.loc,
+            id,
+            ty,
+            ty_loc: Some(field.ty.loc()),
+            indexed: false,
+            readonly: false,
+            infinite_size: false,
+            recursive: false,
+        });
+    }
+
+    let doc = resolve_tags(
+        def.name.as_ref().unwrap().loc.file_no(),
+        "error",
+        tags,
+        Some(&fields),
+        None,
+        None,
+        ns,
+    );
+
+    (doc, fields)
+}
+
 /// Parse enum declaration. If the declaration is invalid, it is still generated
 /// so that we can continue parsing, with errors recorded.
 fn enum_decl(

+ 40 - 0
src/sema/unused_variable.rs

@@ -487,3 +487,43 @@ pub fn check_unused_events(ns: &mut Namespace) {
         }
     }
 }
+
+/// Check for unused error definitions. Here NotEnoughBalance is never used in a
+/// revert statement.
+///
+/// ```ignore
+/// contract c {
+///     error NotEnoughBalance(address user);
+///     error UnknownUser(address user);
+///
+///     mapping(address => uint64) balances;
+///
+///     function balance(address user) public returns (uint64 balance) {
+///         balance = balances[user];
+///         if (balance == 0) {
+///             revert UnknownUser(user);
+///         }
+///     }
+/// }
+/// ```
+pub fn check_unused_errors(ns: &mut Namespace) {
+    // it is an error to shadow error definitions
+    for error in &ns.errors {
+        if !error.used {
+            if let Some(contract_no) = error.contract {
+                // don't complain about error definitions in interfaces or abstract contracts
+                if matches!(
+                    ns.contracts[contract_no].ty,
+                    ContractTy::Interface(_) | ContractTy::Abstract(_)
+                ) {
+                    continue;
+                }
+            }
+
+            ns.diagnostics.push(Diagnostic::warning(
+                error.loc,
+                format!("error '{}' has never been used", error.name),
+            ));
+        }
+    }
+}

File diff suppressed because it is too large
+ 524 - 525
tests/contract_testcases/evm/comment_tests.dot


+ 174 - 0
tests/contract_testcases/evm/error.dot

@@ -0,0 +1,174 @@
+strict digraph "tests/contract_testcases/evm/error.sol" {
+	E1 [label="name:E1\ntests/contract_testcases/evm/error.sol:2:7-9\nfield name:bar ty:int256\nfield name: ty:bool"]
+	E2 [label="name:E2\ntests/contract_testcases/evm/error.sol:3:7-9\nfield name:bar ty:int256\nfield name:foo ty:bool"]
+	E3 [label="name:E3\ncontract: 0\ntests/contract_testcases/evm/error.sol:6:8-10\nfield name:bar ty:int256\nfield name:foo ty:bool"]
+	E4 [label="name:E4\ncontract: 1\ntests/contract_testcases/evm/error.sol:10:8-10\nfield name:bar ty:int256\nfield name:foo ty:bool"]
+	contract [label="contract e\ntests/contract_testcases/evm/error.sol:5:1-7:2"]
+	contract_7 [label="contract c\ntests/contract_testcases/evm/error.sol:9:1-38:2"]
+	base [label="base e\ntests/contract_testcases/evm/error.sol:9:15-16"]
+	named1 [label="function named1\ncontract: c\ntests/contract_testcases/evm/error.sol:12:2-26\nsignature named1()\nvisibility public\nmutability nonpayable"]
+	if [label="if\ntests/contract_testcases/evm/error.sol:13:3-23:4"]
+	not [label="not\ntests/contract_testcases/evm/error.sol:13:7-13"]
+	equal [label="equal\ntests/contract_testcases/evm/error.sol:13:7-13"]
+	number_literal [label="uint8 literal: 1\ntests/contract_testcases/evm/error.sol:13:7-8"]
+	number_literal_14 [label="uint8 literal: 0\ntests/contract_testcases/evm/error.sol:13:12-13"]
+	revert [label="revert\nerror E1\ntests/contract_testcases/evm/error.sol:14:4-34"]
+	number_literal_16 [label="int256 literal: 1\ntests/contract_testcases/evm/error.sol:14:20-21"]
+	if_17 [label="if\ntests/contract_testcases/evm/error.sol:15:10-23:4"]
+	not_18 [label="not\ntests/contract_testcases/evm/error.sol:15:14-20"]
+	equal_19 [label="equal\ntests/contract_testcases/evm/error.sol:15:14-20"]
+	number_literal_20 [label="uint8 literal: 1\ntests/contract_testcases/evm/error.sol:15:14-15"]
+	number_literal_21 [label="uint8 literal: 0\ntests/contract_testcases/evm/error.sol:15:19-20"]
+	revert_22 [label="revert\nerror E2\ntests/contract_testcases/evm/error.sol:16:4-23"]
+	number_literal_23 [label="int256 literal: 1\ntests/contract_testcases/evm/error.sol:16:20-21"]
+	if_24 [label="if\ntests/contract_testcases/evm/error.sol:17:10-23:4"]
+	not_25 [label="not\ntests/contract_testcases/evm/error.sol:17:14-20"]
+	equal_26 [label="equal\ntests/contract_testcases/evm/error.sol:17:14-20"]
+	number_literal_27 [label="uint8 literal: 1\ntests/contract_testcases/evm/error.sol:17:14-15"]
+	number_literal_28 [label="uint8 literal: 0\ntests/contract_testcases/evm/error.sol:17:19-20"]
+	revert_29 [label="revert\nerror e.E3\ntests/contract_testcases/evm/error.sol:18:4-46"]
+	number_literal_30 [label="int256 literal: 1\ntests/contract_testcases/evm/error.sol:18:20-21"]
+	bool_literal [label="bool literal: true\ntests/contract_testcases/evm/error.sol:18:28-32"]
+	if_32 [label="if\ntests/contract_testcases/evm/error.sol:19:10-23:4"]
+	not_33 [label="not\ntests/contract_testcases/evm/error.sol:19:14-20"]
+	equal_34 [label="equal\ntests/contract_testcases/evm/error.sol:19:14-20"]
+	number_literal_35 [label="uint8 literal: 1\ntests/contract_testcases/evm/error.sol:19:14-15"]
+	number_literal_36 [label="uint8 literal: 0\ntests/contract_testcases/evm/error.sol:19:19-20"]
+	revert_37 [label="revert\nerror e.E3\ntests/contract_testcases/evm/error.sol:20:4-48"]
+	number_literal_38 [label="int256 literal: 1\ntests/contract_testcases/evm/error.sol:20:22-23"]
+	bool_literal_39 [label="bool literal: true\ntests/contract_testcases/evm/error.sol:20:30-34"]
+	revert_40 [label="revert\nerror c.E4\ntests/contract_testcases/evm/error.sol:22:4-34"]
+	number_literal_41 [label="int256 literal: 2\ntests/contract_testcases/evm/error.sol:22:20-21"]
+	pos1 [label="function pos1\ncontract: c\ntests/contract_testcases/evm/error.sol:26:2-24\nsignature pos1()\nvisibility public\nmutability nonpayable"]
+	if_43 [label="if\ntests/contract_testcases/evm/error.sol:27:3-35:4"]
+	not_44 [label="not\ntests/contract_testcases/evm/error.sol:27:7-13"]
+	equal_45 [label="equal\ntests/contract_testcases/evm/error.sol:27:7-13"]
+	number_literal_46 [label="uint8 literal: 1\ntests/contract_testcases/evm/error.sol:27:7-8"]
+	number_literal_47 [label="uint8 literal: 0\ntests/contract_testcases/evm/error.sol:27:12-13"]
+	revert_48 [label="revert\nerror E1\ntests/contract_testcases/evm/error.sol:28:4-27"]
+	bool_literal_49 [label="bool literal: false\ntests/contract_testcases/evm/error.sol:28:21-26"]
+	if_50 [label="if\ntests/contract_testcases/evm/error.sol:29:10-35:4"]
+	not_51 [label="not\ntests/contract_testcases/evm/error.sol:29:14-20"]
+	equal_52 [label="equal\ntests/contract_testcases/evm/error.sol:29:14-20"]
+	number_literal_53 [label="uint8 literal: 1\ntests/contract_testcases/evm/error.sol:29:14-15"]
+	number_literal_54 [label="uint8 literal: 0\ntests/contract_testcases/evm/error.sol:29:19-20"]
+	revert_55 [label="revert\nerror E2\ntests/contract_testcases/evm/error.sol:30:4-16"]
+	number_literal_56 [label="int256 literal: 1\ntests/contract_testcases/evm/error.sol:30:14-15"]
+	if_57 [label="if\ntests/contract_testcases/evm/error.sol:31:10-35:4"]
+	not_58 [label="not\ntests/contract_testcases/evm/error.sol:31:14-20"]
+	equal_59 [label="equal\ntests/contract_testcases/evm/error.sol:31:14-20"]
+	number_literal_60 [label="uint8 literal: 1\ntests/contract_testcases/evm/error.sol:31:14-15"]
+	number_literal_61 [label="uint8 literal: 0\ntests/contract_testcases/evm/error.sol:31:19-20"]
+	revert_62 [label="revert\nerror E2\ntests/contract_testcases/evm/error.sol:32:4-31"]
+	number_literal_63 [label="int256 literal: 1\ntests/contract_testcases/evm/error.sol:32:16-17"]
+	bool_literal_64 [label="bool literal: true\ntests/contract_testcases/evm/error.sol:32:19-23"]
+	revert_65 [label="revert\nerror e.E3\ntests/contract_testcases/evm/error.sol:34:4-22"]
+	number_literal_66 [label="int256 literal: 2\ntests/contract_testcases/evm/error.sol:34:14-15"]
+	bool_literal_67 [label="bool literal: true\ntests/contract_testcases/evm/error.sol:34:17-21"]
+	diagnostic [label="found contract 'e'\nlevel Debug\ntests/contract_testcases/evm/error.sol:5:1-7:2"]
+	diagnostic_70 [label="found contract 'c'\nlevel Debug\ntests/contract_testcases/evm/error.sol:9:1-38:2"]
+	diagnostic_71 [label="error 'E1' has 1 unnamed fields\nlevel Error\ntests/contract_testcases/evm/error.sol:14:11-13"]
+	note [label="definition of 'E1'\ntests/contract_testcases/evm/error.sol:2:7-9"]
+	diagnostic_73 [label="error 'E1' has no field called 'foo'\nlevel Error\ntests/contract_testcases/evm/error.sol:14:23-26"]
+	note_74 [label="definition of 'E1'\ntests/contract_testcases/evm/error.sol:2:7-9"]
+	diagnostic_75 [label="missing field 'foo'\nlevel Error\ntests/contract_testcases/evm/error.sol:16:11-13"]
+	note_76 [label="definition of 'E2'\ntests/contract_testcases/evm/error.sol:3:7-9"]
+	diagnostic_77 [label="error 'E3' has no field called 'baz'\nlevel Error\ntests/contract_testcases/evm/error.sol:18:34-37"]
+	note_78 [label="definition of 'E3'\ntests/contract_testcases/evm/error.sol:6:8-10"]
+	diagnostic_79 [label="duplicate argument with name 'foo'\nlevel Error\ntests/contract_testcases/evm/error.sol:20:36-39"]
+	diagnostic_80 [label="missing field 'foo'\nlevel Error\ntests/contract_testcases/evm/error.sol:22:11-13"]
+	note_81 [label="definition of 'E4'\ntests/contract_testcases/evm/error.sol:10:8-10"]
+	diagnostic_82 [label="error 'E4' has no field called 'baz'\nlevel Error\ntests/contract_testcases/evm/error.sol:22:23-26"]
+	note_83 [label="definition of 'E4'\ntests/contract_testcases/evm/error.sol:10:8-10"]
+	diagnostic_84 [label="implicit conversion to int256 from bytes3 not allowed\nlevel Error\ntests/contract_testcases/evm/error.sol:28:14-19"]
+	diagnostic_85 [label="error 'E2' has 2 fields, 1 provided\nlevel Error\ntests/contract_testcases/evm/error.sol:30:11-13"]
+	note_86 [label="definition of 'E2'\ntests/contract_testcases/evm/error.sol:3:7-9"]
+	diagnostic_87 [label="error 'E2' has 2 fields, 3 provided\nlevel Error\ntests/contract_testcases/evm/error.sol:32:11-15"]
+	note_88 [label="definition of 'E2'\ntests/contract_testcases/evm/error.sol:3:7-9"]
+	errors -> E1
+	errors -> E2
+	errors -> E3
+	errors -> E4
+	contracts -> contract
+	contracts -> contract_7
+	contract_7 -> base [label="base"]
+	contract_7 -> named1 [label="function"]
+	named1 -> if [label="body"]
+	if -> not [label="cond"]
+	not -> equal [label="expr"]
+	equal -> number_literal [label="left"]
+	equal -> number_literal_14 [label="right"]
+	if -> revert [label="then"]
+	revert -> number_literal_16 [label="arg #0"]
+	if -> if_17 [label="else"]
+	if_17 -> not_18 [label="cond"]
+	not_18 -> equal_19 [label="expr"]
+	equal_19 -> number_literal_20 [label="left"]
+	equal_19 -> number_literal_21 [label="right"]
+	if_17 -> revert_22 [label="then"]
+	revert_22 -> number_literal_23 [label="arg #0"]
+	if_17 -> if_24 [label="else"]
+	if_24 -> not_25 [label="cond"]
+	not_25 -> equal_26 [label="expr"]
+	equal_26 -> number_literal_27 [label="left"]
+	equal_26 -> number_literal_28 [label="right"]
+	if_24 -> revert_29 [label="then"]
+	revert_29 -> number_literal_30 [label="arg #0"]
+	revert_29 -> bool_literal [label="arg #1"]
+	if_24 -> if_32 [label="else"]
+	if_32 -> not_33 [label="cond"]
+	not_33 -> equal_34 [label="expr"]
+	equal_34 -> number_literal_35 [label="left"]
+	equal_34 -> number_literal_36 [label="right"]
+	if_32 -> revert_37 [label="then"]
+	revert_37 -> number_literal_38 [label="arg #0"]
+	revert_37 -> bool_literal_39 [label="arg #1"]
+	if_32 -> revert_40 [label="else"]
+	revert_40 -> number_literal_41 [label="arg #0"]
+	contract_7 -> pos1 [label="function"]
+	pos1 -> if_43 [label="body"]
+	if_43 -> not_44 [label="cond"]
+	not_44 -> equal_45 [label="expr"]
+	equal_45 -> number_literal_46 [label="left"]
+	equal_45 -> number_literal_47 [label="right"]
+	if_43 -> revert_48 [label="then"]
+	revert_48 -> bool_literal_49 [label="arg #0"]
+	if_43 -> if_50 [label="else"]
+	if_50 -> not_51 [label="cond"]
+	not_51 -> equal_52 [label="expr"]
+	equal_52 -> number_literal_53 [label="left"]
+	equal_52 -> number_literal_54 [label="right"]
+	if_50 -> revert_55 [label="then"]
+	revert_55 -> number_literal_56 [label="arg #0"]
+	if_50 -> if_57 [label="else"]
+	if_57 -> not_58 [label="cond"]
+	not_58 -> equal_59 [label="expr"]
+	equal_59 -> number_literal_60 [label="left"]
+	equal_59 -> number_literal_61 [label="right"]
+	if_57 -> revert_62 [label="then"]
+	revert_62 -> number_literal_63 [label="arg #0"]
+	revert_62 -> bool_literal_64 [label="arg #1"]
+	if_57 -> revert_65 [label="else"]
+	revert_65 -> number_literal_66 [label="arg #0"]
+	revert_65 -> bool_literal_67 [label="arg #1"]
+	diagnostics -> diagnostic [label="Debug"]
+	diagnostics -> diagnostic_70 [label="Debug"]
+	diagnostics -> diagnostic_71 [label="Error"]
+	diagnostic_71 -> note [label="note"]
+	diagnostics -> diagnostic_73 [label="Error"]
+	diagnostic_73 -> note_74 [label="note"]
+	diagnostics -> diagnostic_75 [label="Error"]
+	diagnostic_75 -> note_76 [label="note"]
+	diagnostics -> diagnostic_77 [label="Error"]
+	diagnostic_77 -> note_78 [label="note"]
+	diagnostics -> diagnostic_79 [label="Error"]
+	diagnostics -> diagnostic_80 [label="Error"]
+	diagnostic_80 -> note_81 [label="note"]
+	diagnostics -> diagnostic_82 [label="Error"]
+	diagnostic_82 -> note_83 [label="note"]
+	diagnostics -> diagnostic_84 [label="Error"]
+	diagnostics -> diagnostic_85 [label="Error"]
+	diagnostic_85 -> note_86 [label="note"]
+	diagnostics -> diagnostic_87 [label="Error"]
+	diagnostic_87 -> note_88 [label="note"]
+}

+ 38 - 0
tests/contract_testcases/evm/error.sol

@@ -0,0 +1,38 @@
+
+error E1(int bar, bool);
+error E2(int bar, bool foo);
+
+contract e {
+	error E3(int bar, bool foo);
+}
+
+contract c is e {
+	error E4(int bar, bool foo);
+
+	function named1() public {
+		if (1 != 0) {
+			revert E1({bar: 1, foo: true});
+		} else if (1 != 0) {
+			revert E2({bar: 1});
+		} else if (1 != 0) {
+			revert E3({bar: 1, foo: true, baz: "hey"});
+		} else if (1 != 0) {
+			revert e.E3({bar: 1, foo: true, foo: false});
+		} else {
+			revert E4({bar: 2, baz: true});
+		}
+	}
+
+	function pos1() public {
+		if (1 != 0) {
+			revert E1("feh", false);
+		} else if (1 != 0) {
+			revert E2(1);
+		} else if (1 != 0) {
+			revert e.E2(1, true, "hey");
+		} else {
+			revert E3(2, true);
+		}
+
+	}
+}

+ 392 - 402
tests/contract_testcases/evm/rubixi.dot

@@ -165,227 +165,222 @@ strict digraph "tests/contract_testcases/evm/rubixi.sol" {
 	storage_load_165 [label="storage load uint256\ntests/contract_testcases/evm/rubixi.sol:77:22-35"]
 	storage_var_166 [label="storage variable\nRubixi.collectedFees\nuint256 storage\ntests/contract_testcases/evm/rubixi.sol:77:22-35"]
 	number_literal_167 [label="uint256 literal: 0\ntests/contract_testcases/evm/rubixi.sol:77:39-40"]
-	expr_168 [label="expression\ntests/contract_testcases/evm/rubixi.sol:77:42-50"]
-	builtins_169 [label="builtin Revert\ntests/contract_testcases/evm/rubixi.sol:77:42-48"]
-	expr_170 [label="expression\ntests/contract_testcases/evm/rubixi.sol:79:18-67"]
-	builtins_171 [label="builtin PayableTransfer\ntests/contract_testcases/evm/rubixi.sol:79:18-67"]
-	cast_172 [label="cast address payable\ntests/contract_testcases/evm/rubixi.sol:79:18-34"]
-	storage_load_173 [label="storage load address\ntests/contract_testcases/evm/rubixi.sol:79:18-34"]
-	storage_var_174 [label="storage variable\nRubixi.creator\naddress storage\ntests/contract_testcases/evm/rubixi.sol:79:26-33"]
-	cast_175 [label="cast uint128\ntests/contract_testcases/evm/rubixi.sol:79:44-66"]
+	revert [label="revert\ntests/contract_testcases/evm/rubixi.sol:77:42-50"]
+	expr_169 [label="expression\ntests/contract_testcases/evm/rubixi.sol:79:18-67"]
+	builtins_170 [label="builtin PayableTransfer\ntests/contract_testcases/evm/rubixi.sol:79:18-67"]
+	cast_171 [label="cast address payable\ntests/contract_testcases/evm/rubixi.sol:79:18-34"]
+	storage_load_172 [label="storage load address\ntests/contract_testcases/evm/rubixi.sol:79:18-34"]
+	storage_var_173 [label="storage variable\nRubixi.creator\naddress storage\ntests/contract_testcases/evm/rubixi.sol:79:26-33"]
+	cast_174 [label="cast uint128\ntests/contract_testcases/evm/rubixi.sol:79:44-66"]
 	trunc [label="truncate uint128\ntests/contract_testcases/evm/rubixi.sol:79:44-66"]
-	storage_load_177 [label="storage load uint256\ntests/contract_testcases/evm/rubixi.sol:79:44-66"]
-	storage_var_178 [label="storage variable\nRubixi.collectedFees\nuint256 storage\ntests/contract_testcases/evm/rubixi.sol:79:52-65"]
-	expr_179 [label="expression\ntests/contract_testcases/evm/rubixi.sol:80:18-35"]
-	assign_180 [label="assign\nuint256\ntests/contract_testcases/evm/rubixi.sol:80:18-31"]
-	storage_var_181 [label="storage variable\nRubixi.collectedFees\nuint256 storage\ntests/contract_testcases/evm/rubixi.sol:80:18-31"]
-	number_literal_182 [label="uint256 literal: 0\ntests/contract_testcases/evm/rubixi.sol:80:34-35"]
+	storage_load_176 [label="storage load uint256\ntests/contract_testcases/evm/rubixi.sol:79:44-66"]
+	storage_var_177 [label="storage variable\nRubixi.collectedFees\nuint256 storage\ntests/contract_testcases/evm/rubixi.sol:79:52-65"]
+	expr_178 [label="expression\ntests/contract_testcases/evm/rubixi.sol:80:18-35"]
+	assign_179 [label="assign\nuint256\ntests/contract_testcases/evm/rubixi.sol:80:18-31"]
+	storage_var_180 [label="storage variable\nRubixi.collectedFees\nuint256 storage\ntests/contract_testcases/evm/rubixi.sol:80:18-31"]
+	number_literal_181 [label="uint256 literal: 0\ntests/contract_testcases/evm/rubixi.sol:80:34-35"]
 	collectFeesInEther [label="function collectFeesInEther\ncontract: Rubixi\ntests/contract_testcases/evm/rubixi.sol:83:10-65\nsignature collectFeesInEther(uint256)\nvisibility public\nmutability nonpayable"]
-	parameters_184 [label="parameters\nuint256 _amt"]
-	expr_185 [label="expression\ntests/contract_testcases/evm/rubixi.sol:84:18-33"]
-	assign_186 [label="assign\nuint256\ntests/contract_testcases/evm/rubixi.sol:84:18-33"]
-	variable_187 [label="variable: _amt\nuint256\ntests/contract_testcases/evm/rubixi.sol:84:18-22"]
-	multiply_188 [label="multiply\nuint256\ntests/contract_testcases/evm/rubixi.sol:84:18-33"]
-	variable_189 [label="variable: _amt\nuint256\ntests/contract_testcases/evm/rubixi.sol:84:18-22"]
-	number_literal_190 [label="uint256 literal: 1000000000000000000\ntests/contract_testcases/evm/rubixi.sol:84:26-33"]
-	if_191 [label="if\ntests/contract_testcases/evm/rubixi.sol:85:18-61"]
-	more_192 [label="more\ntests/contract_testcases/evm/rubixi.sol:85:22-42"]
-	variable_193 [label="variable: _amt\nuint256\ntests/contract_testcases/evm/rubixi.sol:85:22-26"]
-	storage_load_194 [label="storage load uint256\ntests/contract_testcases/evm/rubixi.sol:85:29-42"]
-	storage_var_195 [label="storage variable\nRubixi.collectedFees\nuint256 storage\ntests/contract_testcases/evm/rubixi.sol:85:29-42"]
-	expr_196 [label="expression\ntests/contract_testcases/evm/rubixi.sol:85:44-60"]
-	call_internal_function_197 [label="call internal function\ntests/contract_testcases/evm/rubixi.sol:85:44-60"]
-	internal_function_198 [label="function() internal returns (void)\nRubixi.collectAllFees\ntests/contract_testcases/evm/rubixi.sol:85:44-60"]
-	if_199 [label="if\ntests/contract_testcases/evm/rubixi.sol:87:18-51"]
-	equal_200 [label="equal\ntests/contract_testcases/evm/rubixi.sol:87:22-40"]
-	storage_load_201 [label="storage load uint256\ntests/contract_testcases/evm/rubixi.sol:87:22-35"]
-	storage_var_202 [label="storage variable\nRubixi.collectedFees\nuint256 storage\ntests/contract_testcases/evm/rubixi.sol:87:22-35"]
-	number_literal_203 [label="uint256 literal: 0\ntests/contract_testcases/evm/rubixi.sol:87:39-40"]
-	expr_204 [label="expression\ntests/contract_testcases/evm/rubixi.sol:87:42-50"]
-	builtins_205 [label="builtin Revert\ntests/contract_testcases/evm/rubixi.sol:87:42-48"]
-	expr_206 [label="expression\ntests/contract_testcases/evm/rubixi.sol:89:18-58"]
-	builtins_207 [label="builtin PayableTransfer\ntests/contract_testcases/evm/rubixi.sol:89:18-58"]
-	cast_208 [label="cast address payable\ntests/contract_testcases/evm/rubixi.sol:89:18-34"]
-	storage_load_209 [label="storage load address\ntests/contract_testcases/evm/rubixi.sol:89:18-34"]
-	storage_var_210 [label="storage variable\nRubixi.creator\naddress storage\ntests/contract_testcases/evm/rubixi.sol:89:26-33"]
-	cast_211 [label="cast uint128\ntests/contract_testcases/evm/rubixi.sol:89:44-57"]
-	trunc_212 [label="truncate uint128\ntests/contract_testcases/evm/rubixi.sol:89:44-57"]
-	variable_213 [label="variable: _amt\nuint256\ntests/contract_testcases/evm/rubixi.sol:89:52-56"]
-	expr_214 [label="expression\ntests/contract_testcases/evm/rubixi.sol:90:18-39"]
-	assign_215 [label="assign\nuint256\ntests/contract_testcases/evm/rubixi.sol:90:18-39"]
-	storage_var_216 [label="storage variable\nRubixi.collectedFees\nuint256 storage\ntests/contract_testcases/evm/rubixi.sol:90:18-31"]
-	subtract_217 [label="subtract\nuint256\ntests/contract_testcases/evm/rubixi.sol:90:18-39"]
-	storage_load_218 [label="storage load uint256\ntests/contract_testcases/evm/rubixi.sol:90:18-39"]
-	storage_var_219 [label="storage variable\nRubixi.collectedFees\nuint256 storage\ntests/contract_testcases/evm/rubixi.sol:90:18-31"]
-	variable_220 [label="variable: _amt\nuint256\ntests/contract_testcases/evm/rubixi.sol:90:35-39"]
+	parameters_183 [label="parameters\nuint256 _amt"]
+	expr_184 [label="expression\ntests/contract_testcases/evm/rubixi.sol:84:18-33"]
+	assign_185 [label="assign\nuint256\ntests/contract_testcases/evm/rubixi.sol:84:18-33"]
+	variable_186 [label="variable: _amt\nuint256\ntests/contract_testcases/evm/rubixi.sol:84:18-22"]
+	multiply_187 [label="multiply\nuint256\ntests/contract_testcases/evm/rubixi.sol:84:18-33"]
+	variable_188 [label="variable: _amt\nuint256\ntests/contract_testcases/evm/rubixi.sol:84:18-22"]
+	number_literal_189 [label="uint256 literal: 1000000000000000000\ntests/contract_testcases/evm/rubixi.sol:84:26-33"]
+	if_190 [label="if\ntests/contract_testcases/evm/rubixi.sol:85:18-61"]
+	more_191 [label="more\ntests/contract_testcases/evm/rubixi.sol:85:22-42"]
+	variable_192 [label="variable: _amt\nuint256\ntests/contract_testcases/evm/rubixi.sol:85:22-26"]
+	storage_load_193 [label="storage load uint256\ntests/contract_testcases/evm/rubixi.sol:85:29-42"]
+	storage_var_194 [label="storage variable\nRubixi.collectedFees\nuint256 storage\ntests/contract_testcases/evm/rubixi.sol:85:29-42"]
+	expr_195 [label="expression\ntests/contract_testcases/evm/rubixi.sol:85:44-60"]
+	call_internal_function_196 [label="call internal function\ntests/contract_testcases/evm/rubixi.sol:85:44-60"]
+	internal_function_197 [label="function() internal returns (void)\nRubixi.collectAllFees\ntests/contract_testcases/evm/rubixi.sol:85:44-60"]
+	if_198 [label="if\ntests/contract_testcases/evm/rubixi.sol:87:18-51"]
+	equal_199 [label="equal\ntests/contract_testcases/evm/rubixi.sol:87:22-40"]
+	storage_load_200 [label="storage load uint256\ntests/contract_testcases/evm/rubixi.sol:87:22-35"]
+	storage_var_201 [label="storage variable\nRubixi.collectedFees\nuint256 storage\ntests/contract_testcases/evm/rubixi.sol:87:22-35"]
+	number_literal_202 [label="uint256 literal: 0\ntests/contract_testcases/evm/rubixi.sol:87:39-40"]
+	revert_203 [label="revert\ntests/contract_testcases/evm/rubixi.sol:87:42-50"]
+	expr_204 [label="expression\ntests/contract_testcases/evm/rubixi.sol:89:18-58"]
+	builtins_205 [label="builtin PayableTransfer\ntests/contract_testcases/evm/rubixi.sol:89:18-58"]
+	cast_206 [label="cast address payable\ntests/contract_testcases/evm/rubixi.sol:89:18-34"]
+	storage_load_207 [label="storage load address\ntests/contract_testcases/evm/rubixi.sol:89:18-34"]
+	storage_var_208 [label="storage variable\nRubixi.creator\naddress storage\ntests/contract_testcases/evm/rubixi.sol:89:26-33"]
+	cast_209 [label="cast uint128\ntests/contract_testcases/evm/rubixi.sol:89:44-57"]
+	trunc_210 [label="truncate uint128\ntests/contract_testcases/evm/rubixi.sol:89:44-57"]
+	variable_211 [label="variable: _amt\nuint256\ntests/contract_testcases/evm/rubixi.sol:89:52-56"]
+	expr_212 [label="expression\ntests/contract_testcases/evm/rubixi.sol:90:18-39"]
+	assign_213 [label="assign\nuint256\ntests/contract_testcases/evm/rubixi.sol:90:18-39"]
+	storage_var_214 [label="storage variable\nRubixi.collectedFees\nuint256 storage\ntests/contract_testcases/evm/rubixi.sol:90:18-31"]
+	subtract_215 [label="subtract\nuint256\ntests/contract_testcases/evm/rubixi.sol:90:18-39"]
+	storage_load_216 [label="storage load uint256\ntests/contract_testcases/evm/rubixi.sol:90:18-39"]
+	storage_var_217 [label="storage variable\nRubixi.collectedFees\nuint256 storage\ntests/contract_testcases/evm/rubixi.sol:90:18-31"]
+	variable_218 [label="variable: _amt\nuint256\ntests/contract_testcases/evm/rubixi.sol:90:35-39"]
 	collectPercentOfFees [label="function collectPercentOfFees\ncontract: Rubixi\ntests/contract_testcases/evm/rubixi.sol:93:10-69\nsignature collectPercentOfFees(uint256)\nvisibility public\nmutability nonpayable"]
-	parameters_222 [label="parameters\nuint256 _pcent"]
-	if_223 [label="if\ntests/contract_testcases/evm/rubixi.sol:94:18-67"]
+	parameters_220 [label="parameters\nuint256 _pcent"]
+	if_221 [label="if\ntests/contract_testcases/evm/rubixi.sol:94:18-67"]
 	logical_or [label="logical or\ntests/contract_testcases/evm/rubixi.sol:94:22-56"]
-	equal_225 [label="equal\ntests/contract_testcases/evm/rubixi.sol:94:22-40"]
-	storage_load_226 [label="storage load uint256\ntests/contract_testcases/evm/rubixi.sol:94:22-35"]
-	storage_var_227 [label="storage variable\nRubixi.collectedFees\nuint256 storage\ntests/contract_testcases/evm/rubixi.sol:94:22-35"]
-	number_literal_228 [label="uint256 literal: 0\ntests/contract_testcases/evm/rubixi.sol:94:39-40"]
-	more_229 [label="more\ntests/contract_testcases/evm/rubixi.sol:94:44-56"]
-	variable_230 [label="variable: _pcent\nuint256\ntests/contract_testcases/evm/rubixi.sol:94:44-50"]
-	number_literal_231 [label="uint256 literal: 100\ntests/contract_testcases/evm/rubixi.sol:94:53-56"]
-	expr_232 [label="expression\ntests/contract_testcases/evm/rubixi.sol:94:58-66"]
-	builtins_233 [label="builtin Revert\ntests/contract_testcases/evm/rubixi.sol:94:58-64"]
-	var_decl_234 [label="variable decl uint256 feesToCollect\ntests/contract_testcases/evm/rubixi.sol:96:18-67"]
-	multiply_235 [label="multiply\nuint256\ntests/contract_testcases/evm/rubixi.sol:96:39-67"]
-	divide_236 [label="divide\nuint256\ntests/contract_testcases/evm/rubixi.sol:96:39-58"]
-	storage_load_237 [label="storage load uint256\ntests/contract_testcases/evm/rubixi.sol:96:39-52"]
-	storage_var_238 [label="storage variable\nRubixi.collectedFees\nuint256 storage\ntests/contract_testcases/evm/rubixi.sol:96:39-52"]
-	number_literal_239 [label="uint256 literal: 100\ntests/contract_testcases/evm/rubixi.sol:96:55-58"]
-	variable_240 [label="variable: _pcent\nuint256\ntests/contract_testcases/evm/rubixi.sol:96:61-67"]
-	expr_241 [label="expression\ntests/contract_testcases/evm/rubixi.sol:97:18-67"]
-	builtins_242 [label="builtin PayableTransfer\ntests/contract_testcases/evm/rubixi.sol:97:18-67"]
-	cast_243 [label="cast address payable\ntests/contract_testcases/evm/rubixi.sol:97:18-34"]
-	storage_load_244 [label="storage load address\ntests/contract_testcases/evm/rubixi.sol:97:18-34"]
-	storage_var_245 [label="storage variable\nRubixi.creator\naddress storage\ntests/contract_testcases/evm/rubixi.sol:97:26-33"]
-	cast_246 [label="cast uint128\ntests/contract_testcases/evm/rubixi.sol:97:44-66"]
-	trunc_247 [label="truncate uint128\ntests/contract_testcases/evm/rubixi.sol:97:44-66"]
-	variable_248 [label="variable: feesToCollect\nuint256\ntests/contract_testcases/evm/rubixi.sol:97:52-65"]
-	expr_249 [label="expression\ntests/contract_testcases/evm/rubixi.sol:98:18-48"]
-	assign_250 [label="assign\nuint256\ntests/contract_testcases/evm/rubixi.sol:98:18-48"]
+	equal_223 [label="equal\ntests/contract_testcases/evm/rubixi.sol:94:22-40"]
+	storage_load_224 [label="storage load uint256\ntests/contract_testcases/evm/rubixi.sol:94:22-35"]
+	storage_var_225 [label="storage variable\nRubixi.collectedFees\nuint256 storage\ntests/contract_testcases/evm/rubixi.sol:94:22-35"]
+	number_literal_226 [label="uint256 literal: 0\ntests/contract_testcases/evm/rubixi.sol:94:39-40"]
+	more_227 [label="more\ntests/contract_testcases/evm/rubixi.sol:94:44-56"]
+	variable_228 [label="variable: _pcent\nuint256\ntests/contract_testcases/evm/rubixi.sol:94:44-50"]
+	number_literal_229 [label="uint256 literal: 100\ntests/contract_testcases/evm/rubixi.sol:94:53-56"]
+	revert_230 [label="revert\ntests/contract_testcases/evm/rubixi.sol:94:58-66"]
+	var_decl_231 [label="variable decl uint256 feesToCollect\ntests/contract_testcases/evm/rubixi.sol:96:18-67"]
+	multiply_232 [label="multiply\nuint256\ntests/contract_testcases/evm/rubixi.sol:96:39-67"]
+	divide_233 [label="divide\nuint256\ntests/contract_testcases/evm/rubixi.sol:96:39-58"]
+	storage_load_234 [label="storage load uint256\ntests/contract_testcases/evm/rubixi.sol:96:39-52"]
+	storage_var_235 [label="storage variable\nRubixi.collectedFees\nuint256 storage\ntests/contract_testcases/evm/rubixi.sol:96:39-52"]
+	number_literal_236 [label="uint256 literal: 100\ntests/contract_testcases/evm/rubixi.sol:96:55-58"]
+	variable_237 [label="variable: _pcent\nuint256\ntests/contract_testcases/evm/rubixi.sol:96:61-67"]
+	expr_238 [label="expression\ntests/contract_testcases/evm/rubixi.sol:97:18-67"]
+	builtins_239 [label="builtin PayableTransfer\ntests/contract_testcases/evm/rubixi.sol:97:18-67"]
+	cast_240 [label="cast address payable\ntests/contract_testcases/evm/rubixi.sol:97:18-34"]
+	storage_load_241 [label="storage load address\ntests/contract_testcases/evm/rubixi.sol:97:18-34"]
+	storage_var_242 [label="storage variable\nRubixi.creator\naddress storage\ntests/contract_testcases/evm/rubixi.sol:97:26-33"]
+	cast_243 [label="cast uint128\ntests/contract_testcases/evm/rubixi.sol:97:44-66"]
+	trunc_244 [label="truncate uint128\ntests/contract_testcases/evm/rubixi.sol:97:44-66"]
+	variable_245 [label="variable: feesToCollect\nuint256\ntests/contract_testcases/evm/rubixi.sol:97:52-65"]
+	expr_246 [label="expression\ntests/contract_testcases/evm/rubixi.sol:98:18-48"]
+	assign_247 [label="assign\nuint256\ntests/contract_testcases/evm/rubixi.sol:98:18-48"]
+	storage_var_248 [label="storage variable\nRubixi.collectedFees\nuint256 storage\ntests/contract_testcases/evm/rubixi.sol:98:18-31"]
+	subtract_249 [label="subtract\nuint256\ntests/contract_testcases/evm/rubixi.sol:98:18-48"]
+	storage_load_250 [label="storage load uint256\ntests/contract_testcases/evm/rubixi.sol:98:18-48"]
 	storage_var_251 [label="storage variable\nRubixi.collectedFees\nuint256 storage\ntests/contract_testcases/evm/rubixi.sol:98:18-31"]
-	subtract_252 [label="subtract\nuint256\ntests/contract_testcases/evm/rubixi.sol:98:18-48"]
-	storage_load_253 [label="storage load uint256\ntests/contract_testcases/evm/rubixi.sol:98:18-48"]
-	storage_var_254 [label="storage variable\nRubixi.collectedFees\nuint256 storage\ntests/contract_testcases/evm/rubixi.sol:98:18-31"]
-	variable_255 [label="variable: feesToCollect\nuint256\ntests/contract_testcases/evm/rubixi.sol:98:35-48"]
+	variable_252 [label="variable: feesToCollect\nuint256\ntests/contract_testcases/evm/rubixi.sol:98:35-48"]
 	changeOwner [label="function changeOwner\ncontract: Rubixi\ntests/contract_testcases/evm/rubixi.sol:102:10-63\nsignature changeOwner(address)\nvisibility public\nmutability nonpayable"]
-	parameters_257 [label="parameters\naddress _owner"]
-	expr_258 [label="expression\ntests/contract_testcases/evm/rubixi.sol:103:18-34"]
-	assign_259 [label="assign\naddress\ntests/contract_testcases/evm/rubixi.sol:103:18-25"]
-	storage_var_260 [label="storage variable\nRubixi.creator\naddress storage\ntests/contract_testcases/evm/rubixi.sol:103:18-25"]
-	variable_261 [label="variable: _owner\naddress\ntests/contract_testcases/evm/rubixi.sol:103:28-34"]
+	parameters_254 [label="parameters\naddress _owner"]
+	expr_255 [label="expression\ntests/contract_testcases/evm/rubixi.sol:103:18-34"]
+	assign_256 [label="assign\naddress\ntests/contract_testcases/evm/rubixi.sol:103:18-25"]
+	storage_var_257 [label="storage variable\nRubixi.creator\naddress storage\ntests/contract_testcases/evm/rubixi.sol:103:18-25"]
+	variable_258 [label="variable: _owner\naddress\ntests/contract_testcases/evm/rubixi.sol:103:28-34"]
 	changeMultiplier [label="function changeMultiplier\ncontract: Rubixi\ntests/contract_testcases/evm/rubixi.sol:106:10-64\nsignature changeMultiplier(uint256)\nvisibility public\nmutability nonpayable"]
-	parameters_263 [label="parameters\nuint256 _mult"]
-	if_264 [label="if\ntests/contract_testcases/evm/rubixi.sol:107:18-59"]
-	logical_or_265 [label="logical or\ntests/contract_testcases/evm/rubixi.sol:107:22-48"]
-	more_266 [label="more\ntests/contract_testcases/evm/rubixi.sol:107:22-33"]
-	variable_267 [label="variable: _mult\nuint256\ntests/contract_testcases/evm/rubixi.sol:107:22-27"]
-	number_literal_268 [label="uint256 literal: 300\ntests/contract_testcases/evm/rubixi.sol:107:30-33"]
-	less_269 [label="less\ntests/contract_testcases/evm/rubixi.sol:107:37-48"]
-	variable_270 [label="variable: _mult\nuint256\ntests/contract_testcases/evm/rubixi.sol:107:37-42"]
-	number_literal_271 [label="uint256 literal: 120\ntests/contract_testcases/evm/rubixi.sol:107:45-48"]
-	expr_272 [label="expression\ntests/contract_testcases/evm/rubixi.sol:107:50-58"]
-	builtins_273 [label="builtin Revert\ntests/contract_testcases/evm/rubixi.sol:107:50-56"]
-	expr_274 [label="expression\ntests/contract_testcases/evm/rubixi.sol:109:18-43"]
-	assign_275 [label="assign\nuint256\ntests/contract_testcases/evm/rubixi.sol:109:18-35"]
-	storage_var_276 [label="storage variable\nRubixi.pyramidMultiplier\nuint256 storage\ntests/contract_testcases/evm/rubixi.sol:109:18-35"]
-	variable_277 [label="variable: _mult\nuint256\ntests/contract_testcases/evm/rubixi.sol:109:38-43"]
+	parameters_260 [label="parameters\nuint256 _mult"]
+	if_261 [label="if\ntests/contract_testcases/evm/rubixi.sol:107:18-59"]
+	logical_or_262 [label="logical or\ntests/contract_testcases/evm/rubixi.sol:107:22-48"]
+	more_263 [label="more\ntests/contract_testcases/evm/rubixi.sol:107:22-33"]
+	variable_264 [label="variable: _mult\nuint256\ntests/contract_testcases/evm/rubixi.sol:107:22-27"]
+	number_literal_265 [label="uint256 literal: 300\ntests/contract_testcases/evm/rubixi.sol:107:30-33"]
+	less_266 [label="less\ntests/contract_testcases/evm/rubixi.sol:107:37-48"]
+	variable_267 [label="variable: _mult\nuint256\ntests/contract_testcases/evm/rubixi.sol:107:37-42"]
+	number_literal_268 [label="uint256 literal: 120\ntests/contract_testcases/evm/rubixi.sol:107:45-48"]
+	revert_269 [label="revert\ntests/contract_testcases/evm/rubixi.sol:107:50-58"]
+	expr_270 [label="expression\ntests/contract_testcases/evm/rubixi.sol:109:18-43"]
+	assign_271 [label="assign\nuint256\ntests/contract_testcases/evm/rubixi.sol:109:18-35"]
+	storage_var_272 [label="storage variable\nRubixi.pyramidMultiplier\nuint256 storage\ntests/contract_testcases/evm/rubixi.sol:109:18-35"]
+	variable_273 [label="variable: _mult\nuint256\ntests/contract_testcases/evm/rubixi.sol:109:38-43"]
 	changeFeePercentage [label="function changeFeePercentage\ncontract: Rubixi\ntests/contract_testcases/evm/rubixi.sol:112:10-66\nsignature changeFeePercentage(uint256)\nvisibility public\nmutability nonpayable"]
-	parameters_279 [label="parameters\nuint256 _fee"]
-	if_280 [label="if\ntests/contract_testcases/evm/rubixi.sol:113:18-42"]
-	more_281 [label="more\ntests/contract_testcases/evm/rubixi.sol:113:22-31"]
-	variable_282 [label="variable: _fee\nuint256\ntests/contract_testcases/evm/rubixi.sol:113:22-26"]
-	number_literal_283 [label="uint256 literal: 10\ntests/contract_testcases/evm/rubixi.sol:113:29-31"]
-	expr_284 [label="expression\ntests/contract_testcases/evm/rubixi.sol:113:33-41"]
-	builtins_285 [label="builtin Revert\ntests/contract_testcases/evm/rubixi.sol:113:33-39"]
-	expr_286 [label="expression\ntests/contract_testcases/evm/rubixi.sol:115:18-35"]
-	assign_287 [label="assign\nuint256\ntests/contract_testcases/evm/rubixi.sol:115:18-28"]
-	storage_var_288 [label="storage variable\nRubixi.feePercent\nuint256 storage\ntests/contract_testcases/evm/rubixi.sol:115:18-28"]
-	variable_289 [label="variable: _fee\nuint256\ntests/contract_testcases/evm/rubixi.sol:115:31-35"]
+	parameters_275 [label="parameters\nuint256 _fee"]
+	if_276 [label="if\ntests/contract_testcases/evm/rubixi.sol:113:18-42"]
+	more_277 [label="more\ntests/contract_testcases/evm/rubixi.sol:113:22-31"]
+	variable_278 [label="variable: _fee\nuint256\ntests/contract_testcases/evm/rubixi.sol:113:22-26"]
+	number_literal_279 [label="uint256 literal: 10\ntests/contract_testcases/evm/rubixi.sol:113:29-31"]
+	revert_280 [label="revert\ntests/contract_testcases/evm/rubixi.sol:113:33-41"]
+	expr_281 [label="expression\ntests/contract_testcases/evm/rubixi.sol:115:18-35"]
+	assign_282 [label="assign\nuint256\ntests/contract_testcases/evm/rubixi.sol:115:18-28"]
+	storage_var_283 [label="storage variable\nRubixi.feePercent\nuint256 storage\ntests/contract_testcases/evm/rubixi.sol:115:18-28"]
+	variable_284 [label="variable: _fee\nuint256\ntests/contract_testcases/evm/rubixi.sol:115:31-35"]
 	currentMultiplier [label="function currentMultiplier\ncontract: Rubixi\ntests/contract_testcases/evm/rubixi.sol:119:10-95\nsignature currentMultiplier()\nvisibility public\nmutability view"]
 	returns [label="returns\nuint256 multiplier\nstring info"]
-	expr_292 [label="expression\ntests/contract_testcases/evm/rubixi.sol:120:18-48"]
-	assign_293 [label="assign\nuint256\ntests/contract_testcases/evm/rubixi.sol:120:18-48"]
-	variable_294 [label="variable: multiplier\nuint256\ntests/contract_testcases/evm/rubixi.sol:120:18-28"]
-	storage_load_295 [label="storage load uint256\ntests/contract_testcases/evm/rubixi.sol:120:31-48"]
-	storage_var_296 [label="storage variable\nRubixi.pyramidMultiplier\nuint256 storage\ntests/contract_testcases/evm/rubixi.sol:120:31-48"]
-	expr_297 [label="expression\ntests/contract_testcases/evm/rubixi.sol:121:18-314"]
-	assign_298 [label="assign\nstring\ntests/contract_testcases/evm/rubixi.sol:121:18-314"]
-	variable_299 [label="variable: info\nstring\ntests/contract_testcases/evm/rubixi.sol:121:18-22"]
+	expr_287 [label="expression\ntests/contract_testcases/evm/rubixi.sol:120:18-48"]
+	assign_288 [label="assign\nuint256\ntests/contract_testcases/evm/rubixi.sol:120:18-48"]
+	variable_289 [label="variable: multiplier\nuint256\ntests/contract_testcases/evm/rubixi.sol:120:18-28"]
+	storage_load_290 [label="storage load uint256\ntests/contract_testcases/evm/rubixi.sol:120:31-48"]
+	storage_var_291 [label="storage variable\nRubixi.pyramidMultiplier\nuint256 storage\ntests/contract_testcases/evm/rubixi.sol:120:31-48"]
+	expr_292 [label="expression\ntests/contract_testcases/evm/rubixi.sol:121:18-314"]
+	assign_293 [label="assign\nstring\ntests/contract_testcases/evm/rubixi.sol:121:18-314"]
+	variable_294 [label="variable: info\nstring\ntests/contract_testcases/evm/rubixi.sol:121:18-22"]
 	alloc_array [label="alloc array string\ninitializer: 54686973206d756c7469706c696572206170706c69657320746f20796f7520617320736f6f6e206173207472616e73616374696f6e2069732072656365697665642c206d6179206265206c6f776572656420746f2068617374656e207061796f757473206f7220696e63726561736564206966207061796f75747320617265206661737420656e6f7567682e2044756520746f206e6f20666c6f6174206f7220646563696d616c732c206d756c7469706c696572206973207831303020666f722061206672616374696f6e616c206d756c7469706c69657220652e672e203235302069732061637475616c6c79206120322e3578206d756c7469706c6965722e20436170706564206174203378206d617820616e6420312e3278206d696e2e\ntests/contract_testcases/evm/rubixi.sol:121:25-314"]
-	number_literal_301 [label="uint32 literal: 287\ntests/contract_testcases/evm/rubixi.sol:121:25-314"]
+	number_literal_296 [label="uint32 literal: 287\ntests/contract_testcases/evm/rubixi.sol:121:25-314"]
 	currentFeePercentage [label="function currentFeePercentage\ncontract: Rubixi\ntests/contract_testcases/evm/rubixi.sol:124:10-91\nsignature currentFeePercentage()\nvisibility public\nmutability view"]
-	returns_303 [label="returns\nuint256 fee\nstring info"]
-	expr_304 [label="expression\ntests/contract_testcases/evm/rubixi.sol:125:18-34"]
-	assign_305 [label="assign\nuint256\ntests/contract_testcases/evm/rubixi.sol:125:18-34"]
-	variable_306 [label="variable: fee\nuint256\ntests/contract_testcases/evm/rubixi.sol:125:18-21"]
-	storage_load_307 [label="storage load uint256\ntests/contract_testcases/evm/rubixi.sol:125:24-34"]
-	storage_var_308 [label="storage variable\nRubixi.feePercent\nuint256 storage\ntests/contract_testcases/evm/rubixi.sol:125:24-34"]
-	expr_309 [label="expression\ntests/contract_testcases/evm/rubixi.sol:126:18-159"]
-	assign_310 [label="assign\nstring\ntests/contract_testcases/evm/rubixi.sol:126:18-159"]
-	variable_311 [label="variable: info\nstring\ntests/contract_testcases/evm/rubixi.sol:126:18-22"]
-	alloc_array_312 [label="alloc array string\ninitializer: 53686f776e20696e202520666f726d2e204665652069732068616c766564283530252920666f7220616d6f756e747320657175616c206f722067726561746572207468616e203530206574686572732e2028466565206d6179206368616e67652c206275742069732063617070656420746f2061206d6178696d756d206f662031302529\ntests/contract_testcases/evm/rubixi.sol:126:25-159"]
-	number_literal_313 [label="uint32 literal: 132\ntests/contract_testcases/evm/rubixi.sol:126:25-159"]
+	returns_298 [label="returns\nuint256 fee\nstring info"]
+	expr_299 [label="expression\ntests/contract_testcases/evm/rubixi.sol:125:18-34"]
+	assign_300 [label="assign\nuint256\ntests/contract_testcases/evm/rubixi.sol:125:18-34"]
+	variable_301 [label="variable: fee\nuint256\ntests/contract_testcases/evm/rubixi.sol:125:18-21"]
+	storage_load_302 [label="storage load uint256\ntests/contract_testcases/evm/rubixi.sol:125:24-34"]
+	storage_var_303 [label="storage variable\nRubixi.feePercent\nuint256 storage\ntests/contract_testcases/evm/rubixi.sol:125:24-34"]
+	expr_304 [label="expression\ntests/contract_testcases/evm/rubixi.sol:126:18-159"]
+	assign_305 [label="assign\nstring\ntests/contract_testcases/evm/rubixi.sol:126:18-159"]
+	variable_306 [label="variable: info\nstring\ntests/contract_testcases/evm/rubixi.sol:126:18-22"]
+	alloc_array_307 [label="alloc array string\ninitializer: 53686f776e20696e202520666f726d2e204665652069732068616c766564283530252920666f7220616d6f756e747320657175616c206f722067726561746572207468616e203530206574686572732e2028466565206d6179206368616e67652c206275742069732063617070656420746f2061206d6178696d756d206f662031302529\ntests/contract_testcases/evm/rubixi.sol:126:25-159"]
+	number_literal_308 [label="uint32 literal: 132\ntests/contract_testcases/evm/rubixi.sol:126:25-159"]
 	currentPyramidBalanceApproximately [label="function currentPyramidBalanceApproximately\ncontract: Rubixi\ntests/contract_testcases/evm/rubixi.sol:129:10-116\nsignature currentPyramidBalanceApproximately()\nvisibility public\nmutability view"]
-	returns_315 [label="returns\nuint256 pyramidBalance\nstring info"]
-	expr_316 [label="expression\ntests/contract_testcases/evm/rubixi.sol:130:18-52"]
-	assign_317 [label="assign\nuint256\ntests/contract_testcases/evm/rubixi.sol:130:18-52"]
-	variable_318 [label="variable: pyramidBalance\nuint256\ntests/contract_testcases/evm/rubixi.sol:130:18-32"]
-	divide_319 [label="divide\nuint256\ntests/contract_testcases/evm/rubixi.sol:130:35-52"]
-	storage_load_320 [label="storage load uint256\ntests/contract_testcases/evm/rubixi.sol:130:35-42"]
-	storage_var_321 [label="storage variable\nRubixi.balance\nuint256 storage\ntests/contract_testcases/evm/rubixi.sol:130:35-42"]
-	number_literal_322 [label="uint256 literal: 1000000000000000000\ntests/contract_testcases/evm/rubixi.sol:130:45-52"]
-	expr_323 [label="expression\ntests/contract_testcases/evm/rubixi.sol:131:18-229"]
-	assign_324 [label="assign\nstring\ntests/contract_testcases/evm/rubixi.sol:131:18-229"]
-	variable_325 [label="variable: info\nstring\ntests/contract_testcases/evm/rubixi.sol:131:18-22"]
-	alloc_array_326 [label="alloc array string\ninitializer: 416c6c2062616c616e63652076616c75657320617265206d6561737572656420696e204574686572732c206e6f746520746861742064756520746f206e6f20646563696d616c20706c6163696e672c2074686573652076616c7565732073686f7720757020617320696e746567657273206f6e6c792c2077697468696e2074686520636f6e747261637420697473656c6620796f752077696c6c206765742074686520657861637420646563696d616c2076616c756520796f752061726520737570706f73656420746f\ntests/contract_testcases/evm/rubixi.sol:131:25-229"]
-	number_literal_327 [label="uint32 literal: 202\ntests/contract_testcases/evm/rubixi.sol:131:25-229"]
+	returns_310 [label="returns\nuint256 pyramidBalance\nstring info"]
+	expr_311 [label="expression\ntests/contract_testcases/evm/rubixi.sol:130:18-52"]
+	assign_312 [label="assign\nuint256\ntests/contract_testcases/evm/rubixi.sol:130:18-52"]
+	variable_313 [label="variable: pyramidBalance\nuint256\ntests/contract_testcases/evm/rubixi.sol:130:18-32"]
+	divide_314 [label="divide\nuint256\ntests/contract_testcases/evm/rubixi.sol:130:35-52"]
+	storage_load_315 [label="storage load uint256\ntests/contract_testcases/evm/rubixi.sol:130:35-42"]
+	storage_var_316 [label="storage variable\nRubixi.balance\nuint256 storage\ntests/contract_testcases/evm/rubixi.sol:130:35-42"]
+	number_literal_317 [label="uint256 literal: 1000000000000000000\ntests/contract_testcases/evm/rubixi.sol:130:45-52"]
+	expr_318 [label="expression\ntests/contract_testcases/evm/rubixi.sol:131:18-229"]
+	assign_319 [label="assign\nstring\ntests/contract_testcases/evm/rubixi.sol:131:18-229"]
+	variable_320 [label="variable: info\nstring\ntests/contract_testcases/evm/rubixi.sol:131:18-22"]
+	alloc_array_321 [label="alloc array string\ninitializer: 416c6c2062616c616e63652076616c75657320617265206d6561737572656420696e204574686572732c206e6f746520746861742064756520746f206e6f20646563696d616c20706c6163696e672c2074686573652076616c7565732073686f7720757020617320696e746567657273206f6e6c792c2077697468696e2074686520636f6e747261637420697473656c6620796f752077696c6c206765742074686520657861637420646563696d616c2076616c756520796f752061726520737570706f73656420746f\ntests/contract_testcases/evm/rubixi.sol:131:25-229"]
+	number_literal_322 [label="uint32 literal: 202\ntests/contract_testcases/evm/rubixi.sol:131:25-229"]
 	nextPayoutWhenPyramidBalanceTotalsApproximately [label="function nextPayoutWhenPyramidBalanceTotalsApproximately\ncontract: Rubixi\ntests/contract_testcases/evm/rubixi.sol:134:10-108\nsignature nextPayoutWhenPyramidBalanceTotalsApproximately()\nvisibility public\nmutability view"]
-	returns_329 [label="returns\nuint256 balancePayout"]
-	expr_330 [label="expression\ntests/contract_testcases/evm/rubixi.sol:135:18-76"]
-	assign_331 [label="assign\nuint256\ntests/contract_testcases/evm/rubixi.sol:135:18-76"]
-	variable_332 [label="variable: balancePayout\nuint256\ntests/contract_testcases/evm/rubixi.sol:135:18-31"]
-	divide_333 [label="divide\nuint256\ntests/contract_testcases/evm/rubixi.sol:135:34-76"]
-	storage_load_334 [label="storage load uint256\ntests/contract_testcases/evm/rubixi.sol:135:34-66"]
-	structmember_335 [label="struct member #1 uint256 storage\ntests/contract_testcases/evm/rubixi.sol:135:60-66"]
-	subscript_336 [label="subscript struct Rubixi.Participant[] storage\ntests/contract_testcases/evm/rubixi.sol:135:34-59"]
-	storage_var_337 [label="storage variable\nRubixi.participants\nstruct Rubixi.Participant[] storage\ntests/contract_testcases/evm/rubixi.sol:135:34-46"]
-	storage_load_338 [label="storage load uint256\ntests/contract_testcases/evm/rubixi.sol:135:47-58"]
-	storage_var_339 [label="storage variable\nRubixi.payoutOrder\nuint256 storage\ntests/contract_testcases/evm/rubixi.sol:135:47-58"]
-	number_literal_340 [label="uint256 literal: 1000000000000000000\ntests/contract_testcases/evm/rubixi.sol:135:69-76"]
+	returns_324 [label="returns\nuint256 balancePayout"]
+	expr_325 [label="expression\ntests/contract_testcases/evm/rubixi.sol:135:18-76"]
+	assign_326 [label="assign\nuint256\ntests/contract_testcases/evm/rubixi.sol:135:18-76"]
+	variable_327 [label="variable: balancePayout\nuint256\ntests/contract_testcases/evm/rubixi.sol:135:18-31"]
+	divide_328 [label="divide\nuint256\ntests/contract_testcases/evm/rubixi.sol:135:34-76"]
+	storage_load_329 [label="storage load uint256\ntests/contract_testcases/evm/rubixi.sol:135:34-66"]
+	structmember_330 [label="struct member #1 uint256 storage\ntests/contract_testcases/evm/rubixi.sol:135:60-66"]
+	subscript_331 [label="subscript struct Rubixi.Participant[] storage\ntests/contract_testcases/evm/rubixi.sol:135:34-59"]
+	storage_var_332 [label="storage variable\nRubixi.participants\nstruct Rubixi.Participant[] storage\ntests/contract_testcases/evm/rubixi.sol:135:34-46"]
+	storage_load_333 [label="storage load uint256\ntests/contract_testcases/evm/rubixi.sol:135:47-58"]
+	storage_var_334 [label="storage variable\nRubixi.payoutOrder\nuint256 storage\ntests/contract_testcases/evm/rubixi.sol:135:47-58"]
+	number_literal_335 [label="uint256 literal: 1000000000000000000\ntests/contract_testcases/evm/rubixi.sol:135:69-76"]
 	feesSeperateFromBalanceApproximately [label="function feesSeperateFromBalanceApproximately\ncontract: Rubixi\ntests/contract_testcases/evm/rubixi.sol:138:10-88\nsignature feesSeperateFromBalanceApproximately()\nvisibility public\nmutability view"]
-	returns_342 [label="returns\nuint256 fees"]
-	expr_343 [label="expression\ntests/contract_testcases/evm/rubixi.sol:139:18-48"]
-	assign_344 [label="assign\nuint256\ntests/contract_testcases/evm/rubixi.sol:139:18-48"]
-	variable_345 [label="variable: fees\nuint256\ntests/contract_testcases/evm/rubixi.sol:139:18-22"]
-	divide_346 [label="divide\nuint256\ntests/contract_testcases/evm/rubixi.sol:139:25-48"]
-	storage_load_347 [label="storage load uint256\ntests/contract_testcases/evm/rubixi.sol:139:25-38"]
-	storage_var_348 [label="storage variable\nRubixi.collectedFees\nuint256 storage\ntests/contract_testcases/evm/rubixi.sol:139:25-38"]
-	number_literal_349 [label="uint256 literal: 1000000000000000000\ntests/contract_testcases/evm/rubixi.sol:139:41-48"]
+	returns_337 [label="returns\nuint256 fees"]
+	expr_338 [label="expression\ntests/contract_testcases/evm/rubixi.sol:139:18-48"]
+	assign_339 [label="assign\nuint256\ntests/contract_testcases/evm/rubixi.sol:139:18-48"]
+	variable_340 [label="variable: fees\nuint256\ntests/contract_testcases/evm/rubixi.sol:139:18-22"]
+	divide_341 [label="divide\nuint256\ntests/contract_testcases/evm/rubixi.sol:139:25-48"]
+	storage_load_342 [label="storage load uint256\ntests/contract_testcases/evm/rubixi.sol:139:25-38"]
+	storage_var_343 [label="storage variable\nRubixi.collectedFees\nuint256 storage\ntests/contract_testcases/evm/rubixi.sol:139:25-38"]
+	number_literal_344 [label="uint256 literal: 1000000000000000000\ntests/contract_testcases/evm/rubixi.sol:139:41-48"]
 	totalParticipants [label="function totalParticipants\ncontract: Rubixi\ntests/contract_testcases/evm/rubixi.sol:142:10-70\nsignature totalParticipants()\nvisibility public\nmutability view"]
-	returns_351 [label="returns\nuint256 count"]
-	expr_352 [label="expression\ntests/contract_testcases/evm/rubixi.sol:143:18-45"]
-	assign_353 [label="assign\nuint256\ntests/contract_testcases/evm/rubixi.sol:143:18-45"]
-	variable_354 [label="variable: count\nuint256\ntests/contract_testcases/evm/rubixi.sol:143:18-23"]
-	array_length_355 [label="array length uint256\nelement struct Rubixi.Participant\ntests/contract_testcases/evm/rubixi.sol:143:39-45"]
-	storage_var_356 [label="storage variable\nRubixi.participants\nstruct Rubixi.Participant[] storage\ntests/contract_testcases/evm/rubixi.sol:143:26-38"]
+	returns_346 [label="returns\nuint256 count"]
+	expr_347 [label="expression\ntests/contract_testcases/evm/rubixi.sol:143:18-45"]
+	assign_348 [label="assign\nuint256\ntests/contract_testcases/evm/rubixi.sol:143:18-45"]
+	variable_349 [label="variable: count\nuint256\ntests/contract_testcases/evm/rubixi.sol:143:18-23"]
+	array_length_350 [label="array length uint256\nelement struct Rubixi.Participant\ntests/contract_testcases/evm/rubixi.sol:143:39-45"]
+	storage_var_351 [label="storage variable\nRubixi.participants\nstruct Rubixi.Participant[] storage\ntests/contract_testcases/evm/rubixi.sol:143:26-38"]
 	numberOfParticipantsWaitingForPayout [label="function numberOfParticipantsWaitingForPayout\ncontract: Rubixi\ntests/contract_testcases/evm/rubixi.sol:146:10-89\nsignature numberOfParticipantsWaitingForPayout()\nvisibility public\nmutability view"]
-	returns_358 [label="returns\nuint256 count"]
-	expr_359 [label="expression\ntests/contract_testcases/evm/rubixi.sol:147:18-59"]
-	assign_360 [label="assign\nuint256\ntests/contract_testcases/evm/rubixi.sol:147:18-59"]
-	variable_361 [label="variable: count\nuint256\ntests/contract_testcases/evm/rubixi.sol:147:18-23"]
-	subtract_362 [label="subtract\nuint256\ntests/contract_testcases/evm/rubixi.sol:147:26-59"]
-	array_length_363 [label="array length uint256\nelement struct Rubixi.Participant\ntests/contract_testcases/evm/rubixi.sol:147:39-45"]
-	storage_var_364 [label="storage variable\nRubixi.participants\nstruct Rubixi.Participant[] storage\ntests/contract_testcases/evm/rubixi.sol:147:26-38"]
-	storage_load_365 [label="storage load uint256\ntests/contract_testcases/evm/rubixi.sol:147:48-59"]
-	storage_var_366 [label="storage variable\nRubixi.payoutOrder\nuint256 storage\ntests/contract_testcases/evm/rubixi.sol:147:48-59"]
+	returns_353 [label="returns\nuint256 count"]
+	expr_354 [label="expression\ntests/contract_testcases/evm/rubixi.sol:147:18-59"]
+	assign_355 [label="assign\nuint256\ntests/contract_testcases/evm/rubixi.sol:147:18-59"]
+	variable_356 [label="variable: count\nuint256\ntests/contract_testcases/evm/rubixi.sol:147:18-23"]
+	subtract_357 [label="subtract\nuint256\ntests/contract_testcases/evm/rubixi.sol:147:26-59"]
+	array_length_358 [label="array length uint256\nelement struct Rubixi.Participant\ntests/contract_testcases/evm/rubixi.sol:147:39-45"]
+	storage_var_359 [label="storage variable\nRubixi.participants\nstruct Rubixi.Participant[] storage\ntests/contract_testcases/evm/rubixi.sol:147:26-38"]
+	storage_load_360 [label="storage load uint256\ntests/contract_testcases/evm/rubixi.sol:147:48-59"]
+	storage_var_361 [label="storage variable\nRubixi.payoutOrder\nuint256 storage\ntests/contract_testcases/evm/rubixi.sol:147:48-59"]
 	participantDetails [label="function participantDetails\ncontract: Rubixi\ntests/contract_testcases/evm/rubixi.sol:150:10-108\nsignature participantDetails(uint256)\nvisibility public\nmutability view"]
-	parameters_368 [label="parameters\nuint256 orderInPyramid"]
-	returns_369 [label="returns\naddress Address\nuint256 Payout"]
-	if_370 [label="if\ntests/contract_testcases/evm/rubixi.sol:151:18-154:19"]
+	parameters_363 [label="parameters\nuint256 orderInPyramid"]
+	returns_364 [label="returns\naddress Address\nuint256 Payout"]
+	if_365 [label="if\ntests/contract_testcases/evm/rubixi.sol:151:18-154:19"]
 	less_equal [label="less equal\ntests/contract_testcases/evm/rubixi.sol:151:22-59"]
-	variable_372 [label="variable: orderInPyramid\nuint256\ntests/contract_testcases/evm/rubixi.sol:151:22-36"]
-	array_length_373 [label="array length uint256\nelement struct Rubixi.Participant\ntests/contract_testcases/evm/rubixi.sol:151:53-59"]
-	storage_var_374 [label="storage variable\nRubixi.participants\nstruct Rubixi.Participant[] storage\ntests/contract_testcases/evm/rubixi.sol:151:40-52"]
-	expr_375 [label="expression\ntests/contract_testcases/evm/rubixi.sol:153:26-80"]
-	assign_376 [label="assign\nuint256\ntests/contract_testcases/evm/rubixi.sol:153:26-80"]
-	variable_377 [label="variable: Payout\nuint256\ntests/contract_testcases/evm/rubixi.sol:153:26-32"]
-	divide_378 [label="divide\nuint256\ntests/contract_testcases/evm/rubixi.sol:153:35-80"]
-	storage_load_379 [label="storage load uint256\ntests/contract_testcases/evm/rubixi.sol:153:35-70"]
-	structmember_380 [label="struct member #1 uint256 storage\ntests/contract_testcases/evm/rubixi.sol:153:64-70"]
-	subscript_381 [label="subscript struct Rubixi.Participant[] storage\ntests/contract_testcases/evm/rubixi.sol:153:35-63"]
-	storage_var_382 [label="storage variable\nRubixi.participants\nstruct Rubixi.Participant[] storage\ntests/contract_testcases/evm/rubixi.sol:153:35-47"]
-	variable_383 [label="variable: orderInPyramid\nuint256\ntests/contract_testcases/evm/rubixi.sol:153:48-62"]
-	number_literal_384 [label="uint256 literal: 1000000000000000000\ntests/contract_testcases/evm/rubixi.sol:153:73-80"]
+	variable_367 [label="variable: orderInPyramid\nuint256\ntests/contract_testcases/evm/rubixi.sol:151:22-36"]
+	array_length_368 [label="array length uint256\nelement struct Rubixi.Participant\ntests/contract_testcases/evm/rubixi.sol:151:53-59"]
+	storage_var_369 [label="storage variable\nRubixi.participants\nstruct Rubixi.Participant[] storage\ntests/contract_testcases/evm/rubixi.sol:151:40-52"]
+	expr_370 [label="expression\ntests/contract_testcases/evm/rubixi.sol:153:26-80"]
+	assign_371 [label="assign\nuint256\ntests/contract_testcases/evm/rubixi.sol:153:26-80"]
+	variable_372 [label="variable: Payout\nuint256\ntests/contract_testcases/evm/rubixi.sol:153:26-32"]
+	divide_373 [label="divide\nuint256\ntests/contract_testcases/evm/rubixi.sol:153:35-80"]
+	storage_load_374 [label="storage load uint256\ntests/contract_testcases/evm/rubixi.sol:153:35-70"]
+	structmember_375 [label="struct member #1 uint256 storage\ntests/contract_testcases/evm/rubixi.sol:153:64-70"]
+	subscript_376 [label="subscript struct Rubixi.Participant[] storage\ntests/contract_testcases/evm/rubixi.sol:153:35-63"]
+	storage_var_377 [label="storage variable\nRubixi.participants\nstruct Rubixi.Participant[] storage\ntests/contract_testcases/evm/rubixi.sol:153:35-47"]
+	variable_378 [label="variable: orderInPyramid\nuint256\ntests/contract_testcases/evm/rubixi.sol:153:48-62"]
+	number_literal_379 [label="uint256 literal: 1000000000000000000\ntests/contract_testcases/evm/rubixi.sol:153:73-80"]
 	diagnostic [label="pragma 'solidity' is ignored\nlevel Debug\ntests/contract_testcases/evm/rubixi.sol:2:2-25"]
-	diagnostic_387 [label="found contract 'Rubixi'\nlevel Debug\ntests/contract_testcases/evm/rubixi.sol:4:2-156:3"]
-	diagnostic_388 [label="local variable 'payoutToSend' has been assigned, but never read\nlevel Warning\ntests/contract_testcases/evm/rubixi.sol:67:31-43"]
-	diagnostic_389 [label="return variable 'Address' has never been assigned\nlevel Warning\ntests/contract_testcases/evm/rubixi.sol:150:87-94"]
+	diagnostic_382 [label="found contract 'Rubixi'\nlevel Debug\ntests/contract_testcases/evm/rubixi.sol:4:2-156:3"]
+	diagnostic_383 [label="local variable 'payoutToSend' has been assigned, but never read\nlevel Warning\ntests/contract_testcases/evm/rubixi.sol:67:31-43"]
+	diagnostic_384 [label="return variable 'Address' has never been assigned\nlevel Warning\ntests/contract_testcases/evm/rubixi.sol:150:87-94"]
 	structs -> Participant
 	contracts -> contract
 	contract -> var [label="variable"]
@@ -552,225 +547,220 @@ strict digraph "tests/contract_testcases/evm/rubixi.sol" {
 	equal_164 -> storage_load_165 [label="left"]
 	storage_load_165 -> storage_var_166 [label="expr"]
 	equal_164 -> number_literal_167 [label="right"]
-	if_163 -> expr_168 [label="then"]
-	expr_168 -> builtins_169 [label="expr"]
-	if_163 -> expr_170 [label="next"]
-	expr_170 -> builtins_171 [label="expr"]
-	builtins_171 -> cast_172 [label="arg #0"]
-	cast_172 -> storage_load_173 [label="expr"]
-	storage_load_173 -> storage_var_174 [label="expr"]
-	builtins_171 -> cast_175 [label="arg #1"]
-	cast_175 -> trunc [label="expr"]
-	trunc -> storage_load_177 [label="expr"]
-	storage_load_177 -> storage_var_178 [label="expr"]
-	expr_170 -> expr_179 [label="next"]
-	expr_179 -> assign_180 [label="expr"]
-	assign_180 -> storage_var_181 [label="left"]
-	assign_180 -> number_literal_182 [label="right"]
+	if_163 -> revert [label="then"]
+	if_163 -> expr_169 [label="next"]
+	expr_169 -> builtins_170 [label="expr"]
+	builtins_170 -> cast_171 [label="arg #0"]
+	cast_171 -> storage_load_172 [label="expr"]
+	storage_load_172 -> storage_var_173 [label="expr"]
+	builtins_170 -> cast_174 [label="arg #1"]
+	cast_174 -> trunc [label="expr"]
+	trunc -> storage_load_176 [label="expr"]
+	storage_load_176 -> storage_var_177 [label="expr"]
+	expr_169 -> expr_178 [label="next"]
+	expr_178 -> assign_179 [label="expr"]
+	assign_179 -> storage_var_180 [label="left"]
+	assign_179 -> number_literal_181 [label="right"]
 	contract -> collectFeesInEther [label="function"]
-	collectFeesInEther -> parameters_184 [label="parameters"]
-	collectFeesInEther -> expr_185 [label="body"]
-	expr_185 -> assign_186 [label="expr"]
-	assign_186 -> variable_187 [label="left"]
-	assign_186 -> multiply_188 [label="right"]
-	multiply_188 -> variable_189 [label="left"]
-	multiply_188 -> number_literal_190 [label="right"]
-	expr_185 -> if_191 [label="next"]
-	if_191 -> more_192 [label="cond"]
-	more_192 -> variable_193 [label="left"]
-	more_192 -> storage_load_194 [label="right"]
-	storage_load_194 -> storage_var_195 [label="expr"]
-	if_191 -> expr_196 [label="then"]
-	expr_196 -> call_internal_function_197 [label="expr"]
-	call_internal_function_197 -> internal_function_198 [label="function"]
-	if_191 -> if_199 [label="next"]
-	if_199 -> equal_200 [label="cond"]
-	equal_200 -> storage_load_201 [label="left"]
-	storage_load_201 -> storage_var_202 [label="expr"]
-	equal_200 -> number_literal_203 [label="right"]
-	if_199 -> expr_204 [label="then"]
+	collectFeesInEther -> parameters_183 [label="parameters"]
+	collectFeesInEther -> expr_184 [label="body"]
+	expr_184 -> assign_185 [label="expr"]
+	assign_185 -> variable_186 [label="left"]
+	assign_185 -> multiply_187 [label="right"]
+	multiply_187 -> variable_188 [label="left"]
+	multiply_187 -> number_literal_189 [label="right"]
+	expr_184 -> if_190 [label="next"]
+	if_190 -> more_191 [label="cond"]
+	more_191 -> variable_192 [label="left"]
+	more_191 -> storage_load_193 [label="right"]
+	storage_load_193 -> storage_var_194 [label="expr"]
+	if_190 -> expr_195 [label="then"]
+	expr_195 -> call_internal_function_196 [label="expr"]
+	call_internal_function_196 -> internal_function_197 [label="function"]
+	if_190 -> if_198 [label="next"]
+	if_198 -> equal_199 [label="cond"]
+	equal_199 -> storage_load_200 [label="left"]
+	storage_load_200 -> storage_var_201 [label="expr"]
+	equal_199 -> number_literal_202 [label="right"]
+	if_198 -> revert_203 [label="then"]
+	if_198 -> expr_204 [label="next"]
 	expr_204 -> builtins_205 [label="expr"]
-	if_199 -> expr_206 [label="next"]
-	expr_206 -> builtins_207 [label="expr"]
-	builtins_207 -> cast_208 [label="arg #0"]
-	cast_208 -> storage_load_209 [label="expr"]
-	storage_load_209 -> storage_var_210 [label="expr"]
-	builtins_207 -> cast_211 [label="arg #1"]
-	cast_211 -> trunc_212 [label="expr"]
-	trunc_212 -> variable_213 [label="expr"]
-	expr_206 -> expr_214 [label="next"]
-	expr_214 -> assign_215 [label="expr"]
-	assign_215 -> storage_var_216 [label="left"]
-	assign_215 -> subtract_217 [label="right"]
-	subtract_217 -> storage_load_218 [label="left"]
-	storage_load_218 -> storage_var_219 [label="expr"]
-	subtract_217 -> variable_220 [label="right"]
+	builtins_205 -> cast_206 [label="arg #0"]
+	cast_206 -> storage_load_207 [label="expr"]
+	storage_load_207 -> storage_var_208 [label="expr"]
+	builtins_205 -> cast_209 [label="arg #1"]
+	cast_209 -> trunc_210 [label="expr"]
+	trunc_210 -> variable_211 [label="expr"]
+	expr_204 -> expr_212 [label="next"]
+	expr_212 -> assign_213 [label="expr"]
+	assign_213 -> storage_var_214 [label="left"]
+	assign_213 -> subtract_215 [label="right"]
+	subtract_215 -> storage_load_216 [label="left"]
+	storage_load_216 -> storage_var_217 [label="expr"]
+	subtract_215 -> variable_218 [label="right"]
 	contract -> collectPercentOfFees [label="function"]
-	collectPercentOfFees -> parameters_222 [label="parameters"]
-	collectPercentOfFees -> if_223 [label="body"]
-	if_223 -> logical_or [label="cond"]
-	logical_or -> equal_225 [label="left"]
-	equal_225 -> storage_load_226 [label="left"]
-	storage_load_226 -> storage_var_227 [label="expr"]
-	equal_225 -> number_literal_228 [label="right"]
-	logical_or -> more_229 [label="right"]
-	more_229 -> variable_230 [label="left"]
-	more_229 -> number_literal_231 [label="right"]
-	if_223 -> expr_232 [label="then"]
-	expr_232 -> builtins_233 [label="expr"]
-	if_223 -> var_decl_234 [label="next"]
-	var_decl_234 -> multiply_235 [label="init"]
-	multiply_235 -> divide_236 [label="left"]
-	divide_236 -> storage_load_237 [label="left"]
-	storage_load_237 -> storage_var_238 [label="expr"]
-	divide_236 -> number_literal_239 [label="right"]
-	multiply_235 -> variable_240 [label="right"]
-	var_decl_234 -> expr_241 [label="next"]
-	expr_241 -> builtins_242 [label="expr"]
-	builtins_242 -> cast_243 [label="arg #0"]
-	cast_243 -> storage_load_244 [label="expr"]
-	storage_load_244 -> storage_var_245 [label="expr"]
-	builtins_242 -> cast_246 [label="arg #1"]
-	cast_246 -> trunc_247 [label="expr"]
-	trunc_247 -> variable_248 [label="expr"]
-	expr_241 -> expr_249 [label="next"]
-	expr_249 -> assign_250 [label="expr"]
-	assign_250 -> storage_var_251 [label="left"]
-	assign_250 -> subtract_252 [label="right"]
-	subtract_252 -> storage_load_253 [label="left"]
-	storage_load_253 -> storage_var_254 [label="expr"]
-	subtract_252 -> variable_255 [label="right"]
+	collectPercentOfFees -> parameters_220 [label="parameters"]
+	collectPercentOfFees -> if_221 [label="body"]
+	if_221 -> logical_or [label="cond"]
+	logical_or -> equal_223 [label="left"]
+	equal_223 -> storage_load_224 [label="left"]
+	storage_load_224 -> storage_var_225 [label="expr"]
+	equal_223 -> number_literal_226 [label="right"]
+	logical_or -> more_227 [label="right"]
+	more_227 -> variable_228 [label="left"]
+	more_227 -> number_literal_229 [label="right"]
+	if_221 -> revert_230 [label="then"]
+	if_221 -> var_decl_231 [label="next"]
+	var_decl_231 -> multiply_232 [label="init"]
+	multiply_232 -> divide_233 [label="left"]
+	divide_233 -> storage_load_234 [label="left"]
+	storage_load_234 -> storage_var_235 [label="expr"]
+	divide_233 -> number_literal_236 [label="right"]
+	multiply_232 -> variable_237 [label="right"]
+	var_decl_231 -> expr_238 [label="next"]
+	expr_238 -> builtins_239 [label="expr"]
+	builtins_239 -> cast_240 [label="arg #0"]
+	cast_240 -> storage_load_241 [label="expr"]
+	storage_load_241 -> storage_var_242 [label="expr"]
+	builtins_239 -> cast_243 [label="arg #1"]
+	cast_243 -> trunc_244 [label="expr"]
+	trunc_244 -> variable_245 [label="expr"]
+	expr_238 -> expr_246 [label="next"]
+	expr_246 -> assign_247 [label="expr"]
+	assign_247 -> storage_var_248 [label="left"]
+	assign_247 -> subtract_249 [label="right"]
+	subtract_249 -> storage_load_250 [label="left"]
+	storage_load_250 -> storage_var_251 [label="expr"]
+	subtract_249 -> variable_252 [label="right"]
 	contract -> changeOwner [label="function"]
-	changeOwner -> parameters_257 [label="parameters"]
-	changeOwner -> expr_258 [label="body"]
-	expr_258 -> assign_259 [label="expr"]
-	assign_259 -> storage_var_260 [label="left"]
-	assign_259 -> variable_261 [label="right"]
+	changeOwner -> parameters_254 [label="parameters"]
+	changeOwner -> expr_255 [label="body"]
+	expr_255 -> assign_256 [label="expr"]
+	assign_256 -> storage_var_257 [label="left"]
+	assign_256 -> variable_258 [label="right"]
 	contract -> changeMultiplier [label="function"]
-	changeMultiplier -> parameters_263 [label="parameters"]
-	changeMultiplier -> if_264 [label="body"]
-	if_264 -> logical_or_265 [label="cond"]
-	logical_or_265 -> more_266 [label="left"]
-	more_266 -> variable_267 [label="left"]
-	more_266 -> number_literal_268 [label="right"]
-	logical_or_265 -> less_269 [label="right"]
-	less_269 -> variable_270 [label="left"]
-	less_269 -> number_literal_271 [label="right"]
-	if_264 -> expr_272 [label="then"]
-	expr_272 -> builtins_273 [label="expr"]
-	if_264 -> expr_274 [label="next"]
-	expr_274 -> assign_275 [label="expr"]
-	assign_275 -> storage_var_276 [label="left"]
-	assign_275 -> variable_277 [label="right"]
+	changeMultiplier -> parameters_260 [label="parameters"]
+	changeMultiplier -> if_261 [label="body"]
+	if_261 -> logical_or_262 [label="cond"]
+	logical_or_262 -> more_263 [label="left"]
+	more_263 -> variable_264 [label="left"]
+	more_263 -> number_literal_265 [label="right"]
+	logical_or_262 -> less_266 [label="right"]
+	less_266 -> variable_267 [label="left"]
+	less_266 -> number_literal_268 [label="right"]
+	if_261 -> revert_269 [label="then"]
+	if_261 -> expr_270 [label="next"]
+	expr_270 -> assign_271 [label="expr"]
+	assign_271 -> storage_var_272 [label="left"]
+	assign_271 -> variable_273 [label="right"]
 	contract -> changeFeePercentage [label="function"]
-	changeFeePercentage -> parameters_279 [label="parameters"]
-	changeFeePercentage -> if_280 [label="body"]
-	if_280 -> more_281 [label="cond"]
-	more_281 -> variable_282 [label="left"]
-	more_281 -> number_literal_283 [label="right"]
-	if_280 -> expr_284 [label="then"]
-	expr_284 -> builtins_285 [label="expr"]
-	if_280 -> expr_286 [label="next"]
-	expr_286 -> assign_287 [label="expr"]
-	assign_287 -> storage_var_288 [label="left"]
-	assign_287 -> variable_289 [label="right"]
+	changeFeePercentage -> parameters_275 [label="parameters"]
+	changeFeePercentage -> if_276 [label="body"]
+	if_276 -> more_277 [label="cond"]
+	more_277 -> variable_278 [label="left"]
+	more_277 -> number_literal_279 [label="right"]
+	if_276 -> revert_280 [label="then"]
+	if_276 -> expr_281 [label="next"]
+	expr_281 -> assign_282 [label="expr"]
+	assign_282 -> storage_var_283 [label="left"]
+	assign_282 -> variable_284 [label="right"]
 	contract -> currentMultiplier [label="function"]
 	currentMultiplier -> returns [label="returns"]
-	currentMultiplier -> expr_292 [label="body"]
+	currentMultiplier -> expr_287 [label="body"]
+	expr_287 -> assign_288 [label="expr"]
+	assign_288 -> variable_289 [label="left"]
+	assign_288 -> storage_load_290 [label="right"]
+	storage_load_290 -> storage_var_291 [label="expr"]
+	expr_287 -> expr_292 [label="next"]
 	expr_292 -> assign_293 [label="expr"]
 	assign_293 -> variable_294 [label="left"]
-	assign_293 -> storage_load_295 [label="right"]
-	storage_load_295 -> storage_var_296 [label="expr"]
-	expr_292 -> expr_297 [label="next"]
-	expr_297 -> assign_298 [label="expr"]
-	assign_298 -> variable_299 [label="left"]
-	assign_298 -> alloc_array [label="right"]
-	alloc_array -> number_literal_301 [label="length"]
+	assign_293 -> alloc_array [label="right"]
+	alloc_array -> number_literal_296 [label="length"]
 	contract -> currentFeePercentage [label="function"]
-	currentFeePercentage -> returns_303 [label="returns"]
-	currentFeePercentage -> expr_304 [label="body"]
+	currentFeePercentage -> returns_298 [label="returns"]
+	currentFeePercentage -> expr_299 [label="body"]
+	expr_299 -> assign_300 [label="expr"]
+	assign_300 -> variable_301 [label="left"]
+	assign_300 -> storage_load_302 [label="right"]
+	storage_load_302 -> storage_var_303 [label="expr"]
+	expr_299 -> expr_304 [label="next"]
 	expr_304 -> assign_305 [label="expr"]
 	assign_305 -> variable_306 [label="left"]
-	assign_305 -> storage_load_307 [label="right"]
-	storage_load_307 -> storage_var_308 [label="expr"]
-	expr_304 -> expr_309 [label="next"]
-	expr_309 -> assign_310 [label="expr"]
-	assign_310 -> variable_311 [label="left"]
-	assign_310 -> alloc_array_312 [label="right"]
-	alloc_array_312 -> number_literal_313 [label="length"]
+	assign_305 -> alloc_array_307 [label="right"]
+	alloc_array_307 -> number_literal_308 [label="length"]
 	contract -> currentPyramidBalanceApproximately [label="function"]
-	currentPyramidBalanceApproximately -> returns_315 [label="returns"]
-	currentPyramidBalanceApproximately -> expr_316 [label="body"]
-	expr_316 -> assign_317 [label="expr"]
-	assign_317 -> variable_318 [label="left"]
-	assign_317 -> divide_319 [label="right"]
-	divide_319 -> storage_load_320 [label="left"]
-	storage_load_320 -> storage_var_321 [label="expr"]
-	divide_319 -> number_literal_322 [label="right"]
-	expr_316 -> expr_323 [label="next"]
-	expr_323 -> assign_324 [label="expr"]
-	assign_324 -> variable_325 [label="left"]
-	assign_324 -> alloc_array_326 [label="right"]
-	alloc_array_326 -> number_literal_327 [label="length"]
+	currentPyramidBalanceApproximately -> returns_310 [label="returns"]
+	currentPyramidBalanceApproximately -> expr_311 [label="body"]
+	expr_311 -> assign_312 [label="expr"]
+	assign_312 -> variable_313 [label="left"]
+	assign_312 -> divide_314 [label="right"]
+	divide_314 -> storage_load_315 [label="left"]
+	storage_load_315 -> storage_var_316 [label="expr"]
+	divide_314 -> number_literal_317 [label="right"]
+	expr_311 -> expr_318 [label="next"]
+	expr_318 -> assign_319 [label="expr"]
+	assign_319 -> variable_320 [label="left"]
+	assign_319 -> alloc_array_321 [label="right"]
+	alloc_array_321 -> number_literal_322 [label="length"]
 	contract -> nextPayoutWhenPyramidBalanceTotalsApproximately [label="function"]
-	nextPayoutWhenPyramidBalanceTotalsApproximately -> returns_329 [label="returns"]
-	nextPayoutWhenPyramidBalanceTotalsApproximately -> expr_330 [label="body"]
-	expr_330 -> assign_331 [label="expr"]
-	assign_331 -> variable_332 [label="left"]
-	assign_331 -> divide_333 [label="right"]
-	divide_333 -> storage_load_334 [label="left"]
-	storage_load_334 -> structmember_335 [label="expr"]
-	structmember_335 -> subscript_336 [label="var"]
-	subscript_336 -> storage_var_337 [label="array"]
-	subscript_336 -> storage_load_338 [label="index"]
-	storage_load_338 -> storage_var_339 [label="expr"]
-	divide_333 -> number_literal_340 [label="right"]
+	nextPayoutWhenPyramidBalanceTotalsApproximately -> returns_324 [label="returns"]
+	nextPayoutWhenPyramidBalanceTotalsApproximately -> expr_325 [label="body"]
+	expr_325 -> assign_326 [label="expr"]
+	assign_326 -> variable_327 [label="left"]
+	assign_326 -> divide_328 [label="right"]
+	divide_328 -> storage_load_329 [label="left"]
+	storage_load_329 -> structmember_330 [label="expr"]
+	structmember_330 -> subscript_331 [label="var"]
+	subscript_331 -> storage_var_332 [label="array"]
+	subscript_331 -> storage_load_333 [label="index"]
+	storage_load_333 -> storage_var_334 [label="expr"]
+	divide_328 -> number_literal_335 [label="right"]
 	contract -> feesSeperateFromBalanceApproximately [label="function"]
-	feesSeperateFromBalanceApproximately -> returns_342 [label="returns"]
-	feesSeperateFromBalanceApproximately -> expr_343 [label="body"]
-	expr_343 -> assign_344 [label="expr"]
-	assign_344 -> variable_345 [label="left"]
-	assign_344 -> divide_346 [label="right"]
-	divide_346 -> storage_load_347 [label="left"]
-	storage_load_347 -> storage_var_348 [label="expr"]
-	divide_346 -> number_literal_349 [label="right"]
+	feesSeperateFromBalanceApproximately -> returns_337 [label="returns"]
+	feesSeperateFromBalanceApproximately -> expr_338 [label="body"]
+	expr_338 -> assign_339 [label="expr"]
+	assign_339 -> variable_340 [label="left"]
+	assign_339 -> divide_341 [label="right"]
+	divide_341 -> storage_load_342 [label="left"]
+	storage_load_342 -> storage_var_343 [label="expr"]
+	divide_341 -> number_literal_344 [label="right"]
 	contract -> totalParticipants [label="function"]
-	totalParticipants -> returns_351 [label="returns"]
-	totalParticipants -> expr_352 [label="body"]
-	expr_352 -> assign_353 [label="expr"]
-	assign_353 -> variable_354 [label="left"]
-	assign_353 -> array_length_355 [label="right"]
-	array_length_355 -> storage_var_356 [label="array"]
+	totalParticipants -> returns_346 [label="returns"]
+	totalParticipants -> expr_347 [label="body"]
+	expr_347 -> assign_348 [label="expr"]
+	assign_348 -> variable_349 [label="left"]
+	assign_348 -> array_length_350 [label="right"]
+	array_length_350 -> storage_var_351 [label="array"]
 	contract -> numberOfParticipantsWaitingForPayout [label="function"]
-	numberOfParticipantsWaitingForPayout -> returns_358 [label="returns"]
-	numberOfParticipantsWaitingForPayout -> expr_359 [label="body"]
-	expr_359 -> assign_360 [label="expr"]
-	assign_360 -> variable_361 [label="left"]
-	assign_360 -> subtract_362 [label="right"]
-	subtract_362 -> array_length_363 [label="left"]
-	array_length_363 -> storage_var_364 [label="array"]
-	subtract_362 -> storage_load_365 [label="right"]
-	storage_load_365 -> storage_var_366 [label="expr"]
+	numberOfParticipantsWaitingForPayout -> returns_353 [label="returns"]
+	numberOfParticipantsWaitingForPayout -> expr_354 [label="body"]
+	expr_354 -> assign_355 [label="expr"]
+	assign_355 -> variable_356 [label="left"]
+	assign_355 -> subtract_357 [label="right"]
+	subtract_357 -> array_length_358 [label="left"]
+	array_length_358 -> storage_var_359 [label="array"]
+	subtract_357 -> storage_load_360 [label="right"]
+	storage_load_360 -> storage_var_361 [label="expr"]
 	contract -> participantDetails [label="function"]
-	participantDetails -> parameters_368 [label="parameters"]
-	participantDetails -> returns_369 [label="returns"]
-	participantDetails -> if_370 [label="body"]
-	if_370 -> less_equal [label="cond"]
-	less_equal -> variable_372 [label="left"]
-	less_equal -> array_length_373 [label="right"]
-	array_length_373 -> storage_var_374 [label="array"]
-	if_370 -> expr_375 [label="then"]
-	expr_375 -> assign_376 [label="expr"]
-	assign_376 -> variable_377 [label="left"]
-	assign_376 -> divide_378 [label="right"]
-	divide_378 -> storage_load_379 [label="left"]
-	storage_load_379 -> structmember_380 [label="expr"]
-	structmember_380 -> subscript_381 [label="var"]
-	subscript_381 -> storage_var_382 [label="array"]
-	subscript_381 -> variable_383 [label="index"]
-	divide_378 -> number_literal_384 [label="right"]
+	participantDetails -> parameters_363 [label="parameters"]
+	participantDetails -> returns_364 [label="returns"]
+	participantDetails -> if_365 [label="body"]
+	if_365 -> less_equal [label="cond"]
+	less_equal -> variable_367 [label="left"]
+	less_equal -> array_length_368 [label="right"]
+	array_length_368 -> storage_var_369 [label="array"]
+	if_365 -> expr_370 [label="then"]
+	expr_370 -> assign_371 [label="expr"]
+	assign_371 -> variable_372 [label="left"]
+	assign_371 -> divide_373 [label="right"]
+	divide_373 -> storage_load_374 [label="left"]
+	storage_load_374 -> structmember_375 [label="expr"]
+	structmember_375 -> subscript_376 [label="var"]
+	subscript_376 -> storage_var_377 [label="array"]
+	subscript_376 -> variable_378 [label="index"]
+	divide_373 -> number_literal_379 [label="right"]
 	diagnostics -> diagnostic [label="Debug"]
-	diagnostics -> diagnostic_387 [label="Debug"]
-	diagnostics -> diagnostic_388 [label="Warning"]
-	diagnostics -> diagnostic_389 [label="Warning"]
+	diagnostics -> diagnostic_382 [label="Debug"]
+	diagnostics -> diagnostic_383 [label="Warning"]
+	diagnostics -> diagnostic_384 [label="Warning"]
 }

+ 8 - 4
tests/contract_testcases/solana/error.dot

@@ -1,14 +1,18 @@
 strict digraph "tests/contract_testcases/solana/error.sol" {
+	X [label="name:X\ncontract: 0\ntests/contract_testcases/solana/error.sol:3:8-9"]
 	contract [label="contract error\ntests/contract_testcases/solana/error.sol:2:1-8:2"]
 	foo [label="function foo\ncontract: error\ntests/contract_testcases/solana/error.sol:5:2-30\nsignature foo(bytes32)\nvisibility public\nmutability nonpayable"]
 	parameters [label="parameters\ncontract error x"]
 	diagnostic [label="found contract 'error'\nlevel Debug\ntests/contract_testcases/solana/error.sol:2:1-8:2"]
-	diagnostic_6 [label="function can be declared 'pure'\nlevel Warning\ntests/contract_testcases/solana/error.sol:5:2-30"]
-	diagnostic_7 [label="function parameter 'x' has never been read\nlevel Warning\ntests/contract_testcases/solana/error.sol:5:21-22"]
+	diagnostic_8 [label="error 'X' has never been used\nlevel Warning\ntests/contract_testcases/solana/error.sol:3:8-9"]
+	diagnostic_9 [label="function can be declared 'pure'\nlevel Warning\ntests/contract_testcases/solana/error.sol:5:2-30"]
+	diagnostic_10 [label="function parameter 'x' has never been read\nlevel Warning\ntests/contract_testcases/solana/error.sol:5:21-22"]
+	errors -> X
 	contracts -> contract
 	contract -> foo [label="function"]
 	foo -> parameters [label="parameters"]
 	diagnostics -> diagnostic [label="Debug"]
-	diagnostics -> diagnostic_6 [label="Warning"]
-	diagnostics -> diagnostic_7 [label="Warning"]
+	diagnostics -> diagnostic_8 [label="Warning"]
+	diagnostics -> diagnostic_9 [label="Warning"]
+	diagnostics -> diagnostic_10 [label="Warning"]
 }

+ 50 - 0
tests/contract_testcases/solana/error2.dot

@@ -0,0 +1,50 @@
+strict digraph "tests/contract_testcases/solana/error2.sol" {
+	X1 [label="name: X1\ntests/contract_testcases/solana/error2.sol:2:1-14\nvalue: a"]
+	X2 [label="name: X2\ntests/contract_testcases/solana/error2.sol:7:1-14\nvalue: b"]
+	X2_4 [label="name:X2\ntests/contract_testcases/solana/error2.sol:6:7-9\nfield name:bar ty:int256"]
+	X2_5 [label="name:X2\ncontract: 0\ntests/contract_testcases/solana/error2.sol:11:8-10\nfield name:bar ty:int256"]
+	X3 [label="name:X3\ncontract: 0\ntests/contract_testcases/solana/error2.sol:12:8-10\nfield name:X ty:int256"]
+	X4 [label="name:X4\ncontract: 0\ntests/contract_testcases/solana/error2.sol:13:8-10\nfield name:X ty:int256\nfield name: ty:bool"]
+	X5 [label="name:X5\ncontract: 0\ntests/contract_testcases/solana/error2.sol:14:8-10\nfield name: ty:unresolved"]
+	X6 [label="name:X6\ncontract: 0\ntests/contract_testcases/solana/error2.sol:15:8-10\nfield name: ty:unresolved"]
+	contract [label="contract C\ntests/contract_testcases/solana/error2.sol:10:1-18:2"]
+	diagnostic [label="X1 is already defined as an enum\nlevel Error\ntests/contract_testcases/solana/error2.sol:3:7-9"]
+	note [label="location of previous definition\ntests/contract_testcases/solana/error2.sol:2:6-8"]
+	diagnostic_15 [label="'function', 'error', or 'event' expected\nlevel Error\ntests/contract_testcases/solana/error2.sol:4:1-4"]
+	diagnostic_16 [label="'function', 'error', or 'event' expected\nlevel Error\ntests/contract_testcases/solana/error2.sol:5:1-4"]
+	diagnostic_17 [label="X2 is already defined as an error\nlevel Error\ntests/contract_testcases/solana/error2.sol:7:6-8"]
+	note_18 [label="location of previous definition\ntests/contract_testcases/solana/error2.sol:6:7-9"]
+	diagnostic_19 [label="found contract 'C'\nlevel Debug\ntests/contract_testcases/solana/error2.sol:10:1-18:2"]
+	diagnostic_20 [label="X2 is already defined as an error\nlevel Warning\ntests/contract_testcases/solana/error2.sol:11:8-10"]
+	note_21 [label="location of previous definition\ntests/contract_testcases/solana/error2.sol:6:7-9"]
+	diagnostic_22 [label="error 'X3' has duplicate field name 'X'\nlevel Error\ntests/contract_testcases/solana/error2.sol:12:23-24"]
+	note_23 [label="location of previous declaration of 'X'\ntests/contract_testcases/solana/error2.sol:12:11-16"]
+	diagnostic_24 [label="mapping type is not permitted as error field\nlevel Error\ntests/contract_testcases/solana/error2.sol:14:11-32"]
+	diagnostic_25 [label="type 'X' not found\nlevel Error\ntests/contract_testcases/solana/error2.sol:15:11-12"]
+	diagnostic_26 [label="'function', 'error', or 'event' expected\nlevel Error\ntests/contract_testcases/solana/error2.sol:16:2-5"]
+	diagnostic_27 [label="'function', 'error', or 'event' expected\nlevel Error\ntests/contract_testcases/solana/error2.sol:17:2-6"]
+	enums -> X1
+	enums -> X2
+	errors -> X2_4
+	errors -> X2_5
+	errors -> X3
+	errors -> X4
+	errors -> X5
+	errors -> X6
+	contracts -> contract
+	diagnostics -> diagnostic [label="Error"]
+	diagnostic -> note [label="note"]
+	diagnostics -> diagnostic_15 [label="Error"]
+	diagnostics -> diagnostic_16 [label="Error"]
+	diagnostics -> diagnostic_17 [label="Error"]
+	diagnostic_17 -> note_18 [label="note"]
+	diagnostics -> diagnostic_19 [label="Debug"]
+	diagnostics -> diagnostic_20 [label="Warning"]
+	diagnostic_20 -> note_21 [label="note"]
+	diagnostics -> diagnostic_22 [label="Error"]
+	diagnostic_22 -> note_23 [label="note"]
+	diagnostics -> diagnostic_24 [label="Error"]
+	diagnostics -> diagnostic_25 [label="Error"]
+	diagnostics -> diagnostic_26 [label="Error"]
+	diagnostics -> diagnostic_27 [label="Error"]
+}

+ 18 - 0
tests/contract_testcases/solana/error2.sol

@@ -0,0 +1,18 @@
+
+enum X1 { a }
+error X1();
+foo X1();
+a.b X1();
+error X2(int bar);
+enum X2 { b }
+
+
+contract C {
+	error X2(int bar);
+	error X3(int X, bool X);
+	error X4(int X, bool);
+	error X5(mapping (int => bool));
+	error X6(X);
+	meh X7();
+	a[1] X8(int);
+}

+ 110 - 108
tests/contract_testcases/solana/functions/override.dot

@@ -1,16 +1,17 @@
 strict digraph "tests/contract_testcases/solana/functions/override.sol" {
-	S [label="name:S\ntests/contract_testcases/solana/functions/../simple.sol:3:8-9\nfield name:f1 ty:int64\nfield name:f2 ty:bool"]
-	inc [label="function inc\ntests/contract_testcases/solana/functions/../simple.sol:7:1-23\nsignature inc((int64,bool))\nvisibility internal\nmutability pure"]
+	S [label="name:S\ntests/contract_testcases/solana/functions/../simple.sol:4:8-9\nfield name:f1 ty:int64\nfield name:f2 ty:bool"]
+	E [label="name:E\ntests/contract_testcases/solana/functions/../simple.sol:3:7-8\nfield name:foo ty:int256"]
+	inc [label="function inc\ntests/contract_testcases/solana/functions/../simple.sol:8:1-23\nsignature inc((int64,bool))\nvisibility internal\nmutability pure"]
 	parameters [label="parameters\nstruct S s"]
-	expr [label="expression\ntests/contract_testcases/solana/functions/../simple.sol:7:26-35"]
-	assign [label="assign\nint64\ntests/contract_testcases/solana/functions/../simple.sol:7:26-35"]
-	structmember [label="struct member #0 int64\ntests/contract_testcases/solana/functions/../simple.sol:7:28-30"]
-	variable [label="variable: s\nstruct S\ntests/contract_testcases/solana/functions/../simple.sol:7:26-27"]
-	add [label="add\nint64\ntests/contract_testcases/solana/functions/../simple.sol:7:26-35"]
-	load [label="load int64\ntests/contract_testcases/solana/functions/../simple.sol:7:26-35"]
-	structmember_11 [label="struct member #0 int64\ntests/contract_testcases/solana/functions/../simple.sol:7:28-30"]
-	variable_12 [label="variable: s\nstruct S\ntests/contract_testcases/solana/functions/../simple.sol:7:26-27"]
-	number_literal [label="int64 literal: 1\ntests/contract_testcases/solana/functions/../simple.sol:7:34-35"]
+	expr [label="expression\ntests/contract_testcases/solana/functions/../simple.sol:8:26-35"]
+	assign [label="assign\nint64\ntests/contract_testcases/solana/functions/../simple.sol:8:26-35"]
+	structmember [label="struct member #0 int64\ntests/contract_testcases/solana/functions/../simple.sol:8:28-30"]
+	variable [label="variable: s\nstruct S\ntests/contract_testcases/solana/functions/../simple.sol:8:26-27"]
+	add [label="add\nint64\ntests/contract_testcases/solana/functions/../simple.sol:8:26-35"]
+	load [label="load int64\ntests/contract_testcases/solana/functions/../simple.sol:8:26-35"]
+	structmember_13 [label="struct member #0 int64\ntests/contract_testcases/solana/functions/../simple.sol:8:28-30"]
+	variable_14 [label="variable: s\nstruct S\ntests/contract_testcases/solana/functions/../simple.sol:8:26-27"]
+	number_literal [label="int64 literal: 1\ntests/contract_testcases/solana/functions/../simple.sol:8:34-35"]
 	contract [label="contract C\ntests/contract_testcases/solana/functions/override.sol:5:1-7:2"]
 	base [label="base A\ntests/contract_testcases/solana/functions/override.sol:5:15-20"]
 	var [label="variable meh\nvisibility public\nint256\ntests/contract_testcases/solana/functions/override.sol:6:2-32"]
@@ -19,61 +20,62 @@ strict digraph "tests/contract_testcases/solana/functions/override.sol" {
 	return [label="return\nimplicit"]
 	storage_load [label="storage load int256\nimplicit"]
 	storage_var [label="storage variable\nC.meh\nint256 storage\nimplicit"]
-	contract_23 [label="contract A\ntests/contract_testcases/solana/functions/override.sol:9:1-11:2"]
+	contract_25 [label="contract A\ntests/contract_testcases/solana/functions/override.sol:9:1-11:2"]
 	foo [label="function foo\ncontract: A\ntests/contract_testcases/solana/functions/override.sol:10:5-43\nsignature foo()\nvisibility external\nmutability nonpayable\nvirtual"]
-	returns_25 [label="returns\nuint256 "]
-	contract_26 [label="contract B\ntests/contract_testcases/solana/functions/override.sol:12:1-14:2"]
-	foo_27 [label="function foo\ncontract: B\ntests/contract_testcases/solana/functions/override.sol:13:5-43\nsignature foo()\nvisibility external\nmutability nonpayable\nvirtual"]
-	returns_28 [label="returns\nuint256 "]
-	contract_29 [label="contract X\ntests/contract_testcases/solana/functions/override.sol:15:1-17:2"]
-	base_30 [label="base A\ntests/contract_testcases/solana/functions/override.sol:15:15-16"]
-	base_31 [label="base B\ntests/contract_testcases/solana/functions/override.sol:15:18-19"]
-	var_32 [label="variable foo\nvisibility public\nuint256\ntests/contract_testcases/solana/functions/override.sol:16:9-39"]
-	foo_33 [label="function foo\ncontract: X\ntests/contract_testcases/solana/functions/override.sol:16:36-39\nsignature foo()\nvisibility public\nmutability view\noverride A\noverride B"]
-	returns_34 [label="returns\nuint256 foo"]
-	return_35 [label="return\nimplicit"]
-	storage_load_36 [label="storage load uint256\nimplicit"]
-	storage_var_37 [label="storage variable\nX.foo\nuint256 storage\nimplicit"]
-	contract_38 [label="contract Y\ntests/contract_testcases/solana/functions/override.sol:18:1-19:2"]
-	base_39 [label="base X\ntests/contract_testcases/solana/functions/override.sol:18:15-16"]
-	contract_40 [label="contract A2\ntests/contract_testcases/solana/functions/override.sol:21:1-23:2"]
-	foo_41 [label="function foo\ncontract: A2\ntests/contract_testcases/solana/functions/override.sol:22:5-51\nsignature foo()\nvisibility external\nmutability nonpayable\nvirtual"]
-	returns_42 [label="returns\nuint256 "]
-	return_43 [label="return\ntests/contract_testcases/solana/functions/override.sol:22:54-62"]
-	number_literal_44 [label="uint256 literal: 1\ntests/contract_testcases/solana/functions/override.sol:22:61-62"]
-	contract_45 [label="contract B2\ntests/contract_testcases/solana/functions/override.sol:24:1-26:2"]
-	foo_46 [label="function foo\ncontract: B2\ntests/contract_testcases/solana/functions/override.sol:25:5-51\nsignature foo()\nvisibility external\nmutability nonpayable\nvirtual"]
-	returns_47 [label="returns\nuint256 "]
-	return_48 [label="return\ntests/contract_testcases/solana/functions/override.sol:25:54-62"]
-	number_literal_49 [label="uint256 literal: 2\ntests/contract_testcases/solana/functions/override.sol:25:61-62"]
-	contract_50 [label="contract X2\ntests/contract_testcases/solana/functions/override.sol:27:1-29:2"]
-	base_51 [label="base A2\ntests/contract_testcases/solana/functions/override.sol:27:16-18"]
-	base_52 [label="base B2\ntests/contract_testcases/solana/functions/override.sol:27:20-22"]
-	var_53 [label="variable foo\nvisibility public\nuint256\ntests/contract_testcases/solana/functions/override.sol:28:9-37"]
-	foo_54 [label="function foo\ncontract: X2\ntests/contract_testcases/solana/functions/override.sol:28:34-37\nsignature foo()\nvisibility public\nmutability view\noverride A2"]
-	returns_55 [label="returns\nuint256 foo"]
-	return_56 [label="return\nimplicit"]
-	storage_load_57 [label="storage load uint256\nimplicit"]
-	storage_var_58 [label="storage variable\nX2.foo\nuint256 storage\nimplicit"]
-	contract_59 [label="contract Y2\ntests/contract_testcases/solana/functions/override.sol:30:1-31:2"]
-	base_60 [label="base X2\ntests/contract_testcases/solana/functions/override.sol:30:16-18"]
-	contract_61 [label="contract A\ntests/contract_testcases/solana/functions/../simple.sol:1:1-14"]
-	contract_62 [label="contract L\ntests/contract_testcases/solana/functions/../simple.sol:2:1-13"]
+	returns_27 [label="returns\nuint256 "]
+	contract_28 [label="contract B\ntests/contract_testcases/solana/functions/override.sol:12:1-14:2"]
+	foo_29 [label="function foo\ncontract: B\ntests/contract_testcases/solana/functions/override.sol:13:5-43\nsignature foo()\nvisibility external\nmutability nonpayable\nvirtual"]
+	returns_30 [label="returns\nuint256 "]
+	contract_31 [label="contract X\ntests/contract_testcases/solana/functions/override.sol:15:1-17:2"]
+	base_32 [label="base A\ntests/contract_testcases/solana/functions/override.sol:15:15-16"]
+	base_33 [label="base B\ntests/contract_testcases/solana/functions/override.sol:15:18-19"]
+	var_34 [label="variable foo\nvisibility public\nuint256\ntests/contract_testcases/solana/functions/override.sol:16:9-39"]
+	foo_35 [label="function foo\ncontract: X\ntests/contract_testcases/solana/functions/override.sol:16:36-39\nsignature foo()\nvisibility public\nmutability view\noverride A\noverride B"]
+	returns_36 [label="returns\nuint256 foo"]
+	return_37 [label="return\nimplicit"]
+	storage_load_38 [label="storage load uint256\nimplicit"]
+	storage_var_39 [label="storage variable\nX.foo\nuint256 storage\nimplicit"]
+	contract_40 [label="contract Y\ntests/contract_testcases/solana/functions/override.sol:18:1-19:2"]
+	base_41 [label="base X\ntests/contract_testcases/solana/functions/override.sol:18:15-16"]
+	contract_42 [label="contract A2\ntests/contract_testcases/solana/functions/override.sol:21:1-23:2"]
+	foo_43 [label="function foo\ncontract: A2\ntests/contract_testcases/solana/functions/override.sol:22:5-51\nsignature foo()\nvisibility external\nmutability nonpayable\nvirtual"]
+	returns_44 [label="returns\nuint256 "]
+	return_45 [label="return\ntests/contract_testcases/solana/functions/override.sol:22:54-62"]
+	number_literal_46 [label="uint256 literal: 1\ntests/contract_testcases/solana/functions/override.sol:22:61-62"]
+	contract_47 [label="contract B2\ntests/contract_testcases/solana/functions/override.sol:24:1-26:2"]
+	foo_48 [label="function foo\ncontract: B2\ntests/contract_testcases/solana/functions/override.sol:25:5-51\nsignature foo()\nvisibility external\nmutability nonpayable\nvirtual"]
+	returns_49 [label="returns\nuint256 "]
+	return_50 [label="return\ntests/contract_testcases/solana/functions/override.sol:25:54-62"]
+	number_literal_51 [label="uint256 literal: 2\ntests/contract_testcases/solana/functions/override.sol:25:61-62"]
+	contract_52 [label="contract X2\ntests/contract_testcases/solana/functions/override.sol:27:1-29:2"]
+	base_53 [label="base A2\ntests/contract_testcases/solana/functions/override.sol:27:16-18"]
+	base_54 [label="base B2\ntests/contract_testcases/solana/functions/override.sol:27:20-22"]
+	var_55 [label="variable foo\nvisibility public\nuint256\ntests/contract_testcases/solana/functions/override.sol:28:9-37"]
+	foo_56 [label="function foo\ncontract: X2\ntests/contract_testcases/solana/functions/override.sol:28:34-37\nsignature foo()\nvisibility public\nmutability view\noverride A2"]
+	returns_57 [label="returns\nuint256 foo"]
+	return_58 [label="return\nimplicit"]
+	storage_load_59 [label="storage load uint256\nimplicit"]
+	storage_var_60 [label="storage variable\nX2.foo\nuint256 storage\nimplicit"]
+	contract_61 [label="contract Y2\ntests/contract_testcases/solana/functions/override.sol:30:1-31:2"]
+	base_62 [label="base X2\ntests/contract_testcases/solana/functions/override.sol:30:16-18"]
+	contract_63 [label="contract A\ntests/contract_testcases/solana/functions/../simple.sol:1:1-14"]
+	contract_64 [label="contract L\ntests/contract_testcases/solana/functions/../simple.sol:2:1-13"]
 	diagnostic [label="global variable has no bases contracts to override\nlevel Error\ntests/contract_testcases/solana/functions/override.sol:3:14-22"]
-	diagnostic_65 [label="found contract 'C'\nlevel Debug\ntests/contract_testcases/solana/functions/override.sol:5:1-7:2"]
-	diagnostic_66 [label="'meh' does not override anything\nlevel Error\ntests/contract_testcases/solana/functions/override.sol:6:29-32"]
-	diagnostic_67 [label="found interface 'A'\nlevel Debug\ntests/contract_testcases/solana/functions/override.sol:9:1-11:2"]
-	diagnostic_68 [label="found interface 'B'\nlevel Debug\ntests/contract_testcases/solana/functions/override.sol:12:1-14:2"]
-	diagnostic_69 [label="found contract 'X'\nlevel Debug\ntests/contract_testcases/solana/functions/override.sol:15:1-17:2"]
-	diagnostic_70 [label="found contract 'Y'\nlevel Debug\ntests/contract_testcases/solana/functions/override.sol:18:1-19:2"]
-	diagnostic_71 [label="found abstract contract 'A2'\nlevel Debug\ntests/contract_testcases/solana/functions/override.sol:21:1-23:2"]
-	diagnostic_72 [label="found abstract contract 'B2'\nlevel Debug\ntests/contract_testcases/solana/functions/override.sol:24:1-26:2"]
-	diagnostic_73 [label="found contract 'X2'\nlevel Debug\ntests/contract_testcases/solana/functions/override.sol:27:1-29:2"]
-	diagnostic_74 [label="function 'foo' missing overrides 'B2', specify 'override(B2,A2)'\nlevel Error\ntests/contract_testcases/solana/functions/override.sol:28:21-33"]
-	diagnostic_75 [label="found contract 'Y2'\nlevel Debug\ntests/contract_testcases/solana/functions/override.sol:30:1-31:2"]
-	diagnostic_76 [label="found contract 'A'\nlevel Debug\ntests/contract_testcases/solana/functions/../simple.sol:1:1-14"]
-	diagnostic_77 [label="found library 'L'\nlevel Debug\ntests/contract_testcases/solana/functions/../simple.sol:2:1-13"]
+	diagnostic_67 [label="found contract 'C'\nlevel Debug\ntests/contract_testcases/solana/functions/override.sol:5:1-7:2"]
+	diagnostic_68 [label="'meh' does not override anything\nlevel Error\ntests/contract_testcases/solana/functions/override.sol:6:29-32"]
+	diagnostic_69 [label="found interface 'A'\nlevel Debug\ntests/contract_testcases/solana/functions/override.sol:9:1-11:2"]
+	diagnostic_70 [label="found interface 'B'\nlevel Debug\ntests/contract_testcases/solana/functions/override.sol:12:1-14:2"]
+	diagnostic_71 [label="found contract 'X'\nlevel Debug\ntests/contract_testcases/solana/functions/override.sol:15:1-17:2"]
+	diagnostic_72 [label="found contract 'Y'\nlevel Debug\ntests/contract_testcases/solana/functions/override.sol:18:1-19:2"]
+	diagnostic_73 [label="found abstract contract 'A2'\nlevel Debug\ntests/contract_testcases/solana/functions/override.sol:21:1-23:2"]
+	diagnostic_74 [label="found abstract contract 'B2'\nlevel Debug\ntests/contract_testcases/solana/functions/override.sol:24:1-26:2"]
+	diagnostic_75 [label="found contract 'X2'\nlevel Debug\ntests/contract_testcases/solana/functions/override.sol:27:1-29:2"]
+	diagnostic_76 [label="function 'foo' missing overrides 'B2', specify 'override(B2,A2)'\nlevel Error\ntests/contract_testcases/solana/functions/override.sol:28:21-33"]
+	diagnostic_77 [label="found contract 'Y2'\nlevel Debug\ntests/contract_testcases/solana/functions/override.sol:30:1-31:2"]
+	diagnostic_78 [label="found contract 'A'\nlevel Debug\ntests/contract_testcases/solana/functions/../simple.sol:1:1-14"]
+	diagnostic_79 [label="found library 'L'\nlevel Debug\ntests/contract_testcases/solana/functions/../simple.sol:2:1-13"]
 	structs -> S
+	errors -> E
 	free_functions -> inc [label="function"]
 	inc -> parameters [label="parameters"]
 	inc -> expr [label="body"]
@@ -82,8 +84,8 @@ strict digraph "tests/contract_testcases/solana/functions/override.sol" {
 	structmember -> variable [label="var"]
 	assign -> add [label="right"]
 	add -> load [label="left"]
-	load -> structmember_11 [label="expr"]
-	structmember_11 -> variable_12 [label="var"]
+	load -> structmember_13 [label="expr"]
+	structmember_13 -> variable_14 [label="var"]
 	add -> number_literal [label="right"]
 	contracts -> contract
 	contract -> base [label="base"]
@@ -93,58 +95,58 @@ strict digraph "tests/contract_testcases/solana/functions/override.sol" {
 	meh -> return [label="body"]
 	return -> storage_load [label="expr"]
 	storage_load -> storage_var [label="expr"]
-	contracts -> contract_23
-	contract_23 -> foo [label="function"]
-	foo -> returns_25 [label="returns"]
-	contracts -> contract_26
-	contract_26 -> foo_27 [label="function"]
-	foo_27 -> returns_28 [label="returns"]
-	contracts -> contract_29
-	contract_29 -> base_30 [label="base"]
-	contract_29 -> base_31 [label="base"]
-	contract_29 -> var_32 [label="variable"]
-	contract_29 -> foo_33 [label="function"]
-	foo_33 -> returns_34 [label="returns"]
-	foo_33 -> return_35 [label="body"]
-	return_35 -> storage_load_36 [label="expr"]
-	storage_load_36 -> storage_var_37 [label="expr"]
-	contracts -> contract_38
-	contract_38 -> base_39 [label="base"]
+	contracts -> contract_25
+	contract_25 -> foo [label="function"]
+	foo -> returns_27 [label="returns"]
+	contracts -> contract_28
+	contract_28 -> foo_29 [label="function"]
+	foo_29 -> returns_30 [label="returns"]
+	contracts -> contract_31
+	contract_31 -> base_32 [label="base"]
+	contract_31 -> base_33 [label="base"]
+	contract_31 -> var_34 [label="variable"]
+	contract_31 -> foo_35 [label="function"]
+	foo_35 -> returns_36 [label="returns"]
+	foo_35 -> return_37 [label="body"]
+	return_37 -> storage_load_38 [label="expr"]
+	storage_load_38 -> storage_var_39 [label="expr"]
 	contracts -> contract_40
-	contract_40 -> foo_41 [label="function"]
-	foo_41 -> returns_42 [label="returns"]
-	foo_41 -> return_43 [label="body"]
-	return_43 -> number_literal_44 [label="expr"]
-	contracts -> contract_45
-	contract_45 -> foo_46 [label="function"]
-	foo_46 -> returns_47 [label="returns"]
-	foo_46 -> return_48 [label="body"]
-	return_48 -> number_literal_49 [label="expr"]
-	contracts -> contract_50
-	contract_50 -> base_51 [label="base"]
-	contract_50 -> base_52 [label="base"]
-	contract_50 -> var_53 [label="variable"]
-	contract_50 -> foo_54 [label="function"]
-	foo_54 -> returns_55 [label="returns"]
-	foo_54 -> return_56 [label="body"]
-	return_56 -> storage_load_57 [label="expr"]
-	storage_load_57 -> storage_var_58 [label="expr"]
-	contracts -> contract_59
-	contract_59 -> base_60 [label="base"]
+	contract_40 -> base_41 [label="base"]
+	contracts -> contract_42
+	contract_42 -> foo_43 [label="function"]
+	foo_43 -> returns_44 [label="returns"]
+	foo_43 -> return_45 [label="body"]
+	return_45 -> number_literal_46 [label="expr"]
+	contracts -> contract_47
+	contract_47 -> foo_48 [label="function"]
+	foo_48 -> returns_49 [label="returns"]
+	foo_48 -> return_50 [label="body"]
+	return_50 -> number_literal_51 [label="expr"]
+	contracts -> contract_52
+	contract_52 -> base_53 [label="base"]
+	contract_52 -> base_54 [label="base"]
+	contract_52 -> var_55 [label="variable"]
+	contract_52 -> foo_56 [label="function"]
+	foo_56 -> returns_57 [label="returns"]
+	foo_56 -> return_58 [label="body"]
+	return_58 -> storage_load_59 [label="expr"]
+	storage_load_59 -> storage_var_60 [label="expr"]
 	contracts -> contract_61
-	contracts -> contract_62
+	contract_61 -> base_62 [label="base"]
+	contracts -> contract_63
+	contracts -> contract_64
 	diagnostics -> diagnostic [label="Error"]
-	diagnostics -> diagnostic_65 [label="Debug"]
-	diagnostics -> diagnostic_66 [label="Error"]
 	diagnostics -> diagnostic_67 [label="Debug"]
-	diagnostics -> diagnostic_68 [label="Debug"]
+	diagnostics -> diagnostic_68 [label="Error"]
 	diagnostics -> diagnostic_69 [label="Debug"]
 	diagnostics -> diagnostic_70 [label="Debug"]
 	diagnostics -> diagnostic_71 [label="Debug"]
 	diagnostics -> diagnostic_72 [label="Debug"]
 	diagnostics -> diagnostic_73 [label="Debug"]
-	diagnostics -> diagnostic_74 [label="Error"]
+	diagnostics -> diagnostic_74 [label="Debug"]
 	diagnostics -> diagnostic_75 [label="Debug"]
-	diagnostics -> diagnostic_76 [label="Debug"]
+	diagnostics -> diagnostic_76 [label="Error"]
 	diagnostics -> diagnostic_77 [label="Debug"]
+	diagnostics -> diagnostic_78 [label="Debug"]
+	diagnostics -> diagnostic_79 [label="Debug"]
 }

+ 39 - 27
tests/contract_testcases/solana/import_contracts_via_object.dot

@@ -1,29 +1,36 @@
 strict digraph "tests/contract_testcases/solana/import_contracts_via_object.sol" {
-	S [label="name:S\ntests/contract_testcases/solana/simple.sol:3:8-9\nfield name:f1 ty:int64\nfield name:f2 ty:bool"]
-	inc [label="function inc\ntests/contract_testcases/solana/simple.sol:7:1-23\nsignature inc((int64,bool))\nvisibility internal\nmutability pure"]
+	S [label="name:S\ntests/contract_testcases/solana/simple.sol:4:8-9\nfield name:f1 ty:int64\nfield name:f2 ty:bool"]
+	E [label="name:E\ntests/contract_testcases/solana/simple.sol:3:7-8\nfield name:foo ty:int256"]
+	inc [label="function inc\ntests/contract_testcases/solana/simple.sol:8:1-23\nsignature inc((int64,bool))\nvisibility internal\nmutability pure"]
 	parameters [label="parameters\nstruct S s"]
-	expr [label="expression\ntests/contract_testcases/solana/simple.sol:7:26-35"]
-	assign [label="assign\nint64\ntests/contract_testcases/solana/simple.sol:7:26-35"]
-	structmember [label="struct member #0 int64\ntests/contract_testcases/solana/simple.sol:7:28-30"]
-	variable [label="variable: s\nstruct S\ntests/contract_testcases/solana/simple.sol:7:26-27"]
-	add [label="add\nint64\ntests/contract_testcases/solana/simple.sol:7:26-35"]
-	load [label="load int64\ntests/contract_testcases/solana/simple.sol:7:26-35"]
-	structmember_11 [label="struct member #0 int64\ntests/contract_testcases/solana/simple.sol:7:28-30"]
-	variable_12 [label="variable: s\nstruct S\ntests/contract_testcases/solana/simple.sol:7:26-27"]
-	number_literal [label="int64 literal: 1\ntests/contract_testcases/solana/simple.sol:7:34-35"]
+	expr [label="expression\ntests/contract_testcases/solana/simple.sol:8:26-35"]
+	assign [label="assign\nint64\ntests/contract_testcases/solana/simple.sol:8:26-35"]
+	structmember [label="struct member #0 int64\ntests/contract_testcases/solana/simple.sol:8:28-30"]
+	variable [label="variable: s\nstruct S\ntests/contract_testcases/solana/simple.sol:8:26-27"]
+	add [label="add\nint64\ntests/contract_testcases/solana/simple.sol:8:26-35"]
+	load [label="load int64\ntests/contract_testcases/solana/simple.sol:8:26-35"]
+	structmember_13 [label="struct member #0 int64\ntests/contract_testcases/solana/simple.sol:8:28-30"]
+	variable_14 [label="variable: s\nstruct S\ntests/contract_testcases/solana/simple.sol:8:26-27"]
+	number_literal [label="int64 literal: 1\ntests/contract_testcases/solana/simple.sol:8:34-35"]
 	contract [label="contract C\ntests/contract_testcases/solana/import_contracts_via_object.sol:3:1-11:2"]
 	base [label="base A\ntests/contract_testcases/solana/import_contracts_via_object.sol:3:15-20"]
 	using [label="library L"]
-	node_18 [label="constructor \ncontract: C\ntests/contract_testcases/solana/import_contracts_via_object.sol:5:2-23\nsignature ()\nvisibility public\nmutability nonpayable"]
+	node_20 [label="constructor \ncontract: C\ntests/contract_testcases/solana/import_contracts_via_object.sol:5:2-23\nsignature ()\nvisibility public\nmutability nonpayable"]
+	revert [label="revert\nerror E\ntests/contract_testcases/solana/import_contracts_via_object.sol:6:3-17"]
 	foo [label="function foo\ncontract: C\ntests/contract_testcases/solana/import_contracts_via_object.sol:8:2-23\nsignature foo()\nvisibility public\nmutability nonpayable"]
-	contract_20 [label="contract A\ntests/contract_testcases/solana/simple.sol:1:1-14"]
-	contract_21 [label="contract L\ntests/contract_testcases/solana/simple.sol:2:1-13"]
+	revert_23 [label="revert\nerror E\ntests/contract_testcases/solana/import_contracts_via_object.sol:9:3-25"]
+	number_literal_24 [label="int256 literal: 1\ntests/contract_testcases/solana/import_contracts_via_object.sol:9:22-23"]
+	contract_25 [label="contract A\ntests/contract_testcases/solana/simple.sol:1:1-14"]
+	contract_26 [label="contract L\ntests/contract_testcases/solana/simple.sol:2:1-13"]
 	diagnostic [label="found contract 'C'\nlevel Debug\ntests/contract_testcases/solana/import_contracts_via_object.sol:3:1-11:2"]
-	diagnostic_24 [label="revert with custom error 'IMP.E' not supported yet\nlevel Error\ntests/contract_testcases/solana/import_contracts_via_object.sol:6:10-15"]
-	diagnostic_25 [label="revert with custom errors or named arguments not supported yet\nlevel Error\ntests/contract_testcases/solana/import_contracts_via_object.sol:9:3-25"]
-	diagnostic_26 [label="found contract 'A'\nlevel Debug\ntests/contract_testcases/solana/simple.sol:1:1-14"]
-	diagnostic_27 [label="found library 'L'\nlevel Debug\ntests/contract_testcases/solana/simple.sol:2:1-13"]
+	diagnostic_29 [label="revert with custom errors not supported on solana\nlevel Error\ntests/contract_testcases/solana/import_contracts_via_object.sol:6:3-17"]
+	diagnostic_30 [label="error 'E' has 1 fields, 0 provided\nlevel Error\ntests/contract_testcases/solana/import_contracts_via_object.sol:6:10-15"]
+	note [label="definition of 'E'\ntests/contract_testcases/solana/simple.sol:3:7-8"]
+	diagnostic_32 [label="revert with custom errors not supported on solana\nlevel Error\ntests/contract_testcases/solana/import_contracts_via_object.sol:9:3-25"]
+	diagnostic_33 [label="found contract 'A'\nlevel Debug\ntests/contract_testcases/solana/simple.sol:1:1-14"]
+	diagnostic_34 [label="found library 'L'\nlevel Debug\ntests/contract_testcases/solana/simple.sol:2:1-13"]
 	structs -> S
+	errors -> E
 	free_functions -> inc [label="function"]
 	inc -> parameters [label="parameters"]
 	inc -> expr [label="body"]
@@ -32,19 +39,24 @@ strict digraph "tests/contract_testcases/solana/import_contracts_via_object.sol"
 	structmember -> variable [label="var"]
 	assign -> add [label="right"]
 	add -> load [label="left"]
-	load -> structmember_11 [label="expr"]
-	structmember_11 -> variable_12 [label="var"]
+	load -> structmember_13 [label="expr"]
+	structmember_13 -> variable_14 [label="var"]
 	add -> number_literal [label="right"]
 	contracts -> contract
 	contract -> base [label="base"]
 	contract -> using [label="base"]
-	contract -> node_18 [label="constructor"]
+	contract -> node_20 [label="constructor"]
+	node_20 -> revert [label="body"]
 	contract -> foo [label="function"]
-	contracts -> contract_20
-	contracts -> contract_21
+	foo -> revert_23 [label="body"]
+	revert_23 -> number_literal_24 [label="arg #0"]
+	contracts -> contract_25
+	contracts -> contract_26
 	diagnostics -> diagnostic [label="Debug"]
-	diagnostics -> diagnostic_24 [label="Error"]
-	diagnostics -> diagnostic_25 [label="Error"]
-	diagnostics -> diagnostic_26 [label="Debug"]
-	diagnostics -> diagnostic_27 [label="Debug"]
+	diagnostics -> diagnostic_29 [label="Error"]
+	diagnostics -> diagnostic_30 [label="Error"]
+	diagnostic_30 -> note [label="note"]
+	diagnostics -> diagnostic_32 [label="Error"]
+	diagnostics -> diagnostic_33 [label="Debug"]
+	diagnostics -> diagnostic_34 [label="Debug"]
 }

+ 21 - 17
tests/contract_testcases/solana/simple.dot

@@ -1,21 +1,24 @@
 strict digraph "tests/contract_testcases/solana/simple.sol" {
-	S [label="name:S\ntests/contract_testcases/solana/simple.sol:3:8-9\nfield name:f1 ty:int64\nfield name:f2 ty:bool"]
-	inc [label="function inc\ntests/contract_testcases/solana/simple.sol:7:1-23\nsignature inc((int64,bool))\nvisibility internal\nmutability pure"]
+	S [label="name:S\ntests/contract_testcases/solana/simple.sol:4:8-9\nfield name:f1 ty:int64\nfield name:f2 ty:bool"]
+	E [label="name:E\ntests/contract_testcases/solana/simple.sol:3:7-8\nfield name:foo ty:int256"]
+	inc [label="function inc\ntests/contract_testcases/solana/simple.sol:8:1-23\nsignature inc((int64,bool))\nvisibility internal\nmutability pure"]
 	parameters [label="parameters\nstruct S s"]
-	expr [label="expression\ntests/contract_testcases/solana/simple.sol:7:26-35"]
-	assign [label="assign\nint64\ntests/contract_testcases/solana/simple.sol:7:26-35"]
-	structmember [label="struct member #0 int64\ntests/contract_testcases/solana/simple.sol:7:28-30"]
-	variable [label="variable: s\nstruct S\ntests/contract_testcases/solana/simple.sol:7:26-27"]
-	add [label="add\nint64\ntests/contract_testcases/solana/simple.sol:7:26-35"]
-	load [label="load int64\ntests/contract_testcases/solana/simple.sol:7:26-35"]
-	structmember_11 [label="struct member #0 int64\ntests/contract_testcases/solana/simple.sol:7:28-30"]
-	variable_12 [label="variable: s\nstruct S\ntests/contract_testcases/solana/simple.sol:7:26-27"]
-	number_literal [label="int64 literal: 1\ntests/contract_testcases/solana/simple.sol:7:34-35"]
+	expr [label="expression\ntests/contract_testcases/solana/simple.sol:8:26-35"]
+	assign [label="assign\nint64\ntests/contract_testcases/solana/simple.sol:8:26-35"]
+	structmember [label="struct member #0 int64\ntests/contract_testcases/solana/simple.sol:8:28-30"]
+	variable [label="variable: s\nstruct S\ntests/contract_testcases/solana/simple.sol:8:26-27"]
+	add [label="add\nint64\ntests/contract_testcases/solana/simple.sol:8:26-35"]
+	load [label="load int64\ntests/contract_testcases/solana/simple.sol:8:26-35"]
+	structmember_13 [label="struct member #0 int64\ntests/contract_testcases/solana/simple.sol:8:28-30"]
+	variable_14 [label="variable: s\nstruct S\ntests/contract_testcases/solana/simple.sol:8:26-27"]
+	number_literal [label="int64 literal: 1\ntests/contract_testcases/solana/simple.sol:8:34-35"]
 	contract [label="contract A\ntests/contract_testcases/solana/simple.sol:1:1-14"]
-	contract_16 [label="contract L\ntests/contract_testcases/solana/simple.sol:2:1-13"]
+	contract_18 [label="contract L\ntests/contract_testcases/solana/simple.sol:2:1-13"]
 	diagnostic [label="found contract 'A'\nlevel Debug\ntests/contract_testcases/solana/simple.sol:1:1-14"]
-	diagnostic_19 [label="found library 'L'\nlevel Debug\ntests/contract_testcases/solana/simple.sol:2:1-13"]
+	diagnostic_21 [label="found library 'L'\nlevel Debug\ntests/contract_testcases/solana/simple.sol:2:1-13"]
+	diagnostic_22 [label="error 'E' has never been used\nlevel Warning\ntests/contract_testcases/solana/simple.sol:3:7-8"]
 	structs -> S
+	errors -> E
 	free_functions -> inc [label="function"]
 	inc -> parameters [label="parameters"]
 	inc -> expr [label="body"]
@@ -24,11 +27,12 @@ strict digraph "tests/contract_testcases/solana/simple.sol" {
 	structmember -> variable [label="var"]
 	assign -> add [label="right"]
 	add -> load [label="left"]
-	load -> structmember_11 [label="expr"]
-	structmember_11 -> variable_12 [label="var"]
+	load -> structmember_13 [label="expr"]
+	structmember_13 -> variable_14 [label="var"]
 	add -> number_literal [label="right"]
 	contracts -> contract
-	contracts -> contract_16
+	contracts -> contract_18
 	diagnostics -> diagnostic [label="Debug"]
-	diagnostics -> diagnostic_19 [label="Debug"]
+	diagnostics -> diagnostic_21 [label="Debug"]
+	diagnostics -> diagnostic_22 [label="Warning"]
 }

+ 1 - 0
tests/contract_testcases/solana/simple.sol

@@ -1,5 +1,6 @@
 contract A {}
 library L {}
+error E(int foo);
 struct S {
 	int64 f1;
 	bool f2;

+ 61 - 57
tests/contract_testcases/solana/using_import.dot

@@ -1,45 +1,48 @@
 strict digraph "tests/contract_testcases/solana/using_import.sol" {
-	S [label="name:S\ntests/contract_testcases/solana/simple.sol:3:8-9\nfield name:f1 ty:int64\nfield name:f2 ty:bool"]
-	inc [label="function inc\ntests/contract_testcases/solana/simple.sol:7:1-23\nsignature inc((int64,bool))\nvisibility internal\nmutability pure"]
+	S [label="name:S\ntests/contract_testcases/solana/simple.sol:4:8-9\nfield name:f1 ty:int64\nfield name:f2 ty:bool"]
+	E [label="name:E\ntests/contract_testcases/solana/simple.sol:3:7-8\nfield name:foo ty:int256"]
+	inc [label="function inc\ntests/contract_testcases/solana/simple.sol:8:1-23\nsignature inc((int64,bool))\nvisibility internal\nmutability pure"]
 	parameters [label="parameters\nstruct S s"]
-	expr [label="expression\ntests/contract_testcases/solana/simple.sol:7:26-35"]
-	assign [label="assign\nint64\ntests/contract_testcases/solana/simple.sol:7:26-35"]
-	structmember [label="struct member #0 int64\ntests/contract_testcases/solana/simple.sol:7:28-30"]
-	variable [label="variable: s\nstruct S\ntests/contract_testcases/solana/simple.sol:7:26-27"]
-	add [label="add\nint64\ntests/contract_testcases/solana/simple.sol:7:26-35"]
-	load [label="load int64\ntests/contract_testcases/solana/simple.sol:7:26-35"]
-	structmember_11 [label="struct member #0 int64\ntests/contract_testcases/solana/simple.sol:7:28-30"]
-	variable_12 [label="variable: s\nstruct S\ntests/contract_testcases/solana/simple.sol:7:26-27"]
-	number_literal [label="int64 literal: 1\ntests/contract_testcases/solana/simple.sol:7:34-35"]
+	expr [label="expression\ntests/contract_testcases/solana/simple.sol:8:26-35"]
+	assign [label="assign\nint64\ntests/contract_testcases/solana/simple.sol:8:26-35"]
+	structmember [label="struct member #0 int64\ntests/contract_testcases/solana/simple.sol:8:28-30"]
+	variable [label="variable: s\nstruct S\ntests/contract_testcases/solana/simple.sol:8:26-27"]
+	add [label="add\nint64\ntests/contract_testcases/solana/simple.sol:8:26-35"]
+	load [label="load int64\ntests/contract_testcases/solana/simple.sol:8:26-35"]
+	structmember_13 [label="struct member #0 int64\ntests/contract_testcases/solana/simple.sol:8:28-30"]
+	variable_14 [label="variable: s\nstruct S\ntests/contract_testcases/solana/simple.sol:8:26-27"]
+	number_literal [label="int64 literal: 1\ntests/contract_testcases/solana/simple.sol:8:34-35"]
 	dec [label="function dec\ntests/contract_testcases/solana/using_import.sol:3:1-31\nsignature dec((int64,bool))\nvisibility internal\nmutability pure"]
-	parameters_15 [label="parameters\nstruct S s"]
-	expr_16 [label="expression\ntests/contract_testcases/solana/using_import.sol:3:34-43"]
-	assign_17 [label="assign\nint64\ntests/contract_testcases/solana/using_import.sol:3:34-43"]
-	structmember_18 [label="struct member #0 int64\ntests/contract_testcases/solana/using_import.sol:3:36-38"]
-	variable_19 [label="variable: s\nstruct S\ntests/contract_testcases/solana/using_import.sol:3:34-35"]
+	parameters_17 [label="parameters\nstruct S s"]
+	expr_18 [label="expression\ntests/contract_testcases/solana/using_import.sol:3:34-43"]
+	assign_19 [label="assign\nint64\ntests/contract_testcases/solana/using_import.sol:3:34-43"]
+	structmember_20 [label="struct member #0 int64\ntests/contract_testcases/solana/using_import.sol:3:36-38"]
+	variable_21 [label="variable: s\nstruct S\ntests/contract_testcases/solana/using_import.sol:3:34-35"]
 	subtract [label="subtract\nint64\ntests/contract_testcases/solana/using_import.sol:3:34-43"]
-	load_21 [label="load int64\ntests/contract_testcases/solana/using_import.sol:3:34-43"]
-	structmember_22 [label="struct member #0 int64\ntests/contract_testcases/solana/using_import.sol:3:36-38"]
-	variable_23 [label="variable: s\nstruct S\ntests/contract_testcases/solana/using_import.sol:3:34-35"]
-	number_literal_24 [label="int64 literal: 1\ntests/contract_testcases/solana/using_import.sol:3:42-43"]
+	load_23 [label="load int64\ntests/contract_testcases/solana/using_import.sol:3:34-43"]
+	structmember_24 [label="struct member #0 int64\ntests/contract_testcases/solana/using_import.sol:3:36-38"]
+	variable_25 [label="variable: s\nstruct S\ntests/contract_testcases/solana/using_import.sol:3:34-35"]
+	number_literal_26 [label="int64 literal: 1\ntests/contract_testcases/solana/using_import.sol:3:42-43"]
 	contract [label="contract c\ntests/contract_testcases/solana/using_import.sol:6:1-11:2"]
 	test [label="function test\ncontract: c\ntests/contract_testcases/solana/using_import.sol:7:2-35\nsignature test((int64,bool))\nvisibility public\nmutability nonpayable"]
-	parameters_28 [label="parameters\nstruct S s"]
-	expr_29 [label="expression\ntests/contract_testcases/solana/using_import.sol:8:3-10"]
+	parameters_30 [label="parameters\nstruct S s"]
+	expr_31 [label="expression\ntests/contract_testcases/solana/using_import.sol:8:3-10"]
 	call_internal_function [label="call internal function\ntests/contract_testcases/solana/using_import.sol:8:3-10"]
 	internal_function [label="function(struct S) internal pure returns (void)\nfree function inc\ntests/contract_testcases/solana/using_import.sol:8:3-10"]
-	variable_32 [label="variable: s\nstruct S\ntests/contract_testcases/solana/using_import.sol:8:3-4"]
-	expr_33 [label="expression\ntests/contract_testcases/solana/using_import.sol:9:3-10"]
-	call_internal_function_34 [label="call internal function\ntests/contract_testcases/solana/using_import.sol:9:3-10"]
-	internal_function_35 [label="function(struct S) internal pure returns (void)\nfree function dec\ntests/contract_testcases/solana/using_import.sol:9:3-10"]
-	variable_36 [label="variable: s\nstruct S\ntests/contract_testcases/solana/using_import.sol:9:3-4"]
-	contract_37 [label="contract A\ntests/contract_testcases/solana/simple.sol:1:1-14"]
-	contract_38 [label="contract L\ntests/contract_testcases/solana/simple.sol:2:1-13"]
+	variable_34 [label="variable: s\nstruct S\ntests/contract_testcases/solana/using_import.sol:8:3-4"]
+	expr_35 [label="expression\ntests/contract_testcases/solana/using_import.sol:9:3-10"]
+	call_internal_function_36 [label="call internal function\ntests/contract_testcases/solana/using_import.sol:9:3-10"]
+	internal_function_37 [label="function(struct S) internal pure returns (void)\nfree function dec\ntests/contract_testcases/solana/using_import.sol:9:3-10"]
+	variable_38 [label="variable: s\nstruct S\ntests/contract_testcases/solana/using_import.sol:9:3-4"]
+	contract_39 [label="contract A\ntests/contract_testcases/solana/simple.sol:1:1-14"]
+	contract_40 [label="contract L\ntests/contract_testcases/solana/simple.sol:2:1-13"]
 	diagnostic [label="found contract 'c'\nlevel Debug\ntests/contract_testcases/solana/using_import.sol:6:1-11:2"]
-	diagnostic_41 [label="function can be declared 'pure'\nlevel Warning\ntests/contract_testcases/solana/using_import.sol:7:2-35"]
-	diagnostic_42 [label="found contract 'A'\nlevel Debug\ntests/contract_testcases/solana/simple.sol:1:1-14"]
-	diagnostic_43 [label="found library 'L'\nlevel Debug\ntests/contract_testcases/solana/simple.sol:2:1-13"]
+	diagnostic_43 [label="function can be declared 'pure'\nlevel Warning\ntests/contract_testcases/solana/using_import.sol:7:2-35"]
+	diagnostic_44 [label="found contract 'A'\nlevel Debug\ntests/contract_testcases/solana/simple.sol:1:1-14"]
+	diagnostic_45 [label="found library 'L'\nlevel Debug\ntests/contract_testcases/solana/simple.sol:2:1-13"]
+	diagnostic_46 [label="error 'E' has never been used\nlevel Warning\ntests/contract_testcases/solana/simple.sol:3:7-8"]
 	structs -> S
+	errors -> E
 	free_functions -> inc [label="function"]
 	inc -> parameters [label="parameters"]
 	inc -> expr [label="body"]
@@ -48,35 +51,36 @@ strict digraph "tests/contract_testcases/solana/using_import.sol" {
 	structmember -> variable [label="var"]
 	assign -> add [label="right"]
 	add -> load [label="left"]
-	load -> structmember_11 [label="expr"]
-	structmember_11 -> variable_12 [label="var"]
+	load -> structmember_13 [label="expr"]
+	structmember_13 -> variable_14 [label="var"]
 	add -> number_literal [label="right"]
 	free_functions -> dec [label="function"]
-	dec -> parameters_15 [label="parameters"]
-	dec -> expr_16 [label="body"]
-	expr_16 -> assign_17 [label="expr"]
-	assign_17 -> structmember_18 [label="left"]
-	structmember_18 -> variable_19 [label="var"]
-	assign_17 -> subtract [label="right"]
-	subtract -> load_21 [label="left"]
-	load_21 -> structmember_22 [label="expr"]
-	structmember_22 -> variable_23 [label="var"]
-	subtract -> number_literal_24 [label="right"]
+	dec -> parameters_17 [label="parameters"]
+	dec -> expr_18 [label="body"]
+	expr_18 -> assign_19 [label="expr"]
+	assign_19 -> structmember_20 [label="left"]
+	structmember_20 -> variable_21 [label="var"]
+	assign_19 -> subtract [label="right"]
+	subtract -> load_23 [label="left"]
+	load_23 -> structmember_24 [label="expr"]
+	structmember_24 -> variable_25 [label="var"]
+	subtract -> number_literal_26 [label="right"]
 	contracts -> contract
 	contract -> test [label="function"]
-	test -> parameters_28 [label="parameters"]
-	test -> expr_29 [label="body"]
-	expr_29 -> call_internal_function [label="expr"]
+	test -> parameters_30 [label="parameters"]
+	test -> expr_31 [label="body"]
+	expr_31 -> call_internal_function [label="expr"]
 	call_internal_function -> internal_function [label="function"]
-	call_internal_function -> variable_32 [label="arg #0"]
-	expr_29 -> expr_33 [label="next"]
-	expr_33 -> call_internal_function_34 [label="expr"]
-	call_internal_function_34 -> internal_function_35 [label="function"]
-	call_internal_function_34 -> variable_36 [label="arg #0"]
-	contracts -> contract_37
-	contracts -> contract_38
+	call_internal_function -> variable_34 [label="arg #0"]
+	expr_31 -> expr_35 [label="next"]
+	expr_35 -> call_internal_function_36 [label="expr"]
+	call_internal_function_36 -> internal_function_37 [label="function"]
+	call_internal_function_36 -> variable_38 [label="arg #0"]
+	contracts -> contract_39
+	contracts -> contract_40
 	diagnostics -> diagnostic [label="Debug"]
-	diagnostics -> diagnostic_41 [label="Warning"]
-	diagnostics -> diagnostic_42 [label="Debug"]
-	diagnostics -> diagnostic_43 [label="Debug"]
+	diagnostics -> diagnostic_43 [label="Warning"]
+	diagnostics -> diagnostic_44 [label="Debug"]
+	diagnostics -> diagnostic_45 [label="Debug"]
+	diagnostics -> diagnostic_46 [label="Warning"]
 }

+ 1 - 1
tests/solana_tests/runtime_errors.rs

@@ -314,7 +314,7 @@ contract calle_contract {
 
     assert_eq!(
         vm.logs,
-        "runtime_error: revert encountered in test.sol:70:9-15,\n"
+        "runtime_error: revert encountered in test.sol:70:9-17,\n"
     );
 
     vm.logs.clear();

+ 1 - 1
tests/substrate_tests/debug_buffer_format.rs

@@ -40,7 +40,7 @@ call: seal_debug_message=0,
 call: seal_debug_message=0,
 print: I call seal_debug_message under the hood!,
 call: seal_debug_message=0,
-runtime_error: sesa!!! revert encountered in test.sol:10:17-23,
+runtime_error: sesa!!! revert encountered in test.sol:10:17-34,
 call: seal_debug_message=0,
 "#
     );

+ 1 - 1
tests/substrate_tests/errors.rs

@@ -235,7 +235,7 @@ fn errors() {
 
     assert_eq!(
         runtime.printbuf,
-        "runtime_error: revert encountered in test.sol:84:13-19,\n"
+        "runtime_error: revert encountered in test.sol:84:13-21,\n"
     );
 
     runtime.printbuf.clear();

Some files were not shown because too many files changed in this diff