Coverage Report

Created: 2026-03-23 06:45

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