Skip to content
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
426a5e6
feat: add wasm module (WIP)
qartik Apr 17, 2025
2da0811
Bits and pieces (WIP)
croyzor May 7, 2025
219e293
Maintain uniqueness of WASM contexts for a module
croyzor May 9, 2025
7361fe2
Add discard; make progress
croyzor May 9, 2025
d5c570f
Unification of WasmModuleTypes
croyzor May 9, 2025
af7f7d8
Redundant comment
croyzor May 9, 2025
95b1cb2
Oups - add missing file
croyzor May 15, 2025
cc8aef1
Associate WASM functions with modules
croyzor May 15, 2025
caf37f4
Let more types be wasmable
croyzor May 19, 2025
c8a7b71
Add dummy WASM decorators for sphinx
croyzor May 19, 2025
c6d66d8
Add ConstStringArg
croyzor May 20, 2025
fe23a6c
checkpoint
croyzor May 22, 2025
55805ee
yeee
croyzor May 23, 2025
8de275a
Remove array from test file
croyzor May 27, 2025
c0f70b9
cleanup
croyzor May 27, 2025
07e1f62
Merge remote-tracking branch 'origin/main' into 755-add-support-for-wasm
croyzor May 28, 2025
9b3bf0b
cleanup
croyzor May 28, 2025
d355b67
Improve printing of WASM errors
croyzor Jun 4, 2025
3f4bf50
Add tests for WASM errors
croyzor Jun 4, 2025
46f6469
Take GuppyModule arg in WASM decorators
croyzor Jun 4, 2025
50986f7
bad idea
croyzor Jun 11, 2025
061a6ba
Merge remote-tracking branch 'origin/main' into 755-add-support-for-wasm
croyzor Jun 17, 2025
b2aef12
nth times a charm
croyzor Jun 23, 2025
5ed8479
Merge remote-tracking branch 'origin/main' into 755-add-support-for-wasm
croyzor Jun 23, 2025
e27d362
tests: Update error tests
croyzor Jun 23, 2025
147a73a
refactor: Move wasm type error into right file
croyzor Jun 23, 2025
4ff1525
refactor: Use helper for itousize
croyzor Jun 23, 2025
8a0a188
cleanup: Remove duplicate def of `WasmCallChecker`
croyzor Jun 23, 2025
88b5b0c
cleanup: Remove duplicate defs
croyzor Jun 23, 2025
faadea6
refactor: Idiomatic usage of tket2 exts
croyzor Jun 23, 2025
84ebbdb
cleanup: Undo addition of `cached_sig` field to GlobalCall
croyzor Jun 23, 2025
1d09e45
refactor: Move ConstWasmModule to tket2_exts
croyzor Jun 23, 2025
79beec5
cleanup: Remove commented function
croyzor Jun 23, 2025
7aebba1
Update guppylang/tys/builtin.py
croyzor Jun 23, 2025
3b584d3
Update guppylang/checker/errors/wasm.py
croyzor Jun 23, 2025
9ea17ec
tests: Add backticks and update test
croyzor Jun 24, 2025
5b3f43d
Update comments
croyzor Jun 24, 2025
e24e3f5
Revert uv lock file
croyzor Jun 24, 2025
e677be2
remove ConstStringArg
croyzor Jun 24, 2025
3fafda6
Restrict allowed types in WASM signatures
croyzor Jun 24, 2025
9482b31
Add test with comptime interaction
croyzor Jun 24, 2025
925c22d
Update wasm call checker
croyzor Jun 24, 2025
8488e33
Parse wasm functions; move type signature sanity check out of checking
croyzor Jun 24, 2025
c65d4a0
Add test case
croyzor Jun 24, 2025
277182c
Add missing backticks
croyzor Jun 25, 2025
c73ef71
Remove redundant assert
croyzor Jun 25, 2025
3aa675f
Merge remote-tracking branch 'origin/main' into 755-add-support-for-wasm
croyzor Jun 26, 2025
cba859c
Undo uv.lock changes
croyzor Jun 26, 2025
4565fb9
Remove redundant check + error
croyzor Jun 26, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions guppylang/checker/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
SumType,
TupleType,
Type,
WasmModuleType,
)

if TYPE_CHECKING:
Expand Down Expand Up @@ -314,6 +315,8 @@ def get_instance_func(self, ty: Type | TypeDef, name: str) -> CallableDef | None
type_defn = tuple_type_def
case NoneType():
type_defn = none_type_def
case WasmModuleType() as ty:
type_defn = ty.defn
case _:
return assert_never(ty)

Expand Down
7 changes: 7 additions & 0 deletions guppylang/checker/errors/type_errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -304,3 +304,10 @@ class DynamicIterator(Note):
"since the number of elements yielded by this iterator is not statically "
"known"
)


@dataclass(frozen=True)
class WasmTypeConversionError(Error):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be in errors/wasm.py?

title: ClassVar[str] = "Can't convert type to WASM"
span_label: ClassVar[str] = "`{thing}` cannot be converted to WASM"
ty: Type
34 changes: 34 additions & 0 deletions guppylang/checker/errors/wasm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from dataclasses import dataclass
from typing import ClassVar

from guppylang.diagnostic import Error
from guppylang.tys.ty import Type


class WasmError(Error):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
class WasmError(Error):
@dataclass(frozen=True)
class WasmError(Error):

title: ClassVar[str] = "WASM signature error"


@dataclass(frozen=True)
class FirstArgNotModule(WasmError):
span_label: ClassVar[str] = (
"First argument to WASM function should be a reference to a WASM module"
"Instead, found {ty}"
)
ty: Type


