diff options
author | kj <28750310+Fidget-Spinner@users.noreply.github.com> | 2020-12-24 04:33:48 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-12-24 04:33:48 (GMT) |
commit | 73607be68668ab7f4bee53507c8dc7b5a46c9cb4 (patch) | |
tree | 4ec6bb3f178e61b7fc61d979ec65519a4ef1d4bc /Objects/genericaliasobject.c | |
parent | cc3467a57b61b0e7ef254b36790a1c44b13f2228 (diff) | |
download | cpython-73607be68668ab7f4bee53507c8dc7b5a46c9cb4.zip cpython-73607be68668ab7f4bee53507c8dc7b5a46c9cb4.tar.gz cpython-73607be68668ab7f4bee53507c8dc7b5a46c9cb4.tar.bz2 |
bpo-41559: Implement PEP 612 - Add ParamSpec and Concatenate to typing (#23702)
Diffstat (limited to 'Objects/genericaliasobject.c')
-rw-r--r-- | Objects/genericaliasobject.c | 76 |
1 files changed, 62 insertions, 14 deletions
diff --git a/Objects/genericaliasobject.c b/Objects/genericaliasobject.c index 756a7ce..4cc82ff 100644 --- a/Objects/genericaliasobject.c +++ b/Objects/genericaliasobject.c @@ -156,13 +156,24 @@ error: return NULL; } -// isinstance(obj, TypeVar) without importing typing.py. -// Returns -1 for errors. -static int -is_typevar(PyObject *obj) +/* Checks if a variable number of names are from typing.py. +* If any one of the names are found, return 1, else 0. +**/ +static inline int +is_typing_name(PyObject *obj, int num, ...) { + va_list names; + va_start(names, num); + PyTypeObject *type = Py_TYPE(obj); - if (strcmp(type->tp_name, "TypeVar") != 0) { + int hit = 0; + for (int i = 0; i < num; ++i) { + if (!strcmp(type->tp_name, va_arg(names, const char *))) { + hit = 1; + break; + } + } + if (!hit) { return 0; } PyObject *module = PyObject_GetAttrString((PyObject *)type, "__module__"); @@ -172,9 +183,25 @@ is_typevar(PyObject *obj) int res = PyUnicode_Check(module) && _PyUnicode_EqualToASCIIString(module, "typing"); Py_DECREF(module); + + va_end(names); return res; } +// isinstance(obj, (TypeVar, ParamSpec)) without importing typing.py. +// Returns -1 for errors. +static inline int +is_typevarlike(PyObject *obj) +{ + return is_typing_name(obj, 2, "TypeVar", "ParamSpec"); +} + +static inline int +is_paramspec(PyObject *obj) +{ + return is_typing_name(obj, 1, "ParamSpec"); +} + // Index of item in self[:len], or -1 if not found (self is a tuple) static Py_ssize_t tuple_index(PyObject *self, Py_ssize_t len, PyObject *item) @@ -209,7 +236,7 @@ make_parameters(PyObject *args) Py_ssize_t iparam = 0; for (Py_ssize_t iarg = 0; iarg < nargs; iarg++) { PyObject *t = PyTuple_GET_ITEM(args, iarg); - int typevar = is_typevar(t); + int typevar = is_typevarlike(t); if (typevar < 0) { Py_DECREF(parameters); return NULL; @@ -279,7 +306,14 @@ subs_tvars(PyObject *obj, PyObject *params, PyObject **argitems) if (iparam >= 0) { arg = argitems[iparam]; } - Py_INCREF(arg); + // convert all the lists inside args to tuples to help + // with caching in other libaries + if (PyList_CheckExact(arg)) { + arg = PyList_AsTuple(arg); + } + else { + Py_INCREF(arg); + } PyTuple_SET_ITEM(subargs, i, arg); } @@ -314,11 +348,19 @@ ga_getitem(PyObject *self, PyObject *item) int is_tuple = PyTuple_Check(item); Py_ssize_t nitems = is_tuple ? PyTuple_GET_SIZE(item) : 1; PyObject **argitems = is_tuple ? &PyTuple_GET_ITEM(item, 0) : &item; - if (nitems != nparams) { - return PyErr_Format(PyExc_TypeError, - "Too %s arguments for %R", - nitems > nparams ? "many" : "few", - self); + // A special case in PEP 612 where if X = Callable[P, int], + // then X[int, str] == X[[int, str]]. + if (nparams == 1 && nitems > 1 && is_tuple && + is_paramspec(PyTuple_GET_ITEM(alias->parameters, 0))) { + argitems = &item; + } + else { + if (nitems != nparams) { + return PyErr_Format(PyExc_TypeError, + "Too %s arguments for %R", + nitems > nparams ? "many" : "few", + self); + } } /* Replace all type variables (specified by alias->parameters) with corresponding values specified by argitems. @@ -333,7 +375,7 @@ ga_getitem(PyObject *self, PyObject *item) } for (Py_ssize_t iarg = 0; iarg < nargs; iarg++) { PyObject *arg = PyTuple_GET_ITEM(alias->args, iarg); - int typevar = is_typevar(arg); + int typevar = is_typevarlike(arg); if (typevar < 0) { Py_DECREF(newargs); return NULL; @@ -342,7 +384,13 @@ ga_getitem(PyObject *self, PyObject *item) Py_ssize_t iparam = tuple_index(alias->parameters, nparams, arg); assert(iparam >= 0); arg = argitems[iparam]; - Py_INCREF(arg); + // convert lists to tuples to help with caching in other libaries. + if (PyList_CheckExact(arg)) { + arg = PyList_AsTuple(arg); + } + else { + Py_INCREF(arg); + } } else { arg = subs_tvars(arg, alias->parameters, argitems); |