forked from M-Labs/artiq
compiler.embedding: test all diagnostics.
Also, unify and improve diagnostic messages.
This commit is contained in:
parent
d80be482fc
commit
7c1abb25ec
@ -269,12 +269,11 @@ class StitchingInferencer(Inferencer):
|
||||
else:
|
||||
attributes = object_type.attributes
|
||||
|
||||
ast = self.quote(attr_value, None)
|
||||
ast = self.quote(attr_value, object_loc.expanded_from)
|
||||
|
||||
def proxy_diagnostic(diag):
|
||||
note = diagnostic.Diagnostic("note",
|
||||
"expanded from here while trying to infer a type for an"
|
||||
" attribute '{attr}' of a host object",
|
||||
"while inferring a type for an attribute '{attr}' of a host object",
|
||||
{"attr": node.attr},
|
||||
node.loc)
|
||||
diag.notes.append(note)
|
||||
@ -293,10 +292,11 @@ class StitchingInferencer(Inferencer):
|
||||
# Does this conflict with an earlier guess?
|
||||
printer = types.TypePrinter()
|
||||
diag = diagnostic.Diagnostic("error",
|
||||
"host object has an attribute of type {typea}, which is"
|
||||
" different from previously inferred type {typeb}",
|
||||
"host object has an attribute '{attr}' of type {typea}, which is"
|
||||
" different from previously inferred type {typeb} for the same attribute",
|
||||
{"typea": printer.name(ast.type),
|
||||
"typeb": printer.name(attributes[node.attr])},
|
||||
"typeb": printer.name(attributes[node.attr]),
|
||||
"attr": node.attr},
|
||||
object_loc)
|
||||
self.engine.process(diag)
|
||||
|
||||
@ -465,27 +465,23 @@ class Stitcher:
|
||||
source_buffer = source.Buffer(source_line, filename, line)
|
||||
return source.Range(source_buffer, column, column)
|
||||
|
||||
def _function_def_note(self, function):
|
||||
return diagnostic.Diagnostic("note",
|
||||
"definition of function '{function}'",
|
||||
{"function": function.__name__},
|
||||
self._function_loc(function))
|
||||
|
||||
def _extract_annot(self, function, annot, kind, call_loc, is_syscall):
|
||||
if not isinstance(annot, types.Type):
|
||||
def _call_site_note(self, call_loc, is_syscall):
|
||||
if is_syscall:
|
||||
note = diagnostic.Diagnostic("note",
|
||||
return diagnostic.Diagnostic("note",
|
||||
"in system call here", {},
|
||||
call_loc)
|
||||
else:
|
||||
note = diagnostic.Diagnostic("note",
|
||||
return diagnostic.Diagnostic("note",
|
||||
"in function called remotely here", {},
|
||||
call_loc)
|
||||
|
||||
def _extract_annot(self, function, annot, kind, call_loc, is_syscall):
|
||||
if not isinstance(annot, types.Type):
|
||||
diag = diagnostic.Diagnostic("error",
|
||||
"type annotation for {kind}, '{annot}', is not an ARTIQ type",
|
||||
{"kind": kind, "annot": repr(annot)},
|
||||
self._function_loc(function),
|
||||
notes=[note])
|
||||
notes=[self._call_site_note(call_loc, is_syscall)])
|
||||
self.engine.process(diag)
|
||||
|
||||
return types.TVar()
|
||||
@ -503,7 +499,8 @@ class Stitcher:
|
||||
diag = diagnostic.Diagnostic("error",
|
||||
"system call argument '{argument}' must have a type annotation",
|
||||
{"argument": param.name},
|
||||
self._function_loc(function))
|
||||
self._function_loc(function),
|
||||
notes=[self._call_site_note(loc, is_syscall)])
|
||||
self.engine.process(diag)
|
||||
elif param.default is not inspect.Parameter.empty:
|
||||
# Try and infer the type from the default value.
|
||||
@ -517,10 +514,10 @@ class Stitcher:
|
||||
"expanded from here while trying to infer a type for an"
|
||||
" unannotated optional argument '{argument}' from its default value",
|
||||
{"argument": param.name},
|
||||
loc)
|
||||
self._function_loc(function))
|
||||
diag.notes.append(note)
|
||||
|
||||
diag.notes.append(self._function_def_note(function))
|
||||
diag.notes.append(self._call_site_note(loc, is_syscall))
|
||||
|
||||
self.engine.process(diag)
|
||||
|
||||
@ -556,12 +553,13 @@ class Stitcher:
|
||||
is_syscall=syscall is not None)
|
||||
elif syscall is None:
|
||||
optarg_types[param.name] = self._type_of_param(function, loc, param,
|
||||
is_syscall=syscall is not None)
|
||||
is_syscall=False)
|
||||
else:
|
||||
diag = diagnostic.Diagnostic("error",
|
||||
"system call argument '{argument}' must not have a default value",
|
||||
{"argument": param.name},
|
||||
self._function_loc(function))
|
||||
self._function_loc(function),
|
||||
notes=[self._call_site_note(loc, is_syscall=True)])
|
||||
self.engine.process(diag)
|
||||
|
||||
if signature.return_annotation is not inspect.Signature.empty:
|
||||
@ -570,13 +568,15 @@ class Stitcher:
|
||||
elif syscall is None:
|
||||
diag = diagnostic.Diagnostic("error",
|
||||
"function must have a return type annotation to be called remotely", {},
|
||||
self._function_loc(function))
|
||||
self._function_loc(function),
|
||||
notes=[self._call_site_note(loc, is_syscall=False)])
|
||||
self.engine.process(diag)
|
||||
ret_type = types.TVar()
|
||||
else: # syscall is not None
|
||||
diag = diagnostic.Diagnostic("error",
|
||||
"system call must have a return type annotation", {},
|
||||
self._function_loc(function))
|
||||
self._function_loc(function),
|
||||
notes=[self._call_site_note(loc, is_syscall=True)])
|
||||
self.engine.process(diag)
|
||||
ret_type = types.TVar()
|
||||
|
||||
|
25
artiq/compiler/testbench/embedding.py
Normal file
25
artiq/compiler/testbench/embedding.py
Normal file
@ -0,0 +1,25 @@
|
||||
import sys, os
|
||||
|
||||
from artiq.protocols.file_db import FlatFileDB
|
||||
from artiq.master.worker_db import DeviceManager
|
||||
|
||||
from artiq.coredevice.core import Core, CompileError
|
||||
|
||||
def main():
|
||||
with open(sys.argv[1]) as f:
|
||||
testcase_code = compile(f.read(), f.name, "exec")
|
||||
testcase_vars = {}
|
||||
exec(testcase_code, testcase_vars)
|
||||
|
||||
ddb_path = os.path.join(os.path.dirname(sys.argv[1]), "ddb.pyon")
|
||||
|
||||
try:
|
||||
core = Core(dmgr=DeviceManager(FlatFileDB(ddb_path)))
|
||||
core.run(testcase_vars["entrypoint"], (), {})
|
||||
print(core.comm.get_log())
|
||||
core.comm.clear_log()
|
||||
except CompileError as error:
|
||||
print("\n".join(error.__cause__.diagnostic.render(only_line=True)))
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -8,23 +8,11 @@ class Comm:
|
||||
def switch_clock(self, external):
|
||||
pass
|
||||
|
||||
def load(self, kcode):
|
||||
print("================")
|
||||
print(" LLVM IR")
|
||||
print("================")
|
||||
print(kcode)
|
||||
def load(self, kernel_library):
|
||||
pass
|
||||
|
||||
def run(self, kname):
|
||||
print("RUN: "+kname)
|
||||
def run(self):
|
||||
pass
|
||||
|
||||
def serve(self, rpc_map, exception_map):
|
||||
print("================")
|
||||
print(" RPC map")
|
||||
print("================")
|
||||
for k, v in sorted(rpc_map.items(), key=itemgetter(0)):
|
||||
print(str(k)+" -> "+str(v))
|
||||
print("================")
|
||||
print(" Exception map")
|
||||
print("================")
|
||||
for k, v in sorted(exception_map.items(), key=itemgetter(0)):
|
||||
print(str(k)+" -> "+str(v))
|
||||
def serve(self, object_map, symbolizer):
|
||||
pass
|
||||
|
@ -48,7 +48,6 @@ class Core:
|
||||
return stitcher.object_map, stripped_library, \
|
||||
lambda addresses: target.symbolize(library, addresses)
|
||||
except diagnostic.Error as error:
|
||||
print("\n".join(error.diagnostic.render(colored=True)), file=sys.stderr)
|
||||
raise CompileError() from error
|
||||
|
||||
def run(self, function, args, kwargs):
|
||||
|
8
lit-test/test/embedding/ddb.pyon
Normal file
8
lit-test/test/embedding/ddb.pyon
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"comm": {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.comm_dummy",
|
||||
"class": "Comm",
|
||||
"arguments": {}
|
||||
}
|
||||
}
|
16
lit-test/test/embedding/error_attr_absent.py
Normal file
16
lit-test/test/embedding/error_attr_absent.py
Normal file
@ -0,0 +1,16 @@
|
||||
# RUN: %python -m artiq.compiler.testbench.embedding %s >%t
|
||||
# RUN: OutputCheck %s --file-to-check=%t
|
||||
|
||||
from artiq.language.core import *
|
||||
from artiq.language.types import *
|
||||
|
||||
class c:
|
||||
pass
|
||||
|
||||
@kernel
|
||||
def entrypoint():
|
||||
# CHECK-L: <synthesized>:1: error: host object does not have an attribute 'x'
|
||||
# CHECK-L: ${LINE:+1}: note: expanded from here
|
||||
a = c
|
||||
# CHECK-L: ${LINE:+1}: note: attribute accessed here
|
||||
a.x
|
21
lit-test/test/embedding/error_attr_conflict.py
Normal file
21
lit-test/test/embedding/error_attr_conflict.py
Normal file
@ -0,0 +1,21 @@
|
||||
# RUN: %python -m artiq.compiler.testbench.embedding %s >%t
|
||||
# RUN: OutputCheck %s --file-to-check=%t
|
||||
|
||||
from artiq.language.core import *
|
||||
from artiq.language.types import *
|
||||
|
||||
class c:
|
||||
pass
|
||||
|
||||
i1 = c()
|
||||
i1.x = 1
|
||||
|
||||
i2 = c()
|
||||
i2.x = 1.0
|
||||
|
||||
@kernel
|
||||
def entrypoint():
|
||||
# CHECK-L: <synthesized>:1: error: host object has an attribute 'x' of type float, which is different from previously inferred type int(width=32) for the same attribute
|
||||
i1.x
|
||||
# CHECK-L: ${LINE:+1}: note: expanded from here
|
||||
i2.x
|
17
lit-test/test/embedding/error_attr_unify.py
Normal file
17
lit-test/test/embedding/error_attr_unify.py
Normal file
@ -0,0 +1,17 @@
|
||||
# RUN: %python -m artiq.compiler.testbench.embedding %s >%t
|
||||
# RUN: OutputCheck %s --file-to-check=%t
|
||||
|
||||
from artiq.language.core import *
|
||||
from artiq.language.types import *
|
||||
|
||||
class c:
|
||||
x = [1, "x"]
|
||||
|
||||
@kernel
|
||||
def entrypoint():
|
||||
# CHECK-L: <synthesized>:1: error: cannot unify int(width='a) with str
|
||||
# CHECK-NEXT-L: [1, 'x']
|
||||
# CHECK-L: ${LINE:+1}: note: expanded from here
|
||||
a = c
|
||||
# CHECK-L: ${LINE:+1}: note: while inferring a type for an attribute 'x' of a host object
|
||||
a.x
|
14
lit-test/test/embedding/error_rpc_annot_return.py
Normal file
14
lit-test/test/embedding/error_rpc_annot_return.py
Normal file
@ -0,0 +1,14 @@
|
||||
# RUN: %python -m artiq.compiler.testbench.embedding %s >%t
|
||||
# RUN: OutputCheck %s --file-to-check=%t
|
||||
|
||||
from artiq.language.core import *
|
||||
from artiq.language.types import *
|
||||
|
||||
# CHECK-L: ${LINE:+1}: error: type annotation for return type, '1', is not an ARTIQ type
|
||||
def foo() -> 1:
|
||||
pass
|
||||
|
||||
@kernel
|
||||
def entrypoint():
|
||||
# CHECK-L: ${LINE:+1}: note: in function called remotely here
|
||||
foo()
|
15
lit-test/test/embedding/error_rpc_default_unify.py
Normal file
15
lit-test/test/embedding/error_rpc_default_unify.py
Normal file
@ -0,0 +1,15 @@
|
||||
# RUN: %python -m artiq.compiler.testbench.embedding %s >%t
|
||||
# RUN: OutputCheck %s --file-to-check=%t
|
||||
|
||||
from artiq.language.core import *
|
||||
from artiq.language.types import *
|
||||
|
||||
# CHECK-L: <synthesized>:1: error: cannot unify int(width='a) with str
|
||||
# CHECK-L: ${LINE:+1}: note: expanded from here while trying to infer a type for an unannotated optional argument 'x' from its default value
|
||||
def foo(x=[1,"x"]):
|
||||
pass
|
||||
|
||||
@kernel
|
||||
def entrypoint():
|
||||
# CHECK-L: ${LINE:+1}: note: in function called remotely here
|
||||
foo()
|
14
lit-test/test/embedding/error_rpc_return.py
Normal file
14
lit-test/test/embedding/error_rpc_return.py
Normal file
@ -0,0 +1,14 @@
|
||||
# RUN: %python -m artiq.compiler.testbench.embedding %s >%t
|
||||
# RUN: OutputCheck %s --file-to-check=%t
|
||||
|
||||
from artiq.language.core import *
|
||||
from artiq.language.types import *
|
||||
|
||||
# CHECK-L: ${LINE:+1}: error: function must have a return type annotation to be called remotely
|
||||
def foo():
|
||||
pass
|
||||
|
||||
@kernel
|
||||
def entrypoint():
|
||||
# CHECK-L: ${LINE:+1}: note: in function called remotely here
|
||||
foo()
|
15
lit-test/test/embedding/error_syscall_annot.py
Normal file
15
lit-test/test/embedding/error_syscall_annot.py
Normal file
@ -0,0 +1,15 @@
|
||||
# RUN: %python -m artiq.compiler.testbench.embedding %s >%t
|
||||
# RUN: OutputCheck %s --file-to-check=%t
|
||||
|
||||
from artiq.language.core import *
|
||||
from artiq.language.types import *
|
||||
|
||||
# CHECK-L: ${LINE:+2}: error: type annotation for argument 'x', '1', is not an ARTIQ type
|
||||
@syscall
|
||||
def foo(x: 1) -> TNone:
|
||||
pass
|
||||
|
||||
@kernel
|
||||
def entrypoint():
|
||||
# CHECK-L: ${LINE:+1}: note: in system call here
|
||||
foo()
|
15
lit-test/test/embedding/error_syscall_annot_return.py
Normal file
15
lit-test/test/embedding/error_syscall_annot_return.py
Normal file
@ -0,0 +1,15 @@
|
||||
# RUN: %python -m artiq.compiler.testbench.embedding %s >%t
|
||||
# RUN: OutputCheck %s --file-to-check=%t
|
||||
|
||||
from artiq.language.core import *
|
||||
from artiq.language.types import *
|
||||
|
||||
# CHECK-L: ${LINE:+2}: error: type annotation for return type, '1', is not an ARTIQ type
|
||||
@syscall
|
||||
def foo() -> 1:
|
||||
pass
|
||||
|
||||
@kernel
|
||||
def entrypoint():
|
||||
# CHECK-L: ${LINE:+1}: note: in system call here
|
||||
foo()
|
15
lit-test/test/embedding/error_syscall_arg.py
Normal file
15
lit-test/test/embedding/error_syscall_arg.py
Normal file
@ -0,0 +1,15 @@
|
||||
# RUN: %python -m artiq.compiler.testbench.embedding %s >%t
|
||||
# RUN: OutputCheck %s --file-to-check=%t
|
||||
|
||||
from artiq.language.core import *
|
||||
from artiq.language.types import *
|
||||
|
||||
# CHECK-L: ${LINE:+2}: error: system call argument 'x' must have a type annotation
|
||||
@syscall
|
||||
def foo(x) -> TNone:
|
||||
pass
|
||||
|
||||
@kernel
|
||||
def entrypoint():
|
||||
# CHECK-L: ${LINE:+1}: note: in system call here
|
||||
foo()
|
14
lit-test/test/embedding/error_syscall_default_arg.py
Normal file
14
lit-test/test/embedding/error_syscall_default_arg.py
Normal file
@ -0,0 +1,14 @@
|
||||
# RUN: %python -m artiq.compiler.testbench.embedding %s >%t
|
||||
# RUN: OutputCheck %s --file-to-check=%t
|
||||
|
||||
from artiq.language.core import *
|
||||
from artiq.language.types import *
|
||||
|
||||
# CHECK-L: ${LINE:+2}: error: system call argument 'x' must not have a default value
|
||||
@syscall
|
||||
def foo(x=1) -> TNone:
|
||||
pass
|
||||
|
||||
@kernel
|
||||
def entrypoint():
|
||||
foo()
|
14
lit-test/test/embedding/error_syscall_return.py
Normal file
14
lit-test/test/embedding/error_syscall_return.py
Normal file
@ -0,0 +1,14 @@
|
||||
# RUN: %python -m artiq.compiler.testbench.embedding %s >%t
|
||||
# RUN: OutputCheck %s --file-to-check=%t
|
||||
|
||||
from artiq.language.core import *
|
||||
from artiq.language.types import *
|
||||
|
||||
# CHECK-L: ${LINE:+2}: error: system call must have a return type annotation
|
||||
@syscall
|
||||
def foo():
|
||||
pass
|
||||
|
||||
@kernel
|
||||
def entrypoint():
|
||||
foo()
|
Loading…
Reference in New Issue
Block a user