[pypy-commit] pypy mapdict-interp: A test, and fix.

arigo noreply at buildbot.pypy.org
Tue May 17 15:45:52 CEST 2011


Author: Armin Rigo <arigo at tunes.org>
Branch: mapdict-interp
Changeset: r44247:924fc7a7a0f4
Date: 2011-05-17 15:51 +0200
http://bitbucket.org/pypy/pypy/changeset/924fc7a7a0f4/

Log:	A test, and fix.

diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py
--- a/pypy/objspace/std/mapdict.py
+++ b/pypy/objspace/std/mapdict.py
@@ -754,24 +754,32 @@
         w_descr = w_type.getattribute_if_not_from_object()
         if w_descr is not None:
             return space._handle_getattribute(w_descr, w_obj, w_name)
-
         version_tag = w_type.version_tag()
         if version_tag is not None:
             name = space.str_w(w_name)
-            w_descr = w_type.lookup(name)
+            # We need to care for obscure cases in which the w_descr is
+            # a TypeCell, which may change without changing the version_tag
+            assert space.config.objspace.std.withmethodcache
+            _, w_descr = w_type._pure_lookup_where_with_method_cache(
+                name, version_tag)
             selector = ("", INVALID)
-            if w_descr is not None and space.is_data_descr(w_descr):
-                from pypy.interpreter.typedef import Member
-                descr = space.interpclass_w(w_descr)
-                if isinstance(descr, Member):
-                    selector = ("slot", SLOTS_STARTING_FROM + descr.index)
+            if w_descr is None:
+                selector = (name, DICT)   # common case: not shadowing anything
+            elif isinstance(w_descr, TypeCell):
+                pass    # shadowing a TypeCell: give up
             else:
-                selector = (name, DICT)
+                if space.is_data_descr(w_descr):
+                    from pypy.interpreter.typedef import Member
+                    descr = space.interpclass_w(w_descr)
+                    if isinstance(descr, Member):    # a slot
+                        selector = ("slot", SLOTS_STARTING_FROM + descr.index)
+                else:
+                    selector = (name, DICT)   # shadowing a non-data descr
             if selector[1] != INVALID:
                 index = map.index(selector)
                 if index >= 0:
-                    # note that if map.terminator is a DevolvedDictTerminator,
-                    # map.index() will always return -1 if selector[1]==DICT
+                    # Note that if map.terminator is a DevolvedDictTerminator,
+                    # map.index() will always return -1 if selector[1]==DICT.
                     _fill_cache(pycode, nameindex, map, version_tag, index)
                     return w_obj._mapdict_read_storage(index)
     if space.config.objspace.std.withmethodcachecounter:
diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py
--- a/pypy/objspace/std/test/test_mapdict.py
+++ b/pypy/objspace/std/test/test_mapdict.py
@@ -930,6 +930,26 @@
         got = a.method()
         assert got == 44
 
+    def test_bug_slot_via_changing_member_descr(self):
+        class A(object):
+            __slots__ = ['a', 'b', 'c', 'd']
+        x = A()
+        x.a = 'a'
+        x.b = 'b'
+        x.c = 'c'
+        x.d = 'd'
+        got = x.a
+        assert got == 'a'
+        A.a = A.b
+        got = x.a
+        assert got == 'b'
+        A.a = A.c
+        got = x.a
+        assert got == 'c'
+        A.a = A.d
+        got = x.a
+        assert got == 'd'
+
 class AppTestGlobalCaching(AppTestWithMapDict):
     def setup_class(cls):
         cls.space = gettestobjspace(


More information about the pypy-commit mailing list