[pypy-commit] pypy default: try to see whether it's plausible to forbid moving methods up the class

cfbolz pypy.commits at gmail.com
Mon May 21 10:03:57 EDT 2018


Author: Carl Friedrich Bolz-Tereick <cfbolz at gmx.de>
Branch: 
Changeset: r94626:b51d40dbb01d
Date: 2018-05-17 13:56 +0200
http://bitbucket.org/pypy/pypy/changeset/b51d40dbb01d/

Log:	try to see whether it's plausible to forbid moving methods up the
	class hierarchy in rpython

diff --git a/rpython/annotator/classdesc.py b/rpython/annotator/classdesc.py
--- a/rpython/annotator/classdesc.py
+++ b/rpython/annotator/classdesc.py
@@ -102,13 +102,20 @@
 
     def validate(self, homedef):
         s_newvalue = self.s_value
-        # check for after-the-fact method additions
+        homedesc = homedef.classdesc
+        # check for method demotion and after-the-fact method additions
         if isinstance(s_newvalue, SomePBC):
             attr = self.name
             if s_newvalue.getKind() == MethodDesc:
                 # is method
                 if homedef.classdesc.read_attribute(attr, None) is None:
-                    homedef.check_missing_attribute_update(attr)
+                    if not homedef.check_missing_attribute_update(attr):
+                        for desc in s_newvalue.descriptions:
+                            if desc.selfclassdef is None:
+                                raise AnnotatorError(
+                                    "demoting method %s from %s to class "
+                                    "%s not allowed" % (self.name, desc.originclassdef, homedef)
+                                )
 
         # check for attributes forbidden by slots or _attrs_
         if homedef.classdesc.all_enforced_attrs is not None:
@@ -489,6 +496,7 @@
     knowntype = type
     instance_level = False
     all_enforced_attrs = None   # or a set
+    settled = False
     _detect_invalid_attrs = None
 
     def __init__(self, bookkeeper, cls,
@@ -559,6 +567,9 @@
         if base is not object:
             self.basedesc = bookkeeper.getdesc(base)
 
+        if '_settled_' in cls.__dict__:
+            self.settled = bool(cls.__dict__['_settled_'])
+
         if '__slots__' in cls.__dict__ or '_attrs_' in cls.__dict__:
             attrs = {}
             for decl in ('__slots__', '_attrs_'):
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
@@ -2374,7 +2374,8 @@
     def test_stored_bound_method_2(self):
         # issue 129
         class H:
-            pass
+            def h(self):
+                raise NotImplementedError("abstract method")
         class H1(H):
             def h(self):
                 return 42
@@ -3049,6 +3050,7 @@
     def test_slots_check(self):
         class Base(object):
             __slots__ = 'x'
+            def m(self): raise NotImplementedError("abstract")
         class A(Base):
             __slots__ = 'y'
             def m(self):
@@ -3098,6 +3100,7 @@
     def test_enforced_attrs_check(self):
         class Base(object):
             _attrs_ = 'x'
+            def m(self): raise NotImplementedError("abstract")
         class A(Base):
             _attrs_ = 'y'
             def m(self):
@@ -3167,6 +3170,45 @@
         a = self.RPythonAnnotator()
         a.build_types(f, [bool])
 
+    def test_enforce_settled(self):
+        class A(object):
+            _settled_ = True
+
+            def m(self):
+                raise NotImplementedError
+
+        class B(A):
+
+            def m(self):
+                return 1
+
+            def n(self):
+                return 1
+
+        def fun(x):
+            if x:
+                a = A()
+            else:
+                a = B()
+
+            return a.m()
+
+        a = self.RPythonAnnotator()
+        s = a.build_types(fun, [bool])
+        assert s.knowntype == int
+
+        def fun(x):
+            if x:
+                a = A()
+            else:
+                a = B()
+
+            return a.n()
+
+        a = self.RPythonAnnotator()
+        with py.test.raises(AnnotatorError):
+            a.build_types(fun, [bool])
+
     def test_float_cmp(self):
         def fun(x, y):
             return (x < y,
diff --git a/rpython/translator/test/snippet.py b/rpython/translator/test/snippet.py
--- a/rpython/translator/test/snippet.py
+++ b/rpython/translator/test/snippet.py
@@ -375,7 +375,9 @@
     return _getstuff(d), _getstuff(e)
 
 class F:
-    pass
+    def m(self, x):
+        raise NotImplementedError("abstract base")
+
 class G(F):
     def m(self, x):
         return self.m2(x)


More information about the pypy-commit mailing list