[pypy-svn] pypy default: Bah, it's too messy to implement. So let's just say it's not RPython

arigo commits-noreply at bitbucket.org
Sun Mar 13 18:15:46 CET 2011


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r42560:2fb044e92956
Date: 2011-03-13 13:15 -0400
http://bitbucket.org/pypy/pypy/changeset/2fb044e92956/

Log:	Bah, it's too messy to implement. So let's just say it's not
	RPython to have an __init__ in the subclasses but not in the parent
	class in that case.

diff --git a/pypy/annotation/description.py b/pypy/annotation/description.py
--- a/pypy/annotation/description.py
+++ b/pypy/annotation/description.py
@@ -665,6 +665,21 @@
         else:
             # call to multiple classes: specialization not supported
             classdefs = [desc.getuniqueclassdef() for desc in descs]
+            # If some of the classes have an __init__ and others not, then
+            # we complain, even though in theory it could work if all the
+            # __init__s take no argument.  But it's messy to implement, so
+            # let's just say it is not RPython and you have to add an empty
+            # __init__ to your base class.
+            has_init = False
+            for desc in descs:
+                s_init = desc.s_read_attribute('__init__')
+                has_init |= isinstance(s_init, SomePBC)
+            basedesc = ClassDesc.getcommonbase(descs)
+            s_init = basedesc.s_read_attribute('__init__')
+            parent_has_init = isinstance(s_init, SomePBC)
+            if has_init and not parent_has_init:
+                raise Exception("some subclasses among %r declare __init__(),"
+                                " but not the common parent class" % (descs,))
         # make a PBC of MethodDescs, one for the __init__ of each class
         initdescs = []
         for desc, classdef in zip(descs, classdefs):
@@ -687,6 +702,23 @@
                                           args, s_None)
     consider_call_site = staticmethod(consider_call_site)
 
+    def getallbases(self):
+        desc = self
+        while desc is not None:
+            yield desc
+            desc = desc.basedesc
+
+    def getcommonbase(descs):
+        commondesc = descs[0]
+        for desc in descs[1:]:
+            allbases = set(commondesc.getallbases())
+            while desc not in allbases:
+                assert desc is not None, "no common base for %r" % (descs,)
+                desc = desc.basedesc
+            commondesc = desc
+        return commondesc
+    getcommonbase = staticmethod(getcommonbase)
+
     def rowkey(self):
         return self
 

diff --git a/pypy/annotation/test/test_description.py b/pypy/annotation/test/test_description.py
new file mode 100644
--- /dev/null
+++ b/pypy/annotation/test/test_description.py
@@ -0,0 +1,22 @@
+from pypy.annotation.description import ClassDesc
+
+class FakeBookkeeper:
+    def __init__(self):
+        self.seen = {}
+    def getdesc(self, cls):
+        if cls not in self.seen:
+            self.seen[cls] = ClassDesc(self, cls)
+        return self.seen[cls]
+
+def test_getcommonbase():
+    class Base(object): pass
+    class A(Base):      pass
+    class B(A):         pass
+    class C(B):         pass
+    class D(A):         pass
+    bk = FakeBookkeeper()
+    dA = bk.getdesc(A)
+    dB = bk.getdesc(B)
+    dC = bk.getdesc(C)
+    dD = bk.getdesc(D)
+    assert ClassDesc.getcommonbase([dC, dD]) is dA

diff --git a/pypy/annotation/test/test_annrpython.py b/pypy/annotation/test/test_annrpython.py
--- a/pypy/annotation/test/test_annrpython.py
+++ b/pypy/annotation/test/test_annrpython.py
@@ -1060,9 +1060,11 @@
         assert s.const == True
 
     def test_alloc_like(self):
-        class C1(object):
+        class Base(object):
             pass
-        class C2(object):
+        class C1(Base):
+            pass
+        class C2(Base):
             pass
 
         def inst(cls):
@@ -3438,6 +3440,28 @@
         a = self.RPythonAnnotator()
         a.build_types(f, [int])
 
+    def test_call_classes_with_noarg_init(self):
+        class A:
+            foo = 21
+        class B(A):
+            foo = 22
+        class C(A):
+            def __init__(self):
+                self.foo = 42
+        class D(A):
+            def __init__(self):
+                self.foo = 43
+        def f(i):
+            if i == 1:
+                cls = B
+            elif i == 2:
+                cls = D
+            else:
+                cls = C
+            return cls().foo
+        a = self.RPythonAnnotator()
+        raises(Exception, a.build_types, f, [int])
+
 
 def g(n):
     return [0,1,2,n]

diff --git a/pypy/rpython/test/test_rpbc.py b/pypy/rpython/test/test_rpbc.py
--- a/pypy/rpython/test/test_rpbc.py
+++ b/pypy/rpython/test/test_rpbc.py
@@ -617,32 +617,6 @@
         assert self.read_attr(res, "z") == -7645
         assert self.read_attr(res, "extra") == 42
 
-    def test_call_classes_with_noarg_init(self):
-        class A:
-            foo = 21
-        class B(A):
-            foo = 22
-        class C(A):
-            def __init__(self):
-                self.foo = 42
-        class D(A):
-            def __init__(self):
-                self.foo = 43
-        def f(i):
-            if i == 1:
-                cls = B
-            elif i == 2:
-                cls = D
-            else:
-                cls = C
-            return cls().foo
-        res = self.interpret(f, [0])
-        assert res == 42
-        res = self.interpret(f, [1])
-        assert res == 22
-        res = self.interpret(f, [2])
-        assert res == 43
-
     def test_conv_from_None(self):
         class A(object): pass
         def none():


More information about the Pypy-commit mailing list