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