Skip to content

Commit 24948b5

Browse files
committed
[GR-12537] Object.__ne__ doesn't work correctly.
PullRequest: graalpython/277
2 parents d129a07 + 878841e commit 24948b5

File tree

7 files changed

+179
-11
lines changed

7 files changed

+179
-11
lines changed
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
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+
import sys
9+
10+
class Empty:
11+
def __repr__(self):
12+
return '<Empty>'
13+
14+
class Cmp:
15+
def __init__(self,arg):
16+
self.arg = arg
17+
18+
def __repr__(self):
19+
return '<Cmp %s>' % self.arg
20+
21+
def __eq__(self, other):
22+
return self.arg == other
23+
24+
class First():
25+
26+
def __init__(self, value):
27+
self.value = value
28+
29+
def __eq__(self, other):
30+
return self.value == other.value
31+
32+
class BasicComparisonTest(unittest.TestCase):
33+
34+
set1 = [2, 2.0, 2, 2+0j, Cmp(2.0)]
35+
set2 = [[1], (3,), None, Empty()]
36+
candidates = set1 + set2
37+
38+
def test_comparisons(self):
39+
for a in self.candidates:
40+
for b in self.candidates:
41+
if ((a in self.set1) and (b in self.set1)) or a is b:
42+
self.assertEqual(a, b)
43+
else:
44+
self.assertNotEqual(a, b)
45+
46+
def test_id_comparisons(self):
47+
# Ensure default comparison compares id() of args
48+
L = []
49+
for i in range(10):
50+
L.insert(len(L)//2, Empty())
51+
for a in L:
52+
for b in L:
53+
self.assertEqual(a == b, id(a) == id(b),
54+
'a=%r, b=%r' % (a, b))
55+
56+
def test_ne(self):
57+
x = First(1)
58+
y = First(1)
59+
z = First(2)
60+
61+
self.assertIs(x == y, True)
62+
self.assertIs(x != y, False)
63+
self.assertIs(x != z, True)
64+
65+
if (sys.version_info.major >= 3 and sys.version_info.minor >= 5):
66+
def test_ne_high_priority(self):
67+
"""object.__ne__() should allow reflected __ne__() to be tried"""
68+
calls = []
69+
70+
class Left:
71+
# Inherits object.__ne__()
72+
def __eq__(*args):
73+
calls.append('Left.__eq__')
74+
return NotImplemented
75+
76+
class Right:
77+
78+
def __eq__(*args):
79+
calls.append('Right.__eq__')
80+
return NotImplemented
81+
82+
def __ne__(*args):
83+
calls.append('Right.__ne__')
84+
return NotImplemented
85+
86+
Left() != Right()
87+
self.assertSequenceEqual(calls, ['Left.__eq__', 'Right.__ne__'])
88+
89+
def test_ne_low_priority(self):
90+
"""object.__ne__() should not invoke reflected __eq__()"""
91+
calls = []
92+
93+
class Base:
94+
95+
# Inherits object.__ne__()
96+
def __eq__(*args):
97+
calls.append('Base.__eq__')
98+
return NotImplemented
99+
100+
class Derived(Base): # Subclassing forces higher priority
101+
102+
def __eq__(*args):
103+
calls.append('Derived.__eq__')
104+
return NotImplemented
105+
def __ne__(*args):
106+
calls.append('Derived.__ne__')
107+
return NotImplemented
108+
109+
Base() != Derived()
110+
self.assertSequenceEqual(calls, ['Derived.__ne__', 'Base.__eq__'])

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1194,6 +1194,7 @@ private static String toString(byte[] barr) {
11941194
@GenerateNodeFactory
11951195
@SuppressWarnings("unused")
11961196
public abstract static class BoolNode extends PythonBinaryBuiltinNode {
1197+
11971198
@Specialization
11981199
public boolean boolB(Object cls, boolean arg) {
11991200
return arg;
@@ -1228,6 +1229,7 @@ public boolean bool(Object cls, Object obj,
12281229
throw raise(PythonErrorType.TypeError, "__bool__ should return bool, returned %p", ex.getResult());
12291230
}
12301231
}
1232+
12311233
}
12321234

12331235
// list([iterable])

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/CExtNodes.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -870,6 +870,10 @@ private TruffleObject getNativeFunction() {
870870
return isFunc;
871871
}
872872

873+
public static IsNode create() {
874+
return new CExtNodes.IsNode();
875+
}
876+
873877
}
874878

875879
public abstract static class AllToJavaNode extends PNodeWithContext {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/complex/ComplexBuiltins.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,12 +367,41 @@ PNotImplemented doComplex(Object left, Object right) {
367367

368368
@GenerateNodeFactory
369369
@Builtin(name = __EQ__, fixedNumOfPositionalArgs = 2)
370+
@TypeSystemReference(PythonArithmeticTypes.class)
370371
static abstract class EqNode extends PythonBinaryBuiltinNode {
371372
@Specialization
372373
boolean doComplex(PComplex left, PComplex right) {
373374
return left.equals(right);
374375
}
375376

377+
@Specialization
378+
boolean doComplexInt(PComplex left, long right) {
379+
if (left.getImag() == 0) {
380+
return left.getReal() == right;
381+
}
382+
return false;
383+
}
384+
385+
@Specialization
386+
boolean doComplexInt(PComplex left, PInt right) {
387+
if (left.getImag() == 0) {
388+
try {
389+
return left.getReal() == right.getValue().longValueExact();
390+
} catch (ArithmeticException e) {
391+
// do nothing -> return false;
392+
}
393+
}
394+
return false;
395+
}
396+
397+
@Specialization
398+
boolean doComplexInt(PComplex left, double right) {
399+
if (left.getImag() == 0) {
400+
return left.getReal() == right;
401+
}
402+
return false;
403+
}
404+
376405
@SuppressWarnings("unused")
377406
@Fallback
378407
PNotImplemented doGeneric(Object left, Object right) {

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

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@
5555
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
5656
import com.oracle.graal.python.builtins.PythonBuiltins;
5757
import com.oracle.graal.python.builtins.objects.PNone;
58+
import com.oracle.graal.python.builtins.objects.PNotImplemented;
59+
import com.oracle.graal.python.builtins.objects.cext.CExtNodes;
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;
@@ -74,6 +76,7 @@
7476
import com.oracle.graal.python.nodes.call.special.LookupAndCallBinaryNode;
7577
import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode;
7678
import com.oracle.graal.python.nodes.expression.BinaryComparisonNode;
79+
import com.oracle.graal.python.nodes.expression.CastToBooleanNode;
7780
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
7881
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
7982
import com.oracle.graal.python.nodes.function.builtins.PythonTernaryBuiltinNode;
@@ -183,22 +186,45 @@ public int hash(Object self) {
183186
@GenerateNodeFactory
184187
public abstract static class EqNode extends PythonBinaryBuiltinNode {
185188
@Specialization
186-
public boolean eq(PythonNativeObject self, PythonNativeObject other) {
187-
return self.object.equals(other.object);
189+
public boolean eq(PythonNativeObject self, PythonNativeObject other,
190+
@Cached("create()") CExtNodes.IsNode nativeIsNode) {
191+
return nativeIsNode.execute(self, other);
188192
}
189193

190-
@Specialization
191-
public boolean eq(Object self, Object other) {
194+
@Fallback
195+
public Object eq(Object self, Object other) {
192196
return self == other;
193197
}
194198
}
195199

196200
@Builtin(name = __NE__, fixedNumOfPositionalArgs = 2)
197201
@GenerateNodeFactory
198202
public abstract static class NeNode extends PythonBinaryBuiltinNode {
203+
204+
@Child private LookupAndCallBinaryNode eqNode;
205+
@Child private CastToBooleanNode ifFalseNode;
206+
199207
@Specialization
200-
public boolean eq(Object self, Object other) {
201-
return self != other;
208+
public boolean ne(PythonNativeObject self, PythonNativeObject other,
209+
@Cached("create()") CExtNodes.IsNode nativeIsNode) {
210+
return !nativeIsNode.execute(self, other);
211+
}
212+
213+
@Fallback
214+
public Object ne(Object self, Object other) {
215+
if (eqNode == null) {
216+
CompilerDirectives.transferToInterpreterAndInvalidate();
217+
eqNode = insert(LookupAndCallBinaryNode.create(__EQ__));
218+
}
219+
Object result = eqNode.executeObject(self, other);
220+
if (result == PNotImplemented.NOT_IMPLEMENTED) {
221+
return result;
222+
}
223+
if (ifFalseNode == null) {
224+
CompilerDirectives.transferToInterpreterAndInvalidate();
225+
ifFalseNode = insert(CastToBooleanNode.createIfFalseNode());
226+
}
227+
return ifFalseNode.executeWith(result);
202228
}
203229
}
204230

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/expression/IsNode.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -163,13 +163,9 @@ boolean doDD(double left, double right) {
163163
return left == right;
164164
}
165165

166-
protected static CExtNodes.IsNode getNativeIsNode() {
167-
return new CExtNodes.IsNode();
168-
}
169-
170166
@Specialization
171167
boolean doNative(PythonNativeObject left, PythonNativeObject right,
172-
@Cached("getNativeIsNode()") CExtNodes.IsNode isNode) {
168+
@Cached("create()") CExtNodes.IsNode isNode) {
173169
return isNode.execute(left, right);
174170
}
175171

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)