@dataclass(frozen=True)
class UnWasmableType(WasmError):
span_label: ClassVar[str] = (
"WASM function signature contained an unsupported type: {ty}"
)
ty: Type


@dataclass(frozen=True)
class NonFunctionWasmType(WasmError):
span_label: ClassVar[str] = (
"WASM function didn't have a function type, instead found {ty}"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"WASM function didn't have a function type, instead found {ty}"
"WASM function didn't have a function type, instead found `{ty}`"

)
ty: Type
96 changes: 94 additions & 2 deletions guppylang/decorator.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,22 @@

import guppylang
from guppylang.ast_util import annotate_location
from guppylang.checker.core import Globals
from guppylang.compiler.core import GlobalConstId
from guppylang.definition.common import DefId
from guppylang.definition.const import RawConstDef
from guppylang.definition.custom import (
CustomCallChecker,
CustomFunctionDef,
CustomInoutCallCompiler,
DefaultCallChecker,
NotImplementedCallCompiler,
OpCompiler,
RawCustomFunctionDef,
WasmCallChecker,
WasmModuleCallCompiler,
WasmModuleDiscardCompiler,
WasmModuleInitCompiler,
)
from guppylang.definition.extern import RawExternDef
from guppylang.definition.function import (
Expand All @@ -38,7 +45,7 @@
)
from guppylang.definition.struct import RawStructDef
from guppylang.definition.traced import RawTracedFunctionDef
from guppylang.definition.ty import OpaqueTypeDef, TypeDef
from guppylang.definition.ty import OpaqueTypeDef, TypeDef, WasmModule
from guppylang.error import MissingModuleError, pretty_errors
from guppylang.ipython_inspect import (
get_ipython_globals,
Expand All @@ -56,9 +63,16 @@
from guppylang.span import Loc, SourceMap, Span
from guppylang.tracing.object import GuppyDefinition
from guppylang.tys.arg import Argument
from guppylang.tys.builtin import option_type
from guppylang.tys.param import Parameter
from guppylang.tys.subst import Inst
from guppylang.tys.ty import NumericType
from guppylang.tys.ty import (
FuncInput,
FunctionType,
InputFlags,
NoneType,
NumericType,
)

S = TypeVar("S")
T = TypeVar("T")
Expand Down Expand Up @@ -99,6 +113,7 @@ class _Guppy:
def __init__(self) -> None:
self._modules = {}
self._sources = SourceMap()
self._next_wasm_context = 0

@overload
def __call__(self, arg: F) -> F: ...
Expand Down Expand Up @@ -582,6 +597,77 @@ def load_pytket(
mod.register_def(defn)
return GuppyDefinition(defn)

def wasm_module(
self, filename: str, filehash: int
) -> Decorator[PyClass, GuppyDefinition]:
# N.B. Only one module per file and vice-versa
guppy_module = self.get_module()
ctx_id = guppy_module._get_next_wasm_context()
assert guppy_module._instance_func_buffer is None
guppy_module._instance_func_buffer = {}

def dec(cls: PyClass) -> GuppyDefinition:
wasm_module = WasmModule(
DefId.fresh(guppy_module),
cls.__name__,
None,
filename,
filehash,
ctx_id,
)
wasm_module_ty = wasm_module.check_instantiate([], Globals.default(), None)
guppy_module.register_def(wasm_module)
# Add a __call__ to the class
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Add a __call__ to the class
# Add a constructor to the class

call_method = CustomFunctionDef(
DefId.fresh(guppy_module),
"__new__",
None,
FunctionType([], option_type(wasm_module_ty)),
DefaultCallChecker(),
WasmModuleInitCompiler(wasm_module),
False,
GlobalConstId.fresh(f"{cls.__name__}.__new__"),
True,
)
discard = CustomFunctionDef(
DefId.fresh(guppy_module),
"discard",
None,
FunctionType([FuncInput(wasm_module_ty, InputFlags.Owned)], NoneType()),
DefaultCallChecker(),
WasmModuleDiscardCompiler(),
False,
GlobalConstId.fresh(f"{cls.__name__}.__discard__"),
True,
)

assert guppy_module._instance_func_buffer is not None

guppy_module.register_def(wasm_module)
guppy_module._instance_func_buffer |= {
"__new__": call_method,
"discard": discard,
}

guppy_module._register_buffered_instance_funcs(wasm_module)
return GuppyDefinition(wasm_module)

return dec

def wasm(self, f: PyFunc) -> GuppyDefinition:
guppy_module = self.get_module()
func = RawCustomFunctionDef(
DefId.fresh(guppy_module),
f.__name__,
None,
f,
WasmCallChecker(),
WasmModuleCallCompiler(f.__name__),
True,
)
guppy_module.register_def(func)
return GuppyDefinition(func)


class _GuppyDummy:
"""A dummy class with the same interface as `@guppy` that is used during sphinx
Expand Down Expand Up @@ -638,6 +724,12 @@ def load(self, *args: Any, **kwargs: Any) -> None:
def get_module(self, *args: Any, **kwargs: Any) -> Any:
return GuppyModule("dummy", import_builtins=False)

def wasm_module(self, *args: Any, **kwargs: Any) -> Any:
return lambda cls: cls

def wasm(self, *args: Any, **kwargs: Any) -> Any:
return lambda cls: cls


guppy = cast(_Guppy, _GuppyDummy()) if sphinx_running() else _Guppy()

Expand Down
Loading
Loading