Skip to content

Commit

Permalink
feat!: Turn py expression lists into arrays (#697)
Browse files Browse the repository at this point in the history
Closes #545.

BREAKING CHANGE: Lists in `py(...)` expressions are now turned into
Guppy arrays instead of lists.
  • Loading branch information
mark-koch authored Dec 12, 2024
1 parent f441bb8 commit d52a00a
Show file tree
Hide file tree
Showing 4 changed files with 19 additions and 11 deletions.
5 changes: 3 additions & 2 deletions guppylang/checker/expr_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@
from guppylang.span import Span, to_span
from guppylang.tys.arg import TypeArg
from guppylang.tys.builtin import (
array_type,
bool_type,
get_element_type,
is_bool_type,
Expand Down Expand Up @@ -1193,7 +1194,7 @@ def _python_list_to_guppy_type(
representable in Guppy.
"""
if len(vs) == 0:
return list_type(ExistentialTypeVar.fresh("T", False))
return array_type(ExistentialTypeVar.fresh("T", False), 0)

# All the list elements must have a unifiable types
v, *rest = vs
Expand All @@ -1207,4 +1208,4 @@ def _python_list_to_guppy_type(
if (subst := unify(ty, el_ty, {})) is None:
raise GuppyError(PyExprIncoherentListError(node))
el_ty = el_ty.substitute(subst)
return list_type(el_ty)
return array_type(el_ty, len(vs))
15 changes: 11 additions & 4 deletions guppylang/compiler/expr_compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
from hugr import val as hv
from hugr.build.cond_loop import Conditional
from hugr.build.dfg import DP, DfBase
from hugr.std.collections import ListVal
from typing_extensions import assert_never

from guppylang.ast_util import AstNode, AstVisitor, get_type
Expand Down Expand Up @@ -55,8 +54,8 @@
from guppylang.tys.builtin import (
get_element_type,
int_type,
is_array_type,
is_bool_type,
is_list_type,
)
from guppylang.tys.const import BoundConstVar, ConstValue, ExistentialConstVar
from guppylang.tys.subst import Inst
Expand Down Expand Up @@ -601,10 +600,18 @@ def python_value_to_hugr(v: Any, exp_ty: Type) -> hv.Value | None:
if doesnt_contain_none(vs):
return hv.Tuple(*vs)
case list(elts):
assert is_list_type(exp_ty)
assert is_array_type(exp_ty)
vs = [python_value_to_hugr(elt, get_element_type(exp_ty)) for elt in elts]
if doesnt_contain_none(vs):
return ListVal(vs, get_element_type(exp_ty).to_hugr())
# TODO: Use proper array value: https://github.com/CQCL/hugr/issues/1497
return hv.Extension(
name="ArrayValue",
typ=exp_ty.to_hugr(),
# The value list must be serialized at this point, otherwise the
# `Extension` value would not be serializable.
val=[v._to_serial_root() for v in vs],
extensions=["unsupported"],
)
case _:
# TODO replace with hugr protocol handling: https://github.com/CQCL/guppylang/issues/563
# Pytket conversion is an experimental feature
Expand Down
2 changes: 1 addition & 1 deletion tests/error/py_errors/list_empty.err
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ Error: Cannot infer type (at $FILE:6:9)
5 | def foo() -> None:
6 | xs = py([])
| ^^^^^^ Cannot infer type variables in expression of type
| `list[?T]`
| `array[?T, 0]`

Guppy compilation failed due to 1 previous error
8 changes: 4 additions & 4 deletions tests/integration/test_py.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def foo() -> int:

def test_list_basic(validate):
@compile_guppy
def foo() -> list[int]:
def foo() -> array[int, 3]:
xs = py([1, 2, 3])
return xs

Expand All @@ -85,7 +85,7 @@ def foo() -> list[int]:

def test_list_empty(validate):
@compile_guppy
def foo() -> list[int]:
def foo() -> array[int, 0]:
return py([])

validate(foo)
Expand All @@ -94,15 +94,15 @@ def foo() -> list[int]:
def test_list_empty_nested(validate):
@compile_guppy
def foo() -> None:
xs: list[tuple[int, list[bool]]] = py([(42, [])])
xs: array[tuple[int, array[bool, 0]], 1] = py([(42, [])])

validate(foo)


def test_list_empty_multiple(validate):
@compile_guppy
def foo() -> None:
xs: tuple[list[int], list[bool]] = py([], [])
xs: tuple[array[int, 0], array[bool, 0]] = py([], [])

validate(foo)

Expand Down

0 comments on commit d52a00a

Please sign in to comment.