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