Skip to content

Commit 194d60a

Browse files
fix[tool]: fix output formats for .vyz files (#4338)
run the format name through the translate map. for instance, `annotated_ast` output format was not working for `.vyz` files. this commit has some additional fixes that were discovered when adding the integration tests and refactoring related to the settings not getting propagated uniformly across different entry points. --------- Co-authored-by: cyberthirst <[email protected]>
1 parent 614ea0d commit 194d60a

File tree

9 files changed

+155
-15
lines changed

9 files changed

+155
-15
lines changed

tests/functional/venom/test_venom_repr.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from tests.venom_utils import assert_ctx_eq, parse_venom
88
from vyper.compiler import compile_code
99
from vyper.compiler.phases import generate_bytecode
10+
from vyper.compiler.settings import OptimizationLevel
1011
from vyper.venom import generate_assembly_experimental, run_passes_on
1112
from vyper.venom.context import IRContext
1213

@@ -20,14 +21,19 @@ def get_example_vy_filenames():
2021

2122

2223
@pytest.mark.parametrize("vy_filename", get_example_vy_filenames())
23-
def test_round_trip_examples(vy_filename, optimize, compiler_settings):
24+
def test_round_trip_examples(vy_filename, debug, optimize, compiler_settings, request):
2425
"""
2526
Check all examples round trip
2627
"""
2728
path = f"examples/{vy_filename}"
2829
with open(path) as f:
2930
vyper_source = f.read()
3031

32+
if debug and optimize == OptimizationLevel.CODESIZE:
33+
# FIXME: some round-trips fail when debug is enabled due to labels
34+
# not getting pinned
35+
request.node.add_marker(pytest.mark.xfail(strict=False))
36+
3137
_round_trip_helper(vyper_source, optimize, compiler_settings)
3238

3339

@@ -45,11 +51,17 @@ def _loop() -> uint256:
4551

4652

4753
@pytest.mark.parametrize("vyper_source", vyper_sources)
48-
def test_round_trip_sources(vyper_source, optimize, compiler_settings):
54+
def test_round_trip_sources(vyper_source, debug, optimize, compiler_settings, request):
4955
"""
5056
Test vyper_sources round trip
5157
"""
5258
vyper_source = textwrap.dedent(vyper_source)
59+
60+
if debug and optimize == OptimizationLevel.CODESIZE:
61+
# FIXME: some round-trips fail when debug is enabled due to labels
62+
# not getting pinned
63+
request.node.add_marker(pytest.mark.xfail(strict=False))
64+
5365
_round_trip_helper(vyper_source, optimize, compiler_settings)
5466

5567

tests/unit/cli/vyper_compile/test_compile_files.py

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,105 @@ def test_archive_b64_output(input_files):
361361
assert out[contract_file] == out2[archive_path]
362362

363363

364+
def test_archive_compile_options(input_files):
365+
tmpdir, _, _, contract_file = input_files
366+
search_paths = [".", tmpdir]
367+
368+
options = ["abi_python", "json", "ast", "annotated_ast", "ir_json"]
369+
370+
for option in options:
371+
out = compile_files([contract_file], ["archive_b64", option], paths=search_paths)
372+
373+
archive_b64 = out[contract_file].pop("archive_b64")
374+
375+
archive_path = Path("foo.zip.b64")
376+
with archive_path.open("w") as f:
377+
f.write(archive_b64)
378+
379+
# compare compiling the two input bundles
380+
out2 = compile_files([archive_path], [option])
381+
382+
if option in ["ast", "annotated_ast"]:
383+
# would have to normalize paths and imports, so just verify it compiles
384+
continue
385+
386+
assert out[contract_file] == out2[archive_path]
387+
388+
389+
format_options = [
390+
"bytecode",
391+
"bytecode_runtime",
392+
"blueprint_bytecode",
393+
"abi",
394+
"abi_python",
395+
"source_map",
396+
"source_map_runtime",
397+
"method_identifiers",
398+
"userdoc",
399+
"devdoc",
400+
"metadata",
401+
"combined_json",
402+
"layout",
403+
"ast",
404+
"annotated_ast",
405+
"interface",
406+
"external_interface",
407+
"opcodes",
408+
"opcodes_runtime",
409+
"ir",
410+
"ir_json",
411+
"ir_runtime",
412+
"asm",
413+
"integrity",
414+
"archive",
415+
"solc_json",
416+
]
417+
418+
419+
def test_compile_vyz_with_options(input_files):
420+
tmpdir, _, _, contract_file = input_files
421+
search_paths = [".", tmpdir]
422+
423+
for option in format_options:
424+
out_archive = compile_files([contract_file], ["archive"], paths=search_paths)
425+
426+
archive = out_archive[contract_file].pop("archive")
427+
428+
archive_path = Path("foo.zip.out.vyz")
429+
with archive_path.open("wb") as f:
430+
f.write(archive)
431+
432+
# compare compiling the two input bundles
433+
out = compile_files([contract_file], [option], paths=search_paths)
434+
out2 = compile_files([archive_path], [option])
435+
436+
if option in ["ast", "annotated_ast", "metadata"]:
437+
# would have to normalize paths and imports, so just verify it compiles
438+
continue
439+
440+
if option in ["ir_runtime", "ir", "archive"]:
441+
# ir+ir_runtime is different due to being different compiler runs
442+
# archive is different due to different metadata (timestamps)
443+
continue
444+
445+
assert out[contract_file] == out2[archive_path]
446+
447+
448+
def test_archive_compile_simultaneous_options(input_files):
449+
tmpdir, _, _, contract_file = input_files
450+
search_paths = [".", tmpdir]
451+
452+
for option in format_options:
453+
with pytest.raises(ValueError) as e:
454+
_ = compile_files([contract_file], ["archive", option], paths=search_paths)
455+
456+
err_opt = "archive"
457+
if option in ("combined_json", "solc_json"):
458+
err_opt = option
459+
460+
assert f"If using {err_opt} it must be the only output format requested" in str(e.value)
461+
462+
364463
def test_solc_json_output(input_files):
365464
tmpdir, _, _, contract_file = input_files
366465
search_paths = [".", tmpdir]

tests/unit/cli/vyper_json/test_compile_json.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ def oopsie(a: uint256) -> bool:
7373

7474

7575
@pytest.fixture(scope="function")
76-
def input_json(optimize, evm_version, experimental_codegen):
76+
def input_json(optimize, evm_version, experimental_codegen, debug):
7777
return {
7878
"language": "Vyper",
7979
"sources": {
@@ -87,6 +87,7 @@ def input_json(optimize, evm_version, experimental_codegen):
8787
"optimize": optimize.name.lower(),
8888
"evmVersion": evm_version,
8989
"experimentalCodegen": experimental_codegen,
90+
"debug": debug,
9091
},
9192
}
9293

tests/unit/compiler/test_bytecode_runtime.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ def test_bytecode_runtime():
5454
assert out["bytecode_runtime"].removeprefix("0x") in out["bytecode"].removeprefix("0x")
5555

5656

57-
def test_bytecode_signature():
57+
def test_bytecode_signature(optimize, debug):
5858
out = vyper.compile_code(
5959
simple_contract_code, output_formats=["bytecode_runtime", "bytecode", "integrity"]
6060
)
@@ -65,10 +65,16 @@ def test_bytecode_signature():
6565
metadata = _parse_cbor_metadata(initcode)
6666
integrity_hash, runtime_len, data_section_lengths, immutables_len, compiler = metadata
6767

68+
if debug and optimize == OptimizationLevel.CODESIZE:
69+
# debug forces dense jumptable no matter the size of selector table
70+
expected_data_section_lengths = [5, 7]
71+
else:
72+
expected_data_section_lengths = []
73+
6874
assert integrity_hash.hex() == out["integrity"]
6975

7076
assert runtime_len == len(runtime_code)
71-
assert data_section_lengths == []
77+
assert data_section_lengths == expected_data_section_lengths
7278
assert immutables_len == 0
7379
assert compiler == {"vyper": list(vyper.version.version_tuple)}
7480

@@ -119,7 +125,7 @@ def test_bytecode_signature_sparse_jumptable():
119125
assert compiler == {"vyper": list(vyper.version.version_tuple)}
120126

121127

122-
def test_bytecode_signature_immutables():
128+
def test_bytecode_signature_immutables(debug, optimize):
123129
out = vyper.compile_code(
124130
has_immutables, output_formats=["bytecode_runtime", "bytecode", "integrity"]
125131
)
@@ -130,10 +136,16 @@ def test_bytecode_signature_immutables():
130136
metadata = _parse_cbor_metadata(initcode)
131137
integrity_hash, runtime_len, data_section_lengths, immutables_len, compiler = metadata
132138

139+
if debug and optimize == OptimizationLevel.CODESIZE:
140+
# debug forces dense jumptable no matter the size of selector table
141+
expected_data_section_lengths = [5, 7]
142+
else:
143+
expected_data_section_lengths = []
144+
133145
assert integrity_hash.hex() == out["integrity"]
134146

135147
assert runtime_len == len(runtime_code)
136-
assert data_section_lengths == []
148+
assert data_section_lengths == expected_data_section_lengths
137149
assert immutables_len == 32
138150
assert compiler == {"vyper": list(vyper.version.version_tuple)}
139151

vyper/cli/vyper_compile.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ def compile_files(
359359
# we allow this instead of requiring a different mode (like
360360
# `--zip`) so that verifier pipelines do not need a different
361361
# workflow for archive files and single-file contracts.
362-
output = compile_from_zip(file_name, output_formats, settings, no_bytecode_metadata)
362+
output = compile_from_zip(file_name, final_formats, settings, no_bytecode_metadata)
363363
ret[file_path] = output
364364
continue
365365
except NotZipInput:

vyper/cli/vyper_json.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,8 +272,17 @@ def get_settings(input_dict: dict) -> Settings:
272272
else:
273273
assert optimize is None
274274

275+
debug = input_dict["settings"].get("debug", None)
276+
277+
# TODO: maybe change these to camelCase for consistency
278+
enable_decimals = input_dict["settings"].get("enable_decimals", None)
279+
275280
return Settings(
276-
evm_version=evm_version, optimize=optimize, experimental_codegen=experimental_codegen
281+
evm_version=evm_version,
282+
optimize=optimize,
283+
experimental_codegen=experimental_codegen,
284+
debug=debug,
285+
enable_decimals=enable_decimals,
277286
)
278287

279288

vyper/compiler/phases.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from vyper.compiler.input_bundle import FileInput, FilesystemInputBundle, InputBundle
1313
from vyper.compiler.settings import OptimizationLevel, Settings, anchor_settings, merge_settings
1414
from vyper.ir import compile_ir, optimizer
15+
from vyper.ir.compile_ir import reset_symbols
1516
from vyper.semantics import analyze_module, set_data_positions, validate_compilation_target
1617
from vyper.semantics.analysis.data_positions import generate_layout_export
1718
from vyper.semantics.analysis.imports import resolve_imports
@@ -310,6 +311,7 @@ def generate_ir_nodes(global_ctx: ModuleT, settings: Settings) -> tuple[IRnode,
310311
"""
311312
# make IR output the same between runs
312313
codegen.reset_names()
314+
reset_symbols()
313315

314316
with anchor_settings(settings):
315317
ir_nodes, ir_runtime = module.generate_ir_for_module(global_ctx)

vyper/compiler/settings.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,12 @@ def _merge_one(lhs, rhs, helpstr):
120120
return lhs if rhs is None else rhs
121121

122122
ret = Settings()
123-
ret.evm_version = _merge_one(one.evm_version, two.evm_version, "evm version")
124-
ret.optimize = _merge_one(one.optimize, two.optimize, "optimize")
125-
ret.experimental_codegen = _merge_one(
126-
one.experimental_codegen, two.experimental_codegen, "experimental codegen"
127-
)
128-
ret.enable_decimals = _merge_one(one.enable_decimals, two.enable_decimals, "enable-decimals")
123+
for field in dataclasses.fields(ret):
124+
if field.name == "compiler_version":
125+
continue
126+
pretty_name = field.name.replace("_", "-") # e.g. evm_version -> evm-version
127+
val = _merge_one(getattr(one, field.name), getattr(two, field.name), pretty_name)
128+
setattr(ret, field.name, val)
129129

130130
return ret
131131

vyper/ir/compile_ir.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ def mksymbol(name=""):
5454
return f"_sym_{name}{_next_symbol}"
5555

5656

57+
def reset_symbols():
58+
global _next_symbol
59+
_next_symbol = 0
60+
61+
5762
def mkdebug(pc_debugger, ast_source):
5863
i = Instruction("DEBUG", ast_source)
5964
i.pc_debugger = pc_debugger

0 commit comments

Comments
 (0)