[pypy-commit] pypy cpyext-gc-support-2: (ronan, arigo)

arigo pypy.commits at gmail.com
Mon Feb 22 12:30:36 EST 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: cpyext-gc-support-2
Changeset: r82403:f2383d0be1ba
Date: 2016-02-22 18:29 +0100
http://bitbucket.org/pypy/pypy/changeset/f2383d0be1ba/

Log:	(ronan, arigo)

	Fix and test for inheriting at app-level from some PyTypeObject

diff --git a/pypy/module/cpyext/test/foo.c b/pypy/module/cpyext/test/foo.c
--- a/pypy/module/cpyext/test/foo.c
+++ b/pypy/module/cpyext/test/foo.c
@@ -623,11 +623,17 @@
 };
 
 
+static PyObject *size_of_instances(PyObject *self, PyObject *t)
+{
+    return PyInt_FromLong(((PyTypeObject *)t)->tp_basicsize);
+}
+
 /* List of functions exported by this module */
 
 static PyMethodDef foo_functions[] = {
     {"new",        (PyCFunction)foo_new, METH_NOARGS, NULL},
     {"newCustom",  (PyCFunction)newCustom, METH_NOARGS, NULL},
+    {"size_of_instances", (PyCFunction)size_of_instances, METH_O, NULL},
     {NULL,        NULL}    /* Sentinel */
 };
 
diff --git a/pypy/module/cpyext/test/test_typeobject.py b/pypy/module/cpyext/test/test_typeobject.py
--- a/pypy/module/cpyext/test/test_typeobject.py
+++ b/pypy/module/cpyext/test/test_typeobject.py
@@ -744,3 +744,25 @@
         module = self.import_module(name='foo3')
         print('calling module.Type()...')
         module.Type("X", (object,), {})
+
+    def test_app_subclass_of_c_type(self):
+        module = self.import_module(name='foo')
+        size = module.size_of_instances(module.fooType)
+        class f1(object):
+            pass
+        class f2(module.fooType):
+            pass
+        class bar(f1, f2):
+            pass
+        assert bar.__base__ is f2
+        assert module.size_of_instances(bar) == size
+
+    def test_app_cant_subclass_two_types(self):
+        module = self.import_module(name='foo')
+        try:
+            class bar(module.fooType, module.Property):
+                pass
+        except TypeError as e:
+            assert str(e) == 'instance layout conflicts in multiple inheritance'
+        else:
+            raise AssertionError("did not get TypeError!")
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -297,7 +297,7 @@
         name = rffi.charp2str(pto.c_tp_name)
 
         W_TypeObject.__init__(self, space, name,
-            bases_w or [space.w_object], dict_w)
+            bases_w or [space.w_object], dict_w, force_new_layout=True)
         if not space.is_true(space.issubtype(self, space.w_type)):
             self.flag_cpytype = True
         self.flag_heaptype = False
diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py
--- a/pypy/objspace/std/typeobject.py
+++ b/pypy/objspace/std/typeobject.py
@@ -148,7 +148,7 @@
 
     @dont_look_inside
     def __init__(w_self, space, name, bases_w, dict_w,
-                 overridetypedef=None):
+                 overridetypedef=None, force_new_layout=False):
         w_self.space = space
         w_self.name = name
         w_self.bases_w = bases_w
@@ -164,9 +164,10 @@
         w_self.flag_sequence_bug_compat = False
 
         if overridetypedef is not None:
+            assert not force_new_layout
             layout = setup_builtin_type(w_self, overridetypedef)
         else:
-            layout = setup_user_defined_type(w_self)
+            layout = setup_user_defined_type(w_self, force_new_layout)
         w_self.layout = layout
 
         if space.config.objspace.std.withtypeversion:
@@ -1000,7 +1001,7 @@
         w_self.weakrefable = w_self.weakrefable or w_base.weakrefable
     return hasoldstylebase
 
-def create_all_slots(w_self, hasoldstylebase, w_bestbase):
+def create_all_slots(w_self, hasoldstylebase, w_bestbase, force_new_layout):
     base_layout = w_bestbase.layout
     index_next_extra_slot = base_layout.nslots
     space = w_self.space
@@ -1040,7 +1041,7 @@
     if '__del__' in dict_w:
         w_self.needsdel = True
     #
-    if index_next_extra_slot == base_layout.nslots:
+    if index_next_extra_slot == base_layout.nslots and not force_new_layout:
         return base_layout
     else:
         return Layout(base_layout.typedef, index_next_extra_slot,
@@ -1081,7 +1082,7 @@
             return False
     return True
 
-def setup_user_defined_type(w_self):
+def setup_user_defined_type(w_self, force_new_layout):
     if len(w_self.bases_w) == 0:
         w_self.bases_w = [w_self.space.w_object]
     w_bestbase = check_and_find_best_base(w_self.space, w_self.bases_w)
@@ -1093,7 +1094,8 @@
         w_self.flag_abstract |= w_base.flag_abstract
 
     hasoldstylebase = copy_flags_from_bases(w_self, w_bestbase)
-    layout = create_all_slots(w_self, hasoldstylebase, w_bestbase)
+    layout = create_all_slots(w_self, hasoldstylebase, w_bestbase,
+                              force_new_layout)
 
     ensure_common_attributes(w_self)
     return layout


More information about the pypy-commit mailing list