Skip to content
Merged
17 changes: 9 additions & 8 deletions Doc/c-api/typeobj.rst
Original file line numberDiff line numberDiff line change
Expand Up@@ -710,7 +710,7 @@ and :c:type:`PyType_Type` effectively act as defaults.)

.. warning::

It is not recommended for :ref:`heap types <heap-types>` to implement
It is not recommended for :ref:`mutable heap types <heap-types>` to implement
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: It's non-obvious what "mutable" means. It would be nice to add (in a separated PR) a new "Immutable types" section near https://docs.python.org/dev/c-api/typeobj.html#heap-types to explain the effects of the Py_TPFLAGS_IMMUTABLETYPE flag and explains that static types get this flag automatically.

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. I'll see if I can find time for it. Thanks again for reviewing!

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.
Expand All@@ -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 <vectorcall>`, except when
:c:func:`PyVectorcall_Call` is explicitly called.
This is in particular the case for :ref:`heap types <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
Expand DownExpand Up@@ -1125,9 +1126,9 @@ and :c:type:`PyType_Type` effectively act as defaults.)

**Inheritance:**

This flag is never inherited by :ref:`heap types <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?
Expand DownExpand Up@@ -1172,9 +1173,9 @@ and :c:type:`PyType_Type` effectively act as defaults.)

**Inheritance:**

This bit is inherited for :ref:`static subtypes <static-types>` 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 <heap-types>` do not inherit ``Py_TPFLAGS_HAVE_VECTORCALL``.

.. versionadded:: 3.9

Expand Down
5 changes: 5 additions & 0 deletions Doc/whatsnew/3.11.rst
Original file line numberDiff line numberDiff line change
Expand Up@@ -211,6 +211,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 <static-types>`.
(Contributed by Erlend E. Aasland in :issue:`43908`)

Deprecated
----------

Expand Down
4 changes: 2 additions & 2 deletions Lib/test/test_call.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -563,7 +563,7 @@ def test_method_descriptor_flag(self):
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)
Expand All@@ -574,7 +574,7 @@ def test_vectorcall_flag(self):
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)
Expand Down
Original file line numberDiff line numberDiff line change
@@ -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 <static-types>`. Patch by Erlend E. Aasland.
8 changes: 4 additions & 4 deletions Objects/typeobject.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -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;
}
Expand DownExpand Up@@ -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;
}
Expand Down