artiq
artiq copied to clipboard
Type annotations in kernel don't support Callable[[...], ...]
Passing a kernel function as an argument works fine. However, annotating the receiving function breaks with a TypeError:
from artiq.experiment import *
from typing import Callable
class TestTyping(EnvExperiment):
def build(self):
self.setattr_device('core')
@kernel
def run(self):
# This goes fine
self.test_func(1)
# This is fine too
self.call_passed_func(self.test_func)
# This causes a compiler error
self.call_passed_func_annotated(self.test_func)
@kernel
def test_func(self, a: TInt32):
print(a)
@kernel
def call_passed_func(self, f):
f(2)
@kernel
def call_passed_func_annotated(self, f: Callable[[TInt32], TNone]):
f(3)
This raises a root:Terminating with exception (TypeError: Callable[args, result]: result must be a type. Got artiq.compiler.types.TMono('NoneType', OrderedDict()).)
error.
Unfortunately, the ARTIQ compiler isn't compatible with standard Python type annotations; the equivalent would be artiq.compiler.types.TFunction
.
Thanks for that pointer. It seems like TFunction
is present in artiq.compiler.types
but not in artiq.compiler.builtins
or artiq.language.types
, which is presumably why
@kernel
def call_passed_func_annotated(self, f: TFunction):
...
produces error: type annotation for argument 'f', '<class 'artiq.compiler.types.TFunction'>', is not an ARTIQ type
.
Do you know the rational behind this, or is it an oversight?
Try something like TFunction({"a": TInt32}, {}, TNone)
.
Thanks @whitequark but that gives
File "C:\Users\cb6\AppData\Local\Continuum\anaconda3\envs\artiq\lib\site-packages\artiq\compiler\types.py", line 224, in __init__
assert isinstance(args, OrderedDict)
AssertionError
Defining it instead as
@kernel
def call_passed_func_annotated(self, f: TFunction(OrderedDict({"a": TInt32}), OrderedDict(), TNone)):
f(3)
gives
[...] error: cannot unify method(fn=(self:<instance artiq_worker_<repository>\testing\typing_MWE.TestTyping>, a:numpy.int32)->'a delay('b), self=<instance artiq_worker_<repository>\testing\typing_MWE.TestTyping>)
with
(a:numpy.int32)->NoneType delay('c)
[...]
And I'm not sure how to pass the class type in, since this method is a part of the class that's being defined, so the class does not yet exist at the point of its definition.... (f: TFunction(OrderedDict({"self": TestTyping,"a": TInt32})
doesn't work)
Trying
@kernel
def call_passed_func_annotated(self, f: TFunction(OrderedDict({"self": EnvExperiment,"a": TInt32}), OrderedDict(), TNone)):
f(3)
but still a no-go:
AttributeError: type object 'EnvExperiment' has no attribute 'find'
Ah yes. I don't think you can currently write that annotation. In fact I don't think it's realistic to expect to be able to write annotations for arguments that involve curried functions (that is, methods) passed to them, with the way the compiler is currently structured.
For background, the compiler was written to support global type inference exclusively, and annotations were added for a few edge cases (syscalls and unconstrained arguments).