Repository: vyperlang/vyper

Issue:
Compile time evaluation of several builtins wrongfully allows `decimal` arguments.
### Version Information

* vyper Version (output of `vyper --version`): 0.3.9+commit.5c2892b2
* OS: OSX
* Python Version (output of `python --version`): 3.11.3

### What's your issue about?

The arguments of the following builtins are not well type-checked when they all are constant and the builtin is to be folded: (Should be `Int` AST nodes while the functions expect `Num` AST nodes):

- `uint256_addmod`
- `uint256_mulmod`
- `shift` (deprecated)
- `BitwiseAnd`, `BitwiseOr`, `BitwiseXor`, `BitwiseNot` (all deprecated)

For example, trying to compile the following contract will make the compiler panic:

```Vyper
@external
def foo():
    ds:uint256 = uint256_addmod(1.1,2.2,2)
```
```Bash
Error compiling: tests/customs/code.vy
Traceback (most recent call last):
  File "/Users/trocher/Documents/thesis/vyper/venv/bin/vyper", line 33, in <module>
    sys.exit(load_entry_point('vyper==0.3.9', 'console_scripts', 'vyper')())
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/trocher/Documents/thesis/vyper/vyper/cli/vyper_compile.py", line 58, in _parse_cli_args
    return _parse_args(sys.argv[1:])
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/trocher/Documents/thesis/vyper/vyper/cli/vyper_compile.py", line 156, in _parse_args
    compiled = compile_files(
               ^^^^^^^^^^^^^^
  File "/Users/trocher/Documents/thesis/vyper/vyper/cli/vyper_compile.py", line 294, in compile_files
    compiler_data = vyper.compile_codes(
                    ^^^^^^^^^^^^^^^^^^^^
  File "/Users/trocher/Documents/thesis/vyper/vyper/evm/opcodes.py", line 230, in _wrapper
    return fn(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^
  File "/Users/trocher/Documents/thesis/vyper/vyper/compiler/__init__.py", line 142, in compile_codes
    exc_handler(contract_name, exc)
  File "/Users/trocher/Documents/thesis/vyper/vyper/cli/vyper_compile.py", line 191, in exc_handler
    raise exception
  File "/Users/trocher/Documents/thesis/vyper/vyper/compiler/__init__.py", line 139, in compile_codes
    out[contract_name][output_format] = OUTPUT_FORMATS[output_format](compiler_data)
                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/trocher/Documents/thesis/vyper/vyper/compiler/output.py", line 82, in build_ir_output
    return compiler_data.ir_nodes
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/trocher/Documents/thesis/vyper/vyper/compiler/phases.py", line 126, in ir_nodes
    ir, ir_runtime = self._ir_output
                     ^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/functools.py", line 1001, in __get__
    val = self.func(instance)
          ^^^^^^^^^^^^^^^^^^^
  File "/Users/trocher/Documents/thesis/vyper/vyper/compiler/phases.py", line 122, in _ir_output
    return generate_ir_nodes(self.global_ctx, self.no_optimize)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/trocher/Documents/thesis/vyper/vyper/compiler/phases.py", line 259, in generate_ir_nodes
    ir_nodes, ir_runtime = module.generate_ir_for_module(global_ctx)
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/trocher/Documents/thesis/vyper/vyper/codegen/module.py", line 149, in generate_ir_for_module
    runtime = _runtime_ir(runtime_functions, global_ctx)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/trocher/Documents/thesis/vyper/vyper/codegen/module.py", line 106, in _runtime_ir
    func_ir = generate_ir_for_function(func_ast, global_ctx, skip_nonpayable_check)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/trocher/Documents/thesis/vyper/vyper/codegen/function_definitions/common.py", line 114, in generate_ir_for_function
    o = generate_ir_for_external_function(code, func_t, context, skip_nonpayable_check)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/trocher/Documents/thesis/vyper/vyper/codegen/function_definitions/external_function.py", line 187, in generate_ir_for_external_function
    body += [parse_body(code.body, context, ensure_terminated=True)]
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/trocher/Documents/thesis/vyper/vyper/codegen/stmt.py", line 433, in parse_body
    ir = parse_stmt(stmt, context)
         ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/trocher/Documents/thesis/vyper/vyper/codegen/stmt.py", line 407, in parse_stmt
    return Stmt(stmt, context).ir_node
           ^^^^^^^^^^^^^^^^^^^
  File "/Users/trocher/Documents/thesis/vyper/vyper/codegen/stmt.py", line 41, in __init__
    self.ir_node = fn()
                   ^^^^
  File "/Users/trocher/Documents/thesis/vyper/vyper/codegen/stmt.py", line 68, in parse_AnnAssign
    rhs = Expr(self.stmt.value, self.context).ir_node
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/trocher/Documents/thesis/vyper/vyper/codegen/expr.py", line 80, in __init__
    self.ir_node = fn()
                   ^^^^
  File "/Users/trocher/Documents/thesis/vyper/vyper/codegen/expr.py", line 89, in parse_Int
    return IRnode.from_list(self.expr.n, typ=typ)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/trocher/Documents/thesis/vyper/vyper/codegen/ir_node.py", line 532, in from_list
    return cls(
           ^^^^
  File "/Users/trocher/Documents/thesis/vyper/vyper/codegen/ir_node.py", line 319, in __init__
    raise CompilerPanic(f"Invalid value for IR AST node: {self.value}")
vyper.exceptions.CompilerPanic: Invalid value for IR AST node: 1.3

This is an unhandled internal compiler error. Please create an issue on Github to notify the developers.
https://github.com/vyperlang/vyper/issues/new?template=bug.md
```

