Skip to content

Commit

Permalink
fix[tool]: compile multiple files (#4053)
Browse files Browse the repository at this point in the history
fix compilation for multiple files where they initialize the same
module. the analysis was getting cached between compilations, leading to
a compiler panic on allocating the storage layout (because the module
was previously touched by the allocator).

this was not caught in previous testing because the pattern in the test
suite is to run a single compilation per test, with a fresh input
bundle.
  • Loading branch information
charles-cooper authored May 28, 2024
1 parent d6b300d commit 003d0c6
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 7 deletions.
38 changes: 38 additions & 0 deletions tests/unit/cli/storage_layout/test_storage_layout.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from vyper.compiler import compile_code
from vyper.evm.opcodes import version_check

from .utils import adjust_storage_layout_for_cancun

Expand Down Expand Up @@ -342,3 +343,40 @@ def foo() -> uint256:

out = compile_code(code, input_bundle=input_bundle, output_formats=["layout"])
assert out["layout"] == expected_layout


def test_multiple_compile_codes(make_input_bundle):
# test calling compile_code multiple times with the same library allocated
# in different locations
lib = """
x: uint256
"""
input_bundle = make_input_bundle({"lib.vy": lib})

main1 = """
import lib
initializes: lib
t: uint256
"""
main2 = """
import lib
t: uint256
initializes: lib
"""
out1 = compile_code(main1, input_bundle=input_bundle, output_formats=["layout"])["layout"]
out2 = compile_code(main2, input_bundle=input_bundle, output_formats=["layout"])["layout"]

layout1 = out1["storage_layout"]["lib"]
layout2 = out2["storage_layout"]["lib"]

assert layout1 != layout2 # for clarity

if version_check(begin="cancun"):
start_slot = 0
else:
start_slot = 1

assert layout1 == {"x": {"slot": start_slot, "type": "uint256", "n_slots": 1}}
assert layout2 == {"x": {"slot": start_slot + 1, "type": "uint256", "n_slots": 1}}
34 changes: 31 additions & 3 deletions tests/unit/compiler/test_compile_code.py

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions vyper/compiler/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ def compile_from_file_input(
output_formats = ("bytecode",)

# make IR output the same between runs
# TODO: move this to CompilerData.__init__()
codegen.reset_names()

compiler_data = CompilerData(
Expand Down
3 changes: 3 additions & 0 deletions vyper/compiler/phases.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ def __init__(
self.input_bundle = input_bundle or FilesystemInputBundle([Path(".")])
self.expected_integrity_sum = integrity_sum

# ast cache, hitchhike onto the input_bundle object
self.input_bundle._cache._ast_of: dict[int, vy_ast.Module] = {} # type: ignore

@cached_property
def source_code(self):
return self.file_input.source_code
Expand Down
4 changes: 0 additions & 4 deletions vyper/semantics/analysis/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,10 +199,6 @@ def __init__(

self.module_t: Optional[ModuleT] = None

# ast cache, hitchhike onto the input_bundle object
if not hasattr(self.input_bundle._cache, "_ast_of"):
self.input_bundle._cache._ast_of: dict[int, vy_ast.Module] = {} # type: ignore

def analyze_module_body(self):
# generate a `ModuleT` from the top-level node
# note: also validates unique method ids
Expand Down

0 comments on commit 003d0c6

Please sign in to comment.