guppylang-internals 0.21.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.
Files changed (98) hide show
  1. guppylang_internals/__init__.py +3 -0
  2. guppylang_internals/ast_util.py +350 -0
  3. guppylang_internals/cfg/__init__.py +0 -0
  4. guppylang_internals/cfg/analysis.py +230 -0
  5. guppylang_internals/cfg/bb.py +221 -0
  6. guppylang_internals/cfg/builder.py +606 -0
  7. guppylang_internals/cfg/cfg.py +117 -0
  8. guppylang_internals/checker/__init__.py +0 -0
  9. guppylang_internals/checker/cfg_checker.py +388 -0
  10. guppylang_internals/checker/core.py +550 -0
  11. guppylang_internals/checker/errors/__init__.py +0 -0
  12. guppylang_internals/checker/errors/comptime_errors.py +106 -0
  13. guppylang_internals/checker/errors/generic.py +45 -0
  14. guppylang_internals/checker/errors/linearity.py +300 -0
  15. guppylang_internals/checker/errors/type_errors.py +344 -0
  16. guppylang_internals/checker/errors/wasm.py +34 -0
  17. guppylang_internals/checker/expr_checker.py +1413 -0
  18. guppylang_internals/checker/func_checker.py +269 -0
  19. guppylang_internals/checker/linearity_checker.py +821 -0
  20. guppylang_internals/checker/stmt_checker.py +447 -0
  21. guppylang_internals/compiler/__init__.py +0 -0
  22. guppylang_internals/compiler/cfg_compiler.py +233 -0
  23. guppylang_internals/compiler/core.py +613 -0
  24. guppylang_internals/compiler/expr_compiler.py +989 -0
  25. guppylang_internals/compiler/func_compiler.py +97 -0
  26. guppylang_internals/compiler/hugr_extension.py +224 -0
  27. guppylang_internals/compiler/qtm_platform_extension.py +0 -0
  28. guppylang_internals/compiler/stmt_compiler.py +212 -0
  29. guppylang_internals/decorator.py +246 -0
  30. guppylang_internals/definition/__init__.py +0 -0
  31. guppylang_internals/definition/common.py +214 -0
  32. guppylang_internals/definition/const.py +74 -0
  33. guppylang_internals/definition/custom.py +492 -0
  34. guppylang_internals/definition/declaration.py +171 -0
  35. guppylang_internals/definition/extern.py +89 -0
  36. guppylang_internals/definition/function.py +302 -0
  37. guppylang_internals/definition/overloaded.py +150 -0
  38. guppylang_internals/definition/parameter.py +82 -0
  39. guppylang_internals/definition/pytket_circuits.py +405 -0
  40. guppylang_internals/definition/struct.py +392 -0
  41. guppylang_internals/definition/traced.py +151 -0
  42. guppylang_internals/definition/ty.py +51 -0
  43. guppylang_internals/definition/value.py +115 -0
  44. guppylang_internals/definition/wasm.py +61 -0
  45. guppylang_internals/diagnostic.py +523 -0
  46. guppylang_internals/dummy_decorator.py +76 -0
  47. guppylang_internals/engine.py +295 -0
  48. guppylang_internals/error.py +107 -0
  49. guppylang_internals/experimental.py +92 -0
  50. guppylang_internals/ipython_inspect.py +28 -0
  51. guppylang_internals/nodes.py +427 -0
  52. guppylang_internals/py.typed +0 -0
  53. guppylang_internals/span.py +150 -0
  54. guppylang_internals/std/__init__.py +0 -0
  55. guppylang_internals/std/_internal/__init__.py +0 -0
  56. guppylang_internals/std/_internal/checker.py +573 -0
  57. guppylang_internals/std/_internal/compiler/__init__.py +0 -0
  58. guppylang_internals/std/_internal/compiler/arithmetic.py +136 -0
  59. guppylang_internals/std/_internal/compiler/array.py +569 -0
  60. guppylang_internals/std/_internal/compiler/either.py +131 -0
  61. guppylang_internals/std/_internal/compiler/frozenarray.py +68 -0
  62. guppylang_internals/std/_internal/compiler/futures.py +30 -0
  63. guppylang_internals/std/_internal/compiler/list.py +348 -0
  64. guppylang_internals/std/_internal/compiler/mem.py +13 -0
  65. guppylang_internals/std/_internal/compiler/option.py +78 -0
  66. guppylang_internals/std/_internal/compiler/prelude.py +271 -0
  67. guppylang_internals/std/_internal/compiler/qsystem.py +48 -0
  68. guppylang_internals/std/_internal/compiler/quantum.py +118 -0
  69. guppylang_internals/std/_internal/compiler/tket_bool.py +55 -0
  70. guppylang_internals/std/_internal/compiler/tket_exts.py +59 -0
  71. guppylang_internals/std/_internal/compiler/wasm.py +135 -0
  72. guppylang_internals/std/_internal/compiler.py +0 -0
  73. guppylang_internals/std/_internal/debug.py +95 -0
  74. guppylang_internals/std/_internal/util.py +271 -0
  75. guppylang_internals/tracing/__init__.py +0 -0
  76. guppylang_internals/tracing/builtins_mock.py +62 -0
  77. guppylang_internals/tracing/frozenlist.py +57 -0
  78. guppylang_internals/tracing/function.py +186 -0
  79. guppylang_internals/tracing/object.py +551 -0
  80. guppylang_internals/tracing/state.py +69 -0
  81. guppylang_internals/tracing/unpacking.py +194 -0
  82. guppylang_internals/tracing/util.py +86 -0
  83. guppylang_internals/tys/__init__.py +0 -0
  84. guppylang_internals/tys/arg.py +115 -0
  85. guppylang_internals/tys/builtin.py +382 -0
  86. guppylang_internals/tys/common.py +110 -0
  87. guppylang_internals/tys/const.py +114 -0
  88. guppylang_internals/tys/errors.py +178 -0
  89. guppylang_internals/tys/param.py +251 -0
  90. guppylang_internals/tys/parsing.py +425 -0
  91. guppylang_internals/tys/printing.py +174 -0
  92. guppylang_internals/tys/subst.py +112 -0
  93. guppylang_internals/tys/ty.py +876 -0
  94. guppylang_internals/tys/var.py +49 -0
  95. guppylang_internals-0.21.0.dist-info/METADATA +253 -0
  96. guppylang_internals-0.21.0.dist-info/RECORD +98 -0
  97. guppylang_internals-0.21.0.dist-info/WHEEL +4 -0
  98. guppylang_internals-0.21.0.dist-info/licenses/LICENCE +201 -0