### How can it be fixed?

Replacing `vy_ast.Num` by `vy_ast.Int` in the `evaluate` method of the classes of the builtins should be enough.

Discussion:
codecov-commenter: ## [Codecov](https://app.codecov.io/gh/vyperlang/vyper/pull/3490?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=vyperlang) Report
> Merging [#3490](https://app.codecov.io/gh/vyperlang/vyper/pull/3490?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=vyperlang) (448b9c1) into [master](https://app.codecov.io/gh/vyperlang/vyper/commit/c90ab2fb26d66ad2121bf967dabe738ee8eaf21e?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=vyperlang) (c90ab2f) will **decrease** coverage by `21.76%`.
> The diff coverage is `0.00%`.

:exclamation: Your organization is not using the GitHub App Integration. As a result you may experience degraded service beginning May 15th. Please [install the Github App Integration](https://github.com/apps/codecov) for your organization. [Read more](https://about.codecov.io/blog/codecov-is-updating-its-github-integration/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=vyperlang).

```diff
@@             Coverage Diff             @@
##           master    #3490       +/-   ##
===========================================
- Coverage   89.35%   67.60%   -21.76%     
===========================================
  Files          84       84               
  Lines       10777    10777               
  Branches     2456     2456               
===========================================
- Hits         9630     7286     -2344     
- Misses        751     2861     +2110     
- Partials      396      630      +234     
```


| [Impacted Files](https://app.codecov.io/gh/vyperlang/vyper/pull/3490?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=vyperlang) | Coverage Δ | |
|---|---|---|
| [vyper/builtins/functions.py](https://app.codecov.io/gh/vyperlang/vyper/pull/3490?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=vyperlang#diff-dnlwZXIvYnVpbHRpbnMvZnVuY3Rpb25zLnB5) | `61.80% <0.00%> (-28.71%)` | :arrow_down: |

... and [55 files with indirect coverage changes](https://app.codecov.io/gh/vyperlang/vyper/pull/3490/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=vyperlang)

:mega: We’re building smart automated test selection to slash your CI/CD build times. [Learn more](https://about.codecov.io/iterative-testing/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=vyperlang)


Patch:
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index f891ff7e..b4be1043 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -38,7 +38,7 @@ jobs:
 
       - name: Generate Binary
         run: >-
-          pip install . &&
+          pip install --no-binary pycryptodome . &&
           pip install pyinstaller &&
           make freeze
 
diff --git a/vyper/builtins/functions.py b/vyper/builtins/functions.py
index af965afe..90214554 100644
--- a/vyper/builtins/functions.py
+++ b/vyper/builtins/functions.py
@@ -1370,7 +1370,7 @@ class BitwiseAnd(BuiltinFunction):
 
         validate_call_args(node, 2)
         for arg in node.args:
-            if not isinstance(arg, vy_ast.Num):
+            if not isinstance(arg, vy_ast.Int):
                 raise UnfoldableNode
             if arg.value < 0 or arg.value >= 2**256:
                 raise InvalidLiteral("Value out of range for uint256", arg)
@@ -1396,7 +1396,7 @@ class BitwiseOr(BuiltinFunction):
 
         validate_call_args(node, 2)
         for arg in node.args:
-            if not isinstance(arg, vy_ast.Num):
+            if not isinstance(arg, vy_ast.Int):
                 raise UnfoldableNode
             if arg.value < 0 or arg.value >= 2**256:
                 raise InvalidLiteral("Value out of range for uint256", arg)
@@ -1422,7 +1422,7 @@ class BitwiseXor(BuiltinFunction):
 
         validate_call_args(node, 2)
         for arg in node.args:
-            if not isinstance(arg, vy_ast.Num):
+            if not isinstance(arg, vy_ast.Int):
                 raise UnfoldableNode
             if arg.value < 0 or arg.value >= 2**256:
                 raise InvalidLiteral("Value out of range for uint256", arg)
@@ -1447,7 +1447,7 @@ class BitwiseNot(BuiltinFunction):
             self.__class__._warned = True
 
         validate_call_args(node, 1)
-        if not isinstance(node.args[0], vy_ast.Num):
+        if not isinstance(node.args[0], vy_ast.Int):
             raise UnfoldableNode
 
         value = node.args[0].value
@@ -1474,7 +1474,7 @@ class Shift(BuiltinFunction):
             self.__class__._warned = True
 
         validate_call_args(node, 2)
-        if [i for i in node.args if not isinstance(i, vy_ast.Num)]:
+        if [i for i in node.args if not isinstance(i, vy_ast.Int)]:
             raise UnfoldableNode
         value, shift = [i.value for i in node.args]
         if value < 0 or value >= 2**256:
@@ -1522,10 +1522,10 @@ class _AddMulMod(BuiltinFunction):
 
     def evaluate(self, node):
         validate_call_args(node, 3)
-        if isinstance(node.args[2], vy_ast.Num) and node.args[2].value == 0:
+        if isinstance(node.args[2], vy_ast.Int) and node.args[2].value == 0:
             raise ZeroDivisionException("Modulo by 0", node.args[2])
         for arg in node.args:
-            if not isinstance(arg, vy_ast.Num):
+            if not isinstance(arg, vy_ast.Int):
                 raise UnfoldableNode
             if arg.value < 0 or arg.value >= 2**256:
                 raise InvalidLiteral("Value out of range for uint256", arg)
diff --git a/vyper/codegen/ir_node.py b/vyper/codegen/ir_node.py
index d36a18ec..f7698fba 100644
--- a/vyper/codegen/ir_node.py
+++ b/vyper/codegen/ir_node.py
@@ -38,11 +38,6 @@ class NullAttractor(int):
     __mul__ = __add__
 
 
-def push_label_to_stack(labelname: str) -> str:
-    #  items prefixed with `_sym_` are ignored until asm phase
-    return "_sym_" + labelname
-
-
 class Encoding(Enum):
     # vyper encoding, default for memory variables
     VYPER = auto()
diff --git a/vyper/codegen/return_.py b/vyper/codegen/return_.py
index b8468f3e..56bea2b8 100644
--- a/vyper/codegen/return_.py
+++ b/vyper/codegen/return_.py
@@ -21,7 +21,7 @@ Stmt = Any  # mypy kludge
 def make_return_stmt(ir_val: IRnode, stmt: Any, context: Context) -> Optional[IRnode]:
     func_t = context.func_t
 
-    jump_to_exit = ["exit_to", f"_sym_{func_t._ir_info.exit_sequence_label}"]
+    jump_to_exit = ["exit_to", func_t._ir_info.exit_sequence_label]
 
     if context.return_type is None:
         if stmt.value is not None:
@@ -43,7 +43,8 @@ def make_return_stmt(ir_val: IRnode, stmt: Any, context: Context) -> Optional[IR
         return IRnode.from_list(["seq", fill_return_buffer, cleanup_loops, jump_to_exit])
 
     if context.return_type is None:
-        jump_to_exit += ["return_pc"]
+        if context.is_internal:
+            jump_to_exit += ["return_pc"]
         return finalize(["seq"])
 
     if context.is_internal:
diff --git a/vyper/codegen/self_call.py b/vyper/codegen/self_call.py
index 31157619..c320e688 100644
--- a/vyper/codegen/self_call.py
+++ b/vyper/codegen/self_call.py
@@ -1,5 +1,5 @@
 from vyper.codegen.core import _freshname, eval_once_check, make_setter
-from vyper.codegen.ir_node import IRnode, push_label_to_stack
+from vyper.codegen.ir_node import IRnode
 from vyper.evm.address_space import MEMORY
 from vyper.exceptions import StateAccessViolation
 from vyper.semantics.types.subscriptable import TupleT
@@ -104,7 +104,7 @@ def ir_for_self_call(stmt_expr, context):
     if return_buffer is not None:
         goto_op += [return_buffer]
     # pass return label to subroutine
-    goto_op += [push_label_to_stack(return_label)]
+    goto_op.append(["symbol", return_label])
 
     call_sequence = ["seq"]
     call_sequence.append(eval_once_check(_freshname(stmt_expr.node_source_code)))
diff --git a/vyper/compiler/output.py b/vyper/compiler/output.py
index f061bd8e..63d92d9a 100644
--- a/vyper/compiler/output.py
+++ b/vyper/compiler/output.py
@@ -218,9 +218,7 @@ def _build_asm(asm_list):
 
 def build_source_map_output(compiler_data: CompilerData) -> OrderedDict:
     _, line_number_map = compile_ir.assembly_to_evm(
-        compiler_data.assembly_runtime,
-        insert_vyper_signature=True,
-        disable_bytecode_metadata=compiler_data.no_bytecode_metadata,
+        compiler_data.assembly_runtime, insert_vyper_signature=False
     )
     # Sort line_number_map
     out = OrderedDict()
diff --git a/vyper/compiler/phases.py b/vyper/compiler/phases.py
index 5156aa1b..c759f6e2 100644
--- a/vyper/compiler/phases.py
+++ b/vyper/compiler/phases.py
@@ -150,15 +150,12 @@ class CompilerData:
 
     @cached_property
     def bytecode(self) -> bytes:
-        return generate_bytecode(
-            self.assembly, is_runtime=False, no_bytecode_metadata=self.no_bytecode_metadata
-        )
+        insert_vyper_signature = not self.no_bytecode_metadata
+        return generate_bytecode(self.assembly, insert_vyper_signature=insert_vyper_signature)
 
     @cached_property
     def bytecode_runtime(self) -> bytes:
-        return generate_bytecode(
-            self.assembly_runtime, is_runtime=True, no_bytecode_metadata=self.no_bytecode_metadata
-        )
+        return generate_bytecode(self.assembly_runtime, insert_vyper_signature=False)
 
     @cached_property
     def blueprint_bytecode(self) -> bytes:
@@ -295,9 +292,7 @@ def _find_nested_opcode(assembly, key):
         return any(_find_nested_opcode(x, key) for x in sublists)
 
 
-def generate_bytecode(
-    assembly: list, is_runtime: bool = False, no_bytecode_metadata: bool = False
-) -> bytes:
+def generate_bytecode(assembly: list, insert_vyper_signature: bool) -> bytes:
     """
     Generate bytecode from assembly instructions.
 
@@ -311,6 +306,4 @@ def generate_bytecode(
     bytes
         Final compiled bytecode.
     """
-    return compile_ir.assembly_to_evm(
-        assembly, insert_vyper_signature=is_runtime, disable_bytecode_metadata=no_bytecode_metadata
-    )[0]
+    return compile_ir.assembly_to_evm(assembly, insert_vyper_signature=insert_vyper_signature)[0]
diff --git a/vyper/ir/compile_ir.py b/vyper/ir/compile_ir.py
index b2a58fa8..5a35b8f9 100644
--- a/vyper/ir/compile_ir.py
+++ b/vyper/ir/compile_ir.py
@@ -118,14 +118,14 @@ def _rewrite_return_sequences(ir_node, label_params=None):
             args[0].value = "pass"
         else:
             # handle jump to cleanup
-            assert is_symbol(args[0].value)
             ir_node.value = "seq"
 
             _t = ["seq"]
             if "return_buffer" in label_params:
                 _t.append(["pop", "pass"])
 
-            dest = args[0].value[5:]  # `_sym_foo` -> `foo`
+            dest = args[0].value
+            # works for both internal and external exit_to
             more_args = ["pass" if t.value == "return_pc" else t for t in args[1:]]
             _t.append(["goto", dest] + more_args)
             ir_node.args = IRnode.from_list(_t, source_pos=ir_node.source_pos).args
@@ -667,8 +667,8 @@ def _compile_to_assembly(code, withargs=None, existing_labels=None, break_dest=N
         o.extend(["_sym_" + str(code.args[0]), "JUMP"])
         return o
     # push a literal symbol
-    elif isinstance(code.value, str) and is_symbol(code.value):
-        return [code.value]
+    elif code.value == "symbol":
+        return ["_sym_" + str(code.args[0])]
     # set a symbol as a location.
     elif code.value == "label":
         label_name = code.args[0].value
@@ -968,9 +968,7 @@ def adjust_pc_maps(pc_maps, ofst):
     return ret
 
 
-def assembly_to_evm(
-    assembly, pc_ofst=0, insert_vyper_signature=False, disable_bytecode_metadata=False
-):
+def assembly_to_evm(assembly, pc_ofst=0, insert_vyper_signature=False):
     """
     Assembles assembly into EVM
 
@@ -994,7 +992,7 @@ def assembly_to_evm(
     runtime_code, runtime_code_start, runtime_code_end = None, None, None
 
     bytecode_suffix = b""
-    if (not disable_bytecode_metadata) and insert_vyper_signature:
+    if insert_vyper_signature:
         # CBOR encoded: {"vyper": [major,minor,patch]}
         bytecode_suffix += b"\xa1\x65vyper\x83" + bytes(list(version_tuple))
         bytecode_suffix += len(bytecode_suffix).to_bytes(2, "big")
@@ -1011,11 +1009,7 @@ def assembly_to_evm(
     for i, item in enumerate(assembly):
         if isinstance(item, list):
             assert runtime_code is None, "Multiple subcodes"
-            runtime_code, runtime_map = assembly_to_evm(
-                item,
-                insert_vyper_signature=True,
-                disable_bytecode_metadata=disable_bytecode_metadata,
-            )
+            runtime_code, runtime_map = assembly_to_evm(item)
 
             assert item[0].startswith("_DEPLOY_MEM_OFST_")
             assert ctor_mem_size is None
diff --git a/vyper/semantics/analysis/module.py b/vyper/semantics/analysis/module.py
index cb8e93ff..d916dcf1 100644
--- a/vyper/semantics/analysis/module.py
+++ b/vyper/semantics/analysis/module.py
@@ -98,7 +98,7 @@ class ModuleAnalyzer(VyperNodeVisitorBase):
         _ns = Namespace()
         # note that we don't just copy the namespace because
         # there are constructor issues.
-        _ns.update({k: namespace[k] for k in namespace._scopes[-1]})
+        _ns.update({k: namespace[k] for k in namespace._scopes[-1]})  # type: ignore
         module_node._metadata["namespace"] = _ns
 
         # check for collisions between 4byte function selectors
diff --git a/vyper/semantics/analysis/utils.py b/vyper/semantics/analysis/utils.py
index 26f3fd18..f16b0c8c 100644
--- a/vyper/semantics/analysis/utils.py
+++ b/vyper/semantics/analysis/utils.py
@@ -24,7 +24,7 @@ from vyper.semantics.types.base import TYPE_T, VyperType
 from vyper.semantics.types.bytestrings import BytesT, StringT
 from vyper.semantics.types.primitives import AddressT, BoolT, BytesM_T, IntegerT
 from vyper.semantics.types.subscriptable import DArrayT, SArrayT, TupleT
-from vyper.utils import checksum_encode
+from vyper.utils import checksum_encode, int_to_fourbytes
 
 
 def _validate_op(node, types_list, validation_fn_name):
@@ -593,8 +593,13 @@ def validate_unique_method_ids(functions: List) -> None:
     seen = set()
     for method_id in method_ids:
         if method_id in seen:
-            collision_str = ", ".join(i.name for i in functions if method_id in i.method_ids)
-            raise StructureException(f"Methods have conflicting IDs: {collision_str}")
+            collision_str = ", ".join(
+                x for i in functions for x in i.method_ids.keys() if i.method_ids[x] == method_id
+            )
+            collision_hex = int_to_fourbytes(method_id).hex()
+            raise StructureException(
+                f"Methods produce colliding method ID `0x{collision_hex}`: {collision_str}"
+            )
         seen.add(method_id)
 
 
diff --git a/vyper/semantics/namespace.py b/vyper/semantics/namespace.py
index 82a5d5cf..b88bc3d8 100644
--- a/vyper/semantics/namespace.py
+++ b/vyper/semantics/namespace.py
@@ -20,9 +20,13 @@ class Namespace(dict):
         List of sets containing the key names for each scope
     """
 
+    def __new__(cls, *args, **kwargs):
+        self = super().__new__(cls, *args, **kwargs)
+        self._scopes = []
+        return self
+
     def __init__(self):
         super().__init__()
-        self._scopes = []
         # NOTE cyclic imports!
         # TODO: break this cycle by providing an `init_vyper_namespace` in 3rd module
         from vyper.builtins.functions import get_builtin_functions


Test patch:
diff --git a/tests/parser/features/test_assignment.py b/tests/parser/features/test_assignment.py
index 29ec8204..e550f605 100644
--- a/tests/parser/features/test_assignment.py
+++ b/tests/parser/features/test_assignment.py
@@ -367,17 +367,33 @@ def foo():
 """
     assert_compile_failed(lambda: get_contract_with_gas_estimation(code), InvalidType)
 
-
-def test_assign_rhs_lhs_overlap(get_contract):
     # GH issue 2418
-    code = """
+
+
+overlap_codes = [
+    """
 @external
 def bug(xs: uint256[2]) -> uint256[2]:
     # Initial value
     ys: uint256[2] = xs
     ys = [ys[1], ys[0]]
     return ys
+    """,
     """
+foo: uint256[2]
+@external
+def bug(xs: uint256[2]) -> uint256[2]:
+    # Initial value
+    self.foo = xs
+    self.foo = [self.foo[1], self.foo[0]]
+    return self.foo
+    """,
+    # TODO add transient tests when it's available
+]
+
+
+@pytest.mark.parametrize("code", overlap_codes)
+def test_assign_rhs_lhs_overlap(get_contract, code):
     c = get_contract(code)
 
     assert c.bug([1, 2]) == [2, 1]
diff --git a/tests/parser/syntax/test_addmulmod.py b/tests/parser/syntax/test_addmulmod.py
new file mode 100644
index 00000000..ddff4d3e
--- /dev/null
+++ b/tests/parser/syntax/test_addmulmod.py
@@ -0,0 +1,27 @@
+import pytest
+
+from vyper.exceptions import InvalidType
+
+fail_list = [
+    (  # bad AST nodes given as arguments
+        """
+@external
+def foo() -> uint256:
+    return uint256_addmod(1.1, 1.2, 3.0)
+    """,
+        InvalidType,
+    ),
+    (  # bad AST nodes given as arguments
+        """
+@external
+def foo() -> uint256:
+    return uint256_mulmod(1.1, 1.2, 3.0)
+    """,
+        InvalidType,
+    ),
+]
+
+
+@pytest.mark.parametrize("code,exc", fail_list)
+def test_add_mod_fail(assert_compile_failed, get_contract, code, exc):
+    assert_compile_failed(lambda: get_contract(code), exc)
diff --git a/tests/signatures/test_method_id_conflicts.py b/tests/signatures/test_method_id_conflicts.py
index 262348c1..35c10300 100644
--- a/tests/signatures/test_method_id_conflicts.py
+++ b/tests/signatures/test_method_id_conflicts.py
@@ -67,6 +67,13 @@ def gfah(): pass
 @view
 def eexo(): pass
     """,
+    """
+# check collision with ID = 0x00000000
+wycpnbqcyf:public(uint256)
+
+@external
+def randallsRevenge_ilxaotc(): pass
+    """,
 ]