Coverage Report

Created: 2022-07-08 09:39

/home/mdboom/Work/builds/cpython/Objects/genericaliasobject.c
Line
Count
Source (jump to first uncovered line)
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
ga_dealloc(PyObject *self)
28
{
29
    gaobject *alias = (gaobject *)self;
30
31
    _PyObject_GC_UNTRACK(self);
32
    if (alias->weakreflist != NULL) {
  Branch (32:9): [True: 0, False: 2.95k]
33
        PyObject_ClearWeakRefs((PyObject *)alias);
34
    }
35
    Py_XDECREF(alias->origin);
36
    Py_XDECREF(alias->args);
37
    Py_XDECREF(alias->parameters);
38
    Py_TYPE(self)->tp_free(self);
39
}
40
41
static int
42
ga_traverse(PyObject *self, visitproc visit, void *arg)
43
{
44
    gaobject *alias = (gaobject *)self;
45
    Py_VISIT(alias->origin);
46
    Py_VISIT(alias->args);
47
    Py_VISIT(alias->parameters);
48
    return 0;
49
}
50
51
static int
52
ga_repr_item(_PyUnicodeWriter *writer, PyObject *p)
53
{
54
    PyObject *qualname = NULL;
55
    PyObject *module = NULL;
56
    PyObject *r = NULL;
57
    PyObject *tmp;
58
    int err;
59
60
    if (p == Py_Ellipsis) {
  Branch (60:9): [True: 37, False: 313]
61
        // The Ellipsis object
62
        r = PyUnicode_FromString("...");
63
        goto done;
64
    }
65
66
    if (_PyObject_LookupAttr(p, &_Py_ID(__origin__), &tmp) < 0) {
  Branch (66:9): [True: 0, False: 313]
67
        goto done;
68
    }
69
    if (tmp != NULL) {
  Branch (69:9): [True: 15, False: 298]
70
        Py_DECREF(tmp);
71
        if (_PyObject_LookupAttr(p, &_Py_ID(__args__), &tmp) < 0) {
  Branch (71:13): [True: 0, False: 15]
72
            goto done;
73
        }
74
        if (tmp != NULL) {
  Branch (74:13): [True: 15, False: 0]
75
            Py_DECREF(tmp);
76
            // It looks like a GenericAlias
77
            goto use_repr;
78
        }
79
    }
80
81
    if (_PyObject_LookupAttr(p, &_Py_ID(__qualname__), &qualname) < 0) {
  Branch (81:9): [True: 0, False: 298]
82
        goto done;
83
    }
84
    if (qualname == NULL) {
  Branch (84:9): [True: 72, False: 226]
85
        goto use_repr;
86
    }
87
    if (_PyObject_LookupAttr(p, &_Py_ID(__module__), &module) < 0) {
  Branch (87:9): [True: 0, False: 226]
88
        goto done;
89
    }
90
    if (module == NULL || module == Py_None) {
  Branch (90:9): [True: 0, False: 226]
  Branch (90:27): [True: 0, False: 226]
91
        goto use_repr;
92
    }
93
94
    // Looks like a class
95
    if (PyUnicode_Check(module) &&
96
        _PyUnicode_EqualToASCIIString(module, "builtins"))
  Branch (96:9): [True: 210, False: 16]
97
    {
98
        // builtins don't need a module name
99
        r = PyObject_Str(qualname);
100
        goto done;
101
    }
102
    else {
103
        r = PyUnicode_FromFormat("%S.%S", module, qualname);
104
        goto done;
105
    }
106
107
use_repr:
108
    r = PyObject_Repr(p);
109
110
done:
111
    Py_XDECREF(qualname);
112
    Py_XDECREF(module);
113
    if (r == NULL) {
  Branch (113:9): [True: 0, False: 350]
114
        // error if any of the above PyObject_Repr/PyUnicode_From* fail
115
        err = -1;
116
    }
117
    else {
118
        err = _PyUnicodeWriter_WriteStr(writer, r);
119
        Py_DECREF(r);
120
    }
121
    return err;
122
}
123
124
static PyObject *
125
ga_repr(PyObject *self)
126
{
127
    gaobject *alias = (gaobject *)self;
128
    Py_ssize_t len = PyTuple_GET_SIZE(alias->args);
129
130
    _PyUnicodeWriter writer;
131
    _PyUnicodeWriter_Init(&writer);
132
133
    if (alias->starred) {
  Branch (133:9): [True: 29, False: 107]
134
        if (_PyUnicodeWriter_WriteASCIIString(&writer, "*", 1) < 0) {
  Branch (134:13): [True: 0, False: 29]
135
            goto error;
136
        }
137
    }
138
    if (ga_repr_item(&writer, alias->origin) < 0) {
  Branch (138:9): [True: 0, False: 136]
139
        goto error;
140
    }
141
    if (_PyUnicodeWriter_WriteASCIIString(&writer, "[", 1) < 0) {
  Branch (141:9): [True: 0, False: 136]
142
        goto error;
143
    }
144
    
for (Py_ssize_t i = 0; 136
i < len;
i++214
) {
  Branch (144:28): [True: 214, False: 136]
145
        if (i > 0) {
  Branch (145:13): [True: 79, False: 135]
146
            if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ", 2) < 0) {
  Branch (146:17): [True: 0, False: 79]
147
                goto error;
148
            }
149
        }
150
        PyObject *p = PyTuple_GET_ITEM(alias->args, i);
151
        if (ga_repr_item(&writer, p) < 0) {
  Branch (151:13): [True: 0, False: 214]
152
            goto error;
153
        }
154
    }
