Add support for exceptions.

This commit is contained in:
whitequark 2015-06-29 00:31:06 +03:00
parent a4a9cd884e
commit f430bf3f63
6 changed files with 70 additions and 2 deletions

View File

@ -33,6 +33,10 @@ class FunctionDefT(ast.FunctionDef, scoped):
class ModuleT(ast.Module, scoped): class ModuleT(ast.Module, scoped):
pass pass
class ExceptHandlerT(ast.ExceptHandler, commontyped):
_fields = ("filter", "name", "body") # rename ast.ExceptHandler.type
_types = ("name_type",)
class AttributeT(ast.Attribute, commontyped): class AttributeT(ast.Attribute, commontyped):
pass pass
class BinOpT(ast.BinOp, commontyped): class BinOpT(ast.BinOp, commontyped):

View File

@ -125,7 +125,7 @@ def is_builtin(typ, name):
return isinstance(typ, types.TBuiltin) and \ return isinstance(typ, types.TBuiltin) and \
typ.name == name typ.name == name
def is_exception(typ, name=None): def is_exn_constructor(typ, name=None):
typ = typ.find() typ = typ.find()
if name is not None: if name is not None:
return isinstance(typ, types.TExceptionConstructor) and \ return isinstance(typ, types.TExceptionConstructor) and \

View File

@ -227,6 +227,9 @@ class TExceptionConstructor(TBuiltin):
Note that this is not the same as the type of an instance of Note that this is not the same as the type of an instance of
the class, which is ``TMono("Exception", ...)``. 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): class TValue(Type):
""" """

View File

@ -328,6 +328,15 @@ class ASTTypedRewriter(algorithm.Transformer):
finally: finally:
self.env_stack.pop() 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): def visit_Raise(self, node):
node = self.generic_visit(node) node = self.generic_visit(node)
if node.cause: if node.cause:
@ -363,7 +372,6 @@ class ASTTypedRewriter(algorithm.Transformer):
visit_Delete = visit_unsupported visit_Delete = visit_unsupported
visit_Import = visit_unsupported visit_Import = visit_unsupported
visit_ImportFrom = visit_unsupported visit_ImportFrom = visit_unsupported
visit_Try = visit_unsupported
class Inferencer(algorithm.Visitor): class Inferencer(algorithm.Visitor):
@ -1070,6 +1078,30 @@ class Inferencer(algorithm.Visitor):
node.context_expr.loc) node.context_expr.loc)
self.engine.process(diag) 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): def _type_from_arguments(self, node, ret):
self.generic_visit(node) self.generic_visit(node)
@ -1166,6 +1198,13 @@ class Printer(algorithm.Visitor):
self.rewriter.insert_before(node.colon_loc, self.rewriter.insert_before(node.colon_loc,
"->{}".format(self.type_printer.name(node.return_type))) "->{}".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): def generic_visit(self, node):
super().generic_visit(node) super().generic_visit(node)

View File

@ -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

View File

@ -3,3 +3,11 @@
# CHECK-L: Exception:<constructor Exception> # CHECK-L: Exception:<constructor Exception>
Exception Exception
try:
pass
except Exception:
pass
except Exception as e:
# CHECK-L: e:Exception
e