Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: m-labs/artiq
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: ea0d11b8be9b
Choose a base ref
...
head repository: m-labs/artiq
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: f430bf3f638b
Choose a head ref
  • 3 commits
  • 9 files changed
  • 1 contributor

Commits on Jun 28, 2015

  1. Elaborate hierarchy of builtins.

    whitequark committed Jun 28, 2015
    Copy the full SHA
    9044e88 View commit details
  2. Add exception constructor types.

    whitequark committed Jun 28, 2015
    Copy the full SHA
    a4a9cd8 View commit details
  3. Add support for exceptions.

    whitequark committed Jun 28, 2015
    Copy the full SHA
    f430bf3 View commit details
4 changes: 4 additions & 0 deletions artiq/py2llvm/asttyped.py
Original file line number Diff line number Diff line change
@@ -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):
37 changes: 26 additions & 11 deletions artiq/py2llvm/builtins.py
Original file line number Diff line number Diff line change
@@ -37,29 +37,36 @@ def __init__(self, elt=None):
elt = types.TVar()
super().__init__("range", {"elt": elt})

class TException(types.TMono):
def __init__(self):
super().__init__("Exception")

def fn_bool():
return types.TBuiltin("class bool")
return types.TConstructor("bool")

def fn_int():
return types.TBuiltin("class int")
return types.TConstructor("int")

def fn_float():
return types.TBuiltin("class float")
return types.TConstructor("float")

def fn_list():
return types.TBuiltin("class list")
return types.TConstructor("list")

def fn_Exception():
return types.TExceptionConstructor("Exception")

def fn_range():
return types.TBuiltin("function range")
return types.TBuiltinFunction("range")

def fn_len():
return types.TBuiltin("function len")
return types.TBuiltinFunction("len")

def fn_round():
return types.TBuiltin("function round")
return types.TBuiltinFunction("round")

def fn_syscall():
return types.TBuiltin("function syscall")
return types.TBuiltinFunction("syscall")

# Accessors

@@ -70,7 +77,7 @@ def is_bool(typ):
return types.is_mono(typ, "bool")

def is_int(typ, width=None):
if width:
if width is not None:
return types.is_mono(typ, "int", {"width": width})
else:
return types.is_mono(typ, "int")
@@ -88,13 +95,13 @@ def is_numeric(typ):
typ.name in ('int', 'float')

def is_list(typ, elt=None):
if elt:
if elt is not None:
return types.is_mono(typ, "list", {"elt": elt})
else:
return types.is_mono(typ, "list")

def is_range(typ, elt=None):
if elt:
if elt is not None:
return types.is_mono(typ, "range", {"elt": elt})
else:
return types.is_mono(typ, "range")
@@ -117,3 +124,11 @@ def is_builtin(typ, name):
typ = typ.find()
return isinstance(typ, types.TBuiltin) and \
typ.name == name

def is_exn_constructor(typ, name=None):
typ = typ.find()
if name is not None:
return isinstance(typ, types.TExceptionConstructor) and \
typ.name == name
else:
return isinstance(typ, types.TExceptionConstructor)
17 changes: 9 additions & 8 deletions artiq/py2llvm/prelude.py
Original file line number Diff line number Diff line change
@@ -7,12 +7,13 @@

def globals():
return {
"bool": builtins.fn_bool(),
"int": builtins.fn_int(),
"float": builtins.fn_float(),
"list": builtins.fn_list(),
"range": builtins.fn_range(),
"len": builtins.fn_len(),
"round": builtins.fn_round(),
"syscall": builtins.fn_syscall(),
"bool": builtins.fn_bool(),
"int": builtins.fn_int(),
"float": builtins.fn_float(),
"list": builtins.fn_list(),
"range": builtins.fn_range(),
"Exception": builtins.fn_Exception(),
"len": builtins.fn_len(),
"round": builtins.fn_round(),
"syscall": builtins.fn_syscall(),
}
27 changes: 25 additions & 2 deletions artiq/py2llvm/types.py
Original file line number Diff line number Diff line change
@@ -209,6 +209,27 @@ def __eq__(self, other):
def __ne__(self, other):
return not (self == other)

class TBuiltinFunction(TBuiltin):
"""
A type of a builtin function.
"""

class TConstructor(TBuiltin):
"""
A type of a constructor of a builtin class, e.g. ``list``.
Note that this is not the same as the type of an instance of
the class, which is ``TMono("list", ...)``.
"""

class TExceptionConstructor(TBuiltin):
"""
A type of a constructor of a builtin exception, e.g. ``Exception``.
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):
"""
@@ -306,8 +327,10 @@ def name(self, typ):
args += [ "%s:%s" % (arg, self.name(typ.args[arg])) for arg in typ.args]
args += ["?%s:%s" % (arg, self.name(typ.optargs[arg])) for arg in typ.optargs]
return "(%s)->%s" % (", ".join(args), self.name(typ.ret))
elif isinstance(typ, TBuiltin):
return "<built-in %s>" % typ.name
elif isinstance(typ, TBuiltinFunction):
return "<function %s>" % typ.name
elif isinstance(typ, (TConstructor, TExceptionConstructor)):
return "<constructor %s>" % typ.name
elif isinstance(typ, TValue):
return repr(typ.value)
else:
57 changes: 48 additions & 9 deletions artiq/py2llvm/typing.py
Original file line number Diff line number Diff line change
@@ -328,6 +328,15 @@ def visit_Lambda(self, node):
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 @@ def visit_unsupported(self, node):
visit_Delete = visit_unsupported
visit_Import = visit_unsupported
visit_ImportFrom = visit_unsupported
visit_Try = visit_unsupported


