[pypy-commit] pypy use-gc-del-3: Use @rgc.must_be_light_finalizer on classes

arigo pypy.commits at gmail.com
Thu May 5 09:18:32 EDT 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: use-gc-del-3
Changeset: r84214:b00c736dfd7c
Date: 2016-05-05 10:19 +0200
http://bitbucket.org/pypy/pypy/changeset/b00c736dfd7c/

Log:	Use @rgc.must_be_light_finalizer on classes

diff --git a/rpython/annotator/classdesc.py b/rpython/annotator/classdesc.py
--- a/rpython/annotator/classdesc.py
+++ b/rpython/annotator/classdesc.py
@@ -579,6 +579,14 @@
             if cls not in FORCE_ATTRIBUTES_INTO_CLASSES:
                 self.all_enforced_attrs = []    # no attribute allowed
 
+        if (getattr(cls, '_must_be_light_finalizer_', False) and
+            hasattr(cls, '__del__') and
+            not getattr(cls.__del__, '_must_be_light_finalizer_', False)):
+            raise AnnotatorError(
+                "Class %r is in a class hierarchy with "
+                "_must_be_light_finalizer_ = True, but it has a "
+                "destructor without @rgc.must_be_light_finalizer" % (cls,))
+
     def add_source_attribute(self, name, value, mixin=False):
         if isinstance(value, property):
             # special case for property object
diff --git a/rpython/annotator/test/test_annrpython.py b/rpython/annotator/test/test_annrpython.py
--- a/rpython/annotator/test/test_annrpython.py
+++ b/rpython/annotator/test/test_annrpython.py
@@ -4584,6 +4584,32 @@
         e = py.test.raises(Exception, a.build_types, f, [])
         assert str(e.value) == "Don't know how to represent Ellipsis"
 
+    def test_must_be_light_finalizer(self):
+        from rpython.rlib import rgc
+        @rgc.must_be_light_finalizer
+        class A(object):
+            pass
+        class B(A):
+            def __del__(self):
+                pass
+        class C(A):
+            @rgc.must_be_light_finalizer
+            def __del__(self):
+                pass
+        class D(object):
+            def __del__(self):
+                pass
+        def fb():
+            B()
+        def fc():
+            C()
+        def fd():
+            D()
+        a = self.RPythonAnnotator()
+        a.build_types(fc, [])
+        a.build_types(fd, [])
+        py.test.raises(AnnotatorError, a.build_types, fb, [])
+
 
 def g(n):
     return [0, 1, 2, n]
diff --git a/rpython/rlib/rgc.py b/rpython/rlib/rgc.py
--- a/rpython/rlib/rgc.py
+++ b/rpython/rlib/rgc.py
@@ -362,6 +362,16 @@
     return func
 
 def must_be_light_finalizer(func):
+    """Mark a __del__ method as being a destructor, calling only a limited
+    set of operations.  See pypy/doc/discussion/finalizer-order.rst.  
+
+    If you use the same decorator on a class, this class and all its
+    subclasses are only allowed to have __del__ methods which are
+    similarly decorated (or no __del__ at all).  It prevents a class
+    hierarchy from having destructors in some parent classes, which are
+    overridden in subclasses with (non-light, old-style) finalizers.  
+    (This case is the original motivation for FinalizerQueue.)
+    """
     func._must_be_light_finalizer_ = True
     return func
 


More information about the pypy-commit mailing list