@@ -0,0 +1,382 @@
1
+ import ast
2
+ from collections.abc import Sequence
3
+ from dataclasses import dataclass, field
4
+ from typing import Literal, TypeGuard
5
+
6
+ import hugr.std
7
+ import hugr.std.collections.array
8
+ import hugr.std.collections.list
9
+ from hugr import tys as ht
10
+
11
+ from guppylang_internals.ast_util import AstNode
12
+ from guppylang_internals.definition.common import CompiledDef, DefId
13
+ from guppylang_internals.definition.ty import OpaqueTypeDef, TypeDef
14
+ from guppylang_internals.error import GuppyError, InternalGuppyError
15
+ from guppylang_internals.experimental import check_lists_enabled
16
+ from guppylang_internals.std._internal.compiler.tket_bool import OpaqueBool
17
+ from guppylang_internals.std._internal.compiler.tket_exts import WASM_EXTENSION
18
+ from guppylang_internals.tys.arg import Argument, ConstArg, TypeArg
19
+ from guppylang_internals.tys.common import ToHugrContext
20
+ from guppylang_internals.tys.const import Const, ConstValue
21
+ from guppylang_internals.tys.errors import WrongNumberOfTypeArgsError
22
+ from guppylang_internals.tys.param import ConstParam, TypeParam
23
+ from guppylang_internals.tys.ty import (
24
+ FunctionType,
25
+ NoneType,
26
+ NumericType,
27
+ OpaqueType,
28
+ TupleType,
29
+ Type,
30
+ )
31
+
32
+
33
+ @dataclass(frozen=True)
34
+ class CallableTypeDef(TypeDef, CompiledDef):
35
+ """Type definition associated with the builtin `Callable` type.
36
+
37
+ Any impls on functions can be registered with this definition.
38
+ """
39
+
40
+ name: Literal["Callable"] = field(default="Callable", init=False)
41
+
42
+ def check_instantiate(
43
+ self, args: Sequence[Argument], loc: AstNode | None = None
44
+ ) -> FunctionType:
45
+ # Callable types are constructed using special logic in the type parser
46
+ raise InternalGuppyError("Tried to `Callable` type via `check_instantiate`")
47
+
48
+
49
+ @dataclass(frozen=True)
50
+ class _TupleTypeDef(TypeDef, CompiledDef):
51
+ """Type definition associated with the builtin `tuple` type.
52
+
53
+ Any impls on tuples can be registered with this definition.
54
+ """
55
+
56
+ name: Literal["tuple"] = field(default="tuple", init=False)
57
+
58
+ def check_instantiate(
59
+ self, args: Sequence[Argument], loc: AstNode | None = None
60
+ ) -> TupleType:
61
+ # We accept any number of arguments. If users just write `tuple`, we give them
62
+ # the empty tuple type. We just have to make sure that the args are of kind type
63
+ args = [
64
+ # TODO: Better error location
65
+ TypeParam(0, f"T{i}", must_be_copyable=False, must_be_droppable=False)
66
+ .check_arg(arg, loc)
67
+ .ty
68
+ for i, arg in enumerate(args)
69
+ ]
70
+ return TupleType(args)
71
+
72
+
73
+ @dataclass(frozen=True)
74
+ class _NoneTypeDef(TypeDef, CompiledDef):
75
+ """Type definition associated with the builtin `None` type.
76
+
77
+ Any impls on None can be registered with this definition.
78
+ """
79
+
80
+ name: Literal["None"] = field(default="None", init=False)
81
+
82
+ def check_instantiate(
83
+ self, args: Sequence[Argument], loc: AstNode | None = None
84
+ ) -> NoneType:
85
+ if args:
86
+ raise GuppyError(WrongNumberOfTypeArgsError(loc, 0, len(args), "None"))
87
+ return NoneType()
88
+
89
+
90
+ @dataclass(frozen=True)
91
+ class _NumericTypeDef(TypeDef, CompiledDef):
92
+ """Type definition associated with the builtin numeric types.
93
+
94
+ Any impls on numerics can be registered with these definitions.
95
+ """
96
+
97
+ ty: NumericType
98
+
99
+ def check_instantiate(
100
+ self, args: Sequence[Argument], loc: AstNode | None = None
101
+ ) -> NumericType:
102
+ if args:
103
+ raise GuppyError(WrongNumberOfTypeArgsError(loc, 0, len(args), self.name))
104
+ return self.ty
105
+
106
+
107
+ class WasmModuleTypeDef(OpaqueTypeDef):
108
+ wasm_file: str
109
+ wasm_hash: int
110
+
111
+ def __init__(
112
+ self,
113
+ id: DefId,
114
+ name: str,
115
+ defined_at: ast.AST | None,
116
+ wasm_file: str,
117
+ wasm_hash: int,
118
+ ) -> None:
119
+ super().__init__(id, name, defined_at, [], True, True, self.to_hugr)
120
+ self.wasm_file = wasm_file
121
+ self.wasm_hash = wasm_hash
122
+
123
+ def to_hugr(
124
+ self, args: Sequence[TypeArg | ConstArg], ctx: ToHugrContext
125
+ ) -> ht.Type:
126
+ assert args == []
127
+ ty = WASM_EXTENSION.get_type("context")
128
+ return ty.instantiate([])
129
+
130
+
131
+ @dataclass(frozen=True)
132
+ class _ListTypeDef(OpaqueTypeDef, CompiledDef):
133
+ """Type definition associated with the builtin `list` type.
134
+
135
+ We have a custom definition to disable usage of lists unless experimental features
136
+ are enabled.
137
+ """
138
+
139
+ def check_instantiate(
140
+ self, args: Sequence[Argument], loc: AstNode | None = None
141
+ ) -> OpaqueType:
142
+ check_lists_enabled(loc)
143
+ return super().check_instantiate(args, loc)
144
+
145
+
146
+ def _list_to_hugr(args: Sequence[Argument], ctx: ToHugrContext) -> ht.Type:
147
+ # Type checker ensures that we get a single arg of kind type
148
+ [arg] = args
149
+ assert isinstance(arg, TypeArg)
150
+ # Linear elements are turned into an optional to enable unsafe indexing.
151
+ # See `ListGetitemCompiler` for details.
152
+ elem_ty = ht.Option(arg.ty.to_hugr(ctx)) if arg.ty.linear else arg.ty.to_hugr(ctx)
153
+ return hugr.std.collections.list.List(elem_ty)
154
+
155
+
156
+ def _array_to_hugr(args: Sequence[Argument], ctx: ToHugrContext) -> ht.Type:
157
+ # Type checker ensures that we get a two args
158
+ [ty_arg, len_arg] = args
159
+ assert isinstance(ty_arg, TypeArg)
160
+ assert isinstance(len_arg, ConstArg)
161
+
162
+ # Linear elements are turned into an optional to enable unsafe indexing.
163
+ # See `ArrayGetitemCompiler` for details.
164
+ # Same also for classical arrays, see https://github.com/CQCL/guppylang/issues/629
165
+ elem_ty = ht.Option(ty_arg.ty.to_hugr(ctx))
166
+ hugr_arg = len_arg.to_hugr(ctx)
167
+
168
+ return hugr.std.collections.value_array.ValueArray(elem_ty, hugr_arg)
169
+
170
+
171
+ def _frozenarray_to_hugr(args: Sequence[Argument], ctx: ToHugrContext) -> ht.Type:
172
+ # Type checker ensures that we get a two args
173
+ [ty_arg, len_arg] = args
174
+ assert isinstance(ty_arg, TypeArg)
175
+ assert isinstance(len_arg, ConstArg)
176
+ return hugr.std.collections.static_array.StaticArray(ty_arg.ty.to_hugr(ctx))
177
+
178
+
179
+ def _sized_iter_to_hugr(args: Sequence[Argument], ctx: ToHugrContext) -> ht.Type:
180
+ [ty_arg, len_arg] = args
181
+ assert isinstance(ty_arg, TypeArg)
182
+ assert isinstance(len_arg, ConstArg)
183
+ return ty_arg.ty.to_hugr(ctx)
184
+
185
+
186
+ def _option_to_hugr(args: Sequence[Argument], ctx: ToHugrContext) -> ht.Type:
187
+ [arg] = args
188
+ assert isinstance(arg, TypeArg)
189
+ return ht.Option(arg.ty.to_hugr(ctx))
190
+
191
+
192
+ callable_type_def = CallableTypeDef(DefId.fresh(), None)
193
+ tuple_type_def = _TupleTypeDef(DefId.fresh(), None)
194
+ none_type_def = _NoneTypeDef(DefId.fresh(), None)
195
+ bool_type_def = OpaqueTypeDef(
196
+ id=DefId.fresh(),
197
+ name="bool",
198
+ defined_at=None,
199
+ params=[],
200
+ never_copyable=False,
201
+ never_droppable=False,
202
+ to_hugr=lambda args, ctx: OpaqueBool,
203
+ )
204
+ nat_type_def = _NumericTypeDef(
205
+ DefId.fresh(), "nat", None, NumericType(NumericType.Kind.Nat)
206
+ )
207
+ int_type_def = _NumericTypeDef(
208
+ DefId.fresh(), "int", None, NumericType(NumericType.Kind.Int)
209
+ )
210
+ float_type_def = _NumericTypeDef(
211
+ DefId.fresh(), "float", None, NumericType(NumericType.Kind.Float)
212
+ )
213
+ string_type_def = OpaqueTypeDef(
214
+ id=DefId.fresh(),
215
+ name="str",
216
+ defined_at=None,
217
+ params=[],
218
+ never_copyable=False,
219
+ never_droppable=False,
220
+ to_hugr=lambda args, ctx: hugr.std.PRELUDE.get_type("string").instantiate([]),
221
+ )
222
+ list_type_def = _ListTypeDef(
223
+ id=DefId.fresh(),
224
+ name="list",
225
+ defined_at=None,
226
+ params=[TypeParam(0, "T", must_be_copyable=False, must_be_droppable=False)],
227
+ never_copyable=False,
228
+ never_droppable=False,
229
+ to_hugr=_list_to_hugr,
230
+ )
231
+ array_type_def = OpaqueTypeDef(
232
+ id=DefId.fresh(),
233
+ name="array",
234
+ defined_at=None,
235
+ params=[
236
+ TypeParam(0, "T", must_be_copyable=False, must_be_droppable=False),
237
+ ConstParam(1, "n", NumericType(NumericType.Kind.Nat)),
238
+ ],
239
+ never_copyable=True,
240
+ never_droppable=False,
241
+ to_hugr=_array_to_hugr,
242
+ )
243
+ frozenarray_type_def = OpaqueTypeDef(
244
+ id=DefId.fresh(),
245
+ name="frozenarray",
246
+ defined_at=None,
247
+ params=[
248
+ TypeParam(0, "T", must_be_copyable=True, must_be_droppable=True),
249
+ ConstParam(1, "n", NumericType(NumericType.Kind.Nat)),
250
+ ],
251
+ never_copyable=False,
252
+ never_droppable=False,
253
+ to_hugr=_frozenarray_to_hugr,
254
+ )
255
+ sized_iter_type_def = OpaqueTypeDef(
256
+ id=DefId.fresh(),
257
+ name="SizedIter",
258
+ defined_at=None,
259
+ params=[
260
+ TypeParam(0, "T", must_be_copyable=False, must_be_droppable=False),
261
+ ConstParam(1, "n", NumericType(NumericType.Kind.Nat)),
262
+ ],
263
+ never_copyable=False,
264
+ never_droppable=False,
265
+ to_hugr=_sized_iter_to_hugr,
266
+ )
267
+ option_type_def = OpaqueTypeDef(
268
+ id=DefId.fresh(),
269
+ name="Option",
270
+ defined_at=None,
271
+ params=[TypeParam(0, "T", must_be_copyable=False, must_be_droppable=False)],
272
+ never_copyable=False,
273
+ never_droppable=False,
274
+ to_hugr=_option_to_hugr,
275
+ )
276
+
277
+
278
+ def bool_type() -> OpaqueType:
279
+ return OpaqueType([], bool_type_def)
280
+
281
+
282
+ def nat_type() -> NumericType:
283
+ return NumericType(NumericType.Kind.Nat)
284
+
285
+
286
+ def int_type() -> NumericType:
287
+ return NumericType(NumericType.Kind.Int)
288
+
289
+
290
+ def float_type() -> NumericType:
291
+ return NumericType(NumericType.Kind.Float)
292
+
293
+
294
+ def string_type() -> OpaqueType:
295
+ return OpaqueType([], string_type_def)
296
+
297
+
298
+ def list_type(element_ty: Type) -> OpaqueType:
299
+ return OpaqueType([TypeArg(element_ty)], list_type_def)
300
+
301
+
302
+ def array_type(element_ty: Type, length: int | Const) -> OpaqueType:
303
+ if isinstance(length, int):
304
+ length = ConstValue(nat_type(), length)
305
+ return OpaqueType([TypeArg(element_ty), ConstArg(length)], array_type_def)
306
+
307
+
308
+ def frozenarray_type(element_ty: Type, length: int | Const) -> OpaqueType:
309
+ if isinstance(length, int):
310
+ length = ConstValue(nat_type(), length)
311
+ return OpaqueType([TypeArg(element_ty), ConstArg(length)], frozenarray_type_def)
312
+
313
+
314
+ def sized_iter_type(iter_type: Type, size: int | Const) -> OpaqueType:
315
+ if isinstance(size, int):
316
+ size = ConstValue(nat_type(), size)
317
+ return OpaqueType([TypeArg(iter_type), ConstArg(size)], sized_iter_type_def)
318
+
319
+
320
+ def option_type(element_ty: Type) -> OpaqueType:
321
+ return OpaqueType([TypeArg(element_ty)], option_type_def)
322
+
323
+
324
+ def is_bool_type(ty: Type) -> bool:
325
+ return isinstance(ty, OpaqueType) and ty.defn == bool_type_def
326
+
327
+
328
+ def is_string_type(ty: Type) -> bool:
329
+ return isinstance(ty, OpaqueType) and ty.defn == string_type_def
330
+
331
+
332
+ def is_list_type(ty: Type) -> bool:
333
+ return isinstance(ty, OpaqueType) and ty.defn == list_type_def
334
+
335
+
336
+ def is_array_type(ty: Type) -> TypeGuard[OpaqueType]:
337
+ return isinstance(ty, OpaqueType) and ty.defn == array_type_def
338
+
339
+
340
+ def is_frozenarray_type(ty: Type) -> TypeGuard[OpaqueType]:
341
+ return isinstance(ty, OpaqueType) and ty.defn == frozenarray_type_def
342
+
343
+
344
+ def is_sized_iter_type(ty: Type) -> TypeGuard[OpaqueType]:
345
+ return isinstance(ty, OpaqueType) and ty.defn == sized_iter_type_def
346
+
347
+
348
+ def wasm_module_info(ty: Type) -> tuple[str, int] | None:
349
+ if isinstance(ty, OpaqueType) and isinstance(ty.defn, WasmModuleTypeDef):
350
+ return ty.defn.wasm_file, ty.defn.wasm_hash
351
+ return None
352
+
353
+
354
+ def get_element_type(ty: Type) -> Type:
355
+ assert isinstance(ty, OpaqueType)
356
+ assert ty.defn in (
357
+ list_type_def,
358
+ array_type_def,
359
+ frozenarray_type_def,
360
+ option_type_def,
361
+ )
362
+ (arg, *_) = ty.args
363
+ assert isinstance(arg, TypeArg)
364
+ return arg.ty
365
+
366
+
367
+ def get_array_length(ty: Type) -> Const:
368
+ assert isinstance(ty, OpaqueType)
369
+ assert ty.defn == array_type_def
370
+ [_, length_arg] = ty.args
371
+ assert isinstance(length_arg, ConstArg)
372
+ return length_arg.const
373
+
374
+
375
+ def get_iter_size(ty: Type) -> Const:
376
+ assert isinstance(ty, OpaqueType)
377
+ assert ty.defn == sized_iter_type_def
378
+ match ty.args:
379
+ case [_, ConstArg(const)]:
380
+ return const
381
+ case _:
382
+ raise InternalGuppyError("Unexpected type args")
@@ -0,0 +1,110 @@
1
+ from abc import ABC, abstractmethod
2
+ from collections.abc import Sequence
3
+ from dataclasses import dataclass
4
+ from typing import TYPE_CHECKING, Any, Generic, Protocol, TypeVar
5
+
6
+ from hugr import tys as ht
7
+
8
+ if TYPE_CHECKING:
9
+ from guppylang_internals.tys.const import BoundConstVar
10
+ from guppylang_internals.tys.param import Parameter
11
+ from guppylang_internals.tys.ty import BoundTypeVar
12
+
13
+ T = TypeVar("T")
14
+
15
+
16
+ class ToHugrContext(Protocol):
17
+ """Protocol for the context capabilities required to translate Guppy types into Hugr
18
+ types.
19
+
20
+ Currently, the only required capability is translating bound type and const
21
+ variables into Hugr, taking into account partial monomorphization.
22
+ """
23
+
24
+ def type_var_to_hugr(self, var: "BoundTypeVar") -> ht.Type:
25
+ """Compiles a bound Guppy type variable into a Hugr type.
26
+
27
+ Should take care of performing partial monomorphization as specified in the
28
+ current context.
29
+ """
30
+
31
+ def const_var_to_hugr(self, var: "BoundConstVar") -> ht.TypeArg:
32
+ """Compiles a bound Guppy const variable into a Hugr type argument.
33
+
34
+ Should take care of performing partial monomorphization as specified in the
35
+ current context.
36
+ """
37
+
38
+
39
+ @dataclass(frozen=True)
40
+ class QuantifiedToHugrContext(ToHugrContext):
41
+ """Concrete implementation of a `ToHugrContext` that should be used when moving
42
+ inside a quantifier.
43
+
44
+ This prevents the outer context from touching variables that are bound by a tighter
45
+ quantifier.
46
+ """
47
+
48
+ params: Sequence["Parameter"]
49
+
50
+ def type_var_to_hugr(self, var: "BoundTypeVar") -> ht.Type:
51
+ return ht.Variable(var.idx, var.hugr_bound)
52
+
53
+ def const_var_to_hugr(self, var: "BoundConstVar") -> ht.TypeArg:
54
+ return ht.VariableArg(var.idx, self.params[var.idx].to_hugr(self))
55
+
56
+
57
+ class ToHugr(ABC, Generic[T]):
58
+ """Abstract base class for objects that have a Hugr representation."""
59
+
60
+ @abstractmethod
61
+ def to_hugr(self, ctx: ToHugrContext) -> T:
62
+ """Computes the Hugr representation of the object."""
63
+
64
+
65
+ class Visitor(ABC):
66
+ """Abstract base class for a type visitor that transforms types."""
67
+
68
+ @abstractmethod
69
+ def visit(self, arg: Any, /) -> bool:
70
+ """This method is called for each visited type.
71
+
72
+ Return `False` to continue the recursive descent.
73
+ """
74
+
75
+
76
+ class Transformer(ABC):
77
+ """Abstract base class for a type visitor that transforms types."""
78
+
79
+ @abstractmethod
80
+ def transform(self, arg: Any, /) -> Any | None:
81
+ """Transforms the object.
82
+
83
+ Return a transformed type or `None` to continue the recursive visit.
84
+ """
85
+
86
+
87
+ class Visitable(ABC):
88
+ """Abstract base class for objects that can be recursively visited."""
89
+
90
+ @abstractmethod
91
+ def visit(self, visitor: Visitor, /) -> None:
92
+ """Accepts a visitor on the object.
93
+
94
+ Implementors of this method should first invoke the visitor on the object
95
+ itself. If the visitor doesn't handle the object, the visitor should be passed
96
+ to all relevant members of the object.
97
+ """
98
+
99
+
100
+ class Transformable(Visitable, ABC, Generic[T]):
101
+ """Abstract base class for objects that can be recursively transformed."""
102
+
103
+ @abstractmethod
104
+ def transform(self, transformer: Transformer, /) -> T:
105
+ """Accepts a transformer on the object.
106
+
107
+ Implementors of this method should first invoke the transformer on the object
108
+ itself. If the visitor doesn't handle the object, the visitor should be used to
109
+ transform all relevant members of the object.
110
+ """
@@ -0,0 +1,114 @@
1
+ from abc import ABC, abstractmethod
2
+ from dataclasses import dataclass, field
3
+ from typing import TYPE_CHECKING, Any, TypeAlias
4
+
5
+ from guppylang_internals.error import InternalGuppyError
6
+ from guppylang_internals.tys.common import Transformable, Transformer, Visitor
7
+ from guppylang_internals.tys.var import BoundVar, ExistentialVar
8
+
9
+ if TYPE_CHECKING:
10
+ from guppylang_internals.tys.arg import ConstArg
11
+ from guppylang_internals.tys.ty import Type
12
+
13
+
14
+ @dataclass(frozen=True)
15
+ class ConstBase(Transformable["Const"], ABC):
16
+ """Abstract base class for constants arguments in the type system.
17
+
18
+ In principle, we can allow constants of any type representable in the type system.
19
+ For now, we will only support basic consts like `int` or `bool`, but in the future
20
+ we could have struct constants etc.
21
+ """
22
+
23
+ ty: "Type" = field(hash=False) # Types are not hashable
24
+
25
+ def __post_init__(self) -> None:
26
+ if self.ty.unsolved_vars:
27
+ raise InternalGuppyError("Attempted to create constant with unsolved type")
28
+
29
+ @abstractmethod
30
+ def cast(self) -> "Const":
31
+ """Casts an implementor of `ConstBase` into a `Const`.
32
+
33
+ This enforces that all implementors of `ConstBase` can be embedded into the
34
+ `Const` union type.
35
+ """
36
+
37
+ @property
38
+ def unsolved_vars(self) -> set[ExistentialVar]:
39
+ """The existential type variables contained in this constant."""
40
+ return set()
41
+
42
+ def __str__(self) -> str:
43
+ from guppylang_internals.tys.printing import TypePrinter
44
+
45
+ return TypePrinter().visit(self.cast())
46
+
47
+ def visit(self, visitor: Visitor) -> None:
48
+ """Accepts a visitor on this constant."""
49
+ visitor.visit(self)
50
+
51
+ def transform(self, transformer: Transformer, /) -> "Const":
52
+ """Accepts a transformer on this constant."""
53
+ return transformer.transform(self) or self.cast()
54
+
55
+ def to_arg(self) -> "ConstArg":
56
+ """Wraps this constant into a type argument."""
57
+ from guppylang_internals.tys.arg import ConstArg
58
+
59
+ return ConstArg(self.cast())
60
+
61
+
62
+ @dataclass(frozen=True)
63
+ class ConstValue(ConstBase):
64
+ """A constant value in the type system.
65
+
66
+ For example, in the type `array[int, 5]` the second argument is a `ConstArg` that
67
+ contains a `ConstValue(5)`.
68
+ """
69
+
70
+ # TODO: We will need a proper Guppy representation of this in the future
71
+ value: Any
72
+
73
+ def cast(self) -> "Const":
74
+ """Casts an implementor of `ConstBase` into a `Const`."""
75
+ return self
76
+
77
+
78
+ @dataclass(frozen=True)
79
+ class BoundConstVar(BoundVar, ConstBase):
80
+ """Bound variable referencing a `ConstParam`.
81
+
82
+ For example, in the function type `forall n: int. array[float, n] -> array[int, n]`,
83
+ we represent the int argument to `array` as a `ConstArg` containing a
84
+ `BoundConstVar(idx=0)`.
85
+ """
86
+
87
+ def cast(self) -> "Const":
88
+ """Casts an implementor of `ConstBase` into a `Const`."""
89
+ return self
90
+
91
+
92
+ @dataclass(frozen=True)
93
+ class ExistentialConstVar(ExistentialVar, ConstBase):
94
+ """Existential constant variable.
95
+
96
+ During type checking we try to solve all existential constant variables and
97
+ substitute them with concrete constants.
98
+ """
99
+
100
+ @classmethod
101
+ def fresh(cls, display_name: str, ty: "Type") -> "ExistentialConstVar":
102
+ return ExistentialConstVar(ty, display_name, next(cls._fresh_id))
103
+
104
+ @property
105
+ def unsolved_vars(self) -> set[ExistentialVar]:
106
+ """The existential type variables contained in this constant."""
107
+ return {self}
108
+
109
+ def cast(self) -> "Const":
110
+ """Casts an implementor of `ConstBase` into a `Const`."""
111
+ return self
112
+
113
+
114
+ Const: TypeAlias = ConstValue | BoundConstVar | ExistentialConstVar