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