diff --git a/tests/functional/codegen/features/decorators/test_pure.py b/tests/functional/codegen/features/decorators/test_pure.py index 5f8db6bbf2..b2c5a0945b 100644 --- a/tests/functional/codegen/features/decorators/test_pure.py +++ b/tests/functional/codegen/features/decorators/test_pure.py @@ -175,6 +175,19 @@ def foo() -> uint256: compile_code(code) +def test_type_in_pure(get_contract): + code = """ +@pure +@external +def _convert(x: bytes32) -> uint256: + return convert(x, uint256) + """ + c = get_contract(code) + x = 123456 + bs = x.to_bytes(32, "big") + assert x == c._convert(bs) + + def test_invalid_conflicting_decorators(): code = """ @pure diff --git a/tests/unit/compiler/venom/test_dominator_tree.py b/tests/unit/compiler/venom/test_dominator_tree.py index dc27380796..c5b7404b58 100644 --- a/tests/unit/compiler/venom/test_dominator_tree.py +++ b/tests/unit/compiler/venom/test_dominator_tree.py @@ -70,4 +70,4 @@ def test_phi_placement(): bb2.insert_instruction(IRInstruction("add", [x, IRLiteral(1)], x), 0) bb7.insert_instruction(IRInstruction("mstore", [x, IRLiteral(0)]), 0) - MakeSSA.run_pass(ctx, bb1) + MakeSSA().run_pass(ctx, bb1) diff --git a/tests/unit/compiler/venom/test_make_ssa.py b/tests/unit/compiler/venom/test_make_ssa.py index 2a04dfc134..da3a143b30 100644 --- a/tests/unit/compiler/venom/test_make_ssa.py +++ b/tests/unit/compiler/venom/test_make_ssa.py @@ -31,7 +31,7 @@ def test_phi_case(): bb.append_instruction("jmp", bb_cont.label) calculate_cfg(ctx) - MakeSSA.run_pass(ctx, ctx.basic_blocks[0]) + MakeSSA().run_pass(ctx, ctx.basic_blocks[0]) calculate_liveness(ctx) condition_block = ctx.get_basic_block("condition") diff --git a/tests/unit/compiler/venom/test_multi_entry_block.py b/tests/unit/compiler/venom/test_multi_entry_block.py index 47f4b88707..95b6e62daf 100644 --- a/tests/unit/compiler/venom/test_multi_entry_block.py +++ b/tests/unit/compiler/venom/test_multi_entry_block.py @@ -34,7 +34,7 @@ def test_multi_entry_block_1(): calculate_cfg(ctx) assert not ctx.normalized, "CFG should not be normalized" - NormalizationPass.run_pass(ctx) + NormalizationPass().run_pass(ctx) assert ctx.normalized, "CFG should be normalized" @@ -86,7 +86,7 @@ def test_multi_entry_block_2(): calculate_cfg(ctx) assert not ctx.normalized, "CFG should not be normalized" - NormalizationPass.run_pass(ctx) + NormalizationPass().run_pass(ctx) assert ctx.normalized, "CFG should be normalized" @@ -128,7 +128,7 @@ def test_multi_entry_block_with_dynamic_jump(): calculate_cfg(ctx) assert not ctx.normalized, "CFG should not be normalized" - NormalizationPass.run_pass(ctx) + NormalizationPass().run_pass(ctx) assert ctx.normalized, "CFG should be normalized" finish_bb = ctx.get_basic_block(finish_label.value) diff --git a/vyper/semantics/analysis/local.py b/vyper/semantics/analysis/local.py index 1b2e3252c8..b0a6e38d10 100644 --- a/vyper/semantics/analysis/local.py +++ b/vyper/semantics/analysis/local.py @@ -165,7 +165,10 @@ def _validate_msg_value_access(node: vy_ast.Attribute) -> None: raise NonPayableViolation("msg.value is not allowed in non-payable functions", node) -def _validate_pure_access(node: vy_ast.Attribute | vy_ast.Name) -> None: +def _validate_pure_access(node: vy_ast.Attribute | vy_ast.Name, typ: VyperType) -> None: + if isinstance(typ, TYPE_T): + return + info = get_expr_info(node) env_vars = CONSTANT_ENVIRONMENT_VARS @@ -705,7 +708,7 @@ def visit_Attribute(self, node: vy_ast.Attribute, typ: VyperType) -> None: _validate_msg_value_access(node) if self.func and self.func.mutability == StateMutability.PURE: - _validate_pure_access(node) + _validate_pure_access(node, typ) value_type = get_exact_type_from_node(node.value) @@ -886,7 +889,7 @@ def visit_List(self, node: vy_ast.List, typ: VyperType) -> None: def visit_Name(self, node: vy_ast.Name, typ: VyperType) -> None: if self.func and self.func.mutability == StateMutability.PURE: - _validate_pure_access(node) + _validate_pure_access(node, typ) def visit_Subscript(self, node: vy_ast.Subscript, typ: VyperType) -> None: if isinstance(typ, TYPE_T): diff --git a/vyper/venom/__init__.py b/vyper/venom/__init__.py index 2efd58ad6c..0a75e567ba 100644 --- a/vyper/venom/__init__.py +++ b/vyper/venom/__init__.py @@ -52,13 +52,14 @@ def _run_passes(ctx: IRFunction, optimize: OptimizationLevel) -> None: if bb.label.value.startswith("internal") and len(bb.cfg_in) == 0 ] - SimplifyCFGPass.run_pass(ctx, ctx.basic_blocks[0]) + SimplifyCFGPass().run_pass(ctx, ctx.basic_blocks[0]) for entry in internals: - SimplifyCFGPass.run_pass(ctx, entry) + SimplifyCFGPass().run_pass(ctx, entry) - MakeSSA.run_pass(ctx, ctx.basic_blocks[0]) + make_ssa_pass = MakeSSA() + make_ssa_pass.run_pass(ctx, ctx.basic_blocks[0]) for entry in internals: - MakeSSA.run_pass(ctx, entry) + make_ssa_pass.run_pass(ctx, entry) while True: changes = 0 @@ -73,7 +74,7 @@ def _run_passes(ctx: IRFunction, optimize: OptimizationLevel) -> None: calculate_cfg(ctx) calculate_liveness(ctx) - changes += DFTPass.run_pass(ctx) + changes += DFTPass().run_pass(ctx) calculate_cfg(ctx) calculate_liveness(ctx) diff --git a/vyper/venom/passes/base_pass.py b/vyper/venom/passes/base_pass.py index 3fbbdef6df..1851b35233 100644 --- a/vyper/venom/passes/base_pass.py +++ b/vyper/venom/passes/base_pass.py @@ -4,18 +4,16 @@ class IRPass: until no more changes are made. """ - @classmethod - def run_pass(cls, *args, **kwargs): - t = cls() + def run_pass(self, *args, **kwargs): count = 0 for _ in range(1000): - changes_count = t._run_pass(*args, **kwargs) or 0 + changes_count = self._run_pass(*args, **kwargs) or 0 count += changes_count if changes_count == 0: break else: - raise Exception("Too many iterations in IR pass!", t.__class__) + raise Exception("Too many iterations in IR pass!", self.__class__) return count diff --git a/vyper/venom/venom_to_assembly.py b/vyper/venom/venom_to_assembly.py index 0cb13becf2..41fa8888c9 100644 --- a/vyper/venom/venom_to_assembly.py +++ b/vyper/venom/venom_to_assembly.py @@ -146,13 +146,13 @@ def generate_evm(self, no_optimize: bool = False) -> list[str]: # Before emitting the assembly, we need to make sure that the # CFG is normalized. Calling calculate_cfg() will denormalize IR (reset) - # so it should not be called after calling NormalizationPass.run_pass(). + # so it should not be called after calling NormalizationPass().run_pass(). # Liveness is then computed for the normalized IR, and we can proceed to # assembly generation. # This is a side-effect of how dynamic jumps are temporarily being used # to support the O(1) dispatcher. -> look into calculate_cfg() for ctx in self.ctxs: - NormalizationPass.run_pass(ctx) + NormalizationPass().run_pass(ctx) calculate_cfg(ctx) calculate_liveness(ctx) calculate_dup_requirements(ctx)