Skip to content

Commit

Permalink
embedding: reimplement 373578b properly.
Browse files Browse the repository at this point in the history
The core of the problem that 373578b was attempting to solve is
that diagnostics sometimes should be chained; one way of chaining
is the loc.expanded_from feature, which handles macro-like expansion,
but another is providing context.

Before this commit, context was provided using an ad-hoc override
of a diagnostic engine, which did not work in cases where diagnostic
engine was not threaded through the call stack. This commit uses
the newly added pythonparser context feature to elegantly handle
the problem.
whitequark committed Jul 7, 2016
1 parent 6a1706b commit 2678bb0
Showing 2 changed files with 48 additions and 43 deletions.
72 changes: 29 additions & 43 deletions artiq/compiler/embedding.py
Original file line number Diff line number Diff line change
@@ -425,24 +425,18 @@ def _compute_value_type(self, object_value, object_type, object_loc, attr_name,
attr_value_type = builtins.TList(builtins.TInt64())

if attr_value_type is None:
# Slow path. We don't know what exactly is the attribute value,
# so we quote it only for the error message that may possibly result.
ast = self.quote(attr_value, object_loc.loc)

def proxy_diagnostic(diag):
note = diagnostic.Diagnostic("note",
"while inferring a type for an attribute '{attr}' of a host object",
{"attr": attr_name},
loc)
diag.notes.append(note)

self.engine.process(diag)
note = diagnostic.Diagnostic("note",
"while inferring a type for an attribute '{attr}' of a host object",
{"attr": attr_name},
loc)

proxy_engine = diagnostic.Engine()
proxy_engine.process = proxy_diagnostic
Inferencer(engine=proxy_engine).visit(ast)
IntMonomorphizer(engine=proxy_engine).visit(ast)
attr_value_type = ast.type
with self.engine.context(note):
# Slow path. We don't know what exactly is the attribute value,
# so we quote it only for the error message that may possibly result.
ast = self.quote(attr_value, object_loc.expanded_from)
Inferencer(engine=self.engine).visit(ast)
IntMonomorphizer(engine=self.engine).visit(ast)
attr_value_type = ast.type

return attributes, attr_value_type

@@ -716,32 +710,24 @@ def _type_of_param(self, function, loc, param, is_syscall):
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.
# This is tricky, because the default value might not have
# a well-defined type in APython.
# In this case, we bail out, but mention why we do it.
ast = self._quote(param.default, None)

def proxy_diagnostic(diag):
note = diagnostic.Diagnostic("note",
"expanded from here while trying to infer a type for an"
" unannotated optional argument '{argument}' from its default value",
{"argument": param.name},
self._function_loc(function))
diag.notes.append(note)

note = self._call_site_note(loc, is_syscall)
if note:
diag.notes += note

self.engine.process(diag)

proxy_engine = diagnostic.Engine()
proxy_engine.process = proxy_diagnostic
Inferencer(engine=proxy_engine).visit(ast)
IntMonomorphizer(engine=proxy_engine).visit(ast)

return ast.type
notes = []
notes.append(diagnostic.Diagnostic("note",
"expanded from here while trying to infer a type for an"
" unannotated optional argument '{argument}' from its default value",
{"argument": param.name},
self._function_loc(function)))
if loc is not None:
notes.append(self._call_site_note(loc, is_syscall))

with self.engine.context(*notes):
# Try and infer the type from the default value.
# This is tricky, because the default value might not have
# a well-defined type in APython.
# In this case, we bail out, but mention why we do it.
ast = self._quote(param.default, None)
Inferencer(engine=self.engine).visit(ast)
IntMonomorphizer(engine=self.engine).visit(ast)
return ast.type
else:
# Let the rest of the program decide.
return types.TVar()
19 changes: 19 additions & 0 deletions artiq/test/lit/embedding/error_host_only.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t
# RUN: OutputCheck %s --file-to-check=%t

from artiq.language.core import *
from artiq.language.types import *

class foo:
# CHECK-L: ${LINE:+2}: fatal: this function cannot be called as an RPC
@host_only
def pause(self):
pass

x = foo()

@kernel
def entrypoint():
# CHECK-L: ${LINE:+2}: note: in function called remotely here
# CHECK-L: ${LINE:+1}: note: while inferring a type for an attribute 'pause' of a host object
x.pause()

0 comments on commit 2678bb0

Please sign in to comment.