@@ -182,28 +182,60 @@ tuple_index(PyObject *self, Py_ssize_t len, PyObject *item)
182
182
return -1 ;
183
183
}
184
184
185
- // tuple(t for t in args if isinstance(t, TypeVar))
185
+ static int
186
+ tuple_add (PyObject * self , Py_ssize_t len , PyObject * item )
187
+ {
188
+ if (tuple_index (self , len , item ) < 0 ) {
189
+ Py_INCREF (item );
190
+ PyTuple_SET_ITEM (self , len , item );
191
+ return 1 ;
192
+ }
193
+ return 0 ;
194
+ }
195
+
186
196
static PyObject *
187
197
make_parameters (PyObject * args )
188
198
{
189
- Py_ssize_t len = PyTuple_GET_SIZE (args );
199
+ Py_ssize_t nargs = PyTuple_GET_SIZE (args );
200
+ Py_ssize_t len = nargs ;
190
201
PyObject * parameters = PyTuple_New (len );
191
202
if (parameters == NULL )
192
203
return NULL ;
193
204
Py_ssize_t iparam = 0 ;
194
- for (Py_ssize_t iarg = 0 ; iarg < len ; iarg ++ ) {
205
+ for (Py_ssize_t iarg = 0 ; iarg < nargs ; iarg ++ ) {
195
206
PyObject * t = PyTuple_GET_ITEM (args , iarg );
196
207
int typevar = is_typevar (t );
197
208
if (typevar < 0 ) {
198
- Py_XDECREF (parameters );
209
+ Py_DECREF (parameters );
199
210
return NULL ;
200
211
}
201
212
if (typevar ) {
202
- if (tuple_index (parameters , iparam , t ) < 0 ) {
203
- Py_INCREF (t );
204
- PyTuple_SET_ITEM (parameters , iparam , t );
205
- iparam ++ ;
213
+ iparam += tuple_add (parameters , iparam , t );
214
+ }
215
+ else {
216
+ _Py_IDENTIFIER (__parameters__ );
217
+ PyObject * subparams ;
218
+ if (_PyObject_LookupAttrId (t , & PyId___parameters__ , & subparams ) < 0 ) {
219
+ Py_DECREF (parameters );
220
+ return NULL ;
221
+ }
222
+ if (subparams && PyTuple_Check (subparams )) {
223
+ Py_ssize_t len2 = PyTuple_GET_SIZE (subparams );
224
+ Py_ssize_t needed = len2 - 1 - (iarg - iparam );
225
+ if (needed > 0 ) {
226
+ len += needed ;
227
+ if (_PyTuple_Resize (& parameters , len ) < 0 ) {
228
+ Py_DECREF (subparams );
229
+ Py_DECREF (parameters );
230
+ return NULL ;
231
+ }
232
+ }
233
+ for (Py_ssize_t j = 0 ; j < len2 ; j ++ ) {
234
+ PyObject * t2 = PyTuple_GET_ITEM (subparams , j );
235
+ iparam += tuple_add (parameters , iparam , t2 );
236
+ }
206
237
}
238
+ Py_XDECREF (subparams );
207
239
}
208
240
}
209
241
if (iparam < len ) {
@@ -215,6 +247,48 @@ make_parameters(PyObject *args)
215
247
return parameters ;
216
248
}
217
249
250
+ /* If obj is a generic alias, substitute type variables params
251
+ with substitutions argitems. For example, if obj is list[T],
252
+ params is (T, S), and argitems is (str, int), return list[str].
253
+ If obj doesn't have a __parameters__ attribute or that's not
254
+ a non-empty tuple, return a new reference to obj. */
255
+ static PyObject *
256
+ subs_tvars (PyObject * obj , PyObject * params , PyObject * * argitems )
257
+ {
258
+ _Py_IDENTIFIER (__parameters__ );
259
+ PyObject * subparams ;
260
+ if (_PyObject_LookupAttrId (obj , & PyId___parameters__ , & subparams ) < 0 ) {
261
+ return NULL ;
262
+ }
263
+ if (subparams && PyTuple_Check (subparams ) && PyTuple_GET_SIZE (subparams )) {
264
+ Py_ssize_t nparams = PyTuple_GET_SIZE (params );
265
+ Py_ssize_t nsubargs = PyTuple_GET_SIZE (subparams );
266
+ PyObject * subargs = PyTuple_New (nsubargs );
267
+ if (subargs == NULL ) {
268
+ Py_DECREF (subparams );
269
+ return NULL ;
270
+ }
271
+ for (Py_ssize_t i = 0 ; i < nsubargs ; ++ i ) {
272
+ PyObject * arg = PyTuple_GET_ITEM (subparams , i );
273
+ Py_ssize_t iparam = tuple_index (params , nparams , arg );
274
+ if (iparam >= 0 ) {
275
+ arg = argitems [iparam ];
276
+ }
277
+ Py_INCREF (arg );
278
+ PyTuple_SET_ITEM (subargs , i , arg );
279
+ }
280
+
281
+ obj = PyObject_GetItem (obj , subargs );
282
+
283
+ Py_DECREF (subargs );
284
+ }
285
+ else {
286
+ Py_INCREF (obj );
287
+ }
288
+ Py_XDECREF (subparams );
289
+ return obj ;
290
+ }
291
+
218
292
static PyObject *
219
293
ga_getitem (PyObject * self , PyObject * item )
220
294
{
@@ -233,17 +307,25 @@ ga_getitem(PyObject *self, PyObject *item)
233
307
self );
234
308
}
235
309
int is_tuple = PyTuple_Check (item );
236
- Py_ssize_t nitem = is_tuple ? PyTuple_GET_SIZE (item ) : 1 ;
237
- if (nitem != nparams ) {
310
+ Py_ssize_t nitems = is_tuple ? PyTuple_GET_SIZE (item ) : 1 ;
311
+ PyObject * * argitems = is_tuple ? & PyTuple_GET_ITEM (item , 0 ) : & item ;
312
+ if (nitems != nparams ) {
238
313
return PyErr_Format (PyExc_TypeError ,
239
314
"Too %s arguments for %R" ,
240
- nitem > nparams ? "many" : "few" ,
315
+ nitems > nparams ? "many" : "few" ,
241
316
self );
242
317
}
318
+ /* Replace all type variables (specified by alias->parameters)
319
+ with corresponding values specified by argitems.
320
+ t = list[T]; t[int] -> newargs = [int]
321
+ t = dict[str, T]; t[int] -> newargs = [str, int]
322
+ t = dict[T, list[S]]; t[str, int] -> newargs = [str, list[int]]
323
+ */
243
324
Py_ssize_t nargs = PyTuple_GET_SIZE (alias -> args );
244
325
PyObject * newargs = PyTuple_New (nargs );
245
- if (newargs == NULL )
326
+ if (newargs == NULL ) {
246
327
return NULL ;
328
+ }
247
329
for (Py_ssize_t iarg = 0 ; iarg < nargs ; iarg ++ ) {
248
330
PyObject * arg = PyTuple_GET_ITEM (alias -> args , iarg );
249
331
int typevar = is_typevar (arg );
@@ -254,18 +336,21 @@ ga_getitem(PyObject *self, PyObject *item)
254
336
if (typevar ) {
255
337
Py_ssize_t iparam = tuple_index (alias -> parameters , nparams , arg );
256
338
assert (iparam >= 0 );
257
- if (is_tuple ) {
258
- arg = PyTuple_GET_ITEM (item , iparam );
259
- }
260
- else {
261
- assert (iparam == 0 );
262
- arg = item ;
339
+ arg = argitems [iparam ];
340
+ Py_INCREF (arg );
341
+ }
342
+ else {
343
+ arg = subs_tvars (arg , alias -> parameters , argitems );
344
+ if (arg == NULL ) {
345
+ Py_DECREF (newargs );
346
+ return NULL ;
263
347
}
264
348
}
265
- Py_INCREF (arg );
266
349
PyTuple_SET_ITEM (newargs , iarg , arg );
267
350
}
351
+
268
352
PyObject * res = Py_GenericAlias (alias -> origin , newargs );
353
+
269
354
Py_DECREF (newargs );
270
355
return res ;
271
356
}
0 commit comments