From 5a79fcf9baa471e202b6387aa5c2e028d9995627 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 7 Jul 2016 11:49:21 +0000 Subject: [PATCH] embedding: reimplement 373578bc properly. The core of the problem that 373578bc 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. --- artiq/compiler/embedding.py | 70 +++++++++------------ artiq/test/lit/embedding/error_host_only.py | 19 ++++++ 2 files changed, 47 insertions(+), 42 deletions(-) create mode 100644 artiq/test/lit/embedding/error_host_only.py diff --git a/artiq/compiler/embedding.py b/artiq/compiler/embedding.py index 0d35e63df..943550072 100644 --- a/artiq/compiler/embedding.py +++ b/artiq/compiler/embedding.py @@ -556,24 +556,18 @@ class StitchingInferencer(Inferencer): 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, loc) + note = diagnostic.Diagnostic("note", + "while inferring a type for an attribute '{attr}' of a host object", + {"attr": attr_name}, + 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) - - 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 @@ -840,32 +834,24 @@ class Stitcher: 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) + 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)) - 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 + 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() diff --git a/artiq/test/lit/embedding/error_host_only.py b/artiq/test/lit/embedding/error_host_only.py new file mode 100644 index 000000000..2e2eba6db --- /dev/null +++ b/artiq/test/lit/embedding/error_host_only.py @@ -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()