@@ -2,9 +2,10 @@ use crate::{
2
2
builtins:: { PyList , PyStr , PyStrRef , PyTuple , PyTupleRef , PyType , PyTypeRef } ,
3
3
common:: hash,
4
4
function:: { FuncArgs , IntoPyObject } ,
5
- types:: { Callable , Comparable , Constructor , GetAttr , Hashable , PyComparisonOp } ,
6
- IdProtocol , PyClassImpl , PyComparisonValue , PyContext , PyObject , PyObjectRef , PyRef , PyResult ,
7
- PyValue , TryFromObject , TypeProtocol , VirtualMachine ,
5
+ protocol:: PyMappingMethods ,
6
+ types:: { AsMapping , Callable , Comparable , Constructor , GetAttr , Hashable , PyComparisonOp } ,
7
+ IdProtocol , ItemProtocol , PyClassImpl , PyComparisonValue , PyContext , PyObject , PyObjectRef ,
8
+ PyObjectView , PyRef , PyResult , PyValue , TryFromObject , TypeProtocol , VirtualMachine ,
8
9
} ;
9
10
use std:: fmt;
10
11
@@ -53,7 +54,7 @@ impl Constructor for PyGenericAlias {
53
54
}
54
55
55
56
#[ pyimpl(
56
- with( Callable , Comparable , Constructor , GetAttr , Hashable ) ,
57
+ with( AsMapping , Callable , Comparable , Constructor , GetAttr , Hashable ) ,
57
58
flags( BASETYPE )
58
59
) ]
59
60
impl PyGenericAlias {
@@ -192,6 +193,119 @@ fn make_parameters(args: &PyTupleRef, vm: &VirtualMachine) -> PyTupleRef {
192
193
PyTuple :: new_ref ( parameters, & vm. ctx )
193
194
}
194
195
196
+ #[ inline]
197
+ fn tuple_index ( tuple : & PyTupleRef , item : & PyObjectRef ) -> Option < usize > {
198
+ tuple. as_slice ( ) . iter ( ) . position ( |element| element. is ( item) )
199
+ }
200
+
201
+ fn subs_tvars (
202
+ obj : PyObjectRef ,
203
+ params : & PyTupleRef ,
204
+ argitems : & [ PyObjectRef ] ,
205
+ vm : & VirtualMachine ,
206
+ ) -> PyResult {
207
+ obj. clone_class ( )
208
+ . get_attr ( "__parameters__" )
209
+ . and_then ( |sub_params| {
210
+ PyTupleRef :: try_from_object ( vm, sub_params)
211
+ . ok ( )
212
+ . map ( |sub_params| {
213
+ let sub_args = sub_params
214
+ . as_slice ( )
215
+ . iter ( )
216
+ . map ( |arg| {
217
+ if let Some ( idx) = tuple_index ( params, arg) {
218
+ argitems[ idx] . clone ( )
219
+ } else {
220
+ arg. clone ( )
221
+ }
222
+ } )
223
+ . collect :: < Vec < _ > > ( ) ;
224
+ let sub_args: PyObjectRef = PyTuple :: new_ref ( sub_args, & vm. ctx ) . into ( ) ;
225
+ obj. get_item ( sub_args, vm)
226
+ } )
227
+ } )
228
+ . unwrap_or ( Ok ( obj) )
229
+ }
230
+
231
+ impl AsMapping for PyGenericAlias {
232
+ fn as_mapping ( _zelf : & PyObjectView < Self > , _vm : & VirtualMachine ) -> PyMappingMethods {
233
+ PyMappingMethods {
234
+ length : None ,
235
+ subscript : Some ( Self :: subscript) ,
236
+ ass_subscript : None ,
237
+ }
238
+ }
239
+
240
+ #[ cold]
241
+ fn length ( zelf : PyObjectRef , _vm : & VirtualMachine ) -> PyResult < usize > {
242
+ unreachable ! ( "length not implemented for {}" , zelf. class( ) )
243
+ }
244
+
245
+ fn subscript ( zelf : PyObjectRef , needle : PyObjectRef , vm : & VirtualMachine ) -> PyResult {
246
+ Self :: downcast ( zelf, vm) . map ( |zelf| {
247
+ let num_params = zelf. parameters . len ( ) ;
248
+ if num_params == 0 {
249
+ return Err ( vm. new_type_error ( format ! (
250
+ "There are no type variables left in {}" ,
251
+ zelf. repr( vm) ?
252
+ ) ) ) ;
253
+ }
254
+
255
+ let items = PyTupleRef :: try_from_object ( vm, needle. clone ( ) ) ;
256
+ let arg_items = match items {
257
+ Ok ( ref tuple) => tuple. as_slice ( ) ,
258
+ Err ( _) => std:: slice:: from_ref ( & needle) ,
259
+ } ;
260
+
261
+ let num_items = arg_items. len ( ) ;
262
+ if num_params != num_items {
263
+ let plural = if num_items > num_params {
264
+ "many"
265
+ } else {
266
+ "few"
267
+ } ;
268
+ return Err ( vm. new_type_error ( format ! (
269
+ "Too {} arguments for {}" ,
270
+ plural,
271
+ zelf. repr( vm) ?
272
+ ) ) ) ;
273
+ }
274
+
275
+ let new_args = zelf
276
+ . args
277
+ . as_slice ( )
278
+ . iter ( )
279
+ . map ( |arg| {
280
+ if is_typevar ( arg) {
281
+ let idx = tuple_index ( & zelf. parameters , arg) . unwrap ( ) ;
282
+ Ok ( arg_items[ idx] . clone ( ) )
283
+ } else {
284
+ subs_tvars ( arg. clone ( ) , & zelf. parameters , arg_items, vm)
285
+ }
286
+ } )
287
+ . collect :: < PyResult < Vec < _ > > > ( ) ?;
288
+
289
+ Ok ( PyGenericAlias :: new (
290
+ zelf. origin . clone ( ) ,
291
+ PyTuple :: new_ref ( new_args, & vm. ctx ) . into ( ) ,
292
+ vm,
293
+ )
294
+ . into_object ( vm) )
295
+ } ) ?
296
+ }
297
+
298
+ #[ cold]
299
+ fn ass_subscript (
300
+ zelf : PyObjectRef ,
301
+ _needle : PyObjectRef ,
302
+ _value : Option < PyObjectRef > ,
303
+ _vm : & VirtualMachine ,
304
+ ) -> PyResult < ( ) > {
305
+ unreachable ! ( "ass_subscript not implemented for {}" , zelf. class( ) )
306
+ }
307
+ }
308
+
195
309
impl Callable for PyGenericAlias {
196
310
type Args = FuncArgs ;
197
311
fn call ( zelf : & crate :: PyObjectView < Self > , args : FuncArgs , vm : & VirtualMachine ) -> PyResult {
0 commit comments