Skip to content

Commit 47f126a

Browse files
committed
Merge pull request #793 from Daetalus/test_unary
Some improvements to make test unary could pass
2 parents 7c2b76c + 4881de1 commit 47f126a

File tree

4 files changed

+72
-5
lines changed

4 files changed

+72
-5
lines changed

from_cpython/Lib/test/test_unary.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
# expected: fail
21
"""Test compiler changes for unary ops (+, -, ~) introduced in Python 2.2"""
32

43
import unittest

src/runtime/complex.cpp

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,11 @@ extern "C" Box* complexDiv(BoxedComplex* lhs, Box* rhs) {
198198
}
199199
}
200200

201+
Box* complexPos(BoxedComplex* self) {
202+
assert(self->cls == complex_cls);
203+
return PyComplex_FromDoubles(self->real, self->imag);
204+
}
205+
201206
// str and repr
202207
// For now, just print the same way as ordinary doubles.
203208
// TODO this is wrong, e.g. if real or imaginary part is an integer, there should
@@ -260,6 +265,60 @@ Box* complexNew(Box* _cls, Box* real, Box* imag) {
260265
return new BoxedComplex(real_f, imag_f);
261266
}
262267

268+
static PyObject* complex_richcompare(PyObject* v, PyObject* w, int op) noexcept {
269+
PyObject* res;
270+
int equal;
271+
272+
if (op != Py_EQ && op != Py_NE) {
273+
/* for backwards compatibility, comparisons with non-numbers return
274+
* NotImplemented. Only comparisons with core numeric types raise
275+
* TypeError.
276+
*/
277+
if (PyInt_Check(w) || PyLong_Check(w) || PyFloat_Check(w) || PyComplex_Check(w)) {
278+
PyErr_SetString(PyExc_TypeError, "no ordering relation is defined "
279+
"for complex numbers");
280+
return NULL;
281+
}
282+
return Py_NotImplemented;
283+
}
284+
285+
assert(PyComplex_Check(v));
286+
BoxedComplex* lhs = static_cast<BoxedComplex*>(v);
287+
288+
if (PyInt_Check(w) || PyLong_Check(w)) {
289+
/* Check for 0->g0 imaginary part first to avoid the rich
290+
* comparison when possible->g
291+
*/
292+
if (lhs->imag == 0.0) {
293+
PyObject* j, *sub_res;
294+
j = PyFloat_FromDouble(lhs->real);
295+
if (j == NULL)
296+
return NULL;
297+
298+
sub_res = PyObject_RichCompare(j, w, op);
299+
Py_DECREF(j);
300+
return sub_res;
301+
} else {
302+
equal = 0;
303+
}
304+
} else if (PyFloat_Check(w)) {
305+
equal = (lhs->real == PyFloat_AsDouble(w) && lhs->imag == 0.0);
306+
} else if (PyComplex_Check(w)) {
307+
BoxedComplex* rhs = static_cast<BoxedComplex*>(w);
308+
equal = (lhs->real == rhs->real && lhs->imag == rhs->imag);
309+
} else {
310+
return Py_NotImplemented;
311+
}
312+
313+
if (equal == (op == Py_EQ))
314+
res = Py_True;
315+
else
316+
res = Py_False;
317+
318+
Py_INCREF(res);
319+
return res;
320+
}
321+
263322
void setupComplex() {
264323
complex_cls->giveAttr("__new__", new BoxedFunction(boxRTFunction((void*)complexNew, UNKNOWN, 3, 2, false, false),
265324
{ boxInt(0), boxInt(0) }));
@@ -276,13 +335,15 @@ void setupComplex() {
276335
_addFunc("__div__", BOXED_COMPLEX, (void*)complexDivComplex, (void*)complexDivFloat, (void*)complexDivInt,
277336
(void*)complexDiv);
278337

338+
complex_cls->giveAttr("__pos__", new BoxedFunction(boxRTFunction((void*)complexPos, BOXED_COMPLEX, 1)));
279339
complex_cls->giveAttr("__str__", new BoxedFunction(boxRTFunction((void*)complexStr, STR, 1)));
280340
complex_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)complexRepr, STR, 1)));
281341
complex_cls->giveAttr("real",
282342
new BoxedMemberDescriptor(BoxedMemberDescriptor::DOUBLE, offsetof(BoxedComplex, real)));
283343
complex_cls->giveAttr("imag",
284344
new BoxedMemberDescriptor(BoxedMemberDescriptor::DOUBLE, offsetof(BoxedComplex, imag)));
285345
complex_cls->freeze();
346+
complex_cls->tp_richcompare = complex_richcompare;
286347
}
287348

288349
void teardownComplex() {

src/runtime/float.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,11 @@ Box* floatNeg(BoxedFloat* self) {
537537
return boxFloat(-self->d);
538538
}
539539

540+
Box* floatPos(BoxedFloat* self) {
541+
assert(self->cls == float_cls);
542+
return PyFloat_FromDouble(self->d);
543+
}
544+
540545
bool floatNonzeroUnboxed(BoxedFloat* self) {
541546
assert(self->cls == float_cls);
542547
return self->d != 0.0;
@@ -1475,6 +1480,7 @@ void setupFloat() {
14751480
"__new__", new BoxedFunction(boxRTFunction((void*)floatNew, UNKNOWN, 2, 1, false, false), { boxFloat(0.0) }));
14761481

14771482
float_cls->giveAttr("__neg__", new BoxedFunction(boxRTFunction((void*)floatNeg, BOXED_FLOAT, 1)));
1483+
float_cls->giveAttr("__pos__", new BoxedFunction(boxRTFunction((void*)floatPos, BOXED_FLOAT, 1)));
14781484

14791485
CLFunction* nonzero = boxRTFunction((void*)floatNonzeroUnboxed, BOOL, 1);
14801486
addRTFunction(nonzero, (void*)floatNonzero, UNKNOWN);

src/runtime/objmodel.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4378,10 +4378,11 @@ extern "C" Box* unaryop(Box* operand, int op_type) {
43784378

43794379
BoxedString* op_name = getOpName(op_type);
43804380

4381-
// TODO: this code looks very old and like it should be a callattr instead?
4382-
Box* attr_func = getclsattrInternal(operand, op_name, NULL);
4383-
RELEASE_ASSERT(attr_func, "%s.%s", getTypeName(operand), op_name->c_str());
4384-
Box* rtn = runtimeCallInternal<CXX>(attr_func, NULL, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
4381+
CallattrFlags callattr_flags{.cls_only = true, .null_on_nonexistent = true, .argspec = ArgPassSpec(0) };
4382+
Box* rtn = callattr(operand, op_name, callattr_flags, NULL, NULL, NULL, NULL, NULL);
4383+
if (rtn == NULL) {
4384+
raiseExcHelper(TypeError, "bad operand type for unary '%s': '%s'", op_name->c_str(), getTypeName(operand));
4385+
}
43854386

43864387
return rtn;
43874388
}

0 commit comments

Comments
 (0)