From 634568d030f18183212c01bd4544aa7f97e05442 Mon Sep 17 00:00:00 2001 From: Prakash Sellathurai Date: Sat, 18 Apr 2026 05:51:13 +0530 Subject: [PATCH 1/2] gh-148222: Fix NULL dereference bugs in genericaliasobject.c (#148226) --- .../2026-04-07-20-37-23.gh-issue-148222.uF4D4E.rst | 1 + Objects/genericaliasobject.c | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-04-07-20-37-23.gh-issue-148222.uF4D4E.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-04-07-20-37-23.gh-issue-148222.uF4D4E.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-04-07-20-37-23.gh-issue-148222.uF4D4E.rst new file mode 100644 index 00000000000000..2c273fc4daba3d --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-04-07-20-37-23.gh-issue-148222.uF4D4E.rst @@ -0,0 +1 @@ +Fix vectorcall support in :class:`types.GenericAlias` when the underlying type does not support the vectorcall protocol. Fix possible leaks in :class:`types.GenericAlias` and :class:`types.UnionType` in case of memory error. diff --git a/Objects/genericaliasobject.c b/Objects/genericaliasobject.c index 7aef56cf4e93b8..e3bc8eb2739e3f 100644 --- a/Objects/genericaliasobject.c +++ b/Objects/genericaliasobject.c @@ -242,7 +242,6 @@ _Py_make_parameters(PyObject *args) len += needed; if (_PyTuple_Resize(¶meters, len) < 0) { Py_DECREF(subparams); - Py_DECREF(parameters); Py_XDECREF(tuple_args); return NULL; } @@ -650,7 +649,7 @@ ga_vectorcall(PyObject *self, PyObject *const *args, size_t nargsf, PyObject *kwnames) { gaobject *alias = (gaobject *) self; - PyObject *obj = PyVectorcall_Function(alias->origin)(alias->origin, args, nargsf, kwnames); + PyObject *obj = PyObject_Vectorcall(alias->origin, args, nargsf, kwnames); return set_orig_class(obj, self); } From 92164dc91712dcf27e2d526fa6ef8735a8356a36 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Fri, 17 Apr 2026 19:20:41 -0700 Subject: [PATCH 2/2] gh-148639: Implement PEP 800 (typing.disjoint_base) (#148640) Co-authored-by: Victorien <65306057+Viicos@users.noreply.github.com> Co-authored-by: Petr Viktorin --- Doc/library/typing.rst | 30 +++++++++++++++++++ Doc/whatsnew/3.15.rst | 8 +++++ Lib/test/test_typing.py | 14 ++++++++- Lib/typing.py | 24 +++++++++++++++ ...-04-15-20-32-55.gh-issue-148639.-dwsjB.rst | 2 ++ 5 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-04-15-20-32-55.gh-issue-148639.-dwsjB.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 2ce868cf84da9d..9150385bd5888d 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -3358,6 +3358,36 @@ Functions and decorators .. versionadded:: 3.12 +.. decorator:: disjoint_base + + Decorator to mark a class as a disjoint base. + + Type checkers do not allow child classes of a disjoint base ``C`` to + inherit from other disjoint bases that are not parent or child classes of ``C``. + + For example:: + + @disjoint_base + class Disjoint1: pass + + @disjoint_base + class Disjoint2: pass + + class Disjoint3(Disjoint1, Disjoint2): pass # Type checker error + + Type checkers can use knowledge of disjoint bases to detect unreachable code + and determine when two types can overlap. + + The corresponding runtime concept is a solid base (see :ref:`multiple-inheritance`). + Classes that are solid bases at runtime can be marked with ``@disjoint_base`` in stub files. + Users may also mark other classes as disjoint bases to indicate to type checkers that + multiple inheritance with other disjoint bases should not be allowed. + + Note that the concept of a solid base is a CPython implementation + detail, and the exact set of standard library classes that are + disjoint bases at runtime may change in future versions of Python. + + .. versionadded:: next .. decorator:: type_check_only diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 56cc71b40fce82..7cf4dc3701fa6e 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -80,6 +80,7 @@ Summary -- Release highlights * :pep:`728`: ``TypedDict`` with typed extra items * :pep:`747`: :ref:`Annotating type forms with TypeForm ` +* :pep:`800`: Disjoint bases in the type system * :pep:`782`: :ref:`A new PyBytesWriter C API to create a Python bytes object ` * :pep:`803`: :ref:`Stable ABI for Free-Threaded Builds ` @@ -1290,6 +1291,13 @@ typing as it was incorrectly inferred in runtime before. (Contributed by Nikita Sobolev in :gh:`137191`.) +* :pep:`800`: Add :deco:`typing.disjoint_base`, a new decorator marking a class + as a disjoint base. This is an advanced feature primarily intended to allow + type checkers to faithfully reflect the runtime semantics of types defined + as builtins or in compiled extensions. If a class ``C`` is a disjoint base, then + child classes of that class cannot inherit from other disjoint bases that are + not parent or child classes of ``C``. (Contributed by Jelle Zijlstra in :gh:`148639`.) + unicodedata ----------- diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 9c0172f6ba7f23..3fb974c517da7c 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -29,7 +29,7 @@ from typing import assert_type, cast, runtime_checkable from typing import get_type_hints from typing import get_origin, get_args, get_protocol_members -from typing import override +from typing import override, disjoint_base from typing import is_typeddict, is_protocol from typing import reveal_type from typing import dataclass_transform @@ -10920,6 +10920,18 @@ def bar(self): self.assertNotIn('__magic__', dir_items) +class DisjointBaseTests(BaseTestCase): + def test_disjoint_base_unmodified(self): + class C: ... + self.assertIs(C, disjoint_base(C)) + + def test_dunder_disjoint_base(self): + @disjoint_base + class C: ... + + self.assertIs(C.__disjoint_base__, True) + + class RevealTypeTests(BaseTestCase): def test_reveal_type(self): obj = object() diff --git a/Lib/typing.py b/Lib/typing.py index e78fb8b71a996c..868fec9e088cb5 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -126,6 +126,7 @@ 'cast', 'clear_overloads', 'dataclass_transform', + 'disjoint_base', 'evaluate_forward_ref', 'final', 'get_args', @@ -2794,6 +2795,29 @@ class Other(Leaf): # Error reported by type checker return f +def disjoint_base(cls): + """This decorator marks a class as a disjoint base. + + Child classes of a disjoint base cannot inherit from other disjoint bases that are + not parent or child classes of the disjoint base. + + For example: + + @disjoint_base + class Disjoint1: pass + + @disjoint_base + class Disjoint2: pass + + class Disjoint3(Disjoint1, Disjoint2): pass # Type checker error + + Type checkers can use knowledge of disjoint bases to detect unreachable code + and determine when two types can overlap. + """ + cls.__disjoint_base__ = True + return cls + + # Some unconstrained type variables. These were initially used by the container types. # They were never meant for export and are now unused, but we keep them around to # avoid breaking compatibility with users who import them. diff --git a/Misc/NEWS.d/next/Library/2026-04-15-20-32-55.gh-issue-148639.-dwsjB.rst b/Misc/NEWS.d/next/Library/2026-04-15-20-32-55.gh-issue-148639.-dwsjB.rst new file mode 100644 index 00000000000000..d7acdb0983837a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-04-15-20-32-55.gh-issue-148639.-dwsjB.rst @@ -0,0 +1,2 @@ +Implement :pep:`800`, adding the :deco:`typing.disjoint_base` decorator. +Patch by Jelle Zijlstra.