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