(
obj: PyObjectRef,
params: &Py<PyTuple>,
arg_items: &[PyObjectRef],
vm: &VirtualMachine,
)
| 356 | } |
| 357 | |
| 358 | fn subs_tvars( |
| 359 | obj: PyObjectRef, |
| 360 | params: &Py<PyTuple>, |
| 361 | arg_items: &[PyObjectRef], |
| 362 | vm: &VirtualMachine, |
| 363 | ) -> PyResult { |
| 364 | obj.get_attr(identifier!(vm, __parameters__), vm) |
| 365 | .ok() |
| 366 | .and_then(|sub_params| { |
| 367 | PyTupleRef::try_from_object(vm, sub_params) |
| 368 | .ok() |
| 369 | .filter(|sub_params| !sub_params.is_empty()) |
| 370 | .map(|sub_params| { |
| 371 | let mut sub_args = Vec::new(); |
| 372 | |
| 373 | for arg in sub_params.iter() { |
| 374 | if let Some(idx) = tuple_index(params.as_slice(), arg) { |
| 375 | let param = ¶ms[idx]; |
| 376 | let substituted_arg = &arg_items[idx]; |
| 377 | |
| 378 | // Check if this is a TypeVarTuple (has tp_iter) |
| 379 | if param.class().slots.iter.load().is_some() |
| 380 | && substituted_arg.try_to_ref::<PyTuple>(vm).is_ok() |
| 381 | { |
| 382 | // TypeVarTuple case - extend with tuple elements |
| 383 | if let Ok(tuple) = substituted_arg.try_to_ref::<PyTuple>(vm) { |
| 384 | for elem in tuple { |
| 385 | sub_args.push(elem.clone()); |
| 386 | } |
| 387 | continue; |
| 388 | } |
| 389 | } |
| 390 | |
| 391 | sub_args.push(substituted_arg.clone()); |
| 392 | } else { |
| 393 | sub_args.push(arg.clone()); |
| 394 | } |
| 395 | } |
| 396 | |
| 397 | let sub_args: PyObjectRef = PyTuple::new_ref(sub_args, &vm.ctx).into(); |
| 398 | obj.get_item(&*sub_args, vm) |
| 399 | }) |
| 400 | }) |
| 401 | .unwrap_or(Ok(obj)) |
| 402 | } |
| 403 | |
| 404 | // CPython's _unpack_args equivalent |
| 405 | fn unpack_args(item: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyTupleRef> { |
no test coverage detected