/home/mdboom/Work/builds/cpython/Objects/genericaliasobject.c
Line | Count | Source (jump to first uncovered line) |
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) { Branch (32:9): [True: 0, False: 2.95k]
|
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) { Branch (60:9): [True: 37, False: 313]
|
61 | // The Ellipsis object |
62 | r = PyUnicode_FromString("..."); |
63 | goto done; |
64 | } |
65 | |
66 | if (_PyObject_LookupAttr(p, &_Py_ID(__origin__), &tmp) < 0) { Branch (66:9): [True: 0, False: 313]
|
67 | goto done; |
68 | } |
69 | if (tmp != NULL) { Branch (69:9): [True: 15, False: 298]
|
70 | Py_DECREF(tmp); |
71 | if (_PyObject_LookupAttr(p, &_Py_ID(__args__), &tmp) < 0) { Branch (71:13): [True: 0, False: 15]
|
72 | goto done; |
73 | } |
74 | if (tmp != NULL) { Branch (74:13): [True: 15, False: 0]
|
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) { Branch (81:9): [True: 0, False: 298]
|
82 | goto done; |
83 | } |
84 | if (qualname == NULL) { Branch (84:9): [True: 72, False: 226]
|
85 | goto use_repr; |
86 | } |
87 | if (_PyObject_LookupAttr(p, &_Py_ID(__module__), &module) < 0) { Branch (87:9): [True: 0, False: 226]
|
88 | goto done; |
89 | } |
90 | if (module == NULL || module == Py_None) { Branch (90:9): [True: 0, False: 226]
Branch (90:27): [True: 0, False: 226]
|
91 | goto use_repr; |
92 | } |
93 | |
94 | // Looks like a class |
95 | if (PyUnicode_Check(module) && |
96 | _PyUnicode_EqualToASCIIString(module, "builtins")) Branch (96:9): [True: 210, False: 16]
|
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) { Branch (113:9): [True: 0, False: 350]
|
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 PyObject * |
125 | ga_repr(PyObject *self) |
126 | { |
127 | gaobject *alias = (gaobject *)self; |
128 | Py_ssize_t len = PyTuple_GET_SIZE(alias->args); |
129 | |
130 | _PyUnicodeWriter writer; |
131 | _PyUnicodeWriter_Init(&writer); |
132 | |
133 | if (alias->starred) { Branch (133:9): [True: 29, False: 107]
|
134 | if (_PyUnicodeWriter_WriteASCIIString(&writer, "*", 1) < 0) { Branch (134:13): [True: 0, False: 29]
|
135 | goto error; |
136 | } |
137 | } |
138 | if (ga_repr_item(&writer, alias->origin) < 0) { Branch (138:9): [True: 0, False: 136]
|
139 | goto error; |
140 | } |
141 | if (_PyUnicodeWriter_WriteASCIIString(&writer, "[", 1) < 0) { Branch (141:9): [True: 0, False: 136]
|
142 | goto error; |
143 | } |
144 | for (Py_ssize_t i = 0; 136 i < len; i++214 ) { Branch (144:28): [True: 214, False: 136]
|
145 | if (i > 0) { Branch (145:13): [True: 79, False: 135]
|
146 | if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ", 2) < 0) { Branch (146:17): [True: 0, False: 79]
|
147 | goto error; |
148 | } |
149 | } |
150 | PyObject *p = PyTuple_GET_ITEM(alias->args, i); |
151 | if (ga_repr_item(&writer, p) < 0) { Branch (151:13): [True: 0, False: 214]
|
152 | goto error; |
153 | } |
154 | } |
155 | if (len == 0) { Branch (155:9): [True: 1, False: 135]
|
156 | // for something like tuple[()] we should print a "()" |
157 | if (_PyUnicodeWriter_WriteASCIIString(&writer, "()", 2) < 0) { Branch (157:13): [True: 0, False: 1]
|
158 | goto error; |
159 | } |
160 | } |
161 | if (_PyUnicodeWriter_WriteASCIIString(&writer, "]", 1) < 0) { Branch (161:9): [True: 0, False: 136]
|
162 | goto error; |
163 | } |
164 | return _PyUnicodeWriter_Finish(&writer); |
165 | error: |
166 | _PyUnicodeWriter_Dealloc(&writer); |
167 | 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 | tuple_index(PyObject *self, Py_ssize_t len, PyObject *item) |
173 | { |
174 | for (Py_ssize_t i = 0; i < len; i++230 ) { Branch (174:28): [True: 576, False: 466]
|
175 | if (PyTuple_GET_ITEM(self, i) == item) { Branch (175:13): [True: 346, False: 230]
|
176 | return i; |
177 | } |
178 | } |
179 | return -1; |
180 | } |
181 | |
182 | static int |
183 | tuple_add(PyObject *self, Py_ssize_t len, PyObject *item) |
184 | { |
185 | if (tuple_index(self, len, item) < 0) { Branch (185:9): [True: 466, False: 5]
|
186 | Py_INCREF(item); |
187 | PyTuple_SET_ITEM(self, len, item); |
188 | return 1; |
189 | } |
190 | return 0; |
191 | } |
192 | |
193 | static Py_ssize_t |
194 | tuple_extend(PyObject **dst, Py_ssize_t dstindex, |
195 | PyObject **src, Py_ssize_t count) |
196 | { |
197 | assert(count >= 0); |
198 | if (_PyTuple_Resize(dst, PyTuple_GET_SIZE(*dst) + count - 1) != 0) { Branch (198:9): [True: 0, False: 134]
|
199 | return -1; |
200 | } |
201 | assert(dstindex + count <= PyTuple_GET_SIZE(*dst)); |
202 | for (Py_ssize_t i = 0; i < count; ++i172 ) { Branch (202:28): [True: 172, False: 134]
|
203 | PyObject *item = src[i]; |
204 | Py_INCREF(item); |
205 | PyTuple_SET_ITEM(*dst, dstindex + i, item); |
206 | } |
207 | return dstindex + count; |
208 | } |
209 | |
210 | PyObject * |
211 | _Py_make_parameters(PyObject *args) |
212 | { |
213 | Py_ssize_t nargs = PyTuple_GET_SIZE(args); |
214 | Py_ssize_t len = nargs; |
215 | PyObject *parameters = PyTuple_New(len); |
216 | if (parameters == NULL) Branch (216:9): [True: 0, False: 828]
|
217 | return NULL; |
218 | Py_ssize_t iparam = 0; |
219 | for (Py_ssize_t iarg = 0; iarg < nargs; iarg++1.29k ) { Branch (219:31): [True: 1.29k, False: 828]
|
220 | PyObject *t = PyTuple_GET_ITEM(args, iarg); |
221 | PyObject *subst; |
222 | if (_PyObject_LookupAttr(t, &_Py_ID(__typing_subst__), &subst) < 0) { Branch (222:13): [True: 0, False: 1.29k]
|
223 | Py_DECREF(parameters); |
224 | return NULL; |
225 | } |
226 | if (subst) { Branch (226:13): [True: 309, False: 989]
|
227 | iparam += tuple_add(parameters, iparam, t); |
228 | Py_DECREF(subst); |
229 | } |
230 | else { |
231 | PyObject *subparams; |
232 | if (_PyObject_LookupAttr(t, &_Py_ID(__parameters__), Branch (232:17): [True: 0, False: 989]
|
233 | &subparams) < 0) { |
234 | Py_DECREF(parameters); |
235 | return NULL; |
236 | } |
237 | if (subparams && PyTuple_Check302 (subparams)) { Branch (237:17): [True: 302, False: 687]
|
238 | Py_ssize_t len2 = PyTuple_GET_SIZE(subparams); |
239 | Py_ssize_t needed = len2 - 1 - (iarg - iparam); |
240 | if (needed > 0) { Branch (240:21): [True: 11, False: 291]
|
241 | len += needed; |
242 | if (_PyTuple_Resize(¶meters, len) < 0) { Branch (242:25): [True: 0, False: 11]
|
243 | Py_DECREF(subparams); |
244 | Py_DECREF(parameters); |
245 | return NULL; |
246 | } |
247 | } |
248 | for (Py_ssize_t j = 0; 302 j < len2; j++162 ) { Branch (248:40): [True: 162, False: 302]
|
249 | PyObject *t2 = PyTuple_GET_ITEM(subparams, j); |
250 | iparam += tuple_add(parameters, iparam, t2); |
251 | } |
252 | } |
253 | Py_XDECREF(subparams); |
254 | } |
255 | } |
256 | if (iparam < len) { Branch (256:9): [True: 568, False: 260]
|
257 | if (_PyTuple_Resize(¶meters, iparam) < 0) { Branch (257:13): [True: 0, False: 568]
|
258 | Py_XDECREF(parameters); |
259 | return NULL; |
260 | } |
261 | } |
262 | 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 | subs_tvars(PyObject *obj, PyObject *params, |
272 | PyObject **argitems, Py_ssize_t nargs) |
273 | { |
274 | PyObject *subparams; |
275 | if (_PyObject_LookupAttr(obj, &_Py_ID(__parameters__), &subparams) < 0) { Branch (275:9): [True: 0, False: 176]
|
276 | return NULL; |
277 | } |
278 | if (subparams && PyTuple_Check(subparams) && PyTuple_GET_SIZE129 (subparams)) { Branch (278:9): [True: 129, False: 47]
|
279 | Py_ssize_t nparams = PyTuple_GET_SIZE(params); |
280 | Py_ssize_t nsubargs = PyTuple_GET_SIZE(subparams); |
281 | PyObject *subargs = PyTuple_New(nsubargs); |
282 | if (subargs == NULL) { Branch (282:13): [True: 0, False: 117]
|
283 | Py_DECREF(subparams); |
284 | return NULL; |
285 | } |
286 | Py_ssize_t j = 0; |
287 | for (Py_ssize_t i = 0; i < nsubargs; ++i125 ) { Branch (287:32): [True: 125, False: 117]
|
288 | PyObject *arg = PyTuple_GET_ITEM(subparams, i); |
289 | Py_ssize_t iparam = tuple_index(params, nparams, arg); |
290 | if (iparam >= 0) { Branch (290:17): [True: 125, False: 0]
|
291 | PyObject *param = PyTuple_GET_ITEM(params, iparam); |
292 | arg = argitems[iparam]; |
293 | if (Py_TYPE(param)->tp_iter && PyTuple_Check72 (arg)) { // TypeVarTuple Branch (293:21): [True: 72, False: 53]
|
294 | j = tuple_extend(&subargs, j, |
295 | &PyTuple_GET_ITEM(arg, 0), |
296 | PyTuple_GET_SIZE(arg)); |
297 | if (j < 0) { Branch (297:25): [True: 0, False: 72]
|
298 | return NULL; |
299 | } |
300 | continue; |
301 | } |
302 | } |
303 | Py_INCREF(arg); |
304 | PyTuple_SET_ITEM(subargs, j, arg); |
305 | j++; |
306 | } |
307 | assert(j == PyTuple_GET_SIZE(subargs)); |
308 | |
309 | obj = PyObject_GetItem(obj, subargs); |
310 | |
311 | Py_DECREF(subargs); |
312 | } |
313 | else { |
314 | Py_INCREF(obj); |
315 | } |
316 | Py_XDECREF(subparams); |
317 | return obj; |
318 | } |
319 | |
320 | static int |
321 | _is_unpacked_typevartuple(PyObject *arg) |
322 | { |
323 | PyObject *tmp; |
324 | if (PyType_Check(arg)) { // TODO: Add test |
325 | return 0; |
326 | } |
327 | int res = _PyObject_LookupAttr(arg, &_Py_ID(__typing_is_unpacked_typevartuple__), &tmp); |
328 | if (res > 0) { Branch (328:9): [True: 71, False: 288]
|
329 | res = PyObject_IsTrue(tmp); |
330 | Py_DECREF(tmp); |
331 | } |
332 | return res; |
333 | } |
334 | |
335 | static PyObject * |
336 | _unpacked_tuple_args(PyObject *arg) |
337 | { |
338 | PyObject *result; |
339 | assert(!PyType_Check(arg)); |
340 | // Fast path |
341 | if (_PyGenericAlias_Check(arg) && |
342 | ((gaobject *)arg)->starred51 && Branch (342:13): [True: 44, False: 7]
|
343 | ((gaobject *)arg)->origin == (PyObject *)&PyTuple_Type44 ) Branch (343:13): [True: 44, False: 0]
|
344 | { |
345 | result = ((gaobject *)arg)->args; |
346 | Py_INCREF(result); |
347 | return result; |
348 | } |
349 | |
350 | if (_PyObject_LookupAttr(arg, &_Py_ID(__typing_unpacked_tuple_args__), &result) > 0) { Branch (350:9): [True: 61, False: 60]
|
351 | if (result == Py_None) { Branch (351:13): [True: 17, False: 44]
|
352 | Py_DECREF(result); |
353 | return NULL; |
354 | } |
355 | return result; |
356 | } |
357 | return NULL; |
358 | } |
359 | |
360 | static PyObject * |
361 | _unpack_args(PyObject *item) |
362 | { |
363 | PyObject *newargs = PyList_New(0); |
364 | if (newargs == NULL) { Branch (364:9): [True: 0, False: 283]
|
365 | return NULL; |
366 | } |
367 | int is_tuple = PyTuple_Check(item); |
368 | Py_ssize_t nitems = is_tuple ? PyTuple_GET_SIZE240 (item) : 143 ; Branch (368:25): [True: 240, False: 43]
|
369 | PyObject **argitems = is_tuple ? &240 PyTuple_GET_ITEM240 (item, 0) : &item43 ; Branch (369:27): [True: 240, False: 43]
|
370 | for (Py_ssize_t i = 0; i < nitems; i++415 ) { Branch (370:28): [True: 415, False: 283]
|
371 | item = argitems[i]; |
372 | if (!PyType_Check(item)) { Branch (372:13): [True: 165, False: 250]
|
373 | PyObject *subargs = _unpacked_tuple_args(item); |
374 | if (subargs != NULL && Branch (374:17): [True: 88, False: 77]
|
375 | PyTuple_Check(subargs) && |
376 | !(88 PyTuple_GET_SIZE88 (subargs) && |
377 | PyTuple_GET_ITEM78 (subargs, PyTuple_GET_SIZE(subargs)-1) == 78 Py_Ellipsis78 )) Branch (377:19): [True: 34, False: 44]
|
378 | { |
379 | if (PyList_SetSlice(newargs, PY_SSIZE_T_MAX, PY_SSIZE_T_MAX, subargs) < 0) { Branch (379:21): [True: 0, False: 54]
|
380 | Py_DECREF(subargs); |
381 | Py_DECREF(newargs); |
382 | return NULL; |
383 | } |
384 | Py_DECREF(subargs); |
385 | continue; |
386 | } |
387 | Py_XDECREF(subargs); |
388 | if (PyErr_Occurred()) { Branch (388:17): [True: 0, False: 111]
|
389 | Py_DECREF(newargs); |
390 | return NULL; |
391 | } |
392 | } |
393 | if (PyList_Append(newargs, item) < 0) { Branch (393:13): [True: 0, False: 361]
|
394 | Py_DECREF(newargs); |
395 | return NULL; |
396 | } |
397 | } |
398 | Py_SETREF(newargs, PySequence_Tuple(newargs)); |
399 | return newargs; |
400 | } |
401 | |
402 | PyObject * |
403 | _Py_subs_parameters(PyObject *self, PyObject *args, PyObject *parameters, PyObject *item) |
404 | { |
405 | Py_ssize_t nparams = PyTuple_GET_SIZE(parameters); |
406 | if (nparams == 0) { Branch (406:9): [True: 3, False: 283]
|
407 | return PyErr_Format(PyExc_TypeError, |
408 | "%R is not a generic class", |
409 | self); |
410 | } |
411 | item = _unpack_args(item); |
412 | for (Py_ssize_t i = 0; i < nparams; i++411 ) { Branch (412:28): [True: 417, False: 277]
|
413 | PyObject *param = PyTuple_GET_ITEM(parameters, i); |
414 | PyObject *prepare, *tmp; |
415 | if (_PyObject_LookupAttr(param, &_Py_ID(__typing_prepare_subst__), &prepare) < 0) { Branch (415:13): [True: 0, False: 417]
|
416 | Py_DECREF(item); |
417 | return NULL; |
418 | } |
419 | if (prepare && prepare != 116 Py_None116 ) { Branch (419:13): [True: 116, False: 301]
Branch (419:24): [True: 116, False: 0]
|
420 | if (PyTuple_Check(item)) { |
421 | tmp = PyObject_CallFunction(prepare, "OO", self, item); |
422 | } |
423 | else { |
424 | tmp = PyObject_CallFunction(prepare, "O(O)", self, item); |
425 | } |
426 | Py_DECREF(prepare); |
427 | Py_SETREF(item, tmp); |
428 | if (item == NULL) { Branch (428:17): [True: 6, False: 110]
|
429 | return NULL; |
430 | } |
431 | } |
432 | } |
433 | int is_tuple = PyTuple_Check(item); |
434 | Py_ssize_t nitems = is_tuple ? PyTuple_GET_SIZE(item) : 10 ; Branch (434:25): [True: 277, False: 0]
|
435 | PyObject **argitems = is_tuple ? &PyTuple_GET_ITEM(item, 0) : &item0 ; Branch (435:27): [True: 277, False: 0]
|
436 | if (nitems != nparams) { Branch (436:9): [True: 35, False: 242]
|
437 | Py_DECREF(item); |
438 | return PyErr_Format(PyExc_TypeError, |
439 | "Too %s arguments for %R; actual %zd, expected %zd", |
440 | nitems > nparams ? "many"17 : "few"18 , Branch (440:29): [True: 17, False: 18]
|
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 | Py_ssize_t nargs = PyTuple_GET_SIZE(args); |
450 | PyObject *newargs = PyTuple_New(nargs); |
451 | if (newargs == NULL) { Branch (451:9): [True: 0, False: 242]
|
452 | Py_DECREF(item); |
453 | return NULL; |
454 | } |
455 | for (Py_ssize_t iarg = 0, jarg = 0; 242 iarg < nargs; iarg++364 ) { Branch (455:41): [True: 392, False: 214]
|
456 | PyObject *arg = PyTuple_GET_ITEM(args, iarg); |
457 | int unpack = _is_unpacked_typevartuple(arg); |
458 | if (unpack < 0) { Branch (458:13): [True: 0, False: 392]
|
459 | Py_DECREF(newargs); |
460 | Py_DECREF(item); |
461 | return NULL; |
462 | } |
463 | PyObject *subst; |
464 | if (_PyObject_LookupAttr(arg, &_Py_ID(__typing_subst__), &subst) < 0) { Branch (464:13): [True: 0, False: 392]
|
465 | Py_DECREF(newargs); |
466 | Py_DECREF(item); |
467 | return NULL; |
468 | } |
469 | if (subst) { Branch (469:13): [True: 216, False: 176]
|
470 | Py_ssize_t iparam = tuple_index(parameters, nparams, arg); |
471 | assert(iparam >= 0); |
472 | arg = PyObject_CallOneArg(subst, argitems[iparam]); |
473 | Py_DECREF(subst); |
474 | } |
475 | else { |
476 | arg = subs_tvars(arg, parameters, argitems, nitems); |
477 | } |
478 | if (arg == NULL) { Branch (478:13): [True: 28, False: 364]
|
479 | Py_DECREF(newargs); |
480 | Py_DECREF(item); |
481 | return NULL; |
482 | } |
483 | if (unpack) { Branch (483:13): [True: 62, False: 302]
|
484 | jarg = tuple_extend(&newargs, jarg, |
485 | &PyTuple_GET_ITEM(arg, 0), PyTuple_GET_SIZE(arg)); |
486 | Py_DECREF(arg); |
487 | if (jarg < 0) { Branch (487:17): [True: 0, False: 62]
|
488 | Py_DECREF(item); |
489 | return NULL; |
490 | } |
491 | } |
492 | else { |
493 | PyTuple_SET_ITEM(newargs, jarg, arg); |
494 | jarg++; |
495 | } |
496 | } |
497 | |
498 | Py_DECREF(item); |
499 | 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 | ga_getitem(PyObject *self, PyObject *item) |
509 | { |
510 | gaobject *alias = (gaobject *)self; |
511 | // Populate __parameters__ if needed. |
512 | if (alias->parameters == NULL) { Branch (512:9): [True: 162, False: 119]
|
513 | alias->parameters = _Py_make_parameters(alias->args); |
514 | if (alias->parameters == NULL) { Branch (514:13): [True: 0, False: 162]
|
515 | return NULL; |
516 | } |
517 | } |
518 | |
519 | PyObject *newargs = _Py_subs_parameters(self, alias->args, alias->parameters, item); |
520 | if (newargs == NULL) { Branch (520:9): [True: 72, False: 209]
|
521 | return NULL; |
522 | } |
523 | |
524 | PyObject *res = Py_GenericAlias(alias->origin, newargs); |
525 | ((gaobject *)res)->starred = alias->starred; |
526 | |
527 | Py_DECREF(newargs); |
528 | return res; |
529 | } |
530 | |
531 | static PyMappingMethods ga_as_mapping = { |
532 | .mp_subscript = ga_getitem, |
533 | }; |
534 | |
535 | static Py_hash_t |
536 | ga_hash(PyObject *self) |
537 | { |
538 | gaobject *alias = (gaobject *)self; |
539 | // TODO: Hash in the hash for the origin |
540 | Py_hash_t h0 = PyObject_Hash(alias->origin); |
541 | if (h0 == -1) { Branch (541:9): [True: 0, False: 560]
|
542 | return -1; |
543 | } |
544 | Py_hash_t h1 = PyObject_Hash(alias->args); |
545 | if (h1 == -1) { Branch (545:9): [True: 0, False: 560]
|
546 | return -1; |
547 | } |
548 | return h0 ^ h1; |
549 | } |
550 | |
551 | static inline PyObject * |
552 | set_orig_class(PyObject *obj, PyObject *self) |
553 | { |
554 | if (obj != NULL) { Branch (554:9): [True: 42, False: 1]
|
555 | if (PyObject_SetAttr(obj, &_Py_ID(__orig_class__), self) < 0) { Branch (555:13): [True: 21, False: 21]
|
556 | if (!PyErr_ExceptionMatches(PyExc_AttributeError) && Branch (556:17): [True: 1, False: 20]
|
557 | !PyErr_ExceptionMatches(PyExc_TypeError)1 ) Branch (557:17): [True: 0, False: 1]
|
558 | { |
559 | Py_DECREF(obj); |
560 | return NULL; |
561 | } |
562 | PyErr_Clear(); |
563 | } |
564 | } |
565 | return obj; |
566 | } |
567 | |
568 | static PyObject * |
569 | ga_call(PyObject *self, PyObject *args, PyObject *kwds) |
570 | { |
571 | gaobject *alias = (gaobject *)self; |
572 | PyObject *obj = PyObject_Call(alias->origin, args, kwds); |
573 | return set_orig_class(obj, self); |
574 | } |
575 | |
576 | static PyObject * |
577 | ga_vectorcall(PyObject *self, PyObject *const *args, |
578 | size_t nargsf, PyObject *kwnames) |
579 | { |
580 | gaobject *alias = (gaobject *) self; |
581 | PyObject *obj = PyVectorcall_Function(alias->origin)(alias->origin, args, nargsf, kwnames); |
582 | 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 | ga_getattro(PyObject *self, PyObject *name) |
602 | { |
603 | gaobject *alias = (gaobject *)self; |
604 | if (PyUnicode_Check(name)) { |
605 | for (const char * const *p = attr_exceptions; ; p++20.4k ) { |
606 | if (*p == NULL) { Branch (606:17): [True: 522, False: 25.5k]
|
607 | return PyObject_GetAttr(alias->origin, name); |
608 | } |
609 | if (_PyUnicode_EqualToASCIIString(name, *p)) { Branch (609:17): [True: 5.08k, False: 20.4k]
|
610 | break; |
611 | } |
612 | } |
613 | } |
614 | return PyObject_GenericGetAttr(self, name); |
615 | } |
616 | |
617 | static PyObject * |
618 | ga_richcompare(PyObject *a, PyObject *b, int op) |
619 | { |
620 | if (!_PyGenericAlias_Check(b) || Branch (620:9): [True: 1.09k, False: 691]
|
621 | (691 op != 691 Py_EQ691 && op != 9 Py_NE9 )) Branch (621:10): [True: 9, False: 682]
Branch (621:25): [True: 0, False: 9]
|
622 | { |
623 | Py_RETURN_NOTIMPLEMENTED; |
624 | } |
625 | |
626 | if (op == Py_NE) { Branch (626:9): [True: 9, False: 682]
|
627 | PyObject *eq = ga_richcompare(a, b, Py_EQ); |
628 | if (eq == NULL) Branch (628:13): [True: 0, False: 9]
|
629 | return NULL; |
630 | Py_DECREF(eq); |
631 | if (eq == Py_True) { Branch (631:13): [True: 0, False: 9]
|
632 | Py_RETURN_FALSE; |
633 | } |
634 | else { |
635 | Py_RETURN_TRUE; |
636 | } |
637 | } |
638 | |
639 | gaobject *aa = (gaobject *)a; |
640 | gaobject *bb = (gaobject *)b; |
641 | if (aa->starred != bb->starred) { Branch (641:9): [True: 5, False: 677]
|
642 | Py_RETURN_FALSE; |
643 | } |
644 | int eq = PyObject_RichCompareBool(aa->origin, bb->origin, Py_EQ); |
645 | if (eq < 0) { Branch (645:9): [True: 0, False: 677]
|
646 | return NULL; |
647 | } |
648 | if (!eq) { Branch (648:9): [True: 16, False: 661]
|
649 | Py_RETURN_FALSE; |
650 | } |
651 | return PyObject_RichCompare(aa->args, bb->args, Py_EQ); |
652 | } |
653 | |
654 | static PyObject * |
655 | ga_mro_entries(PyObject *self, PyObject *args) |
656 | { |
657 | gaobject *alias = (gaobject *)self; |
658 | return PyTuple_Pack(1, alias->origin); |
659 | } |
660 | |
661 | static PyObject * |
662 | ga_instancecheck(PyObject *self, PyObject *Py_UNUSED(ignored)) |
663 | { |
664 | PyErr_SetString(PyExc_TypeError, |
665 | "isinstance() argument 2 cannot be a parameterized generic"); |
666 | return NULL; |
667 | } |
668 | |
669 | static PyObject * |
670 | ga_subclasscheck(PyObject *self, PyObject *Py_UNUSED(ignored)) |
671 | { |
672 | PyErr_SetString(PyExc_TypeError, |
673 | "issubclass() argument 2 cannot be a parameterized generic"); |
674 | return NULL; |
675 | } |
676 | |
677 | static PyObject * |
678 | ga_reduce(PyObject *self, PyObject *Py_UNUSED(ignored)) |
679 | { |
680 | gaobject *alias = (gaobject *)self; |
681 | if (alias->starred) { Branch (681:9): [True: 103, False: 327]
|
682 | PyObject *tmp = Py_GenericAlias(alias->origin, alias->args); |
683 | if (tmp != NULL) { Branch (683:13): [True: 103, False: 0]
|
684 | Py_SETREF(tmp, PyObject_GetIter(tmp)); |
685 | } |
686 | if (tmp == NULL) { Branch (686:13): [True: 0, False: 103]
|
687 | return NULL; |
688 | } |
689 | return Py_BuildValue("N(N)", _PyEval_GetBuiltin(&_Py_ID(next)), tmp); |
690 | } |
691 | return Py_BuildValue("O(OO)", Py_TYPE(alias), |
692 | alias->origin, alias->args); |
693 | } |
694 | |
695 | static PyObject * |
696 | ga_dir(PyObject *self, PyObject *Py_UNUSED(ignored)) |
697 | { |
698 | gaobject *alias = (gaobject *)self; |
699 | PyObject *dir = PyObject_Dir(alias->origin); |
700 | if (dir == NULL) { Branch (700:9): [True: 0, False: 1]
|
701 | return NULL; |
702 | } |
703 | |
704 | PyObject *dir_entry = NULL; |
705 | for (const char * const *p = attr_exceptions; ; p++11 ) { |
706 | if (*p == NULL) { Branch (706:13): [True: 1, False: 11]
|
707 | break; |
708 | } |
709 | else { |
710 | dir_entry = PyUnicode_FromString(*p); |
711 | if (dir_entry == NULL) { Branch (711:17): [True: 0, False: 11]
|
712 | goto error; |
713 | } |
714 | int contains = PySequence_Contains(dir, dir_entry); |
715 | if (contains < 0) { Branch (715:17): [True: 0, False: 11]
|
716 | goto error; |
717 | } |
718 | if (contains == 0 && PyList_Append(dir, dir_entry) < 08 ) { Branch (718:17): [True: 8, False: 3]
Branch (718:34): [True: 0, False: 8]
|
719 | goto error; |
720 | } |
721 | |
722 | Py_CLEAR(dir_entry); |
723 | } |
724 | } |
725 | return dir; |
726 | |
727 | error: |
728 | Py_DECREF(dir); |
729 | Py_XDECREF(dir_entry); |
730 | 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 | ga_parameters(PyObject *self, void *unused) |
751 | { |
752 | gaobject *alias = (gaobject *)self; |
753 | if (alias->parameters == NULL) { Branch (753:9): [True: 647, False: 483]
|
754 | alias->parameters = _Py_make_parameters(alias->args); |
755 | if (alias->parameters == NULL) { Branch (755:13): [True: 0, False: 647]
|
756 | return NULL; |
757 | } |
758 | } |
759 | Py_INCREF(alias->parameters); |
760 | return alias->parameters; |
761 | } |
762 | |
763 | static PyObject * |
764 | ga_unpacked_tuple_args(PyObject *self, void *unused) |
765 | { |
766 | gaobject *alias = (gaobject *)self; |
767 | if (alias->starred && alias->origin == (PyObject *)&PyTuple_Type170 ) { Branch (767:9): [True: 170, False: 34]
Branch (767:27): [True: 170, False: 0]
|
768 | Py_INCREF(alias->args); |
769 | return alias->args; |
770 | } |
771 | Py_RETURN_NONE34 ; |
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 | setup_ga(gaobject *alias, PyObject *origin, PyObject *args) { |
785 | if (!PyTuple_Check(args)) { Branch (785:9): [True: 1.22k, False: 1.73k]
|
786 | args = PyTuple_Pack(1, args); |
787 | if (args == NULL) { Branch (787:13): [True: 0, False: 1.22k]
|
788 | return 0; |
789 | } |
790 | } |
791 | else { |
792 | Py_INCREF(args); |
793 | } |
794 | |
795 | Py_INCREF(origin); |
796 | alias->origin = origin; |
797 | alias->args = args; |
798 | alias->parameters = NULL; |
799 | alias->weakreflist = NULL; |
800 | |
801 | if (PyVectorcall_Function(origin) != NULL) { Branch (801:9): [True: 2.56k, False: 388]
|
802 | alias->vectorcall = ga_vectorcall; |
803 | } |
804 | else { |
805 | alias->vectorcall = NULL; |
806 | } |
807 | |
808 | return 1; |
809 | } |
810 | |
811 | static PyObject * |
812 | ga_new(PyTypeObject *type, PyObject *args, PyObject *kwds) |
813 | { |
814 | if (!_PyArg_NoKeywords("GenericAlias", kwds)) { |
815 | return NULL; |
816 | } |
817 | if (!_PyArg_CheckPositional("GenericAlias", PyTuple_GET_SIZE(args), 2, 2)) { |
818 | return NULL; |
819 | } |
820 | PyObject *origin = PyTuple_GET_ITEM(args, 0); |
821 | PyObject *arguments = PyTuple_GET_ITEM(args, 1); |
822 | gaobject *self = (gaobject *)type->tp_alloc(type, 0); |
823 | if (self == NULL) { Branch (823:9): [True: 0, False: 628]
|
824 | return NULL; |
825 | } |
826 | if (!setup_ga(self, origin, arguments)) { Branch (826:9): [True: 0, False: 628]
|
827 | Py_DECREF(self); |
828 | return NULL; |
829 | } |
830 | 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 | ga_iternext(gaiterobject *gi) { |
839 | if (gi->obj == NULL) { Branch (839:9): [True: 245, False: 349]
|
840 | PyErr_SetNone(PyExc_StopIteration); |
841 | return NULL; |
842 | } |
843 | gaobject *alias = (gaobject *)gi->obj; |
844 | PyObject *starred_alias = Py_GenericAlias(alias->origin, alias->args); |
845 | if (starred_alias == NULL) { Branch (845:9): [True: 0, False: 349]
|
846 | return NULL; |
847 | } |
848 | ((gaobject *)starred_alias)->starred = true; |
849 | Py_SETREF(gi->obj, NULL); |
850 | return starred_alias; |
851 | } |
852 | |
853 | static void |
854 | ga_iter_dealloc(gaiterobject *gi) { |
855 | PyObject_GC_UnTrack(gi); |
856 | Py_XDECREF(gi->obj); |
857 | PyObject_GC_Del(gi); |
858 | } |
859 | |
860 | static int |
861 | ga_iter_traverse(gaiterobject *gi, visitproc visit, void *arg) |
862 | { |
863 | Py_VISIT(gi->obj); |
864 | return 0; |
865 | } |
866 | |
867 | static int |
868 | ga_iter_clear(PyObject *self) { |
869 | gaiterobject *gi = (gaiterobject *)self; |
870 | Py_CLEAR(gi->obj); |
871 | return 0; |
872 | } |
873 | |
874 | static PyObject * |
875 | ga_iter_reduce(PyObject *self, PyObject *Py_UNUSED(ignored)) |
876 | { |
877 | gaiterobject *gi = (gaiterobject *)self; |
878 | 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 | ga_iter(PyObject *self) { |
903 | gaiterobject *gi = PyObject_GC_New(gaiterobject, &_Py_GenericAliasIterType); |
904 | if (gi == NULL) { Branch (904:9): [True: 0, False: 448]
|
905 | return NULL; |
906 | } |
907 | gi->obj = Py_NewRef(self); |
908 | PyObject_GC_Track(gi); |
909 | 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 | Py_GenericAlias(PyObject *origin, PyObject *args) |
943 | { |
944 | gaobject *alias = (gaobject*) PyType_GenericAlloc( |
945 | (PyTypeObject *)&Py_GenericAliasType, 0); |
946 | if (alias == NULL) { Branch (946:9): [True: 0, False: 2.32k]
|
947 | return NULL; |
948 | } |
949 | if (!setup_ga(alias, origin, args)) { Branch (949:9): [True: 0, False: 2.32k]
|
950 | Py_DECREF(alias); |
951 | return NULL; |
952 | } |
953 | return (PyObject *)alias; |
954 | } |