Skip to content

Commit 7cd6011

Browse files
author
whitequark
committedJun 26, 2015
Add typechecking for most builtin.
1 parent 7520311 commit 7cd6011

File tree

4 files changed

+138
-22
lines changed

4 files changed

+138
-22
lines changed
 

Diff for: ‎artiq/py2llvm/builtins.py

+14-2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,18 @@ def __init__(self, elt=None):
3131
elt = types.TVar()
3232
super().__init__("list", {"elt": elt})
3333

34+
def fn_bool():
35+
return types.TBuiltin("class bool")
36+
37+
def fn_int():
38+
return types.TBuiltin("class int")
39+
40+
def fn_float():
41+
return types.TBuiltin("class float")
42+
43+
def fn_list():
44+
return types.TBuiltin("class list")
45+
3446
def fn_len():
3547
return types.TBuiltin("function len")
3648

@@ -80,7 +92,7 @@ def is_collection(typ):
8092
return isinstance(typ, types.TTuple) or \
8193
types.is_mono(typ, "list")
8294

83-
def is_function(typ, name):
95+
def is_builtin(typ, name):
8496
typ = typ.find()
8597
return isinstance(typ, types.TBuiltin) and \
86-
typ.name == "function " + name
98+
typ.name == name

Diff for: ‎artiq/py2llvm/prelude.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@
77

