From 02b6ab00f96a7801199d0ec2d3c017d7d81cdf59 Mon Sep 17 00:00:00 2001 From: Mark Koch <48097969+mark-koch@users.noreply.github.com> Date: Mon, 16 Dec 2024 16:43:51 +0000 Subject: [PATCH 01/10] fix: Allow borrowing inside comprehensions (#723) Fixes #719 --- examples/demo.ipynb | 6 +- guppylang/checker/linearity_checker.py | 45 ++++-- guppylang/compiler/expr_compiler.py | 3 + guppylang/nodes.py | 3 + .../borrow_after_consume.err | 12 ++ .../borrow_after_consume.py | 24 ++++ .../comprehension_errors/borrow_leaked1.err | 10 ++ .../comprehension_errors/borrow_leaked1.py | 20 +++ .../comprehension_errors/borrow_leaked2.err | 8 ++ .../comprehension_errors/borrow_leaked2.py | 20 +++ .../comprehension_errors/borrow_leaked3.err | 11 ++ .../comprehension_errors/borrow_leaked3.py | 20 +++ .../comprehension_errors/borrow_leaked4.err | 8 ++ .../comprehension_errors/borrow_leaked4.py | 20 +++ .../inout_errors/override_after_call.err | 6 +- .../error/inout_errors/unused_after_call.err | 6 +- tests/integration/test_array_comprehension.py | 75 +++++++++- tests/integration/test_comprehension.py | 133 ++++++++++++++++++ 18 files changed, 409 insertions(+), 21 deletions(-) create mode 100644 tests/error/comprehension_errors/borrow_after_consume.err create mode 100644 tests/error/comprehension_errors/borrow_after_consume.py create mode 100644 tests/error/comprehension_errors/borrow_leaked1.err create mode 100644 tests/error/comprehension_errors/borrow_leaked1.py create mode 100644 tests/error/comprehension_errors/borrow_leaked2.err create mode 100644 tests/error/comprehension_errors/borrow_leaked2.py create mode 100644 tests/error/comprehension_errors/borrow_leaked3.err create mode 100644 tests/error/comprehension_errors/borrow_leaked3.py create mode 100644 tests/error/comprehension_errors/borrow_leaked4.err create mode 100644 tests/error/comprehension_errors/borrow_leaked4.py diff --git a/examples/demo.ipynb b/examples/demo.ipynb index 331c370a..608a42e4 100644 --- a/examples/demo.ipynb +++ b/examples/demo.ipynb @@ -356,12 +356,12 @@ "name": "stderr", "output_type": "stream", "text": [ - "Error: Linearity violation (at :7:7)\n", + "Error: Linearity violation (at :6:4)\n", " | \n", + "4 | @guppy(bad_module)\n", "5 | def bad(q: qubit @owned) -> qubit:\n", "6 | tmp = qubit()\n", - "7 | cx(tmp, q)\n", - " | ^^^ Variable `tmp` with linear type `qubit` is leaked\n", + " | ^^^ Variable `tmp` with linear type `qubit` is leaked\n", "\n", "Help: Make sure that `tmp` is consumed or returned to avoid the leak\n", "\n", diff --git a/guppylang/checker/linearity_checker.py b/guppylang/checker/linearity_checker.py index 5ff7534e..d2d6d323 100644 --- a/guppylang/checker/linearity_checker.py +++ b/guppylang/checker/linearity_checker.py @@ -317,13 +317,13 @@ def _reassign_inout_args(self, func_ty: FunctionType, call: AnyCall) -> None: if InputFlags.Inout in inp.flags: match arg: case PlaceNode(place=place): - self._reassign_single_inout_arg(place, arg) + self._reassign_single_inout_arg(place, place.defined_at or arg) case arg if inp.ty.linear: err = DropAfterCallError(arg, inp.ty, self._call_name(call)) err.add_sub_diagnostic(DropAfterCallError.Assign(None)) raise GuppyError(err) - def _reassign_single_inout_arg(self, place: Place, node: ast.expr) -> None: + def _reassign_single_inout_arg(self, place: Place, node: AstNode) -> None: """Helper function to reassign a single borrowed argument after a function call.""" # Places involving subscripts are given back by visiting the `__setitem__` call @@ -496,6 +496,11 @@ def _check_comprehension( continue for leaf in leaf_places(place): x = leaf.id + # Also ignore borrowed variables + if x in inner_scope.used_parent and ( + inner_scope.used_parent[x].kind == UseKind.BORROW + ): + continue if not self.scope.used(x) and place.ty.linear: err = PlaceNotUsedError(place.defined_at, place) err.add_sub_diagnostic( @@ -508,6 +513,22 @@ def _check_comprehension( # Recursively check the remaining generators self._check_comprehension(gens, elt) + # Look for any linear variables that were borrowed from the outer scope + gen.borrowed_outer_places = [] + for x, use in inner_scope.used_parent.items(): + if use.kind == UseKind.BORROW: + # Since `x` was borrowed, we know that is now also assigned in the + # inner scope since it gets reassigned in the local scope after the + # borrow expires + place = inner_scope[x] + gen.borrowed_outer_places.append(place) + # Also mark this place as implicitly used so we don't complain about + # it later. + for leaf in leaf_places(place): + inner_scope.use( + leaf.id, InoutReturnSentinel(leaf), UseKind.RETURN + ) + # Check the iter finalizer so we record a final use of the iterator self.visit(gen.iterend) @@ -519,15 +540,17 @@ def _check_comprehension( if leaf.ty.linear and not inner_scope.used(x): raise GuppyTypeError(PlaceNotUsedError(leaf.defined_at, leaf)) - # On the other hand, we have to ensure that no linear places from the - # outer scope have been used inside the comprehension (they would be used - # multiple times since the comprehension body is executed repeatedly) - for x, use in inner_scope.used_parent.items(): - place = inner_scope[x] - if place.ty.linear: - raise GuppyTypeError( - ComprAlreadyUsedError(use.node, place, use.kind) - ) + # On the other hand, we have to ensure that no linear places from the + # outer scope have been used inside the comprehension (they would be used + # multiple times since the comprehension body is executed repeatedly) + for x, use in inner_scope.used_parent.items(): + place = inner_scope[x] + # The only exception are values that are only borrowed from the outer + # scope. These can be safely reassigned. + if use.kind == UseKind.BORROW: + self._reassign_single_inout_arg(place, use.node) + elif place.ty.linear: + raise GuppyTypeError(ComprAlreadyUsedError(use.node, place, use.kind)) def leaf_places(place: Place) -> Iterator[Place]: diff --git a/guppylang/compiler/expr_compiler.py b/guppylang/compiler/expr_compiler.py index d71b1c23..b3d8184f 100644 --- a/guppylang/compiler/expr_compiler.py +++ b/guppylang/compiler/expr_compiler.py @@ -543,6 +543,9 @@ def _build_generators( assert isinstance(gen.iter, PlaceNode) assert isinstance(gen.hasnext, PlaceNode) inputs = [gen.iter] + [PlaceNode(place=var) for var in loop_vars] + inputs += [ + PlaceNode(place=place) for place in gen.borrowed_outer_places + ] # Remember to finalize the iterator once we are done with it. Note that # we need to use partial in the callback, so that we bind the *current* # value of `gen` instead of only last diff --git a/guppylang/nodes.py b/guppylang/nodes.py index 101be0ab..2eca1ea4 100644 --- a/guppylang/nodes.py +++ b/guppylang/nodes.py @@ -207,6 +207,8 @@ class DesugaredGenerator(ast.expr): hasnext: ast.expr ifs: list[ast.expr] + borrowed_outer_places: "list[Place]" + _fields = ( "iter_assign", "hasnext_assign", @@ -215,6 +217,7 @@ class DesugaredGenerator(ast.expr): "iter", "hasnext", "ifs", + "borrowed_outer_places", ) diff --git a/tests/error/comprehension_errors/borrow_after_consume.err b/tests/error/comprehension_errors/borrow_after_consume.err new file mode 100644 index 00000000..d925da2d --- /dev/null +++ b/tests/error/comprehension_errors/borrow_after_consume.err @@ -0,0 +1,12 @@ +Error: Linearity violation (at $FILE:21:16) + | +19 | @guppy(module) +20 | def foo(qs: list[qubit] @owned) -> list[int]: +21 | return [baz(q) for q in qs if bar(q)] + | ^ Variable `q` with linear type `qubit` cannot be borrowed + | ... + | +21 | return [baz(q) for q in qs if bar(q)] + | - since it was already consumed here + +Guppy compilation failed due to 1 previous error diff --git a/tests/error/comprehension_errors/borrow_after_consume.py b/tests/error/comprehension_errors/borrow_after_consume.py new file mode 100644 index 00000000..7ea87a4d --- /dev/null +++ b/tests/error/comprehension_errors/borrow_after_consume.py @@ -0,0 +1,24 @@ +import guppylang.std.quantum as quantum +from guppylang.decorator import guppy +from guppylang.module import GuppyModule +from guppylang.std.quantum import qubit +from guppylang.std.builtins import owned + +module = GuppyModule("test") +module.load_all(quantum) + + +@guppy.declare(module) +def bar(q: qubit @owned) -> int: ... + + +@guppy.declare(module) +def baz(q: qubit) -> int: ... + + +@guppy(module) +def foo(qs: list[qubit] @owned) -> list[int]: + return [baz(q) for q in qs if bar(q)] + + +module.compile() diff --git a/tests/error/comprehension_errors/borrow_leaked1.err b/tests/error/comprehension_errors/borrow_leaked1.err new file mode 100644 index 00000000..37128bf3 --- /dev/null +++ b/tests/error/comprehension_errors/borrow_leaked1.err @@ -0,0 +1,10 @@ +Error: Linearity violation (at $FILE:17:16) + | +15 | @guppy(module) +16 | def foo(n: int, q: qubit @owned) -> list[int]: +17 | return [bar(q) for _ in range(n)] + | ^ Variable `q` with linear type `qubit` is leaked + +Help: Make sure that `q` is consumed or returned to avoid the leak + +Guppy compilation failed due to 1 previous error diff --git a/tests/error/comprehension_errors/borrow_leaked1.py b/tests/error/comprehension_errors/borrow_leaked1.py new file mode 100644 index 00000000..3ff39850 --- /dev/null +++ b/tests/error/comprehension_errors/borrow_leaked1.py @@ -0,0 +1,20 @@ +import guppylang.std.quantum as quantum +from guppylang.decorator import guppy +from guppylang.module import GuppyModule +from guppylang.std.quantum import qubit +from guppylang.std.builtins import owned + +module = GuppyModule("test") +module.load_all(quantum) + + +@guppy.declare(module) +def bar(q: qubit) -> int: ... + + +@guppy(module) +def foo(n: int, q: qubit @owned) -> list[int]: + return [bar(q) for _ in range(n)] + + +module.compile() diff --git a/tests/error/comprehension_errors/borrow_leaked2.err b/tests/error/comprehension_errors/borrow_leaked2.err new file mode 100644 index 00000000..35887987 --- /dev/null +++ b/tests/error/comprehension_errors/borrow_leaked2.err @@ -0,0 +1,8 @@ +Error: Linearity violation (at $FILE:17:23) + | +15 | @guppy(module) +16 | def foo(qs: list[qubit] @owned) -> list[int]: +17 | return [bar(q) for q in qs] + | ^ Variable `q` with linear type `qubit` is leaked + +Guppy compilation failed due to 1 previous error diff --git a/tests/error/comprehension_errors/borrow_leaked2.py b/tests/error/comprehension_errors/borrow_leaked2.py new file mode 100644 index 00000000..00fdb613 --- /dev/null +++ b/tests/error/comprehension_errors/borrow_leaked2.py @@ -0,0 +1,20 @@ +import guppylang.std.quantum as quantum +from guppylang.decorator import guppy +from guppylang.module import GuppyModule +from guppylang.std.quantum import qubit +from guppylang.std.builtins import owned + +module = GuppyModule("test") +module.load_all(quantum) + + +@guppy.declare(module) +def bar(q: qubit) -> int: ... + + +@guppy(module) +def foo(qs: list[qubit] @owned) -> list[int]: + return [bar(q) for q in qs] + + +module.compile() diff --git a/tests/error/comprehension_errors/borrow_leaked3.err b/tests/error/comprehension_errors/borrow_leaked3.err new file mode 100644 index 00000000..9b7efded --- /dev/null +++ b/tests/error/comprehension_errors/borrow_leaked3.err @@ -0,0 +1,11 @@ +Error: Linearity violation (at $FILE:17:18) + | +15 | @guppy(module) +16 | def foo(qs: list[qubit] @owned) -> list[int]: +17 | return [0 for q in qs if bar(q)] + | ^ Variable `q` with linear type `qubit` may be leaked ... + | +17 | return [0 for q in qs if bar(q)] + | ------ if this expression is `False` + +Guppy compilation failed due to 1 previous error diff --git a/tests/error/comprehension_errors/borrow_leaked3.py b/tests/error/comprehension_errors/borrow_leaked3.py new file mode 100644 index 00000000..194816f2 --- /dev/null +++ b/tests/error/comprehension_errors/borrow_leaked3.py @@ -0,0 +1,20 @@ +import guppylang.std.quantum as quantum +from guppylang.decorator import guppy +from guppylang.module import GuppyModule +from guppylang.std.quantum import qubit +from guppylang.std.builtins import owned + +module = GuppyModule("test") +module.load_all(quantum) + + +@guppy.declare(module) +def bar(q: qubit) -> bool: ... + + +@guppy(module) +def foo(qs: list[qubit] @owned) -> list[int]: + return [0 for q in qs if bar(q)] + + +module.compile() diff --git a/tests/error/comprehension_errors/borrow_leaked4.err b/tests/error/comprehension_errors/borrow_leaked4.err new file mode 100644 index 00000000..3ea63d8d --- /dev/null +++ b/tests/error/comprehension_errors/borrow_leaked4.err @@ -0,0 +1,8 @@ +Error: Linearity violation (at $FILE:17:18) + | +15 | @guppy(module) +16 | def foo(qs: list[qubit] @owned) -> list[qubit]: +17 | return [r for q in qs for r in bar(q)] + | ^ Variable `q` with linear type `qubit` is leaked + +Guppy compilation failed due to 1 previous error diff --git a/tests/error/comprehension_errors/borrow_leaked4.py b/tests/error/comprehension_errors/borrow_leaked4.py new file mode 100644 index 00000000..ea60c4f7 --- /dev/null +++ b/tests/error/comprehension_errors/borrow_leaked4.py @@ -0,0 +1,20 @@ +import guppylang.std.quantum as quantum +from guppylang.decorator import guppy +from guppylang.module import GuppyModule +from guppylang.std.quantum import qubit +from guppylang.std.builtins import owned + +module = GuppyModule("test") +module.load_all(quantum) + + +@guppy.declare(module) +def bar(q: qubit) -> list[qubit]: ... + + +@guppy(module) +def foo(qs: list[qubit] @owned) -> list[qubit]: + return [r for q in qs for r in bar(q)] + + +module.compile() diff --git a/tests/error/inout_errors/override_after_call.err b/tests/error/inout_errors/override_after_call.err index 3b7b5290..2e686d7f 100644 --- a/tests/error/inout_errors/override_after_call.err +++ b/tests/error/inout_errors/override_after_call.err @@ -1,9 +1,9 @@ -Error: Linearity violation (at $FILE:16:13) +Error: Linearity violation (at $FILE:15:9) | +13 | 14 | @guppy(module) 15 | def test(q1: qubit @owned, q2: qubit @owned) -> tuple[qubit, qubit]: -16 | q1 = foo(q1, q2) - | ^^ Variable `q1` with linear type `qubit` is leaked + | ^^^^^^^^^^^^^^^^ Variable `q1` with linear type `qubit` is leaked Help: Make sure that `q1` is consumed or returned to avoid the leak diff --git a/tests/error/inout_errors/unused_after_call.err b/tests/error/inout_errors/unused_after_call.err index e2bc014c..17635bba 100644 --- a/tests/error/inout_errors/unused_after_call.err +++ b/tests/error/inout_errors/unused_after_call.err @@ -1,9 +1,9 @@ -Error: Linearity violation (at $FILE:16:7) +Error: Linearity violation (at $FILE:15:9) | +13 | 14 | @guppy(module) 15 | def test(q: qubit @owned) -> None: -16 | foo(q) - | ^ Variable `q` with linear type `qubit` is leaked + | ^^^^^^^^^^^^^^^ Variable `q` with linear type `qubit` is leaked Help: Make sure that `q` is consumed or returned to avoid the leak diff --git a/tests/integration/test_array_comprehension.py b/tests/integration/test_array_comprehension.py index bdd4a05a..e012b3a5 100644 --- a/tests/integration/test_array_comprehension.py +++ b/tests/integration/test_array_comprehension.py @@ -2,7 +2,7 @@ from guppylang.decorator import guppy from guppylang.module import GuppyModule -from guppylang.std.builtins import array +from guppylang.std.builtins import array, owned from guppylang.std.quantum import qubit import guppylang.std.quantum_functional as quantum @@ -88,3 +88,76 @@ def test(xs: array[int, n]) -> array[int, n]: return array(x + 1 for x in xs) validate(module.compile()) + + +def test_borrow(validate): + module = GuppyModule("test") + module.load_all(quantum) + module.load(qubit) + n = guppy.nat_var("n", module) + + @guppy.declare(module) + def foo(q: qubit) -> int: ... + + @guppy(module) + def test(q: qubit) -> array[int, n]: + return array(foo(q) for _ in range(n)) + + validate(module.compile()) + + +def test_borrow_twice(validate): + module = GuppyModule("test") + module.load_all(quantum) + module.load(qubit) + n = guppy.nat_var("n", module) + + @guppy.declare(module) + def foo(q: qubit) -> int: ... + + @guppy(module) + def test(q: qubit) -> array[int, n]: + return array(foo(q) + foo(q) for _ in range(n)) + + validate(module.compile()) + + +def test_borrow_struct(validate): + module = GuppyModule("test") + module.load_all(quantum) + module.load(qubit) + n = guppy.nat_var("n", module) + + @guppy.struct(module) + class MyStruct: + q1: qubit + q2: qubit + + @guppy.declare(module) + def foo(s: MyStruct) -> int: ... + + @guppy(module) + def test(s: MyStruct) -> array[int, n]: + return array(foo(s) for _ in range(n)) + + validate(module.compile()) + + +def test_borrow_and_consume(validate): + module = GuppyModule("test") + module.load_all(quantum) + module.load(qubit) + n = guppy.nat_var("n", module) + + @guppy.declare(module) + def foo(q: qubit) -> int: ... + + @guppy.declare(module) + def bar(q: qubit @ owned) -> int: ... + + @guppy(module) + def test(qs: array[qubit, n] @ owned) -> array[int, n]: + return array(foo(q) + bar(q) for q in qs) + + validate(module.compile()) + diff --git a/tests/integration/test_comprehension.py b/tests/integration/test_comprehension.py index 22967d74..bec9fc72 100644 --- a/tests/integration/test_comprehension.py +++ b/tests/integration/test_comprehension.py @@ -310,3 +310,136 @@ def test(mt: MyType, xs: list[int]) -> list[tuple[int, int]]: return [(x, x + y) for x in mt for y in xs] validate(module.compile()) + + +def test_borrow(validate): + module = GuppyModule("test") + module.load_all(quantum) + module.load(qubit) + + @guppy.declare(module) + def foo(q: qubit) -> int: ... + + @guppy(module) + def test(q: qubit, n: int) -> list[int]: + return [foo(q) for _ in range(n)] + + validate(module.compile()) + + +def test_borrow_nested(validate): + module = GuppyModule("test") + module.load_all(quantum) + module.load(qubit) + + @guppy.declare(module) + def foo(q: qubit) -> int: ... + + @guppy(module) + def test(q: qubit, n: int, m: int) -> list[int]: + return [foo(q) for _ in range(n) for _ in range(m)] + + validate(module.compile()) + + +def test_borrow_guarded(validate): + module = GuppyModule("test") + module.load_all(quantum) + module.load(qubit) + + @guppy.declare(module) + def foo(q: qubit) -> int: ... + + @guppy(module) + def test(q: qubit, n: int) -> list[int]: + return [foo(q) for i in range(n) if i % 2 == 0] + + validate(module.compile()) + + +def test_borrow_twice(validate): + module = GuppyModule("test") + module.load_all(quantum) + module.load(qubit) + + @guppy.declare(module) + def foo(q: qubit) -> int: ... + + @guppy(module) + def test(q: qubit, n: int) -> list[int]: + return [foo(q) + foo(q) for _ in range(n)] + + validate(module.compile()) + + +def test_borrow_in_guard(validate): + module = GuppyModule("test") + module.load_all(quantum) + module.load(qubit) + + @guppy.declare(module) + def foo(q: qubit) -> int: ... + + @guppy.declare(module) + def bar(q: qubit) -> bool: ... + + @guppy(module) + def test(q: qubit, n: int) -> list[int]: + return [foo(q) for _ in range(n) if bar(q)] + + validate(module.compile()) + + +def test_borrow_in_iter(validate): + module = GuppyModule("test") + module.load_all(quantum) + module.load(qubit) + + @guppy.declare(module) + def foo(q: qubit) -> int: ... + + @guppy(module) + def test(q: qubit @ owned) -> tuple[list[int], qubit]: + return [foo(q) for _ in range(foo(q))], q + + validate(module.compile()) + + +def test_borrow_struct(validate): + module = GuppyModule("test") + module.load_all(quantum) + module.load(qubit) + + @guppy.struct(module) + class MyStruct: + q1: qubit + q2: qubit + + @guppy.declare(module) + def foo(s: MyStruct) -> int: ... + + @guppy(module) + def test(s: MyStruct, n: int) -> list[int]: + return [foo(s) for _ in range(n)] + + validate(module.compile()) + + +def test_borrow_and_consume(validate): + module = GuppyModule("test") + module.load_all(quantum) + module.load(qubit) + + @guppy.declare(module) + def foo(q: qubit) -> int: ... + + @guppy.declare(module) + def bar(q: qubit @ owned) -> int: ... + + @guppy(module) + def test(qs: list[qubit] @ owned) -> list[int]: + return [foo(q) + bar(q) for q in qs] + + validate(module.compile()) + + From 82dba49362932967c0dda8b0f4baf5dc7174b836 Mon Sep 17 00:00:00 2001 From: Alan Lawrence Date: Tue, 17 Dec 2024 09:26:26 +0000 Subject: [PATCH 02/10] test: rfc: refactor: run_float_fn -> run_float_fn_approx (#507) Uses `pytest.approx`, see https://docs.pytest.org/en/stable/reference/reference.html#pytest-approx, with optional configurable `rel` and `abs`. --- tests/integration/conftest.py | 20 ++++++++++++++++++-- tests/integration/test_arithmetic.py | 4 ++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index 282221fd..b7da6da1 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -97,6 +97,22 @@ def f(module: ModulePointer, expected: Any, fn_name: str = "main"): def run_int_fn(): return _run_fn("run_int_function") + @pytest.fixture -def run_float_fn(): - return _run_fn("run_float_function") +def run_float_fn_approx(): + """Like run_int_fn, but takes optional additional parameters `rel`, `abs` and `nan_ok` + as per `pytest.approx`.""" + run_fn = _run_fn("run_float_function") + + def run_approx( + hugr: Package, + expected: float, + fn_name: str = "main", + *, + rel: float | None = None, + abs: float | None = None, + nan_ok: bool = False, + ): + return run_fn(hugr, pytest.approx(expected, rel=rel, abs=abs, nan_ok=nan_ok)) + + return run_approx diff --git a/tests/integration/test_arithmetic.py b/tests/integration/test_arithmetic.py index d8bbc348..5a8448aa 100644 --- a/tests/integration/test_arithmetic.py +++ b/tests/integration/test_arithmetic.py @@ -251,7 +251,7 @@ def run_rem() -> int: run_int_fn(hugr, expected=2, fn_name="run_rem") -def test_angle_exec(validate, run_float_fn): +def test_angle_exec(validate, run_float_fn_approx): module = GuppyModule("test_angle_exec") module.load_all(angles) @@ -266,4 +266,4 @@ def main() -> float: hugr = module.compile() validate(hugr) import math - run_float_fn(hugr, expected=pytest.approx(-6 * math.pi)) + run_float_fn_approx(hugr, expected=-6 * math.pi) From 63ea7a726edc2512e63b89076db5b4c82bec58af Mon Sep 17 00:00:00 2001 From: Seyon Sivarajah Date: Tue, 17 Dec 2024 10:48:03 +0000 Subject: [PATCH 03/10] feat: update to hugr 0.10 and tket2 0.6 (#725) Closes #720 ~Waiting for tket2 release~ --- Cargo.lock | 745 +++++++--------------- Cargo.toml | 14 +- execute_llvm/Cargo.toml | 3 +- execute_llvm/src/lib.rs | 38 +- guppylang/std/_internal/compiler/array.py | 6 +- guppylang/std/_internal/compiler/list.py | 18 +- guppylang/std/_internal/util.py | 10 +- guppylang/tys/builtin.py | 10 +- pyproject.toml | 20 +- uv.lock | 143 ++--- validator/Cargo.toml | 2 +- 11 files changed, 336 insertions(+), 673 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 31221a0d..ca3c20f0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,18 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -12,19 +24,10 @@ dependencies = [ ] [[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" +name = "allocator-api2" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "anstream" @@ -77,9 +80,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.93" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" +checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" [[package]] name = "approx" @@ -90,6 +93,51 @@ dependencies = [ "num-traits", ] +[[package]] +name = "ascent" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "542b90d362e62ae00b8a9f1c8887919fe5cb4a07c64423b9ab72ab78f4b27f41" +dependencies = [ + "ascent_base", + "ascent_macro", + "boxcar", + "cfg-if", + "dashmap", + "hashbrown 0.14.5", + "instant", + "once_cell", + "paste", + "rayon", + "rustc-hash", +] + +[[package]] +name = "ascent_base" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "606412229e80de366935b461eaef5016a9725064151e52ea35f200e7541c2912" +dependencies = [ + "paste", +] + +[[package]] +name = "ascent_macro" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67685ce7f6568cfd9671322ed3d7c7322ff8ec6a81e07d5323f997e118885972" +dependencies = [ + "ascent_base", + "derive-syn-parse", + "duplicate", + "itertools 0.12.1", + "lazy_static", + "petgraph", + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "autocfg" version = "1.4.0" @@ -116,22 +164,19 @@ dependencies = [ ] [[package]] -name = "block-buffer" -version = "0.10.4" +name = "borsh" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +checksum = "2506947f73ad44e344215ccd6403ac2ae18cd8e046e581a441bf8d199f257f03" dependencies = [ - "generic-array", + "cfg_aliases", ] [[package]] -name = "borsh" -version = "1.5.1" +name = "boxcar" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6362ed55def622cddc70a4746a68554d7b687713770de539e59a739b249f8ed" -dependencies = [ - "cfg_aliases", -] +checksum = "38c99613cb3cd7429889a08dfcf651721ca971c86afa30798461f8eee994de47" [[package]] name = "bumpalo" @@ -139,12 +184,6 @@ version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" -[[package]] -name = "bytemuck" -version = "1.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a" - [[package]] name = "byteorder" version = "1.5.0" @@ -163,12 +202,10 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.2" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f34d93e62b03caf570cccc334cbc6c2fceca82f39211051345108adcba3eebdc" +checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf" dependencies = [ - "jobserver", - "libc", "shlex", ] @@ -195,25 +232,11 @@ dependencies = [ "serde", ] -[[package]] -name = "chrono" -version = "0.4.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits", - "wasm-bindgen", - "windows-targets", -] - [[package]] name = "clap" -version = "4.5.21" +version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" +checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" dependencies = [ "clap_builder", "clap_derive", @@ -221,9 +244,9 @@ dependencies = [ [[package]] name = "clap-verbosity-flag" -version = "2.2.3" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34c77f67047557f62582784fd7482884697731b2932c7d37ced54bce2312e1e2" +checksum = "54381ae56ad222eea3f529c692879e9c65e07945ae48d3dc4d1cb18dbec8cf44" dependencies = [ "clap", "log", @@ -231,9 +254,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.21" +version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" +checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" dependencies = [ "anstream", "anstyle", @@ -250,14 +273,14 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] name = "clap_lex" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "clio" @@ -286,35 +309,11 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07ec5b69614ae4dbce88efe2684f4526e3a5aeb0a68326d1424f69c98f3040d2" -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "cpufeatures" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" -dependencies = [ - "libc", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "crossbeam-deque" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -331,61 +330,44 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "csv" -version = "1.3.1" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf" -dependencies = [ - "csv-core", - "itoa", - "ryu", - "serde", -] +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] -name = "csv-core" -version = "0.1.11" +name = "dashmap" +version = "5.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ - "memchr", + "cfg-if", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", + "rayon", ] [[package]] name = "delegate" -version = "0.12.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e018fccbeeb50ff26562ece792ed06659b9c2dae79ece77c4456bb10d9bf79b" +checksum = "bc2323e10c92e1cf4d86e11538512e6dc03ceb586842970b6332af3d4046a046" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] -name = "delegate" -version = "0.13.1" +name = "derive-syn-parse" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc2323e10c92e1cf4d86e11538512e6dc03ceb586842970b6332af3d4046a046" +checksum = "d65d7ce8132b7c0e54497a4d9a55a1c2a0912a0d786cf894472ba818fba45762" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -405,26 +387,22 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", "unicode-xid", ] -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", -] - [[package]] name = "downcast-rs" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" +[[package]] +name = "duplicate" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de78e66ac9061e030587b2a2e75cc88f22304913c907b11307bca737141230cb" + [[package]] name = "either" version = "1.13.0" @@ -440,7 +418,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -474,7 +452,6 @@ name = "execute_llvm" version = "0.1.0" dependencies = [ "hugr", - "hugr-llvm", "inkwell", "pyo3", "serde_json", @@ -482,9 +459,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fixedbitset" @@ -508,20 +485,21 @@ dependencies = [ ] [[package]] -name = "generic-array" -version = "0.14.7" +name = "hashbrown" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ - "typenum", - "version_check", + "ahash", + "allocator-api2", + "rayon", ] [[package]] name = "hashbrown" -version = "0.15.0" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] name = "heck" @@ -546,19 +524,20 @@ dependencies = [ [[package]] name = "hugr" -version = "0.13.3" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51c5f880029c2ec70b4884f69cd5fd55c628e58830e9225a82bcea7f776ac963" +checksum = "9f209c7cd671de29be8bdf0725e09b2e9d386387f439b13975e158f095e5a0fe" dependencies = [ "hugr-core", + "hugr-llvm", "hugr-passes", ] [[package]] name = "hugr-cli" -version = "0.13.3" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "617a0bf998c9f809eb634a8381896a60a4d7ae418d3db2eb1c661a083c3dd16f" +checksum = "ab6a94a980d47788908d7f93165846164f8b623b7f382cd3813bd0c0d1188e65" dependencies = [ "clap", "clap-verbosity-flag", @@ -567,20 +546,19 @@ dependencies = [ "hugr", "serde", "serde_json", - "thiserror", + "thiserror 2.0.7", ] [[package]] name = "hugr-core" -version = "0.13.3" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d6428f0512a92cc3495e70c709383464bf1deef7ac566f812575e28dad52273" +checksum = "60c3d5422f76dbec1d6948e68544b134562ec9ec087e8e6a599555b716f555dc" dependencies = [ "bitvec", "bumpalo", "cgmath", - "context-iterators", - "delegate 0.13.1", + "delegate", "derive_more", "downcast-rs", "enum_dispatch", @@ -600,73 +578,51 @@ dependencies = [ "smol_str", "strum", "strum_macros", - "thiserror", + "thiserror 2.0.7", "typetag", ] [[package]] name = "hugr-llvm" -version = "0.6.1" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3115ef2a4e4115ea6ae056e71e55418af08cee902007bdfc679f74ce4e60425" +checksum = "ce4117f4f934b1033b82d8cb672b3c33c3a7f8f541c50f7cc7ff53cebb5816d1" dependencies = [ "anyhow", - "delegate 0.12.0", + "delegate", "downcast-rs", - "hugr", + "hugr-core", "inkwell", - "itertools 0.12.1", + "itertools 0.13.0", "lazy_static", "petgraph", "strum", - "tket2", ] [[package]] name = "hugr-passes" -version = "0.13.3" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4ae6bd670bc95f716d153049574e6420fed970edde63ea228529a8df0df2838" +checksum = "ec2591767b6fe03074d38de7c4e61d52b37cb2e73b7340bf4ff957ad4554022a" dependencies = [ + "ascent", "hugr-core", "itertools 0.13.0", "lazy_static", "paste", "petgraph", - "thiserror", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", + "portgraph", + "thiserror 2.0.7", ] [[package]] name = "indexmap" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.15.2", ] [[package]] @@ -677,27 +633,36 @@ checksum = "bfa799dd5ed20a7e349f3b4639aa80d74549c81716d9ec4f994c9b5815598306" [[package]] name = "inkwell" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b597a7b2cdf279aeef6d7149071e35e4bc87c2cf05a5b7f2d731300bffe587ea" +checksum = "40fb405537710d51f6bdbc8471365ddd4cd6d3a3c3ad6e0c8291691031ba94b2" dependencies = [ "either", "inkwell_internals", "libc", "llvm-sys", "once_cell", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "inkwell_internals" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fa4d8d74483041a882adaa9a29f633253a66dde85055f0495c121620ac484b2" +checksum = "9dd28cfd4cfba665d47d31c08a6ba637eed16770abca2eccbbc3ca831fef1e44" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", +] + +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", ] [[package]] @@ -743,28 +708,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" - -[[package]] -name = "jobserver" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" -dependencies = [ - "libc", -] - -[[package]] -name = "js-sys" -version = "0.3.74" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a865e038f7f6ed956f788f0d7d60c541fff74c7bd74272c5d4cf15c63743e705" -dependencies = [ - "once_cell", - "wasm-bindgen", -] +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "lazy_static" @@ -774,9 +720,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.159" +version = "0.2.168" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" +checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" [[package]] name = "linux-raw-sys" @@ -903,51 +849,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" -[[package]] -name = "pest" -version = "2.7.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" -dependencies = [ - "memchr", - "thiserror", - "ucd-trie", -] - -[[package]] -name = "pest_derive" -version = "2.7.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d214365f632b123a47fd913301e14c946c61d1c183ee245fa76eb752e59a02dd" -dependencies = [ - "pest", - "pest_generator", -] - -[[package]] -name = "pest_generator" -version = "2.7.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb55586734301717aea2ac313f50b2eb8f60d2fc3dc01d190eefa2e625f60c4e" -dependencies = [ - "pest", - "pest_meta", - "proc-macro2", - "quote", - "syn 2.0.79", -] - -[[package]] -name = "pest_meta" -version = "2.7.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b75da2a70cf4d9cb76833c990ac9cd3923c9a8905a8929789ce347c84564d03d" -dependencies = [ - "once_cell", - "pest", - "sha2", -] - [[package]] name = "petgraph" version = "0.6.5" @@ -958,49 +859,26 @@ dependencies = [ "indexmap", ] -[[package]] -name = "pin-project-lite" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" - -[[package]] -name = "pkg-config" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" - [[package]] name = "portgraph" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4791aa897c125c0f9e606c9a26092f1a6ca50af86f7e37de54ab7e5a7673bdb0" +checksum = "6bfec2c00343ab6227cb3da08a1c9bed2d79fc379d040ce98582e81e825f96d1" dependencies = [ "bitvec", "context-iterators", - "delegate 0.12.0", + "delegate", "itertools 0.13.0", "petgraph", "serde", - "thiserror", -] - -[[package]] -name = "priority-queue" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "714c75db297bc88a63783ffc6ab9f830698a6705aa0201416931759ef4c8183d" -dependencies = [ - "autocfg", - "equivalent", - "indexmap", + "thiserror 2.0.7", ] [[package]] name = "proc-macro2" -version = "1.0.87" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -1102,18 +980,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -1123,9 +1001,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -1138,17 +1016,23 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustix" -version = "0.38.37" +version = "0.38.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" +checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1180,38 +1064,38 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "semver" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.210" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "itoa", "memchr", @@ -1228,17 +1112,6 @@ dependencies = [ "serde", ] -[[package]] -name = "sha2" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - [[package]] name = "shlex" version = "1.3.0" @@ -1253,9 +1126,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "smol_str" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66eaf762c5af19db3108300515c8aa7a50efc90ff745f4c62288052ebf9fdd25" +checksum = "9676b89cd56310a87b93dec47b11af744f34d5fc9f367b829474eec0a891350d" dependencies = [ "borsh", "serde", @@ -1272,9 +1145,6 @@ name = "strum" version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" -dependencies = [ - "strum_macros", -] [[package]] name = "strum_macros" @@ -1286,7 +1156,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -1302,9 +1172,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.79" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", @@ -1325,9 +1195,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tempfile" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ "cfg-if", "fastrand", @@ -1338,73 +1208,42 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.64" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.69", ] [[package]] -name = "thiserror-impl" -version = "1.0.64" +name = "thiserror" +version = "2.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +checksum = "93605438cbd668185516ab499d589afb7ee1859ea3d5fc8f6b0755e1c7443767" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.79", + "thiserror-impl 2.0.7", ] [[package]] -name = "tket-json-rs" -version = "0.5.1" +name = "thiserror-impl" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2609f8a0343065937000d8aa537a473aaab8591f7da1788d4d1bc3e792b3f293" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ - "serde", - "serde_json", - "strum", - "uuid", + "proc-macro2", + "quote", + "syn 2.0.90", ] [[package]] -name = "tket2" -version = "0.6.0" +name = "thiserror-impl" +version = "2.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79649f07cbc915fc6702bb917be19c27be5d9891561a48f112a74de172159daf" +checksum = "e1d8749b4531af2117677a5fcd12b1348a3fe2b81e36e61ffeac5c4aa3273e36" dependencies = [ - "bytemuck", - "cgmath", - "chrono", - "crossbeam-channel", - "csv", - "delegate 0.13.1", - "derive_more", - "downcast-rs", - "fxhash", - "hugr", - "hugr-cli", - "hugr-core", - "indexmap", - "itertools 0.13.0", - "lazy_static", - "num-rational", - "pest", - "pest_derive", - "petgraph", - "portgraph", - "priority-queue", - "rayon", - "serde", - "serde_json", - "smol_str", - "strum", - "strum_macros", - "tket-json-rs", - "tracing", - "typetag", - "zstd", + "proc-macro2", + "quote", + "syn 2.0.90", ] [[package]] @@ -1441,49 +1280,12 @@ dependencies = [ "winnow", ] -[[package]] -name = "tracing" -version = "0.1.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" -dependencies = [ - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.79", -] - -[[package]] -name = "tracing-core" -version = "0.1.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" -dependencies = [ - "once_cell", -] - [[package]] name = "typeid" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e13db2e0ccd5e14a544e8a246ba2312cd25223f616442d7f2cb0e3db614236e" -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - [[package]] name = "typetag" version = "0.2.18" @@ -1505,20 +1307,14 @@ checksum = "70b20a22c42c8f1cd23ce5e34f165d4d37038f5b663ad20fb6adbdf029172483" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] -[[package]] -name = "ucd-trie" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" - [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-xid" @@ -1544,22 +1340,13 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" -[[package]] -name = "uuid" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" -dependencies = [ - "serde", -] - [[package]] name = "validator" version = "0.2.0" dependencies = [ "cargo_toml", "hugr-cli", - "thiserror", + "thiserror 2.0.7", ] [[package]] @@ -1578,61 +1365,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "wasm-bindgen" -version = "0.2.97" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d15e63b4482863c109d70a7b8706c1e364eb6ea449b201a76c5b89cedcec2d5c" -dependencies = [ - "cfg-if", - "once_cell", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.97" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d36ef12e3aaca16ddd3f67922bc63e48e953f126de60bd33ccc0101ef9998cd" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 2.0.79", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.97" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "705440e08b42d3e4b36de7d66c944be628d579796b8090bfa3471478a2260051" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.97" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98c9ae5a76e46f4deecd0f0255cc223cfa18dc9b261213b8aa0c7b36f61b3f1d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.79", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.97" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ee99da9c5ba11bd675621338ef6fa52296b76b83305e9b6e5c77d4c286d6d49" - [[package]] name = "winapi-util" version = "0.1.9" @@ -1642,15 +1374,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets", -] - [[package]] name = "windows-sys" version = "0.42.0" @@ -1809,29 +1532,21 @@ dependencies = [ ] [[package]] -name = "zstd" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" -dependencies = [ - "zstd-safe", -] - -[[package]] -name = "zstd-safe" -version = "7.2.1" +name = "zerocopy" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ - "zstd-sys", + "zerocopy-derive", ] [[package]] -name = "zstd-sys" -version = "2.0.13+zstd.1.5.6" +name = "zerocopy-derive" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ - "cc", - "pkg-config", + "proc-macro2", + "quote", + "syn 2.0.90", ] diff --git a/Cargo.toml b/Cargo.toml index a20258a0..21c65419 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,14 +25,14 @@ debug_assert_with_mut_call = "warn" pyo3 = "0.19.0" serde_json = "1.0.111" cargo_toml = "0.20.4" -thiserror = "1.0.37" -hugr-llvm = "0.6.1" -hugr = "0.13.1" -inkwell = "0.4.0" +thiserror = "2.0.6" +hugr = "0.14.0" +hugr-cli = "0.14.0" +inkwell = "0.5.0" [patch.crates-io] # Uncomment these to test the latest dependency version during development -#hugr = { git = "https://github.com/CQCL/hugr", rev = "6bf6c82c9ec9d801ab43e311e5f815a3eea7d9c1" } -#hugr-cli = { git = "https://github.com/CQCL/hugr", rev = "6bf6c82c9ec9d801ab43e311e5f815a3eea7d9c1" } -#hugr-llvm = { git = "https://github.com/CQCL/hugr-llvm", rev = "c1e6407" } +# hugr = { git = "https://github.com/CQCL/hugr", rev = "861183e" } +# hugr-cli = { git = "https://github.com/CQCL/hugr", rev = "861183e" } +# hugr-llvm = { git = "https://github.com/CQCL/hugr", rev = "1091755" } diff --git a/execute_llvm/Cargo.toml b/execute_llvm/Cargo.toml index 9df57bca..33e4f51a 100644 --- a/execute_llvm/Cargo.toml +++ b/execute_llvm/Cargo.toml @@ -15,8 +15,7 @@ name = "execute_llvm" crate-type = ["cdylib"] [dependencies] -hugr-llvm.workspace = true -hugr.workspace = true +hugr = {workspace = true, features = ["llvm"]} inkwell.workspace = true pyo3.workspace = true serde_json.workspace = true diff --git a/execute_llvm/src/lib.rs b/execute_llvm/src/lib.rs index cfad4dd1..5eb06261 100644 --- a/execute_llvm/src/lib.rs +++ b/execute_llvm/src/lib.rs @@ -1,9 +1,7 @@ //! This module provides a Python interface to compile and execute a Hugr program to LLVM IR. -use hugr::{ - self, extension::ExtensionRegistry, ops, ops::custom::resolve_extension_ops, std_extensions, - HugrView, -}; -use hugr_llvm::utils::fat::FatExt; +use hugr::llvm::utils::fat::FatExt; +use hugr::Hugr; +use hugr::{self, ops, std_extensions, HugrView}; use inkwell::{context::Context, module::Module, values::GenericValue}; use pyo3::exceptions::PyValueError; use pyo3::prelude::*; @@ -13,22 +11,8 @@ macro_rules! pyerr { } fn parse_hugr(hugr_json: &str) -> PyResult { - // Deserializing should be a given if we validate before running - let mut hugr = - serde_json::from_str(hugr_json).map_err(|e| pyerr!("Couldn't deserialize hugr: {}", e))?; - let reg = ExtensionRegistry::try_new([ - hugr::extension::PRELUDE.to_owned(), - std_extensions::arithmetic::int_ops::EXTENSION.to_owned(), - std_extensions::arithmetic::int_types::EXTENSION.to_owned(), - std_extensions::arithmetic::float_ops::EXTENSION.to_owned(), - std_extensions::arithmetic::float_types::EXTENSION.to_owned(), - std_extensions::arithmetic::conversions::EXTENSION.to_owned(), - std_extensions::collections::EXTENSION.to_owned(), - std_extensions::logic::EXTENSION.to_owned(), - ]) - .map_err(|e| pyerr!("Making extension registry: {}", e))?; - resolve_extension_ops(&mut hugr, ®) - .map_err(|e| pyerr!("Instantiating extension ops: {}", e))?; + let hugr = Hugr::load_json(hugr_json.as_bytes(), &std_extensions::std_reg()) + .map_err(|e| pyerr!("Couldn't deserialize hugr: {}", e))?; Ok(hugr) } @@ -57,19 +41,19 @@ fn find_funcdef_node(hugr: impl HugrView, fn_name: &str) -> PyResult fn compile_module<'a>( hugr: &'a hugr::Hugr, ctx: &'a Context, - namer: hugr_llvm::emit::Namer, + namer: hugr::llvm::emit::Namer, ) -> PyResult> { let llvm_module = ctx.create_module("guppy_llvm"); // TODO: Handle tket2 codegen extension - let extensions = hugr_llvm::custom::CodegenExtsBuilder::default() + let extensions = hugr::llvm::custom::CodegenExtsBuilder::default() .add_int_extensions() .add_default_prelude_extensions() + .add_default_array_extensions() .add_float_extensions() - .add_conversion_extensions() - .add_default_rotation_extensions(); + .add_conversion_extensions(); let emitter = - hugr_llvm::emit::EmitHugr::new(ctx, llvm_module, namer.into(), extensions.finish().into()); + hugr::llvm::emit::EmitHugr::new(ctx, llvm_module, namer.into(), extensions.finish().into()); let hugr_module = hugr.fat_root().unwrap(); let emitter = emitter .emit_module(hugr_module) @@ -96,7 +80,7 @@ fn run_function( let hugr = parse_hugr(hugr_json)?; let ctx = Context::create(); - let namer = hugr_llvm::emit::Namer::default(); + let namer = hugr::llvm::emit::Namer::default(); let funcdefn_node = find_funcdef_node(&hugr, fn_name)?; let mangled_name = namer.name_func(fn_name, funcdefn_node); diff --git a/guppylang/std/_internal/compiler/array.py b/guppylang/std/_internal/compiler/array.py index b6d90b12..66e602cd 100644 --- a/guppylang/std/_internal/compiler/array.py +++ b/guppylang/std/_internal/compiler/array.py @@ -2,9 +2,9 @@ from __future__ import annotations -import hugr.std from hugr import Wire, ops from hugr import tys as ht +from hugr.std.collections.array import EXTENSION from guppylang.compiler.hugr_extension import UnsupportedOp from guppylang.definition.custom import CustomCallCompiler @@ -31,7 +31,7 @@ def _instantiate_array_op( inp: list[ht.Type], out: list[ht.Type], ) -> ops.ExtOp: - return hugr.std.PRELUDE.get_op(name).instantiate( + return EXTENSION.get_op(name).instantiate( [length, ht.TypeTypeArg(elem_ty)], ht.FunctionType(inp, out) ) @@ -39,7 +39,7 @@ def _instantiate_array_op( def array_type(elem_ty: ht.Type, length: ht.TypeArg) -> ht.ExtType: """Returns the hugr type of a fixed length array.""" elem_arg = ht.TypeTypeArg(elem_ty) - return hugr.std.PRELUDE.types["array"].instantiate([length, elem_arg]) + return EXTENSION.types["array"].instantiate([length, elem_arg]) def array_new(elem_ty: ht.Type, length: int) -> ops.ExtOp: diff --git a/guppylang/std/_internal/compiler/list.py b/guppylang/std/_internal/compiler/list.py index 2e7019a1..27414d5e 100644 --- a/guppylang/std/_internal/compiler/list.py +++ b/guppylang/std/_internal/compiler/list.py @@ -6,10 +6,10 @@ from typing import TYPE_CHECKING -import hugr.std.collections +import hugr.std.collections.list from hugr import Wire, ops from hugr import tys as ht -from hugr.std.collections import ListVal +from hugr.std.collections.list import List, ListVal from guppylang.definition.custom import CustomCallCompiler from guppylang.definition.value import CallReturnWires @@ -37,7 +37,7 @@ def _instantiate_list_op( name: str, elem_type: ht.Type, inp: list[ht.Type], out: list[ht.Type] ) -> ops.ExtOp: - op_def = hugr.std.collections.EXTENSION.get_op(name) + op_def = hugr.std.collections.list.EXTENSION.get_op(name) return ops.ExtOp( op_def, ht.FunctionType(inp, out), @@ -47,7 +47,7 @@ def _instantiate_list_op( def list_pop(elem_type: ht.Type) -> ops.ExtOp: """Returns a list `pop` operation.""" - list_type = hugr.std.collections.list_type(elem_type) + list_type = List(elem_type) return _instantiate_list_op( "pop", elem_type, [list_type], [list_type, ht.Option(elem_type)] ) @@ -55,13 +55,13 @@ def list_pop(elem_type: ht.Type) -> ops.ExtOp: def list_push(elem_type: ht.Type) -> ops.ExtOp: """Returns a list `push` operation.""" - list_type = hugr.std.collections.list_type(elem_type) + list_type = List(elem_type) return _instantiate_list_op("push", elem_type, [list_type, elem_type], [list_type]) def list_get(elem_type: ht.Type) -> ops.ExtOp: """Returns a list `get` operation.""" - list_type = hugr.std.collections.list_type(elem_type) + list_type = List(elem_type) return _instantiate_list_op( "get", elem_type, [list_type, ht.USize()], [ht.Option(elem_type)] ) @@ -69,7 +69,7 @@ def list_get(elem_type: ht.Type) -> ops.ExtOp: def list_set(elem_type: ht.Type) -> ops.ExtOp: """Returns a list `set` operation.""" - list_type = hugr.std.collections.list_type(elem_type) + list_type = List(elem_type) return _instantiate_list_op( "set", elem_type, @@ -80,7 +80,7 @@ def list_set(elem_type: ht.Type) -> ops.ExtOp: def list_insert(elem_type: ht.Type) -> ops.ExtOp: """Returns a list `insert` operation.""" - list_type = hugr.std.collections.list_type(elem_type) + list_type = List(elem_type) return _instantiate_list_op( "insert", elem_type, @@ -91,7 +91,7 @@ def list_insert(elem_type: ht.Type) -> ops.ExtOp: def list_length(elem_type: ht.Type) -> ops.ExtOp: """Returns a list `length` operation.""" - list_type = hugr.std.collections.list_type(elem_type) + list_type = List(elem_type) return _instantiate_list_op( "length", elem_type, [list_type], [list_type, ht.USize()] ) diff --git a/guppylang/std/_internal/util.py b/guppylang/std/_internal/util.py index ac1d76b4..5afe0f6e 100644 --- a/guppylang/std/_internal/util.py +++ b/guppylang/std/_internal/util.py @@ -7,7 +7,7 @@ from collections.abc import Callable from typing import TYPE_CHECKING -import hugr.std.collections +import hugr.std.collections.list import hugr.std.float import hugr.std.int import hugr.std.logic @@ -79,11 +79,7 @@ def external_op( def op(ty: ht.FunctionType, inst: Inst) -> ops.DataflowOp: concrete_args = [make_concrete_arg(arg, inst, variable_remap) for arg in args] - return ops.ExtOp( - op_def, - ty, - concrete_args, - ) + return op_def.instantiate(concrete_args, ty) return op @@ -171,7 +167,7 @@ def op(ty: ht.FunctionType, inst: Inst) -> ops.DataflowOp: def list_op( op_name: str, - ext: he.Extension = hugr.std.collections.EXTENSION, + ext: he.Extension = hugr.std.collections.list.EXTENSION, ) -> Callable[[ht.FunctionType, Inst], ops.DataflowOp]: """Utility method to create Hugr list ops. diff --git a/guppylang/tys/builtin.py b/guppylang/tys/builtin.py index 86630c28..f9785b21 100644 --- a/guppylang/tys/builtin.py +++ b/guppylang/tys/builtin.py @@ -3,7 +3,8 @@ from typing import TYPE_CHECKING, Literal, TypeGuard import hugr.std -import hugr.std.collections +import hugr.std.collections.array +import hugr.std.collections.list from hugr import tys as ht from guppylang.ast_util import AstNode @@ -122,7 +123,7 @@ def _list_to_hugr(args: Sequence[Argument]) -> ht.Type: # Linear elements are turned into an optional to enable unsafe indexing. # See `ListGetitemCompiler` for details. elem_ty = ht.Option(arg.ty.to_hugr()) if arg.ty.linear else arg.ty.to_hugr() - return hugr.std.collections.list_type(elem_ty) + return hugr.std.collections.list.List(elem_ty) def _array_to_hugr(args: Sequence[Argument]) -> ht.Type: @@ -135,9 +136,10 @@ def _array_to_hugr(args: Sequence[Argument]) -> ht.Type: # See `ArrayGetitemCompiler` for details. # Same also for classical arrays, see https://github.com/CQCL/guppylang/issues/629 elem_ty = ht.Option(ty_arg.ty.to_hugr()) + hugr_arg = len_arg.to_hugr() - array = hugr.std.PRELUDE.get_type("array") - return array.instantiate([len_arg.to_hugr(), ht.TypeTypeArg(elem_ty)]) + # TODO remove type ignore after Array type annotation fixed to include VariableArg + return hugr.std.collections.array.Array(elem_ty, hugr_arg) # type:ignore[arg-type] def _sized_iter_to_hugr(args: Sequence[Argument]) -> ht.Type: diff --git a/pyproject.toml b/pyproject.toml index e018f49f..473993fb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,14 +38,12 @@ dependencies = [ "networkx >=3.2.1,<4", "pydantic >=2.7.0b1,<3", "typing-extensions >=4.9.0,<5", - "hugr >=0.9.0,<0.10", - "tket2-exts>=0.2.0,<0.3", + "hugr >=0.10.0,<0.11", + "tket2-exts>=0.3.0,<0.4", ] [project.optional-dependencies] # pytket = ["pytket >=1.30.0,<2", "tket2 >=0.4.1,<0.5"] -docs = ["sphinx >=7.2.6,<9", "sphinx-book-theme >=1.1.2,<2"] -execution = ["execute-llvm"] pytket = ["pytket>=1.34"] [project.urls] @@ -53,10 +51,11 @@ homepage = "https://github.com/CQCL/guppylang" repository = "https://github.com/CQCL/guppylang" [dependency-groups] +docs = ["sphinx >=7.2.6,<9", "sphinx-book-theme >=1.1.2,<2"] dev = [ { include-group = "lint" }, { include-group = "test" }, - { include-group = "llvm_integration" }, + { include-group = "execution" }, { include-group = "pytket_integration" }, ] lint = ["pre-commit >=3.6.0,<4", "ruff >=0.6.2,<0.7", "mypy ==1.10.0"] @@ -66,13 +65,14 @@ test = [ "pytest-notebook >=0.10.0,<0.11", "pytest-snapshot >=0.9.0,<1", "ipykernel >=6.29.5,<7", - "tket2>=0.5.0", + "tket2>=0.6.0", ] -llvm_integration = [ +execution = [ { include-group = "test" }, # Required to run the llvm integration tests "maturin >=1.4.0,<2", "pip >=24", + "execute-llvm", ] pytket_integration = [{ include-group = "test" }, "pytket >=1.34.0,<2"] @@ -83,8 +83,10 @@ members = ["execute_llvm"] execute-llvm = { workspace = true } # Uncomment these to test the latest dependency version during development -#hugr = { git = "https://github.com/CQCL/hugr", subdirectory = "hugr-py", rev = "4cbe890ab4e72090708ff83592c0771caf2335df" } -# tket2-exts = { git = "https://github.com/CQCL/tket2", subdirectory = "tket2-exts", branch = "ss/rename" } +# hugr = { git = "https://github.com/CQCL/hugr", subdirectory = "hugr-py", rev = "861183e" } +# tket2-exts = { git = "https://github.com/CQCL/tket2", subdirectory = "tket2-exts", rev = "eb7cc63"} +# tket2 = { git = "https://github.com/CQCL/tket2", subdirectory = "tket2-py", rev = "eb7cc63"} + [build-system] diff --git a/uv.lock b/uv.lock index 4c14daab..8b5ef284 100644 --- a/uv.lock +++ b/uv.lock @@ -553,19 +553,13 @@ dependencies = [ ] [package.optional-dependencies] -docs = [ - { name = "sphinx" }, - { name = "sphinx-book-theme" }, -] -execution = [ - { name = "execute-llvm" }, -] pytket = [ { name = "pytket" }, ] [package.dev-dependencies] dev = [ + { name = "execute-llvm" }, { name = "ipykernel" }, { name = "maturin" }, { name = "mypy" }, @@ -579,12 +573,12 @@ dev = [ { name = "ruff" }, { name = "tket2" }, ] -lint = [ - { name = "mypy" }, - { name = "pre-commit" }, - { name = "ruff" }, +docs = [ + { name = "sphinx" }, + { name = "sphinx-book-theme" }, ] -llvm-integration = [ +execution = [ + { name = "execute-llvm" }, { name = "ipykernel" }, { name = "maturin" }, { name = "pip" }, @@ -594,6 +588,11 @@ llvm-integration = [ { name = "pytest-snapshot" }, { name = "tket2" }, ] +lint = [ + { name = "mypy" }, + { name = "pre-commit" }, + { name = "ruff" }, +] pytket-integration = [ { name = "ipykernel" }, { name = "pytest" }, @@ -614,20 +613,18 @@ test = [ [package.metadata] requires-dist = [ - { name = "execute-llvm", marker = "extra == 'execution'", editable = "execute_llvm" }, { name = "graphviz", specifier = ">=0.20.1,<0.21" }, - { name = "hugr", specifier = ">=0.9.0,<0.10" }, + { name = "hugr", specifier = ">=0.10.0,<0.11" }, { name = "networkx", specifier = ">=3.2.1,<4" }, { name = "pydantic", specifier = ">=2.7.0b1,<3" }, { name = "pytket", marker = "extra == 'pytket'", specifier = ">=1.34" }, - { name = "sphinx", marker = "extra == 'docs'", specifier = ">=7.2.6,<9" }, - { name = "sphinx-book-theme", marker = "extra == 'docs'", specifier = ">=1.1.2,<2" }, - { name = "tket2-exts", specifier = ">=0.2.0,<0.3" }, + { name = "tket2-exts", specifier = ">=0.3.0,<0.4" }, { name = "typing-extensions", specifier = ">=4.9.0,<5" }, ] [package.metadata.requires-dev] dev = [ + { name = "execute-llvm", editable = "execute_llvm" }, { name = "ipykernel", specifier = ">=6.29.5,<7" }, { name = "maturin", specifier = ">=1.4.0,<2" }, { name = "mypy", specifier = "==1.10.0" }, @@ -639,14 +636,14 @@ dev = [ { name = "pytest-snapshot", specifier = ">=0.9.0,<1" }, { name = "pytket", specifier = ">=1.34.0,<2" }, { name = "ruff", specifier = ">=0.6.2,<0.7" }, - { name = "tket2", specifier = ">=0.5.0" }, + { name = "tket2", specifier = ">=0.6.0" }, ] -lint = [ - { name = "mypy", specifier = "==1.10.0" }, - { name = "pre-commit", specifier = ">=3.6.0,<4" }, - { name = "ruff", specifier = ">=0.6.2,<0.7" }, +docs = [ + { name = "sphinx", specifier = ">=7.2.6,<9" }, + { name = "sphinx-book-theme", specifier = ">=1.1.2,<2" }, ] -llvm-integration = [ +execution = [ + { name = "execute-llvm", editable = "execute_llvm" }, { name = "ipykernel", specifier = ">=6.29.5,<7" }, { name = "maturin", specifier = ">=1.4.0,<2" }, { name = "pip", specifier = ">=24" }, @@ -654,7 +651,12 @@ llvm-integration = [ { name = "pytest-cov", specifier = ">=5.0.0,<6" }, { name = "pytest-notebook", specifier = ">=0.10.0,<0.11" }, { name = "pytest-snapshot", specifier = ">=0.9.0,<1" }, - { name = "tket2", specifier = ">=0.5.0" }, + { name = "tket2", specifier = ">=0.6.0" }, +] +lint = [ + { name = "mypy", specifier = "==1.10.0" }, + { name = "pre-commit", specifier = ">=3.6.0,<4" }, + { name = "ruff", specifier = ">=0.6.2,<0.7" }, ] pytket-integration = [ { name = "ipykernel", specifier = ">=6.29.5,<7" }, @@ -663,7 +665,7 @@ pytket-integration = [ { name = "pytest-notebook", specifier = ">=0.10.0,<0.11" }, { name = "pytest-snapshot", specifier = ">=0.9.0,<1" }, { name = "pytket", specifier = ">=1.34.0,<2" }, - { name = "tket2", specifier = ">=0.5.0" }, + { name = "tket2", specifier = ">=0.6.0" }, ] test = [ { name = "ipykernel", specifier = ">=6.29.5,<7" }, @@ -671,12 +673,12 @@ test = [ { name = "pytest-cov", specifier = ">=5.0.0,<6" }, { name = "pytest-notebook", specifier = ">=0.10.0,<0.11" }, { name = "pytest-snapshot", specifier = ">=0.9.0,<1" }, - { name = "tket2", specifier = ">=0.5.0" }, + { name = "tket2", specifier = ">=0.6.0" }, ] [[package]] name = "hugr" -version = "0.9.0" +version = "0.10.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "graphviz" }, @@ -684,9 +686,9 @@ dependencies = [ { name = "pydantic-extra-types" }, { name = "semver" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7a/ea/faf7545e3d3ffd4bc725bfcd622c60303e8cde0e33d847b0c7bcf1a3bb7c/hugr-0.9.0.tar.gz", hash = "sha256:ddb5adc674192520499e624e8f4650f465e059ab3f9048550c9c147fc9bf239a", size = 126531 } +sdist = { url = "https://files.pythonhosted.org/packages/a6/ef/9cd410ff0e3a92c5e88da2ef3c0e051dd971f4f6c5577873c7901ed31dd5/hugr-0.10.0.tar.gz", hash = "sha256:11e5a80ebd4e31cad0cb04d408cdd93a094e6fb817dd81481eedac5a58f86ff7", size = 129441 } wheels = [ - { url = "https://files.pythonhosted.org/packages/08/ad/b82f6cb95452699c29582cef3daaa2c281f86efd91d1d8d88895c47bb5b8/hugr-0.9.0-py3-none-any.whl", hash = "sha256:703da84a1b2fdb192f4ddce6daf9446dac24fb2377b3b259cced6899733530a5", size = 80011 }, + { url = "https://files.pythonhosted.org/packages/f2/71/83556457cfe27f4a1613cd49041cfe4c6e9e087a53b5beec48a8d709c36d/hugr-0.10.0-py3-none-any.whl", hash = "sha256:591e252ef3e4182fd0de99274ebb4999ddd9572a0ec823519de154e4bd9f14ec", size = 83000 }, ] [[package]] @@ -2251,7 +2253,7 @@ wheels = [ [[package]] name = "tket2" -version = "0.5.0" +version = "0.6.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "hugr" }, @@ -2259,80 +2261,43 @@ dependencies = [ { name = "tket2-eccs" }, { name = "tket2-exts" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ab/7c/2aaa2503ea26ab81c06ba964af97cac28904064fef9c122dbe7e82f921c9/tket2-0.5.0.tar.gz", hash = "sha256:0e983f933e9231bebc6fdaf8c3ffa56b8adf13636c51c06f775664524141f19c", size = 224173 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b0/a0/34359c683c6657d33c6e92ea565e5138357ba68d7acbc7825259e11616fc/tket2-0.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:570b1cf6b83fc8c0ac9a67c4e40a8faf5daed8c0b664f64d54ed0746d9ad3789", size = 3803598 }, - { url = "https://files.pythonhosted.org/packages/8d/07/172d33c9f90413d5cdcb09873b040db08b16fa9385c17f0ed6f7a6e12c8e/tket2-0.5.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:86366fadb8740911222a3f3522454badee80f23c142b629753955b7aa2dd351e", size = 4474573 }, - { url = "https://files.pythonhosted.org/packages/6c/9c/c23ae608eb3cd90b3f2b8269080afd385d06c9979176b989a6106fc414bb/tket2-0.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59afbe455dfb274a6874f03dce6040125aba4fb0c854cddf23edc546ff7e8df3", size = 3939809 }, - { url = "https://files.pythonhosted.org/packages/4f/bf/1dde175e668ab30fda7e09e645c27417a9879b4eb7ad5f8c5152ab2c7c96/tket2-0.5.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:31c73a391beef828011f9449d15e12541a31bae25dd52cdfac74b8ffab112f54", size = 3879199 }, - { url = "https://files.pythonhosted.org/packages/44/a0/d9bbb52b9801d4aae9d97cbd30d985052280c62464ed160716cca3c0b0b6/tket2-0.5.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d988087136b098155b345bdd4a232d5df6a802adc2a5e3733a3eee642182f4b2", size = 4521382 }, - { url = "https://files.pythonhosted.org/packages/80/f6/9c0c0e6616fed354987b40a8f0b37317a2394ae91c343c2d389b4dbea2fa/tket2-0.5.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:74c531f798b1ee3c5a8a3f5111205d52449125bfe4dff825888efdde460a5a69", size = 5459797 }, - { url = "https://files.pythonhosted.org/packages/4c/28/bf5e277c72e33f25cabb58f0674b01ca119f813a3170793f06477fafbdac/tket2-0.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3fb4482055c7d7beceb8c34beaa1df4e6c0b51f721c141203795f5ac438518b7", size = 4333591 }, - { url = "https://files.pythonhosted.org/packages/33/81/8270a5eb9b5f0c9e06352263e7a55adb3b3dc6550f4e7ea8b6d001a00844/tket2-0.5.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:afd8a41c08001598173df9fa1eedf3ee90a7ee965845b82c148e77b670eff2c1", size = 4118350 }, - { url = "https://files.pythonhosted.org/packages/e5/c1/57ea758e74f73583bb9622d7c290c77df58c71eccb75171d52b6f2f5c664/tket2-0.5.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c22312a6d1bb8bf736a2234ad6cbde8d02d56968ecc6a8c788511d50ef87dec0", size = 4104065 }, - { url = "https://files.pythonhosted.org/packages/8b/d4/538ef3cd4acb45b381bce4eef23d049a731907166efa2c621e3f11d4f4b9/tket2-0.5.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:8c621b284a4d56283aa3a717dd22764906ff7bb237328b2cdc4bb31e994305f5", size = 4409060 }, - { url = "https://files.pythonhosted.org/packages/eb/7e/efd9af64a68320428169127f527bf7a00b8b45d22cab8631dd717b6b8580/tket2-0.5.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9ff8f8e7cf80473715a093d5336b3ff2e9140bb8448647dc57326e8643feb2b8", size = 4474198 }, - { url = "https://files.pythonhosted.org/packages/7f/c0/cee7847316a04cd8136f325aa2275d7aa0601f4573995f1a625eaa031e65/tket2-0.5.0-cp310-none-win32.whl", hash = "sha256:2071b0759c0c4ae81f8d5bc35f3f8c9139a4d6e2ee7e5f8bd4c9317eecbd9939", size = 3744566 }, - { url = "https://files.pythonhosted.org/packages/4e/87/98dc94fe902b74543d01cb83695d4080285ca95c116c93e0210d092eaf3f/tket2-0.5.0-cp310-none-win_amd64.whl", hash = "sha256:d4f0960d55fa77cdf0579aff7e8cd49f902092ce728b1a7cd4741e59e5e2cd11", size = 4196769 }, - { url = "https://files.pythonhosted.org/packages/10/d1/f3356e7368321ad768202920d84845af7ffe48e1479ab82218d75c9925fd/tket2-0.5.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:3355f90c08be7be1f04de3b1da47ab092d9f0f9aaee427a4b385a4c778acaa4e", size = 4069056 }, - { url = "https://files.pythonhosted.org/packages/31/53/a1d1ff4f3bbfa99a766b27be9567a297c935a0d269db94d9e20e06d93af5/tket2-0.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7ee7c6bbc6bfa81040581390323931a2d2e65d0fe28af43bb9fd431e1b3a97a9", size = 3803758 }, - { url = "https://files.pythonhosted.org/packages/d9/6e/37910978999fa248a70a7e9c6704664d8da31204c99944cf294ebe5af7fb/tket2-0.5.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:85c9107c367e8ed95409137ed43f6fc47f5f698881db12b0505c024569f0cb1d", size = 4475499 }, - { url = "https://files.pythonhosted.org/packages/d1/1e/d01ad167e17d3bc715102579970bb1d8e74b89f56c7fecaab098216aa22b/tket2-0.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4c93f3f43dab15639a7ecf5908a4b40f8c7499aa8c9d2b1c3fb99b43438d2f2", size = 3938290 }, - { url = "https://files.pythonhosted.org/packages/07/65/0f3f6bd294dc4dd2f4eb009da1cb5950550ca7901e55f98867e188aeced5/tket2-0.5.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:61aacc91facb7ffe1a633311fe4493aa7c5a62bc7ada783f91e6ff33e3c6eba5", size = 3884050 }, - { url = "https://files.pythonhosted.org/packages/e1/c4/405987b62243ff28cc542dea0428a4de2b5517e39c4f0cc92cb7688ee21a/tket2-0.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6f1c0dc27604771cace9c91aa133d14302522536f468e2a7eb1c94ab73ed131f", size = 4521538 }, - { url = "https://files.pythonhosted.org/packages/1a/81/d879e3e03aff7da2557d56894fa6c82f73774ddb64a972a928b744de9b2a/tket2-0.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6dcf2ed5b30ccaaa8f618e626be939e14043db6f98b17a3ff2b9b9ada9194101", size = 5459463 }, - { url = "https://files.pythonhosted.org/packages/b5/1f/d24edb71b6146cfa1fda02841b1962f6e35037adff96834e7a77eb10b2ba/tket2-0.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:890906786ba1d4874d726155d063fdcc62286c59077aa9b776a2b404ddd67684", size = 4336956 }, - { url = "https://files.pythonhosted.org/packages/26/d2/4e15b43ebbb2f616b570aaa432f2f65f7877a5bf304c282a49af60a98d86/tket2-0.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:900c3d08be38739a2d7da8892809be02489ec4c0f127477da49a6be4507bb540", size = 4116397 }, - { url = "https://files.pythonhosted.org/packages/ea/b4/0181d5ca54afaee7b267501138dcd8db41deb622f8d8d3c9bad32ab33326/tket2-0.5.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:677297a5fecd73734342d5f1b17f178313817622843f5390dc7e662f64bac280", size = 4105606 }, - { url = "https://files.pythonhosted.org/packages/1b/40/5af365084dbf9f5443ea953221cb67465c7a9d43cf374f6b91bb9a35f262/tket2-0.5.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1559bd173e1b565f6da28288ea10a7d4ffd0daef82c5f4637263541b35c9d68f", size = 4406467 }, - { url = "https://files.pythonhosted.org/packages/3b/48/6a8f685882221093fffcd673957343ef0ebc703b4a33f8ad64fd30684c3f/tket2-0.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1173ecaf47200e79920bae4b7e4a1398e0a58c4ac484f2297729ae8d5ca9ec8a", size = 4476118 }, - { url = "https://files.pythonhosted.org/packages/16/2b/a1a3e506ab5394e564a2af07fe113c521f6511baa07a14e322c3df2f46a4/tket2-0.5.0-cp311-none-win32.whl", hash = "sha256:0e759d4c416a49d22f335706855d5d53b506a38c37981f5e4f9baa65c40c4ec7", size = 3745064 }, - { url = "https://files.pythonhosted.org/packages/eb/ee/7747f464389c30c6a6402d432d23bd6763b892cdc49660b28fb6d65362ed/tket2-0.5.0-cp311-none-win_amd64.whl", hash = "sha256:d4df9b9acaff533e755dc9b0b052f7b02c7853a5021403c45b505933d3f87ffd", size = 4195959 }, - { url = "https://files.pythonhosted.org/packages/38/67/2bfdbaeab2e19ff6cf31a7d8ee9a7e78024972ee6c1ba205603555b68046/tket2-0.5.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:eb1eefb201b4fb5c589cb69a0bfd0ad43167ebf0886701db25f21979cd07cd3a", size = 4067909 }, - { url = "https://files.pythonhosted.org/packages/69/fc/fed0208573aa6f6dae6fa855405f50a20831096f55cee890d288a3b59529/tket2-0.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6008ea83f850c8827ae99435a290540e3ff216b81ca6f00e4c35988597a1cd6e", size = 3804559 }, - { url = "https://files.pythonhosted.org/packages/78/54/1d47c0eb57e04bad3467ff2d541c55bb127493bda1c42eaf28225a8533dd/tket2-0.5.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:99162729722b8b4733d8f14d11a208890e0022d12bd69624d36ce67484c35153", size = 4470733 }, - { url = "https://files.pythonhosted.org/packages/58/33/4da7a02cf9232354fe2216a5bcfdd45db382b30554ee3dcd1ff212bb7dca/tket2-0.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d20577b4f92a83d1933c59c79b837fb87372d2fcccf46936e8426f83103f36e9", size = 3936658 }, - { url = "https://files.pythonhosted.org/packages/26/15/ee480158780871c87e8c91dfb29063972b7895ea1bade1a284d8fba52cfc/tket2-0.5.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bcd4a249cb2bb9ebc11d23246a7053518f596d9ad3e7f82e046c4092f4301434", size = 3875720 }, - { url = "https://files.pythonhosted.org/packages/00/04/a5f7ce686dde146f7dcf8ef9c4fcccf8a86e1072301466b697ddd7148b98/tket2-0.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f9729a028568287b2b66539ce65f43db07107dfa59622cdf74410b7ec270f626", size = 4515140 }, - { url = "https://files.pythonhosted.org/packages/a9/9c/9f54034f18f6bf127b057f36d51e61e92d5b9b7b9397a3f0b68cffec5044/tket2-0.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:075f3c90d8b747b9b24845fad9f6d84ae2428d80ad0d9c4e6d8eda7f207fc789", size = 5438753 }, - { url = "https://files.pythonhosted.org/packages/0d/06/650d41c6260fd71f73b11d05427821820b9c4b8633bbeb19093bdaf9b99d/tket2-0.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b47e9c6dec87b9360027d3f9127770f68483fdbe2202ddc145a50369b8af5428", size = 4340243 }, - { url = "https://files.pythonhosted.org/packages/39/3f/3b823959f0d9629f05d23fc57158473589e9ad6dbec7ec006d68662c27b4/tket2-0.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:81e9d8fb1a142f2375c1ec4fb38b7fbbf652efdbd2056496ed89196b682e5caf", size = 4123197 }, - { url = "https://files.pythonhosted.org/packages/e1/dc/8fa6baa5d64c9f0a41bf47dafd609c59caf5bb9caa041f6d278fb623f9aa/tket2-0.5.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:773dae0435c80e21b8e9e492e378f1f188be0e33d1ae0c616d6f7d0f50507029", size = 4098065 }, - { url = "https://files.pythonhosted.org/packages/d5/1c/a31d8a887670814a68047d536328573d234ed99e8356339c5692a53b7767/tket2-0.5.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4bcf1072dc55bd6d167c4044290984f8dc1785827b6a4ecfa880dd675e5fccb5", size = 4403253 }, - { url = "https://files.pythonhosted.org/packages/fd/8c/9ef0714d98a9649488bb91ec3f1c66ac6b526f725cccccf552522dc945fa/tket2-0.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c55fa3cf3252e9d3f87782650cf586409eb1c1ce095b361621389cf8537fb74f", size = 4476375 }, - { url = "https://files.pythonhosted.org/packages/2a/d6/b850caee0d9b7920750c5b9636f36ecd3562916414f6a1a852db5ea80fe6/tket2-0.5.0-cp312-none-win32.whl", hash = "sha256:5de9ef9b56ff47070581886472161a926ee4e42394d82d5930110e83733ff61d", size = 3749065 }, - { url = "https://files.pythonhosted.org/packages/f8/ac/0968af4b6847ebd03a94595e8846ad982c54d8fe7c9dd5233930e6b8676e/tket2-0.5.0-cp312-none-win_amd64.whl", hash = "sha256:e96f1e1d1d9fa4c11e0c340ceae3057799419905d376f8eeb61f16055d2161b3", size = 4205451 }, - { url = "https://files.pythonhosted.org/packages/91/f4/2a1073033573a654a78c2dcbd6c93f794000063fd9355fae956a95d6b817/tket2-0.5.0-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:94b11bc7dee0e0d706b917a9aca9d300b2a861d8878d45be3136a2218cc88a2f", size = 4470143 }, - { url = "https://files.pythonhosted.org/packages/18/37/05f44f8912ddf76033bef52c08cbd4f9258746b06be50fe07aa6aa21792d/tket2-0.5.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28cd921b7a4ea190d2b012b5938a75a7e4f52633af8f94667f8d58b1d96c99dc", size = 3941477 }, - { url = "https://files.pythonhosted.org/packages/5d/3e/e94ae654b9559ed28ad24c0fc2c25891c0b9b7fe03d8fc87cd1d461db0d7/tket2-0.5.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d69b9c8fb1f2cc2164a8f21cd58baa8210a7ae2e577a3705838d80a5f51c1d91", size = 3883235 }, - { url = "https://files.pythonhosted.org/packages/09/1a/aceb016b53fc1bffe900704e9e298229e67e7d4ee2a03769aaecba2123d6/tket2-0.5.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a89601fb6f3cd224b1c545b6ce5604431caf5e0b86235f070fd835e2bc32e4fa", size = 4521748 }, - { url = "https://files.pythonhosted.org/packages/66/72/7b91d44aeae94516ec59e3a09b4ab421f2e6a61822c09d1129f47dcd4dd6/tket2-0.5.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:232c06a95f45774aeaccaf736a7b51f3ce4b27eaa575e56b44c76012e62d821d", size = 5457635 }, - { url = "https://files.pythonhosted.org/packages/31/42/ec01391ce07794002160dd928b45c2330fbdb15fd7cd97934b652fb24cd3/tket2-0.5.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f06d9f0a191c010bd8b6ad826bc1aa10f8b8566f25cc971407482100799a4a48", size = 4337550 }, - { url = "https://files.pythonhosted.org/packages/7e/78/4f1169799bae4fda6dca90b1a44f15f5d5962d7d14353fab754c84e351db/tket2-0.5.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:8b0cd2afd8b088f37ee4e26b45d9f923526c91446755523bab9381266f616892", size = 4123793 }, - { url = "https://files.pythonhosted.org/packages/f7/73/f311aba98b5dfc619ac60f57fa30e1642d091b2dcd5ab98b0bad6b277f90/tket2-0.5.0-pp310-pypy310_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:d0501c984ee7f6adf73b56ef0c7d1d7e2db6e3a9c1d44f3e9e66f50af652d57e", size = 4101292 }, - { url = "https://files.pythonhosted.org/packages/21/8f/dbae07d8beeedfa1e1788b921c61009734209452809f676c1934e26c0177/tket2-0.5.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:df97424b2e64a804887d17e0e0f3be849fbd88cbf6a13563dc00842a478d6bbf", size = 4413372 }, - { url = "https://files.pythonhosted.org/packages/4c/2a/dc3a947a7195c715bc161ad303afc0f4b836718389161ad4783573ff3748/tket2-0.5.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:a4d8d23ccb9f28d2c8640a274521747f71d3ea839b64564820e4ffe317b31e42", size = 4474374 }, +sdist = { url = "https://files.pythonhosted.org/packages/22/27/285392537150ee0472cd6f0bf615ed512823497b2d5b9e51726e3cdd922a/tket2-0.6.0.tar.gz", hash = "sha256:530eae3a26bec2aac718553d8fb372add69f7082cde952b8e7746ade00333702", size = 224593 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/fc/8fbcc8c98a9243231c6380bcccdfef28c8461a675c6f758309746f316691/tket2-0.6.0-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:e618e8a99b1ddd62b8f09061f83e8206dc877643426844157eb2414f1eefd601", size = 3718551 }, + { url = "https://files.pythonhosted.org/packages/66/cd/79c10b82415ee04a12b333511c133eddbea081c0f195ee133391b182d385/tket2-0.6.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:5a49e63c64588190c197ef9dc3ec12c82eb538347f5d3019f26783e3ec61c018", size = 3463405 }, + { url = "https://files.pythonhosted.org/packages/2a/ea/143b95c373a4d104f5f2cab3b361e29083c9a746b047fe4ff7a62fbc6559/tket2-0.6.0-cp310-abi3-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:27fa940f30333ca004ce487b3398bd5166312551fb6ed62b5545a4d7d4b822d6", size = 4096055 }, + { url = "https://files.pythonhosted.org/packages/be/44/dd35eb58f23e0844cfc4b1c26f7842cf9725f5373ac9a86dabc8aa00214c/tket2-0.6.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5065b42d2e4efe9f308a6e4715c2aeb58be8a7b050e4545724d3e20564e9d6f", size = 3547117 }, + { url = "https://files.pythonhosted.org/packages/4d/d1/5c026c9acd5f26c33cf837fee30abcfe0776bbf66e0c78b1b66a76321682/tket2-0.6.0-cp310-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cbe6bece4e07e08cc92da4083505c02771bc7e91e3c256fbab3bd47bd02d4af2", size = 3546947 }, + { url = "https://files.pythonhosted.org/packages/fe/0c/32a8e929a0e1154fbc3456c5d6fec2ee3dfdd192e8306b9e1027ef5f7bc8/tket2-0.6.0-cp310-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6cb2d7ac3aa2863cbd76389bedf9c3018d58a88e34948776a0ea6c46f4d48c2d", size = 4089364 }, + { url = "https://files.pythonhosted.org/packages/fe/06/a6bec50a1aa155a8f29dc4771956f33307e6799475bd10e84bd8d9f11b96/tket2-0.6.0-cp310-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:06b05957afc0bb816c585ebde367655dfa822087f69699b89d6a8be889af9e64", size = 5021661 }, + { url = "https://files.pythonhosted.org/packages/94/4d/7e4120d4df554a0cc2649fe8911703577af51b7abe770f7258ea8057793d/tket2-0.6.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1454eee61c8c264adaf9f0370966373ba796484efe94cd1377bc3e67ae8f8867", size = 3905811 }, + { url = "https://files.pythonhosted.org/packages/58/bc/3e20b2398f72721962c5319ffb2c0b803e4df0b719b173133e79667f0d4a/tket2-0.6.0-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:15721b5904673aeba0b53901de3977d83a7c5b4bb21d042f48ee4f15f2fad995", size = 3759781 }, + { url = "https://files.pythonhosted.org/packages/f4/39/e22d159182c6054801387ab06d3303eadd4ec013696b674cc7ef11a76ebe/tket2-0.6.0-cp310-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:2db38472d4988f8ae4b1e0711b1b65b636b9a3faa7aa4c255c8258515d88e5d5", size = 3836709 }, + { url = "https://files.pythonhosted.org/packages/26/9d/d23b0e657d8e7295b33439d1846a858a1b5e7cacaf2477cbe05beed0b9cb/tket2-0.6.0-cp310-abi3-musllinux_1_2_i686.whl", hash = "sha256:1255831d7f0fc65291cb50abc96041529679c3abbe7431eee4e3e6ecfbb41fad", size = 4074652 }, + { url = "https://files.pythonhosted.org/packages/b1/0f/f4562bf397365cff2cf13e2c745f66a5275e10992a8d8b07e45e622e7ada/tket2-0.6.0-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a56af6cfa1f4e8ae4ea5be60477b8bf0501972885d985dcd85c7c498b494bdc7", size = 4079034 }, + { url = "https://files.pythonhosted.org/packages/0b/c1/60ff719894882db83220e2e99d54e2c50ec3e274aac60b741a67dee1a0c9/tket2-0.6.0-cp310-abi3-win32.whl", hash = "sha256:80f59a9242d7e05af13564bd872b3a90476089a5fe6b1da95b5538019f9b2639", size = 3393638 }, + { url = "https://files.pythonhosted.org/packages/0f/9f/d0db7192534bbdae6eb07f567421c4672e290391ba603f10a96c9e53b462/tket2-0.6.0-cp310-abi3-win_amd64.whl", hash = "sha256:c2750f0da30efab3b8a0ab68d55b7dc810b9c585c0d83ab86a5734c2ce0b6320", size = 3825783 }, ] [[package]] name = "tket2-eccs" -version = "0.2.0" +version = "0.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/51/75/6a19814c04f4b69bb464b1b4ac80fb317f4ed77bf1474f5474ac9e0c9d4a/tket2_eccs-0.2.0.tar.gz", hash = "sha256:201e52f2eaa6eb54df814f331ad597d3733e12d8fd6c4f8ad571572460c2f62b", size = 4428924 } +sdist = { url = "https://files.pythonhosted.org/packages/8d/66/c235509596f8b719635d38143fdd4ca2aaaaf484c6c3865314e58ea1a0f5/tket2_eccs-0.3.0.tar.gz", hash = "sha256:56c5b350b2f2ab709a33f8b0147a9ac118a501a6c9d6eb95e463e76ba33d3e4f", size = 4425732 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a8/1f/9dbd087f3fc1195dd4c9c5a320923a504dddbdbd4ae3efada551cb291dfe/tket2_eccs-0.2.0-py3-none-any.whl", hash = "sha256:b280f7112fb743383ecd6077c8aa385a3f7f909b7618c345bbebe3c56ca3eb7f", size = 4431360 }, + { url = "https://files.pythonhosted.org/packages/57/dd/10738d78e3af2c0d8b477f73073586363140b60634f44487917f98f423c0/tket2_eccs-0.3.0-py3-none-any.whl", hash = "sha256:3c84ede88cc70b9bd15956ce79f07b0905dc9f8947140c785ef617962a129f89", size = 4427993 }, ] [[package]] name = "tket2-exts" -version = "0.2.0" +version = "0.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "hugr" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0e/56/d9435d4f4fc56af1193b50195e0fe9ff8192919caff0c978ce915d41ecae/tket2_exts-0.2.0.tar.gz", hash = "sha256:bbff2b27ab795fa045efb4c58d4fcdf0e9c94137d1aa5c49677cc8315b5ecfb8", size = 9306 } +sdist = { url = "https://files.pythonhosted.org/packages/26/b4/fb7a861794ba9a3cce6ea94be74627fc83dac946029e67e31ab918e21a57/tket2_exts-0.3.0.tar.gz", hash = "sha256:ddfe1a410059675fad960f8ff6fc3110914a46edf1d29ef59403f242d50551f0", size = 9562 } wheels = [ - { url = "https://files.pythonhosted.org/packages/98/82/4865a9d308b039f89c85020b6537b940d84ab6160d6c7520b911123dd459/tket2_exts-0.2.0-py3-none-any.whl", hash = "sha256:e9c207c90ff03e60faa1e4a1950f5bdf3ddfea8775e5f6f4bf80840d38a807a2", size = 14575 }, + { url = "https://files.pythonhosted.org/packages/af/de/8dce94965f71bf33aac68c69e9c383307d57e1f955fa6e1b1ae67e059aba/tket2_exts-0.3.0-py3-none-any.whl", hash = "sha256:5bc144fcc18aacfa26f3ae68c81aa154db5479097c38a75cde12bccc03d6a8cd", size = 14691 }, ] [[package]] diff --git a/validator/Cargo.toml b/validator/Cargo.toml index 9288b71b..80ab1368 100644 --- a/validator/Cargo.toml +++ b/validator/Cargo.toml @@ -11,6 +11,6 @@ publish = false workspace = true [dependencies] -hugr-cli = "0.13.1" +hugr-cli.workspace = true cargo_toml.workspace = true thiserror.workspace = true From 471b74c2bf5ca6144d6a5dec71b8a0e4aec57a95 Mon Sep 17 00:00:00 2001 From: Seyon Sivarajah Date: Tue, 17 Dec 2024 11:01:16 +0000 Subject: [PATCH 04/10] fix: docs build command (#729) --- docs/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/build.sh b/docs/build.sh index 794cfa11..0cedc716 100755 --- a/docs/build.sh +++ b/docs/build.sh @@ -4,4 +4,4 @@ mkdir build touch build/.nojekyll # Disable jekyll to keep files starting with underscores -uv run --extra docs sphinx-build -b html ./api-docs ./build/api-docs +uv run --group docs sphinx-build -b html ./api-docs ./build/api-docs From a099d1ad5f9584976fb58ff7180f76a6b466ffa8 Mon Sep 17 00:00:00 2001 From: Seyon Sivarajah Date: Tue, 17 Dec 2024 12:16:27 +0000 Subject: [PATCH 05/10] chore: maturin develop in justfile + bump execute version (#730) --- Cargo.lock | 2 +- execute_llvm/Cargo.toml | 2 +- justfile | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ca3c20f0..ddb2de16 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -449,7 +449,7 @@ dependencies = [ [[package]] name = "execute_llvm" -version = "0.1.0" +version = "0.2.0" dependencies = [ "hugr", "inkwell", diff --git a/execute_llvm/Cargo.toml b/execute_llvm/Cargo.toml index 33e4f51a..e67ea79a 100644 --- a/execute_llvm/Cargo.toml +++ b/execute_llvm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "execute_llvm" -version = "0.1.0" +version = "0.2.0" edition.workspace = true homepage.workspace = true repository.workspace = true diff --git a/justfile b/justfile index d0399767..806a1e02 100644 --- a/justfile +++ b/justfile @@ -21,7 +21,7 @@ _prepare-test: # Build the validator binary if rust is installed. Otherwise, skip it. cargo build --release -p validator || true # Build the execution binary if rust is installed. Otherwise, skip it. - uv run maturin build -m execute_llvm/Cargo.toml --release || true + uv run maturin develop -m execute_llvm/Cargo.toml --release || true # Run the tests. test *PYTEST_FLAGS: _prepare-test From 602e2434acb07ca5906d867affe9d4fd1a06d59d Mon Sep 17 00:00:00 2001 From: Mark Koch <48097969+mark-koch@users.noreply.github.com> Date: Tue, 17 Dec 2024 17:08:04 +0000 Subject: [PATCH 06/10] feat: Unpacking assignment of iterable types with static size (#688) Closes #649. Sorry for the big PR, but there was no good way to split the checking logic up. I recommend reviewing commit by commit, most of the actual logic is in 616c0c5. Hugr lowering follows in a separate PR (#689). --- guppylang/cfg/bb.py | 4 +- guppylang/cfg/builder.py | 97 ++--- guppylang/checker/errors/type_errors.py | 41 +- guppylang/checker/expr_checker.py | 34 +- guppylang/checker/stmt_checker.py | 351 ++++++++++++++---- guppylang/compiler/stmt_compiler.py | 100 ++++- guppylang/nodes.py | 54 +++ guppylang/std/_internal/compiler/array.py | 20 + guppylang/tys/const.py | 5 + guppylang/tys/printing.py | 4 +- tests/error/type_errors/not_unpackable.err | 8 + tests/error/type_errors/not_unpackable.py | 7 + .../error/type_errors/unpack_generic_size.err | 12 + .../error/type_errors/unpack_generic_size.py | 15 + tests/error/type_errors/unpack_non_static.err | 12 + tests/error/type_errors/unpack_non_static.py | 7 + .../type_errors/unpack_tuple_starred.err | 10 + .../error/type_errors/unpack_tuple_starred.py | 7 + tests/integration/test_unpack.py | 104 ++++++ 19 files changed, 740 insertions(+), 152 deletions(-) create mode 100644 tests/error/type_errors/not_unpackable.err create mode 100644 tests/error/type_errors/not_unpackable.py create mode 100644 tests/error/type_errors/unpack_generic_size.err create mode 100644 tests/error/type_errors/unpack_generic_size.py create mode 100644 tests/error/type_errors/unpack_non_static.err create mode 100644 tests/error/type_errors/unpack_non_static.py create mode 100644 tests/error/type_errors/unpack_tuple_starred.err create mode 100644 tests/error/type_errors/unpack_tuple_starred.py create mode 100644 tests/integration/test_unpack.py diff --git a/guppylang/cfg/bb.py b/guppylang/cfg/bb.py index 6bb6b75a..776ff333 100644 --- a/guppylang/cfg/bb.py +++ b/guppylang/cfg/bb.py @@ -142,13 +142,15 @@ def _handle_assign_target(self, lhs: ast.expr, node: ast.stmt) -> None: match lhs: case ast.Name(id=name): self.stats.assigned[name] = node - case ast.Tuple(elts=elts): + case ast.Tuple(elts=elts) | ast.List(elts=elts): for elt in elts: self._handle_assign_target(elt, node) case ast.Attribute(value=value): # Setting attributes counts as a use of the value, so we do a regular # visit instead of treating it like a LHS self.visit(value) + case ast.Starred(value=value): + self._handle_assign_target(value, node) def visit_DesugaredListComp(self, node: DesugaredListComp) -> None: self._handle_comprehension(node.generators, node.elt) diff --git a/guppylang/cfg/builder.py b/guppylang/cfg/builder.py index 29316a0e..87715c27 100644 --- a/guppylang/cfg/builder.py +++ b/guppylang/cfg/builder.py @@ -316,56 +316,13 @@ def visit_IfExp(self, node: ast.IfExp) -> ast.Name: def visit_ListComp(self, node: ast.ListComp) -> DesugaredListComp: check_lists_enabled(node) - generators, elt = self._build_comprehension(node.generators, node.elt, node) + generators, elt = desugar_comprehension(node.generators, node.elt, node) return with_loc(node, DesugaredListComp(elt=elt, generators=generators)) def visit_GeneratorExp(self, node: ast.GeneratorExp) -> DesugaredGeneratorExpr: - generators, elt = self._build_comprehension(node.generators, node.elt, node) + generators, elt = desugar_comprehension(node.generators, node.elt, node) return with_loc(node, DesugaredGeneratorExpr(elt=elt, generators=generators)) - def _build_comprehension( - self, generators: list[ast.comprehension], elt: ast.expr, node: ast.AST - ) -> tuple[list[DesugaredGenerator], ast.expr]: - # Check for illegal expressions - illegals = find_nodes(is_illegal_in_list_comp, node) - if illegals: - err = UnsupportedError( - illegals[0], - "This expression", - singular=True, - unsupported_in="a list comprehension", - ) - raise GuppyError(err) - - # Desugar into statements that create the iterator, check for a next element, - # get the next element, and finalise the iterator. - gens = [] - for g in generators: - if g.is_async: - raise GuppyError(UnsupportedError(g, "Async generators")) - g.iter = self.visit(g.iter) - it = make_var(next(tmp_vars), g.iter) - hasnext = make_var(next(tmp_vars), g.iter) - desugared = DesugaredGenerator( - iter=it, - hasnext=hasnext, - iter_assign=make_assign( - [it], with_loc(it, MakeIter(value=g.iter, origin_node=node)) - ), - hasnext_assign=make_assign( - [hasnext, it], with_loc(it, IterHasNext(value=it)) - ), - next_assign=make_assign( - [g.target, it], with_loc(it, IterNext(value=it)) - ), - iterend=with_loc(it, IterEnd(value=it)), - ifs=g.ifs, - ) - gens.append(desugared) - - elt = self.visit(elt) - return gens, elt - def visit_Call(self, node: ast.Call) -> ast.AST: return is_py_expression(node) or self.generic_visit(node) @@ -487,6 +444,56 @@ def generic_visit(self, node: ast.expr, bb: BB, true_bb: BB, false_bb: BB) -> No self.cfg.link(bb, true_bb) +def desugar_comprehension( + generators: list[ast.comprehension], elt: ast.expr, node: ast.AST +) -> tuple[list[DesugaredGenerator], ast.expr]: + """Helper function to desugar a comprehension node.""" + # Check for illegal expressions + illegals = find_nodes(is_illegal_in_list_comp, node) + if illegals: + err = UnsupportedError( + illegals[0], + "This expression", + singular=True, + unsupported_in="a list comprehension", + ) + raise GuppyError(err) + + # The check above ensures that the comprehension doesn't contain any control-flow + # expressions. Thus, we can use a dummy `ExprBuilder` to desugar the insides. + # TODO: Refactor so that desugaring is separate from control-flow building + dummy_cfg = CFG() + builder = ExprBuilder(dummy_cfg, dummy_cfg.entry_bb) + + # Desugar into statements that create the iterator, check for a next element, + # get the next element, and finalise the iterator. + gens = [] + for g in generators: + if g.is_async: + raise GuppyError(UnsupportedError(g, "Async generators")) + g.iter = builder.visit(g.iter) + it = make_var(next(tmp_vars), g.iter) + hasnext = make_var(next(tmp_vars), g.iter) + desugared = DesugaredGenerator( + iter=it, + hasnext=hasnext, + iter_assign=make_assign( + [it], with_loc(it, MakeIter(value=g.iter, origin_node=node)) + ), + hasnext_assign=make_assign( + [hasnext, it], with_loc(it, IterHasNext(value=it)) + ), + next_assign=make_assign([g.target, it], with_loc(it, IterNext(value=it))), + iterend=with_loc(it, IterEnd(value=it)), + ifs=g.ifs, + borrowed_outer_places=[], + ) + gens.append(desugared) + + elt = builder.visit(elt) + return gens, elt + + def is_functional_annotation(stmt: ast.stmt) -> bool: """Returns `True` iff the given statement is the functional pseudo-decorator. diff --git a/guppylang/checker/errors/type_errors.py b/guppylang/checker/errors/type_errors.py index 3aa5d406..df7d771b 100644 --- a/guppylang/checker/errors/type_errors.py +++ b/guppylang/checker/errors/type_errors.py @@ -190,6 +190,7 @@ class WrongNumberOfUnpacksError(Error): title: ClassVar[str] = "{prefix} values to unpack" expected: int actual: int + at_least: bool @property def prefix(self) -> str: @@ -200,9 +201,47 @@ def rendered_span_label(self) -> str: diff = self.expected - self.actual if diff < 0: msg = "Unexpected assignment " + ("targets" if diff < -1 else "target") + at_least = "at least " if self.at_least else "" else: msg = "Not enough assignment targets" - return f"{msg} (expected {self.expected}, got {self.actual})" + assert not self.at_least + at_least = "" + return f"{msg} (expected {self.expected}, got {at_least}{self.actual})" + + +@dataclass(frozen=True) +class UnpackableError(Error): + title: ClassVar[str] = "Unpackable" + span_label: ClassVar[str] = "Expression of type `{ty}` cannot be unpacked" + ty: Type + + @dataclass(frozen=True) + class NonStaticIter(Note): + message: ClassVar[str] = ( + "Unpacking of iterable types like `{ty}` is only allowed if the number of " + "items yielded by the iterator is statically known. This is not the case " + "for `{ty}`." + ) + + @dataclass(frozen=True) + class GenericSize(Note): + message: ClassVar[str] = ( + "Unpacking of iterable types like `{ty}` is only allowed if the number of " + "items yielded by the iterator is statically known. Here, the number of " + "items `{num}` is generic and can change between different function " + "invocations." + ) + num: Const + + +@dataclass(frozen=True) +class StarredTupleUnpackError(Error): + title: ClassVar[str] = "Invalid starred unpacking" + span_label: ClassVar[str] = ( + "Expression of type `{ty}` cannot be collected into a starred assignment since " + "the yielded items have different types" + ) + ty: Type @dataclass(frozen=True) diff --git a/guppylang/checker/expr_checker.py b/guppylang/checker/expr_checker.py index 3d23424a..d6753e30 100644 --- a/guppylang/checker/expr_checker.py +++ b/guppylang/checker/expr_checker.py @@ -1091,15 +1091,35 @@ def synthesize_comprehension( node: AstNode, gens: list[DesugaredGenerator], elt: ast.expr, ctx: Context ) -> tuple[list[DesugaredGenerator], ast.expr, Type]: """Helper function to synthesise the element type of a list comprehension.""" - from guppylang.checker.stmt_checker import StmtChecker - # If there are no more generators left, we can check the list element if not gens: elt, elt_ty = ExprSynthesizer(ctx).synthesize(elt) return gens, elt, elt_ty - # Check the iterator in the outer context + # Check the first generator gen, *gens = gens + gen, inner_ctx = check_generator(gen, ctx) + + # Check remaining generators in inner context + gens, elt, elt_ty = synthesize_comprehension(node, gens, elt, inner_ctx) + + # The iter finalizer is again checked in the outer context + gen.iterend, iterend_ty = ExprSynthesizer(ctx).synthesize(gen.iterend) + gen.iterend = with_type(iterend_ty, gen.iterend) + return [gen, *gens], elt, elt_ty + + +def check_generator( + gen: DesugaredGenerator, ctx: Context +) -> tuple[DesugaredGenerator, Context]: + """Helper function to check a single generator. + + Returns the type annotated generator together with a new nested context in which the + generator variables are bound. + """ + from guppylang.checker.stmt_checker import StmtChecker + + # Check the iterator in the outer context gen.iter_assign = StmtChecker(ctx).visit_Assign(gen.iter_assign) # The rest is checked in a new nested context to ensure that variables don't escape @@ -1119,13 +1139,7 @@ def synthesize_comprehension( gen.ifs[i], if_ty = expr_sth.synthesize(gen.ifs[i]) gen.ifs[i], _ = to_bool(gen.ifs[i], if_ty, inner_ctx) - # Check remaining generators - gens, elt, elt_ty = synthesize_comprehension(node, gens, elt, inner_ctx) - - # The iter finalizer is again checked in the outer context - gen.iterend, iterend_ty = ExprSynthesizer(ctx).synthesize(gen.iterend) - gen.iterend = with_type(iterend_ty, gen.iterend) - return [gen, *gens], elt, elt_ty + return gen, inner_ctx def eval_py_expr(node: PyExpr, ctx: Context) -> Any: diff --git a/guppylang/checker/stmt_checker.py b/guppylang/checker/stmt_checker.py index 177ba517..68269f80 100644 --- a/guppylang/checker/stmt_checker.py +++ b/guppylang/checker/stmt_checker.py @@ -9,10 +9,24 @@ """ import ast -from collections.abc import Sequence +import functools +from collections.abc import Iterable, Sequence +from dataclasses import replace +from itertools import takewhile +from typing import TypeVar, cast -from guppylang.ast_util import AstVisitor, with_loc, with_type +from guppylang.ast_util import ( + AstVisitor, + get_type, + with_loc, + with_type, +) from guppylang.cfg.bb import BB, BBStatement +from guppylang.cfg.builder import ( + desugar_comprehension, + make_var, + tmp_vars, +) from guppylang.checker.core import Context, FieldAccess, Variable from guppylang.checker.errors.generic import UnsupportedError from guppylang.checker.errors.type_errors import ( @@ -20,15 +34,44 @@ AssignNonPlaceHelp, AttributeNotFoundError, MissingReturnValueError, + StarredTupleUnpackError, + TypeInferenceError, + UnpackableError, WrongNumberOfUnpacksError, ) -from guppylang.checker.expr_checker import ExprChecker, ExprSynthesizer +from guppylang.checker.expr_checker import ( + ExprChecker, + ExprSynthesizer, + synthesize_comprehension, +) from guppylang.error import GuppyError, GuppyTypeError, InternalGuppyError -from guppylang.nodes import NestedFunctionDef, PlaceNode +from guppylang.nodes import ( + AnyUnpack, + DesugaredArrayComp, + IterableUnpack, + MakeIter, + NestedFunctionDef, + PlaceNode, + TupleUnpack, + UnpackPattern, +) from guppylang.span import Span, to_span +from guppylang.tys.builtin import ( + array_type, + get_iter_size, + is_sized_iter_type, + nat_type, +) +from guppylang.tys.const import ConstValue from guppylang.tys.parsing import type_from_ast from guppylang.tys.subst import Subst -from guppylang.tys.ty import NoneType, StructType, TupleType, Type +from guppylang.tys.ty import ( + ExistentialTypeVar, + NoneType, + StructType, + TupleType, + Type, +) class StmtChecker(AstVisitor[BBStatement]): @@ -55,81 +98,176 @@ def _check_expr( ) -> tuple[ast.expr, Subst]: return ExprChecker(self.ctx).check(node, ty, kind) - def _check_assign(self, lhs: ast.expr, ty: Type, node: ast.stmt) -> ast.expr: + @functools.singledispatchmethod + def _check_assign(self, lhs: ast.expr, rhs: ast.expr, rhs_ty: Type) -> ast.expr: """Helper function to check assignments with patterns.""" - match lhs: - # Easiest case is if the LHS pattern is a single variable. - case ast.Name(id=x): - var = Variable(x, ty, lhs) - self.ctx.locals[x] = var - return with_loc(lhs, with_type(ty, PlaceNode(place=var))) - - # The LHS could also be a field `expr.field` - case ast.Attribute(value=value, attr=attr): - # Unfortunately, the `attr` is just a string, not an AST node, so we - # have to compute its span by hand. This is fine since linebreaks are - # not allowed in the identifier following the `.` - span = to_span(lhs) - attr_span = Span(span.end.shift_left(len(attr)), span.end) - value, struct_ty = self._synth_expr(value) - if ( - not isinstance(struct_ty, StructType) - or attr not in struct_ty.field_dict - ): - raise GuppyTypeError( - AttributeNotFoundError(attr_span, struct_ty, attr) - ) - field = struct_ty.field_dict[attr] - # TODO: In the future, we could infer some type args here - if field.ty != ty: - # TODO: Get hold of a span for the RHS and use a regular - # `TypeMismatchError` instead (maybe with a custom hint). - raise GuppyTypeError( - AssignFieldTypeMismatchError(attr_span, ty, field) - ) - if not isinstance(value, PlaceNode): - # For now we complain if someone tries to assign to something that - # is not a place, e.g. `f().a = 4`. This would only make sense if - # there is another reference to the return value of `f`, otherwise - # the mutation cannot be observed. We can start supporting this once - # we have proper reference semantics. - err = UnsupportedError( - value, "Assigning to this expression", singular=True - ) - err.add_sub_diagnostic(AssignNonPlaceHelp(None, field)) - raise GuppyError(err) - if not field.ty.linear: - raise GuppyError( - UnsupportedError( - attr_span, "Mutation of classical fields", singular=True - ) - ) - place = FieldAccess(value.place, struct_ty.field_dict[attr], lhs) - return with_loc(lhs, with_type(ty, PlaceNode(place=place))) - - # The only other thing we support right now are tuples - case ast.Tuple(elts=elts) as lhs: - tys = ty.element_types if isinstance(ty, TupleType) else [ty] - n, m = len(elts), len(tys) - if n != m: - if n > m: - span = Span(to_span(elts[m]).start, to_span(elts[-1]).end) - else: - span = to_span(lhs) - raise GuppyTypeError(WrongNumberOfUnpacksError(span, m, n)) - lhs.elts = [ - self._check_assign(pat, el_ty, node) - for pat, el_ty in zip(elts, tys, strict=True) - ] - return with_type(ty, lhs) - - # TODO: Python also supports assignments like `[a, b] = [1, 2]` or - # `a, *b = ...`. The former would require some runtime checks but - # the latter should be easier to do (unpack and repack the rest). - case _: - raise GuppyError( - UnsupportedError(lhs, "This assignment pattern", singular=True) + raise InternalGuppyError("Unexpected assignment pattern") + + @_check_assign.register + def _check_variable_assign( + self, lhs: ast.Name, _rhs: ast.expr, rhs_ty: Type + ) -> PlaceNode: + x = lhs.id + var = Variable(x, rhs_ty, lhs) + self.ctx.locals[x] = var + return with_loc(lhs, with_type(rhs_ty, PlaceNode(place=var))) + + @_check_assign.register + def _check_field_assign( + self, lhs: ast.Attribute, _rhs: ast.expr, rhs_ty: Type + ) -> PlaceNode: + # Unfortunately, the `attr` is just a string, not an AST node, so we + # have to compute its span by hand. This is fine since linebreaks are + # not allowed in the identifier following the `.` + span = to_span(lhs) + value, attr = lhs.value, lhs.attr + attr_span = Span(span.end.shift_left(len(attr)), span.end) + value, struct_ty = self._synth_expr(value) + if not isinstance(struct_ty, StructType) or attr not in struct_ty.field_dict: + raise GuppyTypeError(AttributeNotFoundError(attr_span, struct_ty, attr)) + field = struct_ty.field_dict[attr] + # TODO: In the future, we could infer some type args here + if field.ty != rhs_ty: + # TODO: Get hold of a span for the RHS and use a regular `TypeMismatchError` + # instead (maybe with a custom hint). + raise GuppyTypeError(AssignFieldTypeMismatchError(attr_span, rhs_ty, field)) + if not isinstance(value, PlaceNode): + # For now we complain if someone tries to assign to something that is not a + # place, e.g. `f().a = 4`. This would only make sense if there is another + # reference to the return value of `f`, otherwise the mutation cannot be + # observed. We can start supporting this once we have proper reference + # semantics. + err = UnsupportedError(value, "Assigning to this expression", singular=True) + err.add_sub_diagnostic(AssignNonPlaceHelp(None, field)) + raise GuppyError(err) + if not field.ty.linear: + raise GuppyError( + UnsupportedError( + attr_span, "Mutation of classical fields", singular=True ) + ) + place = FieldAccess(value.place, struct_ty.field_dict[attr], lhs) + return with_loc(lhs, with_type(rhs_ty, PlaceNode(place=place))) + + @_check_assign.register + def _check_tuple_assign( + self, lhs: ast.Tuple, rhs: ast.expr, rhs_ty: Type + ) -> AnyUnpack: + return self._check_unpack_assign(lhs, rhs, rhs_ty) + + @_check_assign.register + def _check_list_assign( + self, lhs: ast.List, rhs: ast.expr, rhs_ty: Type + ) -> AnyUnpack: + return self._check_unpack_assign(lhs, rhs, rhs_ty) + + def _check_unpack_assign( + self, lhs: ast.Tuple | ast.List, rhs: ast.expr, rhs_ty: Type + ) -> AnyUnpack: + """Helper function to check unpacking assignments. + + These are the ones where the LHS is either a tuple or a list. + """ + # Parse LHS into `left, *starred, right` + pattern = parse_unpack_pattern(lhs) + left, starred, right = pattern.left, pattern.starred, pattern.right + # Check that the RHS has an appropriate type to be unpacked + unpack, rhs_elts, rhs_tys = self._check_unpackable(rhs, rhs_ty, pattern) + + # Check that the numbers match up on the LHS and RHS + num_lhs, num_rhs = len(right) + len(left), len(rhs_tys) + err = WrongNumberOfUnpacksError( + lhs, num_rhs, num_lhs, at_least=starred is not None + ) + if num_lhs > num_rhs: + # Build span that covers the unexpected elts on the LHS + span = Span(to_span(lhs.elts[num_rhs]).start, to_span(lhs.elts[-1]).end) + raise GuppyTypeError(replace(err, span=span)) + elif num_lhs < num_rhs and not starred: + raise GuppyTypeError(err) + + # Recursively check any nested patterns on the left or right + le, rs = len(left), len(rhs_elts) - len(right) # left_end, right_start + unpack.pattern.left = [ + self._check_assign(pat, elt, ty) + for pat, elt, ty in zip(left, rhs_elts[:le], rhs_tys[:le], strict=True) + ] + unpack.pattern.right = [ + self._check_assign(pat, elt, ty) + for pat, elt, ty in zip(right, rhs_elts[rs:], rhs_tys[rs:], strict=True) + ] + + # Starred assignments are collected into an array + if starred: + starred_tys = rhs_tys[le:rs] + assert all_equal(starred_tys) + if starred_tys: + starred_ty, *_ = starred_tys + # Starred part could be empty. If it's an iterable unpack, we're still fine + # since we know the yielded type + elif isinstance(unpack, IterableUnpack): + starred_ty = unpack.compr.elt_ty + # For tuple unpacks, there is no way to infer a type for the empty starred + # part + else: + unsolved = array_type(ExistentialTypeVar.fresh("T", False), 0) + raise GuppyError(TypeInferenceError(starred, unsolved)) + array_ty = array_type(starred_ty, len(starred_tys)) + unpack.pattern.starred = self._check_assign(starred, rhs_elts[0], array_ty) + + return with_type(rhs_ty, with_loc(lhs, unpack)) + + def _check_unpackable( + self, expr: ast.expr, ty: Type, pattern: UnpackPattern + ) -> tuple[AnyUnpack, list[ast.expr], Sequence[Type]]: + """Checks that the given expression can be used in an unpacking assignment. + + This is the case for expressions with tuple types or ones that are iterable with + a static size. Also checks that the expression is compatible with the given + unpacking pattern. + + Returns an AST node capturing the unpacking operation together with expressions + and types for all unpacked items. Emits a user error if the given expression is + not unpackable. + """ + left, starred, right = pattern.left, pattern.starred, pattern.right + if isinstance(ty, TupleType): + # Starred assignment of tuples is only allowed if all starred elements have + # the same type + if starred: + starred_tys = ( + ty.element_types[len(left) : -len(right)] + if right + else ty.element_types[len(left) :] + ) + if not all_equal(starred_tys): + tuple_ty = TupleType(starred_tys) + raise GuppyError(StarredTupleUnpackError(starred, tuple_ty)) + tys = ty.element_types + elts = expr.elts if isinstance(expr, ast.Tuple) else [expr] * len(tys) + return TupleUnpack(pattern), elts, tys + + elif self.ctx.globals.get_instance_func(ty, "__iter__"): + size = check_iter_unpack_has_static_size(expr, self.ctx) + # Create a dummy variable and assign the expression to it. This helps us to + # wire it up correctly during Hugr generation. + var = self._check_assign(make_var(next(tmp_vars), expr), expr, ty) + assert isinstance(var, PlaceNode) + # We collect the whole RHS into an array. For this, we can reuse the + # existing array comprehension logic. + elt = make_var(next(tmp_vars), expr) + gen = ast.comprehension(target=elt, iter=var, ifs=[], is_async=False) + [gen], elt = desugar_comprehension([with_loc(expr, gen)], elt, expr) + # Type check the comprehension + [gen], elt, elt_ty = synthesize_comprehension(expr, [gen], elt, self.ctx) + compr = DesugaredArrayComp( + elt, gen, length=ConstValue(nat_type(), size), elt_ty=elt_ty + ) + compr = with_type(array_type(elt_ty, size), compr) + return IterableUnpack(pattern, compr, var), size * [elt], size * [elt_ty] + + # Otherwise, we can't unpack this expression + raise GuppyError(UnpackableError(expr, ty)) def visit_Assign(self, node: ast.Assign) -> ast.Assign: if len(node.targets) > 1: @@ -138,7 +276,7 @@ def visit_Assign(self, node: ast.Assign) -> ast.Assign: [target] = node.targets node.value, ty = self._synth_expr(node.value) - node.targets = [self._check_assign(target, ty, node)] + node.targets = [self._check_assign(target, node.value, ty)] return node def visit_AnnAssign(self, node: ast.AnnAssign) -> ast.stmt: @@ -148,7 +286,7 @@ def visit_AnnAssign(self, node: ast.AnnAssign) -> ast.stmt: node.value, subst = self._check_expr(node.value, ty) assert not ty.unsolved_vars # `ty` must be closed! assert len(subst) == 0 - target = self._check_assign(node.target, ty, node) + target = self._check_assign(node.target, node.value, ty) return with_loc(node, ast.Assign(targets=[target], value=node.value)) def visit_AugAssign(self, node: ast.AugAssign) -> ast.stmt: @@ -197,3 +335,56 @@ def visit_Break(self, node: ast.Break) -> None: def visit_Continue(self, node: ast.Continue) -> None: raise InternalGuppyError("Control-flow statement should not be present here.") + + +T = TypeVar("T") + + +def all_equal(xs: Iterable[T]) -> bool: + """Checks if all elements yielded from an iterable are equal.""" + it = iter(xs) + try: + first = next(it) + except StopIteration: + return True + return all(first == x for x in it) + + +def parse_unpack_pattern(lhs: ast.Tuple | ast.List) -> UnpackPattern: + """Parses the LHS of an unpacking assignment like `a, *bs, c = ...` or + `[a, *bs, c] = ...`.""" + # Split up LHS into `left, *starred, right` (the Python grammar ensures + # that there is at most one starred expression) + left = list(takewhile(lambda e: not isinstance(e, ast.Starred), lhs.elts)) + starred = ( + cast(ast.Starred, lhs.elts[len(left)]).value + if len(left) < len(lhs.elts) + else None + ) + right = lhs.elts[len(left) + 1 :] + assert isinstance(starred, ast.Name | None), "Python grammar" + return UnpackPattern(left, starred, right) + + +def check_iter_unpack_has_static_size(expr: ast.expr, ctx: Context) -> int: + """Helper function to check that an iterable expression is suitable to be unpacked + in an assignment. + + This is the case if the iterator has a static, non-generic size. + + Returns the size of the iterator or emits a user error if the iterable is not + suitable. + """ + expr_synth = ExprSynthesizer(ctx) + make_iter = with_loc(expr, MakeIter(expr, expr, unwrap_size_hint=False)) + make_iter, iter_ty = expr_synth.visit_MakeIter(make_iter) + err = UnpackableError(expr, get_type(expr)) + if not is_sized_iter_type(iter_ty): + err.add_sub_diagnostic(UnpackableError.NonStaticIter(None)) + raise GuppyError(err) + match get_iter_size(iter_ty): + case ConstValue(value=int(size)): + return size + case generic_size: + err.add_sub_diagnostic(UnpackableError.GenericSize(None, generic_size)) + raise GuppyError(err) diff --git a/guppylang/compiler/stmt_compiler.py b/guppylang/compiler/stmt_compiler.py index addcb8cb..6f92854e 100644 --- a/guppylang/compiler/stmt_compiler.py +++ b/guppylang/compiler/stmt_compiler.py @@ -1,6 +1,8 @@ import ast +import functools from collections.abc import Sequence +import hugr.tys as ht from hugr import Wire, ops from hugr.build.dfg import DfBase @@ -14,8 +16,21 @@ ) from guppylang.compiler.expr_compiler import ExprCompiler from guppylang.error import InternalGuppyError -from guppylang.nodes import CheckedNestedFunctionDef, PlaceNode -from guppylang.tys.ty import TupleType, Type +from guppylang.nodes import ( + CheckedNestedFunctionDef, + IterableUnpack, + PlaceNode, + TupleUnpack, +) +from guppylang.std._internal.compiler.array import ( + array_discard_empty, + array_new, + array_pop, +) +from guppylang.std._internal.compiler.prelude import build_unwrap +from guppylang.tys.builtin import get_element_type +from guppylang.tys.const import ConstValue +from guppylang.tys.ty import TupleType, Type, type_to_row class StmtCompiler(CompilerBase, AstVisitor[None]): @@ -49,27 +64,86 @@ def builder(self) -> DfBase[ops.DfParentOp]: """The Hugr dataflow graph builder.""" return self.dfg.builder - def _unpack_assign(self, lhs: ast.expr, port: Wire, node: ast.stmt) -> None: + @functools.singledispatchmethod + def _assign(self, lhs: ast.expr, port: Wire) -> None: """Updates the local DFG with assignments.""" - if isinstance(lhs, PlaceNode): - self.dfg[lhs.place] = port - elif isinstance(lhs, ast.Tuple): - types = [get_type(e).to_hugr() for e in lhs.elts] - unpack = self.builder.add_op(ops.UnpackTuple(types), port) - for pat, wire in zip(lhs.elts, unpack, strict=True): - self._unpack_assign(pat, wire, node) + raise InternalGuppyError("Invalid assign pattern in compiler") + + @_assign.register + def _assign_place(self, lhs: PlaceNode, port: Wire) -> None: + self.dfg[lhs.place] = port + + @_assign.register + def _assign_tuple(self, lhs: TupleUnpack, port: Wire) -> None: + """Handles assignment where the RHS is a tuple that should be unpacked.""" + # Unpack the RHS tuple + left, starred, right = lhs.pattern.left, lhs.pattern.starred, lhs.pattern.right + types = [ty.to_hugr() for ty in type_to_row(get_type(lhs))] + unpack = self.builder.add_op(ops.UnpackTuple(types), port) + ports = list(unpack) + + # Assign left and right + for pat, wire in zip(left, ports[: len(left)], strict=True): + self._assign(pat, wire) + if right: + for pat, wire in zip(right, ports[-len(right) :], strict=True): + self._assign(pat, wire) + + # Starred assignments are collected into an array + if starred: + array_ty = get_type(starred) + starred_ports = ( + ports[len(left) : -len(right)] if right else ports[len(left) :] + ) + opt_ty = ht.Option(get_element_type(array_ty).to_hugr()) + opts = [self.builder.add_op(ops.Tag(1, opt_ty), p) for p in starred_ports] + array = self.builder.add_op(array_new(opt_ty, len(opts)), *opts) + self._assign(starred, array) + + @_assign.register + def _assign_iterable(self, lhs: IterableUnpack, port: Wire) -> None: + """Handles assignment where the RHS is an iterable that should be unpacked.""" + # Given an assignment pattern `left, *starred, right`, collect the RHS into an + # array and pop from the left and right, leaving us with the starred array in + # the middle + assert isinstance(lhs.compr.length, ConstValue) + length = lhs.compr.length.value + assert isinstance(length, int) + opt_elt_ty = ht.Option(lhs.compr.elt_ty.to_hugr()) + + def pop( + array: Wire, length: int, pats: list[ast.expr], from_left: bool + ) -> tuple[Wire, int]: + err = "Internal error: unpacking of iterable failed" + for pat in pats: + res = self.builder.add_op( + array_pop(opt_elt_ty, length, from_left), array + ) + [elt_opt, array] = build_unwrap(self.builder, res, err) + [elt] = build_unwrap(self.builder, elt_opt, err) + self._assign(pat, elt) + length -= 1 + return array, length + + self.dfg[lhs.rhs_var.place] = port + array = self.expr_compiler.visit_DesugaredArrayComp(lhs.compr) + array, length = pop(array, length, lhs.pattern.left, True) + array, length = pop(array, length, lhs.pattern.right, False) + if lhs.pattern.starred: + self._assign(lhs.pattern.starred, array) else: - raise InternalGuppyError("Invalid assign pattern in compiler") + assert length == 0 + self.builder.add_op(array_discard_empty(opt_elt_ty), array) def visit_Assign(self, node: ast.Assign) -> None: [target] = node.targets port = self.expr_compiler.compile(node.value, self.dfg) - self._unpack_assign(target, port, node) + self._assign(target, port) def visit_AnnAssign(self, node: ast.AnnAssign) -> None: assert node.value is not None port = self.expr_compiler.compile(node.value, self.dfg) - self._unpack_assign(node.target, port, node) + self._assign(node.target, port) def visit_AugAssign(self, node: ast.AugAssign) -> None: raise InternalGuppyError("Node should have been removed during type checking.") diff --git a/guppylang/nodes.py b/guppylang/nodes.py index 2eca1ea4..89d03787 100644 --- a/guppylang/nodes.py +++ b/guppylang/nodes.py @@ -290,6 +290,60 @@ class InoutReturnSentinel(ast.expr): _fields = ("var",) +class UnpackPattern(ast.expr): + """The LHS of an unpacking assignment like `a, *bs, c = ...` or + `[a, *bs, c] = ...`.""" + + #: Patterns occurring on the left of the starred target + left: list[ast.expr] + + #: The starred target or `None` if there is none + starred: ast.expr | None + + #: Patterns occurring on the right of the starred target. This will be an empty list + #: if there is no starred target + right: list[ast.expr] + + _fields = ("left", "starred", "right") + + +class TupleUnpack(ast.expr): + """The LHS of an unpacking assignment of a tuple.""" + + #: The (possibly starred) unpacking pattern + pattern: UnpackPattern + + _fields = ("pattern",) + + +class IterableUnpack(ast.expr): + """The LHS of an unpacking assignment of an iterable type.""" + + #: The (possibly starred) unpacking pattern + pattern: UnpackPattern + + #: Comprehension that collects the RHS iterable into an array + compr: DesugaredArrayComp + + #: Dummy variable that the RHS should be bound to. This variable is referenced in + #: `compr` + rhs_var: PlaceNode + + # Don't mention the comprehension in _fields to avoid visitors recursing it + _fields = ("pattern",) + + def __init__( + self, pattern: UnpackPattern, compr: DesugaredArrayComp, rhs_var: PlaceNode + ) -> None: + super().__init__(pattern) + self.compr = compr + self.rhs_var = rhs_var + + +#: Any unpacking operation. +AnyUnpack = TupleUnpack | IterableUnpack + + class NestedFunctionDef(ast.FunctionDef): cfg: "CFG" ty: FunctionType diff --git a/guppylang/std/_internal/compiler/array.py b/guppylang/std/_internal/compiler/array.py index 66e602cd..e4432360 100644 --- a/guppylang/std/_internal/compiler/array.py +++ b/guppylang/std/_internal/compiler/array.py @@ -72,6 +72,26 @@ def array_set(elem_ty: ht.Type, length: ht.TypeArg) -> ops.ExtOp: ) +def array_pop(elem_ty: ht.Type, length: int, from_left: bool) -> ops.ExtOp: + """Returns an operation that pops an element from the left of an array.""" + assert length > 0 + length_arg = ht.BoundedNatArg(length) + arr_ty = array_type(elem_ty, length_arg) + popped_arr_ty = array_type(elem_ty, ht.BoundedNatArg(length - 1)) + op = "pop_left" if from_left else "pop_right" + return _instantiate_array_op( + op, elem_ty, length_arg, [arr_ty], [ht.Option(elem_ty, popped_arr_ty)] + ) + + +def array_discard_empty(elem_ty: ht.Type) -> ops.ExtOp: + """Returns an operation that discards an array of length zero.""" + arr_ty = array_type(elem_ty, ht.BoundedNatArg(0)) + return EXTENSION.get_op("discard_empty").instantiate( + [ht.TypeTypeArg(elem_ty)], ht.FunctionType([arr_ty], []) + ) + + def array_map(elem_ty: ht.Type, length: ht.TypeArg, new_elem_ty: ht.Type) -> ops.ExtOp: """Returns an operation that maps a function across an array.""" # TODO diff --git a/guppylang/tys/const.py b/guppylang/tys/const.py index d942f417..245f0161 100644 --- a/guppylang/tys/const.py +++ b/guppylang/tys/const.py @@ -39,6 +39,11 @@ def unsolved_vars(self) -> set[ExistentialVar]: """The existential type variables contained in this constant.""" return set() + def __str__(self) -> str: + from guppylang.tys.printing import TypePrinter + + return TypePrinter().visit(self.cast()) + def visit(self, visitor: Visitor) -> None: """Accepts a visitor on this constant.""" visitor.visit(self) diff --git a/guppylang/tys/printing.py b/guppylang/tys/printing.py index 633039fd..5ae0b3f9 100644 --- a/guppylang/tys/printing.py +++ b/guppylang/tys/printing.py @@ -2,7 +2,7 @@ from guppylang.error import InternalGuppyError from guppylang.tys.arg import ConstArg, TypeArg -from guppylang.tys.const import ConstValue +from guppylang.tys.const import Const, ConstValue from guppylang.tys.param import ConstParam, TypeParam from guppylang.tys.ty import ( FunctionType, @@ -53,7 +53,7 @@ def _fresh_name(self, display_name: str) -> str: self.counter[display_name] += 1 return indexed - def visit(self, ty: Type) -> str: + def visit(self, ty: Type | Const) -> str: return self._visit(ty, False) @singledispatchmethod diff --git a/tests/error/type_errors/not_unpackable.err b/tests/error/type_errors/not_unpackable.err new file mode 100644 index 00000000..8f4cb981 --- /dev/null +++ b/tests/error/type_errors/not_unpackable.err @@ -0,0 +1,8 @@ +Error: Unpackable (at $FILE:6:9) + | +4 | @compile_guppy +5 | def foo() -> int: +6 | a, = 1 + | ^ Expression of type `int` cannot be unpacked + +Guppy compilation failed due to 1 previous error diff --git a/tests/error/type_errors/not_unpackable.py b/tests/error/type_errors/not_unpackable.py new file mode 100644 index 00000000..d66ab9cd --- /dev/null +++ b/tests/error/type_errors/not_unpackable.py @@ -0,0 +1,7 @@ +from tests.util import compile_guppy + + +@compile_guppy +def foo() -> int: + a, = 1 + return a diff --git a/tests/error/type_errors/unpack_generic_size.err b/tests/error/type_errors/unpack_generic_size.err new file mode 100644 index 00000000..37925025 --- /dev/null +++ b/tests/error/type_errors/unpack_generic_size.err @@ -0,0 +1,12 @@ +Error: Unpackable (at $FILE:11:13) + | + 9 | @guppy(module) +10 | def foo(xs: array[int, n]) -> int: +11 | a, *bs = xs + | ^^ Expression of type `array[int, n]` cannot be unpacked + +Note: Unpacking of iterable types like `array[int, n]` is only allowed if the +number of items yielded by the iterator is statically known. Here, the number of +items `n` is generic and can change between different function invocations. + +Guppy compilation failed due to 1 previous error diff --git a/tests/error/type_errors/unpack_generic_size.py b/tests/error/type_errors/unpack_generic_size.py new file mode 100644 index 00000000..eb7d8013 --- /dev/null +++ b/tests/error/type_errors/unpack_generic_size.py @@ -0,0 +1,15 @@ +from guppylang import GuppyModule, guppy +from guppylang.std.builtins import array + + +module = GuppyModule('main') +n = guppy.nat_var("n", module=module) + + +@guppy(module) +def foo(xs: array[int, n]) -> int: + a, *bs = xs + return a + + +module.compile() diff --git a/tests/error/type_errors/unpack_non_static.err b/tests/error/type_errors/unpack_non_static.err new file mode 100644 index 00000000..a4624983 --- /dev/null +++ b/tests/error/type_errors/unpack_non_static.err @@ -0,0 +1,12 @@ +Error: Unpackable (at $FILE:6:13) + | +4 | @compile_guppy +5 | def foo(xs: list[int]) -> int: +6 | a, *bs = xs + | ^^ Expression of type `list[int]` cannot be unpacked + +Note: Unpacking of iterable types like `list[int]` is only allowed if the number +of items yielded by the iterator is statically known. This is not the case for +`list[int]`. + +Guppy compilation failed due to 1 previous error diff --git a/tests/error/type_errors/unpack_non_static.py b/tests/error/type_errors/unpack_non_static.py new file mode 100644 index 00000000..2bc46f42 --- /dev/null +++ b/tests/error/type_errors/unpack_non_static.py @@ -0,0 +1,7 @@ +from tests.util import compile_guppy + + +@compile_guppy +def foo(xs: list[int]) -> int: + a, *bs = xs + return a diff --git a/tests/error/type_errors/unpack_tuple_starred.err b/tests/error/type_errors/unpack_tuple_starred.err new file mode 100644 index 00000000..7c3776b8 --- /dev/null +++ b/tests/error/type_errors/unpack_tuple_starred.err @@ -0,0 +1,10 @@ +Error: Invalid starred unpacking (at $FILE:6:8) + | +4 | @compile_guppy +5 | def foo() -> int: +6 | a, *bs = 1, 2, True + | ^^ Expression of type `(int, bool)` cannot be collected into a + | starred assignment since the yielded items have + | different types + +Guppy compilation failed due to 1 previous error diff --git a/tests/error/type_errors/unpack_tuple_starred.py b/tests/error/type_errors/unpack_tuple_starred.py new file mode 100644 index 00000000..5c5c845b --- /dev/null +++ b/tests/error/type_errors/unpack_tuple_starred.py @@ -0,0 +1,7 @@ +from tests.util import compile_guppy + + +@compile_guppy +def foo() -> int: + a, *bs = 1, 2, True + return a diff --git a/tests/integration/test_unpack.py b/tests/integration/test_unpack.py new file mode 100644 index 00000000..f399f22d --- /dev/null +++ b/tests/integration/test_unpack.py @@ -0,0 +1,104 @@ +from guppylang.decorator import guppy +from guppylang.module import GuppyModule +from guppylang.std.builtins import array, owned + +from guppylang.std.quantum import qubit + + +def test_unpack_array(validate): + module = GuppyModule("test") + module.load(qubit) + + @guppy(module) + def main(qs: array[qubit, 3] @ owned) -> tuple[qubit, qubit, qubit]: + q1, q2, q3 = qs + return q1, q2, q3 + + validate(module.compile()) + + +def test_unpack_starred(validate): + module = GuppyModule("test") + module.load(qubit) + + @guppy(module) + def main( + qs: array[qubit, 10] @ owned, + ) -> tuple[qubit, qubit, qubit, qubit, qubit, qubit, array[qubit, 4]]: + q1, q2, *qs, q3 = qs + [q4, *qs] = qs + *qs, q5, q6 = qs + [*qs] = qs + return q1, q2, q3, q4, q5, q6, qs + + validate(module.compile()) + + +def test_unpack_starred_empty(validate): + module = GuppyModule("test") + module.load(qubit) + + @guppy(module) + def main(qs: array[qubit, 2] @ owned) -> tuple[qubit, array[qubit, 0], qubit]: + q1, *empty, q2 = qs + return q1, empty, q2 + + validate(module.compile()) + + +def test_unpack_big_iterable(validate): + # Test that the compile-time doesn't scale with the size of the unpacked iterable + module = GuppyModule("test") + module.load(qubit) + + @guppy(module) + def main(qs: array[qubit, 1000] @ owned) -> tuple[qubit, array[qubit, 998], qubit]: + q1, *qs, q2 = qs + return q1, qs, q2 + + validate(module.compile()) + + +def test_unpack_range(validate, run_int_fn): + module = GuppyModule("test") + + @guppy(module) + def main() -> int: + [_, x, *_, y, _] = range(10) + return x + y + + compiled = module.compile() + validate(compiled) + # TODO: Enable execution test once array lowering is fully supported + # run_int_fn(compiled, expected=9) + + +def test_unpack_tuple_starred(validate, run_int_fn): + module = GuppyModule("test") + + @guppy(module) + def main() -> array[int, 2]: + x, *ys, z = 1, 2, 3, 4 + return ys + + validate(module.compile()) + + +def test_unpack_nested(validate, run_int_fn): + module = GuppyModule("test") + + @guppy(module) + def main( + xs: array[array[array[int, 5], 10], 20], + ) -> tuple[ + array[int, 5], # x + int, # y + array[int, 3], # z + array[array[int, 5], 8], # a + array[array[array[int, 5], 10], 18], # b + array[array[int, 5], 10], # c + ]: + (x, [y, *z, _], *a), *b, c = xs + return x, y, z, a, b, c + + validate(module.compile()) From 58980601261d47313303a979150105e2ab68cbe0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 18 Dec 2024 14:43:56 +0000 Subject: [PATCH 07/10] ci(deps): bump mozilla-actions/sccache-action from 0.0.6 to 0.0.7 (#718) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [mozilla-actions/sccache-action](https://github.com/mozilla-actions/sccache-action) from 0.0.6 to 0.0.7.
Release notes

Sourced from mozilla-actions/sccache-action's releases.

v0.0.7

What's Changed

Dependencies

New Contributors

Full Changelog: https://github.com/Mozilla-Actions/sccache-action/compare/v0.0.6...v0.0.7

Commits
  • 054db53 Merge pull request #172 from sylvestre/0.0.7
  • 0f3ae50 Rebuild dist files and update README for releases.
  • 3d14465 recompile the js files: npm run build
  • 42761b0 prepare release 0.0.7
  • e21e59b Merge pull request #170 from Mozilla-Actions/dependabot/npm_and_yarn/typescri...
  • 2e63a0d Merge pull request #169 from Mozilla-Actions/dependabot/npm_and_yarn/actions/...
  • 4cdf591 Merge pull request #167 from Mozilla-Actions/dependabot/npm_and_yarn/vercel/n...
  • 39c9c60 Bump typescript from 5.6.2 to 5.7.2
  • 1786957 Bump @​actions/core from 1.10.1 to 1.11.1
  • 843e562 Bump @​vercel/ncc from 0.38.1 to 0.38.3
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=mozilla-actions/sccache-action&package-manager=github_actions&previous-version=0.0.6&new-version=0.0.7)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/docs.yml | 2 +- .github/workflows/pull-request.yaml | 4 ++-- .github/workflows/python-wheels.yml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 9a95bbc2..e4665645 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -28,7 +28,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Run sccache-cache - uses: mozilla-actions/sccache-action@v0.0.6 + uses: mozilla-actions/sccache-action@v0.0.7 - name: Set up uv uses: astral-sh/setup-uv@v3 diff --git a/.github/workflows/pull-request.yaml b/.github/workflows/pull-request.yaml index 27dfe962..897f4aa9 100644 --- a/.github/workflows/pull-request.yaml +++ b/.github/workflows/pull-request.yaml @@ -27,7 +27,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Run sccache-cache - uses: mozilla-actions/sccache-action@v0.0.6 + uses: mozilla-actions/sccache-action@v0.0.7 - name: Install rust toolchain uses: dtolnay/rust-toolchain@stable - name: install-llvm @@ -76,7 +76,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Run sccache-cache - uses: mozilla-actions/sccache-action@v0.0.6 + uses: mozilla-actions/sccache-action@v0.0.7 - name: Install rust toolchain uses: dtolnay/rust-toolchain@stable diff --git a/.github/workflows/python-wheels.yml b/.github/workflows/python-wheels.yml index 649eec60..b8d134e9 100644 --- a/.github/workflows/python-wheels.yml +++ b/.github/workflows/python-wheels.yml @@ -30,7 +30,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Run sccache-cache - uses: mozilla-actions/sccache-action@v0.0.6 + uses: mozilla-actions/sccache-action@v0.0.7 - name: Set up uv run: curl -LsSf https://astral.sh/uv/0.3.4/install.sh | sh From d0c2da40cdf1fe4e770123d4174bf710dd44e1a6 Mon Sep 17 00:00:00 2001 From: Mark Koch <48097969+mark-koch@users.noreply.github.com> Date: Wed, 18 Dec 2024 16:09:52 +0000 Subject: [PATCH 08/10] fix: Properly report error for unsupported constants (#724) Fixes #721 --- guppylang/checker/errors/type_errors.py | 2 +- tests/error/misc_errors/unsupported_const.err | 8 ++++++++ tests/error/misc_errors/unsupported_const.py | 7 +++++++ 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 tests/error/misc_errors/unsupported_const.err create mode 100644 tests/error/misc_errors/unsupported_const.py diff --git a/guppylang/checker/errors/type_errors.py b/guppylang/checker/errors/type_errors.py index df7d771b..dddd94c7 100644 --- a/guppylang/checker/errors/type_errors.py +++ b/guppylang/checker/errors/type_errors.py @@ -74,7 +74,7 @@ class TypeInferenceError(Error): @dataclass(frozen=True) class IllegalConstant(Error): title: ClassVar[str] = "Unsupported constant" - span_label: ClassVar[str] = "Type `{ty}` is not supported" + span_label: ClassVar[str] = "Type `{python_ty.__name__}` is not supported" python_ty: type diff --git a/tests/error/misc_errors/unsupported_const.err b/tests/error/misc_errors/unsupported_const.err new file mode 100644 index 00000000..baf3536d --- /dev/null +++ b/tests/error/misc_errors/unsupported_const.err @@ -0,0 +1,8 @@ +Error: Unsupported constant (at $FILE:7:8) + | +5 | @compile_guppy +6 | def foo() -> None: +7 | x = "foo" + | ^^^^^ Type `str` is not supported + +Guppy compilation failed due to 1 previous error diff --git a/tests/error/misc_errors/unsupported_const.py b/tests/error/misc_errors/unsupported_const.py new file mode 100644 index 00000000..1959d05b --- /dev/null +++ b/tests/error/misc_errors/unsupported_const.py @@ -0,0 +1,7 @@ +from guppylang.std.builtins import array +from tests.util import compile_guppy + + +@compile_guppy +def foo() -> None: + x = "foo" From 0f6ceaa58648f105e601298081170eaec5a0e026 Mon Sep 17 00:00:00 2001 From: Mark Koch <48097969+mark-koch@users.noreply.github.com> Date: Wed, 18 Dec 2024 16:11:57 +0000 Subject: [PATCH 09/10] fix: Fix array execution bugs (#731) Bumps to Hugr on main and fixes some bugs to make arrays executable. --- Cargo.lock | 18 ++--- Cargo.toml | 6 +- execute_llvm/src/lib.rs | 12 +++- guppylang/compiler/expr_compiler.py | 57 ++++++++-------- guppylang/compiler/stmt_compiler.py | 19 ++++-- guppylang/std/_internal/compiler/array.py | 43 ++++++++---- guppylang/std/builtins.py | 4 +- guppylang/tys/builtin.py | 3 +- pyproject.toml | 2 +- tests/integration/test_array.py | 3 +- tests/integration/test_array_comprehension.py | 68 +++++++++++++++---- tests/integration/test_unpack.py | 22 +++++- uv.lock | 8 +-- 13 files changed, 175 insertions(+), 90 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ddb2de16..0cad9946 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -525,8 +525,7 @@ dependencies = [ [[package]] name = "hugr" version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f209c7cd671de29be8bdf0725e09b2e9d386387f439b13975e158f095e5a0fe" +source = "git+https://github.com/CQCL/hugr?rev=ab94518#ab94518ed2812abca615bfbfb5a822f67c115be8" dependencies = [ "hugr-core", "hugr-llvm", @@ -536,24 +535,20 @@ dependencies = [ [[package]] name = "hugr-cli" version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab6a94a980d47788908d7f93165846164f8b623b7f382cd3813bd0c0d1188e65" +source = "git+https://github.com/CQCL/hugr?rev=ab94518#ab94518ed2812abca615bfbfb5a822f67c115be8" dependencies = [ "clap", "clap-verbosity-flag", "clio", "derive_more", "hugr", - "serde", "serde_json", - "thiserror 2.0.7", ] [[package]] name = "hugr-core" version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60c3d5422f76dbec1d6948e68544b134562ec9ec087e8e6a599555b716f555dc" +source = "git+https://github.com/CQCL/hugr?rev=ab94518#ab94518ed2812abca615bfbfb5a822f67c115be8" dependencies = [ "bitvec", "bumpalo", @@ -585,12 +580,10 @@ dependencies = [ [[package]] name = "hugr-llvm" version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce4117f4f934b1033b82d8cb672b3c33c3a7f8f541c50f7cc7ff53cebb5816d1" +source = "git+https://github.com/CQCL/hugr?rev=ab94518#ab94518ed2812abca615bfbfb5a822f67c115be8" dependencies = [ "anyhow", "delegate", - "downcast-rs", "hugr-core", "inkwell", "itertools 0.13.0", @@ -602,8 +595,7 @@ dependencies = [ [[package]] name = "hugr-passes" version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec2591767b6fe03074d38de7c4e61d52b37cb2e73b7340bf4ff957ad4554022a" +source = "git+https://github.com/CQCL/hugr?rev=ab94518#ab94518ed2812abca615bfbfb5a822f67c115be8" dependencies = [ "ascent", "hugr-core", diff --git a/Cargo.toml b/Cargo.toml index 21c65419..6d600d42 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,6 @@ inkwell = "0.5.0" [patch.crates-io] # Uncomment these to test the latest dependency version during development -# hugr = { git = "https://github.com/CQCL/hugr", rev = "861183e" } -# hugr-cli = { git = "https://github.com/CQCL/hugr", rev = "861183e" } -# hugr-llvm = { git = "https://github.com/CQCL/hugr", rev = "1091755" } + hugr = { git = "https://github.com/CQCL/hugr", rev = "ab94518" } + hugr-cli = { git = "https://github.com/CQCL/hugr", rev = "ab94518" } + hugr-llvm = { git = "https://github.com/CQCL/hugr", rev = "ab94518" } diff --git a/execute_llvm/src/lib.rs b/execute_llvm/src/lib.rs index 5eb06261..3ff6d2d7 100644 --- a/execute_llvm/src/lib.rs +++ b/execute_llvm/src/lib.rs @@ -38,6 +38,11 @@ fn find_funcdef_node(hugr: impl HugrView, fn_name: &str) -> PyResult } } +fn guppy_pass(hugr: Hugr) -> Hugr { + let hugr = hugr::algorithms::monomorphize(hugr); + hugr::algorithms::remove_polyfuncs(hugr) +} + fn compile_module<'a>( hugr: &'a hugr::Hugr, ctx: &'a Context, @@ -47,6 +52,7 @@ fn compile_module<'a>( // TODO: Handle tket2 codegen extension let extensions = hugr::llvm::custom::CodegenExtsBuilder::default() .add_int_extensions() + .add_logic_extensions() .add_default_prelude_extensions() .add_default_array_extensions() .add_float_extensions() @@ -64,9 +70,10 @@ fn compile_module<'a>( #[pyfunction] fn compile_module_to_string(hugr_json: &str) -> PyResult { - let hugr = parse_hugr(hugr_json)?; + let mut hugr = parse_hugr(hugr_json)?; let ctx = Context::create(); + hugr = guppy_pass(hugr); let module = compile_module(&hugr, &ctx, Default::default())?; Ok(module.print_to_string().to_str().unwrap().to_string()) @@ -77,7 +84,8 @@ fn run_function( fn_name: &str, parse_result: impl FnOnce(&Context, GenericValue) -> PyResult, ) -> PyResult { - let hugr = parse_hugr(hugr_json)?; + let mut hugr = parse_hugr(hugr_json)?; + hugr = guppy_pass(hugr); let ctx = Context::create(); let namer = hugr::llvm::emit::Namer::default(); diff --git a/guppylang/compiler/expr_compiler.py b/guppylang/compiler/expr_compiler.py index b3d8184f..e724cdec 100644 --- a/guppylang/compiler/expr_compiler.py +++ b/guppylang/compiler/expr_compiler.py @@ -5,6 +5,7 @@ from typing import Any, TypeGuard, TypeVar import hugr +import hugr.std.collections.array import hugr.std.float import hugr.std.int import hugr.std.logic @@ -21,7 +22,7 @@ from guppylang.checker.errors.generic import UnsupportedError from guppylang.checker.linearity_checker import contains_subscript from guppylang.compiler.core import CompilerBase, DFContainer -from guppylang.compiler.hugr_extension import PartialOp, UnsupportedOp +from guppylang.compiler.hugr_extension import PartialOp from guppylang.definition.custom import CustomFunctionDef from guppylang.definition.value import ( CallReturnWires, @@ -46,6 +47,7 @@ TensorCall, TypeApply, ) +from guppylang.std._internal.compiler.arithmetic import convert_ifromusize from guppylang.std._internal.compiler.array import array_repeat from guppylang.std._internal.compiler.list import ( list_new, @@ -123,7 +125,7 @@ def _new_dfcontainer( def _new_loop( self, loop_vars: list[PlaceNode], - branch: PlaceNode, + continue_predicate: PlaceNode, ) -> Iterator[None]: """Context manager to build a graph inside a new `TailLoop` node. @@ -134,13 +136,12 @@ def _new_loop( loop = self.builder.add_tail_loop([], loop_inputs) with self._new_dfcontainer(loop_vars, loop): yield - # Output the branch predicate and the inputs for the next iteration - loop.set_loop_outputs( - # Note that we have to do fresh calls to `self.visit` here since we're - # in a new context - self.visit(branch), - *(self.visit(name) for name in loop_vars), - ) + # Output the branch predicate and the inputs for the next iteration. Note + # that we have to do fresh calls to `self.visit` here since we're in a new + # context + do_continue = self.visit(continue_predicate) + do_break = loop.add_op(hugr.std.logic.Not, do_continue) + loop.set_loop_outputs(do_break, *(self.visit(name) for name in loop_vars)) # Update the DFG with the outputs from the loop for node, wire in zip(loop_vars, loop, strict=True): self.dfg[node.place] = wire @@ -172,12 +173,12 @@ def _if_true(self, cond: ast.expr, inputs: list[PlaceNode]) -> Iterator[None]: conditional = self.builder.add_conditional( self.visit(cond), *(self.visit(inp) for inp in inputs) ) - # If the condition is true, we enter the `with` block - with self._new_case(inputs, inputs, conditional, 0): - yield # If the condition is false, output the inputs as is - with self._new_case(inputs, inputs, conditional, 1): + with self._new_case(inputs, inputs, conditional, 0): pass + # If the condition is true, we enter the `with` block + with self._new_case(inputs, inputs, conditional, 1): + yield # Update the DFG with the outputs from the Conditional node for node, wire in zip(inputs, conditional, strict=True): self.dfg[node.place] = wire @@ -206,11 +207,16 @@ def visit_GlobalName(self, node: GlobalName) -> Wire: return defn.load(self.dfg, self.globals, node) def visit_GenericParamValue(self, node: GenericParamValue) -> Wire: - # TODO: We need a way to look up the concrete value of a generic type arg in - # Hugr. For example, a new op that captures the value during monomorphisation - return self.builder.add_op( - UnsupportedOp("load_type_param", [], [node.param.ty.to_hugr()]).ext_op - ) + match node.param.ty: + case NumericType(NumericType.Kind.Nat): + arg = node.param.to_bound().to_hugr() + load_nat = hugr.std.PRELUDE.get_op("load_nat").instantiate( + [arg], ht.FunctionType([], [ht.USize()]) + ) + usize = self.builder.add_op(load_nat) + return self.builder.add_op(convert_ifromusize(), usize) + case _: + raise NotImplementedError def visit_Name(self, node: ast.Name) -> Wire: raise InternalGuppyError("Node should have been removed during type checking.") @@ -604,17 +610,12 @@ def python_value_to_hugr(v: Any, exp_ty: Type) -> hv.Value | None: return hv.Tuple(*vs) case list(elts): assert is_array_type(exp_ty) - vs = [python_value_to_hugr(elt, get_element_type(exp_ty)) for elt in elts] + elem_ty = get_element_type(exp_ty) + vs = [python_value_to_hugr(elt, elem_ty) for elt in elts] if doesnt_contain_none(vs): - # 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"], - ) + opt_ty = ht.Option(elem_ty.to_hugr()) + opt_vs: list[hv.Value] = [hv.Some(v) for v in vs] + return hugr.std.collections.array.ArrayVal(opt_vs, opt_ty) case _: # TODO replace with hugr protocol handling: https://github.com/CQCL/guppylang/issues/563 # Pytket conversion is an experimental feature diff --git a/guppylang/compiler/stmt_compiler.py b/guppylang/compiler/stmt_compiler.py index 6f92854e..9132268c 100644 --- a/guppylang/compiler/stmt_compiler.py +++ b/guppylang/compiler/stmt_compiler.py @@ -115,15 +115,26 @@ def pop( array: Wire, length: int, pats: list[ast.expr], from_left: bool ) -> tuple[Wire, int]: err = "Internal error: unpacking of iterable failed" - for pat in pats: + num_pats = len(pats) + # Pop the number of requested elements from the array + elts = [] + for i in range(num_pats): res = self.builder.add_op( - array_pop(opt_elt_ty, length, from_left), array + array_pop(opt_elt_ty, length - i, from_left), array ) [elt_opt, array] = build_unwrap(self.builder, res, err) [elt] = build_unwrap(self.builder, elt_opt, err) + elts.append(elt) + # Assign elements to the given patterns + for pat, elt in zip( + pats, + # Assignments are evaluated from left to right, so we need to assign in + # reverse order if we popped from the right + elts if from_left else reversed(elts), + strict=True, + ): self._assign(pat, elt) - length -= 1 - return array, length + return array, length - num_pats self.dfg[lhs.rhs_var.place] = port array = self.expr_compiler.visit_DesugaredArrayComp(lhs.compr) diff --git a/guppylang/std/_internal/compiler/array.py b/guppylang/std/_internal/compiler/array.py index e4432360..b3195874 100644 --- a/guppylang/std/_internal/compiler/array.py +++ b/guppylang/std/_internal/compiler/array.py @@ -6,7 +6,6 @@ from hugr import tys as ht from hugr.std.collections.array import EXTENSION -from guppylang.compiler.hugr_extension import UnsupportedOp from guppylang.definition.custom import CustomCallCompiler from guppylang.definition.value import CallReturnWires from guppylang.error import InternalGuppyError @@ -92,24 +91,42 @@ def array_discard_empty(elem_ty: ht.Type) -> ops.ExtOp: ) +def array_scan( + elem_ty: ht.Type, + length: ht.TypeArg, + new_elem_ty: ht.Type, + accumulators: list[ht.Type], +) -> ops.ExtOp: + """Returns an operation that maps and folds a function across an array.""" + ty_args = [ + length, + ht.TypeTypeArg(elem_ty), + ht.TypeTypeArg(new_elem_ty), + ht.SequenceArg([ht.TypeTypeArg(acc) for acc in accumulators]), + ht.ExtensionsArg([]), + ] + ins = [ + array_type(elem_ty, length), + ht.FunctionType([elem_ty, *accumulators], [new_elem_ty, *accumulators]), + *accumulators, + ] + outs = [array_type(new_elem_ty, length), *accumulators] + return EXTENSION.get_op("scan").instantiate(ty_args, ht.FunctionType(ins, outs)) + + def array_map(elem_ty: ht.Type, length: ht.TypeArg, new_elem_ty: ht.Type) -> ops.ExtOp: """Returns an operation that maps a function across an array.""" - # TODO - return UnsupportedOp( - op_name="array_map", - inputs=[array_type(elem_ty, length), ht.FunctionType([elem_ty], [new_elem_ty])], - outputs=[array_type(new_elem_ty, length)], - ).ext_op + return array_scan(elem_ty, length, new_elem_ty, accumulators=[]) def array_repeat(elem_ty: ht.Type, length: ht.TypeArg) -> ops.ExtOp: """Returns an array `repeat` operation.""" - # TODO - return UnsupportedOp( - op_name="array.repeat", - inputs=[ht.FunctionType([], [elem_ty])], - outputs=[array_type(elem_ty, length)], - ).ext_op + return EXTENSION.get_op("repeat").instantiate( + [length, ht.TypeTypeArg(elem_ty), ht.ExtensionsArg([])], + ht.FunctionType( + [ht.FunctionType([], [elem_ty])], [array_type(elem_ty, length)] + ), + ) # ------------------------------------------------------ diff --git a/guppylang/std/builtins.py b/guppylang/std/builtins.py index d9843bc2..85a9be7d 100644 --- a/guppylang/std/builtins.py +++ b/guppylang/std/builtins.py @@ -161,7 +161,9 @@ def __ge__(self: nat, other: nat) -> bool: ... @guppy.hugr_op(int_op("igt_u")) def __gt__(self: nat, other: nat) -> bool: ... - @guppy.hugr_op(int_op("iu_to_s")) + # TODO: Use "iu_to_s" once we have lowering: + # https://github.com/CQCL/hugr/issues/1806 + @guppy.custom(NoopCompiler()) def __int__(self: nat) -> int: ... @guppy.hugr_op(int_op("inot")) diff --git a/guppylang/tys/builtin.py b/guppylang/tys/builtin.py index f9785b21..740869dc 100644 --- a/guppylang/tys/builtin.py +++ b/guppylang/tys/builtin.py @@ -138,8 +138,7 @@ def _array_to_hugr(args: Sequence[Argument]) -> ht.Type: elem_ty = ht.Option(ty_arg.ty.to_hugr()) hugr_arg = len_arg.to_hugr() - # TODO remove type ignore after Array type annotation fixed to include VariableArg - return hugr.std.collections.array.Array(elem_ty, hugr_arg) # type:ignore[arg-type] + return hugr.std.collections.array.Array(elem_ty, hugr_arg) def _sized_iter_to_hugr(args: Sequence[Argument]) -> ht.Type: diff --git a/pyproject.toml b/pyproject.toml index 473993fb..29ceb926 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -83,7 +83,7 @@ members = ["execute_llvm"] execute-llvm = { workspace = true } # Uncomment these to test the latest dependency version during development -# hugr = { git = "https://github.com/CQCL/hugr", subdirectory = "hugr-py", rev = "861183e" } + hugr = { git = "https://github.com/CQCL/hugr", subdirectory = "hugr-py", rev = "e40b6c7" } # tket2-exts = { git = "https://github.com/CQCL/tket2", subdirectory = "tket2-exts", rev = "eb7cc63"} # tket2 = { git = "https://github.com/CQCL/tket2", subdirectory = "tket2-py", rev = "eb7cc63"} diff --git a/tests/integration/test_array.py b/tests/integration/test_array.py index ab462cff..9973539a 100644 --- a/tests/integration/test_array.py +++ b/tests/integration/test_array.py @@ -291,8 +291,7 @@ def main() -> int: package = module.compile() validate(package) - # TODO: Enable execution once lowering for missing ops is implemented - # run_int_fn(package, expected=9) + run_int_fn(package, expected=9) def test_mem_swap(validate): diff --git a/tests/integration/test_array_comprehension.py b/tests/integration/test_array_comprehension.py index e012b3a5..d967c705 100644 --- a/tests/integration/test_array_comprehension.py +++ b/tests/integration/test_array_comprehension.py @@ -9,12 +9,23 @@ from tests.util import compile_guppy -def test_basic(validate): - @compile_guppy +def test_basic_exec(validate, run_int_fn): + module = GuppyModule("test") + + @guppy(module) def test() -> array[int, 10]: return array(i + 1 for i in range(10)) - validate(test) + @guppy(module) + def main() -> int: + s = 0 + for x in test(): + s += x + return s + + package = module.compile() + validate(package) + run_int_fn(package, expected=sum(i + 1 for i in range(10))) def test_basic_linear(validate): @@ -29,23 +40,42 @@ def test() -> array[qubit, 42]: validate(module.compile()) -def test_zero_length(validate): - @compile_guppy +def test_zero_length(validate, run_int_fn): + module = GuppyModule("test") + + @guppy(module) def test() -> array[float, 0]: return array(i / 0 for i in range(0)) - validate(test) + @guppy(module) + def main() -> int: + test() + return 0 + package = module.compile() + validate(package) + run_int_fn(package, expected=0) -def test_capture(validate): - @compile_guppy + +def test_capture(validate, run_int_fn): + module = GuppyModule("test") + + @guppy(module) def test(x: int) -> array[int, 42]: return array(i + x for i in range(42)) - validate(test) + @guppy(module) + def main() -> int: + s = 0 + for x in test(3): + s += x + return s + + package = module.compile() + validate(package) + run_int_fn(package, expected=sum(i + 3 for i in range(42))) -@pytest.mark.skip("See https://github.com/CQCL/hugr/issues/1625") def test_capture_struct(validate): module = GuppyModule("test") @@ -71,12 +101,24 @@ def test() -> float: validate(test) -def test_nested_left(validate): - @compile_guppy +def test_nested_left(validate, run_int_fn): + module = GuppyModule("test") + + @guppy(module) def test() -> array[array[int, 10], 20]: return array(array(x + y for y in range(10)) for x in range(20)) - validate(test) + @guppy(module) + def main() -> int: + s = 0 + for xs in test(): + for x in xs: + s += x + return s + + package = module.compile() + validate(package) + run_int_fn(package, expected=sum(x + y for y in range(10) for x in range(20))) def test_generic(validate): diff --git a/tests/integration/test_unpack.py b/tests/integration/test_unpack.py index f399f22d..69f019f7 100644 --- a/tests/integration/test_unpack.py +++ b/tests/integration/test_unpack.py @@ -69,8 +69,7 @@ def main() -> int: compiled = module.compile() validate(compiled) - # TODO: Enable execution test once array lowering is fully supported - # run_int_fn(compiled, expected=9) + run_int_fn(compiled, expected=9) def test_unpack_tuple_starred(validate, run_int_fn): @@ -102,3 +101,22 @@ def main( return x, y, z, a, b, c validate(module.compile()) + + +def test_left_to_right(validate, run_int_fn): + module = GuppyModule("test") + + @guppy(module) + def left() -> int: + [x, x, *_] = range(10) + return x + + @guppy(module) + def right() -> int: + [*_, x, x] = range(10) + return x + + compiled = module.compile() + validate(compiled) + run_int_fn(compiled, fn_name="left", expected=1) + run_int_fn(compiled, fn_name="right", expected=9) diff --git a/uv.lock b/uv.lock index 8b5ef284..c61fbdd1 100644 --- a/uv.lock +++ b/uv.lock @@ -614,7 +614,7 @@ test = [ [package.metadata] requires-dist = [ { name = "graphviz", specifier = ">=0.20.1,<0.21" }, - { name = "hugr", specifier = ">=0.10.0,<0.11" }, + { name = "hugr", git = "https://github.com/CQCL/hugr?subdirectory=hugr-py&rev=e40b6c7" }, { name = "networkx", specifier = ">=3.2.1,<4" }, { name = "pydantic", specifier = ">=2.7.0b1,<3" }, { name = "pytket", marker = "extra == 'pytket'", specifier = ">=1.34" }, @@ -679,17 +679,13 @@ test = [ [[package]] name = "hugr" version = "0.10.0" -source = { registry = "https://pypi.org/simple" } +source = { git = "https://github.com/CQCL/hugr?subdirectory=hugr-py&rev=e40b6c7#e40b6c7057a15ead78bb18aa837e5b84e12a3722" } dependencies = [ { name = "graphviz" }, { name = "pydantic" }, { name = "pydantic-extra-types" }, { name = "semver" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a6/ef/9cd410ff0e3a92c5e88da2ef3c0e051dd971f4f6c5577873c7901ed31dd5/hugr-0.10.0.tar.gz", hash = "sha256:11e5a80ebd4e31cad0cb04d408cdd93a094e6fb817dd81481eedac5a58f86ff7", size = 129441 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f2/71/83556457cfe27f4a1613cd49041cfe4c6e9e087a53b5beec48a8d709c36d/hugr-0.10.0-py3-none-any.whl", hash = "sha256:591e252ef3e4182fd0de99274ebb4999ddd9572a0ec823519de154e4bd9f14ec", size = 83000 }, -] [[package]] name = "identify" From ed3c0b82c1e91824e8468ffffc471677b80e6851 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 18 Dec 2024 16:43:35 +0000 Subject: [PATCH 10/10] ci(deps): bump astral-sh/setup-uv from 3 to 4 (#674) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 3 to 4.
Release notes

