Skip to content

Commit

Permalink
fix: passing a mutable value more than once to a subroutine will now …
Browse files Browse the repository at this point in the history
…raise an error as allowing it would break semantic compatability

BREAKING CHANGE:
passing a mutable value more than once to a subroutine causes an error
  • Loading branch information
daniel-makerx committed Nov 7, 2024
1 parent 0491d0b commit dac51be
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 0 deletions.
8 changes: 8 additions & 0 deletions src/puya/ir/builder/callsub.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import attrs

from puya import log
from puya.awst import (
nodes as awst_nodes,
wtypes,
Expand All @@ -13,6 +14,8 @@
from puya.ir.models import InvokeSubroutine, Register, Subroutine, Value, ValueProvider, ValueTuple
from puya.parse import SourceLocation

logger = log.get_logger(__name__)


def visit_subroutine_call_expression(
context: IRFunctionBuildContext, expr: awst_nodes.SubroutineCallExpression
Expand Down Expand Up @@ -46,6 +49,11 @@ def _call_subroutine(
arg_val = arg_lookup.get(index=idx, param_name=param.name)
resolved_args.append(arg_val)
if param.implicit_return:
if arg_val in implicit_args:
logger.error(
"mutable values cannot be passed more than once to a subroutine",
location=arg_val.source_location,
)
implicit_args.append(arg_val)
if not arg_lookup.is_empty:
raise CodeError("function call arguments do not match signature", call_location) from None
Expand Down
18 changes: 18 additions & 0 deletions tests/test_expected_output/arc4.test
Original file line number Diff line number Diff line change
Expand Up @@ -589,3 +589,21 @@ class MyTest(ARC4Contract):
this_is_ok = some_address[0]
assert this_is_ok == 0
some_address[0] = arc4.Byte(123) ## E: expression is not valid as an assignment target - object is immutable

## case: test_mutable_params_passed_only_once
from algopy import *

class MyTest(ARC4Contract):
@arc4.abimethod
def test(self) -> None:
my_array = arc4.DynamicBytes()
self.double_use_not_allowed(my_array, my_array) ## E: mutable values cannot be passed more than once to a subroutine
# if we allowed this, the following would fail
assert my_array[0] == 42
assert my_array[1] == 43


@subroutine
def double_use_not_allowed(self, arr1: arc4.DynamicBytes, arr2: arc4.DynamicBytes) -> None:
arr1.append(arc4.Byte(42))
arr2.append(arc4.Byte(43))

0 comments on commit dac51be

Please sign in to comment.