Author: Armin Rigo <[email protected]>
Branch: 
Changeset: r91976:e71aec0042dd
Date: 2017-07-27 15:48 +0200
http://bitbucket.org/pypy/pypy/changeset/e71aec0042dd/

Log:    Issue #2619

        Experimental: remove the special case for the identity of *bound*
        method objects. This depends on CPython, where it seems that no
        strange internal type exists where the equivalent of ``x.method is
        x.method`` would return True. (This is unlike unbound methods, where
        e.g. ``list.append is list.append`` returns True; this is why the
        special case remains for *unbound* method objects.)

diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst
--- a/pypy/doc/cpython_differences.rst
+++ b/pypy/doc/cpython_differences.rst
@@ -330,7 +330,7 @@
 
  - ``frozenset`` (empty frozenset only)
 
- - unbound and bound method objects
+ - unbound method objects
 
 This change requires some changes to ``id`` as well. ``id`` fulfills the
 following condition: ``x is y <=> id(x) == id(y)``. Therefore ``id`` of the
diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py
--- a/pypy/interpreter/function.py
+++ b/pypy/interpreter/function.py
@@ -559,21 +559,29 @@
         return space.newbool(space.eq_w(self.w_function, w_other.w_function))
 
     def is_w(self, space, other):
+        if self.w_instance is not None:
+            return W_Root.is_w(self, space, other)
+        # The following special-case is only for *unbound* method objects.
+        # Motivation: in CPython, it seems that no strange internal type
+        # exists where the equivalent of ``x.method is x.method`` would
+        # return True.  This is unlike unbound methods, where e.g.
+        # ``list.append is list.append`` returns True.  The following code
+        # is here to emulate that behaviour.  Unlike CPython, we return
+        # True for all equal unbound methods, not just for built-in types.
         if not isinstance(other, Method):
             return False
-        return (self.w_instance is other.w_instance and
+        return (other.w_instance is None and
                 self.w_function is other.w_function and
                 self.w_class is other.w_class)
 
     def immutable_unique_id(self, space):
-        from pypy.objspace.std.util import IDTAG_METHOD as tag
+        if self.w_instance is not None:
+            return W_Root.immutable_unique_id(self, space)
+        # the special-case is only for *unbound* method objects
+        #
+        from pypy.objspace.std.util import IDTAG_UNBOUND_METHOD as tag
         from pypy.objspace.std.util import IDTAG_SHIFT
-        if self.w_instance is not None:
-            id = space.bigint_w(space.id(self.w_instance))
-            id = id.lshift(LONG_BIT)
-        else:
-            id = rbigint.fromint(0)
-        id = id.or_(space.bigint_w(space.id(self.w_function)))
+        id = space.bigint_w(space.id(self.w_function))
         id = id.lshift(LONG_BIT).or_(space.bigint_w(space.id(self.w_class)))
         id = id.lshift(IDTAG_SHIFT).int_or_(tag)
         return space.newlong_from_rbigint(id)
diff --git a/pypy/interpreter/test/test_function.py 
b/pypy/interpreter/test/test_function.py
--- a/pypy/interpreter/test/test_function.py
+++ b/pypy/interpreter/test/test_function.py
@@ -1,4 +1,4 @@
-import pytest
+import pytest, sys
 from pypy.interpreter import eval
 from pypy.interpreter.function import Function, Method, descr_function_get
 from pypy.interpreter.pycode import PyCode
@@ -342,6 +342,11 @@
         raises(ValueError, type(f).__setstate__, f, (1, 2, 3))
 
 class AppTestMethod:
+    def setup_class(cls):
+        cls.w_runappdirect_on_cpython = cls.space.wrap(
+            cls.runappdirect and
+            '__pypy__' not in sys.builtin_module_names)
+
     def test_simple_call(self):
         class A(object):
             def func(self, arg2):
@@ -572,7 +577,6 @@
         assert meth == meth
         assert meth == MethodType(func, object)
 
-    @pytest.mark.skipif("config.option.runappdirect")
     def test_method_identity(self):
         class A(object):
             def m(self):
@@ -589,19 +593,24 @@
 
         a = A()
         a2 = A()
-        assert a.m is a.m
-        assert id(a.m) == id(a.m)
-        assert a.m is not a.n
-        assert id(a.m) != id(a.n)
-        assert a.m is not a2.m
-        assert id(a.m) != id(a2.m)
+        x = a.m; y = a.m
+        assert x is not y
+        assert id(x) != id(y)
+        assert x == y
+        assert x is not a.n
+        assert id(x) != id(a.n)
+        assert x is not a2.m
+        assert id(x) != id(a2.m)
 
-        assert A.m is A.m
-        assert id(A.m) == id(A.m)
-        assert A.m is not A.n
-        assert id(A.m) != id(A.n)
-        assert A.m is not B.m
-        assert id(A.m) != id(B.m)
+        if not self.runappdirect_on_cpython:
+            assert A.m is A.m
+            assert id(A.m) == id(A.m)
+        assert A.m == A.m
+        x = A.m
+        assert x is not A.n
+        assert id(x) != id(A.n)
+        assert x is not B.m
+        assert id(x) != id(B.m)
 
 
 class TestMethod:
diff --git a/pypy/objspace/std/util.py b/pypy/objspace/std/util.py
--- a/pypy/objspace/std/util.py
+++ b/pypy/objspace/std/util.py
@@ -8,7 +8,7 @@
 IDTAG_LONG    = 3
 IDTAG_FLOAT   = 5
 IDTAG_COMPLEX = 7
-IDTAG_METHOD  = 9
+IDTAG_UNBOUND_METHOD = 9
 IDTAG_SPECIAL = 11    # -1 - (-maxunicode-1): unichar
                       # 0 - 255: char
                       # 256: empty string
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to