bpo-36974: inherit the vectorcall protocol (GH-13498) · python/cpython@735e8af
@@ -5814,6 +5814,29 @@ static PyTypeObject Generic_Type = {
5814581458155815/* Test PEP 590 */
581658165817+typedef struct {
5818+PyObject_HEAD
5819+vectorcallfunc vectorcall;
5820+} MethodDescriptorObject;
5821+5822+static PyObject *
5823+MethodDescriptor_vectorcall(PyObject *callable, PyObject *const *args,
5824+size_t nargsf, PyObject *kwnames)
5825+{
5826+/* True if using the vectorcall function in MethodDescriptorObject
5827+ * but False for MethodDescriptor2Object */
5828+MethodDescriptorObject *md = (MethodDescriptorObject *)callable;
5829+return PyBool_FromLong(md->vectorcall != NULL);
5830+}
5831+5832+static PyObject *
5833+MethodDescriptor_new(PyTypeObject* type, PyObject* args, PyObject *kw)
5834+{
5835+MethodDescriptorObject *op = PyObject_New(MethodDescriptorObject, type);
5836+op->vectorcall = MethodDescriptor_vectorcall;
5837+return (PyObject *)op;
5838+}
5839+58175840static PyObject *
58185841func_descr_get(PyObject *func, PyObject *obj, PyObject *type)
58195842{
@@ -5831,10 +5854,22 @@ nop_descr_get(PyObject *func, PyObject *obj, PyObject *type)
58315854return func;
58325855}
583358565857+static PyObject *
5858+call_return_args(PyObject *self, PyObject *args, PyObject *kwargs)
5859+{
5860+Py_INCREF(args);
5861+return args;
5862+}
5863+58345864static PyTypeObject MethodDescriptorBase_Type = {
58355865PyVarObject_HEAD_INIT(NULL, 0)
58365866"MethodDescriptorBase",
5837- .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_METHOD_DESCRIPTOR,
5867+sizeof(MethodDescriptorObject),
5868+ .tp_new = MethodDescriptor_new,
5869+ .tp_call = PyVectorcall_Call,
5870+ .tp_vectorcall_offset = offsetof(MethodDescriptorObject, vectorcall),
5871+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
5872+Py_TPFLAGS_METHOD_DESCRIPTOR | _Py_TPFLAGS_HAVE_VECTORCALL,
58385873 .tp_descr_get = func_descr_get,
58395874};
58405875@@ -5848,9 +5883,34 @@ static PyTypeObject MethodDescriptorNopGet_Type = {
58485883PyVarObject_HEAD_INIT(NULL, 0)
58495884"MethodDescriptorNopGet",
58505885 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
5886+ .tp_call = call_return_args,
58515887 .tp_descr_get = nop_descr_get,
58525888};
585358895890+typedef struct {
5891+MethodDescriptorObject base;
5892+vectorcallfunc vectorcall;
5893+} MethodDescriptor2Object;
5894+5895+static PyObject *
5896+MethodDescriptor2_new(PyTypeObject* type, PyObject* args, PyObject *kw)
5897+{
5898+MethodDescriptor2Object *op = PyObject_New(MethodDescriptor2Object, type);
5899+op->base.vectorcall = NULL;
5900+op->vectorcall = MethodDescriptor_vectorcall;
5901+return (PyObject *)op;
5902+}
5903+5904+static PyTypeObject MethodDescriptor2_Type = {
5905+PyVarObject_HEAD_INIT(NULL, 0)
5906+"MethodDescriptor2",
5907+sizeof(MethodDescriptor2Object),
5908+ .tp_new = MethodDescriptor2_new,
5909+ .tp_call = PyVectorcall_Call,
5910+ .tp_vectorcall_offset = offsetof(MethodDescriptor2Object, vectorcall),
5911+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | _Py_TPFLAGS_HAVE_VECTORCALL,
5912+};
5913+5854591458555915static struct PyModuleDef _testcapimodule = {
58565916PyModuleDef_HEAD_INIT,
@@ -5916,6 +5976,12 @@ PyInit__testcapi(void)
59165976Py_INCREF(&MethodDescriptorNopGet_Type);
59175977PyModule_AddObject(m, "MethodDescriptorNopGet", (PyObject *)&MethodDescriptorNopGet_Type);
591859785979+MethodDescriptor2_Type.tp_base = &MethodDescriptorBase_Type;
5980+if (PyType_Ready(&MethodDescriptor2_Type) < 0)
5981+return NULL;
5982+Py_INCREF(&MethodDescriptor2_Type);
5983+PyModule_AddObject(m, "MethodDescriptor2", (PyObject *)&MethodDescriptor2_Type);
5984+59195985if (PyType_Ready(&GenericAlias_Type) < 0)
59205986return NULL;
59215987Py_INCREF(&GenericAlias_Type);