From f430bf3f638b793d7365a8fcd5abc4cd060eec59 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 29 Jun 2015 00:31:06 +0300 Subject: [PATCH] Add support for exceptions. --- artiq/py2llvm/asttyped.py | 4 +++ artiq/py2llvm/builtins.py | 2 +- artiq/py2llvm/types.py | 3 ++ artiq/py2llvm/typing.py | 41 +++++++++++++++++++++- lit-test/py2llvm/typing/error_exception.py | 14 ++++++++ lit-test/py2llvm/typing/exception.py | 8 +++++ 6 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 lit-test/py2llvm/typing/error_exception.py diff --git a/artiq/py2llvm/asttyped.py b/artiq/py2llvm/asttyped.py index a9762ac4e..c592161e6 100644 --- a/artiq/py2llvm/asttyped.py +++ b/artiq/py2llvm/asttyped.py @@ -33,6 +33,10 @@ class FunctionDefT(ast.FunctionDef, scoped): class ModuleT(ast.Module, scoped): pass +class ExceptHandlerT(ast.ExceptHandler, commontyped): + _fields = ("filter", "name", "body") # rename ast.ExceptHandler.type + _types = ("name_type",) + class AttributeT(ast.Attribute, commontyped): pass class BinOpT(ast.BinOp, commontyped): diff --git a/artiq/py2llvm/builtins.py b/artiq/py2llvm/builtins.py index c1dcfb7ba..9e44e0da7 100644 --- a/artiq/py2llvm/builtins.py +++ b/artiq/py2llvm/builtins.py @@ -125,7 +125,7 @@ def is_builtin(typ, name): return isinstance(typ, types.TBuiltin) and \ typ.name == name -def is_exception(typ, name=None): +def is_exn_constructor(typ, name=None): typ = typ.find() if name is not None: return isinstance(typ, types.TExceptionConstructor) and \ diff --git a/artiq/py2llvm/types.py b/artiq/py2llvm/types.py index 4f1bc4dfc..388b1d6ff 100644 --- a/artiq/py2llvm/types.py +++ b/artiq/py2llvm/types.py @@ -227,6 +227,9 @@ class TExceptionConstructor(TBuiltin): Note that this is not the same as the type of an instance of the class, which is ``TMono("Exception", ...)``. """ + def to_exception_type(self): + # Exceptions currently can't have type parameters + return TMono(self.name, {}) class TValue(Type): """ diff --git a/artiq/py2llvm/typing.py b/artiq/py2llvm/typing.py index f16191fd8..dc4ffdb33 100644 --- a/artiq/py2llvm/typing.py +++ b/artiq/py2llvm/typing.py @@ -328,6 +328,15 @@ class ASTTypedRewriter(algorithm.Transformer): finally: self.env_stack.pop() + def visit_ExceptHandler(self, node): + node = self.generic_visit(node) + node = asttyped.ExceptHandlerT( + name_type=self._find_name(node.name, node.name_loc), + filter=node.type, name=node.name, body=node.body, + except_loc=node.except_loc, as_loc=node.as_loc, name_loc=node.name_loc, + colon_loc=node.colon_loc, loc=node.loc) + return node + def visit_Raise(self, node): node = self.generic_visit(node) if node.cause: @@ -363,7 +372,6 @@ class ASTTypedRewriter(algorithm.Transformer): visit_Delete = visit_unsupported visit_Import = visit_unsupported visit_ImportFrom = visit_unsupported - visit_Try = visit_unsupported class Inferencer(algorithm.Visitor): @@ -1070,6 +1078,30 @@ class Inferencer(algorithm.Visitor): node.context_expr.loc) self.engine.process(diag) + def visit_ExceptHandlerT(self, node): + self.generic_visit(node) + + if not builtins.is_exn_constructor(node.filter.type): + diag = diagnostic.Diagnostic("error", + "this expression must refer to an exception constructor", + {"type": types.TypePrinter().name(node.filter.type)}, + node.filter.loc) + self.engine.process(diag) + else: + def makenotes(printer, typea, typeb, loca, locb): + return [ + diagnostic.Diagnostic("note", + "expression of type {typea}", + {"typea": printer.name(typea)}, + loca), + diagnostic.Diagnostic("note", + "constructor of an exception of type {typeb}", + {"typeb": printer.name(typeb)}, + locb) + ] + self._unify(node.name_type, node.filter.type.to_exception_type(), + node.name_loc, node.filter.loc, makenotes) + def _type_from_arguments(self, node, ret): self.generic_visit(node) @@ -1166,6 +1198,13 @@ class Printer(algorithm.Visitor): self.rewriter.insert_before(node.colon_loc, "->{}".format(self.type_printer.name(node.return_type))) + def visit_ExceptHandlerT(self, node): + super().generic_visit(node) + + if node.name_loc: + self.rewriter.insert_after(node.name_loc, + ":{}".format(self.type_printer.name(node.name_type))) + def generic_visit(self, node): super().generic_visit(node) diff --git a/lit-test/py2llvm/typing/error_exception.py b/lit-test/py2llvm/typing/error_exception.py new file mode 100644 index 000000000..e418b9b8a --- /dev/null +++ b/lit-test/py2llvm/typing/error_exception.py @@ -0,0 +1,14 @@ +# RUN: %python -m artiq.py2llvm.typing +diag %s >%t +# RUN: OutputCheck %s --file-to-check=%t + +try: + pass +# CHECK-L: ${LINE:+1}: error: this expression must refer to an exception constructor +except 1: + pass + +try: + pass +# CHECK-L: ${LINE:+1}: error: cannot unify int(width='a) with Exception +except Exception as e: + e = 1 diff --git a/lit-test/py2llvm/typing/exception.py b/lit-test/py2llvm/typing/exception.py index 5500d96a0..e7ce38b8d 100644 --- a/lit-test/py2llvm/typing/exception.py +++ b/lit-test/py2llvm/typing/exception.py @@ -3,3 +3,11 @@ # CHECK-L: Exception: Exception + +try: + pass +except Exception: + pass +except Exception as e: + # CHECK-L: e:Exception + e