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