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