Coverage Report

Created: 2025-10-10 06:33

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