Skip to content

Commit 78ed003

Browse files
committed
[GR-12537] Object.__ne__ doesn't work correctly.
1 parent 011af1c commit 78ed003

File tree

4 files changed

+97
-2
lines changed

4 files changed

+97
-2
lines changed
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# Copyright (c) 2018, Oracle and/or its affiliates.
2+
# Copyright (C) 1996-2017 Python Software Foundation
3+
#
4+
# Licensed under the PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
5+
6+
import unittest
7+
8+
class First():
9+
10+
def __init__(self, value):
11+
self.value = value
12+
13+
def __eq__(self, other):
14+
return self.value == other.value
15+
16+
class BasicComparisonTest(unittest.TestCase):
17+
18+
def test_ne(self):
19+
x = First(1)
20+
y = First(1)
21+
z = First(2)
22+
23+
self.assertIs(x == y, True)
24+
self.assertIs(x != y, False)
25+
self.assertIs(x != z, True)
26+
27+
def test_ne_high_priority(self):
28+
"""object.__ne__() should allow reflected __ne__() to be tried"""
29+
calls = []
30+
31+
class Left:
32+
# Inherits object.__ne__()
33+
def __eq__(*args):
34+
calls.append('Left.__eq__')
35+
return NotImplemented
36+
37+
class Right:
38+
39+
def __eq__(*args):
40+
calls.append('Right.__eq__')
41+
return NotImplemented
42+
43+
def __ne__(*args):
44+
calls.append('Right.__ne__')
45+
return NotImplemented
46+
47+
Left() != Right()
48+
self.assertSequenceEqual(calls, ['Left.__eq__', 'Right.__ne__'])
49+
50+
def test_ne_low_priority(self):
51+
"""object.__ne__() should not invoke reflected __eq__()"""
52+
calls = []
53+
54+
class Base:
55+
56+
# Inherits object.__ne__()
57+
def __eq__(*args):
58+
calls.append('Base.__eq__')
59+
return NotImplemented
60+
61+
class Derived(Base): # Subclassing forces higher priority
62+
63+
def __eq__(*args):
64+
calls.append('Derived.__eq__')
65+
return NotImplemented
66+
def __ne__(*args):
67+
calls.append('Derived.__ne__')
68+
return NotImplemented
69+
70+
Base() != Derived()
71+
self.assertSequenceEqual(calls, ['Derived.__ne__', 'Base.__eq__'])

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinConstructors.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1191,6 +1191,9 @@ private static String toString(byte[] barr) {
11911191
@GenerateNodeFactory
11921192
@SuppressWarnings("unused")
11931193
public abstract static class BoolNode extends PythonBinaryBuiltinNode {
1194+
1195+
public abstract boolean executeWith(Object cls, Object val);
1196+
11941197
@Specialization
11951198
public boolean boolB(Object cls, boolean arg) {
11961199
return arg;
@@ -1225,6 +1228,10 @@ public boolean bool(Object cls, Object obj,
12251228
throw raise(PythonErrorType.TypeError, "__bool__ should return bool, returned %p", ex.getResult());
12261229
}
12271230
}
1231+
1232+
public static BoolNode create() {
1233+
return BuiltinConstructorsFactory.BoolNodeFactory.create();
1234+
}
12281235
}
12291236

12301237
// list([iterable])

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/object/ObjectBuiltins.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,9 @@
5454
import com.oracle.graal.python.builtins.CoreFunctions;
5555
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
5656
import com.oracle.graal.python.builtins.PythonBuiltins;
57+
import com.oracle.graal.python.builtins.modules.BuiltinConstructors;
5758
import com.oracle.graal.python.builtins.objects.PNone;
59+
import com.oracle.graal.python.builtins.objects.PNotImplemented;
5860
import com.oracle.graal.python.builtins.objects.cext.PythonNativeClass;
5961
import com.oracle.graal.python.builtins.objects.cext.PythonNativeObject;
6062
import com.oracle.graal.python.builtins.objects.common.PHashingCollection;
@@ -196,9 +198,23 @@ public boolean eq(Object self, Object other) {
196198
@Builtin(name = __NE__, fixedNumOfPositionalArgs = 2)
197199
@GenerateNodeFactory
198200
public abstract static class NeNode extends PythonBinaryBuiltinNode {
201+
199202
@Specialization
200-
public boolean eq(Object self, Object other) {
201-
return self != other;
203+
public boolean ne(PythonNativeObject self, PythonNativeObject other) {
204+
return !self.object.equals(other.object);
205+
}
206+
207+
@Specialization
208+
public Object ne(Object self, Object other,
209+
@Cached("create(__EQ__)") LookupAndCallBinaryNode eqNode,
210+
@Cached("create()") BuiltinConstructors.BoolNode boolNode,
211+
@Cached("create()") GetClassNode getClassNode) {
212+
Object result = eqNode.executeObject(self, other);
213+
if (result == PNotImplemented.NOT_IMPLEMENTED) {
214+
return result;
215+
}
216+
217+
return !boolNode.executeWith(getClassNode.execute(result), result);
202218
}
203219
}
204220

mx.graalpython/copyrights/overrides

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ graalpython/com.oracle.graal.python.test/src/tests/test_call-staticmethod.py,zip
195195
graalpython/com.oracle.graal.python.test/src/tests/test_call-variable-function.py,zippy.copyright
196196
graalpython/com.oracle.graal.python.test/src/tests/test_class-chain-check.py,zippy.copyright
197197
graalpython/com.oracle.graal.python.test/src/tests/test_codecs.py,python.copyright
198+
graalpython/com.oracle.graal.python.test/src/tests/test_compare.py,python.copyright
198199
graalpython/com.oracle.graal.python.test/src/tests/test_enumerate.py,python.copyright
199200
graalpython/com.oracle.graal.python.test/src/tests/test_euler11.py,benchmarks.copyright
200201
graalpython/com.oracle.graal.python.test/src/tests/test_euler31.py,benchmarks.copyright

0 commit comments

Comments
 (0)