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