From 88fd5431b5ed7a709a0be60aa1afccbfddde499a Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 29 Apr 2016 13:05:11 +0000 Subject: [PATCH] compiler: make kernel_invariant an instance, not class, property. Fixes #409. --- artiq/compiler/embedding.py | 41 +++++++++++++++++-- artiq/compiler/testbench/embedding.py | 7 +++- artiq/test/lit/embedding/error_attr_absent.py | 2 +- .../embedding/error_attr_absent_suggest.py | 2 +- .../test/lit/embedding/error_attr_conflict.py | 2 +- .../test/lit/embedding/error_attr_constant.py | 2 +- artiq/test/lit/embedding/error_attr_unify.py | 2 +- .../embedding/error_name_absent_suggest.py | 2 +- .../lit/embedding/error_rpc_annot_return.py | 2 +- .../test/lit/embedding/error_syscall_annot.py | 2 +- .../embedding/error_syscall_annot_return.py | 2 +- artiq/test/lit/embedding/error_syscall_arg.py | 2 +- .../embedding/error_syscall_default_arg.py | 2 +- .../lit/embedding/error_syscall_return.py | 2 +- .../test/lit/embedding/warning_invariant_1.py | 22 ++++++++++ .../test/lit/embedding/warning_invariant_2.py | 22 ++++++++++ artiq/test/lit/escape/error_mutable_attr.py | 2 +- 17 files changed, 100 insertions(+), 18 deletions(-) create mode 100644 artiq/test/lit/embedding/warning_invariant_1.py create mode 100644 artiq/test/lit/embedding/warning_invariant_2.py diff --git a/artiq/compiler/embedding.py b/artiq/compiler/embedding.py index 641ef1c45..69cd7831e 100644 --- a/artiq/compiler/embedding.py +++ b/artiq/compiler/embedding.py @@ -55,6 +55,7 @@ class ASTSynthesizer: self.object_map, self.type_map, self.value_map = object_map, type_map, value_map self.quote_function = quote_function self.expanded_from = expanded_from + self.diagnostics = [] def finalize(self): self.source_buffer.source = self.source @@ -124,6 +125,35 @@ class ASTSynthesizer: if typ in self.type_map: instance_type, constructor_type = self.type_map[typ] + + if hasattr(value, 'kernel_invariants') and \ + value.kernel_invariants != instance_type.constant_attributes: + attr_diff = value.kernel_invariants.difference( + instance_type.constant_attributes) + if len(attr_diff) > 0: + diag = diagnostic.Diagnostic("warning", + "object {value} of type {typ} declares attribute(s) {attrs} as " + "kernel invariant, but other objects of the same type do not; " + "the invariant annotation on this object will be ignored", + {"value": repr(value), + "typ": types.TypePrinter().name(instance_type, max_depth=0), + "attrs": ", ".join(["'{}'".format(attr) for attr in attr_diff])}, + loc) + self.diagnostics.append(diag) + attr_diff = instance_type.constant_attributes.difference( + value.kernel_invariants) + if len(attr_diff) > 0: + diag = diagnostic.Diagnostic("warning", + "object {value} of type {typ} does not declare attribute(s) {attrs} as " + "kernel invariant, but other objects of the same type do; " + "the invariant annotation on other objects will be ignored", + {"value": repr(value), + "typ": types.TypePrinter().name(instance_type, max_depth=0), + "attrs": ", ".join(["'{}'".format(attr) for attr in attr_diff])}, + loc) + self.diagnostics.append(diag) + value.kernel_invariants = value.kernel_invariants.intersection( + instance_type.constant_attributes) else: if issubclass(typ, BaseException): if hasattr(typ, 'artiq_builtin'): @@ -138,16 +168,16 @@ class ASTSynthesizer: instance_type = types.TInstance("{}.{}".format(typ.__module__, typ.__qualname__), OrderedDict()) instance_type.attributes['__objectid__'] = builtins.TInt32() - if hasattr(typ, 'kernel_invariants'): - assert isinstance(typ.kernel_invariants, set) - instance_type.constant_attributes = typ.kernel_invariants - constructor_type = types.TConstructor(instance_type) constructor_type.attributes['__objectid__'] = builtins.TInt32() instance_type.constructor = constructor_type self.type_map[typ] = instance_type, constructor_type + if hasattr(value, 'kernel_invariants'): + assert isinstance(value.kernel_invariants, set) + instance_type.constant_attributes = value.kernel_invariants + if isinstance(value, type): self.value_map[constructor_type].append((value, loc)) return asttyped.QuoteT(value=value, type=constructor_type, @@ -801,4 +831,7 @@ class Stitcher: synthesizer = self._synthesizer(loc) node = synthesizer.quote(value) synthesizer.finalize() + if len(synthesizer.diagnostics) > 0: + for warning in synthesizer.diagnostics: + self.engine.process(warning) return node diff --git a/artiq/compiler/testbench/embedding.py b/artiq/compiler/testbench/embedding.py index d51e3ca99..01300c62a 100644 --- a/artiq/compiler/testbench/embedding.py +++ b/artiq/compiler/testbench/embedding.py @@ -3,8 +3,14 @@ import sys, os from artiq.master.databases import DeviceDB from artiq.master.worker_db import DeviceManager +import artiq.coredevice.core from artiq.coredevice.core import Core, CompileError +def _render_diagnostic(diagnostic, colored): + return "\n".join(diagnostic.render(only_line=True)) + +artiq.coredevice.core._render_diagnostic = _render_diagnostic + def main(): if len(sys.argv) > 1 and sys.argv[1] == "+diag": del sys.argv[1] @@ -35,7 +41,6 @@ def main(): print(core.comm.get_log()) core.comm.clear_log() except CompileError as error: - print("\n".join(error.__cause__.diagnostic.render(only_line=True))) if not diag: exit(1) diff --git a/artiq/test/lit/embedding/error_attr_absent.py b/artiq/test/lit/embedding/error_attr_absent.py index b39b0049b..986c5d06a 100644 --- a/artiq/test/lit/embedding/error_attr_absent.py +++ b/artiq/test/lit/embedding/error_attr_absent.py @@ -1,4 +1,4 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s >%t +# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t # RUN: OutputCheck %s --file-to-check=%t from artiq.language.core import * diff --git a/artiq/test/lit/embedding/error_attr_absent_suggest.py b/artiq/test/lit/embedding/error_attr_absent_suggest.py index b705a881f..474a5791a 100644 --- a/artiq/test/lit/embedding/error_attr_absent_suggest.py +++ b/artiq/test/lit/embedding/error_attr_absent_suggest.py @@ -1,4 +1,4 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s >%t +# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t # RUN: OutputCheck %s --file-to-check=%t from artiq.language.core import * diff --git a/artiq/test/lit/embedding/error_attr_conflict.py b/artiq/test/lit/embedding/error_attr_conflict.py index 307272d4c..e38d45fba 100644 --- a/artiq/test/lit/embedding/error_attr_conflict.py +++ b/artiq/test/lit/embedding/error_attr_conflict.py @@ -1,4 +1,4 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s >%t +# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t # RUN: OutputCheck %s --file-to-check=%t from artiq.language.core import * diff --git a/artiq/test/lit/embedding/error_attr_constant.py b/artiq/test/lit/embedding/error_attr_constant.py index 1adda638c..d20913408 100644 --- a/artiq/test/lit/embedding/error_attr_constant.py +++ b/artiq/test/lit/embedding/error_attr_constant.py @@ -1,4 +1,4 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s >%t +# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t # RUN: OutputCheck %s --file-to-check=%t from artiq.language.core import * diff --git a/artiq/test/lit/embedding/error_attr_unify.py b/artiq/test/lit/embedding/error_attr_unify.py index 4659d62be..b677d2822 100644 --- a/artiq/test/lit/embedding/error_attr_unify.py +++ b/artiq/test/lit/embedding/error_attr_unify.py @@ -1,4 +1,4 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s >%t +# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t # RUN: OutputCheck %s --file-to-check=%t from artiq.language.core import * diff --git a/artiq/test/lit/embedding/error_name_absent_suggest.py b/artiq/test/lit/embedding/error_name_absent_suggest.py index 1ab961291..561638010 100644 --- a/artiq/test/lit/embedding/error_name_absent_suggest.py +++ b/artiq/test/lit/embedding/error_name_absent_suggest.py @@ -1,4 +1,4 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s >%t +# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t # RUN: OutputCheck %s --file-to-check=%t from artiq.language.core import * diff --git a/artiq/test/lit/embedding/error_rpc_annot_return.py b/artiq/test/lit/embedding/error_rpc_annot_return.py index 0a092f287..b60709f7c 100644 --- a/artiq/test/lit/embedding/error_rpc_annot_return.py +++ b/artiq/test/lit/embedding/error_rpc_annot_return.py @@ -1,4 +1,4 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s >%t +# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t # RUN: OutputCheck %s --file-to-check=%t from artiq.language.core import * diff --git a/artiq/test/lit/embedding/error_syscall_annot.py b/artiq/test/lit/embedding/error_syscall_annot.py index 9cc1aeda5..4849910b3 100644 --- a/artiq/test/lit/embedding/error_syscall_annot.py +++ b/artiq/test/lit/embedding/error_syscall_annot.py @@ -1,4 +1,4 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s >%t +# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t # RUN: OutputCheck %s --file-to-check=%t from artiq.language.core import * diff --git a/artiq/test/lit/embedding/error_syscall_annot_return.py b/artiq/test/lit/embedding/error_syscall_annot_return.py index 36bde42b9..dfc24db9f 100644 --- a/artiq/test/lit/embedding/error_syscall_annot_return.py +++ b/artiq/test/lit/embedding/error_syscall_annot_return.py @@ -1,4 +1,4 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s >%t +# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t # RUN: OutputCheck %s --file-to-check=%t from artiq.language.core import * diff --git a/artiq/test/lit/embedding/error_syscall_arg.py b/artiq/test/lit/embedding/error_syscall_arg.py index da1862650..a077e7d57 100644 --- a/artiq/test/lit/embedding/error_syscall_arg.py +++ b/artiq/test/lit/embedding/error_syscall_arg.py @@ -1,4 +1,4 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s >%t +# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t # RUN: OutputCheck %s --file-to-check=%t from artiq.language.core import * diff --git a/artiq/test/lit/embedding/error_syscall_default_arg.py b/artiq/test/lit/embedding/error_syscall_default_arg.py index ce556cb23..0bfdce88a 100644 --- a/artiq/test/lit/embedding/error_syscall_default_arg.py +++ b/artiq/test/lit/embedding/error_syscall_default_arg.py @@ -1,4 +1,4 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s >%t +# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t # RUN: OutputCheck %s --file-to-check=%t from artiq.language.core import * diff --git a/artiq/test/lit/embedding/error_syscall_return.py b/artiq/test/lit/embedding/error_syscall_return.py index de38b02a5..bad7b20d1 100644 --- a/artiq/test/lit/embedding/error_syscall_return.py +++ b/artiq/test/lit/embedding/error_syscall_return.py @@ -1,4 +1,4 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s >%t +# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t # RUN: OutputCheck %s --file-to-check=%t from artiq.language.core import * diff --git a/artiq/test/lit/embedding/warning_invariant_1.py b/artiq/test/lit/embedding/warning_invariant_1.py new file mode 100644 index 000000000..5a0b8bdd1 --- /dev/null +++ b/artiq/test/lit/embedding/warning_invariant_1.py @@ -0,0 +1,22 @@ +# 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 c: + a = b = 0 + def __init__(self, invariants): + self.kernel_invariants = invariants + + def __repr__(self): + return "" + +i1 = c({'a'}) +i2 = c({'a', 'b'}) + +@kernel +def entrypoint(): + # CHECK-L: :1: warning: object of type declares attribute(s) 'b' as kernel invariant, but other objects of the same type do not; the invariant annotation on this object will be ignored + # CHECK-L: ${LINE:+1}: note: expanded from here + [i1, i2] diff --git a/artiq/test/lit/embedding/warning_invariant_2.py b/artiq/test/lit/embedding/warning_invariant_2.py new file mode 100644 index 000000000..4160a29c0 --- /dev/null +++ b/artiq/test/lit/embedding/warning_invariant_2.py @@ -0,0 +1,22 @@ +# 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 c: + a = b = 0 + def __init__(self, invariants): + self.kernel_invariants = invariants + + def __repr__(self): + return "" + +i1 = c({'a', 'b'}) +i2 = c({'a'}) + +@kernel +def entrypoint(): + # CHECK-L: :1: warning: object of type does not declare attribute(s) 'b' as kernel invariant, but other objects of the same type do; the invariant annotation on other objects will be ignored + # CHECK-L: ${LINE:+1}: note: expanded from here + [i1, i2] diff --git a/artiq/test/lit/escape/error_mutable_attr.py b/artiq/test/lit/escape/error_mutable_attr.py index f626cb24c..2d5bc885a 100644 --- a/artiq/test/lit/escape/error_mutable_attr.py +++ b/artiq/test/lit/escape/error_mutable_attr.py @@ -1,4 +1,4 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s >%t +# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t # RUN: OutputCheck %s --file-to-check=%t from artiq.experiment import *