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.
- guppylang_internals/__init__.py +3 -0
- guppylang_internals/ast_util.py +350 -0
- guppylang_internals/cfg/__init__.py +0 -0
- guppylang_internals/cfg/analysis.py +230 -0
- guppylang_internals/cfg/bb.py +221 -0
- guppylang_internals/cfg/builder.py +606 -0
- guppylang_internals/cfg/cfg.py +117 -0
- guppylang_internals/checker/__init__.py +0 -0
- guppylang_internals/checker/cfg_checker.py +388 -0
- guppylang_internals/checker/core.py +550 -0
- guppylang_internals/checker/errors/__init__.py +0 -0
- guppylang_internals/checker/errors/comptime_errors.py +106 -0
- guppylang_internals/checker/errors/generic.py +45 -0
- guppylang_internals/checker/errors/linearity.py +300 -0
- guppylang_internals/checker/errors/type_errors.py +344 -0
- guppylang_internals/checker/errors/wasm.py +34 -0
- guppylang_internals/checker/expr_checker.py +1413 -0
- guppylang_internals/checker/func_checker.py +269 -0
- guppylang_internals/checker/linearity_checker.py +821 -0
- guppylang_internals/checker/stmt_checker.py +447 -0
- guppylang_internals/compiler/__init__.py +0 -0
- guppylang_internals/compiler/cfg_compiler.py +233 -0
- guppylang_internals/compiler/core.py +613 -0
- guppylang_internals/compiler/expr_compiler.py +989 -0
- guppylang_internals/compiler/func_compiler.py +97 -0
- guppylang_internals/compiler/hugr_extension.py +224 -0
- guppylang_internals/compiler/qtm_platform_extension.py +0 -0
- guppylang_internals/compiler/stmt_compiler.py +212 -0
- guppylang_internals/decorator.py +246 -0
- guppylang_internals/definition/__init__.py +0 -0
- guppylang_internals/definition/common.py +214 -0
- guppylang_internals/definition/const.py +74 -0
- guppylang_internals/definition/custom.py +492 -0
- guppylang_internals/definition/declaration.py +171 -0
- guppylang_internals/definition/extern.py +89 -0
- guppylang_internals/definition/function.py +302 -0
- guppylang_internals/definition/overloaded.py +150 -0
- guppylang_internals/definition/parameter.py +82 -0
- guppylang_internals/definition/pytket_circuits.py +405 -0
- guppylang_internals/definition/struct.py +392 -0
- guppylang_internals/definition/traced.py +151 -0
- guppylang_internals/definition/ty.py +51 -0
- guppylang_internals/definition/value.py +115 -0
- guppylang_internals/definition/wasm.py +61 -0
- guppylang_internals/diagnostic.py +523 -0
- guppylang_internals/dummy_decorator.py +76 -0
- guppylang_internals/engine.py +295 -0
- guppylang_internals/error.py +107 -0
- guppylang_internals/experimental.py +92 -0
- guppylang_internals/ipython_inspect.py +28 -0
- guppylang_internals/nodes.py +427 -0
- guppylang_internals/py.typed +0 -0
- guppylang_internals/span.py +150 -0
- guppylang_internals/std/__init__.py +0 -0
- guppylang_internals/std/_internal/__init__.py +0 -0
- guppylang_internals/std/_internal/checker.py +573 -0
- guppylang_internals/std/_internal/compiler/__init__.py +0 -0
- guppylang_internals/std/_internal/compiler/arithmetic.py +136 -0
- guppylang_internals/std/_internal/compiler/array.py +569 -0
- guppylang_internals/std/_internal/compiler/either.py +131 -0
- guppylang_internals/std/_internal/compiler/frozenarray.py +68 -0
- guppylang_internals/std/_internal/compiler/futures.py +30 -0
- guppylang_internals/std/_internal/compiler/list.py +348 -0
- guppylang_internals/std/_internal/compiler/mem.py +13 -0
- guppylang_internals/std/_internal/compiler/option.py +78 -0
- guppylang_internals/std/_internal/compiler/prelude.py +271 -0
- guppylang_internals/std/_internal/compiler/qsystem.py +48 -0
- guppylang_internals/std/_internal/compiler/quantum.py +118 -0
- guppylang_internals/std/_internal/compiler/tket_bool.py +55 -0
- guppylang_internals/std/_internal/compiler/tket_exts.py +59 -0
- guppylang_internals/std/_internal/compiler/wasm.py +135 -0
- guppylang_internals/std/_internal/compiler.py +0 -0
- guppylang_internals/std/_internal/debug.py +95 -0
- guppylang_internals/std/_internal/util.py +271 -0
- guppylang_internals/tracing/__init__.py +0 -0
- guppylang_internals/tracing/builtins_mock.py +62 -0
- guppylang_internals/tracing/frozenlist.py +57 -0
- guppylang_internals/tracing/function.py +186 -0
- guppylang_internals/tracing/object.py +551 -0
- guppylang_internals/tracing/state.py +69 -0
- guppylang_internals/tracing/unpacking.py +194 -0
- guppylang_internals/tracing/util.py +86 -0
- guppylang_internals/tys/__init__.py +0 -0
- guppylang_internals/tys/arg.py +115 -0
- guppylang_internals/tys/builtin.py +382 -0
- guppylang_internals/tys/common.py +110 -0
- guppylang_internals/tys/const.py +114 -0
- guppylang_internals/tys/errors.py +178 -0
- guppylang_internals/tys/param.py +251 -0
- guppylang_internals/tys/parsing.py +425 -0
- guppylang_internals/tys/printing.py +174 -0
- guppylang_internals/tys/subst.py +112 -0
- guppylang_internals/tys/ty.py +876 -0
- guppylang_internals/tys/var.py +49 -0
- guppylang_internals-0.21.0.dist-info/METADATA +253 -0
- guppylang_internals-0.21.0.dist-info/RECORD +98 -0
- guppylang_internals-0.21.0.dist-info/WHEEL +4 -0
- 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
|