summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorsobolevn <mail@sobolevn.me>2024-10-11 14:39:18 (GMT)
committerGitHub <noreply@github.com>2024-10-11 14:39:18 (GMT)
commit2115d76acc14effb3dbb9fedcf21048b2ad62c5e (patch)
tree9d7477942b22a8517348cc9f27759eef3ade28d0 /Objects
parentb3aa1b5fe260382788a2df416599325ad680a5ee (diff)
downloadcpython-2115d76acc14effb3dbb9fedcf21048b2ad62c5e.zip
cpython-2115d76acc14effb3dbb9fedcf21048b2ad62c5e.tar.gz
cpython-2115d76acc14effb3dbb9fedcf21048b2ad62c5e.tar.bz2
gh-124787: Fix `TypeAliasType` and incorrect `type_params` (#124795)
Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
Diffstat (limited to 'Objects')
-rw-r--r--Objects/typevarobject.c97
1 files changed, 86 insertions, 11 deletions
diff --git a/Objects/typevarobject.c b/Objects/typevarobject.c
index 51d93ed..91cc37c 100644
--- a/Objects/typevarobject.c
+++ b/Objects/typevarobject.c
@@ -1799,6 +1799,24 @@ _Py_make_typevartuple(PyThreadState *Py_UNUSED(ignored), PyObject *v)
return (PyObject *)typevartuple_alloc(v, NULL, NULL);
}
+static PyObject *
+get_type_param_default(PyThreadState *ts, PyObject *typeparam) {
+ // Does not modify refcount of existing objects.
+ if (Py_IS_TYPE(typeparam, ts->interp->cached_objects.typevar_type)) {
+ return typevar_default((typevarobject *)typeparam, NULL);
+ }
+ else if (Py_IS_TYPE(typeparam, ts->interp->cached_objects.paramspec_type)) {
+ return paramspec_default((paramspecobject *)typeparam, NULL);
+ }
+ else if (Py_IS_TYPE(typeparam, ts->interp->cached_objects.typevartuple_type)) {
+ return typevartuple_default((typevartupleobject *)typeparam, NULL);
+ }
+ else {
+ PyErr_Format(PyExc_TypeError, "Expected a type param, got %R", typeparam);
+ return NULL;
+ }
+}
+
static void
typealias_dealloc(PyObject *self)
{
@@ -1906,25 +1924,75 @@ static PyGetSetDef typealias_getset[] = {
{0}
};
-static typealiasobject *
-typealias_alloc(PyObject *name, PyObject *type_params, PyObject *compute_value,
- PyObject *value, PyObject *module)
-{
- typealiasobject *ta = PyObject_GC_New(typealiasobject, &_PyTypeAlias_Type);
- if (ta == NULL) {
+static PyObject *
+typealias_check_type_params(PyObject *type_params, int *err) {
+ // Can return type_params or NULL without exception set.
+ // Does not change the reference count of type_params,
+ // sets `*err` to 1 when error happens and sets an exception,
+ // otherwise `*err` is set to 0.
+ *err = 0;
+ if (type_params == NULL) {
return NULL;
}
- ta->name = Py_NewRef(name);
+
+ assert(PyTuple_Check(type_params));
+ Py_ssize_t length = PyTuple_GET_SIZE(type_params);
+ if (!length) { // 0-length tuples are the same as `NULL`.
+ return NULL;
+ }
+
+ PyThreadState *ts = _PyThreadState_GET();
+ int default_seen = 0;
+ for (Py_ssize_t index = 0; index < length; index++) {
+ PyObject *type_param = PyTuple_GET_ITEM(type_params, index);
+ PyObject *dflt = get_type_param_default(ts, type_param);
+ if (dflt == NULL) {
+ *err = 1;
+ return NULL;
+ }
+ if (dflt == &_Py_NoDefaultStruct) {
+ if (default_seen) {
+ *err = 1;
+ PyErr_Format(PyExc_TypeError,
+ "non-default type parameter '%R' "
+ "follows default type parameter",
+ type_param);
+ return NULL;
+ }
+ } else {
+ default_seen = 1;
+ Py_DECREF(dflt);
+ }
+ }
+
+ return type_params;
+}
+
+static PyObject *
+typelias_convert_type_params(PyObject *type_params)
+{
if (
type_params == NULL
|| Py_IsNone(type_params)
|| (PyTuple_Check(type_params) && PyTuple_GET_SIZE(type_params) == 0)
) {
- ta->type_params = NULL;
+ return NULL;
}
else {
- ta->type_params = Py_NewRef(type_params);
+ return type_params;
}
+}
+
+static typealiasobject *
+typealias_alloc(PyObject *name, PyObject *type_params, PyObject *compute_value,
+ PyObject *value, PyObject *module)
+{
+ typealiasobject *ta = PyObject_GC_New(typealiasobject, &_PyTypeAlias_Type);
+ if (ta == NULL) {
+ return NULL;
+ }
+ ta->name = Py_NewRef(name);
+ ta->type_params = Py_XNewRef(type_params);
ta->compute_value = Py_XNewRef(compute_value);
ta->value = Py_XNewRef(value);
ta->module = Py_XNewRef(module);
@@ -2002,11 +2070,18 @@ typealias_new_impl(PyTypeObject *type, PyObject *name, PyObject *value,
PyErr_SetString(PyExc_TypeError, "type_params must be a tuple");
return NULL;
}
+
+ int err = 0;
+ PyObject *checked_params = typealias_check_type_params(type_params, &err);
+ if (err) {
+ return NULL;
+ }
+
PyObject *module = caller();
if (module == NULL) {
return NULL;
}
- PyObject *ta = (PyObject *)typealias_alloc(name, type_params, NULL, value,
+ PyObject *ta = (PyObject *)typealias_alloc(name, checked_params, NULL, value,
module);
Py_DECREF(module);
return ta;
@@ -2072,7 +2147,7 @@ _Py_make_typealias(PyThreadState* unused, PyObject *args)
assert(PyTuple_GET_SIZE(args) == 3);
PyObject *name = PyTuple_GET_ITEM(args, 0);
assert(PyUnicode_Check(name));
- PyObject *type_params = PyTuple_GET_ITEM(args, 1);
+ PyObject *type_params = typelias_convert_type_params(PyTuple_GET_ITEM(args, 1));
PyObject *compute_value = PyTuple_GET_ITEM(args, 2);
assert(PyFunction_Check(compute_value));
return (PyObject *)typealias_alloc(name, type_params, compute_value, NULL, NULL);