guppylang-internals 0.24.0__py3-none-any.whl → 0.25.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- guppylang_internals/__init__.py +1 -1
- guppylang_internals/ast_util.py +21 -0
- guppylang_internals/cfg/bb.py +20 -0
- guppylang_internals/cfg/builder.py +101 -3
- guppylang_internals/checker/core.py +4 -0
- guppylang_internals/checker/errors/generic.py +32 -1
- guppylang_internals/checker/errors/type_errors.py +14 -0
- guppylang_internals/checker/expr_checker.py +46 -10
- guppylang_internals/checker/func_checker.py +1 -1
- guppylang_internals/checker/linearity_checker.py +65 -0
- guppylang_internals/checker/modifier_checker.py +116 -0
- guppylang_internals/checker/stmt_checker.py +48 -1
- guppylang_internals/compiler/core.py +90 -53
- guppylang_internals/compiler/expr_compiler.py +49 -114
- guppylang_internals/compiler/modifier_compiler.py +174 -0
- guppylang_internals/compiler/stmt_compiler.py +15 -8
- guppylang_internals/definition/custom.py +35 -1
- guppylang_internals/definition/declaration.py +3 -4
- guppylang_internals/definition/parameter.py +8 -3
- guppylang_internals/definition/pytket_circuits.py +13 -41
- guppylang_internals/definition/struct.py +7 -4
- guppylang_internals/definition/ty.py +3 -3
- guppylang_internals/experimental.py +5 -0
- guppylang_internals/nodes.py +124 -0
- guppylang_internals/std/_internal/compiler/array.py +94 -282
- guppylang_internals/std/_internal/compiler/tket_exts.py +9 -2
- guppylang_internals/tracing/unpacking.py +19 -20
- guppylang_internals/tys/arg.py +18 -3
- guppylang_internals/tys/builtin.py +2 -5
- guppylang_internals/tys/const.py +33 -4
- guppylang_internals/tys/param.py +31 -16
- guppylang_internals/tys/parsing.py +8 -21
- guppylang_internals/tys/qubit.py +27 -0
- guppylang_internals/tys/subst.py +8 -26
- guppylang_internals/tys/ty.py +31 -21
- {guppylang_internals-0.24.0.dist-info → guppylang_internals-0.25.0.dist-info}/METADATA +3 -3
- {guppylang_internals-0.24.0.dist-info → guppylang_internals-0.25.0.dist-info}/RECORD +39 -36
- {guppylang_internals-0.24.0.dist-info → guppylang_internals-0.25.0.dist-info}/WHEEL +0 -0
- {guppylang_internals-0.24.0.dist-info → guppylang_internals-0.25.0.dist-info}/licenses/LICENCE +0 -0
|
@@ -2,31 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from typing import TYPE_CHECKING,
|
|
5
|
+
from typing import TYPE_CHECKING, TypeVar
|
|
6
6
|
|
|
7
7
|
import hugr
|
|
8
8
|
from hugr import Wire, ops
|
|
9
9
|
from hugr import tys as ht
|
|
10
|
-
from hugr.std.collections.
|
|
10
|
+
from hugr.std.collections.borrow_array import EXTENSION
|
|
11
11
|
|
|
12
|
-
from guppylang_internals.compiler.core import (
|
|
13
|
-
GlobalConstId,
|
|
14
|
-
)
|
|
15
12
|
from guppylang_internals.definition.custom import CustomCallCompiler
|
|
16
13
|
from guppylang_internals.definition.value import CallReturnWires
|
|
17
14
|
from guppylang_internals.error import InternalGuppyError
|
|
18
15
|
from guppylang_internals.std._internal.compiler.arithmetic import convert_itousize
|
|
19
16
|
from guppylang_internals.std._internal.compiler.prelude import (
|
|
20
|
-
build_expect_none,
|
|
21
|
-
build_unwrap,
|
|
22
|
-
build_unwrap_left,
|
|
23
17
|
build_unwrap_right,
|
|
24
18
|
)
|
|
25
19
|
from guppylang_internals.tys.arg import ConstArg, TypeArg
|
|
26
|
-
from guppylang_internals.tys.builtin import int_type
|
|
27
20
|
|
|
28
21
|
if TYPE_CHECKING:
|
|
29
|
-
from hugr.build import function as hf
|
|
30
22
|
from hugr.build.dfg import DfBase
|
|
31
23
|
|
|
32
24
|
|
|
@@ -50,10 +42,10 @@ def _instantiate_array_op(
|
|
|
50
42
|
def array_type(elem_ty: ht.Type, length: ht.TypeArg) -> ht.ExtType:
|
|
51
43
|
"""Returns the hugr type of a fixed length array.
|
|
52
44
|
|
|
53
|
-
This is the
|
|
45
|
+
This is the linear `borrow_array` type used by Guppy.
|
|
54
46
|
"""
|
|
55
47
|
elem_arg = ht.TypeTypeArg(elem_ty)
|
|
56
|
-
return EXTENSION.types["
|
|
48
|
+
return EXTENSION.types["borrow_array"].instantiate([length, elem_arg])
|
|
57
49
|
|
|
58
50
|
|
|
59
51
|
def standard_array_type(elem_ty: ht.Type, length: ht.TypeArg) -> ht.ExtType:
|
|
@@ -162,9 +154,9 @@ def array_repeat(elem_ty: ht.Type, length: ht.TypeArg) -> ops.ExtOp:
|
|
|
162
154
|
)
|
|
163
155
|
|
|
164
156
|
|
|
165
|
-
def
|
|
166
|
-
"""Returns an array operation to convert the `
|
|
167
|
-
|
|
157
|
+
def array_to_std_array(elem_ty: ht.Type, length: ht.TypeArg) -> ops.ExtOp:
|
|
158
|
+
"""Returns an array operation to convert a value of the `borrow_array` type
|
|
159
|
+
used by Guppy into a standard `array`.
|
|
168
160
|
"""
|
|
169
161
|
return EXTENSION.get_op("to_array").instantiate(
|
|
170
162
|
[length, ht.TypeTypeArg(elem_ty)],
|
|
@@ -174,9 +166,9 @@ def array_convert_to_std_array(elem_ty: ht.Type, length: ht.TypeArg) -> ops.ExtO
|
|
|
174
166
|
)
|
|
175
167
|
|
|
176
168
|
|
|
177
|
-
def
|
|
178
|
-
"""Returns an array operation to convert the `array` type
|
|
179
|
-
`
|
|
169
|
+
def std_array_to_array(elem_ty: ht.Type, length: ht.TypeArg) -> ops.ExtOp:
|
|
170
|
+
"""Returns an array operation to convert the standard `array` type into the
|
|
171
|
+
`borrow_array` type used by Guppy.
|
|
180
172
|
"""
|
|
181
173
|
return EXTENSION.get_op("from_array").instantiate(
|
|
182
174
|
[length, ht.TypeTypeArg(elem_ty)],
|
|
@@ -186,6 +178,42 @@ def array_convert_from_std_array(elem_ty: ht.Type, length: ht.TypeArg) -> ops.Ex
|
|
|
186
178
|
)
|
|
187
179
|
|
|
188
180
|
|
|
181
|
+
def barray_borrow(elem_ty: ht.Type, length: ht.TypeArg) -> ops.ExtOp:
|
|
182
|
+
"""Returns an array `borrow` operation."""
|
|
183
|
+
arr_ty = array_type(elem_ty, length)
|
|
184
|
+
return _instantiate_array_op(
|
|
185
|
+
"borrow", elem_ty, length, [arr_ty, ht.USize()], [arr_ty, elem_ty]
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def barray_return(elem_ty: ht.Type, length: ht.TypeArg) -> ops.ExtOp:
|
|
190
|
+
"""Returns an array `return` operation."""
|
|
191
|
+
arr_ty = array_type(elem_ty, length)
|
|
192
|
+
return _instantiate_array_op(
|
|
193
|
+
"return", elem_ty, length, [arr_ty, ht.USize(), elem_ty], [arr_ty]
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def barray_discard_all_borrowed(elem_ty: ht.Type, length: ht.TypeArg) -> ops.ExtOp:
|
|
198
|
+
"""Returns an array `discard_all_borrowed` operation."""
|
|
199
|
+
arr_ty = array_type(elem_ty, length)
|
|
200
|
+
return _instantiate_array_op("discard_all_borrowed", elem_ty, length, [arr_ty], [])
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def barray_new_all_borrowed(elem_ty: ht.Type, length: ht.TypeArg) -> ops.ExtOp:
|
|
204
|
+
"""Returns an array `new_all_borrowed` operation."""
|
|
205
|
+
arr_ty = array_type(elem_ty, length)
|
|
206
|
+
return _instantiate_array_op("new_all_borrowed", elem_ty, length, [], [arr_ty])
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def array_clone(elem_ty: ht.Type, length: ht.TypeArg) -> ops.ExtOp:
|
|
210
|
+
"""Returns an array `clone` operation for arrays none of whose elements are
|
|
211
|
+
borrowed."""
|
|
212
|
+
assert elem_ty.type_bound() == ht.TypeBound.Copyable
|
|
213
|
+
arr_ty = array_type(elem_ty, length)
|
|
214
|
+
return _instantiate_array_op("clone", elem_ty, length, [arr_ty], [arr_ty, arr_ty])
|
|
215
|
+
|
|
216
|
+
|
|
189
217
|
# ------------------------------------------------------
|
|
190
218
|
# --------- Custom compilers for non-native ops --------
|
|
191
219
|
# ------------------------------------------------------
|
|
@@ -238,12 +266,7 @@ class NewArrayCompiler(ArrayCompiler):
|
|
|
238
266
|
|
|
239
267
|
def build_linear_array(self, elems: list[Wire]) -> Wire:
|
|
240
268
|
"""Lowers a call to `array.__new__` for linear arrays."""
|
|
241
|
-
|
|
242
|
-
self.builder.add_op(ops.Some(self.elem_ty), elem) for elem in elems
|
|
243
|
-
]
|
|
244
|
-
return self.builder.add_op(
|
|
245
|
-
array_new(ht.Option(self.elem_ty), len(elems)), *elem_opts
|
|
246
|
-
)
|
|
269
|
+
return self.builder.add_op(array_new(self.elem_ty, len(elems)), *elems)
|
|
247
270
|
|
|
248
271
|
def compile(self, args: list[Wire]) -> list[Wire]:
|
|
249
272
|
if self.elem_ty.type_bound() == ht.TypeBound.Linear:
|
|
@@ -252,131 +275,35 @@ class NewArrayCompiler(ArrayCompiler):
|
|
|
252
275
|
return [self.build_classical_array(args)]
|
|
253
276
|
|
|
254
277
|
|
|
255
|
-
ARRAY_GETITEM_CLASSICAL: Final[GlobalConstId] = GlobalConstId.fresh(
|
|
256
|
-
"array.__getitem__.classical"
|
|
257
|
-
)
|
|
258
|
-
ARRAY_GETITEM_LINEAR: Final[GlobalConstId] = GlobalConstId.fresh(
|
|
259
|
-
"array.__getitem__.linear"
|
|
260
|
-
)
|
|
261
|
-
ARRAY_SETITEM_CLASSICAL: Final[GlobalConstId] = GlobalConstId.fresh(
|
|
262
|
-
"array.__setitem__.classical"
|
|
263
|
-
)
|
|
264
|
-
ARRAY_SETITEM_LINEAR: Final[GlobalConstId] = GlobalConstId.fresh(
|
|
265
|
-
"array.__setitem__.linear"
|
|
266
|
-
)
|
|
267
|
-
ARRAY_ITER_ASSERT_ALL_USED_HELPER: Final[GlobalConstId] = GlobalConstId.fresh(
|
|
268
|
-
"ArrayIter._assert_all_used.helper"
|
|
269
|
-
)
|
|
270
|
-
|
|
271
|
-
|
|
272
278
|
class ArrayGetitemCompiler(ArrayCompiler):
|
|
273
279
|
"""Compiler for the `array.__getitem__` function."""
|
|
274
280
|
|
|
275
|
-
def
|
|
276
|
-
"""Constructs
|
|
277
|
-
|
|
278
|
-
# Array element type parameter
|
|
279
|
-
elem_ty_param = ht.TypeTypeParam(bound)
|
|
280
|
-
# Array length parameter
|
|
281
|
-
length_param = ht.BoundedNatParam()
|
|
282
|
-
return ht.PolyFuncType(
|
|
283
|
-
params=[elem_ty_param, length_param],
|
|
284
|
-
body=ht.FunctionType(
|
|
285
|
-
input=[
|
|
286
|
-
array_type(
|
|
287
|
-
ht.Option(ht.Variable(0, bound)),
|
|
288
|
-
ht.VariableArg(1, length_param),
|
|
289
|
-
),
|
|
290
|
-
int_type().to_hugr(self.ctx),
|
|
291
|
-
],
|
|
292
|
-
output=[
|
|
293
|
-
ht.Variable(0, bound),
|
|
294
|
-
array_type(
|
|
295
|
-
ht.Option(ht.Variable(0, bound)),
|
|
296
|
-
ht.VariableArg(1, length_param),
|
|
297
|
-
),
|
|
298
|
-
],
|
|
299
|
-
),
|
|
300
|
-
)
|
|
301
|
-
|
|
302
|
-
def _build_classical_getitem(self, func: hf.Function) -> None:
|
|
303
|
-
"""Constructs a generic function for `__getitem__` for classical arrays."""
|
|
304
|
-
elem_ty = ht.Variable(0, ht.TypeBound.Copyable)
|
|
305
|
-
length = ht.VariableArg(1, ht.BoundedNatParam())
|
|
281
|
+
def _build_classical_getitem(self, array: Wire, idx: Wire) -> CallReturnWires:
|
|
282
|
+
"""Constructs `__getitem__` for classical arrays."""
|
|
283
|
+
idx = self.builder.add_op(convert_itousize(), idx)
|
|
306
284
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
idx = func.add_op(convert_itousize(), func.inputs()[1])
|
|
311
|
-
# As copyable elements can be used multiple times, we need to swap the element
|
|
312
|
-
# back after initially swapping it out for `None` to get the value.
|
|
313
|
-
initial_result = func.add_op(
|
|
314
|
-
array_set(elem_opt_ty, length),
|
|
315
|
-
func.inputs()[0],
|
|
316
|
-
idx,
|
|
317
|
-
none,
|
|
318
|
-
)
|
|
319
|
-
elem_opt, arr = build_unwrap_right(
|
|
320
|
-
func, initial_result, "Array index out of bounds"
|
|
321
|
-
)
|
|
322
|
-
swapped_back = func.add_op(
|
|
323
|
-
array_set(elem_opt_ty, length),
|
|
324
|
-
arr,
|
|
325
|
-
idx,
|
|
326
|
-
elem_opt,
|
|
327
|
-
)
|
|
328
|
-
_, arr = build_unwrap_right(func, swapped_back, "Array index out of bounds")
|
|
329
|
-
elem = build_unwrap(func, elem_opt, "array.__getitem__: Internal error")
|
|
330
|
-
|
|
331
|
-
func.set_outputs(elem, arr)
|
|
332
|
-
|
|
333
|
-
def _build_linear_getitem(self, func: hf.Function) -> None:
|
|
334
|
-
"""Constructs function to call `array.__getitem__` for linear arrays."""
|
|
335
|
-
elem_ty = ht.Variable(0, ht.TypeBound.Linear)
|
|
336
|
-
length = ht.VariableArg(1, ht.BoundedNatParam())
|
|
337
|
-
|
|
338
|
-
elem_opt_ty = ht.Option(elem_ty)
|
|
339
|
-
none = func.add_op(ops.Tag(0, elem_opt_ty))
|
|
340
|
-
idx = func.add_op(convert_itousize(), func.inputs()[1])
|
|
341
|
-
result = func.add_op(
|
|
342
|
-
array_set(elem_opt_ty, length),
|
|
343
|
-
func.inputs()[0],
|
|
285
|
+
opt_elem, arr = self.builder.add_op(
|
|
286
|
+
array_get(self.elem_ty, self.length),
|
|
287
|
+
array,
|
|
344
288
|
idx,
|
|
345
|
-
none,
|
|
346
289
|
)
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
290
|
+
elem = build_unwrap_right(self.builder, opt_elem, "Array index out of bounds")
|
|
291
|
+
return CallReturnWires(
|
|
292
|
+
regular_returns=[elem],
|
|
293
|
+
inout_returns=[arr],
|
|
350
294
|
)
|
|
351
295
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
self
|
|
356
|
-
|
|
357
|
-
array: Wire,
|
|
358
|
-
idx: Wire,
|
|
359
|
-
) -> CallReturnWires:
|
|
360
|
-
"""Inserts a call to `array.__getitem__`."""
|
|
361
|
-
concrete_func_ty = ht.FunctionType(
|
|
362
|
-
input=[
|
|
363
|
-
array_type(ht.Option(self.elem_ty), self.length),
|
|
364
|
-
int_type().to_hugr(self.ctx),
|
|
365
|
-
],
|
|
366
|
-
output=[self.elem_ty, array_type(ht.Option(self.elem_ty), self.length)],
|
|
367
|
-
)
|
|
368
|
-
type_args = [ht.TypeTypeArg(self.elem_ty), self.length]
|
|
369
|
-
func_call = self.builder.call(
|
|
370
|
-
func.parent_node,
|
|
296
|
+
def _build_linear_getitem(self, array: Wire, idx: Wire) -> CallReturnWires:
|
|
297
|
+
"""Constructs `array.__getitem__` for linear arrays."""
|
|
298
|
+
idx = self.builder.add_op(convert_itousize(), idx)
|
|
299
|
+
arr, elem = self.builder.add_op(
|
|
300
|
+
barray_borrow(self.elem_ty, self.length),
|
|
371
301
|
array,
|
|
372
302
|
idx,
|
|
373
|
-
instantiation=concrete_func_ty,
|
|
374
|
-
type_args=type_args,
|
|
375
303
|
)
|
|
376
|
-
outputs = list(func_call.outputs())
|
|
377
304
|
return CallReturnWires(
|
|
378
|
-
regular_returns=[
|
|
379
|
-
inout_returns=[
|
|
305
|
+
regular_returns=[elem],
|
|
306
|
+
inout_returns=[arr],
|
|
380
307
|
)
|
|
381
308
|
|
|
382
309
|
def compile_with_inouts(self, args: list[Wire]) -> CallReturnWires:
|
|
@@ -384,24 +311,9 @@ class ArrayGetitemCompiler(ArrayCompiler):
|
|
|
384
311
|
[elem_ty_arg, _] = self.type_args
|
|
385
312
|
assert isinstance(elem_ty_arg, TypeArg)
|
|
386
313
|
if not elem_ty_arg.ty.copyable:
|
|
387
|
-
|
|
388
|
-
func, already_exists = self.ctx.declare_global_func(
|
|
389
|
-
ARRAY_GETITEM_LINEAR, func_ty
|
|
390
|
-
)
|
|
391
|
-
if not already_exists:
|
|
392
|
-
self._build_linear_getitem(func)
|
|
314
|
+
return self._build_linear_getitem(array, idx)
|
|
393
315
|
else:
|
|
394
|
-
|
|
395
|
-
func, already_exists = self.ctx.declare_global_func(
|
|
396
|
-
ARRAY_GETITEM_CLASSICAL, func_ty
|
|
397
|
-
)
|
|
398
|
-
if not already_exists:
|
|
399
|
-
self._build_classical_getitem(func)
|
|
400
|
-
return self._build_call_getitem(
|
|
401
|
-
func=func,
|
|
402
|
-
array=array,
|
|
403
|
-
idx=idx,
|
|
404
|
-
)
|
|
316
|
+
return self._build_classical_getitem(array, idx)
|
|
405
317
|
|
|
406
318
|
def compile(self, args: list[Wire]) -> list[Wire]:
|
|
407
319
|
raise InternalGuppyError("Call compile_with_inouts instead")
|
|
@@ -410,160 +322,60 @@ class ArrayGetitemCompiler(ArrayCompiler):
|
|
|
410
322
|
class ArraySetitemCompiler(ArrayCompiler):
|
|
411
323
|
"""Compiler for the `array.__setitem__` function."""
|
|
412
324
|
|
|
413
|
-
def
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
input=[
|
|
422
|
-
array_type(
|
|
423
|
-
ht.Option(ht.Variable(0, bound)),
|
|
424
|
-
ht.VariableArg(1, length_param),
|
|
425
|
-
),
|
|
426
|
-
int_type().to_hugr(self.ctx),
|
|
427
|
-
ht.Variable(0, bound),
|
|
428
|
-
],
|
|
429
|
-
output=[
|
|
430
|
-
array_type(
|
|
431
|
-
ht.Option(ht.Variable(0, bound)),
|
|
432
|
-
ht.VariableArg(1, length_param),
|
|
433
|
-
),
|
|
434
|
-
],
|
|
435
|
-
),
|
|
436
|
-
)
|
|
437
|
-
|
|
438
|
-
def _build_classical_setitem(self, func: hf.Function) -> None:
|
|
439
|
-
"""Constructs a generic function for `__setitem__` for classical arrays."""
|
|
440
|
-
elem_ty = ht.Variable(0, ht.TypeBound.Copyable)
|
|
441
|
-
length = ht.VariableArg(1, ht.BoundedNatParam())
|
|
442
|
-
|
|
443
|
-
elem_opt_ty = ht.Option(elem_ty)
|
|
444
|
-
idx = func.add_op(convert_itousize(), func.inputs()[1])
|
|
445
|
-
elem_opt = func.add_op(ops.Some(elem_ty), func.inputs()[2])
|
|
446
|
-
result = func.add_op(
|
|
447
|
-
array_set(elem_opt_ty, length),
|
|
448
|
-
func.inputs()[0],
|
|
449
|
-
idx,
|
|
450
|
-
elem_opt,
|
|
451
|
-
)
|
|
452
|
-
_, array = build_unwrap_right(func, result, "Array index out of bounds")
|
|
453
|
-
|
|
454
|
-
func.set_outputs(array)
|
|
455
|
-
|
|
456
|
-
def _build_linear_setitem(self, func: hf.Function) -> None:
|
|
457
|
-
"""Constructs function to call `array.__setitem__` for linear arrays."""
|
|
458
|
-
elem_ty = ht.Variable(0, ht.TypeBound.Linear)
|
|
459
|
-
length = ht.VariableArg(1, ht.BoundedNatParam())
|
|
460
|
-
|
|
461
|
-
elem_opt_ty = ht.Option(elem_ty)
|
|
462
|
-
elem = func.add_op(ops.Some(elem_ty), func.inputs()[2])
|
|
463
|
-
idx = func.add_op(convert_itousize(), func.inputs()[1])
|
|
464
|
-
result = func.add_op(
|
|
465
|
-
array_set(elem_opt_ty, length),
|
|
466
|
-
func.inputs()[0],
|
|
325
|
+
def _build_classical_setitem(
|
|
326
|
+
self, array: Wire, idx: Wire, elem: Wire
|
|
327
|
+
) -> CallReturnWires:
|
|
328
|
+
"""Constructs `__setitem__` for classical arrays."""
|
|
329
|
+
idx = self.builder.add_op(convert_itousize(), idx)
|
|
330
|
+
result = self.builder.add_op(
|
|
331
|
+
array_set(self.elem_ty, self.length),
|
|
332
|
+
array,
|
|
467
333
|
idx,
|
|
468
334
|
elem,
|
|
469
335
|
)
|
|
470
|
-
|
|
471
|
-
func, result, "Array index out of bounds"
|
|
472
|
-
)
|
|
473
|
-
build_unwrap_left(func, old_elem_opt, "Linear array element has not been used")
|
|
336
|
+
_, arr = build_unwrap_right(self.builder, result, "Array index out of bounds")
|
|
474
337
|
|
|
475
|
-
|
|
338
|
+
return CallReturnWires(
|
|
339
|
+
regular_returns=[],
|
|
340
|
+
inout_returns=[arr],
|
|
341
|
+
)
|
|
476
342
|
|
|
477
|
-
def
|
|
478
|
-
self,
|
|
479
|
-
func: hf.Function,
|
|
480
|
-
array: Wire,
|
|
481
|
-
idx: Wire,
|
|
482
|
-
elem: Wire,
|
|
343
|
+
def _build_linear_setitem(
|
|
344
|
+
self, array: Wire, idx: Wire, elem: Wire
|
|
483
345
|
) -> CallReturnWires:
|
|
484
|
-
"""
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
int_type().to_hugr(self.ctx),
|
|
489
|
-
self.elem_ty,
|
|
490
|
-
],
|
|
491
|
-
output=[array_type(ht.Option(self.elem_ty), self.length)],
|
|
492
|
-
)
|
|
493
|
-
type_args = [ht.TypeTypeArg(self.elem_ty), self.length]
|
|
494
|
-
func_call = self.builder.call(
|
|
495
|
-
func.parent_node,
|
|
346
|
+
"""Constructs `array.__setitem__` for linear arrays."""
|
|
347
|
+
idx = self.builder.add_op(convert_itousize(), idx)
|
|
348
|
+
arr = self.builder.add_op(
|
|
349
|
+
barray_return(self.elem_ty, self.length),
|
|
496
350
|
array,
|
|
497
351
|
idx,
|
|
498
352
|
elem,
|
|
499
|
-
instantiation=concrete_func_ty,
|
|
500
|
-
type_args=type_args,
|
|
501
353
|
)
|
|
354
|
+
|
|
502
355
|
return CallReturnWires(
|
|
503
356
|
regular_returns=[],
|
|
504
|
-
inout_returns=
|
|
357
|
+
inout_returns=[arr],
|
|
505
358
|
)
|
|
506
359
|
|
|
507
360
|
def compile_with_inouts(self, args: list[Wire]) -> CallReturnWires:
|
|
508
361
|
[array, idx, elem] = args
|
|
509
362
|
if self.elem_ty.type_bound() == ht.TypeBound.Linear:
|
|
510
|
-
|
|
511
|
-
func, already_exists = self.ctx.declare_global_func(
|
|
512
|
-
ARRAY_SETITEM_LINEAR, func_ty
|
|
513
|
-
)
|
|
514
|
-
if not already_exists:
|
|
515
|
-
self._build_linear_setitem(func)
|
|
363
|
+
return self._build_linear_setitem(array, idx, elem)
|
|
516
364
|
else:
|
|
517
|
-
|
|
518
|
-
func, already_exists = self.ctx.declare_global_func(
|
|
519
|
-
ARRAY_SETITEM_CLASSICAL, func_ty
|
|
520
|
-
)
|
|
521
|
-
if not already_exists:
|
|
522
|
-
self._build_classical_setitem(func)
|
|
523
|
-
return self._build_call_setitem(func=func, array=array, idx=idx, elem=elem)
|
|
365
|
+
return self._build_classical_setitem(array, idx, elem)
|
|
524
366
|
|
|
525
367
|
def compile(self, args: list[Wire]) -> list[Wire]:
|
|
526
368
|
raise InternalGuppyError("Call compile_with_inouts instead")
|
|
527
369
|
|
|
528
370
|
|
|
529
|
-
class
|
|
530
|
-
"""Compiler for the `
|
|
371
|
+
class ArrayDiscardAllUsedCompiler(ArrayCompiler):
|
|
372
|
+
"""Compiler for the `_array_discard_all_used` method."""
|
|
531
373
|
|
|
532
374
|
def compile(self, args: list[Wire]) -> list[Wire]:
|
|
533
|
-
# For linear array iterators, map the array of optional elements to an
|
|
534
|
-
# `array[None, n]` that we can discard.
|
|
535
375
|
if self.elem_ty.type_bound() == ht.TypeBound.Linear:
|
|
536
|
-
|
|
537
|
-
unit_ty = ht.UnitSum(1)
|
|
538
|
-
# Instantiate `unwrap_none` function
|
|
539
|
-
func = self.builder.load_function(
|
|
540
|
-
self.define_unwrap_none_helper(),
|
|
541
|
-
type_args=[ht.TypeTypeArg(self.elem_ty)],
|
|
542
|
-
instantiation=ht.FunctionType([elem_opt_ty], [unit_ty]),
|
|
543
|
-
)
|
|
544
|
-
# Map it over the array so that the resulting array is no longer linear and
|
|
545
|
-
# can be discarded
|
|
546
|
-
[array_iter] = args
|
|
547
|
-
array, _ = self.builder.add_op(ops.UnpackTuple(), array_iter)
|
|
376
|
+
[arr] = args
|
|
548
377
|
self.builder.add_op(
|
|
549
|
-
|
|
378
|
+
barray_discard_all_borrowed(self.elem_ty, self.length),
|
|
379
|
+
arr,
|
|
550
380
|
)
|
|
551
381
|
return []
|
|
552
|
-
|
|
553
|
-
def define_unwrap_none_helper(self) -> hf.Function:
|
|
554
|
-
"""Define an `unwrap_none` function that checks that the passed element is
|
|
555
|
-
indeed `None`."""
|
|
556
|
-
opt_ty = ht.Option(ht.Variable(0, ht.TypeBound.Linear))
|
|
557
|
-
unit_ty = ht.UnitSum(1)
|
|
558
|
-
func_ty = ht.PolyFuncType(
|
|
559
|
-
params=[ht.TypeTypeParam(ht.TypeBound.Linear)],
|
|
560
|
-
body=ht.FunctionType([opt_ty], [unit_ty]),
|
|
561
|
-
)
|
|
562
|
-
func, already_defined = self.ctx.declare_global_func(
|
|
563
|
-
ARRAY_ITER_ASSERT_ALL_USED_HELPER, func_ty
|
|
564
|
-
)
|
|
565
|
-
if not already_defined:
|
|
566
|
-
err_msg = "ArrayIter._assert_all_used: array element has not been used"
|
|
567
|
-
build_expect_none(func, func.inputs()[0], err_msg)
|
|
568
|
-
func.set_outputs(func.add_op(ops.MakeTuple()))
|
|
569
|
-
return func
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
from dataclasses import dataclass
|
|
2
2
|
|
|
3
|
+
import tket_exts
|
|
3
4
|
from hugr import val
|
|
4
5
|
from tket_exts import (
|
|
5
6
|
debug,
|
|
6
7
|
futures,
|
|
8
|
+
global_phase,
|
|
7
9
|
guppy,
|
|
8
|
-
|
|
10
|
+
modifier,
|
|
9
11
|
qsystem,
|
|
10
12
|
qsystem_random,
|
|
11
13
|
qsystem_utils,
|
|
@@ -15,10 +17,11 @@ from tket_exts import (
|
|
|
15
17
|
wasm,
|
|
16
18
|
)
|
|
17
19
|
|
|
18
|
-
BOOL_EXTENSION =
|
|
20
|
+
BOOL_EXTENSION = tket_exts.bool()
|
|
19
21
|
DEBUG_EXTENSION = debug()
|
|
20
22
|
FUTURES_EXTENSION = futures()
|
|
21
23
|
GUPPY_EXTENSION = guppy()
|
|
24
|
+
MODIFIER_EXTENSION = modifier()
|
|
22
25
|
QSYSTEM_EXTENSION = qsystem()
|
|
23
26
|
QSYSTEM_RANDOM_EXTENSION = qsystem_random()
|
|
24
27
|
QSYSTEM_UTILS_EXTENSION = qsystem_utils()
|
|
@@ -26,6 +29,8 @@ QUANTUM_EXTENSION = quantum()
|
|
|
26
29
|
RESULT_EXTENSION = result()
|
|
27
30
|
ROTATION_EXTENSION = rotation()
|
|
28
31
|
WASM_EXTENSION = wasm()
|
|
32
|
+
MODIFIER_EXTENSION = modifier()
|
|
33
|
+
GLOBAL_PHASE_EXTENSION = global_phase()
|
|
29
34
|
|
|
30
35
|
TKET_EXTENSIONS = [
|
|
31
36
|
BOOL_EXTENSION,
|
|
@@ -39,6 +44,8 @@ TKET_EXTENSIONS = [
|
|
|
39
44
|
RESULT_EXTENSION,
|
|
40
45
|
ROTATION_EXTENSION,
|
|
41
46
|
WASM_EXTENSION,
|
|
47
|
+
MODIFIER_EXTENSION,
|
|
48
|
+
GLOBAL_PHASE_EXTENSION,
|
|
42
49
|
]
|
|
43
50
|
|
|
44
51
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from typing import Any, TypeVar
|
|
2
2
|
|
|
3
3
|
from hugr import ops
|
|
4
|
-
from hugr import tys as ht
|
|
5
4
|
from hugr.build.dfg import DfBase
|
|
6
5
|
|
|
7
6
|
from guppylang_internals.ast_util import AstNode
|
|
@@ -13,7 +12,6 @@ from guppylang_internals.compiler.core import CompilerContext
|
|
|
13
12
|
from guppylang_internals.compiler.expr_compiler import python_value_to_hugr
|
|
14
13
|
from guppylang_internals.error import GuppyComptimeError, GuppyError
|
|
15
14
|
from guppylang_internals.std._internal.compiler.array import array_new, unpack_array
|
|
16
|
-
from guppylang_internals.std._internal.compiler.prelude import build_unwrap
|
|
17
15
|
from guppylang_internals.tracing.frozenlist import frozenlist
|
|
18
16
|
from guppylang_internals.tracing.object import (
|
|
19
17
|
GuppyObject,
|
|
@@ -71,9 +69,7 @@ def unpack_guppy_object(
|
|
|
71
69
|
# them as Guppy objects here
|
|
72
70
|
return obj
|
|
73
71
|
elem_ty = get_element_type(ty)
|
|
74
|
-
|
|
75
|
-
err = "Non-copyable array element has already been used"
|
|
76
|
-
elems = [build_unwrap(builder, opt_elem, err) for opt_elem in opt_elems]
|
|
72
|
+
elems = unpack_array(builder, obj._use_wire(None))
|
|
77
73
|
obj_list = [
|
|
78
74
|
unpack_guppy_object(GuppyObject(elem_ty, wire), builder, frozen)
|
|
79
75
|
for wire in elems
|
|
@@ -128,11 +124,8 @@ def guppy_object_from_py(
|
|
|
128
124
|
f"Element at index {i + 1} does not match the type of "
|
|
129
125
|
f"previous elements. Expected `{elem_ty}`, got `{obj._ty}`."
|
|
130
126
|
)
|
|
131
|
-
hugr_elem_ty =
|
|
132
|
-
wires = [
|
|
133
|
-
builder.add_op(ops.Tag(1, hugr_elem_ty), obj._use_wire(None))
|
|
134
|
-
for obj in objs
|
|
135
|
-
]
|
|
127
|
+
hugr_elem_ty = elem_ty.to_hugr(ctx)
|
|
128
|
+
wires = [obj._use_wire(None) for obj in objs]
|
|
136
129
|
return GuppyObject(
|
|
137
130
|
array_type(elem_ty, len(vs)),
|
|
138
131
|
builder.add_op(array_new(hugr_elem_ty, len(vs)), *wires),
|
|
@@ -172,26 +165,32 @@ def update_packed_value(v: Any, obj: "GuppyObject", builder: DfBase[P]) -> bool:
|
|
|
172
165
|
assert isinstance(obj._ty, NoneType)
|
|
173
166
|
case tuple(vs):
|
|
174
167
|
assert isinstance(obj._ty, TupleType)
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
168
|
+
wire_iterator = builder.add_op(
|
|
169
|
+
ops.UnpackTuple(), obj._use_wire(None)
|
|
170
|
+
).outputs()
|
|
171
|
+
for v, ty, out_wire in zip(
|
|
172
|
+
vs, obj._ty.element_types, wire_iterator, strict=True
|
|
173
|
+
):
|
|
174
|
+
success = update_packed_value(v, GuppyObject(ty, out_wire), builder)
|
|
178
175
|
if not success:
|
|
179
176
|
return False
|
|
180
177
|
case GuppyStructObject(_ty=ty, _field_values=values):
|
|
181
178
|
assert obj._ty == ty
|
|
182
|
-
|
|
183
|
-
|
|
179
|
+
wire_iterator = builder.add_op(
|
|
180
|
+
ops.UnpackTuple(), obj._use_wire(None)
|
|
181
|
+
).outputs()
|
|
182
|
+
for field, out_wire in zip(ty.fields, wire_iterator, strict=True):
|
|
184
183
|
v = values[field.name]
|
|
185
|
-
success = update_packed_value(
|
|
184
|
+
success = update_packed_value(
|
|
185
|
+
v, GuppyObject(field.ty, out_wire), builder
|
|
186
|
+
)
|
|
186
187
|
if not success:
|
|
187
188
|
values[field.name] = obj
|
|
188
189
|
case list(vs) if len(vs) > 0:
|
|
189
190
|
assert is_array_type(obj._ty)
|
|
190
191
|
elem_ty = get_element_type(obj._ty)
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
for i, (v, opt_wire) in enumerate(zip(vs, opt_wires, strict=True)):
|
|
194
|
-
(wire,) = build_unwrap(builder, opt_wire, err).outputs()
|
|
192
|
+
wires = unpack_array(builder, obj._use_wire(None))
|
|
193
|
+
for i, (v, wire) in enumerate(zip(vs, wires, strict=True)):
|
|
195
194
|
success = update_packed_value(v, GuppyObject(elem_ty, wire), builder)
|
|
196
195
|
if not success:
|
|
197
196
|
vs[i] = obj
|
guppylang_internals/tys/arg.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from abc import ABC, abstractmethod
|
|
2
|
-
from dataclasses import dataclass
|
|
2
|
+
from dataclasses import dataclass, field
|
|
3
3
|
from typing import TYPE_CHECKING, TypeAlias
|
|
4
4
|
|
|
5
5
|
from hugr import tys as ht
|
|
@@ -18,7 +18,7 @@ from guppylang_internals.tys.const import (
|
|
|
18
18
|
ConstValue,
|
|
19
19
|
ExistentialConstVar,
|
|
20
20
|
)
|
|
21
|
-
from guppylang_internals.tys.var import ExistentialVar
|
|
21
|
+
from guppylang_internals.tys.var import BoundVar, ExistentialVar
|
|
22
22
|
|
|
23
23
|
if TYPE_CHECKING:
|
|
24
24
|
from guppylang_internals.tys.ty import Type
|
|
@@ -45,19 +45,29 @@ class ArgumentBase(ToHugr[ht.TypeArg], Transformable["Argument"], ABC):
|
|
|
45
45
|
def unsolved_vars(self) -> set[ExistentialVar]:
|
|
46
46
|
"""The existential type variables contained in this argument."""
|
|
47
47
|
|
|
48
|
+
@property
|
|
49
|
+
@abstractmethod
|
|
50
|
+
def bound_vars(self) -> set[BoundVar]:
|
|
51
|
+
"""The bound type variables contained in this argument."""
|
|
52
|
+
|
|
48
53
|
|
|
49
54
|
@dataclass(frozen=True)
|
|
50
55
|
class TypeArg(ArgumentBase):
|
|
51
56
|
"""Argument that can be instantiated for a `TypeParameter`."""
|
|
52
57
|
|
|
53
58
|
# The type to instantiate
|
|
54
|
-
ty: "Type"
|
|
59
|
+
ty: "Type" = field(hash=False) # Types are not hashable
|
|
55
60
|
|
|
56
61
|
@property
|
|
57
62
|
def unsolved_vars(self) -> set[ExistentialVar]:
|
|
58
63
|
"""The existential type variables contained in this argument."""
|
|
59
64
|
return self.ty.unsolved_vars
|
|
60
65
|
|
|
66
|
+
@property
|
|
67
|
+
def bound_vars(self) -> set[BoundVar]:
|
|
68
|
+
"""The bound type variables contained in this type."""
|
|
69
|
+
return self.ty.bound_vars
|
|
70
|
+
|
|
61
71
|
def to_hugr(self, ctx: ToHugrContext) -> ht.TypeTypeArg:
|
|
62
72
|
"""Computes the Hugr representation of the argument."""
|
|
63
73
|
ty: ht.Type = self.ty.to_hugr(ctx)
|
|
@@ -84,6 +94,11 @@ class ConstArg(ArgumentBase):
|
|
|
84
94
|
"""The existential const variables contained in this argument."""
|
|
85
95
|
return self.const.unsolved_vars
|
|
86
96
|
|
|
97
|
+
@property
|
|
98
|
+
def bound_vars(self) -> set[BoundVar]:
|
|
99
|
+
"""The bound type variables contained in this argument."""
|
|
100
|
+
return self.const.bound_vars
|
|
101
|
+
|
|
87
102
|
def to_hugr(self, ctx: ToHugrContext) -> ht.TypeArg:
|
|
88
103
|
"""Computes the Hugr representation of this argument."""
|
|
89
104
|
from guppylang_internals.tys.ty import NumericType
|