From a3739b207adb5d17e3b53347df05b54b1a8b87f0 Mon Sep 17 00:00:00 2001 From: Erlend Egeberg Aasland Date: Thu, 8 Jul 2021 12:48:01 +0200 Subject: bpo-43908: Immutable types inherit vectorcall (GH-27001) Heap types with the Py_TPFLAGS_IMMUTABLETYPE flag can now inherit the PEP 590 vectorcall protocol. Previously, this was only possible for static types. Co-authored-by: Victor Stinner --- Doc/c-api/typeobj.rst | 17 +++++++++-------- Doc/whatsnew/3.11.rst | 5 +++++ Lib/test/test_call.py | 4 ++-- .../2021-07-03-00-20-39.bpo-43908.YHuV_s.rst | 3 +++ Objects/typeobject.c | 8 ++++---- 5 files changed, 23 insertions(+), 14 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2021-07-03-00-20-39.bpo-43908.YHuV_s.rst diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index ea81115..004cecd 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -710,7 +710,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) .. warning:: - It is not recommended for :ref:`heap types ` to implement + It is not recommended for :ref:`mutable heap types ` to implement the vectorcall protocol. When a user sets :attr:`__call__` in Python code, only *tp_call* is updated, likely making it inconsistent with the vectorcall function. @@ -734,8 +734,9 @@ and :c:type:`PyType_Type` effectively act as defaults.) always inherited. If it's not, then the subclass won't use :ref:`vectorcall `, except when :c:func:`PyVectorcall_Call` is explicitly called. - This is in particular the case for :ref:`heap types ` - (including subclasses defined in Python). + This is in particular the case for types without the + :const:`Py_TPFLAGS_IMMUTABLETYPE` flag set (including subclasses defined in + Python). .. c:member:: getattrfunc PyTypeObject.tp_getattr @@ -1125,9 +1126,9 @@ and :c:type:`PyType_Type` effectively act as defaults.) **Inheritance:** - This flag is never inherited by :ref:`heap types `. - For extension types, it is inherited whenever - :c:member:`~PyTypeObject.tp_descr_get` is inherited. + This flag is never inherited by types without the + :const:`Py_TPFLAGS_IMMUTABLETYPE` flag set. For extension types, it is + inherited whenever :c:member:`~PyTypeObject.tp_descr_get` is inherited. .. XXX Document more flags here? @@ -1172,9 +1173,9 @@ and :c:type:`PyType_Type` effectively act as defaults.) **Inheritance:** - This bit is inherited for :ref:`static subtypes ` if + This bit is inherited for types with the + :const:`Py_TPFLAGS_IMMUTABLETYPE` flag set, if :c:member:`~PyTypeObject.tp_call` is also inherited. - :ref:`Heap types ` do not inherit ``Py_TPFLAGS_HAVE_VECTORCALL``. .. versionadded:: 3.9 diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 5b58ef6..bfadda1 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -214,6 +214,11 @@ Porting to Python 3.11 (:c:member:`PyTypeObject.tp_traverse`). (Contributed by Victor Stinner in :issue:`44263`.) +* Heap types with the :const:`Py_TPFLAGS_IMMUTABLETYPE` flag can now inherit + the :pep:`590` vectorcall protocol. Previously, this was only possible for + :ref:`static types `. + (Contributed by Erlend E. Aasland in :issue:`43908`) + Deprecated ---------- diff --git a/Lib/test/test_call.py b/Lib/test/test_call.py index 3f45922..c929ca8 100644 --- a/Lib/test/test_call.py +++ b/Lib/test/test_call.py @@ -563,7 +563,7 @@ class TestPEP590(unittest.TestCase): self.assertTrue(_testcapi.MethodDescriptorDerived.__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR) self.assertFalse(_testcapi.MethodDescriptorNopGet.__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR) - # Heap type should not inherit Py_TPFLAGS_METHOD_DESCRIPTOR + # Mutable heap types should not inherit Py_TPFLAGS_METHOD_DESCRIPTOR class MethodDescriptorHeap(_testcapi.MethodDescriptorBase): pass self.assertFalse(MethodDescriptorHeap.__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR) @@ -574,7 +574,7 @@ class TestPEP590(unittest.TestCase): self.assertFalse(_testcapi.MethodDescriptorNopGet.__flags__ & Py_TPFLAGS_HAVE_VECTORCALL) self.assertTrue(_testcapi.MethodDescriptor2.__flags__ & Py_TPFLAGS_HAVE_VECTORCALL) - # Heap type should not inherit Py_TPFLAGS_HAVE_VECTORCALL + # Mutable heap types should not inherit Py_TPFLAGS_HAVE_VECTORCALL class MethodDescriptorHeap(_testcapi.MethodDescriptorBase): pass self.assertFalse(MethodDescriptorHeap.__flags__ & Py_TPFLAGS_HAVE_VECTORCALL) diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-07-03-00-20-39.bpo-43908.YHuV_s.rst b/Misc/NEWS.d/next/Core and Builtins/2021-07-03-00-20-39.bpo-43908.YHuV_s.rst new file mode 100644 index 0000000..6113d0f --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2021-07-03-00-20-39.bpo-43908.YHuV_s.rst @@ -0,0 +1,3 @@ +Heap types with the :const:`Py_TPFLAGS_IMMUTABLETYPE` flag can now inherit the +:pep:`590` vectorcall protocol. Previously, this was only possible for +:ref:`static types `. Patch by Erlend E. Aasland. diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 116ac14..02ea618 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -5881,8 +5881,8 @@ inherit_slots(PyTypeObject *type, PyTypeObject *base) /* Inherit Py_TPFLAGS_HAVE_VECTORCALL for non-heap types * if tp_call is not overridden */ if (!type->tp_call && - (base->tp_flags & Py_TPFLAGS_HAVE_VECTORCALL) && - !(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) + _PyType_HasFeature(base, Py_TPFLAGS_HAVE_VECTORCALL) && + _PyType_HasFeature(type, Py_TPFLAGS_IMMUTABLETYPE)) { type->tp_flags |= Py_TPFLAGS_HAVE_VECTORCALL; } @@ -5915,8 +5915,8 @@ inherit_slots(PyTypeObject *type, PyTypeObject *base) * but only for extension types */ if (base->tp_descr_get && type->tp_descr_get == base->tp_descr_get && - !(type->tp_flags & Py_TPFLAGS_HEAPTYPE) && - (base->tp_flags & Py_TPFLAGS_METHOD_DESCRIPTOR)) + _PyType_HasFeature(type, Py_TPFLAGS_IMMUTABLETYPE) && + _PyType_HasFeature(base, Py_TPFLAGS_METHOD_DESCRIPTOR)) { type->tp_flags |= Py_TPFLAGS_METHOD_DESCRIPTOR; } -- cgit v0.12