Skip to content

Commit

Permalink
Merge pull request #298 from OpShin/fix/disallow_retyping
Browse files Browse the repository at this point in the history
Disallow retyping of variables to incompatible types
  • Loading branch information
nielstron authored Dec 30, 2023
2 parents 3b82458 + 3123243 commit 8c2d321
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 6 deletions.
20 changes: 19 additions & 1 deletion opshin/tests/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,21 @@ def a(x: int) -> int:
ret = eval_uplc_value(source_code, Unit())
self.assertEqual(100, ret)

@unittest.expectedFailure
def test_type_reassignment_function_bound(self):
# changing the type of a variable should be disallowed if the variable is bound by a function
# it can be ok if the types can be merged (resulting in union type inside the function) but
# generally should be disallowed
source_code = """
def validator(_: None) -> int:
b = 1
def a(n: int) -> int:
return b
b = b''
return a(1)
"""
builder._compile(source_code)

def test_datum_cast(self):
input_file = "examples/datum_cast.py"
with open(input_file) as fp:
Expand Down Expand Up @@ -1769,7 +1784,7 @@ def validator(x: Union[A, B], y: int) -> bool:
)

@hypothesis.given(a_or_b)
def test_retype_if(self, x):
def test_uniontype_if(self, x):
source_code = """
from dataclasses import dataclass
from typing import Dict, List, Union
Expand Down Expand Up @@ -1850,6 +1865,7 @@ def validator(x: Union[A, B]):
"""
builder._compile(source_code)

@unittest.expectedFailure
@hypothesis.given(a_or_b)
def test_retype_while(self, x):
source_code = """
Expand Down Expand Up @@ -1926,6 +1942,7 @@ def validator(x: Union[A, B]) -> int:
"""
builder._compile(source_code)

@unittest.expectedFailure
def test_retype(self):
source_code = """
def validator(x: int) -> str:
Expand All @@ -1935,6 +1952,7 @@ def validator(x: int) -> str:
res = eval_uplc_value(source_code, 1)
self.assertEqual(res, b"hello")

@unittest.expectedFailure
def test_retype_if_primitives(self):
source_code = """
def validator(x: int) -> str:
Expand Down
9 changes: 4 additions & 5 deletions opshin/type_inference.py
Original file line number Diff line number Diff line change
Expand Up @@ -411,8 +411,8 @@ def visit_Assign(self, node: Assign) -> TypedAssign:
assert isinstance(
t, Name
), "Can only assign to variable names, no type deconstruction"
# Overwrite previous type -> this will only affect following statements
self.set_variable_type(t.id, typed_ass.value.typ, force=True)
# Check compatability to previous types -> variable can be bound in a function before and needs to maintain type
self.set_variable_type(t.id, typed_ass.value.typ)
typed_ass.targets = [self.visit(t) for t in node.targets]
return typed_ass

Expand All @@ -423,9 +423,8 @@ def visit_AnnAssign(self, node: AnnAssign) -> TypedAnnAssign:
assert isinstance(
node.target, Name
), "Can only assign to variable names, no type deconstruction"
self.set_variable_type(
node.target.id, InstanceType(typed_ass.annotation), force=True
)
# Check compatability to previous types -> variable can be bound in a function before and needs to maintain type
self.set_variable_type(node.target.id, InstanceType(typed_ass.annotation))
typed_ass.target = self.visit(node.target)
assert (
typed_ass.value.typ >= InstanceType(typed_ass.annotation)
Expand Down

0 comments on commit 8c2d321

Please sign in to comment.