@@ -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,111 @@ 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
+ let sub_params = obj. clone ( ) . get_attr ( "__parameters__" , vm) ?;
208
+ if let Ok ( sub_params) = PyTupleRef :: try_from_object ( vm, sub_params) {
209
+ let sub_args = sub_params
210
+ . as_slice ( )
211
+ . iter ( )
212
+ . map ( |arg| {
213
+ if let Some ( idx) = tuple_index ( params, arg) {
214
+ argitems[ idx] . clone ( )
215
+ } else {
216
+ arg. clone ( )
217
+ }
218
+ } )
219
+ . collect :: < Vec < _ > > ( ) ;
220
+ let sub_args: PyObjectRef = PyTuple :: new_ref ( sub_args, & vm. ctx ) . into ( ) ;
221
+ obj. get_item ( sub_args, vm)
222
+ } else {
223
+ Ok ( obj)
224
+ }
225
+ }
226
+
227
+ impl AsMapping for PyGenericAlias {
228
+ fn as_mapping ( _zelf : & PyObjectView < Self > , _vm : & VirtualMachine ) -> PyMappingMethods {
229
+ PyMappingMethods {
230
+ length : None ,
231
+ subscript : Some ( Self :: subscript) ,
232
+ ass_subscript : None ,
233
+ }
234
+ }
235
+
236
+ #[ cold]
237
+ fn length ( zelf : PyObjectRef , _vm : & VirtualMachine ) -> PyResult < usize > {
238
+ unreachable ! ( "length not implemented for {}" , zelf. class( ) )
239
+ }
240
+
241
+ fn subscript ( zelf : PyObjectRef , needle : PyObjectRef , vm : & VirtualMachine ) -> PyResult {
242
+ Self :: downcast ( zelf, vm) . map ( |zelf| {
243
+ let num_params = zelf. parameters . len ( ) ;
244
+ if num_params == 0 {
245
+ return Err ( vm. new_type_error ( format ! (
246
+ "There are no type variables left in {}" ,
247
+ zelf. repr( vm) ?
248
+ ) ) ) ;
249
+ }
250
+
251
+ let items = PyTupleRef :: try_from_object ( vm, needle. clone ( ) ) ;
252
+ let arg_items = match items {
253
+ Ok ( ref tuple) => tuple. as_slice ( ) ,
254
+ Err ( _) => std:: slice:: from_ref ( & needle) ,
255
+ } ;
256
+
257
+ let num_items = arg_items. len ( ) ;
258
+ if num_params != num_items {
259
+ let plural = if num_items > num_params {
260
+ "many"
261
+ } else {
262
+ "few"
263
+ } ;
264
+ return Err ( vm. new_type_error ( format ! (
265
+ "Too {} arguments for {}" ,
266
+ plural,
267
+ zelf. repr( vm) ?
268
+ ) ) ) ;
269
+ }
270
+
271
+ let mut new_args: Vec < PyObjectRef > = Vec :: with_capacity ( zelf. args . len ( ) ) ;
272
+ for arg in zelf. args . as_slice ( ) . iter ( ) {
273
+ if is_typevar ( arg) {
274
+ let idx = tuple_index ( & zelf. parameters , arg) . unwrap ( ) ;
275
+ new_args. push ( arg_items[ idx] . clone ( ) ) ;
276
+ } else {
277
+ new_args. push ( subs_tvars ( arg. clone ( ) , & zelf. parameters , arg_items, vm) ?) ;
278
+ }
279
+ }
280
+
281
+ Ok ( PyGenericAlias :: new (
282
+ zelf. origin . clone ( ) ,
283
+ PyTuple :: new_ref ( new_args, & vm. ctx ) . into ( ) ,
284
+ vm,
285
+ )
286
+ . into_object ( vm) )
287
+ } ) ?
288
+ }
289
+
290
+ #[ cold]
291
+ fn ass_subscript (
292
+ zelf : PyObjectRef ,
293
+ _needle : PyObjectRef ,
294
+ _value : Option < PyObjectRef > ,
295
+ _vm : & VirtualMachine ,
296
+ ) -> PyResult < ( ) > {
297
+ unreachable ! ( "ass_subscript not implemented for {}" , zelf. class( ) )
298
+ }
299
+ }
300
+
195
301
impl Callable for PyGenericAlias {
196
302
type Args = FuncArgs ;
197
303
fn call ( zelf : & crate :: PyObjectView < Self > , args : FuncArgs , vm : & VirtualMachine ) -> PyResult {
0 commit comments