class Inferencer(algorithm.Visitor):
@@ -739,7 +747,7 @@ def diagnose(valid_forms):
node.func.loc, notes=valid_forms)
self.engine.process(diag)

if builtins.is_builtin(typ, "class bool"):
if builtins.is_builtin(typ, "bool"):
valid_forms = lambda: [
valid_form("bool() -> bool"),
valid_form("bool(x:'a) -> bool")
@@ -755,7 +763,7 @@ def diagnose(valid_forms):

self._unify(node.type, builtins.TBool(),
node.loc, None)
elif builtins.is_builtin(typ, "class int"):
elif builtins.is_builtin(typ, "int"):
valid_forms = lambda: [
valid_form("int() -> int(width='a)"),
valid_form("int(x:'a) -> int(width='b) where 'a is numeric"),
@@ -785,7 +793,7 @@ def diagnose(valid_forms):
node.loc, None)
else:
diagnose(valid_forms())
elif builtins.is_builtin(typ, "class float"):
elif builtins.is_builtin(typ, "float"):
valid_forms = lambda: [
valid_form("float() -> float"),
valid_form("float(x:'a) -> float where 'a is numeric")
@@ -801,7 +809,7 @@ def diagnose(valid_forms):
pass
else:
diagnose(valid_forms())
elif builtins.is_builtin(typ, "class list"):
elif builtins.is_builtin(typ, "list"):
valid_forms = lambda: [
valid_form("list() -> list(elt='a)"),
valid_form("list(x:'a) -> list(elt='b) where 'a is iterable")
@@ -828,7 +836,7 @@ def diagnose(valid_forms):
self.engine.process(diag)
else:
diagnose(valid_forms())
elif builtins.is_builtin(typ, "function range"):
elif builtins.is_builtin(typ, "range"):
valid_forms = lambda: [
valid_form("range(max:'a) -> range(elt='a)"),
valid_form("range(min:'a, max:'a) -> range(elt='a)"),
@@ -855,7 +863,7 @@ def diagnose(valid_forms):
self.engine.process(diag)
else:
diagnose(valid_forms())
elif builtins.is_builtin(typ, "function len"):
elif builtins.is_builtin(typ, "len"):
valid_forms = lambda: [
valid_form("len(x:'a) -> int(width='b) where 'a is iterable"),
]
@@ -880,7 +888,7 @@ def diagnose(valid_forms):
self.engine.process(diag)
else:
diagnose(valid_forms())
elif builtins.is_builtin(typ, "function round"):
elif builtins.is_builtin(typ, "round"):
valid_forms = lambda: [
valid_form("round(x:float) -> int(width='a)"),
]
@@ -896,7 +904,7 @@ def diagnose(valid_forms):
else:
diagnose(valid_forms())
# TODO: add when it is clear what interface syscall() has
# elif builtins.is_builtin(typ, "function syscall"):
# elif builtins.is_builtin(typ, "syscall"):
# valid_Forms = lambda: [
# ]

@@ -1070,6 +1078,30 @@ def visit_withitem(self, node):
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 @@ def visit_FunctionDefT(self, node):
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)

20 changes: 10 additions & 10 deletions lit-test/py2llvm/typing/builtin_calls.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
# RUN: %python -m artiq.py2llvm.typing %s >%t
# RUN: OutputCheck %s --file-to-check=%t

# CHECK-L: bool:<built-in class bool>():bool
# CHECK-L: bool:<constructor bool>():bool
bool()

# CHECK-L: bool:<built-in class bool>([]:list(elt='a)):bool
# CHECK-L: bool:<constructor bool>([]:list(elt='a)):bool
bool([])

# CHECK-L: int:<built-in class int>():int(width='b)
# CHECK-L: int:<constructor int>():int(width='b)
int()

# CHECK-L: int:<built-in class int>(1.0:float):int(width='c)
# CHECK-L: int:<constructor int>(1.0:float):int(width='c)
int(1.0)

# CHECK-L: int:<built-in class int>(1.0:float, width=64:int(width='d)):int(width=64)
# CHECK-L: int:<constructor int>(1.0:float, width=64:int(width='d)):int(width=64)
int(1.0, width=64)

# CHECK-L: float:<built-in class float>():float
# CHECK-L: float:<constructor float>():float
float()

# CHECK-L: float:<built-in class float>(1:int(width='e)):float
# CHECK-L: float:<constructor float>(1:int(width='e)):float
float(1)

# CHECK-L: list:<built-in class list>():list(elt='f)
# CHECK-L: list:<constructor list>():list(elt='f)
list()

# CHECK-L: len:<built-in function len>([]:list(elt='g)):int(width=32)
# CHECK-L: len:<function len>([]:list(elt='g)):int(width=32)
len([])

# CHECK-L: round:<built-in function round>(1.0:float):int(width='h)
# CHECK-L: round:<function round>(1.0:float):int(width='h)
round(1.0)
14 changes: 14 additions & 0 deletions lit-test/py2llvm/typing/error_exception.py
Original file line number Diff line number Diff line change
@@ -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
13 changes: 13 additions & 0 deletions lit-test/py2llvm/typing/exception.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# RUN: %python -m artiq.py2llvm.typing %s >%t
# RUN: OutputCheck %s --file-to-check=%t

# CHECK-L: Exception:<constructor Exception>
Exception

try:
pass
except Exception:
pass
except Exception as e:
# CHECK-L: e:Exception
e
2 changes: 1 addition & 1 deletion lit-test/py2llvm/typing/prelude.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# RUN: %python -m artiq.py2llvm.typing %s >%t
# RUN: OutputCheck %s --file-to-check=%t

# CHECK-L: x:<built-in function len>
# CHECK-L: x:<function len>
x = len

def f():