LCOV - code coverage report
Current view: top level - Objects - genericaliasobject.c (source / functions) Hit Total Coverage
Test: CPython lcov report Lines: 398 481 82.7 %
Date: 2022-07-07 18:19:46 Functions: 35 36 97.2 %

          Line data    Source code
       1             : // types.GenericAlias -- used to represent e.g. list[int].
       2             : 
       3             : #include "Python.h"
       4             : #include "pycore_object.h"
       5             : #include "pycore_unionobject.h"   // _Py_union_type_or, _PyGenericAlias_Check
       6             : #include "structmember.h"         // PyMemberDef
       7             : 
       8             : #include <stdbool.h>
       9             : 
      10             : typedef struct {
      11             :     PyObject_HEAD
      12             :     PyObject *origin;
      13             :     PyObject *args;
      14             :     PyObject *parameters;
      15             :     PyObject *weakreflist;
      16             :     // Whether we're a starred type, e.g. *tuple[int].
      17             :     bool starred;
      18             :     vectorcallfunc vectorcall;
      19             : } gaobject;
      20             : 
      21             : typedef struct {
      22             :     PyObject_HEAD
      23             :     PyObject *obj;  /* Set to NULL when iterator is exhausted */
      24             : } gaiterobject;
      25             : 
      26             : static void
      27       22948 : ga_dealloc(PyObject *self)
      28             : {
      29       22948 :     gaobject *alias = (gaobject *)self;
      30             : 
      31       22948 :     _PyObject_GC_UNTRACK(self);
      32       22948 :     if (alias->weakreflist != NULL) {
      33           0 :         PyObject_ClearWeakRefs((PyObject *)alias);
      34             :     }
      35       22948 :     Py_XDECREF(alias->origin);
      36       22948 :     Py_XDECREF(alias->args);
      37       22948 :     Py_XDECREF(alias->parameters);
      38       22948 :     Py_TYPE(self)->tp_free(self);
      39       22948 : }
      40             : 
      41             : static int
      42      608130 : ga_traverse(PyObject *self, visitproc visit, void *arg)
      43             : {
      44      608130 :     gaobject *alias = (gaobject *)self;
      45      608130 :     Py_VISIT(alias->origin);
      46      608130 :     Py_VISIT(alias->args);
      47      608130 :     Py_VISIT(alias->parameters);
      48      608130 :     return 0;
      49             : }
      50             : 
      51             : static int
      52         350 : ga_repr_item(_PyUnicodeWriter *writer, PyObject *p)
      53             : {
      54         350 :     PyObject *qualname = NULL;
      55         350 :     PyObject *module = NULL;
      56         350 :     PyObject *r = NULL;
      57             :     PyObject *tmp;
      58             :     int err;
      59             : 
      60         350 :     if (p == Py_Ellipsis) {
      61             :         // The Ellipsis object
      62          37 :         r = PyUnicode_FromString("...");
      63          37 :         goto done;
      64             :     }
      65             : 
      66         313 :     if (_PyObject_LookupAttr(p, &_Py_ID(__origin__), &tmp) < 0) {
      67           0 :         goto done;
      68             :     }
      69         313 :     if (tmp != NULL) {
      70          15 :         Py_DECREF(tmp);
      71          15 :         if (_PyObject_LookupAttr(p, &_Py_ID(__args__), &tmp) < 0) {
      72           0 :             goto done;
      73             :         }
      74          15 :         if (tmp != NULL) {
      75          15 :             Py_DECREF(tmp);
      76             :             // It looks like a GenericAlias
      77          15 :             goto use_repr;
      78             :         }
      79             :     }
      80             : 
      81         298 :     if (_PyObject_LookupAttr(p, &_Py_ID(__qualname__), &qualname) < 0) {
      82           0 :         goto done;
      83             :     }
      84         298 :     if (qualname == NULL) {
      85          72 :         goto use_repr;
      86             :     }
      87         226 :     if (_PyObject_LookupAttr(p, &_Py_ID(__module__), &module) < 0) {
      88           0 :         goto done;
      89             :     }
      90         226 :     if (module == NULL || module == Py_None) {
      91           0 :         goto use_repr;
      92             :     }
      93             : 
      94             :     // Looks like a class
      95         452 :     if (PyUnicode_Check(module) &&
      96         226 :         _PyUnicode_EqualToASCIIString(module, "builtins"))
      97             :     {
      98             :         // builtins don't need a module name
      99         210 :         r = PyObject_Str(qualname);
     100         210 :         goto done;
     101             :     }
     102             :     else {
     103          16 :         r = PyUnicode_FromFormat("%S.%S", module, qualname);
     104          16 :         goto done;
     105             :     }
     106             : 
     107          87 : use_repr:
     108          87 :     r = PyObject_Repr(p);
     109             : 
     110         350 : done:
     111         350 :     Py_XDECREF(qualname);
     112         350 :     Py_XDECREF(module);
     113         350 :     if (r == NULL) {
     114             :         // error if any of the above PyObject_Repr/PyUnicode_From* fail
     115           0 :         err = -1;
     116             :     }
     117             :     else {
     118         350 :         err = _PyUnicodeWriter_WriteStr(writer, r);
     119         350 :         Py_DECREF(r);
     120             :     }
     121         350 :     return err;
     122             : }
     123             : 
     124             : static PyObject *
     125         136 : ga_repr(PyObject *self)
     126             : {
     127         136 :     gaobject *alias = (gaobject *)self;
     128         136 :     Py_ssize_t len = PyTuple_GET_SIZE(alias->args);
     129             : 
     130             :     _PyUnicodeWriter writer;
     131         136 :     _PyUnicodeWriter_Init(&writer);
     132             : 
     133         136 :     if (alias->starred) {
     134          29 :         if (_PyUnicodeWriter_WriteASCIIString(&writer, "*", 1) < 0) {
     135           0 :             goto error;
     136             :         }
     137             :     }
     138         136 :     if (ga_repr_item(&writer, alias->origin) < 0) {
     139           0 :         goto error;
     140             :     }
     141         136 :     if (_PyUnicodeWriter_WriteASCIIString(&writer, "[", 1) < 0) {
     142           0 :         goto error;
     143             :     }
     144         350 :     for (Py_ssize_t i = 0; i < len; i++) {
     145         214 :         if (i > 0) {
     146          79 :             if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ", 2) < 0) {
     147           0 :                 goto error;
     148             :             }
     149             :         }
     150         214 :         PyObject *p = PyTuple_GET_ITEM(alias->args, i);
     151         214 :         if (ga_repr_item(&writer, p) < 0) {
     152           0 :             goto error;
     153             :         }
     154             :     }
     155         136 :     if (len == 0) {
     156             :         // for something like tuple[()] we should print a "()"
     157           1 :         if (_PyUnicodeWriter_WriteASCIIString(&writer, "()", 2) < 0) {
     158           0 :             goto error;
     159             :         }
     160             :     }
     161         136 :     if (_PyUnicodeWriter_WriteASCIIString(&writer, "]", 1) < 0) {
     162           0 :         goto error;
     163             :     }
     164         136 :     return _PyUnicodeWriter_Finish(&writer);
     165           0 : error:
     166           0 :     _PyUnicodeWriter_Dealloc(&writer);
     167           0 :     return NULL;
     168             : }
     169             : 
     170             : // Index of item in self[:len], or -1 if not found (self is a tuple)
     171             : static Py_ssize_t
     172         812 : tuple_index(PyObject *self, Py_ssize_t len, PyObject *item)
     173             : {
     174        1042 :     for (Py_ssize_t i = 0; i < len; i++) {
     175         576 :         if (PyTuple_GET_ITEM(self, i) == item) {
     176         346 :             return i;
     177             :         }
     178             :     }
     179         466 :     return -1;
     180             : }
     181             : 
     182             : static int
     183         471 : tuple_add(PyObject *self, Py_ssize_t len, PyObject *item)
     184             : {
     185         471 :     if (tuple_index(self, len, item) < 0) {
     186         466 :         Py_INCREF(item);
     187         466 :         PyTuple_SET_ITEM(self, len, item);
     188         466 :         return 1;
     189             :     }
     190           5 :     return 0;
     191             : }
     192             : 
     193             : static Py_ssize_t
     194         134 : tuple_extend(PyObject **dst, Py_ssize_t dstindex,
     195             :              PyObject **src, Py_ssize_t count)
     196             : {
     197         134 :     assert(count >= 0);
     198         134 :     if (_PyTuple_Resize(dst, PyTuple_GET_SIZE(*dst) + count - 1) != 0) {
     199           0 :         return -1;
     200             :     }
     201         134 :     assert(dstindex + count <= PyTuple_GET_SIZE(*dst));
     202         306 :     for (Py_ssize_t i = 0; i < count; ++i) {
     203         172 :         PyObject *item = src[i];
     204         172 :         Py_INCREF(item);
     205         172 :         PyTuple_SET_ITEM(*dst, dstindex + i, item);
     206             :     }
     207         134 :     return dstindex + count;
     208             : }
     209             : 
     210             : PyObject *
     211        1762 : _Py_make_parameters(PyObject *args)
     212             : {
     213        1762 :     Py_ssize_t nargs = PyTuple_GET_SIZE(args);
     214        1762 :     Py_ssize_t len = nargs;
     215        1762 :     PyObject *parameters = PyTuple_New(len);
     216        1762 :     if (parameters == NULL)
     217           0 :         return NULL;
     218        1762 :     Py_ssize_t iparam = 0;
     219        3994 :     for (Py_ssize_t iarg = 0; iarg < nargs; iarg++) {
     220        2232 :         PyObject *t = PyTuple_GET_ITEM(args, iarg);
     221             :         PyObject *subst;
     222        2232 :         if (_PyObject_LookupAttr(t, &_Py_ID(__typing_subst__), &subst) < 0) {
     223           0 :             Py_DECREF(parameters);
     224           0 :             return NULL;
     225             :         }
     226        2232 :         if (subst) {
     227         309 :             iparam += tuple_add(parameters, iparam, t);
     228         309 :             Py_DECREF(subst);
     229             :         }
     230             :         else {
     231             :             PyObject *subparams;
     232        1923 :             if (_PyObject_LookupAttr(t, &_Py_ID(__parameters__),
     233             :                                      &subparams) < 0) {
     234           0 :                 Py_DECREF(parameters);
     235           0 :                 return NULL;
     236             :             }
     237        1923 :             if (subparams && PyTuple_Check(subparams)) {
     238         302 :                 Py_ssize_t len2 = PyTuple_GET_SIZE(subparams);
     239         302 :                 Py_ssize_t needed = len2 - 1 - (iarg - iparam);
     240         302 :                 if (needed > 0) {
     241          11 :                     len += needed;
     242          11 :                     if (_PyTuple_Resize(&parameters, len) < 0) {
     243           0 :                         Py_DECREF(subparams);
     244           0 :                         Py_DECREF(parameters);
     245           0 :                         return NULL;
     246             :                     }
     247             :                 }
     248         464 :                 for (Py_ssize_t j = 0; j < len2; j++) {
     249         162 :                     PyObject *t2 = PyTuple_GET_ITEM(subparams, j);
     250         162 :                     iparam += tuple_add(parameters, iparam, t2);
     251             :                 }
     252             :             }
     253        1923 :             Py_XDECREF(subparams);
     254             :         }
     255             :     }
     256        1762 :     if (iparam < len) {
     257        1502 :         if (_PyTuple_Resize(&parameters, iparam) < 0) {
     258           0 :             Py_XDECREF(parameters);
     259           0 :             return NULL;
     260             :         }
     261             :     }
     262        1762 :     return parameters;
     263             : }
     264             : 
     265             : /* If obj is a generic alias, substitute type variables params
     266             :    with substitutions argitems.  For example, if obj is list[T],
     267             :    params is (T, S), and argitems is (str, int), return list[str].
     268             :    If obj doesn't have a __parameters__ attribute or that's not
     269             :    a non-empty tuple, return a new reference to obj. */
     270             : static PyObject *
     271         176 : subs_tvars(PyObject *obj, PyObject *params,
     272             :            PyObject **argitems, Py_ssize_t nargs)
     273             : {
     274             :     PyObject *subparams;
     275         176 :     if (_PyObject_LookupAttr(obj, &_Py_ID(__parameters__), &subparams) < 0) {
     276           0 :         return NULL;
     277             :     }
     278         293 :     if (subparams && PyTuple_Check(subparams) && PyTuple_GET_SIZE(subparams)) {
     279         117 :         Py_ssize_t nparams = PyTuple_GET_SIZE(params);
     280         117 :         Py_ssize_t nsubargs = PyTuple_GET_SIZE(subparams);
     281         117 :         PyObject *subargs = PyTuple_New(nsubargs);
     282         117 :         if (subargs == NULL) {
     283           0 :             Py_DECREF(subparams);
     284           0 :             return NULL;
     285             :         }
     286         117 :         Py_ssize_t j = 0;
     287         242 :         for (Py_ssize_t i = 0; i < nsubargs; ++i) {
     288         125 :             PyObject *arg = PyTuple_GET_ITEM(subparams, i);
     289         125 :             Py_ssize_t iparam = tuple_index(params, nparams, arg);
     290         125 :             if (iparam >= 0) {
     291         125 :                 PyObject *param = PyTuple_GET_ITEM(params, iparam);
     292         125 :                 arg = argitems[iparam];
     293         125 :                 if (Py_TYPE(param)->tp_iter && PyTuple_Check(arg)) {  // TypeVarTuple
     294         144 :                     j = tuple_extend(&subargs, j,
     295          72 :                                     &PyTuple_GET_ITEM(arg, 0),
     296             :                                     PyTuple_GET_SIZE(arg));
     297          72 :                     if (j < 0) {
     298           0 :                         return NULL;
     299             :                     }
     300          72 :                     continue;
     301             :                 }
     302             :             }
     303          53 :             Py_INCREF(arg);
     304          53 :             PyTuple_SET_ITEM(subargs, j, arg);
     305          53 :             j++;
     306             :         }
     307         117 :         assert(j == PyTuple_GET_SIZE(subargs));
     308             : 
     309         117 :         obj = PyObject_GetItem(obj, subargs);
     310             : 
     311         117 :         Py_DECREF(subargs);
     312             :     }
     313             :     else {
     314          59 :         Py_INCREF(obj);
     315             :     }
     316         176 :     Py_XDECREF(subparams);
     317         176 :     return obj;
     318             : }
     319             : 
     320             : static int
     321         392 : _is_unpacked_typevartuple(PyObject *arg)
     322             : {
     323             :     PyObject *tmp;
     324         392 :     if (PyType_Check(arg)) { // TODO: Add test
     325          33 :         return 0;
     326             :     }
     327         359 :     int res = _PyObject_LookupAttr(arg, &_Py_ID(__typing_is_unpacked_typevartuple__), &tmp);
     328         359 :     if (res > 0) {
     329          71 :         res = PyObject_IsTrue(tmp);
     330          71 :         Py_DECREF(tmp);
     331             :     }
     332         359 :     return res;
     333             : }
     334             : 
     335             : static PyObject *
     336         165 : _unpacked_tuple_args(PyObject *arg)
     337             : {
     338             :     PyObject *result;
     339         165 :     assert(!PyType_Check(arg));
     340             :     // Fast path
     341         165 :     if (_PyGenericAlias_Check(arg) &&
     342          51 :             ((gaobject *)arg)->starred &&
     343          44 :             ((gaobject *)arg)->origin == (PyObject *)&PyTuple_Type)
     344             :     {
     345          44 :         result = ((gaobject *)arg)->args;
     346          44 :         Py_INCREF(result);
     347          44 :         return result;
     348             :     }
     349             : 
     350         121 :     if (_PyObject_LookupAttr(arg, &_Py_ID(__typing_unpacked_tuple_args__), &result) > 0) {
     351          61 :         if (result == Py_None) {
     352          17 :             Py_DECREF(result);
     353          17 :             return NULL;
     354             :         }
     355          44 :         return result;
     356             :     }
     357          60 :     return NULL;
     358             : }
     359             : 
     360             : static PyObject *
     361         283 : _unpack_args(PyObject *item)
     362             : {
     363         283 :     PyObject *newargs = PyList_New(0);
     364         283 :     if (newargs == NULL) {
     365           0 :         return NULL;
     366             :     }
     367         283 :     int is_tuple = PyTuple_Check(item);
     368         283 :     Py_ssize_t nitems = is_tuple ? PyTuple_GET_SIZE(item) : 1;
     369         283 :     PyObject **argitems = is_tuple ? &PyTuple_GET_ITEM(item, 0) : &item;
     370         698 :     for (Py_ssize_t i = 0; i < nitems; i++) {
     371         415 :         item = argitems[i];
     372         415 :         if (!PyType_Check(item)) {
     373         165 :             PyObject *subargs = _unpacked_tuple_args(item);
     374         253 :             if (subargs != NULL &&
     375         176 :                 PyTuple_Check(subargs) &&
     376          88 :                 !(PyTuple_GET_SIZE(subargs) &&
     377          78 :                   PyTuple_GET_ITEM(subargs, PyTuple_GET_SIZE(subargs)-1) == Py_Ellipsis))
     378             :             {
     379          54 :                 if (PyList_SetSlice(newargs, PY_SSIZE_T_MAX, PY_SSIZE_T_MAX, subargs) < 0) {
     380           0 :                     Py_DECREF(subargs);
     381           0 :                     Py_DECREF(newargs);
     382           0 :                     return NULL;
     383             :                 }
     384          54 :                 Py_DECREF(subargs);
     385          54 :                 continue;
     386             :             }
     387         111 :             Py_XDECREF(subargs);
     388         111 :             if (PyErr_Occurred()) {
     389           0 :                 Py_DECREF(newargs);
     390           0 :                 return NULL;
     391             :             }
     392             :         }
     393         361 :         if (PyList_Append(newargs, item) < 0) {
     394           0 :             Py_DECREF(newargs);
     395           0 :             return NULL;
     396             :         }
     397             :     }
     398         283 :     Py_SETREF(newargs, PySequence_Tuple(newargs));
     399         283 :     return newargs;
     400             : }
     401             : 
     402             : PyObject *
     403         286 : _Py_subs_parameters(PyObject *self, PyObject *args, PyObject *parameters, PyObject *item)
     404             : {
     405         286 :     Py_ssize_t nparams = PyTuple_GET_SIZE(parameters);
     406         286 :     if (nparams == 0) {
     407           3 :         return PyErr_Format(PyExc_TypeError,
     408             :                             "%R is not a generic class",
     409             :                             self);
     410             :     }
     411         283 :     item = _unpack_args(item);
     412         694 :     for (Py_ssize_t i = 0; i < nparams; i++) {
     413         417 :         PyObject *param = PyTuple_GET_ITEM(parameters, i);
     414             :         PyObject *prepare, *tmp;
     415         417 :         if (_PyObject_LookupAttr(param, &_Py_ID(__typing_prepare_subst__), &prepare) < 0) {
     416           0 :             Py_DECREF(item);
     417           6 :             return NULL;
     418             :         }
     419         417 :         if (prepare && prepare != Py_None) {
     420         116 :             if (PyTuple_Check(item)) {
     421         116 :                 tmp = PyObject_CallFunction(prepare, "OO", self, item);
     422             :             }
     423             :             else {
     424           0 :                 tmp = PyObject_CallFunction(prepare, "O(O)", self, item);
     425             :             }
     426         116 :             Py_DECREF(prepare);
     427         116 :             Py_SETREF(item, tmp);
     428         116 :             if (item == NULL) {
     429           6 :                 return NULL;
     430             :             }
     431             :         }
     432             :     }
     433         277 :     int is_tuple = PyTuple_Check(item);
     434         277 :     Py_ssize_t nitems = is_tuple ? PyTuple_GET_SIZE(item) : 1;
     435         277 :     PyObject **argitems = is_tuple ? &PyTuple_GET_ITEM(item, 0) : &item;
     436         277 :     if (nitems != nparams) {
     437          35 :         Py_DECREF(item);
     438          35 :         return PyErr_Format(PyExc_TypeError,
     439             :                             "Too %s arguments for %R; actual %zd, expected %zd",
     440             :                             nitems > nparams ? "many" : "few",
     441             :                             self, nitems, nparams);
     442             :     }
     443             :     /* Replace all type variables (specified by parameters)
     444             :        with corresponding values specified by argitems.
     445             :         t = list[T];          t[int]      -> newargs = [int]
     446             :         t = dict[str, T];     t[int]      -> newargs = [str, int]
     447             :         t = dict[T, list[S]]; t[str, int] -> newargs = [str, list[int]]
     448             :      */
     449         242 :     Py_ssize_t nargs = PyTuple_GET_SIZE(args);
     450         242 :     PyObject *newargs = PyTuple_New(nargs);
     451         242 :     if (newargs == NULL) {
     452           0 :         Py_DECREF(item);
     453           0 :         return NULL;
     454             :     }
     455         606 :     for (Py_ssize_t iarg = 0, jarg = 0; iarg < nargs; iarg++) {
     456         392 :         PyObject *arg = PyTuple_GET_ITEM(args, iarg);
     457         392 :         int unpack = _is_unpacked_typevartuple(arg);
     458         392 :         if (unpack < 0) {
     459           0 :             Py_DECREF(newargs);
     460           0 :             Py_DECREF(item);
     461          28 :             return NULL;
     462             :         }
     463             :         PyObject *subst;
     464         392 :         if (_PyObject_LookupAttr(arg, &_Py_ID(__typing_subst__), &subst) < 0) {
     465           0 :             Py_DECREF(newargs);
     466           0 :             Py_DECREF(item);
     467           0 :             return NULL;
     468             :         }
     469         392 :         if (subst) {
     470         216 :             Py_ssize_t iparam = tuple_index(parameters, nparams, arg);
     471         216 :             assert(iparam >= 0);
     472         216 :             arg = PyObject_CallOneArg(subst, argitems[iparam]);
     473         216 :             Py_DECREF(subst);
     474             :         }
     475             :         else {
     476         176 :             arg = subs_tvars(arg, parameters, argitems, nitems);
     477             :         }
     478         392 :         if (arg == NULL) {
     479          28 :             Py_DECREF(newargs);
     480          28 :             Py_DECREF(item);
     481          28 :             return NULL;
     482             :         }
     483         364 :         if (unpack) {
     484         124 :             jarg = tuple_extend(&newargs, jarg,
     485          62 :                     &PyTuple_GET_ITEM(arg, 0), PyTuple_GET_SIZE(arg));
     486          62 :             Py_DECREF(arg);
     487          62 :             if (jarg < 0) {
     488           0 :                 Py_DECREF(item);
     489           0 :                 return NULL;
     490             :             }
     491             :         }
     492             :         else {
     493         302 :             PyTuple_SET_ITEM(newargs, jarg, arg);
     494         302 :             jarg++;
     495             :         }
     496             :     }
     497             : 
     498         214 :     Py_DECREF(item);
     499         214 :     return newargs;
     500             : }
     501             : 
     502             : PyDoc_STRVAR(genericalias__doc__,
     503             : "Represent a PEP 585 generic type\n"
     504             : "\n"
     505             : "E.g. for t = list[int], t.__origin__ is list and t.__args__ is (int,).");
     506             : 
     507             : static PyObject *
     508         281 : ga_getitem(PyObject *self, PyObject *item)
     509             : {
     510         281 :     gaobject *alias = (gaobject *)self;
     511             :     // Populate __parameters__ if needed.
     512         281 :     if (alias->parameters == NULL) {
     513         162 :         alias->parameters = _Py_make_parameters(alias->args);
     514         162 :         if (alias->parameters == NULL) {
     515           0 :             return NULL;
     516             :         }
     517             :     }
     518             : 
     519         281 :     PyObject *newargs = _Py_subs_parameters(self, alias->args, alias->parameters, item);
     520         281 :     if (newargs == NULL) {
     521          72 :         return NULL;
     522             :     }
     523             : 
     524         209 :     PyObject *res = Py_GenericAlias(alias->origin, newargs);
     525         209 :     ((gaobject *)res)->starred = alias->starred;
     526             : 
     527         209 :     Py_DECREF(newargs);
     528         209 :     return res;
     529             : }
     530             : 
     531             : static PyMappingMethods ga_as_mapping = {
     532             :     .mp_subscript = ga_getitem,
     533             : };
     534             : 
     535             : static Py_hash_t
     536        2429 : ga_hash(PyObject *self)
     537             : {
     538        2429 :     gaobject *alias = (gaobject *)self;
     539             :     // TODO: Hash in the hash for the origin
     540        2429 :     Py_hash_t h0 = PyObject_Hash(alias->origin);
     541        2429 :     if (h0 == -1) {
     542           0 :         return -1;
     543             :     }
     544        2429 :     Py_hash_t h1 = PyObject_Hash(alias->args);
     545        2429 :     if (h1 == -1) {
     546           0 :         return -1;
     547             :     }
     548        2429 :     return h0 ^ h1;
     549             : }
     550             : 
     551             : static inline PyObject *
     552          43 : set_orig_class(PyObject *obj, PyObject *self)
     553             : {
     554          43 :     if (obj != NULL) {
     555          42 :         if (PyObject_SetAttr(obj, &_Py_ID(__orig_class__), self) < 0) {
     556          22 :             if (!PyErr_ExceptionMatches(PyExc_AttributeError) &&
     557           1 :                 !PyErr_ExceptionMatches(PyExc_TypeError))
     558             :             {
     559           0 :                 Py_DECREF(obj);
     560           0 :                 return NULL;
     561             :             }
     562          21 :             PyErr_Clear();
     563             :         }
     564             :     }
     565          43 :     return obj;
     566             : }
     567             : 
     568             : static PyObject *
     569          27 : ga_call(PyObject *self, PyObject *args, PyObject *kwds)
     570             : {
     571          27 :     gaobject *alias = (gaobject *)self;
     572          27 :     PyObject *obj = PyObject_Call(alias->origin, args, kwds);
     573          27 :     return set_orig_class(obj, self);
     574             : }
     575             : 
     576             : static PyObject *
     577          16 : ga_vectorcall(PyObject *self, PyObject *const *args,
     578             :               size_t nargsf, PyObject *kwnames)
     579             : {
     580          16 :     gaobject *alias = (gaobject *) self;
     581          16 :     PyObject *obj = PyVectorcall_Function(alias->origin)(alias->origin, args, nargsf, kwnames);
     582          16 :     return set_orig_class(obj, self);
     583             : }
     584             : 
     585             : static const char* const attr_exceptions[] = {
     586             :     "__class__",
     587             :     "__origin__",
     588             :     "__args__",
     589             :     "__unpacked__",
     590             :     "__parameters__",
     591             :     "__typing_unpacked_tuple_args__",
     592             :     "__mro_entries__",
     593             :     "__reduce_ex__",  // needed so we don't look up object.__reduce_ex__
     594             :     "__reduce__",
     595             :     "__copy__",
     596             :     "__deepcopy__",
     597             :     NULL,
     598             : };
     599             : 
     600             : static PyObject *
     601       12132 : ga_getattro(PyObject *self, PyObject *name)
     602             : {
     603       12132 :     gaobject *alias = (gaobject *)self;
     604       12132 :     if (PyUnicode_Check(name)) {
     605       46615 :         for (const char * const *p = attr_exceptions; ; p++) {
     606       46615 :             if (*p == NULL) {
     607        1456 :                 return PyObject_GetAttr(alias->origin, name);
     608             :             }
     609       45159 :             if (_PyUnicode_EqualToASCIIString(name, *p)) {
     610       10676 :                 break;
     611             :             }
     612             :         }
     613             :     }
     614       10676 :     return PyObject_GenericGetAttr(self, name);
     615             : }
     616             : 
     617             : static PyObject *
     618       10668 : ga_richcompare(PyObject *a, PyObject *b, int op)
     619             : {
     620       10668 :     if (!_PyGenericAlias_Check(b) ||
     621           9 :         (op != Py_EQ && op != Py_NE))
     622             :     {
     623        9496 :         Py_RETURN_NOTIMPLEMENTED;
     624             :     }
     625             : 
     626        1172 :     if (op == Py_NE) {
     627           9 :         PyObject *eq = ga_richcompare(a, b, Py_EQ);
     628           9 :         if (eq == NULL)
     629           0 :             return NULL;
     630           9 :         Py_DECREF(eq);
     631           9 :         if (eq == Py_True) {
     632           0 :             Py_RETURN_FALSE;
     633             :         }
     634             :         else {
     635           9 :             Py_RETURN_TRUE;
     636             :         }
     637             :     }
     638             : 
     639        1163 :     gaobject *aa = (gaobject *)a;
     640        1163 :     gaobject *bb = (gaobject *)b;
     641        1163 :     if (aa->starred != bb->starred) {
     642           5 :         Py_RETURN_FALSE;
     643             :     }
     644        1158 :     int eq = PyObject_RichCompareBool(aa->origin, bb->origin, Py_EQ);
     645        1158 :     if (eq < 0) {
     646           0 :         return NULL;
     647             :     }
     648        1158 :     if (!eq) {
     649          16 :         Py_RETURN_FALSE;
     650             :     }
     651        1142 :     return PyObject_RichCompare(aa->args, bb->args, Py_EQ);
     652             : }
     653             : 
     654             : static PyObject *
     655           3 : ga_mro_entries(PyObject *self, PyObject *args)
     656             : {
     657           3 :     gaobject *alias = (gaobject *)self;
     658           3 :     return PyTuple_Pack(1, alias->origin);
     659             : }
     660             : 
     661             : static PyObject *
     662          11 : ga_instancecheck(PyObject *self, PyObject *Py_UNUSED(ignored))
     663             : {
     664          11 :     PyErr_SetString(PyExc_TypeError,
     665             :                     "isinstance() argument 2 cannot be a parameterized generic");
     666          11 :     return NULL;
     667             : }
     668             : 
     669             : static PyObject *
     670           6 : ga_subclasscheck(PyObject *self, PyObject *Py_UNUSED(ignored))
     671             : {
     672           6 :     PyErr_SetString(PyExc_TypeError,
     673             :                     "issubclass() argument 2 cannot be a parameterized generic");
     674           6 :     return NULL;
     675             : }
     676             : 
     677             : static PyObject *
     678         430 : ga_reduce(PyObject *self, PyObject *Py_UNUSED(ignored))
     679             : {
     680         430 :     gaobject *alias = (gaobject *)self;
     681         430 :     if (alias->starred) {
     682         103 :         PyObject *tmp = Py_GenericAlias(alias->origin, alias->args);
     683         103 :         if (tmp != NULL) {
     684         103 :             Py_SETREF(tmp, PyObject_GetIter(tmp));
     685             :         }
     686         103 :         if (tmp == NULL) {
     687           0 :             return NULL;
     688             :         }
     689         103 :         return Py_BuildValue("N(N)", _PyEval_GetBuiltin(&_Py_ID(next)), tmp);
     690             :     }
     691         327 :     return Py_BuildValue("O(OO)", Py_TYPE(alias),
     692             :                          alias->origin, alias->args);
     693             : }
     694             : 
     695             : static PyObject *
     696           1 : ga_dir(PyObject *self, PyObject *Py_UNUSED(ignored))
     697             : {
     698           1 :     gaobject *alias = (gaobject *)self;
     699           1 :     PyObject *dir = PyObject_Dir(alias->origin);
     700           1 :     if (dir == NULL) {
     701           0 :         return NULL;
     702             :     }
     703             : 
     704           1 :     PyObject *dir_entry = NULL;
     705          12 :     for (const char * const *p = attr_exceptions; ; p++) {
     706          12 :         if (*p == NULL) {
     707           1 :             break;
     708             :         }
     709             :         else {
     710          11 :             dir_entry = PyUnicode_FromString(*p);
     711          11 :             if (dir_entry == NULL) {
     712           0 :                 goto error;
     713             :             }
     714          11 :             int contains = PySequence_Contains(dir, dir_entry);
     715          11 :             if (contains < 0) {
     716           0 :                 goto error;
     717             :             }
     718          11 :             if (contains == 0 && PyList_Append(dir, dir_entry) < 0) {
     719           0 :                 goto error;
     720             :             }
     721             : 
     722          11 :             Py_CLEAR(dir_entry);
     723             :         }
     724             :     }
     725           1 :     return dir;
     726             : 
     727           0 : error:
     728           0 :     Py_DECREF(dir);
     729           0 :     Py_XDECREF(dir_entry);
     730           0 :     return NULL;
     731             : }
     732             : 
     733             : static PyMethodDef ga_methods[] = {
     734             :     {"__mro_entries__", ga_mro_entries, METH_O},
     735             :     {"__instancecheck__", ga_instancecheck, METH_O},
     736             :     {"__subclasscheck__", ga_subclasscheck, METH_O},
     737             :     {"__reduce__", ga_reduce, METH_NOARGS},
     738             :     {"__dir__", ga_dir, METH_NOARGS},
     739             :     {0}
     740             : };
     741             : 
     742             : static PyMemberDef ga_members[] = {
     743             :     {"__origin__", T_OBJECT, offsetof(gaobject, origin), READONLY},
     744             :     {"__args__", T_OBJECT, offsetof(gaobject, args), READONLY},
     745             :     {"__unpacked__", T_BOOL, offsetof(gaobject, starred), READONLY},
     746             :     {0}
     747             : };
     748             : 
     749             : static PyObject *
     750        2064 : ga_parameters(PyObject *self, void *unused)
     751             : {
     752        2064 :     gaobject *alias = (gaobject *)self;
     753        2064 :     if (alias->parameters == NULL) {
     754        1581 :         alias->parameters = _Py_make_parameters(alias->args);
     755        1581 :         if (alias->parameters == NULL) {
     756           0 :             return NULL;
     757             :         }
     758             :     }
     759        2064 :     Py_INCREF(alias->parameters);
     760        2064 :     return alias->parameters;
     761             : }
     762             : 
     763             : static PyObject *
     764         204 : ga_unpacked_tuple_args(PyObject *self, void *unused)
     765             : {
     766         204 :     gaobject *alias = (gaobject *)self;
     767         204 :     if (alias->starred && alias->origin == (PyObject *)&PyTuple_Type) {
     768         170 :         Py_INCREF(alias->args);
     769         170 :         return alias->args;
     770             :     }
     771          34 :     Py_RETURN_NONE;
     772             : }
     773             : 
     774             : static PyGetSetDef ga_properties[] = {
     775             :     {"__parameters__", ga_parameters, (setter)NULL, "Type variables in the GenericAlias.", NULL},
     776             :     {"__typing_unpacked_tuple_args__", ga_unpacked_tuple_args, (setter)NULL, NULL},
     777             :     {0}
     778             : };
     779             : 
     780             : /* A helper function to create GenericAlias' args tuple and set its attributes.
     781             :  * Returns 1 on success, 0 on failure.
     782             :  */
     783             : static inline int
     784       22948 : setup_ga(gaobject *alias, PyObject *origin, PyObject *args) {
     785       22948 :     if (!PyTuple_Check(args)) {
     786       15515 :         args = PyTuple_Pack(1, args);
     787       15515 :         if (args == NULL) {
     788           0 :             return 0;
     789             :         }
     790             :     }
     791             :     else {
     792        7433 :         Py_INCREF(args);
     793             :     }
     794             : 
     795       22948 :     Py_INCREF(origin);
     796       22948 :     alias->origin = origin;
     797       22948 :     alias->args = args;
     798       22948 :     alias->parameters = NULL;
     799       22948 :     alias->weakreflist = NULL;
     800             : 
     801       22948 :     if (PyVectorcall_Function(origin) != NULL) {
     802       22536 :         alias->vectorcall = ga_vectorcall;
     803             :     }
     804             :     else {
     805         412 :         alias->vectorcall = NULL;
     806             :     }
     807             : 
     808       22948 :     return 1;
     809             : }
     810             : 
     811             : static PyObject *
     812         654 : ga_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     813             : {
     814         654 :     if (!_PyArg_NoKeywords("GenericAlias", kwds)) {
     815           2 :         return NULL;
     816             :     }
     817         652 :     if (!_PyArg_CheckPositional("GenericAlias", PyTuple_GET_SIZE(args), 2, 2)) {
     818           0 :         return NULL;
     819             :     }
     820         652 :     PyObject *origin = PyTuple_GET_ITEM(args, 0);
     821         652 :     PyObject *arguments = PyTuple_GET_ITEM(args, 1);
     822         652 :     gaobject *self = (gaobject *)type->tp_alloc(type, 0);
     823         652 :     if (self == NULL) {
     824           0 :         return NULL;
     825             :     }
     826         652 :     if (!setup_ga(self, origin, arguments)) {
     827           0 :         Py_DECREF(self);
     828           0 :         return NULL;
     829             :     }
     830         652 :     return (PyObject *)self;
     831             : }
     832             : 
     833             : static PyNumberMethods ga_as_number = {
     834             :         .nb_or = _Py_union_type_or, // Add __or__ function
     835             : };
     836             : 
     837             : static PyObject *
     838         594 : ga_iternext(gaiterobject *gi) {
     839         594 :     if (gi->obj == NULL) {
     840         245 :         PyErr_SetNone(PyExc_StopIteration);
     841         245 :         return NULL;
     842             :     }
     843         349 :     gaobject *alias = (gaobject *)gi->obj;
     844         349 :     PyObject *starred_alias = Py_GenericAlias(alias->origin, alias->args);
     845         349 :     if (starred_alias == NULL) {
     846           0 :         return NULL;
     847             :     }
     848         349 :     ((gaobject *)starred_alias)->starred = true;
     849         349 :     Py_SETREF(gi->obj, NULL);
     850         349 :     return starred_alias;
     851             : }
     852             : 
     853             : static void
     854         448 : ga_iter_dealloc(gaiterobject *gi) {
     855         448 :     PyObject_GC_UnTrack(gi);
     856         448 :     Py_XDECREF(gi->obj);
     857         448 :     PyObject_GC_Del(gi);
     858         448 : }
     859             : 
     860             : static int
     861         452 : ga_iter_traverse(gaiterobject *gi, visitproc visit, void *arg)
     862             : {
     863         452 :     Py_VISIT(gi->obj);
     864         452 :     return 0;
     865             : }
     866             : 
     867             : static int
     868           0 : ga_iter_clear(PyObject *self) {
     869           0 :     gaiterobject *gi = (gaiterobject *)self;
     870           0 :     Py_CLEAR(gi->obj);
     871           0 :     return 0;
     872             : }
     873             : 
     874             : static PyObject *
     875          98 : ga_iter_reduce(PyObject *self, PyObject *Py_UNUSED(ignored))
     876             : {
     877          98 :     gaiterobject *gi = (gaiterobject *)self;
     878          98 :     return Py_BuildValue("N(O)", _PyEval_GetBuiltin(&_Py_ID(iter)), gi->obj);
     879             : }
     880             : 
     881             : static PyMethodDef ga_iter_methods[] = {
     882             :     {"__reduce__", ga_iter_reduce, METH_NOARGS},
     883             :     {0}
     884             : };
     885             : 
     886             : // gh-91632: _Py_GenericAliasIterType is exported  to be cleared
     887             : // in _PyTypes_FiniTypes.
     888             : PyTypeObject _Py_GenericAliasIterType = {
     889             :     PyVarObject_HEAD_INIT(&PyType_Type, 0)
     890             :     .tp_name = "generic_alias_iterator",
     891             :     .tp_basicsize = sizeof(gaiterobject),
     892             :     .tp_iter = PyObject_SelfIter,
     893             :     .tp_iternext = (iternextfunc)ga_iternext,
     894             :     .tp_traverse = (traverseproc)ga_iter_traverse,
     895             :     .tp_methods = ga_iter_methods,
     896             :     .tp_dealloc = (destructor)ga_iter_dealloc,
     897             :     .tp_clear = (inquiry)ga_iter_clear,
     898             :     .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
     899             : };
     900             : 
     901             : static PyObject *
     902         448 : ga_iter(PyObject *self) {
     903         448 :     gaiterobject *gi = PyObject_GC_New(gaiterobject, &_Py_GenericAliasIterType);
     904         448 :     if (gi == NULL) {
     905           0 :         return NULL;
     906             :     }
     907         448 :     gi->obj = Py_NewRef(self);
     908         448 :     PyObject_GC_Track(gi);
     909         448 :     return (PyObject *)gi;
     910             : }
     911             : 
     912             : // TODO:
     913             : // - argument clinic?
     914             : // - cache?
     915             : PyTypeObject Py_GenericAliasType = {
     916             :     PyVarObject_HEAD_INIT(&PyType_Type, 0)
     917             :     .tp_name = "types.GenericAlias",
     918             :     .tp_doc = genericalias__doc__,
     919             :     .tp_basicsize = sizeof(gaobject),
     920             :     .tp_dealloc = ga_dealloc,
     921             :     .tp_repr = ga_repr,
     922             :     .tp_as_number = &ga_as_number,  // allow X | Y of GenericAlias objs
     923             :     .tp_as_mapping = &ga_as_mapping,
     924             :     .tp_hash = ga_hash,
     925             :     .tp_call = ga_call,
     926             :     .tp_getattro = ga_getattro,
     927             :     .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_VECTORCALL,
     928             :     .tp_traverse = ga_traverse,
     929             :     .tp_richcompare = ga_richcompare,
     930             :     .tp_weaklistoffset = offsetof(gaobject, weakreflist),
     931             :     .tp_methods = ga_methods,
     932             :     .tp_members = ga_members,
     933             :     .tp_alloc = PyType_GenericAlloc,
     934             :     .tp_new = ga_new,
     935             :     .tp_free = PyObject_GC_Del,
     936             :     .tp_getset = ga_properties,
     937             :     .tp_iter = (getiterfunc)ga_iter,
     938             :     .tp_vectorcall_offset = offsetof(gaobject, vectorcall),
     939             : };
     940             : 
     941             : PyObject *
     942       22296 : Py_GenericAlias(PyObject *origin, PyObject *args)
     943             : {
     944       22296 :     gaobject *alias = (gaobject*) PyType_GenericAlloc(
     945             :             (PyTypeObject *)&Py_GenericAliasType, 0);
     946       22296 :     if (alias == NULL) {
     947           0 :         return NULL;
     948             :     }
     949       22296 :     if (!setup_ga(alias, origin, args)) {
     950           0 :         Py_DECREF(alias);
     951           0 :         return NULL;
     952             :     }
     953       22296 :     return (PyObject *)alias;
     954             : }

Generated by: LCOV version 1.14