155
    if (len == 0) {
  Branch (155:9): [True: 1, False: 135]
156
        // for something like tuple[()] we should print a "()"
157
        if (_PyUnicodeWriter_WriteASCIIString(&writer, "()", 2) < 0) {
  Branch (157:13): [True: 0, False: 1]
158
            goto error;
159
        }
160
    }
161
    if (_PyUnicodeWriter_WriteASCIIString(&writer, "]", 1) < 0) {
  Branch (161:9): [True: 0, False: 136]
162
        goto error;
163
    }
164
    return _PyUnicodeWriter_Finish(&writer);
165
error:
166
    _PyUnicodeWriter_Dealloc(&writer);
167
    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
tuple_index(PyObject *self, Py_ssize_t len, PyObject *item)
173
{
174
    for (Py_ssize_t i = 0; i < len; 
i++230
) {
  Branch (174:28): [True: 576, False: 466]
175
        if (PyTuple_GET_ITEM(self, i) == item) {
  Branch (175:13): [True: 346, False: 230]
176
            return i;
177
        }
178
    }
179
    return -1;
180
}
181
182
static int
183
tuple_add(PyObject *self, Py_ssize_t len, PyObject *item)
184
{
185
    if (tuple_index(self, len, item) < 0) {
  Branch (185:9): [True: 466, False: 5]
186
        Py_INCREF(item);
187
        PyTuple_SET_ITEM(self, len, item);
188
        return 1;
189
    }
190
    return 0;
191
}
192
193
static Py_ssize_t
194
tuple_extend(PyObject **dst, Py_ssize_t dstindex,
195
             PyObject **src, Py_ssize_t count)
