guppylang-internals 0.27.0__py3-none-any.whl → 0.28.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 +37 -18
- guppylang_internals/cfg/analysis.py +6 -6
- guppylang_internals/cfg/builder.py +41 -12
- guppylang_internals/cfg/cfg.py +1 -1
- guppylang_internals/checker/core.py +1 -1
- guppylang_internals/checker/errors/comptime_errors.py +0 -12
- guppylang_internals/checker/expr_checker.py +27 -17
- guppylang_internals/checker/func_checker.py +4 -3
- guppylang_internals/checker/stmt_checker.py +1 -1
- guppylang_internals/compiler/cfg_compiler.py +1 -1
- guppylang_internals/compiler/core.py +17 -4
- guppylang_internals/compiler/expr_compiler.py +9 -9
- guppylang_internals/decorator.py +2 -2
- guppylang_internals/definition/common.py +1 -0
- guppylang_internals/definition/custom.py +2 -2
- guppylang_internals/definition/declaration.py +3 -3
- guppylang_internals/definition/function.py +8 -1
- guppylang_internals/definition/metadata.py +1 -1
- guppylang_internals/definition/pytket_circuits.py +44 -65
- guppylang_internals/definition/value.py +1 -1
- guppylang_internals/definition/wasm.py +3 -3
- guppylang_internals/diagnostic.py +17 -1
- guppylang_internals/engine.py +83 -30
- guppylang_internals/error.py +1 -1
- guppylang_internals/nodes.py +269 -3
- guppylang_internals/span.py +7 -3
- guppylang_internals/std/_internal/checker.py +104 -2
- guppylang_internals/std/_internal/debug.py +5 -3
- guppylang_internals/tracing/builtins_mock.py +2 -2
- guppylang_internals/tracing/object.py +2 -2
- guppylang_internals/tys/parsing.py +4 -1
- guppylang_internals/tys/qubit.py +6 -4
- guppylang_internals/tys/subst.py +2 -2
- guppylang_internals/tys/ty.py +2 -2
- guppylang_internals/wasm_util.py +1 -2
- {guppylang_internals-0.27.0.dist-info → guppylang_internals-0.28.0.dist-info}/METADATA +5 -4
- {guppylang_internals-0.27.0.dist-info → guppylang_internals-0.28.0.dist-info}/RECORD +40 -40
- {guppylang_internals-0.27.0.dist-info → guppylang_internals-0.28.0.dist-info}/WHEEL +0 -0
- {guppylang_internals-0.27.0.dist-info → guppylang_internals-0.28.0.dist-info}/licenses/LICENCE +0 -0
guppylang_internals/nodes.py
CHANGED
|
@@ -31,6 +31,14 @@ class PlaceNode(ast.expr):
|
|
|
31
31
|
|
|
32
32
|
_fields = ("place",)
|
|
33
33
|
|
|
34
|
+
def __init__(self, place: "Place") -> None:
|
|
35
|
+
super().__init__()
|
|
36
|
+
self.place = place
|
|
37
|
+
|
|
38
|
+
# See MakeIter for explanation
|
|
39
|
+
__reduce__ = object.__reduce__
|
|
40
|
+
__reduce_ex__ = object.__reduce_ex__
|
|
41
|
+
|
|
34
42
|
|
|
35
43
|
class GlobalName(ast.Name):
|
|
36
44
|
id: str
|
|
@@ -41,6 +49,15 @@ class GlobalName(ast.Name):
|
|
|
41
49
|
"def_id",
|
|
42
50
|
)
|
|
43
51
|
|
|
52
|
+
def __init__(self, id: str, def_id: "DefId") -> None:
|
|
53
|
+
super().__init__(id=id)
|
|
54
|
+
self.id = id
|
|
55
|
+
self.def_id = def_id
|
|
56
|
+
|
|
57
|
+
# See MakeIter for explanation
|
|
58
|
+
__reduce__ = object.__reduce__
|
|
59
|
+
__reduce_ex__ = object.__reduce_ex__
|
|
60
|
+
|
|
44
61
|
|
|
45
62
|
class GenericParamValue(ast.Name):
|
|
46
63
|
id: str
|
|
@@ -51,6 +68,15 @@ class GenericParamValue(ast.Name):
|
|
|
51
68
|
"param",
|
|
52
69
|
)
|
|
53
70
|
|
|
71
|
+
def __init__(self, id: str, param: "ConstParam") -> None:
|
|
72
|
+
super().__init__(id=id)
|
|
73
|
+
self.id = id
|
|
74
|
+
self.param = param
|
|
75
|
+
|
|
76
|
+
# See MakeIter for explanation
|
|
77
|
+
__reduce__ = object.__reduce__
|
|
78
|
+
__reduce_ex__ = object.__reduce_ex__
|
|
79
|
+
|
|
54
80
|
|
|
55
81
|
class LocalCall(ast.expr):
|
|
56
82
|
func: ast.expr
|
|
@@ -61,6 +87,15 @@ class LocalCall(ast.expr):
|
|
|
61
87
|
"args",
|
|
62
88
|
)
|
|
63
89
|
|
|
90
|
+
def __init__(self, func: ast.expr, args: list[ast.expr]) -> None:
|
|
91
|
+
super().__init__()
|
|
92
|
+
self.func = func
|
|
93
|
+
self.args = args
|
|
94
|
+
|
|
95
|
+
# See MakeIter for explanation
|
|
96
|
+
__reduce__ = object.__reduce__
|
|
97
|
+
__reduce_ex__ = object.__reduce_ex__
|
|
98
|
+
|
|
64
99
|
|
|
65
100
|
class GlobalCall(ast.expr):
|
|
66
101
|
def_id: "DefId"
|
|
@@ -73,6 +108,16 @@ class GlobalCall(ast.expr):
|
|
|
73
108
|
"type_args",
|
|
74
109
|
)
|
|
75
110
|
|
|
111
|
+
def __init__(self, def_id: "DefId", args: list[ast.expr], type_args: Inst) -> None:
|
|
112
|
+
super().__init__()
|
|
113
|
+
self.def_id = def_id
|
|
114
|
+
self.args = args
|
|
115
|
+
self.type_args = type_args
|
|
116
|
+
|
|
117
|
+
# See MakeIter for explanation
|
|
118
|
+
__reduce__ = object.__reduce__
|
|
119
|
+
__reduce_ex__ = object.__reduce_ex__
|
|
120
|
+
|
|
76
121
|
|
|
77
122
|
class TensorCall(ast.expr):
|
|
78
123
|
"""A call to a tuple of functions. Behaves like a local call, but more
|
|
@@ -88,6 +133,18 @@ class TensorCall(ast.expr):
|
|
|
88
133
|
"tensor_ty",
|
|
89
134
|
)
|
|
90
135
|
|
|
136
|
+
def __init__(
|
|
137
|
+
self, func: ast.expr, args: list[ast.expr], tensor_ty: FunctionType
|
|
138
|
+
) -> None:
|
|
139
|
+
super().__init__()
|
|
140
|
+
self.func = func
|
|
141
|
+
self.args = args
|
|
142
|
+
self.tensor_ty = tensor_ty
|
|
143
|
+
|
|
144
|
+
# See MakeIter for explanation
|
|
145
|
+
__reduce__ = object.__reduce__
|
|
146
|
+
__reduce_ex__ = object.__reduce_ex__
|
|
147
|
+
|
|
91
148
|
|
|
92
149
|
class TypeApply(ast.expr):
|
|
93
150
|
value: ast.expr
|
|
@@ -98,6 +155,15 @@ class TypeApply(ast.expr):
|
|
|
98
155
|
"inst",
|
|
99
156
|
)
|
|
100
157
|
|
|
158
|
+
def __init__(self, value: ast.expr, inst: Inst) -> None:
|
|
159
|
+
super().__init__()
|
|
160
|
+
self.value = value
|
|
161
|
+
self.inst = inst
|
|
162
|
+
|
|
163
|
+
# See MakeIter for explanation
|
|
164
|
+
__reduce__ = object.__reduce__
|
|
165
|
+
__reduce_ex__ = object.__reduce_ex__
|
|
166
|
+
|
|
101
167
|
|
|
102
168
|
class PartialApply(ast.expr):
|
|
103
169
|
"""A partial function application.
|
|
@@ -114,6 +180,15 @@ class PartialApply(ast.expr):
|
|
|
114
180
|
"args",
|
|
115
181
|
)
|
|
116
182
|
|
|
183
|
+
def __init__(self, func: ast.expr, args: list[ast.expr]) -> None:
|
|
184
|
+
super().__init__()
|
|
185
|
+
self.func = func
|
|
186
|
+
self.args = args
|
|
187
|
+
|
|
188
|
+
# See MakeIter for explanation
|
|
189
|
+
__reduce__ = object.__reduce__
|
|
190
|
+
__reduce_ex__ = object.__reduce_ex__
|
|
191
|
+
|
|
117
192
|
|
|
118
193
|
class FieldAccessAndDrop(ast.expr):
|
|
119
194
|
"""A field access on a struct, dropping all the remaining other fields."""
|
|
@@ -128,6 +203,18 @@ class FieldAccessAndDrop(ast.expr):
|
|
|
128
203
|
"field",
|
|
129
204
|
)
|
|
130
205
|
|
|
206
|
+
def __init__(
|
|
207
|
+
self, value: ast.expr, struct_ty: "StructType", field: "StructField"
|
|
208
|
+
) -> None:
|
|
209
|
+
super().__init__()
|
|
210
|
+
self.value = value
|
|
211
|
+
self.struct_ty = struct_ty
|
|
212
|
+
self.field = field
|
|
213
|
+
|
|
214
|
+
# See MakeIter for explanation
|
|
215
|
+
__reduce__ = object.__reduce__
|
|
216
|
+
__reduce_ex__ = object.__reduce_ex__
|
|
217
|
+
|
|
131
218
|
|
|
132
219
|
class SubscriptAccessAndDrop(ast.expr):
|
|
133
220
|
"""A subscript element access on an object, dropping all the remaining items."""
|
|
@@ -139,6 +226,23 @@ class SubscriptAccessAndDrop(ast.expr):
|
|
|
139
226
|
|
|
140
227
|
_fields = ("item", "item_expr", "getitem_expr", "original_expr")
|
|
141
228
|
|
|
229
|
+
def __init__(
|
|
230
|
+
self,
|
|
231
|
+
item: "Variable",
|
|
232
|
+
item_expr: ast.expr,
|
|
233
|
+
getitem_expr: ast.expr,
|
|
234
|
+
original_expr: ast.Subscript,
|
|
235
|
+
) -> None:
|
|
236
|
+
super().__init__()
|
|
237
|
+
self.item = item
|
|
238
|
+
self.item_expr = item_expr
|
|
239
|
+
self.getitem_expr = getitem_expr
|
|
240
|
+
self.original_expr = original_expr
|
|
241
|
+
|
|
242
|
+
# See MakeIter for explanation
|
|
243
|
+
__reduce__ = object.__reduce__
|
|
244
|
+
__reduce_ex__ = object.__reduce_ex__
|
|
245
|
+
|
|
142
246
|
|
|
143
247
|
class TupleAccessAndDrop(ast.expr):
|
|
144
248
|
"""A subscript element access on a tuple, dropping all the remaining items."""
|
|
@@ -149,6 +253,16 @@ class TupleAccessAndDrop(ast.expr):
|
|
|
149
253
|
|
|
150
254
|
_fields = ("value", "tuple_ty", "index")
|
|
151
255
|
|
|
256
|
+
def __init__(self, value: ast.expr, tuple_ty: TupleType, index: int) -> None:
|
|
257
|
+
super().__init__()
|
|
258
|
+
self.value = value
|
|
259
|
+
self.tuple_ty = tuple_ty
|
|
260
|
+
self.index = index
|
|
261
|
+
|
|
262
|
+
# See MakeIter for explanation
|
|
263
|
+
__reduce__ = object.__reduce__
|
|
264
|
+
__reduce_ex__ = object.__reduce_ex__
|
|
265
|
+
|
|
152
266
|
|
|
153
267
|
class MakeIter(ast.expr):
|
|
154
268
|
"""Creates an iterator using the `__iter__` magic method.
|
|
@@ -168,7 +282,8 @@ class MakeIter(ast.expr):
|
|
|
168
282
|
def __init__(
|
|
169
283
|
self, value: ast.expr, origin_node: ast.AST, unwrap_size_hint: bool = True
|
|
170
284
|
) -> None:
|
|
171
|
-
super().__init__(
|
|
285
|
+
super().__init__()
|
|
286
|
+
self.value = value
|
|
172
287
|
self.origin_node = origin_node
|
|
173
288
|
self.unwrap_size_hint = unwrap_size_hint
|
|
174
289
|
|
|
@@ -191,6 +306,14 @@ class IterNext(ast.expr):
|
|
|
191
306
|
|
|
192
307
|
_fields = ("value",)
|
|
193
308
|
|
|
309
|
+
def __init__(self, value: ast.expr) -> None:
|
|
310
|
+
super().__init__()
|
|
311
|
+
self.value = value
|
|
312
|
+
|
|
313
|
+
# See MakeIter for explanation
|
|
314
|
+
__reduce__ = object.__reduce__
|
|
315
|
+
__reduce_ex__ = object.__reduce_ex__
|
|
316
|
+
|
|
194
317
|
|
|
195
318
|
class DesugaredGenerator(ast.expr):
|
|
196
319
|
"""A single desugared generator in a list comprehension.
|
|
@@ -215,6 +338,27 @@ class DesugaredGenerator(ast.expr):
|
|
|
215
338
|
"ifs",
|
|
216
339
|
)
|
|
217
340
|
|
|
341
|
+
def __init__(
|
|
342
|
+
self,
|
|
343
|
+
iter_assign: ast.Assign,
|
|
344
|
+
next_call: ast.expr,
|
|
345
|
+
iter: ast.expr,
|
|
346
|
+
target: ast.expr,
|
|
347
|
+
ifs: list[ast.expr],
|
|
348
|
+
used_outer_places: "list[Place]",
|
|
349
|
+
) -> None:
|
|
350
|
+
super().__init__()
|
|
351
|
+
self.iter_assign = iter_assign
|
|
352
|
+
self.next_call = next_call
|
|
353
|
+
self.iter = iter
|
|
354
|
+
self.target = target
|
|
355
|
+
self.ifs = ifs
|
|
356
|
+
self.used_outer_places = used_outer_places
|
|
357
|
+
|
|
358
|
+
# See MakeIter for explanation
|
|
359
|
+
__reduce__ = object.__reduce__
|
|
360
|
+
__reduce_ex__ = object.__reduce_ex__
|
|
361
|
+
|
|
218
362
|
|
|
219
363
|
class DesugaredGeneratorExpr(ast.expr):
|
|
220
364
|
"""A desugared generator expression."""
|
|
@@ -227,6 +371,15 @@ class DesugaredGeneratorExpr(ast.expr):
|
|
|
227
371
|
"generators",
|
|
228
372
|
)
|
|
229
373
|
|
|
374
|
+
def __init__(self, elt: ast.expr, generators: list[DesugaredGenerator]) -> None:
|
|
375
|
+
super().__init__()
|
|
376
|
+
self.elt = elt
|
|
377
|
+
self.generators = generators
|
|
378
|
+
|
|
379
|
+
# See MakeIter for explanation
|
|
380
|
+
__reduce__ = object.__reduce__
|
|
381
|
+
__reduce_ex__ = object.__reduce_ex__
|
|
382
|
+
|
|
230
383
|
|
|
231
384
|
class DesugaredListComp(ast.expr):
|
|
232
385
|
"""A desugared list comprehension."""
|
|
@@ -239,6 +392,15 @@ class DesugaredListComp(ast.expr):
|
|
|
239
392
|
"generators",
|
|
240
393
|
)
|
|
241
394
|
|
|
395
|
+
def __init__(self, elt: ast.expr, generators: list[DesugaredGenerator]) -> None:
|
|
396
|
+
super().__init__()
|
|
397
|
+
self.elt = elt
|
|
398
|
+
self.generators = generators
|
|
399
|
+
|
|
400
|
+
# See MakeIter for explanation
|
|
401
|
+
__reduce__ = object.__reduce__
|
|
402
|
+
__reduce_ex__ = object.__reduce_ex__
|
|
403
|
+
|
|
242
404
|
|
|
243
405
|
class DesugaredArrayComp(ast.expr):
|
|
244
406
|
"""A desugared array comprehension."""
|
|
@@ -255,6 +417,19 @@ class DesugaredArrayComp(ast.expr):
|
|
|
255
417
|
"elt_ty",
|
|
256
418
|
)
|
|
257
419
|
|
|
420
|
+
def __init__(
|
|
421
|
+
self, elt: ast.expr, generator: DesugaredGenerator, length: Const, elt_ty: Type
|
|
422
|
+
) -> None:
|
|
423
|
+
super().__init__()
|
|
424
|
+
self.elt = elt
|
|
425
|
+
self.generator = generator
|
|
426
|
+
self.length = length
|
|
427
|
+
self.elt_ty = elt_ty
|
|
428
|
+
|
|
429
|
+
# See MakeIter for explanation
|
|
430
|
+
__reduce__ = object.__reduce__
|
|
431
|
+
__reduce_ex__ = object.__reduce_ex__
|
|
432
|
+
|
|
258
433
|
|
|
259
434
|
class ComptimeExpr(ast.expr):
|
|
260
435
|
"""A compile-time evaluated `py(...)` expression."""
|
|
@@ -263,6 +438,14 @@ class ComptimeExpr(ast.expr):
|
|
|
263
438
|
|
|
264
439
|
_fields = ("value",)
|
|
265
440
|
|
|
441
|
+
def __init__(self, value: ast.expr) -> None:
|
|
442
|
+
super().__init__()
|
|
443
|
+
self.value = value
|
|
444
|
+
|
|
445
|
+
# See MakeIter for explanation
|
|
446
|
+
__reduce__ = object.__reduce__
|
|
447
|
+
__reduce_ex__ = object.__reduce_ex__
|
|
448
|
+
|
|
266
449
|
|
|
267
450
|
class ExitKind(Enum):
|
|
268
451
|
ExitShot = 0 # Exit the current shot
|
|
@@ -279,6 +462,19 @@ class PanicExpr(ast.expr):
|
|
|
279
462
|
|
|
280
463
|
_fields = ("kind", "signal", "msg", "values")
|
|
281
464
|
|
|
465
|
+
def __init__(
|
|
466
|
+
self, kind: ExitKind, signal: ast.expr, msg: ast.expr, values: list[ast.expr]
|
|
467
|
+
) -> None:
|
|
468
|
+
super().__init__()
|
|
469
|
+
self.kind = kind
|
|
470
|
+
self.signal = signal
|
|
471
|
+
self.msg = msg
|
|
472
|
+
self.values = values
|
|
473
|
+
|
|
474
|
+
# See MakeIter for explanation
|
|
475
|
+
__reduce__ = object.__reduce__
|
|
476
|
+
__reduce_ex__ = object.__reduce_ex__
|
|
477
|
+
|
|
282
478
|
|
|
283
479
|
class BarrierExpr(ast.expr):
|
|
284
480
|
"""A `barrier(*args)` expression."""
|
|
@@ -287,6 +483,15 @@ class BarrierExpr(ast.expr):
|
|
|
287
483
|
func_ty: FunctionType
|
|
288
484
|
_fields = ("args", "func_ty")
|
|
289
485
|
|
|
486
|
+
def __init__(self, args: list[ast.expr], func_ty: FunctionType) -> None:
|
|
487
|
+
super().__init__()
|
|
488
|
+
self.args = args
|
|
489
|
+
self.func_ty = func_ty
|
|
490
|
+
|
|
491
|
+
# See MakeIter for explanation
|
|
492
|
+
__reduce__ = object.__reduce__
|
|
493
|
+
__reduce_ex__ = object.__reduce_ex__
|
|
494
|
+
|
|
290
495
|
|
|
291
496
|
class StateResultExpr(ast.expr):
|
|
292
497
|
"""A `state_result(tag, *args)` expression."""
|
|
@@ -299,6 +504,25 @@ class StateResultExpr(ast.expr):
|
|
|
299
504
|
array_len: Const | None
|
|
300
505
|
_fields = ("tag_value", "tag_expr", "args", "func_ty", "has_array_input")
|
|
301
506
|
|
|
507
|
+
def __init__(
|
|
508
|
+
self,
|
|
509
|
+
tag_value: Const,
|
|
510
|
+
tag_expr: ast.expr,
|
|
511
|
+
args: list[ast.expr],
|
|
512
|
+
func_ty: FunctionType,
|
|
513
|
+
array_len: Const | None,
|
|
514
|
+
) -> None:
|
|
515
|
+
super().__init__()
|
|
516
|
+
self.tag_value = tag_value
|
|
517
|
+
self.tag_expr = tag_expr
|
|
518
|
+
self.args = args
|
|
519
|
+
self.func_ty = func_ty
|
|
520
|
+
self.array_len = array_len
|
|
521
|
+
|
|
522
|
+
# See MakeIter for explanation
|
|
523
|
+
__reduce__ = object.__reduce__
|
|
524
|
+
__reduce_ex__ = object.__reduce_ex__
|
|
525
|
+
|
|
302
526
|
|
|
303
527
|
AnyCall = LocalCall | GlobalCall | TensorCall | BarrierExpr | StateResultExpr
|
|
304
528
|
|
|
@@ -311,6 +535,14 @@ class InoutReturnSentinel(ast.expr):
|
|
|
311
535
|
|
|
312
536
|
_fields = ("var",)
|
|
313
537
|
|
|
538
|
+
def __init__(self, var: "Place | str") -> None:
|
|
539
|
+
super().__init__()
|
|
540
|
+
self.var = var
|
|
541
|
+
|
|
542
|
+
# See MakeIter for explanation
|
|
543
|
+
__reduce__ = object.__reduce__
|
|
544
|
+
__reduce_ex__ = object.__reduce_ex__
|
|
545
|
+
|
|
314
546
|
|
|
315
547
|
class UnpackPattern(ast.expr):
|
|
316
548
|
"""The LHS of an unpacking assignment like `a, *bs, c = ...` or
|
|
@@ -328,6 +560,18 @@ class UnpackPattern(ast.expr):
|
|
|
328
560
|
|
|
329
561
|
_fields = ("left", "starred", "right")
|
|
330
562
|
|
|
563
|
+
def __init__(
|
|
564
|
+
self, left: list[ast.expr], starred: ast.expr | None, right: list[ast.expr]
|
|
565
|
+
) -> None:
|
|
566
|
+
super().__init__()
|
|
567
|
+
self.left = left
|
|
568
|
+
self.starred = starred
|
|
569
|
+
self.right = right
|
|
570
|
+
|
|
571
|
+
# See MakeIter for explanation
|
|
572
|
+
__reduce__ = object.__reduce__
|
|
573
|
+
__reduce_ex__ = object.__reduce_ex__
|
|
574
|
+
|
|
331
575
|
|
|
332
576
|
class TupleUnpack(ast.expr):
|
|
333
577
|
"""The LHS of an unpacking assignment of a tuple."""
|
|
@@ -337,6 +581,14 @@ class TupleUnpack(ast.expr):
|
|
|
337
581
|
|
|
338
582
|
_fields = ("pattern",)
|
|
339
583
|
|
|
584
|
+
def __init__(self, pattern: UnpackPattern) -> None:
|
|
585
|
+
super().__init__()
|
|
586
|
+
self.pattern = pattern
|
|
587
|
+
|
|
588
|
+
# See MakeIter for explanation
|
|
589
|
+
__reduce__ = object.__reduce__
|
|
590
|
+
__reduce_ex__ = object.__reduce_ex__
|
|
591
|
+
|
|
340
592
|
|
|
341
593
|
class ArrayUnpack(ast.expr):
|
|
342
594
|
"""The LHS of an unpacking assignment of an array."""
|
|
@@ -353,7 +605,8 @@ class ArrayUnpack(ast.expr):
|
|
|
353
605
|
_fields = ("pattern",)
|
|
354
606
|
|
|
355
607
|
def __init__(self, pattern: UnpackPattern, length: int, elt_type: Type) -> None:
|
|
356
|
-
super().__init__(
|
|
608
|
+
super().__init__()
|
|
609
|
+
self.pattern = pattern
|
|
357
610
|
self.length = length
|
|
358
611
|
self.elt_type = elt_type
|
|
359
612
|
|
|
@@ -381,7 +634,8 @@ class IterableUnpack(ast.expr):
|
|
|
381
634
|
def __init__(
|
|
382
635
|
self, pattern: UnpackPattern, compr: DesugaredArrayComp, rhs_var: PlaceNode
|
|
383
636
|
) -> None:
|
|
384
|
-
super().__init__(
|
|
637
|
+
super().__init__()
|
|
638
|
+
self.pattern = pattern
|
|
385
639
|
self.compr = compr
|
|
386
640
|
self.rhs_var = rhs_var
|
|
387
641
|
|
|
@@ -404,6 +658,10 @@ class NestedFunctionDef(ast.FunctionDef):
|
|
|
404
658
|
self.cfg = cfg
|
|
405
659
|
self.ty = ty
|
|
406
660
|
|
|
661
|
+
# See MakeIter for explanation
|
|
662
|
+
__reduce__ = object.__reduce__
|
|
663
|
+
__reduce_ex__ = object.__reduce_ex__
|
|
664
|
+
|
|
407
665
|
|
|
408
666
|
class CheckedNestedFunctionDef(ast.FunctionDef):
|
|
409
667
|
def_id: "DefId"
|
|
@@ -429,6 +687,10 @@ class CheckedNestedFunctionDef(ast.FunctionDef):
|
|
|
429
687
|
self.ty = ty
|
|
430
688
|
self.captured = captured
|
|
431
689
|
|
|
690
|
+
# See MakeIter for explanation
|
|
691
|
+
__reduce__ = object.__reduce__
|
|
692
|
+
__reduce_ex__ = object.__reduce_ex__
|
|
693
|
+
|
|
432
694
|
|
|
433
695
|
class Dagger(ast.expr):
|
|
434
696
|
"""The dagger modifier"""
|
|
@@ -491,6 +753,10 @@ class ModifiedBlock(ast.With):
|
|
|
491
753
|
self.control = []
|
|
492
754
|
self.power = []
|
|
493
755
|
|
|
756
|
+
# See MakeIter for explanation
|
|
757
|
+
__reduce__ = object.__reduce__
|
|
758
|
+
__reduce_ex__ = object.__reduce_ex__
|
|
759
|
+
|
|
494
760
|
def is_dagger(self) -> bool:
|
|
495
761
|
return len(self.dagger) % 2 == 1
|
|
496
762
|
|
guppylang_internals/span.py
CHANGED
|
@@ -113,11 +113,15 @@ def to_span(x: ToSpan) -> Span:
|
|
|
113
113
|
assert file is not None
|
|
114
114
|
assert line_offset is not None
|
|
115
115
|
# x.lineno and line_offset both start at 1, so we have to subtract 1
|
|
116
|
-
start = Loc(
|
|
116
|
+
start = Loc(
|
|
117
|
+
file,
|
|
118
|
+
x.lineno + line_offset - 1, # type: ignore[attr-defined]
|
|
119
|
+
x.col_offset, # type: ignore[attr-defined]
|
|
120
|
+
)
|
|
117
121
|
end = Loc(
|
|
118
122
|
file,
|
|
119
|
-
(x.end_lineno or x.lineno) + line_offset - 1,
|
|
120
|
-
x.end_col_offset or x.col_offset,
|
|
123
|
+
(x.end_lineno or x.lineno) + line_offset - 1, # type: ignore[attr-defined]
|
|
124
|
+
x.end_col_offset or x.col_offset, # type: ignore[attr-defined]
|
|
121
125
|
)
|
|
122
126
|
return Span(start, end)
|
|
123
127
|
|
|
@@ -5,7 +5,7 @@ from typing import ClassVar
|
|
|
5
5
|
from typing_extensions import assert_never
|
|
6
6
|
|
|
7
7
|
from guppylang_internals.ast_util import get_type, with_loc, with_type
|
|
8
|
-
from guppylang_internals.checker.core import Context
|
|
8
|
+
from guppylang_internals.checker.core import Context, Variable
|
|
9
9
|
from guppylang_internals.checker.errors.generic import UnsupportedError
|
|
10
10
|
from guppylang_internals.checker.errors.type_errors import (
|
|
11
11
|
ArrayComprUnknownSizeError,
|
|
@@ -33,6 +33,7 @@ from guppylang_internals.nodes import (
|
|
|
33
33
|
GlobalCall,
|
|
34
34
|
MakeIter,
|
|
35
35
|
PanicExpr,
|
|
36
|
+
PlaceNode,
|
|
36
37
|
)
|
|
37
38
|
from guppylang_internals.tys.arg import ConstArg, TypeArg
|
|
38
39
|
from guppylang_internals.tys.builtin import (
|
|
@@ -172,6 +173,105 @@ class ArrayCopyChecker(CustomCallChecker):
|
|
|
172
173
|
return with_loc(self.node, node), get_type(array_arg)
|
|
173
174
|
|
|
174
175
|
|
|
176
|
+
class ArrayIndexChecker(CustomCallChecker):
|
|
177
|
+
"""Performs compile-time bounds checking for array indexing.
|
|
178
|
+
|
|
179
|
+
When the array size is statically known and the index is a literal constant,
|
|
180
|
+
this checker validates that the index is within bounds and raises an error
|
|
181
|
+
at compile time if it's not.
|
|
182
|
+
"""
|
|
183
|
+
|
|
184
|
+
@dataclass(frozen=True)
|
|
185
|
+
class IndexOutOfBoundsError(Error):
|
|
186
|
+
title: ClassVar[str] = "Index out of bounds"
|
|
187
|
+
span_label: ClassVar[str] = (
|
|
188
|
+
"Array index {index} is out of bounds for array of size {size}."
|
|
189
|
+
)
|
|
190
|
+
index: int
|
|
191
|
+
size: int
|
|
192
|
+
|
|
193
|
+
def __init__(self, *, expr_index: int = 1):
|
|
194
|
+
"""
|
|
195
|
+
Args:
|
|
196
|
+
expr_index: Position of the expression index argument (0 based)
|
|
197
|
+
"""
|
|
198
|
+
self.expr_index: int = expr_index
|
|
199
|
+
|
|
200
|
+
def _extract_constant_index(self, index_expr: ast.expr) -> int | None:
|
|
201
|
+
"""Extract a constant integer value from an index expression if possible.
|
|
202
|
+
|
|
203
|
+
Handles both AST constants and PlaceNode structures.
|
|
204
|
+
"""
|
|
205
|
+
# Case 1: Simple AST constant (e.g., arr.take(0))
|
|
206
|
+
if isinstance(index_expr, ast.Constant) and isinstance(index_expr.value, int):
|
|
207
|
+
return index_expr.value
|
|
208
|
+
|
|
209
|
+
# Case 2: Subscript accesses (e.g., arr[0])
|
|
210
|
+
if isinstance(index_expr, PlaceNode):
|
|
211
|
+
place = index_expr.place
|
|
212
|
+
if isinstance(place, Variable):
|
|
213
|
+
defined_at = place.defined_at
|
|
214
|
+
if isinstance(defined_at, ast.Constant) and isinstance(
|
|
215
|
+
defined_at.value, int
|
|
216
|
+
):
|
|
217
|
+
return defined_at.value
|
|
218
|
+
|
|
219
|
+
return None
|
|
220
|
+
|
|
221
|
+
def _check_constant_index_bounds(
|
|
222
|
+
self, index_expr: ast.expr, length_arg: TypeArg | ConstArg
|
|
223
|
+
) -> None:
|
|
224
|
+
"""Perform compile-time bounds checking if size and index are constant."""
|
|
225
|
+
|
|
226
|
+
# Check if array size is statically known
|
|
227
|
+
if not (
|
|
228
|
+
isinstance(length_arg, ConstArg)
|
|
229
|
+
and isinstance(length_arg.const, ConstValue)
|
|
230
|
+
):
|
|
231
|
+
return
|
|
232
|
+
|
|
233
|
+
array_length = length_arg.const.value
|
|
234
|
+
|
|
235
|
+
index_value = self._extract_constant_index(index_expr)
|
|
236
|
+
if index_value is None:
|
|
237
|
+
return
|
|
238
|
+
|
|
239
|
+
if index_value < 0 or index_value >= array_length:
|
|
240
|
+
raise GuppyError(
|
|
241
|
+
ArrayIndexChecker.IndexOutOfBoundsError(
|
|
242
|
+
index_expr,
|
|
243
|
+
index=index_value,
|
|
244
|
+
size=array_length,
|
|
245
|
+
)
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
def check(self, args: list[ast.expr], ty: Type) -> tuple[ast.expr, Subst]:
|
|
249
|
+
"""Check-mode: verify arguments against
|
|
250
|
+
expected type and perform bounds check."""
|
|
251
|
+
|
|
252
|
+
# Run regular type checking for the arguments
|
|
253
|
+
args, subs, type_args = check_call(self.func.ty, args, ty, self.node, self.ctx)
|
|
254
|
+
|
|
255
|
+
# Check the index bounds (first:index expression, second: length_arg)
|
|
256
|
+
self._check_constant_index_bounds(args[self.expr_index], type_args[1])
|
|
257
|
+
|
|
258
|
+
# Return the synthesized node and type
|
|
259
|
+
node = GlobalCall(def_id=self.func.id, args=args, type_args=type_args)
|
|
260
|
+
return with_loc(self.node, node), subs
|
|
261
|
+
|
|
262
|
+
def synthesize(self, args: list[ast.expr]) -> tuple[ast.expr, Type]:
|
|
263
|
+
"""Synthesize-mode: infer return type and perform bounds check."""
|
|
264
|
+
# Run regular type synthesis for the arguments
|
|
265
|
+
args, ty, type_args = synthesize_call(self.func.ty, args, self.node, self.ctx)
|
|
266
|
+
|
|
267
|
+
# Check the index bounds (first:index expression, second: length_arg)
|
|
268
|
+
self._check_constant_index_bounds(args[self.expr_index], type_args[1])
|
|
269
|
+
|
|
270
|
+
# Return the synthesized node and type
|
|
271
|
+
node = GlobalCall(def_id=self.func.id, args=args, type_args=type_args)
|
|
272
|
+
return with_loc(self.node, node), ty
|
|
273
|
+
|
|
274
|
+
|
|
175
275
|
class NewArrayChecker(CustomCallChecker):
|
|
176
276
|
"""Function call checker for the `array.__new__` function."""
|
|
177
277
|
|
|
@@ -251,7 +351,9 @@ class NewArrayChecker(CustomCallChecker):
|
|
|
251
351
|
ConstValue(nat_type(), len(args)),
|
|
252
352
|
]
|
|
253
353
|
call = GlobalCall(
|
|
254
|
-
|
|
354
|
+
self.func.id,
|
|
355
|
+
args,
|
|
356
|
+
type_args, # type: ignore[arg-type]
|
|
255
357
|
)
|
|
256
358
|
return with_loc(self.node, call), subst
|
|
257
359
|
case type_args:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import ast
|
|
2
2
|
from dataclasses import dataclass
|
|
3
|
-
from typing import ClassVar, cast
|
|
3
|
+
from typing import TYPE_CHECKING, ClassVar, cast
|
|
4
4
|
|
|
5
5
|
from guppylang_internals.ast_util import with_loc
|
|
6
6
|
from guppylang_internals.checker.core import ComptimeVariable
|
|
@@ -12,7 +12,6 @@ from guppylang_internals.checker.expr_checker import (
|
|
|
12
12
|
synthesize_call,
|
|
13
13
|
)
|
|
14
14
|
from guppylang_internals.definition.custom import CustomCallChecker
|
|
15
|
-
from guppylang_internals.definition.ty import TypeDef
|
|
16
15
|
from guppylang_internals.diagnostic import Error
|
|
17
16
|
from guppylang_internals.error import GuppyTypeError
|
|
18
17
|
from guppylang_internals.nodes import GenericParamValue, PlaceNode, StateResultExpr
|
|
@@ -31,6 +30,9 @@ from guppylang_internals.tys.ty import (
|
|
|
31
30
|
Type,
|
|
32
31
|
)
|
|
33
32
|
|
|
33
|
+
if TYPE_CHECKING:
|
|
34
|
+
from guppylang_internals.definition.ty import TypeDef
|
|
35
|
+
|
|
34
36
|
|
|
35
37
|
class StateResultChecker(CustomCallChecker):
|
|
36
38
|
"""Call checker for the `state_result` function."""
|
|
@@ -63,7 +65,7 @@ class StateResultChecker(CustomCallChecker):
|
|
|
63
65
|
from guppylang.std.quantum import qubit
|
|
64
66
|
|
|
65
67
|
assert isinstance(qubit, GuppyDefinition)
|
|
66
|
-
qubit_ty = cast(TypeDef, qubit.wrapped).check_instantiate([])
|
|
68
|
+
qubit_ty = cast("TypeDef", qubit.wrapped).check_instantiate([])
|
|
67
69
|
|
|
68
70
|
array_len = None
|
|
69
71
|
arg, ty = ExprSynthesizer(self.ctx).synthesize(args[1])
|
|
@@ -39,14 +39,14 @@ def _mock_meta(cls: type) -> type:
|
|
|
39
39
|
return MockMeta
|
|
40
40
|
|
|
41
41
|
|
|
42
|
-
class float(builtins.float, metaclass=_mock_meta(builtins.float)): # type: ignore[
|
|
42
|
+
class float(builtins.float, metaclass=_mock_meta(builtins.float)): # type: ignore[metaclass]
|
|
43
43
|
def __new__(cls, x: Any = 0.0, /) -> Any:
|
|
44
44
|
if isinstance(x, GuppyObject):
|
|
45
45
|
return x.__float__()
|
|
46
46
|
return builtins.float(x)
|
|
47
47
|
|
|
48
48
|
|
|
49
|
-
class int(builtins.int, metaclass=_mock_meta(builtins.int)): # type: ignore[
|
|
49
|
+
class int(builtins.int, metaclass=_mock_meta(builtins.int)): # type: ignore[metaclass]
|
|
50
50
|
def __new__(cls, x: Any = 0, /, *args: Any, **kwargs: Any) -> Any:
|
|
51
51
|
if isinstance(x, GuppyObject):
|
|
52
52
|
return x.__int__(*args, **kwargs)
|
|
@@ -347,7 +347,7 @@ class GuppyObject(DunderMixin):
|
|
|
347
347
|
return self
|
|
348
348
|
|
|
349
349
|
@hide_trace
|
|
350
|
-
def __getattr__(self, key: str) -> Any:
|
|
350
|
+
def __getattr__(self, key: str) -> Any:
|
|
351
351
|
# Guppy objects don't have fields (structs are treated separately below), so the
|
|
352
352
|
# only attributes we have to worry about are methods.
|
|
353
353
|
func = get_tracing_state().globals.get_instance_func(self._ty, key)
|
|
@@ -454,7 +454,7 @@ class GuppyStructObject(DunderMixin):
|
|
|
454
454
|
object.__setattr__(self, "_frozen", frozen)
|
|
455
455
|
|
|
456
456
|
@hide_trace
|
|
457
|
-
def __getattr__(self, key: str) -> Any:
|
|
457
|
+
def __getattr__(self, key: str) -> Any:
|
|
458
458
|
# It could be an attribute
|
|
459
459
|
if key in self._field_values:
|
|
460
460
|
return self._field_values[key]
|
|
@@ -143,6 +143,7 @@ def arg_from_ast(node: AstNode, ctx: TypeParsingCtx) -> Argument:
|
|
|
143
143
|
def _try_parse_defn(node: AstNode, globals: Globals) -> Definition | None:
|
|
144
144
|
"""Tries to parse a (possibly qualified) name into a global definition."""
|
|
145
145
|
from guppylang.defs import GuppyDefinition
|
|
146
|
+
|
|
146
147
|
from guppylang_internals.checker.cfg_checker import VarNotDefinedError
|
|
147
148
|
|
|
148
149
|
match node:
|
|
@@ -378,7 +379,9 @@ def type_from_ast(node: AstNode, ctx: TypeParsingCtx) -> Type:
|
|
|
378
379
|
"""Turns an AST expression into a Guppy type."""
|
|
379
380
|
ty, flags = type_with_flags_from_ast(node, ctx)
|
|
380
381
|
if flags != InputFlags.NoFlags:
|
|
381
|
-
|
|
382
|
+
# Users shouldn't be able to set this
|
|
383
|
+
# Ignore needed for Python 3.10 mypy compatibility with Flag enums
|
|
384
|
+
assert InputFlags.Inout not in flags # type: ignore[operator, unused-ignore]
|
|
382
385
|
raise GuppyError(FlagNotAllowedError(node))
|
|
383
386
|
return ty
|
|
384
387
|
|