88
def globals():
99
return {
10-
"bool": builtins.TBool(),
11-
"int": builtins.TInt(),
12-
"float": builtins.TFloat(),
10+
"bool": builtins.fn_bool(),
11+
"int": builtins.fn_int(),
12+
"float": builtins.fn_float(),
13+
"list": builtins.fn_list(),
1314
"len": builtins.fn_len(),
1415
"round": builtins.fn_round(),
1516
"range": builtins.fn_range(),

Diff for: ‎artiq/py2llvm/typing.py

+90-17
Original file line numberDiff line numberDiff line change
@@ -716,62 +716,135 @@ def visit_comprehension(self, node):
716716
self._unify_collection(element=node.target, collection=node.iter)
717717

718718
def visit_builtin_call(self, node):
719-
if types.is_mono(node.func.type):
720-
func_name = "function " + node.func.type.find().name
721-
elif builtins.is_function(node.func.type):
722-
func_name = node.func.type.find().name
719+
typ = node.func.type.find()
723720

724721
def valid_form(signature):
725722
return diagnostic.Diagnostic("note",
726723
"{func} can be invoked as: {signature}",
727-
{"func": func_name},
724+
{"func": typ.name, "signature": signature},
728725
node.func.loc)
729726

730727
def diagnose(valid_forms):
731728
diag = diagnostic.Diagnostic("error",
732729
"{func} cannot be invoked with these arguments",
733-
{"func": func_name},
730+
{"func": typ.name},
734731
node.func.loc, notes=valid_forms)
732+
self.engine.process(diag)
735733

736-
if builtins.is_bool(node.type):
734+
if builtins.is_builtin(typ, "class bool"):
737735
valid_forms = lambda: [
738736
valid_form("bool() -> bool"),
739-
valid_form("bool(x:'a) -> bool where 'a is numeric")
737+
valid_form("bool(x:'a) -> bool")
740738
]
741-
elif builtins.is_int(node.type):
739+
740+
if len(node.args) == 0 and len(node.keywords) == 0:
741+
pass # False
742+
elif len(node.args) == 1 and len(node.keywords) == 0:
743+
arg, = node.args
744+
pass # anything goes
745+
else:
746+
diagnose(valid_forms())
747+
748+
self._unify(node.type, builtins.TBool(),
749+
node.loc, None)
750+
elif builtins.is_builtin(typ, "class int"):
742751
valid_forms = lambda: [
743752
valid_form("int() -> int(width='a)"),
744753
valid_form("int(x:'a) -> int(width='b) where 'a is numeric"),
745-
valid_form("int(x:'a, width='b <int literal>) -> int(width='b) where 'a is numeric")
754+
valid_form("int(x:'a, width='b:<int literal>) -> int(width='b) where 'a is numeric")
746755
]
747-
elif builtins.is_float(node.type):
756+
757+
self._unify(node.type, builtins.TInt(),
758+
node.loc, None)
759+
760+
if len(node.args) == 0 and len(node.keywords) == 0:
761+
pass # 0
762+
elif len(node.args) == 1 and len(node.keywords) == 0 and \
763+
builtins.is_numeric(node.args[0].type):
764+
pass
765+
elif len(node.args) == 1 and len(node.keywords) == 1 and \
766+
builtins.is_numeric(node.args[0].type) and \
767+
node.keywords[0].arg == 'width':
768+
width = node.keywords[0].value
769+
if not (isinstance(width, asttyped.NumT) and isinstance(width.n, int)):
770+
diag = diagnostic.Diagnostic("error",
771+
"the width argument of int() must be an integer literal", {},
772+
node.keywords[0].loc)
773+
774+
self._unify(node.type, builtins.TInt(types.TValue(width.n)),
775+
node.loc, None)
776+
else:
777+
diagnose(valid_forms())
778+
elif builtins.is_builtin(typ, "class float"):
748779
valid_forms = lambda: [
749780
valid_form("float() -> float"),
750781
valid_form("float(x:'a) -> float where 'a is numeric")
751782
]
752-
elif builtins.is_list(node.type):
783+
784+
self._unify(node.type, builtins.TFloat(),
785+
node.loc, None)
786+
787+
if len(node.args) == 0 and len(node.keywords) == 0:
788+
pass # 0.0
789+
elif len(node.args) == 1 and len(node.keywords) == 0 and \
790+
builtins.is_numeric(node.args[0].type):
791+
pass
792+
else:
793+
diagnose(valid_forms())
794+
elif builtins.is_builtin(typ, "class list"):
753795
valid_forms = lambda: [
754796
valid_form("list() -> list(elt='a)"),
755797
# TODO: add this form when adding iterators
756798
# valid_form("list(x) -> list(elt='a)")
757799
]
758-
elif builtins.is_function(node.type, "len"):
800+
801+
self._unify(node.type, builtins.TList(),
802+
node.loc, None)
803+
804+
if len(node.args) == 0 and len(node.keywords) == 0:
805+
pass # []
806+
else:
807+
diagnose(valid_forms())
808+
elif builtins.is_builtin(typ, "function len"):
759809
valid_forms = lambda: [
760810
valid_form("len(x:list(elt='a)) -> int(width='b)"),
761811
]
762-
elif builtins.is_function(node.type, "round"):
812+
813+
# TODO: should be ssize_t-sized
814+
self._unify(node.type, builtins.TInt(types.TValue(32)),
815+
node.loc, None)
816+
817+
if len(node.args) == 1 and len(node.keywords) == 0:
818+
arg, = node.args
819+
820+
self._unify(arg.type, builtins.TList(),
821+
arg.loc, None)
822+
else:
823+
diagnose(valid_forms())
824+
elif builtins.is_builtin(typ, "function round"):
763825
valid_forms = lambda: [
764826
valid_form("round(x:float) -> int(width='a)"),
765827
]
828+
829+
self._unify(node.type, builtins.TInt(),
830+
node.loc, None)
831+
832+
if len(node.args) == 1 and len(node.keywords) == 0:
833+
arg, = node.args
834+
835+
self._unify(arg.type, builtins.TFloat(),
836+
arg.loc, None)
837+
else:
838+
diagnose(valid_forms())
766839
# TODO: add when there are range types
767-
# elif builtins.is_function(node.type, "range"):
840+
# elif builtins.is_builtin(typ, "function range"):
768841
# valid_forms = lambda: [
769842
# valid_form("range(max:'a) -> range(elt='a)"),
770843
# valid_form("range(min:'a, max:'a) -> range(elt='a)"),
771844
# valid_form("range(min:'a, max:'a, step:'a) -> range(elt='a)"),
772845
# ]
773846
# TODO: add when it is clear what interface syscall() has
774-
# elif builtins.is_function(node.type, "syscall"):
847+
# elif builtins.is_builtin(typ, "function syscall"):
775848
# valid_Forms = lambda: [
776849
# ]
777850

@@ -790,7 +863,7 @@ def visit_CallT(self, node):
790863
if types.is_var(node.func.type):
791864
return # not enough info yet
792865
elif types.is_mono(node.func.type) or types.is_builtin(node.func.type):
793-
return self.visit_builtin_call(self, node)
866+
return self.visit_builtin_call(node)
794867
elif not types.is_function(node.func.type):
795868
diag = diagnostic.Diagnostic("error",
796869
"cannot call this expression of type {type}",

Diff for: ‎lit-test/py2llvm/typing/builtin_calls.py

+30
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,32 @@
11
# RUN: %python -m artiq.py2llvm.typing %s >%t
22
# RUN: OutputCheck %s --file-to-check=%t
3+
4+
# CHECK-L: bool:<built-in class bool>():bool
5+
bool()
6+
7+
# CHECK-L: bool:<built-in class bool>([]:list(elt='a)):bool
8+
bool([])
9+
10+
# CHECK-L: int:<built-in class int>():int(width='b)
11+
int()
12+
13+
# CHECK-L: int:<built-in class int>(1.0:float):int(width='c)
14+
int(1.0)
15+
16+
# CHECK-L: int:<built-in class int>(1.0:float, width=64:int(width='d)):int(width=64)
17+
int(1.0, width=64)
18+
19+
# CHECK-L: float:<built-in class float>():float
20+
float()
21+
22+
# CHECK-L: float:<built-in class float>(1:int(width='e)):float
23+
float(1)
24+
25+
# CHECK-L: list:<built-in class list>():list(elt='f)
26+
list()
27+
28+
# CHECK-L: len:<built-in function len>([]:list(elt='g)):int(width=32)
29+
len([])
30+
31+
# CHECK-L: round:<built-in function round>(1.0:float):int(width='h)
32+
round(1.0)

0 commit comments

Comments
 (0)
Please sign in to comment.