[pypy-commit] pypy share-mapdict-methods: fix problems with __del__: only make a single RPython subclass if the base

cfbolz pypy.commits at gmail.com
Thu Apr 28 02:24:08 EDT 2016


Author: Carl Friedrich Bolz <cfbolz at gmx.de>
Branch: share-mapdict-methods
Changeset: r84000:dafa64985e85
Date: 2016-04-28 09:23 +0300
http://bitbucket.org/pypy/pypy/changeset/dafa64985e85/

Log:	fix problems with __del__: only make a single RPython subclass if
	the base class already has a del

diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py
--- a/pypy/interpreter/test/test_typedef.py
+++ b/pypy/interpreter/test/test_typedef.py
@@ -383,6 +383,26 @@
         assert not hasattr(b, "storage")
         assert hasattr(c, "storage")
 
+    def test_del(self):
+        space = self.space
+        a, b, c, d = space.unpackiterable(space.appexec([], """():
+            class A(object):
+                pass
+            class B(object):
+                def __del__(self):
+                    pass
+            class F(file):
+                pass
+            class G(file):
+                def __del__(self):
+                    pass
+            return A(), B(), F("xyz", "w"), G("ghi", "w")
+        """))
+        assert type(b).__base__ is type(a)
+        assert hasattr(c, "__del__")
+        assert type(d) is type(c)
+
+
 class AppTestTypeDef:
 
     def setup_class(cls):
diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py
--- a/pypy/interpreter/typedef.py
+++ b/pypy/interpreter/typedef.py
@@ -112,12 +112,18 @@
     try:
         return _subclass_cache[key]
     except KeyError:
-        # XXX can save a class if cls already has a __del__
-        if needsdel:
+        keys = [key]
+        base_has_del = hasattr(cls, '__del__')
+        if base_has_del:
+            # if the base has a __del__, we only need one class
+            keys = [(config, cls, True), (config, cls, False)]
+            needsdel = True
+        elif needsdel:
             cls = get_unique_interplevel_subclass(config, cls, False)
         subcls = _getusercls(config, cls, needsdel)
         assert key not in _subclass_cache
-        _subclass_cache[key] = subcls
+        for key in keys:
+            _subclass_cache[key] = subcls
         return subcls
 get_unique_interplevel_subclass._annspecialcase_ = "specialize:memo"
 _subclass_cache = {}
@@ -130,17 +136,19 @@
             MapdictDictSupport,
             _make_storage_mixin_size_n, MapdictStorageMixin)
     typedef = cls.typedef
-    name = cls.__name__ + "User"
-
-    mixins_needed = [BaseUserClassMapdict]
-    if cls is W_ObjectObject or cls is W_InstanceObject:
-        mixins_needed.append(_make_storage_mixin_size_n())
-    else:
-        mixins_needed.append(MapdictStorageMixin)
-    if reallywantdict or not typedef.hasdict:
-        # the type has no dict, mapdict to provide the dict
-        mixins_needed.append(MapdictDictSupport)
-        name += "Dict"
+    mixins_needed = []
+    name = cls.__name__
+    if not cls.user_overridden_class:
+        mixins_needed.append(BaseUserClassMapdict)
+        name += "User"
+        if cls is W_ObjectObject or cls is W_InstanceObject:
+            mixins_needed.append(_make_storage_mixin_size_n())
+        else:
+            mixins_needed.append(MapdictStorageMixin)
+        if reallywantdict or not typedef.hasdict:
+            # the type has no dict, mapdict to provide the dict
+            mixins_needed.append(MapdictDictSupport)
+            name += "Dict"
     if wants_del:
         name += "Del"
         parent_destructor = getattr(cls, '__del__', None)
diff --git a/pypy/module/__builtin__/interp_classobj.py b/pypy/module/__builtin__/interp_classobj.py
--- a/pypy/module/__builtin__/interp_classobj.py
+++ b/pypy/module/__builtin__/interp_classobj.py
@@ -197,7 +197,7 @@
         self.cls_without_del = _getusercls(
                 space.config, W_InstanceObject, False, reallywantdict=True)
         self.cls_with_del = _getusercls(
-                space.config, W_InstanceObject, True, reallywantdict=True)
+                space.config, self.cls_without_del, True, reallywantdict=True)
 
 
 def class_descr_call(space, w_self, __args__):


More information about the pypy-commit mailing list