summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
Diffstat (limited to 'Objects')
-rw-r--r--Objects/abstract.c51
-rw-r--r--Objects/typeobject.c31
2 files changed, 60 insertions, 22 deletions
diff --git a/Objects/abstract.c b/Objects/abstract.c
index 54f4e96..159af34 100644
--- a/Objects/abstract.c
+++ b/Objects/abstract.c
@@ -610,14 +610,11 @@ PyNumber_Add(PyObject *v, PyObject *w)
PyObject *result = binary_op1(v, w, NB_SLOT(nb_add));
if (result == Py_NotImplemented) {
PySequenceMethods *m = v->ob_type->tp_as_sequence;
+ Py_DECREF(result);
if (m && m->sq_concat) {
- Py_DECREF(result);
- result = (*m->sq_concat)(v, w);
+ return (*m->sq_concat)(v, w);
}
- if (result == Py_NotImplemented) {
- Py_DECREF(result);
- return binop_type_error(v, w, "+");
- }
+ result = binop_type_error(v, w, "+");
}
return result;
}
@@ -1129,6 +1126,15 @@ PySequence_Concat(PyObject *s, PyObject *o)
if (m && m->sq_concat)
return m->sq_concat(s, o);
+ /* Instances of user classes defining an __add__() method only
+ have an nb_add slot, not an sq_concat slot. So we fall back
+ to nb_add if both arguments appear to be sequences. */
+ if (PySequence_Check(s) && PySequence_Check(o)) {
+ PyObject *result = binary_op1(s, o, NB_SLOT(nb_add));
+ if (result != Py_NotImplemented)
+ return result;
+ Py_DECREF(result);
+ }
return type_error("object can't be concatenated");
}
@@ -1144,6 +1150,20 @@ PySequence_Repeat(PyObject *o, int count)
if (m && m->sq_repeat)
return m->sq_repeat(o, count);
+ /* Instances of user classes defining a __mul__() method only
+ have an nb_multiply slot, not an sq_repeat slot. so we fall back
+ to nb_multiply if o appears to be a sequence. */
+ if (PySequence_Check(o)) {
+ PyObject *n, *result;
+ n = PyInt_FromLong(count);
+ if (n == NULL)
+ return NULL;
+ result = binary_op1(o, n, NB_SLOT(nb_multiply));
+ Py_DECREF(n);
+ if (result != Py_NotImplemented)
+ return result;
+ Py_DECREF(result);
+ }
return type_error("object can't be repeated");
}
@@ -1161,6 +1181,13 @@ PySequence_InPlaceConcat(PyObject *s, PyObject *o)
if (m && m->sq_concat)
return m->sq_concat(s, o);
+ if (PySequence_Check(s) && PySequence_Check(o)) {
+ PyObject *result = binary_iop1(s, o, NB_SLOT(nb_inplace_add),
+ NB_SLOT(nb_add));
+ if (result != Py_NotImplemented)
+ return result;
+ Py_DECREF(result);
+ }
return type_error("object can't be concatenated");
}
@@ -1178,6 +1205,18 @@ PySequence_InPlaceRepeat(PyObject *o, int count)
if (m && m->sq_repeat)
return m->sq_repeat(o, count);
+ if (PySequence_Check(o)) {
+ PyObject *n, *result;
+ n = PyInt_FromLong(count);
+ if (n == NULL)
+ return NULL;
+ result = binary_iop1(o, n, NB_SLOT(nb_inplace_multiply),
+ NB_SLOT(nb_multiply));
+ Py_DECREF(n);
+ if (result != Py_NotImplemented)
+ return result;
+ Py_DECREF(result);
+ }
return type_error("object can't be repeated");
}
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 41c660d..5fec015 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -4097,9 +4097,6 @@ slot_sq_length(PyObject *self)
return len;
}
-SLOT1(slot_sq_concat, "__add__", PyObject *, "O")
-SLOT1(slot_sq_repeat, "__mul__", int, "i")
-
/* Super-optimized version of slot_sq_item.
Other slots could do the same... */
static PyObject *
@@ -4213,9 +4210,6 @@ slot_sq_contains(PyObject *self, PyObject *value)
return result;
}
-SLOT1(slot_sq_inplace_concat, "__iadd__", PyObject *, "O")
-SLOT1(slot_sq_inplace_repeat, "__imul__", int, "i")
-
#define slot_mp_length slot_sq_length
SLOT1(slot_mp_subscript, "__getitem__", PyObject *, "O")
@@ -4929,12 +4923,17 @@ typedef struct wrapperbase slotdef;
static slotdef slotdefs[] = {
SQSLOT("__len__", sq_length, slot_sq_length, wrap_inquiry,
"x.__len__() <==> len(x)"),
- SQSLOT("__add__", sq_concat, slot_sq_concat, wrap_binaryfunc,
- "x.__add__(y) <==> x+y"),
- SQSLOT("__mul__", sq_repeat, slot_sq_repeat, wrap_intargfunc,
- "x.__mul__(n) <==> x*n"),
- SQSLOT("__rmul__", sq_repeat, slot_sq_repeat, wrap_intargfunc,
- "x.__rmul__(n) <==> n*x"),
+ /* Heap types defining __add__/__mul__ have sq_concat/sq_repeat == NULL.
+ The logic in abstract.c always falls back to nb_add/nb_multiply in
+ this case. Defining both the nb_* and the sq_* slots to call the
+ user-defined methods has unexpected side-effects, as shown by
+ test_descr.notimplemented() */
+ SQSLOT("__add__", sq_concat, NULL, wrap_binaryfunc,
+ "x.__add__(y) <==> x+y"),
+ SQSLOT("__mul__", sq_repeat, NULL, wrap_intargfunc,
+ "x.__mul__(n) <==> x*n"),
+ SQSLOT("__rmul__", sq_repeat, NULL, wrap_intargfunc,
+ "x.__rmul__(n) <==> n*x"),
SQSLOT("__getitem__", sq_item, slot_sq_item, wrap_sq_item,
"x.__getitem__(y) <==> x[y]"),
SQSLOT("__getslice__", sq_slice, slot_sq_slice, wrap_intintargfunc,
@@ -4956,10 +4955,10 @@ static slotdef slotdefs[] = {
Use of negative indices is not supported."),
SQSLOT("__contains__", sq_contains, slot_sq_contains, wrap_objobjproc,
"x.__contains__(y) <==> y in x"),
- SQSLOT("__iadd__", sq_inplace_concat, slot_sq_inplace_concat,
- wrap_binaryfunc, "x.__iadd__(y) <==> x+=y"),
- SQSLOT("__imul__", sq_inplace_repeat, slot_sq_inplace_repeat,
- wrap_intargfunc, "x.__imul__(y) <==> x*=y"),
+ SQSLOT("__iadd__", sq_inplace_concat, NULL,
+ wrap_binaryfunc, "x.__iadd__(y) <==> x+=y"),
+ SQSLOT("__imul__", sq_inplace_repeat, NULL,
+ wrap_intargfunc, "x.__imul__(y) <==> x*=y"),
MPSLOT("__len__", mp_length, slot_mp_length, wrap_inquiry,
"x.__len__() <==> len(x)"),