Sourced from astral-sh/setup-uv's releases.

v4.0.0 🌈 Fail when cache local path does not exist when trying to cache

🚨 Breaking change 🚨

By default, the action will now fail if caching is enabled but there is nothing to upload (the uv cache directory does not exist). If you want to ignore this, set the ignore-nothing-to-cache input to true.

- name: Ignore nothing to cache
  uses: astral-sh/setup-uv@v3
  with:
    enable-cache: true
    ignore-nothing-to-cache: true

In previous releases only an error got logged when saving the cache failed. In most cases users did not realize something was wrong with their config.

Changes

🚨 Breaking changes

  • Fail when cache local path does not exist when trying to cache @​eifinger (#163)

🐛 Bug fixes

  • Fail when cache local path does not exist when trying to cache @​eifinger (#163)
  • Remove working dir from cacheDependencyGlob error message @​eifinger (#162)

📚 Documentation

v3.2.4 🌈 Expand ~ tilde in input paths

This release adds support for expanding the ~ character to the user's home directory for the following inputs:

  • cache-local-path
  • tool-dir
  • tool-bin-dir
  • cache-dependency-glob
- name: Expand the tilde character
  uses: astral-sh/setup-uv@v3
  with:
    cache-local-path: "~/path/to/cache"
</tr></table>

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=astral-sh/setup-uv&package-manager=github_actions&previous-version=3&new-version=4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/docs.yml | 2 +- .github/workflows/pull-request.yaml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index e4665645..b6398488 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -31,7 +31,7 @@ jobs: uses: mozilla-actions/sccache-action@v0.0.7 - name: Set up uv - uses: astral-sh/setup-uv@v3 + uses: astral-sh/setup-uv@v4 with: version: ${{ env.UV_VERSION }} enable-cache: true diff --git a/.github/workflows/pull-request.yaml b/.github/workflows/pull-request.yaml index 897f4aa9..943c59ca 100644 --- a/.github/workflows/pull-request.yaml +++ b/.github/workflows/pull-request.yaml @@ -34,7 +34,7 @@ jobs: run: "sudo apt-get update && sudo apt-get install -y llvm-14" - name: Set up uv - uses: astral-sh/setup-uv@v3 + uses: astral-sh/setup-uv@v4 with: version: ${{ env.UV_VERSION }} enable-cache: true @@ -81,7 +81,7 @@ jobs: uses: dtolnay/rust-toolchain@stable - name: Set up uv - uses: astral-sh/setup-uv@v3 + uses: astral-sh/setup-uv@v4 with: version: ${{ env.UV_VERSION }} enable-cache: true