196
{
197
    assert(count >= 0);
198
    if (_PyTuple_Resize(dst, PyTuple_GET_SIZE(*dst) + count - 1) != 0) {
  Branch (198:9): [True: 0, False: 134]
199
        return -1;
200
    }
201
    assert(dstindex + count <= PyTuple_GET_SIZE(*dst));
202
    for (Py_ssize_t i = 0; i < count; 
++i172
) {
  Branch (202:28): [True: 172, False: 134]
203
        PyObject *item = src[i];
204
        Py_INCREF(item);
205
        PyTuple_SET_ITEM(*dst, dstindex + i, item);
206
    }
207
    return dstindex + count;
208
}
209
210
PyObject *
211
_Py_make_parameters(PyObject *args)
212
{
213
    Py_ssize_t nargs = PyTuple_GET_SIZE(args);
214
    Py_ssize_t len = nargs;
215
    PyObject *parameters = PyTuple_New(len);
216
    if (parameters == NULL)
  Branch (216:9): [True: 0, False: 828]
217
        return NULL;
218
    Py_ssize_t iparam = 0;
219
    for (Py_ssize_t iarg = 0; iarg < nargs; 
iarg++1.29k
) {
  Branch (219:31): [True: 1.29k, False: 828]
220
        PyObject *t = PyTuple_GET_ITEM(args, iarg);
221
        PyObject *subst;
222
        if (_PyObject_LookupAttr(t, &_Py_ID(__typing_subst__), &subst) < 0) {
  Branch (222:13): [True: 0, False: 1.29k]
223
            Py_DECREF(parameters);
224
            return NULL;
225
        }
226
        if (subst) {
  Branch (226:13): [True: 309, False: 989]
227
            iparam += tuple_add(parameters, iparam, t);
228
            Py_DECREF(subst);
229
        }
230
        else {
231
            PyObject *subparams;
232
            if (_PyObject_LookupAttr(t, &_Py_ID(__parameters__),
  Branch (232:17): [True: 0, False: 989]
233
                                     &subparams) < 0) {
234
                Py_DECREF(parameters);
235
                return NULL;
236
            }
237
            if (subparams && 
PyTuple_Check302
(subparams)) {
  Branch (237:17): [True: 302, False: 687]
238
                Py_ssize_t len2 = PyTuple_GET_SIZE(subparams);
239
                Py_ssize_t needed = len2 - 1 - (iarg - iparam);
240
                if (needed > 0) {
  Branch (240:21): [True: 11, False: 291]
241
                    len += needed;
242
                    if (_PyTuple_Resize(&parameters, len) < 0) {
  Branch (242:25): [True: 0, False: 11]
243
                        Py_DECREF(subparams);
244
                        Py_DECREF(parameters);
245
                        return NULL;
246
                    }
247
                }
248
                
for (Py_ssize_t j = 0; 302
j < len2;
j++162
) {
  Branch (248:40): [True: 162, False: 302]
249
                    PyObject *t2 = PyTuple_GET_ITEM(subparams, j);
250
                    iparam += tuple_add(parameters, iparam, t2);
251
                }
252
            }
253
            Py_XDECREF(subparams);
254
        }
255
    }
256
    if (iparam < len) {
  Branch (256:9): [True: 568, False: 260]
257
        if (_PyTuple_Resize(&parameters, iparam) < 0) {
  Branch (257:13): [True: 0, False: 568]
258
            Py_XDECREF(parameters);
259
            return NULL;
260
        }
261
    }
262
    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
subs_tvars(PyObject *obj, PyObject *params,
272
           PyObject **argitems, Py_ssize_t nargs)
273
{
274
    PyObject *subparams;
275
    if (_PyObject_LookupAttr(obj, &_Py_ID(__parameters__), &subparams) < 0) {
  Branch (275:9): [True: 0, False: 176]
276
        return NULL;
277
    }
278
    if (subparams && PyTuple_Check(subparams) && 
PyTuple_GET_SIZE129
(subparams)) {
  Branch (278:9): [True: 129, False: 47]
279
        Py_ssize_t nparams = PyTuple_GET_SIZE(params);
280
        Py_ssize_t nsubargs = PyTuple_GET_SIZE(subparams);
281
        PyObject *subargs = PyTuple_New(nsubargs);
282
        if (subargs == NULL) {
  Branch (282:13): [True: 0, False: 117]
283
            Py_DECREF(subparams);
284
            return NULL;
285
        }
286
        Py_ssize_t j = 0;
287
        for (Py_ssize_t i = 0; i < nsubargs; 
++i125
) {
  Branch (287:32): [True: 125, False: 117]
288
            PyObject *arg = PyTuple_GET_ITEM(subparams, i);
289
            Py_ssize_t iparam = tuple_index(params, nparams, arg);
290
            if (iparam >= 0) {
  Branch (290:17): [True: 125, False: 0]
291
                PyObject *param = PyTuple_GET_ITEM(params, iparam);
292
                arg = argitems[iparam];
293
                if (Py_TYPE(param)->tp_iter && 
PyTuple_Check72
(arg)) { // TypeVarTuple
  Branch (293:21): [True: 72, False: 53]
294
                    j = tuple_extend(&subargs, j,
295
                                    &PyTuple_GET_ITEM(arg, 0),
296
                                    PyTuple_GET_SIZE(arg));
297
                    if (j < 0) {
  Branch (297:25): [True: 0, False: 72]
298
                        return NULL;
299
                    }
300
                    continue;
301
                }
302
            }
303
            Py_INCREF(arg);
304
            PyTuple_SET_ITEM(subargs, j, arg);
305
            j++;
306
        }
307
        assert(j == PyTuple_GET_SIZE(subargs));
308
309
        obj = PyObject_GetItem(obj, subargs);
310
311
        Py_DECREF(subargs);
312
    }
313
    else {
314
        Py_INCREF(obj);
315
    }
316
    Py_XDECREF(subparams);
317
    return obj;
318
}
319
320
static int
321
_is_unpacked_typevartuple(PyObject *arg)
322
{
323
    PyObject *tmp;
324
    if (PyType_Check(arg)) { // TODO: Add test
325
        return 0;
326
    }
327
    int res = _PyObject_LookupAttr(arg, &_Py_ID(__typing_is_unpacked_typevartuple__), &tmp);
328
    if (res > 0) {
  Branch (328:9): [True: 71, False: 288]
329
        res = PyObject_IsTrue(tmp);
330
        Py_DECREF(tmp);
331
    }
332
    return res;
333
}
334
335
static PyObject *
336
_unpacked_tuple_args(PyObject *arg)
337
{
338
    PyObject *result;
339
    assert(!PyType_Check(arg));
340
    // Fast path
341
    if (_PyGenericAlias_Check(arg) &&
342
            
((gaobject *)arg)->starred51
&&
  Branch (342:13): [True: 44, False: 7]
343
            
((gaobject *)arg)->origin == (PyObject *)&PyTuple_Type44
)
  Branch (343:13): [True: 44, False: 0]
344
    {
345
        result = ((gaobject *)arg)->args;
346
        Py_INCREF(result);
347
        return result;
348
    }
349
350
    if (_PyObject_LookupAttr(arg, &_Py_ID(__typing_unpacked_tuple_args__), &result) > 0) {
  Branch (350:9): [True: 61, False: 60]
351
        if (result == Py_None) {
  Branch (351:13): [True: 17, False: 44]
352
            Py_DECREF(result);
353
            return NULL;
354
        }
355
        return result;
356
    }
357
    return NULL;
358
}
359
360
static PyObject *
361
_unpack_args(PyObject *item)
362
{
363
    PyObject *newargs = PyList_New(0);
364
    if (newargs == NULL) {
  Branch (364:9): [True: 0, False: 283]
365
        return NULL;
366
    }
367
    int is_tuple = PyTuple_Check(item);
368
    Py_ssize_t nitems = is_tuple ? 
PyTuple_GET_SIZE240
(item) :
143
;
  Branch (368:25): [True: 240, False: 43]
369
    PyObject **argitems = is_tuple ? 
&240
PyTuple_GET_ITEM240
(item, 0) :
&item43
;
  Branch (369:27): [True: 240, False: 43]
370
    for (Py_ssize_t i = 0; i < nitems; 
i++415
) {
  Branch (370:28): [True: 415, False: 283]
371
        item = argitems[i];
372
        if (!PyType_Check(item)) {
  Branch (372:13): [True: 165, False: 250]
373
            PyObject *subargs = _unpacked_tuple_args(item);
374
            if (subargs != NULL &&
  Branch (374:17): [True: 88, False: 77]
375
                PyTuple_Check(subargs) &&
376
                
!(88
PyTuple_GET_SIZE88
(subargs) &&
377
                  
PyTuple_GET_ITEM78
(subargs, PyTuple_GET_SIZE(subargs)-1) == 78
Py_Ellipsis78
))
  Branch (377:19): [True: 34, False: 44]
378
            {
379
                if (PyList_SetSlice(newargs, PY_SSIZE_T_MAX, PY_SSIZE_T_MAX, subargs) < 0) {
  Branch (379:21): [True: 0, False: 54]
380
                    Py_DECREF(subargs);
381
                    Py_DECREF(newargs);
382
                    return NULL;
383
                }
384
                Py_DECREF(subargs);
385
                continue;
386
            }
387
            Py_XDECREF(subargs);
388
            if (PyErr_Occurred()) {
  Branch (388:17): [True: 0, False: 111]
389
                Py_DECREF(newargs);
390
                return NULL;
391
            }
392
        }
393
        if (PyList_Append(newargs, item) < 0) {
  Branch (393:13): [True: 0, False: 361]
394
            Py_DECREF(newargs);
395
            return NULL;
396
        }
397
    }
398
    Py_SETREF(newargs, PySequence_Tuple(newargs));
399
    return newargs;
400
}
401
402
PyObject *
403
_Py_subs_parameters(PyObject *self, PyObject *args, PyObject *parameters, PyObject *item)
404
{
405
    Py_ssize_t nparams = PyTuple_GET_SIZE(parameters);
406
    if (nparams == 0) {
  Branch (406:9): [True: 3, False: 283]
407
        return PyErr_Format(PyExc_TypeError,
408
                            "%R is not a generic class",
409
                            self);
410
    }
411
    item = _unpack_args(item);
412
    for (Py_ssize_t i = 0; i < nparams; 
i++411
) {
  Branch (412:28): [True: 417, False: 277]
413
        PyObject *param = PyTuple_GET_ITEM(parameters, i);
414
        PyObject *prepare, *tmp;
415
        if (_PyObject_LookupAttr(param, &_Py_ID(__typing_prepare_subst__), &prepare) < 0) {
  Branch (415:13): [True: 0, False: 417]
416
            Py_DECREF(item);
417
            return NULL;
418
        }
419
        if (prepare && 
prepare != 116
Py_None116
) {
  Branch (419:13): [True: 116, False: 301]
  Branch (419:24): [True: 116, False: 0]
420
            if (PyTuple_Check(item)) {
421
                tmp = PyObject_CallFunction(prepare, "OO", self, item);
422
            }
423
            else {
424
                tmp = PyObject_CallFunction(prepare, "O(O)", self, item);
425
            }
426
            Py_DECREF(prepare);
427
            Py_SETREF(item, tmp);
428
            if (item == NULL) {
  Branch (428:17): [True: 6, False: 110]
429
                return NULL;
430
            }
431
        }
432
    }
433
    int is_tuple = PyTuple_Check(item);
434
    Py_ssize_t nitems = is_tuple ? PyTuple_GET_SIZE(item) : 
10
;
  Branch (434:25): [True: 277, False: 0]
435
    PyObject **argitems = is_tuple ? &PyTuple_GET_ITEM(item, 0) : 
&item0
;
  Branch (435:27): [True: 277, False: 0]
436
    if (nitems != nparams) {
  Branch (436:9): [True: 35, False: 242]
437
        Py_DECREF(item);
438
        return PyErr_Format(PyExc_TypeError,
439
                            "Too %s arguments for %R; actual %zd, expected %zd",
440
                            nitems > nparams ? 
"many"17
:
"few"18
,
  Branch (440:29): [True: 17, False: 18]
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
    Py_ssize_t nargs = PyTuple_GET_SIZE(args);
450
    PyObject *newargs = PyTuple_New(nargs);
451
    if (newargs == NULL) {
  Branch (451:9): [True: 0, False: 242]
452
        Py_DECREF(item);
453
        return NULL;
454
    }
455
    
for (Py_ssize_t iarg = 0, jarg = 0; 242
iarg < nargs;
iarg++364
) {
  Branch (455:41): [True: 392, False: 214]
456
        PyObject *arg = PyTuple_GET_ITEM(args, iarg);
457
        int unpack = _is_unpacked_typevartuple(arg);
458
        if (unpack < 0) {
  Branch (458:13): [True: 0, False: 392]
459
            Py_DECREF(newargs);
460
            Py_DECREF(item);
461
            return NULL;
462
        }
463
        PyObject *subst;
464
        if (_PyObject_LookupAttr(arg, &_Py_ID(__typing_subst__), &subst) < 0) {
  Branch (464:13): [True: 0, False: 392]
465
            Py_DECREF(newargs);
466
            Py_DECREF(item);
467
            return NULL;
468
        }
469
        if (subst) {
  Branch (469:13): [True: 216, False: 176]
470
            Py_ssize_t iparam = tuple_index(parameters, nparams, arg);
471
            assert(iparam >= 0);
472
            arg = PyObject_CallOneArg(subst, argitems[iparam]);
473
            Py_DECREF(subst);
474
        }
475
        else {
476
            arg = subs_tvars(arg, parameters, argitems, nitems);
477
        }
478
        if (arg == NULL) {
  Branch (478:13): [True: 28, False: 364]
479
            Py_DECREF(newargs);
480
            Py_DECREF(item);
481
            return NULL;
482
        }
483
        if (unpack) {
  Branch (483:13): [True: 62, False: 302]
484
            jarg = tuple_extend(&newargs, jarg,
485
                    &PyTuple_GET_ITEM(arg, 0), PyTuple_GET_SIZE(arg));
486
            Py_DECREF(arg);
487
            if (jarg < 0) {
  Branch (487:17): [True: 0, False: 62]
488
                Py_DECREF(item);
489
                return NULL;
490
            }
491
        }
492
        else {
493
            PyTuple_SET_ITEM(newargs, jarg, arg);
494
            jarg++;
495
        }
496
    }
497
498
    Py_DECREF(item);
499
    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
ga_getitem(PyObject *self, PyObject *item)
509
{
510
    gaobject *alias = (gaobject *)self;
511
    // Populate __parameters__ if needed.
512
    if (alias->parameters == NULL) {
  Branch (512:9): [True: 162, False: 119]
513
        alias->parameters = _Py_make_parameters(alias->args);
514
        if (alias->parameters == NULL) {
  Branch (514:13): [True: 0, False: 162]
515
            return NULL;
516
        }
517
    }
518
519
    PyObject *newargs = _Py_subs_parameters(self, alias->args, alias->parameters, item);
520
    if (newargs == NULL) {
  Branch (520:9): [True: 72, False: 209]
521
        return NULL;
522
    }
523
524
    PyObject *res = Py_GenericAlias(alias->origin, newargs);
525
    ((gaobject *)res)->starred = alias->starred;
526
527
    Py_DECREF(newargs);
528
    return res;
529
}
530
531
static PyMappingMethods ga_as_mapping = {
532
    .mp_subscript = ga_getitem,
533
};
534
535
static Py_hash_t
536
ga_hash(PyObject *self)
537
{
538
    gaobject *alias = (gaobject *)self;
539
    // TODO: Hash in the hash for the origin
540
    Py_hash_t h0 = PyObject_Hash(alias->origin);
541
    if (h0 == -1) {
  Branch (541:9): [True: 0, False: 560]
542
        return -1;
543
    }
544
    Py_hash_t h1 = PyObject_Hash(alias->args);
545
    if (h1 == -1) {
  Branch (545:9): [True: 0, False: 560]
546
        return -1;
547
    }
548
    return h0 ^ h1;
549
}
550
551
static inline PyObject *
552
set_orig_class(PyObject *obj, PyObject *self)
553
{
554
    if (obj != NULL) {
  Branch (554:9): [True: 42, False: 1]
555
        if (PyObject_SetAttr(obj, &_Py_ID(__orig_class__), self) < 0) {
  Branch (555:13): [True: 21, False: 21]
556
            if (!PyErr_ExceptionMatches(PyExc_AttributeError) &&
  Branch (556:17): [True: 1, False: 20]
557
                
!PyErr_ExceptionMatches(PyExc_TypeError)1
)
  Branch (557:17): [True: 0, False: 1]
558
            {
559
                Py_DECREF(obj);
560
                return NULL;
561
            }
562
            PyErr_Clear();
563
        }
564
    }
565
    return obj;
566
}
567
568
static PyObject *
569
ga_call(PyObject *self, PyObject *args, PyObject *kwds)
570
{
571
    gaobject *alias = (gaobject *)self;
572
    PyObject *obj = PyObject_Call(alias->origin, args, kwds);
573
    return set_orig_class(obj, self);
574
}
575
576
static PyObject *
577
ga_vectorcall(PyObject *self, PyObject *const *args,
578
              size_t nargsf, PyObject *kwnames)
579
{
580
    gaobject *alias = (gaobject *) self;
581
    PyObject *obj = PyVectorcall_Function(alias->origin)(alias->origin, args, nargsf, kwnames);
582
    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
ga_getattro(PyObject *self, PyObject *name)
602
{
603
    gaobject *alias = (gaobject *)self;
604
    if (PyUnicode_Check(name)) {
605
        for (const char * const *p = attr_exceptions; ; 
p++20.4k
) {
606
            if (*p == NULL) {
  Branch (606:17): [True: 522, False: 25.5k]
607
                return PyObject_GetAttr(alias->origin, name);
608
            }
609
            if (_PyUnicode_EqualToASCIIString(name, *p)) {
  Branch (609:17): [True: 5.08k, False: 20.4k]
610
                break;
611
            }
612
        }
613
    }
614
    return PyObject_GenericGetAttr(self, name);
615
}
616
617
static PyObject *
618
ga_richcompare(PyObject *a, PyObject *b, int op)
619
{
620
    if (!_PyGenericAlias_Check(b) ||
  Branch (620:9): [True: 1.09k, False: 691]
621
        
(691
op != 691
Py_EQ691
&&
op != 9
Py_NE9
))
  Branch (621:10): [True: 9, False: 682]
  Branch (621:25): [True: 0, False: 9]
622
    {
623
        Py_RETURN_NOTIMPLEMENTED;
624
    }
625
626
    if (op == Py_NE) {
  Branch (626:9): [True: 9, False: 682]
627
        PyObject *eq = ga_richcompare(a, b, Py_EQ);
628
        if (eq == NULL)
  Branch (628:13): [True: 0, False: 9]
629
            return NULL;
630
        Py_DECREF(eq);
631
        if (eq == Py_True) {
  Branch (631:13): [True: 0, False: 9]
632
            Py_RETURN_FALSE;
633
        }
634
        else {
635
            Py_RETURN_TRUE;
636
        }
637
    }
638
639
    gaobject *aa = (gaobject *)a;
640
    gaobject *bb = (gaobject *)b;
641
    if (aa->starred != bb->starred) {
  Branch (641:9): [True: 5, False: 677]
642
        Py_RETURN_FALSE;
643
    }
644
    int eq = PyObject_RichCompareBool(aa->origin, bb->origin, Py_EQ);
645
    if (eq < 0) {
  Branch (645:9): [True: 0, False: 677]
646
        return NULL;
647
    }
648
    if (!eq) {
  Branch (648:9): [True: 16, False: 661]
649
        Py_RETURN_FALSE;
650
    }
651
    return PyObject_RichCompare(aa->args, bb->args, Py_EQ);
652
}
653
654
static PyObject *
655
ga_mro_entries(PyObject *self, PyObject *args)
656
{
657
    gaobject *alias = (gaobject *)self;
658
    return PyTuple_Pack(1, alias->origin);
659
}
660
661
static PyObject *
662
ga_instancecheck(PyObject *self, PyObject *Py_UNUSED(ignored))
663
{
664
    PyErr_SetString(PyExc_TypeError,
665
                    "isinstance() argument 2 cannot be a parameterized generic");
666
    return NULL;
667
}
668
669
static PyObject *
670
ga_subclasscheck(PyObject *self, PyObject *Py_UNUSED(ignored))
671
{
672
    PyErr_SetString(PyExc_TypeError,
673
                    "issubclass() argument 2 cannot be a parameterized generic");
674
    return NULL;
675
}
676
677
static PyObject *
678
ga_reduce(PyObject *self, PyObject *Py_UNUSED(ignored))
679
{
680
    gaobject *alias = (gaobject *)self;
681
    if (alias->starred) {
  Branch (681:9): [True: 103, False: 327]
682
        PyObject *tmp = Py_GenericAlias(alias->origin, alias->args);
683
        if (tmp != NULL) {
  Branch (683:13): [True: 103, False: 0]
684
            Py_SETREF(tmp, PyObject_GetIter(tmp));
685
        }
686
        if (tmp == NULL) {
  Branch (686:13): [True: 0, False: 103]
687
            return NULL;
688
        }
689
        return Py_BuildValue("N(N)", _PyEval_GetBuiltin(&_Py_ID(next)), tmp);
690
    }
691
    return Py_BuildValue("O(OO)", Py_TYPE(alias),
692
                         alias->origin, alias->args);
693
}
694
695
static PyObject *
696
ga_dir(PyObject *self, PyObject *Py_UNUSED(ignored))
697
{
698
    gaobject *alias = (gaobject *)self;
699
    PyObject *dir = PyObject_Dir(alias->origin);
700
    if (dir == NULL) {
  Branch (700:9): [True: 0, False: 1]
701
        return NULL;
702
    }
703
704
    PyObject *dir_entry = NULL;
705
    for (const char * const *p = attr_exceptions; ; 
p++11
) {
706
        if (*p == NULL) {
  Branch (706:13): [True: 1, False: 11]
707
            break;
708
        }
709
        else {
710
            dir_entry = PyUnicode_FromString(*p);
711
            if (dir_entry == NULL) {
  Branch (711:17): [True: 0, False: 11]
712
                goto error;
713
            }
714
            int contains = PySequence_Contains(dir, dir_entry);
715
            if (contains < 0) {
  Branch (715:17): [True: 0, False: 11]
716
                goto error;
717
            }
718
            if (contains == 0 && 
PyList_Append(dir, dir_entry) < 08
) {
  Branch (718:17): [True: 8, False: 3]
  Branch (718:34): [True: 0, False: 8]
719
                goto error;
720
            }
721
722
            Py_CLEAR(dir_entry);
723
        }
724
    }
725
    return dir;
726
727
error:
728
    Py_DECREF(dir);
729
    Py_XDECREF(dir_entry);
730
    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
ga_parameters(PyObject *self, void *unused)
751
{
752
    gaobject *alias = (gaobject *)self;
753
    if (alias->parameters == NULL) {
  Branch (753:9): [True: 647, False: 483]
754
        alias->parameters = _Py_make_parameters(alias->args);
755
        if (alias->parameters == NULL) {
  Branch (755:13): [True: 0, False: 647]
756
            return NULL;
757
        }
758
    }
759
    Py_INCREF(alias->parameters);
760
    return alias->parameters;
761
}
762
763
static PyObject *
764
ga_unpacked_tuple_args(PyObject *self, void *unused)
765
{
766
    gaobject *alias = (gaobject *)self;
767
    if (alias->starred && 
alias->origin == (PyObject *)&PyTuple_Type170
) {
  Branch (767:9): [True: 170, False: 34]
  Branch (767:27): [True: 170, False: 0]
768
        Py_INCREF(alias->args);
769
        return alias->args;
770
    }
771
    
Py_RETURN_NONE34
;
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
setup_ga(gaobject *alias, PyObject *origin, PyObject *args) {
785
    if (!PyTuple_Check(args)) {
  Branch (785:9): [True: 1.22k, False: 1.73k]
786
        args = PyTuple_Pack(1, args);
787
        if (args == NULL) {
  Branch (787:13): [True: 0, False: 1.22k]
788
            return 0;
789
        }
790
    }
791
    else {
792
        Py_INCREF(args);
793
    }
794
795
    Py_INCREF(origin);
796
    alias->origin = origin;
797
    alias->args = args;
798
    alias->parameters = NULL;
799
    alias->weakreflist = NULL;
800
801
    if (PyVectorcall_Function(origin) != NULL) {
  Branch (801:9): [True: 2.56k, False: 388]
802
        alias->vectorcall = ga_vectorcall;
803
    }
804
    else {
805
        alias->vectorcall = NULL;
806
    }
807
808
    return 1;
809
}
810
811
static PyObject *
812
ga_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
813
{
814
    if (!_PyArg_NoKeywords("GenericAlias", kwds)) {
815
        return NULL;
816
    }
817
    if (!_PyArg_CheckPositional("GenericAlias", PyTuple_GET_SIZE(args), 2, 2)) {
818
        return NULL;
819
    }
820
    PyObject *origin = PyTuple_GET_ITEM(args, 0);
821
    PyObject *arguments = PyTuple_GET_ITEM(args, 1);
822
    gaobject *self = (gaobject *)type->tp_alloc(type, 0);
823
    if (self == NULL) {
  Branch (823:9): [True: 0, False: 628]
824
        return NULL;
825
    }
826
    if (!setup_ga(self, origin, arguments)) {
  Branch (826:9): [True: 0, False: 628]
827
        Py_DECREF(self);
828
        return NULL;
829
    }
830
    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
ga_iternext(gaiterobject *gi) {
839
    if (gi->obj == NULL) {
  Branch (839:9): [True: 245, False: 349]
840
        PyErr_SetNone(PyExc_StopIteration);
841
        return NULL;
842
    }
843
    gaobject *alias = (gaobject *)gi->obj;
844
    PyObject *starred_alias = Py_GenericAlias(alias->origin, alias->args);
845
    if (starred_alias == NULL) {
  Branch (845:9): [True: 0, False: 349]
846
        return NULL;
847
    }
848
    ((gaobject *)starred_alias)->starred = true;
849
    Py_SETREF(gi->obj, NULL);
850
    return starred_alias;
851
}
852
853
static void
854
ga_iter_dealloc(gaiterobject *gi) {
855
    PyObject_GC_UnTrack(gi);
856
    Py_XDECREF(gi->obj);
857
    PyObject_GC_Del(gi);
858
}
859
860
static int
861
ga_iter_traverse(gaiterobject *gi, visitproc visit, void *arg)
862
{
863
    Py_VISIT(gi->obj);
864
    return 0;
865
}
866
867
static int
868
ga_iter_clear(PyObject *self) {
869
    gaiterobject *gi = (gaiterobject *)self;
870
    Py_CLEAR(gi->obj);
871
    return 0;
872
}
873
874
static PyObject *
875
ga_iter_reduce(PyObject *self, PyObject *Py_UNUSED(ignored))
876
{
877
    gaiterobject *gi = (gaiterobject *)self;
878
    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
ga_iter(PyObject *self) {
903
    gaiterobject *gi = PyObject_GC_New(gaiterobject, &_Py_GenericAliasIterType);
904
    if (gi == NULL) {
  Branch (904:9): [True: 0, False: 448]
905
        return NULL;
906
    }
907
    gi->obj = Py_NewRef(self);
908
    PyObject_GC_Track(gi);
909
    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
Py_GenericAlias(PyObject *origin, PyObject *args)
943
{
944
    gaobject *alias = (gaobject*) PyType_GenericAlloc(
945
            (PyTypeObject *)&Py_GenericAliasType, 0);
946
    if (alias == NULL) {
  Branch (946:9): [True: 0, False: 2.32k]
947
        return NULL;
948
    }
949
    if (!setup_ga(alias, origin, args)) {
  Branch (949:9): [True: 0, False: 2.32k]
950
        Py_DECREF(alias);
951
        return NULL;
952
    }
953
    return (PyObject *)alias;
954
}