Skip to content

Commit

Permalink
test: Add list, loop, and comprehension tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mark-koch committed Dec 20, 2023
1 parent 34d5415 commit a55c147
Show file tree
Hide file tree
Showing 75 changed files with 1,517 additions and 8 deletions.
25 changes: 19 additions & 6 deletions guppy/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from guppy.hugr.hugr import Hugr

PyFunc = Callable[..., Any]
PyFuncDefOrDecl = tuple[bool, PyFunc]


class GuppyModule:
Expand Down Expand Up @@ -44,7 +45,7 @@ class GuppyModule:
# When `_instance_buffer` is not `None`, then all registered functions will be
# buffered in this list. They only get properly registered, once
# `_register_buffered_instance_funcs` is called. This way, we can associate
_instance_func_buffer: dict[str, PyFunc | CustomFunction] | None
_instance_func_buffer: dict[str, PyFuncDefOrDecl | CustomFunction] | None

def __init__(self, name: str, import_builtins: bool = True):
self.name = name
Expand Down Expand Up @@ -94,20 +95,28 @@ def register_func_def(
self._check_not_yet_compiled()
func_ast = parse_py_func(f)
if self._instance_func_buffer is not None:
self._instance_func_buffer[func_ast.name] = f
self._instance_func_buffer[func_ast.name] = (True, f)
else:
name = (
qualified_name(instance, func_ast.name) if instance else func_ast.name
)
self._check_name_available(name, func_ast)
self._func_defs[name] = func_ast

def register_func_decl(self, f: PyFunc) -> None:
def register_func_decl(
self, f: PyFunc, instance: type[GuppyType] | None = None
) -> None:
"""Registers a Python function declaration as belonging to this Guppy module."""
self._check_not_yet_compiled()
func_ast = parse_py_func(f)
self._check_name_available(func_ast.name, func_ast)
self._func_decls[func_ast.name] = func_ast
if self._instance_func_buffer is not None:
self._instance_func_buffer[func_ast.name] = (False, f)
else:
name = (
qualified_name(instance, func_ast.name) if instance else func_ast.name
)
self._check_name_available(name, func_ast)
self._func_decls[name] = func_ast

def register_custom_func(
self, func: CustomFunction, instance: type[GuppyType] | None = None
Expand Down Expand Up @@ -142,7 +151,11 @@ def _register_buffered_instance_funcs(self, instance: type[GuppyType]) -> None:
if isinstance(f, CustomFunction):
self.register_custom_func(f, instance)
else:
self.register_func_def(f, instance)
is_def, pyfunc = f
if is_def:
self.register_func_def(pyfunc, instance)
else:
self.register_func_decl(pyfunc, instance)

@property
def compiled(self) -> bool:
Expand Down
2 changes: 1 addition & 1 deletion ruff.toml
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ ignore = [
[per-file-ignores]
"guppy/ast_util.py" = ["B009", "B010"]
"guppy/decorator.py" = ["B010"]
"tests/integration/*" = ["F841"]
"tests/integration/*" = ["F841", "C416", "RUF005"]
"tests/{hugr,integration}/*" = ["B", "FBT", "SIM", "I"]

# [pydocstyle]
Expand Down
Empty file.
7 changes: 7 additions & 0 deletions tests/error/comprehension_errors/capture1.err
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Guppy compilation failed. Error in file $FILE:13

11: @guppy(module)
12: def foo(xs: list[int], q: Qubit) -> linst[Qubit]:
13: return [q for x in xs]
^
GuppyTypeError: Variable `q` with linear type `Qubit` would be used multiple times when evaluating this comprehension
16 changes: 16 additions & 0 deletions tests/error/comprehension_errors/capture1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import guppy.prelude.quantum as quantum
from guppy.decorator import guppy
from guppy.module import GuppyModule
from guppy.hugr.tys import Qubit
from guppy.prelude.builtins import linst

module = GuppyModule("test")
module.load(quantum)


@guppy(module)
def foo(xs: list[int], q: Qubit) -> linst[Qubit]:
return [q for x in xs]


module.compile()
7 changes: 7 additions & 0 deletions tests/error/comprehension_errors/capture2.err
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Guppy compilation failed. Error in file $FILE:18

16: @guppy(module)
17: def foo(xs: list[int], q: Qubit) -> list[int]:
18: return [x for x in xs if bar(q)]
^
GuppyTypeError: Variable `q` with linear type `Qubit` would be used multiple times when evaluating this comprehension
21 changes: 21 additions & 0 deletions tests/error/comprehension_errors/capture2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import guppy.prelude.quantum as quantum
from guppy.decorator import guppy
from guppy.module import GuppyModule
from guppy.hugr.tys import Qubit
from guppy.prelude.builtins import linst

module = GuppyModule("test")
module.load(quantum)


@guppy.declare(module)
def bar(q: Qubit) -> bool:
...


@guppy(module)
def foo(xs: list[int], q: Qubit) -> list[int]:
return [x for x in xs if bar(q)]


module.compile()
7 changes: 7 additions & 0 deletions tests/error/comprehension_errors/guarded1.err
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Guppy compilation failed. Error in file $FILE:13

11: @guppy(module)
12: def foo(qs: linst[tuple[bool, Qubit]]) -> linst[Qubit]:
13: return [q for b, q in qs if b]
^
GuppyTypeError: Variable `q` with linear type `Qubit` is not used on all control-flow paths of the list comprehension
16 changes: 16 additions & 0 deletions tests/error/comprehension_errors/guarded1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import guppy.prelude.quantum as quantum
from guppy.decorator import guppy
from guppy.module import GuppyModule
from guppy.hugr.tys import Qubit
from guppy.prelude.builtins import linst

module = GuppyModule("test")
module.load(quantum)


@guppy(module)
def foo(qs: linst[tuple[bool, Qubit]]) -> linst[Qubit]:
return [q for b, q in qs if b]


module.compile()
7 changes: 7 additions & 0 deletions tests/error/comprehension_errors/guarded2.err
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Guppy compilation failed. Error in file $FILE:18

16: @guppy(module)
17: def foo(qs: linst[tuple[bool, Qubit]]) -> list[int]:
18: return [42 for b, q in qs if b if q]
^
GuppyTypeError: Variable `q` with linear type `Qubit` is not used on all control-flow paths of the list comprehension
21 changes: 21 additions & 0 deletions tests/error/comprehension_errors/guarded2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import guppy.prelude.quantum as quantum
from guppy.decorator import guppy
from guppy.module import GuppyModule
from guppy.hugr.tys import Qubit
from guppy.prelude.builtins import linst

module = GuppyModule("test")
module.load(quantum)


@guppy.declare(module)
def bar(q: Qubit) -> bool:
...


@guppy(module)
def foo(qs: linst[tuple[bool, Qubit]]) -> list[int]:
return [42 for b, q in qs if b if q]


module.compile()
7 changes: 7 additions & 0 deletions tests/error/comprehension_errors/illegal_short_circuit.err
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Guppy compilation failed. Error in file $FILE:6

4: @guppy
5: def foo(xs: list[int]) -> None:
6: [x for x in xs if x < 5 and x != 6]
^^^^^^^^^^^^^^^^
GuppyError: Expression is not supported inside a list comprehension
6 changes: 6 additions & 0 deletions tests/error/comprehension_errors/illegal_short_circuit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from guppy.decorator import guppy


@guppy
def foo(xs: list[int]) -> None:
[x for x in xs if x < 5 and x != 6]
7 changes: 7 additions & 0 deletions tests/error/comprehension_errors/illegal_ternary.err
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Guppy compilation failed. Error in file $FILE:6

4: @guppy
5: def foo(xs: list[int], ys: list[int], b: bool) -> None:
6: [x for x in (xs if b else ys)]
^^^^^^^^^^^^^^^
GuppyError: Expression is not supported inside a list comprehension
6 changes: 6 additions & 0 deletions tests/error/comprehension_errors/illegal_ternary.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from guppy.decorator import guppy


@guppy
def foo(xs: list[int], ys: list[int], b: bool) -> None:
[x for x in (xs if b else ys)]
7 changes: 7 additions & 0 deletions tests/error/comprehension_errors/illegal_walrus.err
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Guppy compilation failed. Error in file $FILE:6

4: @guppy
5: def foo(xs: list[int]) -> None:
6: [y := x for x in xs]
^^^^^^
GuppyError: Expression is not supported inside a list comprehension
6 changes: 6 additions & 0 deletions tests/error/comprehension_errors/illegal_walrus.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from guppy.decorator import guppy


@guppy
def foo(xs: list[int]) -> None:
[y := x for x in xs]
7 changes: 7 additions & 0 deletions tests/error/comprehension_errors/multi_use1.err
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Guppy compilation failed. Error in file $FILE:13

11: @guppy(module)
12: def foo(qs: linst[Qubit], xs: list[int]) -> linst[Qubit]:
13: return [q for q in qs for x in xs]
^
GuppyTypeError: Variable `q` with linear type `Qubit` would be used multiple times when evaluating this comprehension
16 changes: 16 additions & 0 deletions tests/error/comprehension_errors/multi_use1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import guppy.prelude.quantum as quantum
from guppy.decorator import guppy
from guppy.module import GuppyModule
from guppy.hugr.tys import Qubit
from guppy.prelude.builtins import linst

module = GuppyModule("test")
module.load(quantum)


@guppy(module)
def foo(qs: linst[Qubit], xs: list[int]) -> linst[Qubit]:
return [q for q in qs for x in xs]


module.compile()
7 changes: 7 additions & 0 deletions tests/error/comprehension_errors/multi_use2.err
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Guppy compilation failed. Error in file $FILE:13

11: @guppy(module)
12: def foo(qs: linst[Qubit], xs: list[int]) -> linst[Qubit]:
13: return [q for x in xs for q in qs]
^^
GuppyTypeError: Variable `qs` with linear type `linst[Qubit]` would be used multiple times when evaluating this comprehension
16 changes: 16 additions & 0 deletions tests/error/comprehension_errors/multi_use2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import guppy.prelude.quantum as quantum
from guppy.decorator import guppy
from guppy.module import GuppyModule
from guppy.hugr.tys import Qubit
from guppy.prelude.builtins import linst

module = GuppyModule("test")
module.load(quantum)


@guppy(module)
def foo(qs: linst[Qubit], xs: list[int]) -> linst[Qubit]:
return [q for x in xs for q in qs]


module.compile()
7 changes: 7 additions & 0 deletions tests/error/comprehension_errors/multi_use3.err
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Guppy compilation failed. Error in file $FILE:18

16: @guppy(module)
17: def foo(qs: linst[Qubit], xs: list[int]) -> list[int]:
18: return [x for q in qs for x in xs if bar(q)]
^
GuppyTypeError: Variable `q` with linear type `Qubit` would be used multiple times when evaluating this comprehension
21 changes: 21 additions & 0 deletions tests/error/comprehension_errors/multi_use3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import guppy.prelude.quantum as quantum
from guppy.decorator import guppy
from guppy.module import GuppyModule
from guppy.hugr.tys import Qubit
from guppy.prelude.builtins import linst

module = GuppyModule("test")
module.load(quantum)


@guppy.declare(module)
def bar(q: Qubit) -> bool:
...


@guppy(module)
def foo(qs: linst[Qubit], xs: list[int]) -> list[int]:
return [x for q in qs for x in xs if bar(q)]


module.compile()
7 changes: 7 additions & 0 deletions tests/error/comprehension_errors/not_used.err
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Guppy compilation failed. Error in file $FILE:13

11: @guppy(module)
12: def foo(qs: linst[Qubit]) -> list[int]:
13: return [42 for q in qs]
^
GuppyTypeError: Variable `q` with linear type `Qubit` is not used
16 changes: 16 additions & 0 deletions tests/error/comprehension_errors/not_used.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import guppy.prelude.quantum as quantum
from guppy.decorator import guppy
from guppy.module import GuppyModule
from guppy.hugr.tys import Qubit
from guppy.prelude.builtins import linst

module = GuppyModule("test")
module.load(quantum)


@guppy(module)
def foo(qs: linst[Qubit]) -> list[int]:
return [42 for q in qs]


module.compile()
7 changes: 7 additions & 0 deletions tests/error/comprehension_errors/pattern_override1.err
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Guppy compilation failed. Error in file $FILE:13

11: @guppy(module)
12: def foo(qs: linst[tuple[Qubit, Qubit]]) -> linst[Qubit]:
13: return [q for q, q in qs]
^
GuppyError: Variable `q` with linear type `Qubit` is not used
16 changes: 16 additions & 0 deletions tests/error/comprehension_errors/pattern_override1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import guppy.prelude.quantum as quantum
from guppy.decorator import guppy
from guppy.module import GuppyModule
from guppy.hugr.tys import Qubit
from guppy.prelude.builtins import linst

module = GuppyModule("test")
module.load(quantum)


@guppy(module)
def foo(qs: linst[tuple[Qubit, Qubit]]) -> linst[Qubit]:
return [q for q, q in qs]


module.compile()
7 changes: 7 additions & 0 deletions tests/error/comprehension_errors/pattern_override2.err
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Guppy compilation failed. Error in file $FILE:13

11: @guppy(module)
12: def foo(qs: linst[Qubit], xs: list[int]) -> linst[Qubit]:
13: return [q for q in qs for q in xs]
^
GuppyError: Variable `q` with linear type `Qubit` is not used
16 changes: 16 additions & 0 deletions tests/error/comprehension_errors/pattern_override2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import guppy.prelude.quantum as quantum
from guppy.decorator import guppy
from guppy.module import GuppyModule
from guppy.hugr.tys import Qubit
from guppy.prelude.builtins import linst

module = GuppyModule("test")
module.load(quantum)


@guppy(module)
def foo(qs: linst[Qubit], xs: list[int]) -> linst[Qubit]:
return [q for q in qs for q in xs]


module.compile()
7 changes: 7 additions & 0 deletions tests/error/comprehension_errors/used_twice1.err
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Guppy compilation failed. Error in file $FILE:13

11: @guppy(module)
12: def foo(qs: linst[Qubit]) -> linst[tuple[Qubit, Qubit]]:
13: return [(q, q) for q in qs]
^
GuppyError: Variable `q` with linear type `Qubit` was already used (at 13:13)
Loading

0 comments on commit a55c147

Please sign in to comment.