PageRenderTime 45ms CodeModel.GetById 10ms RepoModel.GetById 1ms app.codeStats 0ms

/pypy/rpython/test/test_rclass.py

https://bitbucket.org/pypy/pypy/
Python | 1265 lines | 1143 code | 102 blank | 20 comment | 64 complexity | 0b174461116859a4efac4766f98f45b1 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import py
  2. import sys
  3. from pypy.translator.translator import TranslationContext, graphof
  4. from pypy.rpython.lltypesystem.lltype import *
  5. from pypy.rpython.ootypesystem import ootype
  6. from pypy.rlib.rarithmetic import r_longlong
  7. from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin
  8. from pypy.rpython.rclass import IR_IMMUTABLE, IR_IMMUTABLE_ARRAY
  9. from pypy.rpython.rclass import IR_QUASIIMMUTABLE, IR_QUASIIMMUTABLE_ARRAY
  10. from pypy.rpython.error import TyperError
  11. from pypy.objspace.flow.model import summary
  12. class EmptyBase(object):
  13. pass
  14. class Random:
  15. xyzzy = 12
  16. yadda = 21
  17. # for method calls
  18. class A:
  19. def f(self):
  20. return self.g()
  21. def g(self):
  22. return 42
  23. class B(A):
  24. def g(self):
  25. return 1
  26. class C(B):
  27. pass
  28. class BaseTestRclass(BaseRtypingTest):
  29. def test_instanceattr(self):
  30. def dummyfn():
  31. x = EmptyBase()
  32. x.a = 5
  33. x.a += 1
  34. return x.a
  35. res = self.interpret(dummyfn, [])
  36. assert res == 6
  37. def test_simple(self):
  38. def dummyfn():
  39. x = EmptyBase()
  40. return x
  41. res = self.interpret(dummyfn, [])
  42. assert self.is_of_instance_type(res)
  43. def test_classattr(self):
  44. def dummyfn():
  45. x = Random()
  46. return x.xyzzy
  47. res = self.interpret(dummyfn, [])
  48. assert res == 12
  49. def test_classattr_both(self):
  50. class A:
  51. a = 1
  52. class B(A):
  53. a = 2
  54. def pick(i):
  55. if i == 0:
  56. return A
  57. else:
  58. return B
  59. def dummyfn(i):
  60. C = pick(i)
  61. i = C()
  62. return C.a + i.a
  63. res = self.interpret(dummyfn, [0])
  64. assert res == 2
  65. res = self.interpret(dummyfn, [1])
  66. assert res == 4
  67. def test_classattr_both2(self):
  68. class Base(object):
  69. a = 0
  70. class A(Base):
  71. a = 1
  72. class B(Base):
  73. a = 2
  74. def pick(i):
  75. if i == 0:
  76. return A
  77. else:
  78. return B
  79. def dummyfn(i):
  80. C = pick(i)
  81. i = C()
  82. return C.a + i.a
  83. res = self.interpret(dummyfn, [0])
  84. assert res == 2
  85. res = self.interpret(dummyfn, [1])
  86. assert res == 4
  87. def test_runtime_exception(self):
  88. class MyExc(Exception):
  89. pass
  90. class Sub1(MyExc):
  91. pass
  92. class Sub2(MyExc):
  93. pass
  94. def pick(flag):
  95. if flag:
  96. return Sub1
  97. else:
  98. return Sub2
  99. def g(flag):
  100. ex = pick(flag)
  101. raise ex()
  102. def f(flag):
  103. try:
  104. g(flag)
  105. except Sub1:
  106. return 1
  107. except Sub2:
  108. return 2
  109. else:
  110. return 3
  111. assert self.interpret(f, [True]) == 1
  112. assert self.interpret(f, [False]) == 2
  113. def test_classattr_as_defaults(self):
  114. def dummyfn():
  115. x = Random()
  116. x.xyzzy += 1
  117. return x.xyzzy
  118. res = self.interpret(dummyfn, [])
  119. assert res == 13
  120. def test_overridden_classattr_as_defaults(self):
  121. class W_Root(object):
  122. pass
  123. class W_Thunk(W_Root):
  124. pass
  125. THUNK_PLACEHOLDER = W_Thunk()
  126. W_Root.w_thunkalias = None
  127. W_Thunk.w_thunkalias = THUNK_PLACEHOLDER
  128. def dummyfn(x):
  129. if x == 1:
  130. t = W_Thunk()
  131. elif x == 2:
  132. t = W_Thunk()
  133. t.w_thunkalias = W_Thunk()
  134. else:
  135. t = W_Root()
  136. return t.w_thunkalias is THUNK_PLACEHOLDER
  137. res = self.interpret(dummyfn, [1])
  138. assert res == True
  139. def test_prebuilt_instance(self):
  140. a = EmptyBase()
  141. a.x = 5
  142. def dummyfn():
  143. a.x += 1
  144. return a.x
  145. self.interpret(dummyfn, [])
  146. def test_recursive_prebuilt_instance(self):
  147. a = EmptyBase()
  148. b = EmptyBase()
  149. a.x = 5
  150. b.x = 6
  151. a.peer = b
  152. b.peer = a
  153. def dummyfn():
  154. return a.peer.peer.peer.x
  155. res = self.interpret(dummyfn, [])
  156. assert res == 6
  157. def test_recursive_prebuilt_instance_classattr(self):
  158. class Base:
  159. def m(self):
  160. return self.d.t.v
  161. class T1(Base):
  162. v = 3
  163. class T2(Base):
  164. v = 4
  165. class D:
  166. def _freeze_(self):
  167. return True
  168. t1 = T1()
  169. t2 = T2()
  170. T1.d = D()
  171. T2.d = D()
  172. T1.d.t = t1
  173. def call_meth(obj):
  174. return obj.m()
  175. def fn():
  176. return call_meth(t1) + call_meth(t2)
  177. assert self.interpret(fn, []) == 6
  178. def test_prebuilt_instances_with_void(self):
  179. def marker():
  180. return 42
  181. a = EmptyBase()
  182. a.nothing_special = marker
  183. def dummyfn():
  184. return a.nothing_special()
  185. res = self.interpret(dummyfn, [])
  186. assert res == 42
  187. def test_simple_method_call(self):
  188. def f(i):
  189. if i:
  190. a = A()
  191. else:
  192. a = B()
  193. return a.f()
  194. res = self.interpret(f, [True])
  195. assert res == 42
  196. res = self.interpret(f, [False])
  197. assert res == 1
  198. def test_isinstance(self):
  199. def f(i):
  200. if i == 0:
  201. o = None
  202. elif i == 1:
  203. o = A()
  204. elif i == 2:
  205. o = B()
  206. else:
  207. o = C()
  208. return 100*isinstance(o, A)+10*isinstance(o, B)+1*isinstance(o ,C)
  209. res = self.interpret(f, [1])
  210. assert res == 100
  211. res = self.interpret(f, [2])
  212. assert res == 110
  213. res = self.interpret(f, [3])
  214. assert res == 111
  215. res = self.interpret(f, [0])
  216. assert res == 0
  217. def test_method_used_in_subclasses_only(self):
  218. class A:
  219. def meth(self):
  220. return 123
  221. class B(A):
  222. pass
  223. def f():
  224. x = B()
  225. return x.meth()
  226. res = self.interpret(f, [])
  227. assert res == 123
  228. def test_method_both_A_and_B(self):
  229. class A:
  230. def meth(self):
  231. return 123
  232. class B(A):
  233. pass
  234. def f():
  235. a = A()
  236. b = B()
  237. return a.meth() + b.meth()
  238. res = self.interpret(f, [])
  239. assert res == 246
  240. def test_method_specialized_with_subclass(self):
  241. class A:
  242. def meth(self, n):
  243. return -1
  244. meth._annspecialcase_ = 'specialize:arg(1)'
  245. class B(A):
  246. pass
  247. def f():
  248. a = A()
  249. b = B()
  250. a.meth(1) # the self of this variant is annotated with A
  251. b.meth(2) # the self of this variant is annotated with B
  252. return 42
  253. res = self.interpret(f, [])
  254. assert res == 42
  255. def test_issubclass_type(self):
  256. class Abstract:
  257. pass
  258. class A(Abstract):
  259. pass
  260. class B(A):
  261. pass
  262. def f(i):
  263. if i == 0:
  264. c1 = A()
  265. else:
  266. c1 = B()
  267. return issubclass(type(c1), B)
  268. assert self.interpret(f, [0]) == False
  269. assert self.interpret(f, [1]) == True
  270. def g(i):
  271. if i == 0:
  272. c1 = A()
  273. else:
  274. c1 = B()
  275. return issubclass(type(c1), A)
  276. assert self.interpret(g, [0]) == True
  277. assert self.interpret(g, [1]) == True
  278. def test_staticmethod(self):
  279. class A(object):
  280. f = staticmethod(lambda x, y: x*y)
  281. def f():
  282. a = A()
  283. return a.f(6, 7)
  284. res = self.interpret(f, [])
  285. assert res == 42
  286. def test_staticmethod2(self):
  287. class A(object):
  288. f = staticmethod(lambda x, y: x*y)
  289. class B(A):
  290. f = staticmethod(lambda x, y: x+y)
  291. def f():
  292. b = B()
  293. return b.f(6, 7)
  294. res = self.interpret(f, [])
  295. assert res == 13
  296. def test_is(self):
  297. class A: pass
  298. class B(A): pass
  299. class C: pass
  300. def f(i):
  301. a = A()
  302. b = B()
  303. c = C()
  304. d = None
  305. e = None
  306. if i == 0:
  307. d = a
  308. elif i == 1:
  309. d = b
  310. elif i == 2:
  311. e = c
  312. return (0x0001*(a is b) | 0x0002*(a is c) | 0x0004*(a is d) |
  313. 0x0008*(a is e) | 0x0010*(b is c) | 0x0020*(b is d) |
  314. 0x0040*(b is e) | 0x0080*(c is d) | 0x0100*(c is e) |
  315. 0x0200*(d is e))
  316. res = self.interpret(f, [0])
  317. assert res == 0x0004
  318. res = self.interpret(f, [1])
  319. assert res == 0x0020
  320. res = self.interpret(f, [2])
  321. assert res == 0x0100
  322. res = self.interpret(f, [3])
  323. assert res == 0x0200
  324. def test_eq(self):
  325. class A: pass
  326. class B(A): pass
  327. class C: pass
  328. def f(i):
  329. a = A()
  330. b = B()
  331. c = C()
  332. d = None
  333. e = None
  334. if i == 0:
  335. d = a
  336. elif i == 1:
  337. d = b
  338. elif i == 2:
  339. e = c
  340. return (0x0001*(a == b) | 0x0002*(a == c) | 0x0004*(a == d) |
  341. 0x0008*(a == e) | 0x0010*(b == c) | 0x0020*(b == d) |
  342. 0x0040*(b == e) | 0x0080*(c == d) | 0x0100*(c == e) |
  343. 0x0200*(d == e))
  344. res = self.interpret(f, [0])
  345. assert res == 0x0004
  346. res = self.interpret(f, [1])
  347. assert res == 0x0020
  348. res = self.interpret(f, [2])
  349. assert res == 0x0100
  350. res = self.interpret(f, [3])
  351. assert res == 0x0200
  352. def test_istrue(self):
  353. class A:
  354. pass
  355. def f(i):
  356. if i == 0:
  357. a = A()
  358. else:
  359. a = None
  360. if a:
  361. return 1
  362. else:
  363. return 2
  364. res = self.interpret(f, [0])
  365. assert res == 1
  366. res = self.interpret(f, [1])
  367. assert res == 2
  368. def test_ne(self):
  369. class A: pass
  370. class B(A): pass
  371. class C: pass
  372. def f(i):
  373. a = A()
  374. b = B()
  375. c = C()
  376. d = None
  377. e = None
  378. if i == 0:
  379. d = a
  380. elif i == 1:
  381. d = b
  382. elif i == 2:
  383. e = c
  384. return (0x0001*(a != b) | 0x0002*(a != c) | 0x0004*(a != d) |
  385. 0x0008*(a != e) | 0x0010*(b != c) | 0x0020*(b != d) |
  386. 0x0040*(b != e) | 0x0080*(c != d) | 0x0100*(c != e) |
  387. 0x0200*(d != e))
  388. res = self.interpret(f, [0])
  389. assert res == ~0x0004 & 0x3ff
  390. res = self.interpret(f, [1])
  391. assert res == ~0x0020 & 0x3ff
  392. res = self.interpret(f, [2])
  393. assert res == ~0x0100 & 0x3ff
  394. res = self.interpret(f, [3])
  395. assert res == ~0x0200 & 0x3ff
  396. def test_hash_preservation(self):
  397. from pypy.rlib.objectmodel import current_object_addr_as_int
  398. from pypy.rlib.objectmodel import compute_identity_hash
  399. class C:
  400. pass
  401. class D(C):
  402. pass
  403. c = C()
  404. d = D()
  405. h_c = compute_identity_hash(c)
  406. h_d = compute_identity_hash(d)
  407. #
  408. def f():
  409. d2 = D()
  410. return (compute_identity_hash(d2),
  411. current_object_addr_as_int(d2),
  412. compute_identity_hash(c),
  413. compute_identity_hash(d))
  414. res = self.interpret(f, [])
  415. # xxx the following test is too precise, checking the exact
  416. # implementation. On Python 2.7 it doesn't work anyway, because
  417. # object.__hash__(x) is different from id(x). The test is disabled
  418. # for now, and nobody should rely on compute_identity_hash() returning
  419. # a value that is (or was) the current_object_addr_as_int().
  420. # --- disabled: assert res.item0 == res.item1
  421. # the following property is essential on top of the lltypesystem
  422. # otherwise prebuilt dictionaries are broken. It's wrong on
  423. # top of the ootypesystem though.
  424. if isinstance(self, LLRtypeMixin):
  425. assert res.item2 == h_c
  426. assert res.item3 == h_d
  427. def test_circular_hash_initialization(self):
  428. class B:
  429. pass
  430. class C(B):
  431. pass
  432. c1 = C()
  433. c1.somedict = {c1: True, C(): False}
  434. def f():
  435. B().somedict = {} # force the attribute up
  436. c1.somedict[c1] = 123
  437. return len(c1.somedict)
  438. res = self.interpret(f, [])
  439. assert res == 2
  440. def test_type(self):
  441. class A:
  442. pass
  443. class B(A):
  444. pass
  445. def g(a):
  446. return type(a)
  447. def f(i):
  448. if i > 0:
  449. a = A()
  450. elif i < 0:
  451. a = B()
  452. else:
  453. a = None
  454. return g(a) is A # should type(None) work? returns None for now
  455. res = self.interpret(f, [1])
  456. assert res is True
  457. res = self.interpret(f, [-1])
  458. assert res is False
  459. res = self.interpret(f, [0])
  460. assert res is False
  461. def test_type_of_constant(self):
  462. class A:
  463. pass
  464. a = A()
  465. def f():
  466. return type(a) is A
  467. res = self.interpret(f, [])
  468. def test_void_fnptr(self):
  469. def g():
  470. return 42
  471. def f():
  472. e = EmptyBase()
  473. e.attr = g
  474. return e.attr()
  475. res = self.interpret(f, [])
  476. assert res == 42
  477. def test_getattr_on_classes(self):
  478. class A:
  479. def meth(self):
  480. return self.value + 42
  481. class B(A):
  482. def meth(self):
  483. shouldnt**be**seen
  484. class C(B):
  485. def meth(self):
  486. return self.value - 1
  487. def pick_class(i):
  488. if i > 0:
  489. return A
  490. else:
  491. return C
  492. def f(i):
  493. meth = pick_class(i).meth
  494. x = C()
  495. x.value = 12
  496. return meth(x) # calls A.meth or C.meth, completely ignores B.meth
  497. res = self.interpret(f, [1])
  498. assert res == 54
  499. res = self.interpret(f, [0])
  500. assert res == 11
  501. def test_constant_bound_method(self):
  502. class C:
  503. value = 1
  504. def meth(self):
  505. return self.value
  506. meth = C().meth
  507. def f():
  508. return meth()
  509. res = self.interpret(f, [])
  510. assert res == 1
  511. def test_mixin(self):
  512. class Mixin(object):
  513. _mixin_ = True
  514. def m(self, v):
  515. return v
  516. class Base(object):
  517. pass
  518. class A(Base, Mixin):
  519. pass
  520. class B(Base, Mixin):
  521. pass
  522. class C(B):
  523. pass
  524. def f():
  525. a = A()
  526. v0 = a.m(2)
  527. b = B()
  528. v1 = b.m('x')
  529. c = C()
  530. v2 = c.m('y')
  531. return v0, v1, v2
  532. res = self.interpret(f, [])
  533. assert typeOf(res.item0) == Signed
  534. def test___class___attribute(self):
  535. class Base(object): pass
  536. class A(Base): pass
  537. class B(Base): pass
  538. class C(A): pass
  539. def seelater():
  540. C()
  541. def f(n):
  542. if n == 1:
  543. x = A()
  544. else:
  545. x = B()
  546. y = B()
  547. result = x.__class__, y.__class__
  548. seelater()
  549. return result
  550. def g():
  551. cls1, cls2 = f(1)
  552. return cls1 is A, cls2 is B
  553. res = self.interpret(g, [])
  554. assert res.item0
  555. assert res.item1
  556. def test_common_class_attribute(self):
  557. class A:
  558. def meth(self):
  559. return self.x
  560. class B(A):
  561. x = 42
  562. class C(A):
  563. x = 43
  564. def call_meth(a):
  565. return a.meth()
  566. def f():
  567. b = B()
  568. c = C()
  569. return call_meth(b) + call_meth(c)
  570. assert self.interpret(f, []) == 85
  571. def test_default_attribute_non_primitive(self):
  572. class A:
  573. x = (1, 2)
  574. def f():
  575. a = A()
  576. a.x = (3, 4)
  577. return a.x[0]
  578. assert self.interpret(f, []) == 3
  579. def test_filter_unreachable_methods(self):
  580. # this creates a family with 20 unreachable methods m(), all
  581. # hidden by a 21st method m().
  582. class Base:
  583. pass
  584. prev = Base
  585. for i in range(20):
  586. class Intermediate(prev):
  587. def m(self, value=i):
  588. return value
  589. prev = Intermediate
  590. class Final(prev):
  591. def m(self):
  592. return -7
  593. def f():
  594. return Final().m()
  595. res = self.interpret(f, [])
  596. assert res == -7
  597. def test_instantiate_despite_abstract_methods(self):
  598. class A:
  599. pass
  600. class B(A):
  601. def foo(self):
  602. return 42
  603. def fn(n):
  604. # Although the code below is a bit strange, there are
  605. # subtle ways in which the same situation could occur.
  606. # One is shown by test_specialize_methods().
  607. if n < 10:
  608. x = B()
  609. else:
  610. x = A()
  611. if n < 7:
  612. return x.foo()
  613. else:
  614. return 100
  615. assert self.interpret(fn, [5]) == 42
  616. assert self.interpret(fn, [15]) == 100
  617. def test_specialize_methods(self):
  618. from pypy.rlib.objectmodel import specialize
  619. class A:
  620. @specialize.arg(1)
  621. def revealconst(self, T):
  622. return 3 * T
  623. revealconst.cls = 'A'
  624. class B(A):
  625. @specialize.arg(1)
  626. def revealconst(self, T):
  627. return 4 * T
  628. revealconst.cls = 'B'
  629. def fn():
  630. a = A()
  631. b = B()
  632. return a.revealconst(1) + b.revealconst(2) + a.revealconst(3)
  633. assert self.interpret(fn, []) == 3 + 8 + 9
  634. def test_hash_of_none(self):
  635. from pypy.rlib.objectmodel import compute_hash
  636. class A:
  637. pass
  638. def fn(x):
  639. if x:
  640. obj = A()
  641. else:
  642. obj = None
  643. return compute_hash(obj)
  644. res = self.interpret(fn, [0])
  645. assert res == 0
  646. def test_hash_of_only_none(self):
  647. from pypy.rlib.objectmodel import compute_hash
  648. def fn():
  649. obj = None
  650. return compute_hash(obj)
  651. res = self.interpret(fn, [])
  652. assert res == 0
  653. def test_immutable(self):
  654. class I(object):
  655. _immutable_ = True
  656. def __init__(self, v):
  657. self.v = v
  658. i = I(3)
  659. def f():
  660. return i.v
  661. t, typer, graph = self.gengraph(f, [], backendopt=True)
  662. assert summary(graph) == {}
  663. def test_immutable_fields(self):
  664. from pypy.jit.metainterp.typesystem import deref
  665. class A(object):
  666. _immutable_fields_ = ["x", "y[*]"]
  667. def __init__(self, x, y):
  668. self.x = x
  669. self.y = y
  670. def f():
  671. return A(3, [])
  672. t, typer, graph = self.gengraph(f, [])
  673. A_TYPE = deref(graph.getreturnvar().concretetype)
  674. accessor = A_TYPE._hints["immutable_fields"]
  675. assert accessor.fields == {"inst_x": IR_IMMUTABLE,
  676. "inst_y": IR_IMMUTABLE_ARRAY} or \
  677. accessor.fields == {"ox": IR_IMMUTABLE,
  678. "oy": IR_IMMUTABLE_ARRAY} # for ootype
  679. def test_immutable_fields_subclass_1(self):
  680. from pypy.jit.metainterp.typesystem import deref
  681. class A(object):
  682. _immutable_fields_ = ["x"]
  683. def __init__(self, x):
  684. self.x = x
  685. class B(A):
  686. def __init__(self, x, y):
  687. A.__init__(self, x)
  688. self.y = y
  689. def f():
  690. return B(3, 5)
  691. t, typer, graph = self.gengraph(f, [])
  692. B_TYPE = deref(graph.getreturnvar().concretetype)
  693. accessor = B_TYPE._hints["immutable_fields"]
  694. assert accessor.fields == {"inst_x": IR_IMMUTABLE} or \
  695. accessor.fields == {"ox": IR_IMMUTABLE} # for ootype
  696. def test_immutable_fields_subclass_2(self):
  697. from pypy.jit.metainterp.typesystem import deref
  698. class A(object):
  699. _immutable_fields_ = ["x"]
  700. def __init__(self, x):
  701. self.x = x
  702. class B(A):
  703. _immutable_fields_ = ["y"]
  704. def __init__(self, x, y):
  705. A.__init__(self, x)
  706. self.y = y
  707. def f():
  708. return B(3, 5)
  709. t, typer, graph = self.gengraph(f, [])
  710. B_TYPE = deref(graph.getreturnvar().concretetype)
  711. accessor = B_TYPE._hints["immutable_fields"]
  712. assert accessor.fields == {"inst_x": IR_IMMUTABLE,
  713. "inst_y": IR_IMMUTABLE} or \
  714. accessor.fields == {"ox": IR_IMMUTABLE,
  715. "oy": IR_IMMUTABLE} # for ootype
  716. def test_immutable_fields_only_in_subclass(self):
  717. from pypy.jit.metainterp.typesystem import deref
  718. class A(object):
  719. def __init__(self, x):
  720. self.x = x
  721. class B(A):
  722. _immutable_fields_ = ["y"]
  723. def __init__(self, x, y):
  724. A.__init__(self, x)
  725. self.y = y
  726. def f():
  727. return B(3, 5)
  728. t, typer, graph = self.gengraph(f, [])
  729. B_TYPE = deref(graph.getreturnvar().concretetype)
  730. accessor = B_TYPE._hints["immutable_fields"]
  731. assert accessor.fields == {"inst_y": IR_IMMUTABLE} or \
  732. accessor.fields == {"oy": IR_IMMUTABLE} # for ootype
  733. def test_immutable_forbidden_inheritance_1(self):
  734. from pypy.rpython.rclass import ImmutableConflictError
  735. class A(object):
  736. pass
  737. class B(A):
  738. _immutable_fields_ = ['v']
  739. def f():
  740. A().v = 123
  741. B() # crash: class B says 'v' is immutable,
  742. # but it is defined on parent class A
  743. py.test.raises(ImmutableConflictError, self.gengraph, f, [])
  744. def test_immutable_forbidden_inheritance_2(self):
  745. from pypy.rpython.rclass import ImmutableConflictError
  746. class A(object):
  747. pass
  748. class B(A):
  749. _immutable_ = True
  750. def f():
  751. A().v = 123
  752. B() # crash: class B has _immutable_ = True
  753. # but class A defines 'v' to be mutable
  754. py.test.raises(ImmutableConflictError, self.gengraph, f, [])
  755. def test_immutable_ok_inheritance_2(self):
  756. from pypy.jit.metainterp.typesystem import deref
  757. class A(object):
  758. _immutable_fields_ = ['v']
  759. class B(A):
  760. _immutable_ = True
  761. def f():
  762. A().v = 123
  763. B().w = 456
  764. return B()
  765. t, typer, graph = self.gengraph(f, [])
  766. B_TYPE = deref(graph.getreturnvar().concretetype)
  767. assert B_TYPE._hints["immutable"]
  768. try:
  769. A_TYPE = B_TYPE.super
  770. except AttributeError:
  771. A_TYPE = B_TYPE._superclass # for ootype
  772. accessor = A_TYPE._hints["immutable_fields"]
  773. assert accessor.fields == {"inst_v": IR_IMMUTABLE} or \
  774. accessor.fields == {"ov": IR_IMMUTABLE} # for ootype
  775. def test_immutable_subclass_1(self):
  776. from pypy.rpython.rclass import ImmutableConflictError
  777. from pypy.jit.metainterp.typesystem import deref
  778. class A(object):
  779. _immutable_ = True
  780. class B(A):
  781. pass
  782. def f():
  783. A()
  784. B().v = 123
  785. return B()
  786. py.test.raises(ImmutableConflictError, self.gengraph, f, [])
  787. def test_immutable_subclass_2(self):
  788. from pypy.jit.metainterp.typesystem import deref
  789. class A(object):
  790. pass
  791. class B(A):
  792. _immutable_ = True
  793. def f():
  794. A()
  795. B().v = 123
  796. return B()
  797. t, typer, graph = self.gengraph(f, [])
  798. B_TYPE = deref(graph.getreturnvar().concretetype)
  799. assert B_TYPE._hints["immutable"]
  800. def test_immutable_subclass_void(self):
  801. from pypy.jit.metainterp.typesystem import deref
  802. class A(object):
  803. pass
  804. class B(A):
  805. _immutable_ = True
  806. def myfunc():
  807. pass
  808. def f():
  809. A().f = myfunc # it's ok to add Void attributes to A
  810. B().v = 123 # even though only B is declared _immutable_
  811. return B()
  812. t, typer, graph = self.gengraph(f, [])
  813. B_TYPE = deref(graph.getreturnvar().concretetype)
  814. assert B_TYPE._hints["immutable"]
  815. def test_quasi_immutable(self):
  816. from pypy.jit.metainterp.typesystem import deref
  817. class A(object):
  818. _immutable_fields_ = ['x', 'y', 'a?', 'b?']
  819. class B(A):
  820. pass
  821. def f():
  822. a = A()
  823. a.x = 42
  824. a.a = 142
  825. b = B()
  826. b.x = 43
  827. b.y = 41
  828. b.a = 44
  829. b.b = 45
  830. return B()
  831. t, typer, graph = self.gengraph(f, [])
  832. B_TYPE = deref(graph.getreturnvar().concretetype)
  833. accessor = B_TYPE._hints["immutable_fields"]
  834. assert accessor.fields == {"inst_y": IR_IMMUTABLE,
  835. "inst_b": IR_QUASIIMMUTABLE} or \
  836. accessor.fields == {"ox": IR_IMMUTABLE,
  837. "oy": IR_IMMUTABLE,
  838. "oa": IR_QUASIIMMUTABLE,
  839. "ob": IR_QUASIIMMUTABLE} # for ootype
  840. found = []
  841. for op in graph.startblock.operations:
  842. if op.opname == 'jit_force_quasi_immutable':
  843. found.append(op.args[1].value)
  844. assert found == ['mutate_a', 'mutate_a', 'mutate_b']
  845. def test_quasi_immutable_array(self):
  846. from pypy.jit.metainterp.typesystem import deref
  847. class A(object):
  848. _immutable_fields_ = ['c?[*]']
  849. class B(A):
  850. pass
  851. def f():
  852. a = A()
  853. a.c = [3, 4, 5]
  854. return A()
  855. t, typer, graph = self.gengraph(f, [])
  856. A_TYPE = deref(graph.getreturnvar().concretetype)
  857. accessor = A_TYPE._hints["immutable_fields"]
  858. assert accessor.fields == {"inst_c": IR_QUASIIMMUTABLE_ARRAY} or \
  859. accessor.fields == {"oc": IR_QUASIIMMUTABLE_ARRAY} # for ootype
  860. found = []
  861. for op in graph.startblock.operations:
  862. if op.opname == 'jit_force_quasi_immutable':
  863. found.append(op.args[1].value)
  864. assert found == ['mutate_c']
  865. class TestLLtype(BaseTestRclass, LLRtypeMixin):
  866. def test__del__(self):
  867. class A(object):
  868. def __init__(self):
  869. self.a = 2
  870. def __del__(self):
  871. self.a = 3
  872. def f():
  873. a = A()
  874. return a.a
  875. t = TranslationContext()
  876. t.buildannotator().build_types(f, [])
  877. t.buildrtyper().specialize()
  878. graph = graphof(t, f)
  879. TYPE = graph.startblock.operations[0].args[0].value
  880. RTTI = getRuntimeTypeInfo(TYPE)
  881. RTTI._obj.query_funcptr # should not raise
  882. destrptr = RTTI._obj.destructor_funcptr
  883. assert destrptr is not None
  884. def test_del_inheritance(self):
  885. from pypy.rlib import rgc
  886. class State:
  887. pass
  888. s = State()
  889. s.a_dels = 0
  890. s.b_dels = 0
  891. class A(object):
  892. def __del__(self):
  893. s.a_dels += 1
  894. class B(A):
  895. def __del__(self):
  896. s.b_dels += 1
  897. class C(A):
  898. pass
  899. def f():
  900. A()
  901. B()
  902. C()
  903. A()
  904. B()
  905. C()
  906. rgc.collect()
  907. return s.a_dels * 10 + s.b_dels
  908. res = f()
  909. assert res == 42
  910. t = TranslationContext()
  911. t.buildannotator().build_types(f, [])
  912. t.buildrtyper().specialize()
  913. graph = graphof(t, f)
  914. TYPEA = graph.startblock.operations[0].args[0].value
  915. RTTIA = getRuntimeTypeInfo(TYPEA)
  916. TYPEB = graph.startblock.operations[3].args[0].value
  917. RTTIB = getRuntimeTypeInfo(TYPEB)
  918. TYPEC = graph.startblock.operations[6].args[0].value
  919. RTTIC = getRuntimeTypeInfo(TYPEC)
  920. queryptra = RTTIA._obj.query_funcptr # should not raise
  921. queryptrb = RTTIB._obj.query_funcptr # should not raise
  922. queryptrc = RTTIC._obj.query_funcptr # should not raise
  923. destrptra = RTTIA._obj.destructor_funcptr
  924. destrptrb = RTTIB._obj.destructor_funcptr
  925. destrptrc = RTTIC._obj.destructor_funcptr
  926. assert destrptra == destrptrc
  927. assert typeOf(destrptra).TO.ARGS[0] != typeOf(destrptrb).TO.ARGS[0]
  928. assert destrptra is not None
  929. assert destrptrb is not None
  930. def test_del_forbidden(self):
  931. class A(object):
  932. def __del__(self):
  933. self.foo()
  934. def foo(self):
  935. self.bar()
  936. def bar(self):
  937. pass
  938. bar._dont_reach_me_in_del_ = True
  939. def f():
  940. a = A()
  941. a.foo()
  942. a.bar()
  943. t = TranslationContext()
  944. t.buildannotator().build_types(f, [])
  945. e = py.test.raises(TyperError, t.buildrtyper().specialize)
  946. print e.value
  947. def test_instance_repr(self):
  948. from pypy.rlib.objectmodel import current_object_addr_as_int
  949. class FooBar(object):
  950. pass
  951. def f():
  952. x = FooBar()
  953. # on lltype, the RPython-level repr of an instance contains the
  954. # current object address
  955. return current_object_addr_as_int(x), str(x)
  956. res = self.interpret(f, [])
  957. xid, xstr = self.ll_unpack_tuple(res, 2)
  958. xstr = self.ll_to_string(xstr)
  959. print xid, xstr
  960. assert 'FooBar' in xstr
  961. from pypy.rlib.rarithmetic import r_uint
  962. expected = hex(r_uint(xid)).lower().replace('l', '')
  963. assert expected in xstr
  964. def test_hash_via_type(self):
  965. from pypy.annotation import model as annmodel
  966. from pypy.rpython import extregistry
  967. from pypy.rpython.annlowlevel import cast_object_to_ptr
  968. from pypy.rlib.objectmodel import compute_identity_hash
  969. class Z(object):
  970. pass
  971. def my_gethash(z):
  972. not_implemented
  973. def ll_my_gethash(ptr):
  974. return identityhash(ptr) # from lltype
  975. class MyGetHashEntry(extregistry.ExtRegistryEntry):
  976. _about_ = my_gethash
  977. def compute_result_annotation(self, s_instance):
  978. return annmodel.SomeInteger()
  979. def specialize_call(self, hop):
  980. [v_instance] = hop.inputargs(*hop.args_r)
  981. return hop.gendirectcall(ll_my_gethash, v_instance)
  982. def f(n):
  983. z = Z()
  984. got = my_gethash(z)
  985. expected = compute_identity_hash(z)
  986. return got - expected
  987. res = self.interpret(f, [5])
  988. assert res == 0
  989. def test_order_of_fields(self):
  990. class A(object):
  991. pass
  992. def f(n):
  993. a = A()
  994. a.as_int = n
  995. a.as_char = chr(n)
  996. a.as_unichar = unichr(n)
  997. a.as_double = n + 0.5
  998. a.as_bool = bool(n)
  999. a.as_void = None
  1000. a.as_longlong = r_longlong(n)
  1001. a.as_reference = A()
  1002. return a
  1003. res = self.interpret(f, [5])
  1004. names = list(typeOf(res).TO._names)
  1005. i = names.index('inst_as_int')
  1006. c = names.index('inst_as_char')
  1007. u = names.index('inst_as_unichar')
  1008. d = names.index('inst_as_double')
  1009. b = names.index('inst_as_bool')
  1010. v = names.index('inst_as_void')
  1011. l = names.index('inst_as_longlong')
  1012. r = names.index('inst_as_reference')
  1013. assert v == 1 # void fields are first
  1014. assert sorted([c, b]) == [7, 8]
  1015. if sys.maxint == 2147483647:
  1016. assert sorted([u, i, r]) == [4, 5, 6] # 32-bit types
  1017. assert sorted([d, l]) == [2, 3] # 64-bit types
  1018. else:
  1019. assert sorted([u]) == [6] # 32-bit types
  1020. assert sorted([i, r, d, l]) == [2, 3, 4, 5] # 64-bit types
  1021. def test_nonmovable(self):
  1022. for (nonmovable, opname) in [(True, 'malloc_nonmovable'),
  1023. (False, 'malloc')]:
  1024. class A(object):
  1025. _alloc_nonmovable_ = nonmovable
  1026. def f():
  1027. return A()
  1028. t, typer, graph = self.gengraph(f, [])
  1029. assert summary(graph) == {opname: 1,
  1030. 'cast_pointer': 1,
  1031. 'setfield': 1}
  1032. class TestOOtype(BaseTestRclass, OORtypeMixin):
  1033. def test__del__(self):
  1034. class A(object):
  1035. def __init__(self):
  1036. self.a = 2
  1037. def __del__(self):
  1038. self.a = 3
  1039. def f():
  1040. a = A()
  1041. return a.a
  1042. t = TranslationContext()
  1043. t.buildannotator().build_types(f, [])
  1044. t.buildrtyper(type_system=self.type_system).specialize()
  1045. graph = graphof(t, f)
  1046. TYPE = graph.startblock.operations[0].args[0].value
  1047. _, meth = TYPE._lookup("o__del__")
  1048. assert meth.finalizer
  1049. def test_del_inheritance(self):
  1050. from pypy.rlib import rgc
  1051. class State:
  1052. pass
  1053. s = State()
  1054. s.a_dels = 0
  1055. s.b_dels = 0
  1056. class A(object):
  1057. def __del__(self):
  1058. s.a_dels += 1
  1059. class B(A):
  1060. def __del__(self):
  1061. s.b_dels += 1
  1062. class C(A):
  1063. pass
  1064. def f():
  1065. A()
  1066. B()
  1067. C()
  1068. A()
  1069. B()
  1070. C()
  1071. rgc.collect()
  1072. return s.a_dels * 10 + s.b_dels
  1073. res = f()
  1074. assert res == 42
  1075. t = TranslationContext()
  1076. t.buildannotator().build_types(f, [])
  1077. t.buildrtyper(type_system=self.type_system).specialize()
  1078. graph = graphof(t, f)
  1079. TYPEA = graph.startblock.operations[0].args[0].value
  1080. TYPEB = graph.startblock.operations[1].args[0].value
  1081. TYPEC = graph.startblock.operations[2].args[0].value
  1082. _, destra = TYPEA._lookup("o__del__")
  1083. _, destrb = TYPEB._lookup("o__del__")
  1084. _, destrc = TYPEC._lookup("o__del__")
  1085. assert destra == destrc
  1086. assert destrb is not None
  1087. assert destra is not None
  1088. def test_cast_object_instance(self):
  1089. A = ootype.Instance("Foo", ootype.ROOT)
  1090. def fn_instance():
  1091. a = ootype.new(A)
  1092. obj = ootype.cast_to_object(a)
  1093. a2 = ootype.cast_from_object(A, obj)
  1094. a3 = ootype.cast_from_object(ootype.ROOT, obj)
  1095. assert a is a2
  1096. assert a is a3
  1097. self.interpret(fn_instance, [])
  1098. def test_cast_object_record(self):
  1099. B = ootype.Record({'x': ootype.Signed})
  1100. def fn_record():
  1101. b = ootype.new(B)
  1102. b.x = 42
  1103. obj = ootype.cast_to_object(b)
  1104. b2 = ootype.cast_from_object(B, obj)
  1105. assert b2.x == 42
  1106. assert b is b2
  1107. self.interpret(fn_record, [])
  1108. def test_cast_object_null(self):
  1109. A = ootype.Instance("Foo", ootype.ROOT)
  1110. B = ootype.Record({'x': ootype.Signed})
  1111. def fn_null():
  1112. a = ootype.null(A)
  1113. b = ootype.null(B)
  1114. obj1 = ootype.cast_to_object(a)
  1115. obj2 = ootype.cast_to_object(b)
  1116. assert obj1 == obj2
  1117. assert ootype.cast_from_object(A, obj1) == a
  1118. assert ootype.cast_from_object(B, obj2) == b
  1119. self.interpret(fn_null, [])
  1120. def test_cast_object_is_true(self):
  1121. A = ootype.Instance("Foo", ootype.ROOT)
  1122. def fn_is_true(flag):
  1123. if flag:
  1124. a = ootype.new(A)
  1125. else:
  1126. a = ootype.null(A)
  1127. obj = ootype.cast_to_object(a)
  1128. return bool(obj)
  1129. assert self.interpret(fn_is_true, [True]) is True
  1130. assert self.interpret(fn_is_true, [False]) is False
  1131. def test_cast_object_mix_null(self):
  1132. A = ootype.Instance("Foo", ootype.ROOT)
  1133. def fn_mix_null(flag):
  1134. a = ootype.new(A)
  1135. obj = ootype.cast_to_object(a)
  1136. if flag:
  1137. return obj
  1138. else:
  1139. return ootype.NULL
  1140. res = self.interpret(fn_mix_null, [False])
  1141. assert res is ootype.NULL