diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 106ffdede6fd4ef..f99e8f12e941561 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -6053,6 +6053,22 @@ class A: with self.assertRaises(TypeError): a[int] + def test_parameter_added_after_parameters_cached(self): + # gh-155752: GenericAlias parameters are cached before substitution, so + # an argument can gain __typing_subst__ after the tuple is calculated. + class Parameter: + pass + + first = Parameter() + first.__typing_subst__ = lambda value: value + late = Parameter() + alias = types.GenericAlias(dict, (first, late)) + self.assertEqual(alias.__parameters__, (first,)) + late.__typing_subst__ = lambda value: value + + with self.assertRaisesRegex(TypeError, "not found in __parameters__"): + alias[0] + def test_return_non_tuple_while_unpacking(self): # GH-138497: GenericAlias objects didn't ensure that __typing_subst__ actually # returned a tuple diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-08-13-13-50-00.gh-issue-155752.Rp7K2x.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-08-13-13-50-00.gh-issue-155752.Rp7K2x.rst new file mode 100644 index 000000000000000..300e97ad5d257bc --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-08-13-13-50-00.gh-issue-155752.Rp7K2x.rst @@ -0,0 +1,2 @@ +Fix a crash when a :class:`types.GenericAlias` argument gains a +``__typing_subst__`` hook after the alias parameters have been cached. diff --git a/Objects/genericaliasobject.c b/Objects/genericaliasobject.c index 71d946a637df1c9..9c3ecd7a453c152 100644 --- a/Objects/genericaliasobject.c +++ b/Objects/genericaliasobject.c @@ -524,8 +524,18 @@ _Py_subs_parameters(PyObject *self, PyObject *args, PyObject *parameters, PyObje } if (subst) { Py_ssize_t iparam = tuple_index(parameters, nparams, arg); - assert(iparam >= 0); - arg = PyObject_CallOneArg(subst, argitems[iparam]); + if (iparam < 0) { + // __parameters__ may be stale if an argument gained + // __typing_subst__ after the tuple was computed. + PyErr_Format(PyExc_TypeError, + "argument %R with __typing_subst__ was not found " + "in __parameters__", + arg); + arg = NULL; + } + else { + arg = PyObject_CallOneArg(subst, argitems[iparam]); + } Py_DECREF(subst); } else {