/rpython/rtyper/test/test_rpbc.py
Python | 2072 lines | 1799 code | 248 blank | 25 comment | 236 complexity | 1ea9b5714e8b86266151f05e069e4956 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
Large files files are truncated, but you can click here to view the full file
- import py
- from rpython.annotator import model as annmodel
- from rpython.annotator import specialize
- from rpython.rtyper.lltypesystem.lltype import typeOf
- from rpython.rtyper.test.tool import BaseRtypingTest
- from rpython.rtyper.llannotation import SomePtr, lltype_to_annotation
- class MyBase:
- def m(self, x):
- return self.z + x
- class MySubclass(MyBase):
- def m(self, x):
- return self.z - x
- class MyStrangerSubclass(MyBase):
- def m(self, x, y):
- return x*y
- class MyBaseWithInit:
- def __init__(self, a):
- self.a1 = a
- class MySubclassWithInit(MyBaseWithInit):
- def __init__(self, a, b):
- MyBaseWithInit.__init__(self, a)
- self.b1 = b
- class MySubclassWithoutInit(MyBaseWithInit):
- pass
- class MySubclassWithoutMethods(MyBase):
- pass
- class Freezing:
- def _freeze_(self):
- return True
- def mymethod(self, y):
- return self.x + y
- class TestRPBC(BaseRtypingTest):
- def test_easy_call(self):
- def f(x):
- return x+1
- def g(y):
- return f(y+2)
- res = self.interpret(g, [5])
- assert res == 8
- def test_multiple_call(self):
- def f1(x):
- return x+1
- def f2(x):
- return x+2
- def g(y):
- if y < 0:
- f = f1
- else:
- f = f2
- return f(y+3)
- res = self.interpret(g, [-1])
- assert res == 3
- res = self.interpret(g, [1])
- assert res == 6
- def test_function_is_null(self):
- def f1(x):
- return x+1
- def f2(x):
- return x+2
- def g(x):
- if x < 0:
- return None
- elif x == 0:
- return f2
- else:
- return f1
- def fn(x):
- func = g(x)
- if func:
- return 42
- else:
- return 43
- assert self.interpret(fn, [1]) == 42
- assert self.interpret(fn, [-1]) == 43
- def test_method_call(self):
- def f(a, b):
- obj = MyBase()
- obj.z = a
- return obj.m(b)
- res = self.interpret(f, [4, 5])
- assert res == 9
- def test_virtual_method_call(self):
- def f(a, b):
- if a > 0:
- obj = MyBase()
- else:
- obj = MySubclass()
- obj.z = a
- return obj.m(b)
- res = self.interpret(f, [1, 2.3])
- assert res == 3.3
- res = self.interpret(f, [-1, 2.3])
- assert res == -3.3
- def test_stranger_subclass_1(self):
- def f1():
- obj = MyStrangerSubclass()
- obj.z = 100
- return obj.m(6, 7)
- res = self.interpret(f1, [])
- assert res == 42
- def test_stranger_subclass_2(self):
- def f2():
- obj = MyStrangerSubclass()
- obj.z = 100
- return obj.m(6, 7) + MyBase.m(obj, 58)
- res = self.interpret(f2, [])
- assert res == 200
- def test_class_init(self):
- def f(a):
- instance = MyBaseWithInit(a)
- return instance.a1
- assert self.interpret(f, [5]) == 5
- def test_class_init_2(self):
- def f(a, b):
- instance = MySubclassWithInit(a, b)
- return instance.a1 * instance.b1
- assert self.interpret(f, [6, 7]) == 42
- def test_class_calling_init(self):
- def f():
- instance = MySubclassWithInit(1, 2)
- instance.__init__(3, 4)
- return instance.a1 * instance.b1
- assert self.interpret(f, []) == 12
- def test_class_init_w_kwds(self):
- def f(a):
- instance = MyBaseWithInit(a=a)
- return instance.a1
- assert self.interpret(f, [5]) == 5
- def test_class_init_2_w_kwds(self):
- def f(a, b):
- instance = MySubclassWithInit(a, b=b)
- return instance.a1 * instance.b1
- assert self.interpret(f, [6, 7]) == 42
- def test_class_init_inherited(self):
- def f(a):
- instance = MySubclassWithoutInit(a)
- return instance.a1
- assert self.interpret(f, [42]) == 42
- def test_class_method_inherited(self):
- # The strange names for this test are taken from richards,
- # where the problem originally arose.
- class Task:
- def waitTask(self, a):
- return a+1
- def fn(self, a):
- raise NotImplementedError
- def runTask(self, a):
- return self.fn(a)
- class HandlerTask(Task):
- def fn(self, a):
- return self.waitTask(a)+2
- class DeviceTask(Task):
- def fn(self, a):
- return self.waitTask(a)+3
- def f(a, b):
- if b:
- inst = HandlerTask()
- else:
- inst = DeviceTask()
- return inst.runTask(a)
- assert self.interpret(f, [42, True]) == 45
- assert self.interpret(f, [42, False]) == 46
- def test_freezing(self):
- fr1 = Freezing()
- fr2 = Freezing()
- fr1.x = 5
- fr2.x = 6
- def g(fr):
- return fr.x
- def f(n):
- if n > 0:
- fr = fr1
- elif n < 0:
- fr = fr2
- else:
- fr = None
- return g(fr)
- res = self.interpret(f, [1])
- assert res == 5
- res = self.interpret(f, [-1])
- assert res == 6
- def test_call_frozen_pbc_simple(self):
- fr1 = Freezing()
- fr1.x = 5
- def f(n):
- return fr1.mymethod(n)
- res = self.interpret(f, [6])
- assert res == 11
- def test_call_frozen_pbc_simple_w_kwds(self):
- fr1 = Freezing()
- fr1.x = 5
- def f(n):
- return fr1.mymethod(y=n)
- res = self.interpret(f, [6])
- assert res == 11
- def test_call_frozen_pbc_multiple(self):
- fr1 = Freezing()
- fr2 = Freezing()
- fr1.x = 5
- fr2.x = 6
- def f(n):
- if n > 0:
- fr = fr1
- else:
- fr = fr2
- return fr.mymethod(n)
- res = self.interpret(f, [1])
- assert res == 6
- res = self.interpret(f, [-1])
- assert res == 5
- def test_call_frozen_pbc_multiple_w_kwds(self):
- fr1 = Freezing()
- fr2 = Freezing()
- fr1.x = 5
- fr2.x = 6
- def f(n):
- if n > 0:
- fr = fr1
- else:
- fr = fr2
- return fr.mymethod(y=n)
- res = self.interpret(f, [1])
- assert res == 6
- res = self.interpret(f, [-1])
- assert res == 5
- def test_is_among_frozen(self):
- fr1 = Freezing()
- fr2 = Freezing()
- def givefr1():
- return fr1
- def givefr2():
- return fr2
- def f(i):
- if i == 1:
- fr = givefr1()
- else:
- fr = givefr2()
- return fr is fr1
- res = self.interpret(f, [0])
- assert res is False
- res = self.interpret(f, [1])
- assert res is True
- def test_unbound_method(self):
- def f():
- inst = MySubclass()
- inst.z = 40
- return MyBase.m(inst, 2)
- res = self.interpret(f, [])
- assert res == 42
- def test_call_defaults(self):
- def g(a, b=2, c=3):
- return a+b+c
- def f1():
- return g(1)
- def f2():
- return g(1, 10)
- def f3():
- return g(1, 10, 100)
- res = self.interpret(f1, [])
- assert res == 1+2+3
- res = self.interpret(f2, [])
- assert res == 1+10+3
- res = self.interpret(f3, [])
- assert res == 1+10+100
- def test_call_memoized_function(self):
- fr1 = Freezing()
- fr2 = Freezing()
- def getorbuild(key):
- a = 1
- if key is fr1:
- result = eval("a+2")
- else:
- result = eval("a+6")
- return result
- getorbuild._annspecialcase_ = "specialize:memo"
- def f1(i):
- if i > 0:
- fr = fr1
- else:
- fr = fr2
- return getorbuild(fr)
- res = self.interpret(f1, [0])
- assert res == 7
- res = self.interpret(f1, [1])
- assert res == 3
- def test_call_memoized_function_with_bools(self):
- fr1 = Freezing()
- fr2 = Freezing()
- def getorbuild(key, flag1, flag2):
- a = 1
- if key is fr1:
- result = eval("a+2")
- else:
- result = eval("a+6")
- if flag1:
- result += 100
- if flag2:
- result += 1000
- return result
- getorbuild._annspecialcase_ = "specialize:memo"
- def f1(i):
- if i > 0:
- fr = fr1
- else:
- fr = fr2
- return getorbuild(fr, i % 2 == 0, i % 3 == 0)
- for n in [0, 1, 2, -3, 6]:
- res = self.interpret(f1, [n])
- assert res == f1(n)
- def test_call_memoized_cache(self):
- # this test checks that we add a separate field
- # per specialization and also it uses a subclass of
- # the standard rpython.rlib.cache.Cache
- from rpython.rlib.cache import Cache
- fr1 = Freezing()
- fr2 = Freezing()
- class Cache1(Cache):
- def _build(self, key):
- "NOT_RPYTHON"
- if key is fr1:
- return fr2
- else:
- return fr1
- class Cache2(Cache):
- def _build(self, key):
- "NOT_RPYTHON"
- a = 1
- if key is fr1:
- result = eval("a+2")
- else:
- result = eval("a+6")
- return result
- cache1 = Cache1()
- cache2 = Cache2()
- def f1(i):
- if i > 0:
- fr = fr1
- else:
- fr = fr2
- newfr = cache1.getorbuild(fr)
- return cache2.getorbuild(newfr)
- res = self.interpret(f1, [0])
- assert res == 3
- res = self.interpret(f1, [1])
- assert res == 7
- def test_call_memo_with_single_value(self):
- class A: pass
- def memofn(cls):
- return len(cls.__name__)
- memofn._annspecialcase_ = "specialize:memo"
- def f1():
- A() # make sure we have a ClassDef
- return memofn(A)
- res = self.interpret(f1, [])
- assert res == 1
- def test_call_memo_with_class(self):
- class A: pass
- class FooBar(A): pass
- def memofn(cls):
- return len(cls.__name__)
- memofn._annspecialcase_ = "specialize:memo"
- def f1(i):
- if i == 1:
- cls = A
- else:
- cls = FooBar
- FooBar() # make sure we have ClassDefs
- return memofn(cls)
- res = self.interpret(f1, [1])
- assert res == 1
- res = self.interpret(f1, [2])
- assert res == 6
- def test_call_memo_with_string(self):
- def memofn(s):
- return eval(s)
- memofn._annspecialcase_ = "specialize:memo"
- def f1(i):
- if i == 1:
- return memofn("6*7")
- else:
- return memofn("1+2+3+4")
- res = self.interpret(f1, [1])
- assert res == 42
- res = self.interpret(f1, [2])
- assert res == 10
- def test_rpbc_bound_method_static_call(self):
- class R:
- def meth(self):
- return 0
- r = R()
- m = r.meth
- def fn():
- return m()
- res = self.interpret(fn, [])
- assert res == 0
- def test_rpbc_bound_method_static_call_w_kwds(self):
- class R:
- def meth(self, x):
- return x
- r = R()
- m = r.meth
- def fn():
- return m(x=3)
- res = self.interpret(fn, [])
- assert res == 3
- def test_constant_return_disagreement(self):
- class R:
- def meth(self):
- return 0
- r = R()
- def fn():
- return r.meth()
- res = self.interpret(fn, [])
- assert res == 0
- def test_None_is_false(self):
- def fn(i):
- if i == 0:
- v = None
- else:
- v = fn
- return bool(v)
- res = self.interpret(fn, [1])
- assert res is True
- res = self.interpret(fn, [0])
- assert res is False
- def test_classpbc_getattr(self):
- class A:
- myvalue = 123
- class B(A):
- myvalue = 456
- def f(i):
- if i == 0:
- v = A
- else:
- v = B
- return v.myvalue
- res = self.interpret(f, [0])
- assert res == 123
- res = self.interpret(f, [1])
- assert res == 456
- def test_function_or_None(self):
- def g1():
- return 42
- def f(i):
- g = None
- if i > 5:
- g = g1
- if i > 6:
- return g()
- else:
- return 12
- res = self.interpret(f, [0])
- assert res == 12
- res = self.interpret(f, [6])
- assert res == 12
- res = self.interpret(f, [7])
- assert res == 42
- def test_simple_function_pointer(self):
- def f1(x):
- return x + 1
- def f2(x):
- return x + 2
- l = [f1, f2]
- def pointersimple(i):
- return l[i](i)
- res = self.interpret(pointersimple, [1])
- assert res == 3
- def test_classdef_getattr(self):
- class A:
- myvalue = 123
- class B(A):
- myvalue = 456
- def f(i):
- B() # for A and B to have classdefs
- if i == 0:
- v = A
- else:
- v = B
- return v.myvalue
- res = self.interpret(f, [0])
- assert res == 123
- res = self.interpret(f, [1])
- assert res == 456
- def test_call_classes(self):
- class A: pass
- class B(A): pass
- def f(i):
- if i == 1:
- cls = B
- else:
- cls = A
- return cls()
- res = self.interpret(f, [0])
- assert self.class_name(res) == 'A'
- res = self.interpret(f, [1])
- assert self.class_name(res) == 'B'
- def test_call_classes_or_None(self):
- class A: pass
- class B(A): pass
- def f(i):
- if i == -1:
- cls = None
- elif i == 1:
- cls = B
- else:
- cls = A
- return cls()
- res = self.interpret(f, [0])
- assert self.class_name(res) == 'A'
- res = self.interpret(f, [1])
- assert self.class_name(res) == 'B'
- #def f(i):
- # if i == -1:
- # cls = None
- # else:
- # cls = A
- # return cls()
- #res = self.interpret(f, [0])
- #assert self.class_name(res) == 'A'
- def test_call_classes_with_init2(self):
- class A:
- def __init__(self, z):
- self.z = z
- class B(A):
- def __init__(self, z, x=42):
- A.__init__(self, z)
- self.extra = x
- def f(i, z):
- if i == 1:
- cls = B
- else:
- cls = A
- return cls(z)
- res = self.interpret(f, [0, 5])
- assert self.class_name(res) == 'A'
- assert self.read_attr(res, "z") == 5
- res = self.interpret(f, [1, -7645])
- assert self.class_name(res) == 'B'
- assert self.read_attr(res, "z") == -7645
- assert self.read_attr(res, "extra") == 42
- def test_conv_from_None(self):
- class A(object): pass
- def none():
- return None
- def f(i):
- if i == 1:
- return none()
- else:
- return "ab"
- res = self.interpret(f, [1])
- assert not res
- res = self.interpret(f, [0])
- assert self.ll_to_string(res) == "ab"
- def g(i):
- if i == 1:
- return none()
- else:
- return A()
- res = self.interpret(g, [1])
- assert not res
- res = self.interpret(g, [0])
- assert self.class_name(res) == 'A'
- def test_conv_from_classpbcset_to_larger(self):
- class A(object): pass
- class B(A): pass
- class C(A): pass
- def a():
- return A
- def b():
- return B
- def g(i):
- if i == 1:
- cls = a()
- else:
- cls = b()
- return cls()
- res = self.interpret(g, [0])
- assert self.class_name(res) == 'B'
- res = self.interpret(g, [1])
- assert self.class_name(res) == 'A'
- def bc(j):
- if j == 1:
- return B
- else:
- return C
- def g(i, j):
- if i == 1:
- cls = a()
- else:
- cls = bc(j)
- return cls()
- res = self.interpret(g, [0, 0])
- assert self.class_name(res) == 'C'
- res = self.interpret(g, [0, 1])
- assert self.class_name(res) == 'B'
- res = self.interpret(g, [1, 0])
- assert self.class_name(res) == 'A'
- def test_call_starargs(self):
- def g(x=-100, *arg):
- return x + len(arg)
- def f(i):
- if i == -1:
- return g()
- elif i == 0:
- return g(4)
- elif i == 1:
- return g(5, 15)
- elif i == 2:
- return g(7, 17, 27)
- else:
- return g(10, 198, 1129, 13984)
- res = self.interpret(f, [-1])
- assert res == -100
- res = self.interpret(f, [0])
- assert res == 4
- res = self.interpret(f, [1])
- assert res == 6
- res = self.interpret(f, [2])
- assert res == 9
- res = self.interpret(f, [3])
- assert res == 13
- def test_call_keywords(self):
- def g(a=1, b=2, c=3):
- return 100*a+10*b+c
- def f(i):
- if i == 0:
- return g(a=7)
- elif i == 1:
- return g(b=11)
- elif i == 2:
- return g(c=13)
- elif i == 3:
- return g(a=7, b=11)
- elif i == 4:
- return g(b=7, a=11)
- elif i == 5:
- return g(a=7, c=13)
- elif i == 6:
- return g(c=7, a=13)
- elif i == 7:
- return g(a=7,b=11,c=13)
- elif i == 8:
- return g(a=7,c=11,b=13)
- elif i == 9:
- return g(b=7,a=11,c=13)
- else:
- return g(b=7,c=11,a=13)
- for i in range(11):
- res = self.interpret(f, [i])
- assert res == f(i)
- def test_call_star_and_keywords(self):
- def g(a=1, b=2, c=3):
- return 100*a+10*b+c
- def f(i, x):
- if x == 1:
- j = 11
- else:
- j = 22
- if i == 0:
- return g(7)
- elif i == 1:
- return g(7,*(j,))
- elif i == 2:
- return g(7,*(11,j))
- elif i == 3:
- return g(a=7)
- elif i == 4:
- return g(b=7, *(j,))
- elif i == 5:
- return g(b=7, c=13, *(j,))
- elif i == 6:
- return g(c=7, b=13, *(j,))
- elif i == 7:
- return g(c=7,*(j,))
- elif i == 8:
- return g(c=7,*(11,j))
- else:
- return 0
- for i in range(9):
- for x in range(1):
- res = self.interpret(f, [i, x])
- assert res == f(i, x)
- def test_call_star_and_keywords_starargs(self):
- def g(a=1, b=2, c=3, *rest):
- return 1000*len(rest)+100*a+10*b+c
- def f(i, x):
- if x == 1:
- j = 13
- else:
- j = 31
- if i == 0:
- return g()
- elif i == 1:
- return g(*(j,))
- elif i == 2:
- return g(*(13, j))
- elif i == 3:
- return g(*(13, j, 19))
- elif i == 4:
- return g(*(13, j, 19, 21))
- elif i == 5:
- return g(7)
- elif i == 6:
- return g(7, *(j,))
- elif i == 7:
- return g(7, *(13, j))
- elif i == 8:
- return g(7, *(13, 17, j))
- elif i == 9:
- return g(7, *(13, 17, j, 21))
- elif i == 10:
- return g(7, 9)
- elif i == 11:
- return g(7, 9, *(j,))
- elif i == 12:
- return g(7, 9, *(j, 17))
- elif i == 13:
- return g(7, 9, *(13, j, 19))
- elif i == 14:
- return g(7, 9, 11)
- elif i == 15:
- return g(7, 9, 11, *(j,))
- elif i == 16:
- return g(7, 9, 11, *(13, j))
- elif i == 17:
- return g(7, 9, 11, *(13, 17, j))
- elif i == 18:
- return g(7, 9, 11, 2)
- elif i == 19:
- return g(7, 9, 11, 2, *(j,))
- elif i == 20:
- return g(7, 9, 11, 2, *(13, j))
- else:
- return 0
- for i in range(21):
- for x in range(1):
- res = self.interpret(f, [i, x])
- assert res == f(i, x)
- def test_conv_from_funcpbcset_to_larger(self):
- def f1():
- return 7
- def f2():
- return 11
- def f3():
- return 13
- def a():
- return f1
- def b():
- return f2
- def g(i):
- if i == 1:
- f = a()
- else:
- f = b()
- return f()
- res = self.interpret(g, [0])
- assert res == 11
- res = self.interpret(g, [1])
- assert res == 7
- def bc(j):
- if j == 1:
- return f2
- else:
- return f3
- def g(i, j):
- if i == 1:
- cls = a()
- else:
- cls = bc(j)
- return cls()
- res = self.interpret(g, [0, 0])
- assert res == 13
- res = self.interpret(g, [0, 1])
- assert res == 11
- res = self.interpret(g, [1, 0])
- assert res == 7
- def test_call_special_starargs_method(self):
- class Star:
- def __init__(self, d):
- self.d = d
- def meth(self, *args):
- return self.d + len(args)
- def f(i, j):
- s = Star(i)
- return s.meth(i, j)
- res = self.interpret(f, [3, 0])
- assert res == 5
- def test_call_star_method(self):
- class N:
- def __init__(self, d):
- self.d = d
- def meth(self, a, b):
- return self.d + a + b
- def f(i, j):
- n = N(i)
- return n.meth(*(i, j))
- res = self.interpret(f, [3, 7])
- assert res == 13
- def test_call_star_special_starargs_method(self):
- class N:
- def __init__(self, d):
- self.d = d
- def meth(self, *args):
- return self.d + len(args)
- def f(i, j):
- n = N(i)
- return n.meth(*(i, j))
- res = self.interpret(f, [3, 0])
- assert res == 5
- def test_various_patterns_but_one_signature_method(self):
- class A:
- def meth(self, a, b=0):
- raise NotImplementedError
- class B(A):
- def meth(self, a, b=0):
- return a+b
- class C(A):
- def meth(self, a, b=0):
- return a*b
- def f(i):
- if i == 0:
- x = B()
- else:
- x = C()
- r1 = x.meth(1)
- r2 = x.meth(3, 2)
- r3 = x.meth(7, b=11)
- return r1+r2+r3
- res = self.interpret(f, [0])
- assert res == 1+3+2+7+11
- res = self.interpret(f, [1])
- assert res == 3*2+11*7
- def test_multiple_ll_one_hl_op(self):
- class E(Exception):
- pass
- class A(object):
- pass
- class B(A):
- pass
- class C(object):
- def method(self, x):
- if x:
- raise E()
- else:
- return A()
- class D(C):
- def method(self, x):
- if x:
- raise E()
- else:
- return B()
- def call(x):
- c = D()
- c.method(x)
- try:
- c.method(x + 1)
- except E:
- pass
- c = C()
- c.method(x)
- try:
- return c.method(x + 1)
- except E:
- return None
- res = self.interpret(call, [0])
- def test_multiple_pbc_with_void_attr(self):
- class A:
- def _freeze_(self):
- return True
- a1 = A()
- a2 = A()
- unique = A()
- unique.result = 42
- a1.value = unique
- a2.value = unique
- def g(a):
- return a.value.result
- def f(i):
- if i == 1:
- a = a1
- else:
- a = a2
- return g(a)
- res = self.interpret(f, [0])
- assert res == 42
- res = self.interpret(f, [1])
- assert res == 42
- def test_function_or_none(self):
- def h(y):
- return y+84
- def g(y):
- return y+42
- def f(x, y):
- if x == 1:
- func = g
- elif x == 2:
- func = h
- else:
- func = None
- if func:
- return func(y)
- return -1
- res = self.interpret(f, [1, 100])
- assert res == 142
- res = self.interpret(f, [2, 100])
- assert res == 184
- res = self.interpret(f, [3, 100])
- assert res == -1
- def test_pbc_getattr_conversion(self):
- fr1 = Freezing()
- fr2 = Freezing()
- fr3 = Freezing()
- fr1.value = 10
- fr2.value = 5
- fr3.value = 2.5
- def pick12(i):
- if i > 0:
- return fr1
- else:
- return fr2
- def pick23(i):
- if i > 5:
- return fr2
- else:
- return fr3
- def f(i):
- x = pick12(i)
- y = pick23(i)
- return x.value, y.value
- for i in [0, 5, 10]:
- res = self.interpret(f, [i])
- item0, item1 = self.ll_unpack_tuple(res, 2)
- assert type(item0) is int # precise
- assert type(item1) in (float, int) # we get int on JS
- assert item0 == f(i)[0]
- assert item1 == f(i)[1]
- def test_pbc_getattr_conversion_with_classes(self):
- class base: pass
- class fr1(base): pass
- class fr2(base): pass
- class fr3(base): pass
- fr1.value = 10
- fr2.value = 5
- fr3.value = 2.5
- def pick12(i):
- if i > 0:
- return fr1
- else:
- return fr2
- def pick23(i):
- if i > 5:
- return fr2
- else:
- return fr3
- def f(i):
- x = pick12(i)
- y = pick23(i)
- return x.value, y.value
- for i in [0, 5, 10]:
- res = self.interpret(f, [i])
- item0, item1 = self.ll_unpack_tuple(res, 2)
- assert type(item0) is int # precise
- assert type(item1) in (float, int) # we get int on JS
- assert item0 == f(i)[0]
- assert item1 == f(i)[1]
- def test_pbc_imprecise_attrfamily(self):
- fr1 = Freezing(); fr1.x = 5; fr1.y = [8]
- fr2 = Freezing(); fr2.x = 6; fr2.y = ["string"]
- def head(fr):
- return fr.y[0]
- def f(n):
- if n == 1:
- fr = fr1
- else:
- fr = fr2
- return head(fr1) + fr.x
- res = self.interpret(f, [2])
- assert res == 8 + 6
- def test_multiple_specialized_functions(self):
- def myadder(x, y): # int,int->int or str,str->str
- return x+y
- def myfirst(x, y): # int,int->int or str,str->str
- return x
- def mysecond(x, y): # int,int->int or str,str->str
- return y
- myadder._annspecialcase_ = 'specialize:argtype(0)'
- myfirst._annspecialcase_ = 'specialize:argtype(0)'
- mysecond._annspecialcase_ = 'specialize:argtype(0)'
- def f(i):
- if i == 0:
- g = myfirst
- elif i == 1:
- g = mysecond
- else:
- g = myadder
- s = g("hel", "lo")
- n = g(40, 2)
- return len(s) * n
- for i in range(3):
- res = self.interpret(f, [i])
- assert res == f(i)
- def test_specialized_method_of_frozen(self):
- class space:
- def _freeze_(self):
- return True
- def __init__(self, tag):
- self.tag = tag
- def wrap(self, x):
- if isinstance(x, int):
- return self.tag + '< %d >' % x
- else:
- return self.tag + x
- wrap._annspecialcase_ = 'specialize:argtype(1)'
- space1 = space("tag1:")
- space2 = space("tag2:")
- def f(i):
- if i == 1:
- sp = space1
- else:
- sp = space2
- w1 = sp.wrap('hello')
- w2 = sp.wrap(42)
- return w1 + w2
- res = self.interpret(f, [1])
- assert self.ll_to_string(res) == 'tag1:hellotag1:< 42 >'
- res = self.interpret(f, [0])
- assert self.ll_to_string(res) == 'tag2:hellotag2:< 42 >'
- def test_specialized_method(self):
- class A:
- def __init__(self, tag):
- self.tag = tag
- def wrap(self, x):
- if isinstance(x, int):
- return self.tag + '< %d >' % x
- else:
- return self.tag + x
- wrap._annspecialcase_ = 'specialize:argtype(1)'
- a1 = A("tag1:")
- a2 = A("tag2:")
- def f(i):
- if i == 1:
- sp = a1
- else:
- sp = a2
- w1 = sp.wrap('hello')
- w2 = sp.wrap(42)
- return w1 + w2
- res = self.interpret(f, [1])
- assert self.ll_to_string(res) == 'tag1:hellotag1:< 42 >'
- res = self.interpret(f, [0])
- assert self.ll_to_string(res) == 'tag2:hellotag2:< 42 >'
- def test_precise_method_call_1(self):
- class A(object):
- def meth(self, x=5):
- return x+1
- class B(A):
- def meth(self, x=5):
- return x+2
- class C(A):
- pass
- def f(i, n):
- # call both A.meth and B.meth with an explicit argument
- if i > 0:
- x = A()
- else:
- x = B()
- result1 = x.meth(n)
- # now call A.meth only, using the default argument
- result2 = C().meth()
- return result1 * result2
- for i in [0, 1]:
- res = self.interpret(f, [i, 1234])
- assert res == f(i, 1234)
- def test_precise_method_call_2(self):
- class A(object):
- def meth(self, x=5):
- return x+1
- class B(A):
- def meth(self, x=5):
- return x+2
- class C(A):
- def meth(self, x=5):
- return x+3
- def f(i, n):
- # call both A.meth and B.meth with an explicit argument
- if i > 0:
- x = A()
- else:
- x = B()
- result1 = x.meth(n)
- # now call A.meth and C.meth, using the default argument
- if i > 0:
- x = C()
- else:
- x = A()
- result2 = x.meth()
- return result1 * result2
- for i in [0, 1]:
- res = self.interpret(f, [i, 1234])
- assert res == f(i, 1234)
- def test_disjoint_pbcs(self):
- class Frozen(object):
- def __init__(self, v):
- self.v = v
- def _freeze_(self):
- return True
- fr1 = Frozen(2)
- fr2 = Frozen(3)
- def g1(x):
- return x.v
- def g2(y):
- return y.v
- def h(x):
- return x is not None
- def h2(x):
- return x is fr1
- def f():
- a = g1(fr1)
- b = g2(fr2)
- h(None)
- return (h(fr1) + 10*h(fr2) + 100*a + 1000*b +
- 10000*h2(fr1) + 100000*h2(fr2))
- res = self.interpret(f, [])
- assert res == 13211
- def test_disjoint_pbcs_2(self):
- class Frozen(object):
- def __init__(self, v):
- self.v = v
- def _freeze_(self):
- return True
- fr1 = Frozen(1)
- fr2 = Frozen(2)
- fr3 = Frozen(3)
- def getv(x):
- return x.v
- def h(x):
- return (x is not None) + 2*(x is fr2) + 3*(x is fr3)
- def f(n):
- if n == 1:
- fr = fr1
- else:
- fr = fr2
- total = getv(fr)
- if n == 3:
- fr = fr3
- h(None)
- return total + 10*h(fr)
- res = self.interpret(f, [3])
- assert res == 42
- def test_convert_multiple_to_single(self):
- class A:
- def meth(self, fr):
- return 65
- class B(A):
- def meth(self, fr):
- return 66
- fr1 = Freezing()
- fr2 = Freezing()
- def f():
- return A().meth(fr1) * B().meth(fr2)
- res = self.interpret(f, [])
- assert res == 65*66
- def test_convert_multiple_to_single_method_of_frozen_pbc(self):
- class A:
- def meth(self, frmeth):
- return frmeth(100)
- class B(A):
- def meth(self, frmeth):
- return frmeth(1000)
- fr1 = Freezing(); fr1.x = 65
- fr2 = Freezing(); fr2.x = 66
- def f():
- return A().meth(fr1.mymethod) * B().meth(fr2.mymethod)
- res = self.interpret(f, [])
- assert res == 165 * 1066
- def test_convert_none_to_frozen_pbc(self):
- fr1 = Freezing(); fr1.x = 65
- fr2 = Freezing(); fr2.y = 65
- def g(fr):
- return fr.x
- def identity(z):
- return z
- def f(n): # NB. this crashes with n == 0
- if n == 0:
- fr = identity(None)
- else:
- fr = fr1
- return g(fr)
- res = self.interpret(f, [1])
- assert res == 65
- def test_multiple_attribute_access_patterns(self):
- class Base(object):
- pass
- class A(Base):
- value = 1000
- def meth(self): return self.n + 1
- class B(A):
- def meth(self): return self.n + 2
- class C(Base):
- value = 2000
- def meth(self): ShouldNotBeSeen
- def AorB(n):
- if n == 5: return A
- else: return B
- def BorC(n):
- if n == 3: return B
- else: return C
- def f(n):
- value = BorC(n).value
- x = B()
- x.n = 100
- return value + AorB(n).meth(x)
- for i in [1, 3, 5]:
- res = self.interpret(f, [i])
- assert res == f(i)
- def test_function_as_frozen_pbc(self):
- def f1(): pass
- def f2(): pass
- def choose(n):
- if n == 1:
- return f1
- else:
- return f2
- def f(n):
- return choose(n) is f1
- res = self.interpret(f, [1])
- assert res == True
- res = self.interpret(f, [2])
- assert res == False
- def test_call_from_list(self):
- def f0(n): return n+200
- def f1(n): return n+192
- def f2(n): return n+46
- def f3(n): return n+2987
- def f4(n): return n+217
- lst = [f0, f1, f2, f3, f4]
- def f(i, n):
- return lst[i](n)
- for i in range(5):
- res = self.interpret(f, [i, 1000])
- assert res == f(i, 1000)
- def test_None_is_None(self):
- def g():
- return None
- def f():
- return g() is None
- res = self.interpret(f, [])
- assert res == True
- def test_except_class_call(self):
- class A:
- pass # no constructor
- def f():
- try:
- A()
- IndexError()
- return 12
- except ValueError:
- return 23
- res = self.interpret(f, [])
- assert res == 12
- def test_exception_with_non_empty_baseclass(self):
- class BE(Exception):
- pass
- class E1(BE):
- pass
- class E2(BE):
- pass
- def f(x):
- if x:
- e = E1()
- else:
- e = E2()
- witness = E1()
- witness.x = 42
- e.x = 3
- return witness.x
- res = self.interpret(f, [0])
- assert res == 42
- res = self.interpret(f, [1])
- assert res == 42
- def test_funcornone_to_func(self):
- def g(y):
- return y*2
- def f(x):
- if x > 0:
- g1 = g
- else:
- g1 = None
- x += 1
- if g1:
- return g1(x)
- else:
- return -1
- res = self.interpret(f, [20])
- assert res == 42
- def test_specialize_functionarg(self):
- def f(x, y):
- return x + y
- def g(x, y, z):
- return x + y + z
- def functionarg(func, *extraargs):
- return func(42, *extraargs)
- functionarg._annspecialcase_ = "specialize:arg(0)"
- def call_functionarg():
- return functionarg(f, 1) + functionarg(g, 1, 2)
- assert call_functionarg() == 2 * 42 + 4
- res = self.interpret(call_functionarg, [])
- assert res == 2 * 42 + 4
- def test_convert_multiple_classes_to_single(self):
- class A:
- result = 321
- def meth(self, n):
- if n:
- return A
- else:
- return B
- class B(A):
- result = 123
- def meth(self, n):
- return B
- def f(n):
- A().meth(n)
- cls = B().meth(n)
- return cls().result
- res = self.interpret(f, [5])
- assert res == 123
- def test_is_among_functions(self):
- def g1(): pass
- def g2(): pass
- def g3(): pass
- def f(n):
- if n > 5:
- g = g2
- else:
- g = g1
- g()
- g3()
- return g is g3
- res = self.interpret(f, [2])
- assert res == False
- def test_is_among_functions_2(self):
- def g1(): pass
- def g2(): pass
- def f(n):
- if n > 5:
- g = g2
- else:
- g = g1
- g()
- return g is g2
- res = self.interpret(f, [2])
- assert res == False
- res = self.interpret(f, [8])
- assert res == True
- def test_is_among_functions_3(self):
- def g0(): pass
- def g1(): pass
- def g2(): pass
- def g3(): pass
- def g4(): pass
- def g5(): pass
- def g6(): pass
- def g7(): pass
- glist = [g0, g1, g2, g3, g4, g5, g6, g7]
- def f(n):
- if n > 5:
- g = g2
- else:
- g = g1
- h = glist[n]
- g()
- h()
- return g is h
- res = self.interpret(f, [2])
- assert res == False
- res = self.interpret(f, [1])
- assert res == True
- res = self.interpret(f, [6])
- assert res == False
- def test_shrink_pbc_set(self):
- def g1():
- return 10
- def g2():
- return 20
- def g3():
- return 30
- def h1(g): # g in {g1, g2}
- return 1 + g()
- def h2(g): # g in {g1, g2, g3}
- return 2 + g()
- def f(n):
- if n > 5: g = g1
- else: g = g2
- if n % 2: h = h1
- else: h = h2
- res = h(g)
- if n > 7: g = g3
- h2(g)
- return res
- res = self.interpret(f, [7])
- assert res == 11
- def test_single_pbc_getattr(self):
- class C:
- def __init__(self, v1, v2):
- self.v1 = v1
- self.v2 = v2
- def _freeze_(self):
- return True
- c1 = C(11, lambda: "hello")
- c2 = C(22, lambda: 623)
- def f1(l, c):
- l.append(c.v1)
- def f2(c):
- return c.v2
- def f3(c):
- return c.v2
- def g():
- l = []
- f1(l, c1)
- f1(l, c2)
- return f2(c1)(), f3(c2)()
- res = self.interpret(g, [])
- item0, item1 = self.ll_unpack_tuple(res, 2)
- assert self.ll_to_string(item0) == "hello"
- assert item1 == 623
- def test_always_raising_methods(self):
- class Base:
- def m(self):
- raise KeyError
- class A(Base):
- def m(self):
- return 42
- class B(Base):
- pass
- def f(n):
- if n > 3:
- o = A()
- else:
- o = B()
- try:
- o.m()
- except KeyError:
- assert 0
- return B().m()
- self.interpret_raises(KeyError, f, [7])
- def test_possible_missing_attribute_access(self):
- py.test.skip("Should explode or give some warning")
- class Base(object):
- pass
- class A(Base):
- a = 1
- b = 2
- class B(Base):
- a = 2
- b = 2
- class C(Base):
- b = 8
- def f(n):
- if n > 3:
- x = A
- elif n > 1:
- x = B
- else:
- x = C
- if n > 0:
- return x.a
- return 9
- self.interpret(f, [int])
- def test_funcpointer_default_value(self):
- def foo(x): return x+1
- class Foo:
- func = None
- def __init__(self, n):
- if n == 1:
- self.func = foo
- def fn(n):
- a = Foo(n)
- if a.func:
- return a.func(n)
- return -1
- res = self.interpret(fn, [0])
- assert res == -1
- def test_is_none(self):
- from rpython.rlib.nonconst import NonConstant
- def g(x):
- return NonConstant(g) is None
- res = self.interpret(g, [1])
- assert not res
- def test_pbc_of_classes_not_all_used(self):
- class Base(object): pass
- class A(Base): pass
- class B(Base): pass
- def poke(lst):
- pass
- def g():
- A()
- poke([A, B])
- self.interpret(g, [])
- def test_pbc_of_classes_isinstance_only(self):
- class Base(object): pass
- class ASub(Base): pass
- def g():
- x = Base()
- return isinstance(x, ASub)
- res = self.interpret(g, [])
- assert res == False
- def test_class___name__(self):
- class Base(object): pass
- class ASub(Base): pass
- def g(n):
- if n == 1:
- x = Base()
- else:
- x = ASub()
- return x.__class__.__name__
- res = self.interpret(g, [1])
- assert self.ll_to_string(res) == "Base"
- res = self.interpret(g, [2])
- assert self.ll_to_string(res) == "ASub"
- def test_str_class(self):
- class Base(object): pass
- class ASub(Base): pass
- def g(n):
- if n == 1:
- x = Base()
- else:
- x = ASub()
- return str(x.__class__)
- res = self.interpret(g, [1])
- assert self.ll_to_string(res) == "Base"
- res = self.interpret(g, [2])
- assert self.ll_to_string(res) == "ASub"
- def test_bug_callfamily(self):
- def cb1():
- xxx # never actually called
- def cb2():
- pass
- def g(cb, result):
- assert (cb is None) == (result == 0)
- def h(cb):
- cb()
- def f():
- g(None, 0)
- g(cb1, 1)
- g(cb2, 2)
- h(cb2)
- return 42
- res = self.interpret(f, [])
- assert res == 42
- # ____________________________________________________________
- def test_hlinvoke_simple():
- def f(a,b):
- return a + b
- from rpython.translator import translator
- from rpython.annotator import annrpython
- a = annrpython.RPythonAnnotator()
- s_f = a.bookkeeper.immutablevalue(f)
- a.bookkeeper.emulate_pbc_call('f', s_f, [annmodel.SomeInteger(), annmodel.SomeInteger()])
- a.complete()
- from rpython.rtyper import rtyper
- rt = rtyper.RPythonTyper(a)
- rt.specialize()
- def ll_h(R, f, x):
- from rpython.rlib.objectmodel import hlinvoke
- return hlinvoke(R, f, x, 2)
- from rpython.rtyper import annlowlevel
- r_f = rt.getrepr(s_f)
- s_R = a.bookkeeper.immutablevalue(r_f)
- s_ll_f = lltype_to_annotation(r_f.lowleveltype)
- ll_h_graph = annlowlevel.annotate_lowlevel_helper(a, ll_h, [s_R, s_ll_f, annmodel.SomeInteger()])
- assert a.binding(ll_h_graph.getreturnvar()).knowntype == int
- rt.specialize_more_blocks()
- from rpython.rtyper.llinterp import LLInterpreter
- interp = LLInterpreter(rt)
- #a.translator.view()
- res = interp.eval_graph(ll_h_graph, [None, None, 3])
- assert res == 5
- def test_hlinvoke_simple2():
- def f1(a,b):
- return a + b
- def f2(a,b):
- return a - b
- from rpython.annotator import annrpython
- a = annrpython.RPythonAnnotator()
- def g(i):
- if i:
- f = f1
- else:
- f = f2
- f(5,4)
- f(3,2)
- a.build_types(g, [int])
- from rpython.rtyper import rtyper
- rt = rtyper.RPythonTyper(a)
- rt.specialize()
- def ll_h(R, f, x):
- from rpython.rlib.objectmodel import hlinvoke
- return hlinvoke(R, f, x, 2)
- from rpython.rtyper import annlowlevel
- f1desc = a.bookkeeper.getdesc(f1)
- f2desc = a.bookkeeper.getdesc(f2)
- s_f = annmodel.SomePBC([f1desc, f2desc])
- r_f = rt.getrepr(s_f)
- s_R = a.bookkeeper.immutablevalue(r_f)
- s_ll_f = lltype_to_annotation(r_f.lowleveltype)
- ll_h_graph= annlowlevel.annotate_lowlevel_helper(a, ll_h, [s_R, s_ll_f, annmodel.SomeInteger()])
- assert a.binding(ll_h_graph.getreturnvar()).knowntype == int
- rt.specialize_more_blocks()
- from rpython.rtyper.llinterp import LLInterpreter
- interp = LLInterpreter(rt)
- #a.translator.view()
- res = interp.eval_graph(ll_h_graph, [None, r_f.convert_desc(f1desc), 3])
- assert res == 5
- res = interp.eval_graph(ll_h_graph, [None, r_f.convert_desc(f2desc), 3])
- assert res == 1
- def test_hlinvoke_hltype():
- class A(object):
- def __init__(self, v):
- self.v = v
- def f(a):
- return A(a)
- from rpython.annotator import annrpython
- a = annrpython.RPythonAnnotator()
- def g():
- a = A(None)
- f(a)
- a.build_types(g, [])
- from rpython.rtyper import rtyper
- from rpython.rtyper import rclass
- rt = rtyper.RPythonTyper(a)
- rt.specialize()
- def ll_h(R, f, a):
- from rpython.rlib.objectmodel import hlinvoke
- return hlinvoke(R, f, a)
- from rpython.rtyper import annlowlevel
- s_f = a.bookkeeper.immutablevalue(f)
- r_f = rt.getrepr(s_f)
- s_R = a.bookkeeper.immutablevalue(r_f)
- s_ll_f = lltype_to_annotation(r_f.lowleveltype)
- A_repr = rclass.getinstancerepr(rt, a.bookkeeper.getdesc(A).
- getuniqueclassdef())
- ll_h_graph = annlowlevel.annotate_lowlevel_helper(
- a, ll_h, [s_R, s_ll_f, SomePtr(A_repr.lowleveltype)])
- s = a.binding(ll_h_graph.getreturnvar())
- assert s.ll_ptrtype == A_repr.lowleveltype
- rt.specialize_more_blocks()
- from rpython.rtyper.llinterp import LLInterpreter
- interp = LLInterpreter(rt)
- #a.translator.view()
- c_a = A_repr.convert_const(A(None))
- res = interp.eval_graph(ll_h_graph, [None, None, c_a])
- assert typeOf(res) == A_repr.lowleveltype
- def test_hlinvoke_method_hltype():
- class A(object):
- def __init__(self, v):
- self.v = v
- class Impl(object):
- def f(self, a):
- return A(a)
- from rpython.annotator import annrpython
- a = annrpython.RPythonAnnotator()
- def g():
- a = A(None)
- i = Impl()
- i.f(a)
- a.build_types(g, [])
- from rpython.rtyper import rtyper
- from rpython.rtyper import rclass
- rt = rtyper.RPythonTyper(a)
- rt.specialize()
- def ll_h(R, f, a):
- from rpython.rlib.objectmodel import hlinvo…
Large files files are truncated, but you can click here to view the full file