From f4e6b18690c327410464bc6bb624f8264d34deb2 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sun, 27 Mar 2016 16:10:01 +0000 Subject: [PATCH] compiler: implement kernel constant attributes. Part of #322. --- artiq/compiler/analyses/__init__.py | 1 + artiq/compiler/analyses/constness.py | 30 +++++++++++++++++++ artiq/compiler/embedding.py | 3 ++ artiq/compiler/module.py | 2 ++ artiq/compiler/types.py | 1 + .../test/lit/embedding/error_attr_constant.py | 18 +++++++++++ 6 files changed, 55 insertions(+) create mode 100644 artiq/compiler/analyses/constness.py create mode 100644 artiq/test/lit/embedding/error_attr_constant.py diff --git a/artiq/compiler/analyses/__init__.py b/artiq/compiler/analyses/__init__.py index 708b325ef..f1553fc74 100644 --- a/artiq/compiler/analyses/__init__.py +++ b/artiq/compiler/analyses/__init__.py @@ -1,2 +1,3 @@ +from .constness import Constness from .domination import DominatorTree from .devirtualization import Devirtualization diff --git a/artiq/compiler/analyses/constness.py b/artiq/compiler/analyses/constness.py new file mode 100644 index 000000000..4fab07ea4 --- /dev/null +++ b/artiq/compiler/analyses/constness.py @@ -0,0 +1,30 @@ +""" +:class:`Constness` checks that no attribute marked +as constant is ever set. +""" + +from pythonparser import algorithm, diagnostic +from .. import types + +class Constness(algorithm.Visitor): + def __init__(self, engine): + self.engine = engine + self.in_assign = False + + def visit_Assign(self, node): + self.visit(node.value) + self.in_assign = True + self.visit(node.targets) + self.in_assign = False + + def visit_AttributeT(self, node): + self.generic_visit(node) + if self.in_assign: + typ = node.value.type.find() + if types.is_instance(typ) and node.attr in typ.constant_attributes: + diag = diagnostic.Diagnostic("error", + "cannot assign to constant attribute '{attr}' of class '{class}'", + {"attr": node.attr, "class": typ.name}, + node.loc) + self.engine.process(diag) + return diff --git a/artiq/compiler/embedding.py b/artiq/compiler/embedding.py index caa02bc9b..fe4f41642 100644 --- a/artiq/compiler/embedding.py +++ b/artiq/compiler/embedding.py @@ -137,6 +137,9 @@ class ASTSynthesizer: instance_type = types.TInstance("{}.{}".format(typ.__module__, typ.__qualname__), OrderedDict()) instance_type.attributes['__objectid__'] = builtins.TInt32() + if hasattr(typ, 'kernel_constant_attributes'): + assert isinstance(typ.kernel_constant_attributes, set) + instance_type.constant_attributes = typ.kernel_constant_attributes constructor_type = types.TConstructor(instance_type) constructor_type.attributes['__objectid__'] = builtins.TInt32() diff --git a/artiq/compiler/module.py b/artiq/compiler/module.py index 06c3a2615..b3c324fc2 100644 --- a/artiq/compiler/module.py +++ b/artiq/compiler/module.py @@ -56,6 +56,7 @@ class Module: escape_validator = validators.EscapeValidator(engine=self.engine) iodelay_estimator = transforms.IODelayEstimator(engine=self.engine, ref_period=ref_period) + constness = analyses.Constness(engine=self.engine) artiq_ir_generator = transforms.ARTIQIRGenerator(engine=self.engine, module_name=src.name, ref_period=ref_period) @@ -71,6 +72,7 @@ class Module: monomorphism_validator.visit(src.typedtree) escape_validator.visit(src.typedtree) iodelay_estimator.visit_fixpoint(src.typedtree) + constness.visit(src.typedtree) devirtualization.visit(src.typedtree) self.artiq_ir = artiq_ir_generator.visit(src.typedtree) artiq_ir_generator.annotate_calls(devirtualization) diff --git a/artiq/compiler/types.py b/artiq/compiler/types.py index ec4701852..878b40089 100644 --- a/artiq/compiler/types.py +++ b/artiq/compiler/types.py @@ -443,6 +443,7 @@ class TInstance(TMono): assert isinstance(attributes, OrderedDict) super().__init__(name) self.attributes = attributes + self.constant_attributes = set() def __repr__(self): return "artiq.compiler.types.TInstance({}, {})".format( diff --git a/artiq/test/lit/embedding/error_attr_constant.py b/artiq/test/lit/embedding/error_attr_constant.py new file mode 100644 index 000000000..22e8fe977 --- /dev/null +++ b/artiq/test/lit/embedding/error_attr_constant.py @@ -0,0 +1,18 @@ +# RUN: %python -m artiq.compiler.testbench.embedding +diag %s >%t +# RUN: OutputCheck %s --file-to-check=%t + +from artiq.language.core import * +from artiq.language.types import * + +class c: + kernel_constant_attributes = {'a'} + + def __init__(self): + self.a = 1 + +i = c() + +@kernel +def entrypoint(): + # CHECK-L: ${LINE:+1}: error: cannot assign to constant attribute 'a' of class 'testbench.c' + i.a = 1