guppylang-internals 0.23.0__tar.gz → 0.24.0__tar.gz

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 (100) hide show
  1. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/CHANGELOG.md +34 -0
  2. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/PKG-INFO +3 -3
  3. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/README.md +1 -1
  4. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/pyproject.toml +2 -2
  5. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/__init__.py +1 -1
  6. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/checker/core.py +8 -0
  7. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/checker/expr_checker.py +10 -20
  8. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/checker/func_checker.py +170 -21
  9. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/checker/stmt_checker.py +1 -1
  10. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/decorator.py +124 -58
  11. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/definition/const.py +2 -2
  12. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/definition/custom.py +1 -1
  13. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/definition/declaration.py +1 -1
  14. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/definition/extern.py +2 -2
  15. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/definition/function.py +1 -1
  16. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/definition/parameter.py +2 -2
  17. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/definition/pytket_circuits.py +1 -1
  18. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/definition/struct.py +10 -10
  19. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/definition/traced.py +1 -1
  20. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/definition/ty.py +6 -0
  21. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/definition/wasm.py +2 -2
  22. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/engine.py +13 -2
  23. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/nodes.py +0 -23
  24. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/std/_internal/compiler/tket_exts.py +3 -6
  25. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/std/_internal/compiler/wasm.py +37 -26
  26. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/tracing/function.py +13 -2
  27. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/tracing/unpacking.py +18 -12
  28. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/tys/builtin.py +30 -11
  29. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/tys/errors.py +6 -0
  30. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/tys/parsing.py +111 -125
  31. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/.gitignore +0 -0
  32. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/LICENCE +0 -0
  33. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/ast_util.py +0 -0
  34. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/cfg/__init__.py +0 -0
  35. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/cfg/analysis.py +0 -0
  36. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/cfg/bb.py +0 -0
  37. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/cfg/builder.py +0 -0
  38. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/cfg/cfg.py +0 -0
  39. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/checker/__init__.py +0 -0
  40. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/checker/cfg_checker.py +0 -0
  41. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/checker/errors/__init__.py +0 -0
  42. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/checker/errors/comptime_errors.py +0 -0
  43. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/checker/errors/generic.py +0 -0
  44. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/checker/errors/linearity.py +0 -0
  45. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/checker/errors/type_errors.py +0 -0
  46. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/checker/errors/wasm.py +0 -0
  47. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/checker/linearity_checker.py +0 -0
  48. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/compiler/__init__.py +0 -0
  49. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/compiler/cfg_compiler.py +0 -0
  50. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/compiler/core.py +0 -0
  51. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/compiler/expr_compiler.py +0 -0
  52. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/compiler/func_compiler.py +0 -0
  53. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/compiler/hugr_extension.py +0 -0
  54. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/compiler/qtm_platform_extension.py +0 -0
  55. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/compiler/stmt_compiler.py +0 -0
  56. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/definition/__init__.py +0 -0
  57. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/definition/common.py +0 -0
  58. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/definition/overloaded.py +0 -0
  59. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/definition/value.py +0 -0
  60. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/diagnostic.py +0 -0
  61. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/dummy_decorator.py +0 -0
  62. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/error.py +0 -0
  63. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/experimental.py +0 -0
  64. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/ipython_inspect.py +0 -0
  65. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/py.typed +0 -0
  66. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/span.py +0 -0
  67. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/std/__init__.py +0 -0
  68. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/std/_internal/__init__.py +0 -0
  69. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/std/_internal/checker.py +0 -0
  70. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/std/_internal/compiler/__init__.py +0 -0
  71. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/std/_internal/compiler/arithmetic.py +0 -0
  72. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/std/_internal/compiler/array.py +0 -0
  73. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/std/_internal/compiler/either.py +0 -0
  74. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/std/_internal/compiler/frozenarray.py +0 -0
  75. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/std/_internal/compiler/futures.py +0 -0
  76. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/std/_internal/compiler/list.py +0 -0
  77. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/std/_internal/compiler/mem.py +0 -0
  78. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/std/_internal/compiler/option.py +0 -0
  79. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/std/_internal/compiler/prelude.py +0 -0
  80. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/std/_internal/compiler/qsystem.py +0 -0
  81. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/std/_internal/compiler/quantum.py +0 -0
  82. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/std/_internal/compiler/tket_bool.py +0 -0
  83. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/std/_internal/compiler.py +0 -0
  84. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/std/_internal/debug.py +0 -0
  85. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/std/_internal/util.py +0 -0
  86. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/tracing/__init__.py +0 -0
  87. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/tracing/builtins_mock.py +0 -0
  88. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/tracing/frozenlist.py +0 -0
  89. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/tracing/object.py +0 -0
  90. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/tracing/state.py +0 -0
  91. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/tracing/util.py +0 -0
  92. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/tys/__init__.py +0 -0
  93. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/tys/arg.py +0 -0
  94. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/tys/common.py +0 -0
  95. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/tys/const.py +0 -0
  96. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/tys/param.py +0 -0
  97. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/tys/printing.py +0 -0
  98. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/tys/subst.py +0 -0
  99. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/tys/ty.py +0 -0
  100. {guppylang_internals-0.23.0 → guppylang_internals-0.24.0}/src/guppylang_internals/tys/var.py +0 -0
