Vectorcall for PyType (PEP 590). Fast path: type(x) returns x.__class__ without constructing FuncArgs. # Implementation note: `slots.vectorcall` dual use CPython has three distinct fields on PyTypeObject: - `tp_vectorcall`: constructor fast path (e.g. `list_vectorcall`) - `tp_vectorcall_offset`: per-instance vectorcall for callables (e.g. functions) - `tp_call`: standard call slot RustPython co
(
zelf_obj: &PyObject,
args: Vec<PyObjectRef>,
nargs: usize,
kwnames: Option<&[PyObjectRef]>,
vm: &VirtualMachine,
)
| 2685 | /// If more such types arise, consider splitting into a dedicated |
| 2686 | /// `constructor_vectorcall` slot. |
| 2687 | fn vectorcall_type( |
| 2688 | zelf_obj: &PyObject, |
| 2689 | args: Vec<PyObjectRef>, |
| 2690 | nargs: usize, |
| 2691 | kwnames: Option<&[PyObjectRef]>, |
| 2692 | vm: &VirtualMachine, |
| 2693 | ) -> PyResult { |
| 2694 | let zelf: &Py<PyType> = zelf_obj.downcast_ref().unwrap(); |
| 2695 | |
| 2696 | // type(x) fast path: single positional arg, no kwargs |
| 2697 | if zelf.is(vm.ctx.types.type_type) { |
| 2698 | let no_kwargs = kwnames.is_none_or(|kw| kw.is_empty()); |
| 2699 | if nargs == 1 && no_kwargs { |
| 2700 | return Ok(args[0].obj_type()); |
| 2701 | } |
| 2702 | } else if zelf.slots.call.load().is_none() && zelf.slots.new.load().is_some() { |
| 2703 | // Per-type constructor vectorcall for non-callable types (dict, list, int, etc.) |
| 2704 | // Also guard on slots.new to avoid dispatching for DISALLOW_INSTANTIATION types. |
| 2705 | if let Some(type_vc) = zelf.slots.vectorcall.load() { |
| 2706 | return type_vc(zelf_obj, args, nargs, kwnames, vm); |
| 2707 | } |
| 2708 | } |
| 2709 | |
| 2710 | // Fallback: construct FuncArgs and use standard call |
| 2711 | let func_args = FuncArgs::from_vectorcall_owned(args, nargs, kwnames); |
| 2712 | PyType::call(zelf, func_args, vm) |
| 2713 | } |
| 2714 | |
| 2715 | pub(crate) fn init(ctx: &'static Context) { |
| 2716 | PyType::extend_class(ctx, ctx.types.type_type); |