Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: m-labs/artiq
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: c21387dc0926
Choose a base ref
...
head repository: m-labs/artiq
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 13e612c11bd9
Choose a head ref
  • 3 commits
  • 25 files changed
  • 1 contributor

Commits on Aug 28, 2015

  1. Allow clearing core device log buffer.

    This is useful to get a fresh environment, such as when
    running tests that print to log buffer.
    whitequark committed Aug 28, 2015

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    d80be48 View commit details
  2. compiler.embedding: test all diagnostics.

    Also, unify and improve diagnostic messages.
    whitequark committed Aug 28, 2015
    Copy the full SHA
    7c1abb2 View commit details
  3. Fix tests.

    whitequark committed Aug 28, 2015
    Copy the full SHA
    13e612c View commit details
54 changes: 27 additions & 27 deletions artiq/compiler/embedding.py
Original file line number Diff line number Diff line change
@@ -269,12 +269,11 @@ def visit_AttributeT(self, node):
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 @@ def proxy_diagnostic(diag):
# 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 @@ def _function_loc(self, function):
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 _call_site_note(self, call_loc, is_syscall):
if is_syscall:
return diagnostic.Diagnostic("note",
"in system call here", {},
call_loc)
else:
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):
if is_syscall:
note = diagnostic.Diagnostic("note",
"in system call here", {},
call_loc)
else:
note = diagnostic.Diagnostic("note",
"in function called remotely here", {},
call_loc)
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 @@ def _type_of_param(self, function, loc, param, is_syscall):
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 @@ def proxy_diagnostic(diag):
"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 @@ def _quote_foreign_function(self, function, loc, syscall):
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 @@ def _quote_foreign_function(self, function, loc, syscall):
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 changes: 25 additions & 0 deletions artiq/compiler/testbench/embedding.py
Original file line number Diff line number Diff line change
@@ -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 changes: 4 additions & 4 deletions artiq/compiler/types.py
Original file line number Diff line number Diff line change
@@ -521,10 +521,10 @@ def name(self, typ):
self.map[typ] = "'%s" % next(self.gen)
return self.map[typ]
elif isinstance(typ, TInstance):
if typ.name in self.recurse_guard:
if typ in self.recurse_guard:
return "<instance {}>".format(typ.name)
else:
self.recurse_guard.add(typ.name)
self.recurse_guard.add(typ)
attrs = ", ".join(["{}: {}".format(attr, self.name(typ.attributes[attr]))
for attr in typ.attributes])
return "<instance {} {{{}}}>".format(typ.name, attrs)
@@ -554,10 +554,10 @@ def name(self, typ):
elif isinstance(typ, TBuiltinFunction):
return "<function {}>".format(typ.name)
elif isinstance(typ, (TConstructor, TExceptionConstructor)):
if typ.name in self.recurse_guard:
if typ in self.recurse_guard:
return "<constructor {}>".format(typ.name)
else:
self.recurse_guard.add(typ.name)
self.recurse_guard.add(typ)
attrs = ", ".join(["{}: {}".format(attr, self.name(typ.attributes[attr]))
for attr in typ.attributes])
return "<constructor {} {{{}}}>".format(typ.name, attrs)
24 changes: 6 additions & 18 deletions artiq/coredevice/comm_dummy.py
Original file line number Diff line number Diff line change
@@ -8,23 +8,11 @@ def __init__(self, dmgr):
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
28 changes: 18 additions & 10 deletions artiq/coredevice/comm_generic.py
Original file line number Diff line number Diff line change
@@ -12,23 +12,26 @@

class _H2DMsgType(Enum):
LOG_REQUEST = 1
IDENT_REQUEST = 2
SWITCH_CLOCK = 3
LOG_CLEAR = 2

LOAD_LIBRARY = 4
RUN_KERNEL = 5
IDENT_REQUEST = 3
SWITCH_CLOCK = 4

RPC_REPLY = 6
RPC_EXCEPTION = 7
LOAD_LIBRARY = 5
RUN_KERNEL = 6

FLASH_READ_REQUEST = 8
FLASH_WRITE_REQUEST = 9
FLASH_ERASE_REQUEST = 10
FLASH_REMOVE_REQUEST = 11
RPC_REPLY = 7
RPC_EXCEPTION = 8

FLASH_READ_REQUEST = 9
FLASH_WRITE_REQUEST = 10
FLASH_ERASE_REQUEST = 11
FLASH_REMOVE_REQUEST = 12


class _D2HMsgType(Enum):
LOG_REPLY = 1

IDENT_REPLY = 2
CLOCK_SWITCH_COMPLETED = 3
CLOCK_SWITCH_FAILED = 4
@@ -235,6 +238,11 @@ def get_log(self):
self._read_expect(_D2HMsgType.LOG_REPLY)
return self._read_chunk(self._read_length).decode('utf-8')

def clear_log(self):
self._write_empty(_H2DMsgType.LOG_CLEAR)

self._read_empty(_D2HMsgType.LOG_REPLY)

def flash_storage_read(self, key):
self._write_header(_H2DMsgType.FLASH_READ_REQUEST)
self._write_string(key)
1 change: 0 additions & 1 deletion artiq/coredevice/core.py
Original file line number Diff line number Diff line change
@@ -48,7 +48,6 @@ def compile(self, function, args, kwargs, with_attr_writeback=True):
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 changes: 8 additions & 0 deletions lit-test/test/embedding/ddb.pyon
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"comm": {
"type": "local",
"module": "artiq.coredevice.comm_dummy",
"class": "Comm",
"arguments": {}
}
}
16 changes: 16 additions & 0 deletions lit-test/test/embedding/error_attr_absent.py
Original file line number Diff line number Diff line change
@@ -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 changes: 21 additions & 0 deletions lit-test/test/embedding/error_attr_conflict.py
Original file line number Diff line number Diff line change
@@ -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 changes: 17 additions & 0 deletions lit-test/test/embedding/error_attr_unify.py
Original file line number Diff line number Diff line change
@@ -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 changes: 14 additions & 0 deletions lit-test/test/embedding/error_rpc_annot_return.py
Original file line number Diff line number Diff line change
@@ -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 changes: 15 additions & 0 deletions lit-test/test/embedding/error_rpc_default_unify.py
Original file line number Diff line number Diff line change
@@ -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 changes: 14 additions & 0 deletions lit-test/test/embedding/error_rpc_return.py
Original file line number Diff line number Diff line change
@@ -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 changes: 15 additions & 0 deletions lit-test/test/embedding/error_syscall_annot.py
Original file line number Diff line number Diff line change
@@ -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()
Loading