@@ -3,6 +3,40 @@
3
3
  First release of `guppylang_internals` package containing refactored out internal components
4
4
  from `guppylang`.
5
5
 
6
+ ## [0.24.0](https://github.com/CQCL/guppylang/compare/guppylang-internals-v0.23.0...guppylang-internals-v0.24.0) (2025-09-19)
7
+
8
+
9
+ ### ⚠ BREAKING CHANGES
10
+
11
+ * `guppylang_internals.decorator.extend_type` now returns a `GuppyDefinition` by default. To get the previous behaviour of returning the annotated class unchanged, pass `return_class=True`.
12
+ * `TypeDef`s now require a `params` field
13
+ * guppylang_internals.ty.parsing.parse_function_io_types replaced with parse_function_arg_annotation and check_function_arg
14
+ * Significant changes to the WASM decorators, types and operations
15
+ * Deleted `guppylang_internals.nodes.{IterHasNext, IterEnd}`
16
+ * guppylang_internals.tracing.unpacking.update_packed_value now returns a bool signalling whether the operation was successful.
17
+ * `CompilationEngine` now initialises all it's fields
18
+ * Calling `CompilationEngine.reset` no longer nullifies `additional_extensions`
19
+ * `CompilationEngine.register_extension` no longer adds duplicates to the `additional_extensions` list
20
+
21
+ ### Features
22
+
23
+ * Infer type of `self` arguments ([#1192](https://github.com/CQCL/guppylang/issues/1192)) ([51f5a2b](https://github.com/CQCL/guppylang/commit/51f5a2b3a9b06bc4ab054f32a4d07f7395df8ff4))
24
+
25
+
26
+ ### Bug Fixes
27
+
28
+ * Add init to CompilationEngine; don't trash additional_extensions ([#1256](https://github.com/CQCL/guppylang/issues/1256)) ([e413748](https://github.com/CQCL/guppylang/commit/e413748532db3895cab4925a222177a4fa3fd61b))
29
+ * Allow generic specialization of methods ([#1206](https://github.com/CQCL/guppylang/issues/1206)) ([93936cc](https://github.com/CQCL/guppylang/commit/93936cc275c56dd856d11fabc7aac20176304147)), closes [#1182](https://github.com/CQCL/guppylang/issues/1182)
30
+ * Correctly update borrowed values after calls and catch cases where it's impossible ([#1253](https://github.com/CQCL/guppylang/issues/1253)) ([3ec5462](https://github.com/CQCL/guppylang/commit/3ec54627729b49689da006a743e9e2c359cd3728))
31
+ * Fix `nat` constructor in comptime functions ([#1258](https://github.com/CQCL/guppylang/issues/1258)) ([e257b6f](https://github.com/CQCL/guppylang/commit/e257b6fc2fe3793d6d8f63feca83bf5ed6643673))
32
+ * Fix incorrect leak error for borrowing functions in comptime ([#1252](https://github.com/CQCL/guppylang/issues/1252)) ([855244e](https://github.com/CQCL/guppylang/commit/855244e2d5e3aeb04c2028f9f2310dba0e74210a)), closes [#1249](https://github.com/CQCL/guppylang/issues/1249)
33
+ * wasm module updates based on tested lowering ([#1230](https://github.com/CQCL/guppylang/issues/1230)) ([657cea2](https://github.com/CQCL/guppylang/commit/657cea27af00a9c02e8d1a3190db535bbd1e7981))
34
+
35
+
36
+ ### Miscellaneous Chores
37
+
38
+ * Delete unused old iterator AST nodes ([#1215](https://github.com/CQCL/guppylang/issues/1215)) ([2310897](https://github.com/CQCL/guppylang/commit/231089750e33cf70754e5218feed64053c558c17))
39
+
6
40
  ## [0.23.0](https://github.com/CQCL/guppylang/compare/guppylang-internals-v0.22.0...guppylang-internals-v0.23.0) (2025-08-19)
7
41
 
8
42
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: guppylang-internals
3
- Version: 0.23.0
3
+ Version: 0.24.0
4
4
  Summary: Compiler internals for `guppylang` package.
5
5
  Author-email: Mark Koch <mark.koch@quantinuum.com>, TKET development team <tket-support@quantinuum.com>
6
6
  Maintainer-email: Mark Koch <mark.koch@quantinuum.com>, TKET development team <tket-support@quantinuum.com>
@@ -220,7 +220,7 @@ Classifier: Programming Language :: Python :: 3.14
220
220
  Classifier: Topic :: Software Development :: Compilers
221
221
  Requires-Python: <4,>=3.10
222
222
  Requires-Dist: hugr~=0.13.1
223
- Requires-Dist: tket-exts~=0.10.0
223
+ Requires-Dist: tket-exts~=0.11.0
224
224
  Requires-Dist: typing-extensions<5,>=4.9.0
225
225
  Provides-Extra: pytket
226
226
  Requires-Dist: pytket>=1.34; extra == 'pytket'
@@ -228,7 +228,7 @@ Description-Content-Type: text/markdown
228
228
 
229
229
  # guppylang-internals
230
230
 
231
- This packages contains the internals of the Guppy compiler.
231
+ This packages contains the internals of the Guppy compiler.
232
232
 
233
233
  See `guppylang` for the package providing the user-facing language frontend.
234
234
 
@@ -1,6 +1,6 @@
1
1
  # guppylang-internals
2
2
 
3
- This packages contains the internals of the Guppy compiler.
3
+ This packages contains the internals of the Guppy compiler.
4
4
 
5
5
  See `guppylang` for the package providing the user-facing language frontend.
6
6
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "guppylang-internals"
3
- version = "0.23.0"
3
+ version = "0.24.0"
4
4
  requires-python = ">=3.10,<4"
5
5
  description = "Compiler internals for `guppylang` package."
6
6
  license = { file = "LICENCE" }
@@ -34,7 +34,7 @@ classifiers = [
34
34
 
35
35
  dependencies = [
36
36
  "typing-extensions >=4.9.0,<5",
37
- "tket-exts ~= 0.10.0",
37
+ "tket-exts ~= 0.11.0",
38
38
  "hugr ~= 0.13.1",
39
39
  ]
40
40
 
@@ -1,3 +1,3 @@
1
1
  # This is updated by our release-please workflow, triggered by this
2
2
  # annotation: x-release-please-version
3
- __version__ = "0.23.0"
3
+ __version__ = "0.24.0"
@@ -54,6 +54,7 @@ from guppylang_internals.tys.ty import (
54
54
 
55
55
  if TYPE_CHECKING:
56
56
  from guppylang_internals.definition.struct import StructField
57
+ from guppylang_internals.tys.parsing import TypeParsingCtx
57
58
 
58
59
 
59
60
  #: A "place" is a description for a storage location of a local value that users
@@ -507,6 +508,13 @@ class Context(NamedTuple):
507
508
  locals: Locals[str, Variable]
508
509
  generic_params: dict[str, Parameter]
509
510
 
511
+ @property
512
+ def parsing_ctx(self) -> "TypeParsingCtx":
513
+ """A type parsing context derived from this checking context."""
514
+ from guppylang_internals.tys.parsing import TypeParsingCtx
515
+
516
+ return TypeParsingCtx(self.globals, self.generic_params)
517
+
510
518
 
511
519
  class DummyEvalDict(dict[str, Any]):
512
520
  """A custom dict that can be passed to `eval` to give better error messages.
@@ -34,6 +34,7 @@ from guppylang_internals.ast_util import (
34
34
  AstNode,
35
35
  AstVisitor,
36
36
  breaks_in_loop,
37
+ get_type,
37
38
  get_type_opt,
38
39
  return_nodes_in_ast,
39
40
  with_loc,
@@ -101,8 +102,6 @@ from guppylang_internals.nodes import (
101
102
  FieldAccessAndDrop,
102
103
  GenericParamValue,
103
104
  GlobalName,
104
- IterEnd,
105
- IterHasNext,
106
105
  IterNext,
107
106
  LocalCall,
108
107
  MakeIter,
@@ -784,14 +783,6 @@ class ExprSynthesizer(AstVisitor[tuple[ast.expr, Type]]):
784
783
  raise GuppyTypeError(err)
785
784
  return expr, ty
786
785
 
787
- def visit_IterHasNext(self, node: IterHasNext) -> tuple[ast.expr, Type]:
788
- node.value, ty = self.synthesize(node.value)
789
- flags = InputFlags.Owned if not ty.copyable else InputFlags.NoFlags
790
- exp_sig = FunctionType([FuncInput(ty, flags)], TupleType([bool_type(), ty]))
791
- return self.synthesize_instance_func(
792
- node.value, [], "__hasnext__", "an iterator", exp_sig, True
793
- )
794
-
795
786
  def visit_IterNext(self, node: IterNext) -> tuple[ast.expr, Type]:
796
787
  node.value, ty = self.synthesize(node.value)
797
788
  flags = InputFlags.Owned if not ty.copyable else InputFlags.NoFlags
@@ -803,14 +794,6 @@ class ExprSynthesizer(AstVisitor[tuple[ast.expr, Type]]):
803
794
  node.value, [], "__next__", "an iterator", exp_sig, True
804
795
  )
805
796
 
806
- def visit_IterEnd(self, node: IterEnd) -> tuple[ast.expr, Type]:
807
- node.value, ty = self.synthesize(node.value)
808
- flags = InputFlags.Owned if not ty.copyable else InputFlags.NoFlags
809
- exp_sig = FunctionType([FuncInput(ty, flags)], NoneType())
810
- return self.synthesize_instance_func(
811
- node.value, [], "__end__", "an iterator", exp_sig, True
812
- )
813
-
814
797
  def visit_ListComp(self, node: ast.ListComp) -> tuple[ast.expr, Type]:
815
798
  raise InternalGuppyError(
816
799
  "BB contains `ListComp`. Should have been removed during CFG"
@@ -946,7 +929,7 @@ def check_type_apply(ty: FunctionType, node: ast.Subscript, ctx: Context) -> Ins
946
929
  raise GuppyError(err)
947
930
 
948
931
  return [
949
- param.check_arg(arg_from_ast(arg_expr, globals, ctx.generic_params), arg_expr)
932
+ param.check_arg(arg_from_ast(arg_expr, ctx.parsing_ctx), arg_expr)
950
933
  for arg_expr, param in zip(arg_exprs, ty.params, strict=True)
951
934
  ]
952
935
 
@@ -1232,7 +1215,14 @@ def instantiate_poly(node: ast.expr, ty: FunctionType, inst: Inst) -> ast.expr:
1232
1215
  """Instantiates quantified type arguments in a function."""
1233
1216
  assert len(ty.params) == len(inst)
1234
1217
  if len(inst) > 0:
1235
- node = with_loc(node, TypeApply(value=with_type(ty, node), inst=inst))
1218
+ # Partial applications need to be instantiated on the inside
1219
+ if isinstance(node, PartialApply):
1220
+ full_ty = get_type(node.func)
1221
+ assert isinstance(full_ty, FunctionType)
1222
+ assert full_ty.params == ty.params
1223
+ node.func = instantiate_poly(node.func, full_ty, inst)
1224
+ else:
1225
+ node = with_loc(node, TypeApply(value=with_type(ty, node), inst=inst))
1236
1226
  return with_type(ty.instantiate(inst), node)
1237
1227
  return with_type(ty, node)
1238
1228
 
@@ -7,8 +7,8 @@ node straight from the Python AST. We build a CFG, check it, and return a
7
7
 
8
8
  import ast
9
9
  import sys
10
- from dataclasses import dataclass
11
- from typing import TYPE_CHECKING, ClassVar
10
+ from dataclasses import dataclass, replace
11
+ from typing import TYPE_CHECKING, ClassVar, cast
12
12
 
13
13
  from guppylang_internals.ast_util import return_nodes_in_ast, with_loc
14
14
  from guppylang_internals.cfg.bb import BB
@@ -17,13 +17,28 @@ from guppylang_internals.checker.cfg_checker import CheckedCFG, check_cfg
17
17
  from guppylang_internals.checker.core import Context, Globals, Place, Variable
18
18
  from guppylang_internals.checker.errors.generic import UnsupportedError
19
19
  from guppylang_internals.definition.common import DefId
20
+ from guppylang_internals.definition.ty import TypeDef
20
21
  from guppylang_internals.diagnostic import Error, Help, Note
21
22
  from guppylang_internals.engine import DEF_STORE, ENGINE
22
23
  from guppylang_internals.error import GuppyError
23
24
  from guppylang_internals.experimental import check_capturing_closures_enabled
24
25
  from guppylang_internals.nodes import CheckedNestedFunctionDef, NestedFunctionDef
25
- from guppylang_internals.tys.parsing import parse_function_io_types
26
- from guppylang_internals.tys.ty import FunctionType, InputFlags, NoneType
26
+ from guppylang_internals.tys.parsing import (
27
+ TypeParsingCtx,
28
+ check_function_arg,
29
+ parse_function_arg_annotation,
30
+ type_from_ast,
31
+ type_with_flags_from_ast,
32
+ )
33
+ from guppylang_internals.tys.ty import (
34
+ ExistentialTypeVar,
35
+ FuncInput,
36
+ FunctionType,
37
+ InputFlags,
38
+ NoneType,
39
+ Type,
40
+ unify,
41
+ )
27
42
 
28
43
  if sys.version_info >= (3, 12):
29
44
  from guppylang_internals.tys.parsing import parse_parameter
@@ -53,6 +68,15 @@ class MissingArgAnnotationError(Error):
53
68
  span_label: ClassVar[str] = "Argument requires a type annotation"
54
69
 
55
70
 
71
+ @dataclass(frozen=True)
72
+ class RecursiveSelfError(Error):
73
+ title: ClassVar[str] = "Recursive self annotation"
74
+ span_label: ClassVar[str] = (
75
+ "Type of `{self_arg}` cannot recursively refer to `Self`"
76
+ )
77
+ self_arg: str
78
+
79
+
56
80
  @dataclass(frozen=True)
57
81
  class MissingReturnAnnotationError(Error):
58
82
  title: ClassVar[str] = "Missing type annotation"
@@ -67,6 +91,43 @@ class MissingReturnAnnotationError(Error):
67
91
  func: str
68
92
 
69
93
 
94
+ @dataclass(frozen=True)
95
+ class InvalidSelfError(Error):
96
+ title: ClassVar[str] = "Invalid self annotation"
97
+ span_label: ClassVar[str] = "`{self_arg}` must be of type `{self_ty}`"
98
+ self_arg: str
99
+ self_ty: Type
100
+
101
+
102
+ @dataclass(frozen=True)
103
+ class SelfParamsShadowedError(Error):
104
+ title: ClassVar[str] = "Shadowed generic parameters"
105
+ span_label: ClassVar[str] = (
106
+ "Cannot infer type for `{self_arg}` since parameter `{param}` of "
107
+ "`{ty_defn.name}` is shadowed"
108
+ )
109
+ param: str
110
+ ty_defn: "TypeDef"
111
+ self_arg: str
112
+
113
+ @dataclass(frozen=True)
114
+ class ExplicitHelp(Help):
115
+ span_label: ClassVar[str] = (
116
+ "Consider specifying the type explicitly: `{suggestion}`"
117
+ )
118
+
119
+ @property
120
+ def suggestion(self) -> str:
121
+ parent = self._parent
122
+ assert isinstance(parent, SelfParamsShadowedError)
123
+ params = (
124
+ f"[{', '.join(f'?{p.name}' for p in parent.ty_defn.params)}]"
125
+ if parent.ty_defn.params
126
+ else ""
127
+ )
128
+ return f'{parent.self_arg}: "{parent.ty_defn.name}{params}"'
129
+
130
+
70
131
  def check_global_func_def(
71
132
  func_def: ast.FunctionDef, ty: FunctionType, globals: Globals
72
133
  ) -> CheckedCFG[Place]:
@@ -176,9 +237,16 @@ def check_nested_func_def(
176
237
  return with_loc(func_def, checked_def)
177
238
 
178
239
 
179
- def check_signature(func_def: ast.FunctionDef, globals: Globals) -> FunctionType:
240
+ def check_signature(
241
+ func_def: ast.FunctionDef, globals: Globals, def_id: DefId | None = None
242
+ ) -> FunctionType:
180
243
  """Checks the signature of a function definition and returns the corresponding
181
- Guppy type."""
244
+ Guppy type.
245
+
246
+ If this is a method, then the `DefId` of the associated parent type should also be
247
+ passed. This will be used to check or infer the type annotation for the `self`
248
+ argument.
249
+ """
182
250
  if len(func_def.args.posonlyargs) != 0:
183
251
  raise GuppyError(
184
252
  UnsupportedError(func_def.args.posonlyargs[0], "Positional-only parameters")
@@ -211,23 +279,29 @@ def check_signature(func_def: ast.FunctionDef, globals: Globals) -> FunctionType
211
279
  param = parse_parameter(param_node, i, globals)
212
280
  param_var_mapping[param.name] = param
213
281
 
214
- input_nodes = []
282
+ # Figure out if this is a method
283
+ self_defn: TypeDef | None = None
284
+ if def_id is not None and def_id in DEF_STORE.impl_parents:
285
+ self_defn = cast(TypeDef, ENGINE.get_checked(DEF_STORE.impl_parents[def_id]))
286
+ assert isinstance(self_defn, TypeDef)
287
+
288
+ inputs = []
215
289
  input_names = []
216
- for inp in func_def.args.args:
217
- ty_ast = inp.annotation
218
- if ty_ast is None:
219
- raise GuppyError(MissingArgAnnotationError(inp))
220
- input_nodes.append(ty_ast)
290
+ ctx = TypeParsingCtx(globals, param_var_mapping, allow_free_vars=True)
291
+ for i, inp in enumerate(func_def.args.args):
292
+ # Special handling for `self` arguments. Note that `__new__` is excluded here
293
+ # since it's not a method so doesn't take `self`.
294
+ if self_defn and i == 0 and func_def.name != "__new__":
295
+ input = parse_self_arg(inp, self_defn, ctx)
296
+ ctx = replace(ctx, self_ty=input.ty)
297
+ else:
298
+ ty_ast = inp.annotation
299
+ if ty_ast is None:
300
+ raise GuppyError(MissingArgAnnotationError(inp))
301
+ input = parse_function_arg_annotation(ty_ast, inp.arg, ctx)
302
+ inputs.append(input)
221
303
  input_names.append(inp.arg)
222
- inputs, output = parse_function_io_types(
223
- input_nodes,
224
- func_def.returns,
225
- input_names,
226
- func_def,
227
- globals,
228
- param_var_mapping,
229
- True,
230
- )
304
+ output = type_from_ast(func_def.returns, ctx)
231
305
  return FunctionType(
232
306
  inputs,
233
307
  output,
@@ -236,6 +310,81 @@ def check_signature(func_def: ast.FunctionDef, globals: Globals) -> FunctionType
236
310
  )
237
311
 
238
312
 
313
+ def parse_self_arg(arg: ast.arg, self_defn: TypeDef, ctx: TypeParsingCtx) -> FuncInput:
314
+ """Handles parsing of the `self` argument on methods.
315
+
316
+ This argument is special since its type annotation may be omitted. Furthermore, if a
317
+ type is provided then it must match the parent type.
318
+ """
319
+ assert self_defn.params is not None
320
+ if arg.annotation is None:
321
+ return handle_implicit_self_arg(arg, self_defn, ctx)
322
+
323
+ # If the user has provided an annotation for `self`, then we go ahead and parse it.
324
+ # However, in the annotation the user is also allowed to use `Self`, so we have to
325
+ # specify a `self_ty` in the context.
326
+ self_ty_head = self_defn.check_instantiate(
327
+ [param.to_existential()[0] for param in self_defn.params]
328
+ )
329
+ self_ty_placeholder = ExistentialTypeVar.fresh(
330
+ "Self", copyable=self_ty_head.copyable, droppable=self_ty_head.droppable
331
+ )
332
+ assert ctx.self_ty is None
333
+ ctx = replace(ctx, self_ty=self_ty_placeholder)
334
+ user_ty, user_flags = type_with_flags_from_ast(arg.annotation, ctx)
335
+
336
+ # If the user just annotates `self: Self` then we can fall back to the case where
337
+ # no annotation is provided at all
338
+ if user_ty == self_ty_placeholder:
339
+ return handle_implicit_self_arg(arg, self_defn, ctx, user_flags)
340
+
341
+ # Annotations like `self: Foo[Self]` are not allowed (would be an infinite type)
342
+ if self_ty_placeholder in user_ty.unsolved_vars:
343
+ raise GuppyError(RecursiveSelfError(arg.annotation, arg.arg))
344
+
345
+ # Check that the annotation matches the parent type. We can do this by unifying with
346
+ # the expected self type where all params are instantiated with unification vars
347
+ subst = unify(user_ty, self_ty_head, {})
348
+ if subst is None:
349
+ raise GuppyError(InvalidSelfError(arg.annotation, arg.arg, self_ty_head))
350
+
351
+ return check_function_arg(user_ty, user_flags, arg, arg.arg, ctx)
352
+
353
+
354
+ def handle_implicit_self_arg(
355
+ arg: ast.arg,
356
+ self_defn: TypeDef,
357
+ ctx: TypeParsingCtx,
358
+ flags: InputFlags = InputFlags.NoFlags,
359
+ ) -> FuncInput:
360
+ """Handles the case where no annotation for `self` is provided.
361
+
362
+ Generates the most generic annotation that is possible by making the function as
363
+ generic as the parent type.
364
+ """
365
+ # Check that the user hasn't shadowed some of the parent type parameters using a
366
+ # Python 3.12 style parameter declaration
367
+ assert self_defn.params is not None
368
+ shadowed_params = [
369
+ param for param in self_defn.params if param.name in ctx.param_var_mapping
370
+ ]
371
+ if shadowed_params:
372
+ param = shadowed_params.pop()
373
+ err = SelfParamsShadowedError(arg, param.name, self_defn, arg.arg)
374
+ err.add_sub_diagnostic(SelfParamsShadowedError.ExplicitHelp(arg))
375
+ raise GuppyError(err)
376
+
377
+ # The generic params inherited from the parent type should appear first in the
378
+ # parameter list, so we have to shift the existing ones
379
+ for name, param in ctx.param_var_mapping.items():
380
+ ctx.param_var_mapping[name] = param.with_idx(param.idx + len(self_defn.params))
381
+
382
+ ctx.param_var_mapping.update({param.name: param for param in self_defn.params})
383
+ self_args = [param.to_bound() for param in self_defn.params]
384
+ self_ty = self_defn.check_instantiate(self_args, loc=arg)
385
+ return check_function_arg(self_ty, flags, arg, arg.arg, ctx)
386
+
387
+
239
388
  def parse_function_with_docstring(
240
389
  func_ast: ast.FunctionDef,
241
390
  ) -> tuple[ast.FunctionDef, str | None]:
@@ -356,7 +356,7 @@ class StmtChecker(AstVisitor[BBStatement]):
356
356
  def visit_AnnAssign(self, node: ast.AnnAssign) -> ast.stmt:
357
357
  if node.value is None:
358
358
  raise GuppyError(UnsupportedError(node, "Variable declarations"))
359
- ty = type_from_ast(node.annotation, self.ctx.globals, self.ctx.generic_params)
359
+ ty = type_from_ast(node.annotation, self.ctx.parsing_ctx)
360
360
  node.value, subst = self._check_expr(node.value, ty)
361
361
  assert not ty.unsolved_vars # `ty` must be closed!
362
362
  assert len(subst) == 0
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import inspect
4
- from typing import TYPE_CHECKING, ParamSpec, TypeVar
4
+ from typing import TYPE_CHECKING, ParamSpec, TypeVar, overload
5
5
 
6
6
  from hugr import ops
7
7
  from hugr import tys as ht
@@ -42,6 +42,7 @@ from guppylang_internals.tys.ty import (
42
42
  )
43
43
 
44
44
  if TYPE_CHECKING:
45
+ import ast
45
46
  import builtins
46
47
  from collections.abc import Callable, Sequence
47
48
  from types import FrameType
@@ -121,15 +122,19 @@ def hugr_op(
121
122
  return custom_function(OpCompiler(op), checker, higher_order_value, name, signature)
122
123
 
123
124
 
124
- def extend_type(defn: TypeDef) -> Callable[[type], type]:
125
- """Decorator to add new instance functions to a type."""
125
+ def extend_type(defn: TypeDef, return_class: bool = False) -> Callable[[type], type]:
126
+ """Decorator to add new instance functions to a type.
127
+
128
+ By default, returns a `GuppyDefinition` object referring to the type. Alternatively,
129
+ `return_class=True` can be set to return the decorated class unchanged.
130
+ """
126
131
  from guppylang.defs import GuppyDefinition
127
132
 
128
133
  def dec(c: type) -> type:
129
134
  for val in c.__dict__.values():
130
135
  if isinstance(val, GuppyDefinition):
131
136
  DEF_STORE.register_impl(defn.id, val.wrapped.name, val.id)
132
- return c
137
+ return c if return_class else GuppyDefinition(defn) # type: ignore[return-value]
133
138
 
134
139
  return dec
135
140
 
@@ -181,63 +186,124 @@ def custom_type(
181
186
 
182
187
 
183
188
  def wasm_module(
184
- filename: str, filehash: int
189
+ filename: str,
185
190
  ) -> Callable[[builtins.type[T]], GuppyDefinition]:
186
- from guppylang.defs import GuppyDefinition
187
-
188
- def dec(cls: builtins.type[T]) -> GuppyDefinition:
189
- # N.B. Only one module per file and vice-versa
190
- wasm_module = WasmModuleTypeDef(
191
- DefId.fresh(),
192
- cls.__name__,
193
- None,
194
- filename,
195
- filehash,
196
- )
197
-
198
- wasm_module_ty = wasm_module.check_instantiate([], None)
199
-
200
- DEF_STORE.register_def(wasm_module, get_calling_frame())
201
- for val in cls.__dict__.values():
202
- if isinstance(val, GuppyDefinition):
203
- DEF_STORE.register_impl(wasm_module.id, val.wrapped.name, val.id)
204
- # Add a constructor to the class
205
- call_method = CustomFunctionDef(
206
- DefId.fresh(),
207
- "__new__",
208
- None,
209
- FunctionType(
210
- [FuncInput(NumericType(NumericType.Kind.Nat), flags=InputFlags.Owned)],
211
- wasm_module_ty,
212
- ),
213
- DefaultCallChecker(),
214
- WasmModuleInitCompiler(),
215
- True,
216
- GlobalConstId.fresh(f"{cls.__name__}.__new__"),
217
- True,
218
- )
219
- discard = CustomFunctionDef(
220
- DefId.fresh(),
221
- "discard",
222
- None,
223
- FunctionType([FuncInput(wasm_module_ty, InputFlags.Owned)], NoneType()),
224
- DefaultCallChecker(),
225
- WasmModuleDiscardCompiler(),
226
- False,
227
- GlobalConstId.fresh(f"{cls.__name__}.__discard__"),
228
- True,
229
- )
230
- DEF_STORE.register_def(call_method, get_calling_frame())
231
- DEF_STORE.register_impl(wasm_module.id, "__new__", call_method.id)
232
- DEF_STORE.register_def(discard, get_calling_frame())
233
- DEF_STORE.register_impl(wasm_module.id, "discard", discard.id)
191
+ def type_def_wrapper(
192
+ id: DefId,
193
+ name: str,
194
+ defined_at: ast.AST | None,
195
+ wasm_file: str,
196
+ config: str | None,
197
+ ) -> OpaqueTypeDef:
198
+ assert config is None
199
+ return WasmModuleTypeDef(id, name, defined_at, wasm_file)
200
+
201
+ f = ext_module_decorator(
202
+ type_def_wrapper, WasmModuleInitCompiler(), WasmModuleDiscardCompiler(), True
203
+ )
204
+ return f(filename, None)
234
205
 
235
- return GuppyDefinition(wasm_module)
236
-
237
- return dec
238
206
 
207
+ def ext_module_decorator(
208
+ type_def: Callable[[DefId, str, ast.AST | None, str, str | None], OpaqueTypeDef],
209
+ init_compiler: CustomInoutCallCompiler,
210
+ discard_compiler: CustomInoutCallCompiler,
211
+ init_arg: bool, # Whether the init function should take a nat argument
212
+ ) -> Callable[[str, str | None], Callable[[builtins.type[T]], GuppyDefinition]]:
213
+ from guppylang.defs import GuppyDefinition
239
214
 
240
- def wasm(f: Callable[P, T]) -> GuppyFunctionDefinition[P, T]:
215
+ def fun(
216
+ filename: str, module: str | None
217
+ ) -> Callable[[builtins.type[T]], GuppyDefinition]:
218
+ def dec(cls: builtins.type[T]) -> GuppyDefinition:
219
+ # N.B. Only one module per file and vice-versa
220
+ ext_module = type_def(
221
+ DefId.fresh(),
222
+ cls.__name__,
223
+ None,
224
+ filename,
225
+ module,
226
+ )
227
+
228
+ ext_module_ty = ext_module.check_instantiate([], None)
229
+
230
+ DEF_STORE.register_def(ext_module, get_calling_frame())
231
+ for val in cls.__dict__.values():
232
+ if isinstance(val, GuppyDefinition):
233
+ DEF_STORE.register_impl(ext_module.id, val.wrapped.name, val.id)
234
+ # Add a constructor to the class
235
+ if init_arg:
236
+ init_fn_ty = FunctionType(
237
+ [
238
+ FuncInput(
239
+ NumericType(NumericType.Kind.Nat),
240
+ flags=InputFlags.Owned,
241
+ )
242
+ ],
243
+ ext_module_ty,
244
+ )
245
+ else:
246
+ init_fn_ty = FunctionType([], ext_module_ty)
247
+
248
+ call_method = CustomFunctionDef(
249
+ DefId.fresh(),
250
+ "__new__",
251
+ None,
252
+ init_fn_ty,
253
+ DefaultCallChecker(),
254
+ init_compiler,
255
+ True,
256
+ GlobalConstId.fresh(f"{cls.__name__}.__new__"),
257
+ True,
258
+ )
259
+ discard = CustomFunctionDef(
260
+ DefId.fresh(),
261
+ "discard",
262
+ None,
263
+ FunctionType([FuncInput(ext_module_ty, InputFlags.Owned)], NoneType()),
264
+ DefaultCallChecker(),
265
+ discard_compiler,
266
+ False,
267
+ GlobalConstId.fresh(f"{cls.__name__}.__discard__"),
268
+ True,
269
+ )
270
+ DEF_STORE.register_def(call_method, get_calling_frame())
271
+ DEF_STORE.register_impl(ext_module.id, "__new__", call_method.id)
272
+ DEF_STORE.register_def(discard, get_calling_frame())
273
+ DEF_STORE.register_impl(ext_module.id, "discard", discard.id)
274
+
275
+ return GuppyDefinition(ext_module)
276
+
277
+ return dec
278
+
279
+ return fun
280
+
281
+
282
+ @overload
283
+ def wasm(arg: Callable[P, T]) -> GuppyFunctionDefinition[P, T]: ...
284
+
285
+
286
+ @overload
287
+ def wasm(arg: int) -> Callable[[Callable[P, T]], GuppyFunctionDefinition[P, T]]: ...
288
+
289
+
290
+ def wasm(
291
+ arg: int | Callable[P, T],
292
+ ) -> (
293
+ GuppyFunctionDefinition[P, T]
294
+ | Callable[[Callable[P, T]], GuppyFunctionDefinition[P, T]]
295
+ ):
296
+ if isinstance(arg, int):
297
+
298
+ def wrapper(f: Callable[P, T]) -> GuppyFunctionDefinition[P, T]:
299
+ return wasm_helper(arg, f)
300
+
301
+ return wrapper
302
+ else:
303
+ return wasm_helper(None, arg)
304
+
305
+
306
+ def wasm_helper(fn_id: int | None, f: Callable[P, T]) -> GuppyFunctionDefinition[P, T]:
241
307
  from guppylang.defs import GuppyFunctionDefinition
242
308
 
243
309
  func = RawWasmFunctionDef(
@@ -246,7 +312,7 @@ def wasm(f: Callable[P, T]) -> GuppyFunctionDefinition[P, T]:
246
312
  None,
247
313
  f,
248
314
  WasmCallChecker(),
249
- WasmModuleCallCompiler(f.__name__),
315
+ WasmModuleCallCompiler(f.__name__, fn_id),
250
316
  True,
251
317
  signature=None,
252
318
  )