Coverage Report

Created: 2026-08-31 07:18

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