diff --git a/crates/stdlib/src/array.rs b/crates/stdlib/src/array.rs index 0501faedffd..4fcba1f8725 100644 --- a/crates/stdlib/src/array.rs +++ b/crates/stdlib/src/array.rs @@ -45,7 +45,8 @@ mod array { atomic_func, builtins::{ PositionIterInternal, PyByteArray, PyBytes, PyBytesRef, PyDictRef, PyFloat, - PyGenericAlias, PyInt, PyList, PyListRef, PyStr, PyStrRef, PyTupleRef, PyTypeRef, + PyGenericAlias, PyInt, PyList, PyListRef, PyStr, PyStrRef, PyTupleRef, PyType, + PyTypeRef, }, class_or_notimplemented, convert::{ToPyObject, ToPyResult, TryFromBorrowedObject, TryFromObject}, @@ -651,10 +652,10 @@ mod array { type Args = (ArrayNewArgs, KwArgs); fn py_new( - cls: PyTypeRef, + cls: &Py, (ArrayNewArgs { spec, init }, kwargs): Self::Args, vm: &VirtualMachine, - ) -> PyResult { + ) -> PyResult { let spec = spec.as_str().chars().exactly_one().map_err(|_| { vm.new_type_error("array() argument 1 must be a unicode character, not str") })?; @@ -701,8 +702,7 @@ mod array { } } - let zelf = Self::from(array).into_ref_with_type(vm, cls)?; - Ok(zelf.into()) + Ok(Self::from(array)) } } diff --git a/crates/stdlib/src/bz2.rs b/crates/stdlib/src/bz2.rs index f4db2d9fa1c..a2a40953cff 100644 --- a/crates/stdlib/src/bz2.rs +++ b/crates/stdlib/src/bz2.rs @@ -8,11 +8,11 @@ mod _bz2 { DecompressArgs, DecompressError, DecompressState, DecompressStatus, Decompressor, }; use crate::vm::{ - VirtualMachine, - builtins::{PyBytesRef, PyTypeRef}, + Py, VirtualMachine, + builtins::{PyBytesRef, PyType}, common::lock::PyMutex, function::{ArgBytesLike, OptionalArg}, - object::{PyPayload, PyResult}, + object::PyResult, types::Constructor, }; use bzip2::{Decompress, Status, write::BzEncoder}; @@ -61,12 +61,10 @@ mod _bz2 { impl Constructor for BZ2Decompressor { type Args = (); - fn py_new(cls: PyTypeRef, _: Self::Args, vm: &VirtualMachine) -> PyResult { - Self { + fn py_new(_cls: &Py, _args: Self::Args, vm: &VirtualMachine) -> PyResult { + Ok(Self { state: PyMutex::new(DecompressState::new(Decompress::new(false), vm)), - } - .into_ref_with_type(vm, cls) - .map(Into::into) + }) } } @@ -132,8 +130,11 @@ mod _bz2 { impl Constructor for BZ2Compressor { type Args = (OptionalArg,); - fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { - let (compresslevel,) = args; + fn py_new( + _cls: &Py, + (compresslevel,): Self::Args, + vm: &VirtualMachine, + ) -> PyResult { // TODO: seriously? // compresslevel.unwrap_or(bzip2::Compression::best().level().try_into().unwrap()); let compresslevel = compresslevel.unwrap_or(9); @@ -144,14 +145,12 @@ mod _bz2 { } }; - Self { + Ok(Self { state: PyMutex::new(CompressorState { flushed: false, encoder: Some(BzEncoder::new(Vec::new(), level)), }), - } - .into_ref_with_type(vm, cls) - .map(Into::into) + }) } } diff --git a/crates/stdlib/src/contextvars.rs b/crates/stdlib/src/contextvars.rs index cb66b8511f9..f48df167a71 100644 --- a/crates/stdlib/src/contextvars.rs +++ b/crates/stdlib/src/contextvars.rs @@ -24,7 +24,7 @@ thread_local! { mod _contextvars { use crate::vm::{ AsObject, Py, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, atomic_func, - builtins::{PyGenericAlias, PyStrRef, PyTypeRef}, + builtins::{PyGenericAlias, PyStrRef, PyType, PyTypeRef}, class::StaticType, common::hash::PyHash, function::{ArgCallable, FuncArgs, OptionalArg}, @@ -244,8 +244,8 @@ mod _contextvars { impl Constructor for PyContext { type Args = (); - fn py_new(_cls: PyTypeRef, _args: Self::Args, vm: &VirtualMachine) -> PyResult { - Ok(Self::empty(vm).into_pyobject(vm)) + fn py_new(_cls: &Py, _args: Self::Args, vm: &VirtualMachine) -> PyResult { + Ok(Self::empty(vm)) } } @@ -488,7 +488,9 @@ mod _contextvars { impl Constructor for ContextVar { type Args = ContextVarOptions; - fn py_new(_cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { + + fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { + let args: Self::Args = args.bind(vm)?; let var = Self { name: args.name.to_string(), default: args.default.into_option(), @@ -496,7 +498,7 @@ mod _contextvars { cached: AtomicCell::new(None), hash: UnsafeCell::new(0), }; - let py_var = var.into_ref(&vm.ctx); + let py_var = var.into_ref_with_type(vm, cls)?; unsafe { // SAFETY: py_var is not exposed to python memory model yet @@ -504,6 +506,10 @@ mod _contextvars { }; Ok(py_var.into()) } + + fn py_new(_cls: &Py, _args: Self::Args, _vm: &VirtualMachine) -> PyResult { + unreachable!("use slot_new") + } } impl std::hash::Hash for ContextVar { @@ -578,8 +584,8 @@ mod _contextvars { fn slot_new(_cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { Err(vm.new_runtime_error("Tokens can only be created by ContextVars")) } - fn py_new(_cls: PyTypeRef, _args: Self::Args, _vm: &VirtualMachine) -> PyResult { - unreachable!() + fn py_new(_cls: &Py, _args: Self::Args, _vm: &VirtualMachine) -> PyResult { + unreachable!("use slot_new") } } diff --git a/crates/stdlib/src/csv.rs b/crates/stdlib/src/csv.rs index 5f6d2494763..39ca70640d0 100644 --- a/crates/stdlib/src/csv.rs +++ b/crates/stdlib/src/csv.rs @@ -68,10 +68,8 @@ mod _csv { impl Constructor for PyDialect { type Args = PyObjectRef; - fn py_new(cls: PyTypeRef, ctx: Self::Args, vm: &VirtualMachine) -> PyResult { - Self::try_from_object(vm, ctx)? - .into_ref_with_type(vm, cls) - .map(Into::into) + fn py_new(_cls: &Py, ctx: Self::Args, vm: &VirtualMachine) -> PyResult { + Self::try_from_object(vm, ctx) } } #[pyclass(with(Constructor))] diff --git a/crates/stdlib/src/json.rs b/crates/stdlib/src/json.rs index afc9af234b6..eb6ed3a5f64 100644 --- a/crates/stdlib/src/json.rs +++ b/crates/stdlib/src/json.rs @@ -6,7 +6,7 @@ mod _json { use super::machinery; use crate::vm::{ AsObject, Py, PyObjectRef, PyPayload, PyResult, VirtualMachine, - builtins::{PyBaseExceptionRef, PyStrRef, PyType, PyTypeRef}, + builtins::{PyBaseExceptionRef, PyStrRef, PyType}, convert::{ToPyObject, ToPyResult}, function::{IntoFuncArgs, OptionalArg}, protocol::PyIterReturn, @@ -33,7 +33,7 @@ mod _json { impl Constructor for JsonScanner { type Args = PyObjectRef; - fn py_new(cls: PyTypeRef, ctx: Self::Args, vm: &VirtualMachine) -> PyResult { + fn py_new(_cls: &Py, ctx: Self::Args, vm: &VirtualMachine) -> PyResult { let strict = ctx.get_attr("strict", vm)?.try_to_bool(vm)?; let object_hook = vm.option_if_none(ctx.get_attr("object_hook", vm)?); let object_pairs_hook = vm.option_if_none(ctx.get_attr("object_pairs_hook", vm)?); @@ -52,7 +52,7 @@ mod _json { }; let parse_constant = ctx.get_attr("parse_constant", vm)?; - Self { + Ok(Self { strict, object_hook, object_pairs_hook, @@ -60,9 +60,7 @@ mod _json { parse_int, parse_constant, ctx, - } - .into_ref_with_type(vm, cls) - .map(Into::into) + }) } } diff --git a/crates/stdlib/src/lzma.rs b/crates/stdlib/src/lzma.rs index 885af30bc6f..855a5eae562 100644 --- a/crates/stdlib/src/lzma.rs +++ b/crates/stdlib/src/lzma.rs @@ -33,11 +33,11 @@ mod _lzma { LZMA_PRESET_LEVEL_MASK as PRESET_LEVEL_MASK, }; use rustpython_common::lock::PyMutex; - use rustpython_vm::builtins::{PyBaseExceptionRef, PyBytesRef, PyTypeRef}; + use rustpython_vm::builtins::{PyBaseExceptionRef, PyBytesRef, PyType, PyTypeRef}; use rustpython_vm::convert::ToPyException; use rustpython_vm::function::ArgBytesLike; use rustpython_vm::types::Constructor; - use rustpython_vm::{PyObjectRef, PyPayload, PyResult, VirtualMachine}; + use rustpython_vm::{Py, PyObjectRef, PyPayload, PyResult, VirtualMachine}; use std::fmt; use xz2::stream::{Action, Check, Error, Filters, LzmaOptions, Status, Stream}; @@ -148,7 +148,7 @@ mod _lzma { impl Constructor for LZMADecompressor { type Args = LZMADecompressorConstructorArgs; - fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { + fn py_new(_cls: &Py, args: Self::Args, vm: &VirtualMachine) -> PyResult { if args.format == FORMAT_RAW && args.mem_limit.is_some() { return Err(vm.new_value_error("Cannot specify memory limit with FORMAT_RAW")); } @@ -161,15 +161,13 @@ mod _lzma { // TODO: FORMAT_RAW _ => return Err(new_lzma_error("Invalid format", vm)), }; - Self { + Ok(Self { state: PyMutex::new(DecompressState::new( stream_result .map_err(|_| new_lzma_error("Failed to initialize decoder", vm))?, vm, )), - } - .into_ref_with_type(vm, cls) - .map(Into::into) + }) } } @@ -366,7 +364,7 @@ mod _lzma { impl Constructor for LZMACompressor { type Args = LZMACompressorConstructorArgs; - fn py_new(_cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { + fn py_new(_cls: &Py, args: Self::Args, vm: &VirtualMachine) -> PyResult { let preset = args.preset.unwrap_or(PRESET_DEFAULT); #[allow(clippy::unnecessary_cast)] if args.format != FORMAT_XZ as i32 @@ -392,8 +390,7 @@ mod _lzma { }; Ok(Self { state: PyMutex::new(CompressState::new(CompressorInner::new(stream))), - } - .into_pyobject(vm)) + }) } } diff --git a/crates/stdlib/src/mmap.rs b/crates/stdlib/src/mmap.rs index 7e53a27be85..5309917a999 100644 --- a/crates/stdlib/src/mmap.rs +++ b/crates/stdlib/src/mmap.rs @@ -11,7 +11,7 @@ mod mmap { use crate::vm::{ AsObject, FromArgs, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromBorrowedObject, VirtualMachine, atomic_func, - builtins::{PyBytes, PyBytesRef, PyInt, PyIntRef, PyTypeRef}, + builtins::{PyBytes, PyBytesRef, PyInt, PyIntRef, PyType, PyTypeRef}, byte::{bytes_from_object, value_from_object}, convert::ToPyException, function::{ArgBytesLike, FuncArgs, OptionalArg}, @@ -388,7 +388,7 @@ mod mmap { type Args = MmapNewArgs; #[cfg(unix)] - fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { + fn py_new(_cls: &Py, args: Self::Args, vm: &VirtualMachine) -> PyResult { use libc::{MAP_PRIVATE, MAP_SHARED, PROT_READ, PROT_WRITE}; let mut map_size = args.validate_new_args(vm)?; @@ -477,7 +477,7 @@ mod mmap { }() .map_err(|e| e.to_pyexception(vm))?; - let m_obj = Self { + Ok(Self { closed: AtomicCell::new(false), mmap: PyMutex::new(Some(mmap)), fd: AtomicCell::new(fd.map_or(-1, |fd| fd.into_raw())), @@ -486,13 +486,11 @@ mod mmap { pos: AtomicCell::new(0), exports: AtomicCell::new(0), access, - }; - - m_obj.into_ref_with_type(vm, cls).map(Into::into) + }) } #[cfg(windows)] - fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { + fn py_new(_cls: &Py, args: Self::Args, vm: &VirtualMachine) -> PyResult { let mut map_size = args.validate_new_args(vm)?; let MmapNewArgs { fileno, @@ -627,7 +625,7 @@ mod mmap { (INVALID_HANDLE_VALUE as isize, MmapObj::Write(mmap)) }; - let m_obj = Self { + Ok(Self { closed: AtomicCell::new(false), mmap: PyMutex::new(Some(mmap)), handle: AtomicCell::new(handle), @@ -636,9 +634,7 @@ mod mmap { pos: AtomicCell::new(0), exports: AtomicCell::new(0), access, - }; - - m_obj.into_ref_with_type(vm, cls).map(Into::into) + }) } } diff --git a/crates/stdlib/src/overlapped.rs b/crates/stdlib/src/overlapped.rs index a5b5fa14fc3..d8f14baf35e 100644 --- a/crates/stdlib/src/overlapped.rs +++ b/crates/stdlib/src/overlapped.rs @@ -9,7 +9,7 @@ mod _overlapped { use crate::vm::{ Py, PyObjectRef, PyPayload, PyResult, VirtualMachine, - builtins::{PyBaseExceptionRef, PyBytesRef, PyTypeRef}, + builtins::{PyBaseExceptionRef, PyBytesRef, PyType}, common::lock::PyMutex, convert::{ToPyException, ToPyObject}, protocol::PyBuffer, @@ -264,7 +264,11 @@ mod _overlapped { impl Constructor for Overlapped { type Args = (isize,); - fn py_new(cls: PyTypeRef, (mut event,): Self::Args, vm: &VirtualMachine) -> PyResult { + fn py_new( + _cls: &Py, + (mut event,): Self::Args, + vm: &VirtualMachine, + ) -> PyResult { if event == INVALID_HANDLE_VALUE { event = unsafe { windows_sys::Win32::System::Threading::CreateEventA( @@ -289,10 +293,9 @@ mod _overlapped { error: 0, data: OverlappedData::None, }; - let overlapped = Overlapped { + Ok(Overlapped { inner: PyMutex::new(inner), - }; - overlapped.into_ref_with_type(vm, cls).map(Into::into) + }) } } diff --git a/crates/stdlib/src/pystruct.rs b/crates/stdlib/src/pystruct.rs index a4c91507621..798e5f5de80 100644 --- a/crates/stdlib/src/pystruct.rs +++ b/crates/stdlib/src/pystruct.rs @@ -12,7 +12,7 @@ pub(crate) mod _struct { use crate::vm::{ AsObject, Py, PyObjectRef, PyPayload, PyResult, TryFromObject, VirtualMachine, buffer::{FormatSpec, new_struct_error, struct_error_type}, - builtins::{PyBytes, PyStr, PyStrRef, PyTupleRef, PyTypeRef}, + builtins::{PyBytes, PyStr, PyStrRef, PyTupleRef, PyType, PyTypeRef}, function::{ArgBytesLike, ArgMemoryBuffer, PosArgs}, match_class, protocol::PyIterReturn, @@ -241,12 +241,10 @@ pub(crate) mod _struct { impl Constructor for PyStruct { type Args = IntoStructFormatBytes; - fn py_new(cls: PyTypeRef, fmt: Self::Args, vm: &VirtualMachine) -> PyResult { + fn py_new(_cls: &Py, fmt: Self::Args, vm: &VirtualMachine) -> PyResult { let spec = fmt.format_spec(vm)?; let format = fmt.0; - Self { spec, format } - .into_ref_with_type(vm, cls) - .map(Into::into) + Ok(Self { spec, format }) } } diff --git a/crates/stdlib/src/select.rs b/crates/stdlib/src/select.rs index c19052965b4..5639a66d2cc 100644 --- a/crates/stdlib/src/select.rs +++ b/crates/stdlib/src/select.rs @@ -546,8 +546,8 @@ mod decl { pub(super) mod epoll { use super::*; use crate::vm::{ - PyPayload, - builtins::PyTypeRef, + Py, PyPayload, + builtins::PyType, common::lock::{PyRwLock, PyRwLockReadGuard}, convert::{IntoPyException, ToPyObject}, function::OptionalArg, @@ -575,17 +575,15 @@ mod decl { impl Constructor for PyEpoll { type Args = EpollNewArgs; - fn py_new(cls: PyTypeRef, args: EpollNewArgs, vm: &VirtualMachine) -> PyResult { + + fn py_new(_cls: &Py, args: Self::Args, vm: &VirtualMachine) -> PyResult { if let ..=-2 | 0 = args.sizehint { return Err(vm.new_value_error("negative sizehint")); } if !matches!(args.flags, 0 | libc::EPOLL_CLOEXEC) { return Err(vm.new_os_error("invalid flags".to_owned())); } - Self::new() - .map_err(|e| e.into_pyexception(vm))? - .into_ref_with_type(vm, cls) - .map(Into::into) + Self::new().map_err(|e| e.into_pyexception(vm)) } } diff --git a/crates/stdlib/src/sqlite.rs b/crates/stdlib/src/sqlite.rs index 7650221fb90..deff3c3a66a 100644 --- a/crates/stdlib/src/sqlite.rs +++ b/crates/stdlib/src/sqlite.rs @@ -650,7 +650,9 @@ mod _sqlite { #[pyfunction] fn connect(args: ConnectArgs, vm: &VirtualMachine) -> PyResult { - Connection::py_new(args.factory.clone(), args, vm) + let factory = args.factory.clone(); + let conn = Connection::py_new(&factory, args, vm)?; + conn.into_ref_with_type(vm, factory).map(Into::into) } #[pyfunction] @@ -851,12 +853,12 @@ mod _sqlite { impl Constructor for Connection { type Args = ConnectArgs; - fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { + fn py_new(cls: &Py, args: Self::Args, vm: &VirtualMachine) -> PyResult { let text_factory = PyStr::class(&vm.ctx).to_owned().into_object(); // For non-subclassed Connection, initialize in __new__ // For subclassed Connection, leave db as None and require __init__ to be called - let is_base_class = cls.is(Connection::class(&vm.ctx).as_object()); + let is_base_class = cls.is(Connection::class(&vm.ctx)); let db = if is_base_class { // Initialize immediately for base class @@ -868,7 +870,7 @@ mod _sqlite { let initialized = db.is_some(); - let conn = Self { + Ok(Self { db: PyMutex::new(db), initialized: Radium::new(initialized), detect_types: Radium::new(args.detect_types), @@ -877,9 +879,7 @@ mod _sqlite { thread_ident: PyMutex::new(std::thread::current().id()), row_factory: PyAtomicRef::from(None), text_factory: PyAtomicRef::from(text_factory), - }; - - Ok(conn.into_ref_with_type(vm, cls)?.into()) + }) } } @@ -1940,10 +1940,12 @@ mod _sqlite { impl Constructor for Cursor { type Args = (PyRef,); - fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { - Self::new_uninitialized(args.0, vm) - .into_ref_with_type(vm, cls) - .map(Into::into) + fn py_new( + _cls: &Py, + (connection,): Self::Args, + vm: &VirtualMachine, + ) -> PyResult { + Ok(Self::new_uninitialized(connection, vm)) } } @@ -2109,20 +2111,18 @@ mod _sqlite { impl Constructor for Row { type Args = (PyRef, PyTupleRef); - fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { - let description = args - .0 + fn py_new( + _cls: &Py, + (cursor, data): Self::Args, + vm: &VirtualMachine, + ) -> PyResult { + let description = cursor .inner(vm)? .description .clone() .ok_or_else(|| vm.new_value_error("no description in Cursor"))?; - Self { - data: args.1, - description, - } - .into_ref_with_type(vm, cls) - .map(Into::into) + Ok(Self { data, description }) } } diff --git a/crates/stdlib/src/ssl.rs b/crates/stdlib/src/ssl.rs index 25227a5556a..ad8952aedb7 100644 --- a/crates/stdlib/src/ssl.rs +++ b/crates/stdlib/src/ssl.rs @@ -37,9 +37,9 @@ mod _ssl { vm::{ AsObject, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject, VirtualMachine, - builtins::{PyBaseExceptionRef, PyBytesRef, PyListRef, PyStrRef, PyTypeRef}, + builtins::{PyBaseExceptionRef, PyBytesRef, PyListRef, PyStrRef, PyType, PyTypeRef}, convert::IntoPyException, - function::{ArgBytesLike, ArgMemoryBuffer, OptionalArg, PyComparisonValue}, + function::{ArgBytesLike, ArgMemoryBuffer, FuncArgs, OptionalArg, PyComparisonValue}, stdlib::warnings, types::{Comparable, Constructor, Hashable, PyComparisonOp, Representable}, }, @@ -2288,7 +2288,11 @@ mod _ssl { impl Constructor for PySSLContext { type Args = (i32,); - fn py_new(cls: PyTypeRef, (protocol,): Self::Args, vm: &VirtualMachine) -> PyResult { + fn py_new( + _cls: &Py, + (protocol,): Self::Args, + vm: &VirtualMachine, + ) -> PyResult { // Validate protocol match protocol { PROTOCOL_TLS | PROTOCOL_TLS_CLIENT | PROTOCOL_TLS_SERVER | PROTOCOL_TLSv1_2 @@ -2353,7 +2357,7 @@ mod _ssl { session_cache: shared_session_cache.clone(), }); - PySSLContext { + Ok(PySSLContext { protocol, check_hostname: PyRwLock::new(protocol == PROTOCOL_TLS_CLIENT), verify_mode: PyRwLock::new(default_verify_mode), @@ -2388,9 +2392,7 @@ mod _ssl { accept_count: AtomicUsize::new(0), session_hits: AtomicUsize::new(0), selected_ciphers: PyRwLock::new(None), - } - .into_ref_with_type(vm, cls) - .map(Into::into) + }) } } @@ -4107,11 +4109,15 @@ mod _ssl { impl Constructor for PySSLSocket { type Args = (); - fn py_new(_cls: PyTypeRef, _args: Self::Args, vm: &VirtualMachine) -> PyResult { + fn slot_new(_cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { Err(vm.new_type_error( "Cannot directly instantiate SSLSocket, use SSLContext.wrap_socket()", )) } + + fn py_new(_cls: &Py, _args: Self::Args, _vm: &VirtualMachine) -> PyResult { + unreachable!("use slot_new") + } } // MemoryBIO - provides in-memory buffer for SSL/TLS I/O @@ -4204,13 +4210,11 @@ mod _ssl { impl Constructor for PyMemoryBIO { type Args = (); - fn py_new(cls: PyTypeRef, _args: Self::Args, vm: &VirtualMachine) -> PyResult { - let obj = PyMemoryBIO { + fn py_new(_cls: &Py, _args: Self::Args, _vm: &VirtualMachine) -> PyResult { + Ok(PyMemoryBIO { buffer: PyMutex::new(Vec::new()), eof: PyRwLock::new(false), - } - .into_ref_with_type(vm, cls)?; - Ok(obj.into()) + }) } } diff --git a/crates/stdlib/src/zlib.rs b/crates/stdlib/src/zlib.rs index cb444ec8c0a..328452ae9d5 100644 --- a/crates/stdlib/src/zlib.rs +++ b/crates/stdlib/src/zlib.rs @@ -10,8 +10,8 @@ mod zlib { Decompressor, USE_AFTER_FINISH_ERR, flush_sync, }; use crate::vm::{ - PyObject, PyPayload, PyResult, VirtualMachine, - builtins::{PyBaseExceptionRef, PyBytesRef, PyIntRef, PyTypeRef}, + Py, PyObject, PyPayload, PyResult, VirtualMachine, + builtins::{PyBaseExceptionRef, PyBytesRef, PyIntRef, PyType, PyTypeRef}, common::lock::PyMutex, convert::{ToPyException, TryFromBorrowedObject}, function::{ArgBytesLike, ArgPrimitiveIndex, ArgSize, OptionalArg}, @@ -570,7 +570,7 @@ mod zlib { impl Constructor for ZlibDecompressor { type Args = DecompressobjArgs; - fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { + fn py_new(_cls: &Py, args: Self::Args, vm: &VirtualMachine) -> PyResult { let mut decompress = InitOptions::new(args.wbits.value, vm)?.decompress(); let zdict = args.zdict.into_option(); if let Some(dict) = &zdict @@ -580,11 +580,9 @@ mod zlib { .map_err(|_| new_zlib_error("failed to set dictionary", vm))?; } let inner = DecompressState::new(DecompressWithDict { decompress, zdict }, vm); - Self { + Ok(Self { inner: PyMutex::new(inner), - } - .into_ref_with_type(vm, cls) - .map(Into::into) + }) } } diff --git a/crates/vm/src/builtins/bool.rs b/crates/vm/src/builtins/bool.rs index 829d8b2384b..902656da2c8 100644 --- a/crates/vm/src/builtins/bool.rs +++ b/crates/vm/src/builtins/bool.rs @@ -5,7 +5,7 @@ use crate::{ VirtualMachine, class::PyClassImpl, convert::{IntoPyException, ToPyObject, ToPyResult}, - function::OptionalArg, + function::{FuncArgs, OptionalArg}, identifier, protocol::PyNumberMethods, types::{AsNumber, Constructor, Representable}, @@ -101,7 +101,8 @@ impl Debug for PyBool { impl Constructor for PyBool { type Args = OptionalArg; - fn py_new(zelf: PyTypeRef, x: Self::Args, vm: &VirtualMachine) -> PyResult { + fn slot_new(zelf: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { + let x: Self::Args = args.bind(vm)?; if !zelf.fast_isinstance(vm.ctx.types.type_type) { let actual_class = zelf.class(); let actual_type = &actual_class.name(); @@ -112,6 +113,10 @@ impl Constructor for PyBool { let val = x.map_or(Ok(false), |val| val.try_to_bool(vm))?; Ok(vm.ctx.new_bool(val).into()) } + + fn py_new(_cls: &Py, _args: Self::Args, _vm: &VirtualMachine) -> PyResult { + unreachable!("use slot_new") + } } #[pyclass(with(Constructor, AsNumber, Representable), flags(_MATCH_SELF))] diff --git a/crates/vm/src/builtins/bytes.rs b/crates/vm/src/builtins/bytes.rs index a06588cc8f2..3da1b68ef07 100644 --- a/crates/vm/src/builtins/bytes.rs +++ b/crates/vm/src/builtins/bytes.rs @@ -15,7 +15,8 @@ use crate::{ common::{hash::PyHash, lock::PyMutex}, convert::{ToPyObject, ToPyResult}, function::{ - ArgBytesLike, ArgIndex, ArgIterable, Either, OptionalArg, OptionalOption, PyComparisonValue, + ArgBytesLike, ArgIndex, ArgIterable, Either, FuncArgs, OptionalArg, OptionalOption, + PyComparisonValue, }, protocol::{ BufferDescriptor, BufferMethods, PyBuffer, PyIterReturn, PyMappingMethods, PyNumberMethods, @@ -93,9 +94,14 @@ pub(crate) fn init(context: &Context) { impl Constructor for PyBytes { type Args = ByteInnerNewOptions; - fn py_new(cls: PyTypeRef, options: Self::Args, vm: &VirtualMachine) -> PyResult { + fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { + let options: Self::Args = args.bind(vm)?; options.get_bytes(cls, vm).to_pyresult(vm) } + + fn py_new(_cls: &Py, _args: Self::Args, _vm: &VirtualMachine) -> PyResult { + unreachable!("use slot_new") + } } impl PyBytes { diff --git a/crates/vm/src/builtins/classmethod.rs b/crates/vm/src/builtins/classmethod.rs index f88f14819d2..197b6805ef9 100644 --- a/crates/vm/src/builtins/classmethod.rs +++ b/crates/vm/src/builtins/classmethod.rs @@ -3,6 +3,7 @@ use crate::{ AsObject, Context, Py, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, class::PyClassImpl, common::lock::PyMutex, + function::FuncArgs, types::{Constructor, GetDescriptor, Initializer, Representable}, }; @@ -69,7 +70,8 @@ impl GetDescriptor for PyClassMethod { impl Constructor for PyClassMethod { type Args = PyObjectRef; - fn py_new(cls: PyTypeRef, callable: Self::Args, vm: &VirtualMachine) -> PyResult { + fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { + let callable: Self::Args = args.bind(vm)?; // Create a dictionary to hold copied attributes let dict = vm.ctx.new_dict(); @@ -99,6 +101,10 @@ impl Constructor for PyClassMethod { let result = PyRef::new_ref(classmethod, cls, Some(dict)); Ok(PyObjectRef::from(result)) } + + fn py_new(_cls: &Py, _args: Self::Args, _vm: &VirtualMachine) -> PyResult { + unreachable!("use slot_new") + } } impl Initializer for PyClassMethod { diff --git a/crates/vm/src/builtins/code.rs b/crates/vm/src/builtins/code.rs index f9f3429e303..e46cc711bb3 100644 --- a/crates/vm/src/builtins/code.rs +++ b/crates/vm/src/builtins/code.rs @@ -1,6 +1,6 @@ //! Infamous code object. The python class `code` -use super::{PyBytesRef, PyStrRef, PyTupleRef, PyType, PyTypeRef}; +use super::{PyBytesRef, PyStrRef, PyTupleRef, PyType}; use crate::{ AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyResult, VirtualMachine, builtins::PyStrInterned, @@ -390,7 +390,7 @@ pub struct PyCodeNewArgs { impl Constructor for PyCode { type Args = PyCodeNewArgs; - fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { + fn py_new(_cls: &Py, args: Self::Args, vm: &VirtualMachine) -> PyResult { // Convert names tuple to vector of interned strings let names: Box<[&'static PyStrInterned]> = args .names @@ -508,9 +508,7 @@ impl Constructor for PyCode { exceptiontable: args.exceptiontable.as_bytes().to_vec().into_boxed_slice(), }; - Ok(PyCode::new(code) - .into_ref_with_type(vm, cls)? - .to_pyobject(vm)) + Ok(PyCode::new(code)) } } diff --git a/crates/vm/src/builtins/complex.rs b/crates/vm/src/builtins/complex.rs index d2e0911240b..3b38ab0dc94 100644 --- a/crates/vm/src/builtins/complex.rs +++ b/crates/vm/src/builtins/complex.rs @@ -6,7 +6,7 @@ use crate::{ common::format::FormatSpec, convert::{IntoPyException, ToPyObject, ToPyResult}, function::{ - OptionalArg, OptionalOption, + FuncArgs, OptionalArg, OptionalOption, PyArithmeticValue::{self, *}, PyComparisonValue, }, @@ -151,22 +151,26 @@ fn powc(a: Complex64, exp: Complex64) -> Complex64 { impl Constructor for PyComplex { type Args = ComplexArgs; - fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { + fn slot_new(cls: PyTypeRef, func_args: FuncArgs, vm: &VirtualMachine) -> PyResult { + // Optimization: return exact complex as-is (only when imag is not provided) + if cls.is(vm.ctx.types.complex_type) + && func_args.args.len() == 1 + && func_args.kwargs.is_empty() + && func_args.args[0].class().is(vm.ctx.types.complex_type) + { + return Ok(func_args.args[0].clone()); + } + + let args: Self::Args = func_args.bind(vm)?; + let payload = Self::py_new(&cls, args, vm)?; + payload.into_ref_with_type(vm, cls).map(Into::into) + } + + fn py_new(_cls: &Py, args: Self::Args, vm: &VirtualMachine) -> PyResult { let imag_missing = args.imag.is_missing(); let (real, real_was_complex) = match args.real { OptionalArg::Missing => (Complex64::new(0.0, 0.0), false), OptionalArg::Present(val) => { - let val = if cls.is(vm.ctx.types.complex_type) && imag_missing { - match val.downcast_exact::(vm) { - Ok(c) => { - return Ok(c.into_pyref().into()); - } - Err(val) => val, - } - } else { - val - }; - if let Some(c) = val.try_complex(vm)? { c } else if let Some(s) = val.downcast_ref::() { @@ -179,9 +183,7 @@ impl Constructor for PyComplex { .to_str() .and_then(rustpython_literal::complex::parse_str) .ok_or_else(|| vm.new_value_error("complex() arg is a malformed string"))?; - return Self::from(Complex64 { re, im }) - .into_ref_with_type(vm, cls) - .map(Into::into); + return Ok(Self::from(Complex64 { re, im })); } else { return Err(vm.new_type_error(format!( "complex() first argument must be a string or a number, not '{}'", @@ -221,9 +223,7 @@ impl Constructor for PyComplex { imag.re }; let value = Complex64::new(final_real, final_imag); - Self::from(value) - .into_ref_with_type(vm, cls) - .map(Into::into) + Ok(Self::from(value)) } } diff --git a/crates/vm/src/builtins/enumerate.rs b/crates/vm/src/builtins/enumerate.rs index 9d163899a3a..29d51f420e1 100644 --- a/crates/vm/src/builtins/enumerate.rs +++ b/crates/vm/src/builtins/enumerate.rs @@ -41,17 +41,15 @@ impl Constructor for PyEnumerate { type Args = EnumerateArgs; fn py_new( - cls: PyTypeRef, + _cls: &Py, Self::Args { iterable, start }: Self::Args, - vm: &VirtualMachine, - ) -> PyResult { + _vm: &VirtualMachine, + ) -> PyResult { let counter = start.map_or_else(BigInt::zero, |start| start.as_bigint().clone()); - Self { + Ok(Self { counter: PyRwLock::new(counter), iterable, - } - .into_ref_with_type(vm, cls) - .map(Into::into) + }) } } diff --git a/crates/vm/src/builtins/filter.rs b/crates/vm/src/builtins/filter.rs index 661fbd02286..388fb8bb603 100644 --- a/crates/vm/src/builtins/filter.rs +++ b/crates/vm/src/builtins/filter.rs @@ -24,13 +24,15 @@ impl PyPayload for PyFilter { impl Constructor for PyFilter { type Args = (PyObjectRef, PyIter); - fn py_new(cls: PyTypeRef, (function, iterator): Self::Args, vm: &VirtualMachine) -> PyResult { - Self { + fn py_new( + _cls: &Py, + (function, iterator): Self::Args, + _vm: &VirtualMachine, + ) -> PyResult { + Ok(Self { predicate: function, iterator, - } - .into_ref_with_type(vm, cls) - .map(Into::into) + }) } } diff --git a/crates/vm/src/builtins/float.rs b/crates/vm/src/builtins/float.rs index ad18db36a43..26182d748a9 100644 --- a/crates/vm/src/builtins/float.rs +++ b/crates/vm/src/builtins/float.rs @@ -8,7 +8,7 @@ use crate::{ common::{float_ops, format::FormatSpec, hash}, convert::{IntoPyException, ToPyObject, ToPyResult}, function::{ - ArgBytesLike, OptionalArg, OptionalOption, + ArgBytesLike, FuncArgs, OptionalArg, OptionalOption, PyArithmeticValue::{self, *}, PyComparisonValue, }, @@ -131,14 +131,25 @@ pub fn float_pow(v1: f64, v2: f64, vm: &VirtualMachine) -> PyResult { impl Constructor for PyFloat { type Args = OptionalArg; - fn py_new(cls: PyTypeRef, arg: Self::Args, vm: &VirtualMachine) -> PyResult { + fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { + // Optimization: return exact float as-is + if cls.is(vm.ctx.types.float_type) + && args.kwargs.is_empty() + && let Some(first) = args.args.first() + && first.class().is(vm.ctx.types.float_type) + { + return Ok(first.clone()); + } + + let arg: Self::Args = args.bind(vm)?; + let payload = Self::py_new(&cls, arg, vm)?; + payload.into_ref_with_type(vm, cls).map(Into::into) + } + + fn py_new(_cls: &Py, arg: Self::Args, vm: &VirtualMachine) -> PyResult { let float_val = match arg { OptionalArg::Missing => 0.0, OptionalArg::Present(val) => { - if cls.is(vm.ctx.types.float_type) && val.class().is(vm.ctx.types.float_type) { - return Ok(val); - } - if let Some(f) = val.try_float_opt(vm) { f?.value } else { @@ -146,9 +157,7 @@ impl Constructor for PyFloat { } } }; - Self::from(float_val) - .into_ref_with_type(vm, cls) - .map(Into::into) + Ok(Self::from(float_val)) } } diff --git a/crates/vm/src/builtins/function.rs b/crates/vm/src/builtins/function.rs index 19daf885fb1..0b322c6be5b 100644 --- a/crates/vm/src/builtins/function.rs +++ b/crates/vm/src/builtins/function.rs @@ -3,7 +3,7 @@ mod jit; use super::{ PyAsyncGen, PyCode, PyCoroutine, PyDictRef, PyGenerator, PyStr, PyStrRef, PyTuple, PyTupleRef, - PyType, PyTypeRef, + PyType, }; #[cfg(feature = "jit")] use crate::common::lock::OnceCell; @@ -670,7 +670,7 @@ pub struct PyFunctionNewArgs { impl Constructor for PyFunction { type Args = PyFunctionNewArgs; - fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { + fn py_new(_cls: &Py, args: Self::Args, vm: &VirtualMachine) -> PyResult { // Handle closure - must be a tuple of cells let closure = if let Some(closure_tuple) = args.closure.into_option() { // Check that closure length matches code's free variables @@ -710,7 +710,7 @@ impl Constructor for PyFunction { func.defaults_and_kwdefaults.lock().1 = Some(kwdefaults); } - func.into_ref_with_type(vm, cls).map(Into::into) + Ok(func) } } @@ -771,13 +771,11 @@ impl Constructor for PyBoundMethod { type Args = PyBoundMethodNewArgs; fn py_new( - cls: PyTypeRef, + _cls: &Py, Self::Args { function, object }: Self::Args, - vm: &VirtualMachine, - ) -> PyResult { - Self::new(object, function) - .into_ref_with_type(vm, cls) - .map(Into::into) + _vm: &VirtualMachine, + ) -> PyResult { + Ok(Self::new(object, function)) } } @@ -897,10 +895,8 @@ impl PyPayload for PyCell { impl Constructor for PyCell { type Args = OptionalArg; - fn py_new(cls: PyTypeRef, value: Self::Args, vm: &VirtualMachine) -> PyResult { - Self::new(value.into_option()) - .into_ref_with_type(vm, cls) - .map(Into::into) + fn py_new(_cls: &Py, value: Self::Args, _vm: &VirtualMachine) -> PyResult { + Ok(Self::new(value.into_option())) } } diff --git a/crates/vm/src/builtins/genericalias.rs b/crates/vm/src/builtins/genericalias.rs index bcaeb1bfb2d..494b580e563 100644 --- a/crates/vm/src/builtins/genericalias.rs +++ b/crates/vm/src/builtins/genericalias.rs @@ -58,7 +58,7 @@ impl PyPayload for PyGenericAlias { impl Constructor for PyGenericAlias { type Args = FuncArgs; - fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { + fn py_new(_cls: &Py, args: Self::Args, vm: &VirtualMachine) -> PyResult { if !args.kwargs.is_empty() { return Err(vm.new_type_error("GenericAlias() takes no keyword arguments")); } @@ -68,9 +68,7 @@ impl Constructor for PyGenericAlias { } else { PyTuple::new_ref(vec![arguments], &vm.ctx) }; - Self::new(origin, args, false, vm) - .into_ref_with_type(vm, cls) - .map(Into::into) + Ok(Self::new(origin, args, false, vm)) } } diff --git a/crates/vm/src/builtins/int.rs b/crates/vm/src/builtins/int.rs index 36cfd425328..f019d2634a5 100644 --- a/crates/vm/src/builtins/int.rs +++ b/crates/vm/src/builtins/int.rs @@ -12,7 +12,7 @@ use crate::{ }, convert::{IntoPyException, ToPyObject, ToPyResult}, function::{ - ArgByteOrder, ArgIntoBool, OptionalArg, OptionalOption, PyArithmeticValue, + ArgByteOrder, ArgIntoBool, FuncArgs, OptionalArg, OptionalOption, PyArithmeticValue, PyComparisonValue, }, protocol::{PyNumberMethods, handle_bytes_to_int_err}, @@ -205,13 +205,23 @@ fn inner_truediv(i1: &BigInt, i2: &BigInt, vm: &VirtualMachine) -> PyResult { } impl Constructor for PyInt { - type Args = IntOptions; + type Args = FuncArgs; - fn py_new(cls: PyTypeRef, options: Self::Args, vm: &VirtualMachine) -> PyResult { + fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { if cls.is(vm.ctx.types.bool_type) { return Err(vm.new_type_error("int.__new__(bool) is not safe, use bool.__new__()")); } + // Optimization: return exact int as-is (only for exact int type, not subclasses) + if cls.is(vm.ctx.types.int_type) + && args.args.len() == 1 + && args.kwargs.is_empty() + && args.args[0].class().is(vm.ctx.types.int_type) + { + return Ok(args.args[0].clone()); + } + + let options: IntOptions = args.bind(vm)?; let value = if let OptionalArg::Present(val) = options.val_options { if let OptionalArg::Present(base) = options.base { let base = base @@ -222,17 +232,6 @@ impl Constructor for PyInt { .ok_or_else(|| vm.new_value_error("int() base must be >= 2 and <= 36, or 0"))?; try_int_radix(&val, base, vm) } else { - let val = if cls.is(vm.ctx.types.int_type) { - match val.downcast_exact::(vm) { - Ok(i) => { - return Ok(i.into_pyref().into()); - } - Err(val) => val, - } - } else { - val - }; - val.try_int(vm).map(|x| x.as_bigint().clone()) } } else if let OptionalArg::Present(_) = options.base { @@ -241,7 +240,11 @@ impl Constructor for PyInt { Ok(Zero::zero()) }?; - Self::with_value(cls, value, vm).to_pyresult(vm) + Self::with_value(cls, value, vm).map(Into::into) + } + + fn py_new(_cls: &Py, _args: Self::Args, _vm: &VirtualMachine) -> PyResult { + unreachable!("use slot_new") } } diff --git a/crates/vm/src/builtins/list.rs b/crates/vm/src/builtins/list.rs index 13f29de401b..b2927462cac 100644 --- a/crates/vm/src/builtins/list.rs +++ b/crates/vm/src/builtins/list.rs @@ -379,8 +379,8 @@ impl MutObjectSequenceOp for PyList { impl Constructor for PyList { type Args = FuncArgs; - fn py_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { - Self::default().into_ref_with_type(vm, cls).map(Into::into) + fn py_new(_cls: &Py, _args: FuncArgs, _vm: &VirtualMachine) -> PyResult { + Ok(Self::default()) } } diff --git a/crates/vm/src/builtins/map.rs b/crates/vm/src/builtins/map.rs index 06a533f8bcd..f5cee945ece 100644 --- a/crates/vm/src/builtins/map.rs +++ b/crates/vm/src/builtins/map.rs @@ -26,11 +26,13 @@ impl PyPayload for PyMap { impl Constructor for PyMap { type Args = (PyObjectRef, PosArgs); - fn py_new(cls: PyTypeRef, (mapper, iterators): Self::Args, vm: &VirtualMachine) -> PyResult { + fn py_new( + _cls: &Py, + (mapper, iterators): Self::Args, + _vm: &VirtualMachine, + ) -> PyResult { let iterators = iterators.into_vec(); - Self { mapper, iterators } - .into_ref_with_type(vm, cls) - .map(Into::into) + Ok(Self { mapper, iterators }) } } diff --git a/crates/vm/src/builtins/mappingproxy.rs b/crates/vm/src/builtins/mappingproxy.rs index 04eb6ef671c..fb8ff5de9cc 100644 --- a/crates/vm/src/builtins/mappingproxy.rs +++ b/crates/vm/src/builtins/mappingproxy.rs @@ -61,18 +61,16 @@ impl From for PyMappingProxy { impl Constructor for PyMappingProxy { type Args = PyObjectRef; - fn py_new(cls: PyTypeRef, mapping: Self::Args, vm: &VirtualMachine) -> PyResult { + fn py_new(_cls: &Py, mapping: Self::Args, vm: &VirtualMachine) -> PyResult { if let Some(methods) = PyMapping::find_methods(&mapping) && !mapping.downcastable::() && !mapping.downcastable::() { - return Self { + return Ok(Self { mapping: MappingProxyInner::Mapping(ArgMapping::with_methods(mapping, unsafe { methods.borrow_static() })), - } - .into_ref_with_type(vm, cls) - .map(Into::into); + }); } Err(vm.new_type_error(format!( "mappingproxy() argument must be a mapping, not {}", diff --git a/crates/vm/src/builtins/memory.rs b/crates/vm/src/builtins/memory.rs index 87e31256c39..c8656cb1362 100644 --- a/crates/vm/src/builtins/memory.rs +++ b/crates/vm/src/builtins/memory.rs @@ -61,9 +61,8 @@ pub struct PyMemoryView { impl Constructor for PyMemoryView { type Args = PyMemoryViewNewArgs; - fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { - let zelf = Self::from_object(&args.object, vm)?; - zelf.into_ref_with_type(vm, cls).map(Into::into) + fn py_new(_cls: &Py, args: Self::Args, vm: &VirtualMachine) -> PyResult { + Self::from_object(&args.object, vm) } } diff --git a/crates/vm/src/builtins/object.rs b/crates/vm/src/builtins/object.rs index 94a1e0c9ad9..735d5461186 100644 --- a/crates/vm/src/builtins/object.rs +++ b/crates/vm/src/builtins/object.rs @@ -32,7 +32,7 @@ impl Constructor for PyBaseObject { type Args = FuncArgs; // = object_new - fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { + fn slot_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { if !args.args.is_empty() || !args.kwargs.is_empty() { // Check if type's __new__ != object.__new__ let tp_new = cls.get_attr(identifier!(vm, __new__)); @@ -109,6 +109,10 @@ impl Constructor for PyBaseObject { Ok(crate::PyRef::new_ref(Self, cls, dict).into()) } + + fn py_new(_cls: &Py, _args: Self::Args, _vm: &VirtualMachine) -> PyResult { + unreachable!("use slot_new") + } } // TODO: implement _PyType_GetSlotNames properly diff --git a/crates/vm/src/builtins/property.rs b/crates/vm/src/builtins/property.rs index a75357f7611..1a2e04ee8b0 100644 --- a/crates/vm/src/builtins/property.rs +++ b/crates/vm/src/builtins/property.rs @@ -1,7 +1,7 @@ /*! Python `property` descriptor class. */ -use super::{PyStrRef, PyType, PyTypeRef}; +use super::{PyStrRef, PyType}; use crate::common::lock::PyRwLock; use crate::function::{IntoFuncArgs, PosArgs}; use crate::{ @@ -224,7 +224,7 @@ impl PyProperty { }; // Create new property using py_new and init - let new_prop = Self::py_new(zelf.class().to_owned(), FuncArgs::default(), vm)?; + let new_prop = Self::slot_new(zelf.class().to_owned(), FuncArgs::default(), vm)?; let new_prop_ref = new_prop.downcast::().unwrap(); Self::init(new_prop_ref.clone(), args, vm)?; @@ -336,17 +336,15 @@ impl PyProperty { impl Constructor for PyProperty { type Args = FuncArgs; - fn py_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { - Self { + fn py_new(_cls: &Py, _args: FuncArgs, _vm: &VirtualMachine) -> PyResult { + Ok(Self { getter: PyRwLock::new(None), setter: PyRwLock::new(None), deleter: PyRwLock::new(None), doc: PyRwLock::new(None), name: PyRwLock::new(None), getter_doc: AtomicBool::new(false), - } - .into_ref_with_type(vm, cls) - .map(Into::into) + }) } } diff --git a/crates/vm/src/builtins/set.rs b/crates/vm/src/builtins/set.rs index 53ebc931a74..429fd94c2a2 100644 --- a/crates/vm/src/builtins/set.rs +++ b/crates/vm/src/builtins/set.rs @@ -12,7 +12,7 @@ use crate::{ common::{ascii, hash::PyHash, lock::PyMutex, rc::PyRc}, convert::ToPyResult, dict_inner::{self, DictSize}, - function::{ArgIterable, OptionalArg, PosArgs, PyArithmeticValue, PyComparisonValue}, + function::{ArgIterable, FuncArgs, OptionalArg, PosArgs, PyArithmeticValue, PyComparisonValue}, protocol::{PyIterReturn, PyNumberMethods, PySequenceMethods}, recursion::ReprGuard, types::AsNumber, @@ -920,7 +920,8 @@ impl Representable for PySet { impl Constructor for PyFrozenSet { type Args = OptionalArg; - fn py_new(cls: PyTypeRef, iterable: Self::Args, vm: &VirtualMachine) -> PyResult { + fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { + let iterable: Self::Args = args.bind(vm)?; let elements = if let OptionalArg::Present(iterable) = iterable { let iterable = if cls.is(vm.ctx.types.frozenset_type) { match iterable.downcast_exact::(vm) { @@ -943,6 +944,10 @@ impl Constructor for PyFrozenSet { .and_then(|o| o.into_ref_with_type(vm, cls).map(Into::into)) } } + + fn py_new(_cls: &Py, _args: Self::Args, _vm: &VirtualMachine) -> PyResult { + unreachable!("use slot_new") + } } #[pyclass( diff --git a/crates/vm/src/builtins/singletons.rs b/crates/vm/src/builtins/singletons.rs index 7b674cb35b1..bdc032cc865 100644 --- a/crates/vm/src/builtins/singletons.rs +++ b/crates/vm/src/builtins/singletons.rs @@ -3,6 +3,7 @@ use crate::{ Context, Py, PyObjectRef, PyPayload, PyResult, VirtualMachine, class::PyClassImpl, convert::ToPyObject, + function::FuncArgs, protocol::PyNumberMethods, types::{AsNumber, Constructor, Representable}, }; @@ -38,9 +39,14 @@ impl ToPyObject for Option { impl Constructor for PyNone { type Args = (); - fn py_new(_: PyTypeRef, _args: Self::Args, vm: &VirtualMachine) -> PyResult { + fn slot_new(_cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { + let _: () = args.bind(vm)?; Ok(vm.ctx.none.clone().into()) } + + fn py_new(_cls: &Py, _args: Self::Args, _vm: &VirtualMachine) -> PyResult { + unreachable!("None is a singleton") + } } #[pyclass(with(Constructor, AsNumber, Representable))] @@ -87,9 +93,14 @@ impl PyPayload for PyNotImplemented { impl Constructor for PyNotImplemented { type Args = (); - fn py_new(_: PyTypeRef, _args: Self::Args, vm: &VirtualMachine) -> PyResult { + fn slot_new(_cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { + let _: () = args.bind(vm)?; Ok(vm.ctx.not_implemented.clone().into()) } + + fn py_new(_cls: &Py, _args: Self::Args, _vm: &VirtualMachine) -> PyResult { + unreachable!("PyNotImplemented is a singleton") + } } #[pyclass(with(Constructor))] diff --git a/crates/vm/src/builtins/slice.rs b/crates/vm/src/builtins/slice.rs index bcb959ea98c..09a6c462ed5 100644 --- a/crates/vm/src/builtins/slice.rs +++ b/crates/vm/src/builtins/slice.rs @@ -313,9 +313,14 @@ impl PyPayload for PyEllipsis { impl Constructor for PyEllipsis { type Args = (); - fn py_new(_cls: PyTypeRef, _args: Self::Args, vm: &VirtualMachine) -> PyResult { + fn slot_new(_cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { + let _: () = args.bind(vm)?; Ok(vm.ctx.ellipsis.clone().into()) } + + fn py_new(_cls: &Py, _args: Self::Args, _vm: &VirtualMachine) -> PyResult { + unreachable!("Ellipsis is a singleton") + } } #[pyclass(with(Constructor, Representable))] diff --git a/crates/vm/src/builtins/staticmethod.rs b/crates/vm/src/builtins/staticmethod.rs index 36aef728a3a..98717205503 100644 --- a/crates/vm/src/builtins/staticmethod.rs +++ b/crates/vm/src/builtins/staticmethod.rs @@ -43,7 +43,8 @@ impl From for PyStaticMethod { impl Constructor for PyStaticMethod { type Args = PyObjectRef; - fn py_new(cls: PyTypeRef, callable: Self::Args, vm: &VirtualMachine) -> PyResult { + fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { + let callable: Self::Args = args.bind(vm)?; let doc = callable.get_attr("__doc__", vm); let result = Self { @@ -58,6 +59,10 @@ impl Constructor for PyStaticMethod { Ok(obj) } + + fn py_new(_cls: &Py, _args: Self::Args, _vm: &VirtualMachine) -> PyResult { + unreachable!("use slot_new") + } } impl PyStaticMethod { diff --git a/crates/vm/src/builtins/str.rs b/crates/vm/src/builtins/str.rs index 9fa1472c26e..86c3ab9c81f 100644 --- a/crates/vm/src/builtins/str.rs +++ b/crates/vm/src/builtins/str.rs @@ -350,7 +350,8 @@ pub struct StrArgs { impl Constructor for PyStr { type Args = StrArgs; - fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { + fn slot_new(cls: PyTypeRef, func_args: FuncArgs, vm: &VirtualMachine) -> PyResult { + let args: Self::Args = func_args.bind(vm)?; let string: PyRef = match args.object { OptionalArg::Present(input) => { if let OptionalArg::Present(enc) = args.encoding { @@ -376,6 +377,10 @@ impl Constructor for PyStr { .map(Into::into) } } + + fn py_new(_cls: &Py, _args: Self::Args, _vm: &VirtualMachine) -> PyResult { + unreachable!("use slot_new") + } } impl PyStr { diff --git a/crates/vm/src/builtins/super.rs b/crates/vm/src/builtins/super.rs index 419055b79ff..f0d873abfbb 100644 --- a/crates/vm/src/builtins/super.rs +++ b/crates/vm/src/builtins/super.rs @@ -47,16 +47,14 @@ impl PyPayload for PySuper { impl Constructor for PySuper { type Args = FuncArgs; - fn py_new(cls: PyTypeRef, _args: Self::Args, vm: &VirtualMachine) -> PyResult { - let obj = Self { + fn py_new(_cls: &Py, _args: Self::Args, vm: &VirtualMachine) -> PyResult { + Ok(Self { inner: PyRwLock::new(PySuperInner::new( vm.ctx.types.object_type.to_owned(), // is this correct? vm.ctx.none(), vm, )?), - } - .into_ref_with_type(vm, cls)?; - Ok(obj.into()) + }) } } diff --git a/crates/vm/src/builtins/traceback.rs b/crates/vm/src/builtins/traceback.rs index b5a185a8ab6..6bf4070c9b5 100644 --- a/crates/vm/src/builtins/traceback.rs +++ b/crates/vm/src/builtins/traceback.rs @@ -1,4 +1,4 @@ -use super::{PyType, PyTypeRef}; +use super::PyType; use crate::{ Context, Py, PyPayload, PyRef, PyResult, VirtualMachine, class::PyClassImpl, frame::FrameRef, types::Constructor, @@ -71,12 +71,11 @@ impl PyTraceback { impl Constructor for PyTraceback { type Args = (Option>, FrameRef, u32, usize); - fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { + fn py_new(_cls: &Py, args: Self::Args, vm: &VirtualMachine) -> PyResult { let (next, frame, lasti, lineno) = args; let lineno = OneIndexed::new(lineno) .ok_or_else(|| vm.new_value_error("lineno must be positive".to_owned()))?; - let tb = Self::new(next, frame, lasti, lineno); - tb.into_ref_with_type(vm, cls).map(Into::into) + Ok(Self::new(next, frame, lasti, lineno)) } } diff --git a/crates/vm/src/builtins/tuple.rs b/crates/vm/src/builtins/tuple.rs index f6a6dde7914..61a9cf414c4 100644 --- a/crates/vm/src/builtins/tuple.rs +++ b/crates/vm/src/builtins/tuple.rs @@ -8,7 +8,7 @@ use crate::{ atomic_func, class::PyClassImpl, convert::{ToPyObject, TransmuteFromObject}, - function::{ArgSize, OptionalArg, PyArithmeticValue, PyComparisonValue}, + function::{ArgSize, FuncArgs, OptionalArg, PyArithmeticValue, PyComparisonValue}, iter::PyExactSizeIterator, protocol::{PyIterReturn, PyMappingMethods, PySequenceMethods}, recursion::ReprGuard, @@ -112,7 +112,8 @@ pub type PyTupleRef = PyRef; impl Constructor for PyTuple { type Args = OptionalArg; - fn py_new(cls: PyTypeRef, iterable: Self::Args, vm: &VirtualMachine) -> PyResult { + fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { + let iterable: Self::Args = args.bind(vm)?; let elements = if let OptionalArg::Present(iterable) = iterable { let iterable = if cls.is(vm.ctx.types.tuple_type) { match iterable.downcast_exact::(vm) { @@ -137,6 +138,10 @@ impl Constructor for PyTuple { .map(Into::into) } } + + fn py_new(_cls: &Py, _args: Self::Args, _vm: &VirtualMachine) -> PyResult { + unreachable!("use slot_new") + } } impl AsRef<[R]> for PyTuple { diff --git a/crates/vm/src/builtins/type.rs b/crates/vm/src/builtins/type.rs index b9c996371a0..11d74982681 100644 --- a/crates/vm/src/builtins/type.rs +++ b/crates/vm/src/builtins/type.rs @@ -991,7 +991,7 @@ impl PyType { impl Constructor for PyType { type Args = FuncArgs; - fn py_new(metatype: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { + fn slot_new(metatype: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { vm_trace!("type.__new__ {:?}", args); let is_type_type = metatype.is(vm.ctx.types.type_type); @@ -1287,6 +1287,10 @@ impl Constructor for PyType { Ok(typ.into()) } + + fn py_new(_cls: &Py, _args: Self::Args, _vm: &VirtualMachine) -> PyResult { + unreachable!("use slot_new") + } } const SIGNATURE_END_MARKER: &str = ")\n--\n\n"; diff --git a/crates/vm/src/builtins/weakproxy.rs b/crates/vm/src/builtins/weakproxy.rs index 6f01e5eb225..a9221ec876f 100644 --- a/crates/vm/src/builtins/weakproxy.rs +++ b/crates/vm/src/builtins/weakproxy.rs @@ -38,10 +38,10 @@ impl Constructor for PyWeakProxy { type Args = WeakProxyNewArgs; fn py_new( - cls: PyTypeRef, + _cls: &Py, Self::Args { referent, callback }: Self::Args, vm: &VirtualMachine, - ) -> PyResult { + ) -> PyResult { // using an internal subclass as the class prevents us from getting the generic weakref, // which would mess up the weakref count let weak_cls = WEAK_SUBCLASS.get_or_init(|| { @@ -53,11 +53,9 @@ impl Constructor for PyWeakProxy { ) }); // TODO: PyWeakProxy should use the same payload as PyWeak - Self { + Ok(Self { weak: referent.downgrade_with_typ(callback.into_option(), weak_cls.clone(), vm)?, - } - .into_ref_with_type(vm, cls) - .map(Into::into) + }) } } diff --git a/crates/vm/src/builtins/weakref.rs b/crates/vm/src/builtins/weakref.rs index 441cac9b3f9..93edbbecbb1 100644 --- a/crates/vm/src/builtins/weakref.rs +++ b/crates/vm/src/builtins/weakref.rs @@ -6,7 +6,7 @@ use crate::common::{ use crate::{ AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyResult, VirtualMachine, class::PyClassImpl, - function::OptionalArg, + function::{FuncArgs, OptionalArg}, types::{Callable, Comparable, Constructor, Hashable, PyComparisonOp, Representable}, }; @@ -38,14 +38,15 @@ impl Callable for PyWeak { impl Constructor for PyWeak { type Args = WeakNewArgs; - fn py_new( - cls: PyTypeRef, - Self::Args { referent, callback }: Self::Args, - vm: &VirtualMachine, - ) -> PyResult { + fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { + let Self::Args { referent, callback } = args.bind(vm)?; let weak = referent.downgrade_with_typ(callback.into_option(), cls, vm)?; Ok(weak.into()) } + + fn py_new(_cls: &Py, _args: Self::Args, _vm: &VirtualMachine) -> PyResult { + unreachable!("use slot_new") + } } #[pyclass( diff --git a/crates/vm/src/builtins/zip.rs b/crates/vm/src/builtins/zip.rs index 98371d2f6c3..ee3ecb57b27 100644 --- a/crates/vm/src/builtins/zip.rs +++ b/crates/vm/src/builtins/zip.rs @@ -1,4 +1,4 @@ -use super::{PyType, PyTypeRef}; +use super::PyType; use crate::{ AsObject, Context, Py, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject, VirtualMachine, builtins::PyTupleRef, @@ -33,12 +33,14 @@ pub struct PyZipNewArgs { impl Constructor for PyZip { type Args = (PosArgs, PyZipNewArgs); - fn py_new(cls: PyTypeRef, (iterators, args): Self::Args, vm: &VirtualMachine) -> PyResult { + fn py_new( + _cls: &Py, + (iterators, args): Self::Args, + _vm: &VirtualMachine, + ) -> PyResult { let iterators = iterators.into_vec(); let strict = Radium::new(args.strict.unwrap_or(false)); - Self { iterators, strict } - .into_ref_with_type(vm, cls) - .map(Into::into) + Ok(Self { iterators, strict }) } } diff --git a/crates/vm/src/exceptions.rs b/crates/vm/src/exceptions.rs index 9d3d239ad46..a5bc3f0a71b 100644 --- a/crates/vm/src/exceptions.rs +++ b/crates/vm/src/exceptions.rs @@ -707,7 +707,7 @@ impl PyRef { impl Constructor for PyBaseException { type Args = FuncArgs; - fn py_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { + fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { if cls.is(Self::class(&vm.ctx)) && !args.kwargs.is_empty() { return Err(vm.new_type_error("BaseException() takes no keyword arguments")); } @@ -715,6 +715,10 @@ impl Constructor for PyBaseException { .into_ref_with_type(vm, cls) .map(Into::into) } + + fn py_new(_cls: &Py, _args: FuncArgs, _vm: &VirtualMachine) -> PyResult { + unreachable!("use slot_new") + } } impl Initializer for PyBaseException { diff --git a/crates/vm/src/protocol/object.rs b/crates/vm/src/protocol/object.rs index 0e8d7cf5fa7..744eba9c555 100644 --- a/crates/vm/src/protocol/object.rs +++ b/crates/vm/src/protocol/object.rs @@ -4,8 +4,8 @@ use crate::{ AsObject, Py, PyObject, PyObjectRef, PyRef, PyResult, TryFromObject, VirtualMachine, builtins::{ - PyAsyncGen, PyBytes, PyDict, PyDictRef, PyGenericAlias, PyInt, PyList, PyStr, PyTuple, - PyTupleRef, PyType, PyTypeRef, PyUtf8Str, pystr::AsPyStr, + PyAsyncGen, PyDict, PyDictRef, PyGenericAlias, PyInt, PyList, PyStr, PyTuple, PyTupleRef, + PyType, PyTypeRef, PyUtf8Str, pystr::AsPyStr, }, bytes_inner::ByteInnerNewOptions, common::{hash::PyHash, str::to_ascii}, @@ -14,7 +14,7 @@ use crate::{ function::{Either, OptionalArg, PyArithmeticValue, PySetterValue}, object::PyPayload, protocol::{PyIter, PyMapping, PySequence}, - types::{Constructor, PyComparisonOp}, + types::PyComparisonOp, }; // RustPython doesn't need these items @@ -36,15 +36,14 @@ impl PyObjectRef { let bytes_type = vm.ctx.types.bytes_type; match self.downcast_exact::(vm) { Ok(int) => Err(vm.new_downcast_type_error(bytes_type, &int)), - Err(obj) => PyBytes::py_new( - bytes_type.to_owned(), - ByteInnerNewOptions { + Err(obj) => { + let options = ByteInnerNewOptions { source: OptionalArg::Present(obj), encoding: OptionalArg::Missing, errors: OptionalArg::Missing, - }, - vm, - ), + }; + options.get_bytes(bytes_type.to_owned(), vm).map(Into::into) + } } } diff --git a/crates/vm/src/stdlib/ast/python.rs b/crates/vm/src/stdlib/ast/python.rs index 40ab3ce72dd..ef8a85f85f2 100644 --- a/crates/vm/src/stdlib/ast/python.rs +++ b/crates/vm/src/stdlib/ast/python.rs @@ -3,8 +3,8 @@ use super::{PY_CF_OPTIMIZED_AST, PY_CF_TYPE_COMMENTS, PY_COMPILE_FLAG_AST_ONLY}; #[pymodule] pub(crate) mod _ast { use crate::{ - AsObject, Context, PyObjectRef, PyPayload, PyResult, VirtualMachine, - builtins::{PyStrRef, PyTupleRef, PyTypeRef}, + AsObject, Context, Py, PyObjectRef, PyPayload, PyResult, VirtualMachine, + builtins::{PyStrRef, PyTupleRef, PyType, PyTypeRef}, function::FuncArgs, types::Constructor, }; @@ -76,8 +76,8 @@ pub(crate) mod _ast { Ok(zelf) } - fn py_new(_cls: PyTypeRef, _args: Self::Args, _vm: &VirtualMachine) -> PyResult { - unreachable!("slow_new is implemented"); + fn py_new(_cls: &Py, _args: Self::Args, _vm: &VirtualMachine) -> PyResult { + unreachable!("use slot_new") } } diff --git a/crates/vm/src/stdlib/collections.rs b/crates/vm/src/stdlib/collections.rs index 651a470bfa3..32596b65386 100644 --- a/crates/vm/src/stdlib/collections.rs +++ b/crates/vm/src/stdlib/collections.rs @@ -7,7 +7,7 @@ mod _collections { atomic_func, builtins::{ IterStatus::{Active, Exhausted}, - PositionIterInternal, PyGenericAlias, PyInt, PyTypeRef, + PositionIterInternal, PyGenericAlias, PyInt, PyType, PyTypeRef, }, common::lock::{PyMutex, PyRwLock, PyRwLockReadGuard, PyRwLockWriteGuard}, function::{KwArgs, OptionalArg, PyComparisonValue}, @@ -606,16 +606,16 @@ mod _collections { type Args = (DequeIterArgs, KwArgs); fn py_new( - cls: PyTypeRef, + _cls: &Py, (DequeIterArgs { deque, index }, _kwargs): Self::Args, - vm: &VirtualMachine, - ) -> PyResult { + _vm: &VirtualMachine, + ) -> PyResult { let iter = Self::new(deque); if let OptionalArg::Present(index) = index { let index = max(index, 0) as usize; iter.internal.lock().position = index; } - iter.into_ref_with_type(vm, cls).map(Into::into) + Ok(iter) } } @@ -678,17 +678,16 @@ mod _collections { type Args = (DequeIterArgs, KwArgs); fn py_new( - cls: PyTypeRef, - + _cls: &Py, (DequeIterArgs { deque, index }, _kwargs): Self::Args, - vm: &VirtualMachine, - ) -> PyResult { + _vm: &VirtualMachine, + ) -> PyResult { let iter = PyDeque::__reversed__(deque)?; if let OptionalArg::Present(index) = index { let index = max(index, 0) as usize; iter.internal.lock().position = index; } - iter.into_ref_with_type(vm, cls).map(Into::into) + Ok(iter) } } diff --git a/crates/vm/src/stdlib/ctypes/array.rs b/crates/vm/src/stdlib/ctypes/array.rs index 62d714329e6..d87679f3595 100644 --- a/crates/vm/src/stdlib/ctypes/array.rs +++ b/crates/vm/src/stdlib/ctypes/array.rs @@ -75,8 +75,8 @@ impl Callable for PyCArrayType { impl Constructor for PyCArrayType { type Args = PyObjectRef; - fn py_new(_cls: PyTypeRef, _args: Self::Args, _vm: &VirtualMachine) -> PyResult { - unreachable!() + fn py_new(_cls: &Py, _args: Self::Args, _vm: &VirtualMachine) -> PyResult { + unreachable!("use slot_new") } } @@ -249,7 +249,7 @@ impl std::fmt::Debug for PyCArray { impl Constructor for PyCArray { type Args = FuncArgs; - fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { + fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { // Get _type_ and _length_ from the class let type_attr = cls.as_object().get_attr("_type_", vm).ok(); let length_attr = cls.as_object().get_attr("_length_", vm).ok(); @@ -287,7 +287,7 @@ impl Constructor for PyCArray { } let offset = i * element_size; if let Ok(int_val) = value.try_int(vm) { - let bytes = Self::int_to_bytes(int_val.as_bigint(), element_size); + let bytes = PyCArray::int_to_bytes(int_val.as_bigint(), element_size); if offset + element_size <= buffer.len() { buffer[offset..offset + element_size].copy_from_slice(&bytes); } @@ -303,6 +303,10 @@ impl Constructor for PyCArray { .into_ref_with_type(vm, cls) .map(Into::into) } + + fn py_new(_cls: &Py, _args: Self::Args, _vm: &VirtualMachine) -> PyResult { + unreachable!("use slot_new") + } } impl AsSequence for PyCArray { diff --git a/crates/vm/src/stdlib/ctypes/base.rs b/crates/vm/src/stdlib/ctypes/base.rs index 5e2deeb5607..6b03e0e2348 100644 --- a/crates/vm/src/stdlib/ctypes/base.rs +++ b/crates/vm/src/stdlib/ctypes/base.rs @@ -3,7 +3,7 @@ use super::array::PyCArrayType; use super::util::StgInfo; use crate::builtins::{PyBytes, PyFloat, PyInt, PyNone, PyStr, PyStrRef, PyType, PyTypeRef}; use crate::convert::ToPyObject; -use crate::function::{ArgBytesLike, Either, OptionalArg}; +use crate::function::{ArgBytesLike, Either, FuncArgs, KwArgs, OptionalArg}; use crate::protocol::{BufferDescriptor, BufferMethods, PyBuffer, PyNumberMethods}; use crate::stdlib::ctypes::_ctypes::new_simple_type; use crate::types::{AsBuffer, AsNumber, Constructor}; @@ -610,7 +610,8 @@ fn value_to_bytes_endian( impl Constructor for PyCSimple { type Args = (OptionalArg,); - fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { + fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { + let args: Self::Args = args.bind(vm)?; let attributes = cls.get_attributes(); let _type_ = attributes .iter() @@ -659,6 +660,10 @@ impl Constructor for PyCSimple { .into_ref_with_type(vm, cls) .map(Into::into) } + + fn py_new(_cls: &Py, _args: Self::Args, _vm: &VirtualMachine) -> PyResult { + unreachable!("use slot_new") + } } #[pyclass(flags(BASETYPE), with(Constructor, AsBuffer))] @@ -796,8 +801,8 @@ impl PyCSimple { }; // Create instance using the type's constructor - let instance = PyCSimple::py_new(cls.clone(), (OptionalArg::Present(value),), vm)?; - Ok(instance) + let args = FuncArgs::new(vec![value], KwArgs::default()); + PyCSimple::slot_new(cls.clone(), args, vm) } #[pyclassmethod] @@ -846,7 +851,8 @@ impl PyCSimple { let value = bytes_to_pyobject(&cls, data, vm)?; // Create instance - let instance = PyCSimple::py_new(cls.clone(), (OptionalArg::Present(value),), vm)?; + let args = FuncArgs::new(vec![value], KwArgs::default()); + let instance = PyCSimple::slot_new(cls.clone(), args, vm)?; // TODO: Store reference to source in _objects to keep buffer alive Ok(instance) @@ -892,7 +898,8 @@ impl PyCSimple { let value = bytes_to_pyobject(&cls, data, vm)?; // Create instance (independent copy, no reference tracking) - PyCSimple::py_new(cls.clone(), (OptionalArg::Present(value),), vm) + let args = FuncArgs::new(vec![value], KwArgs::default()); + PyCSimple::slot_new(cls.clone(), args, vm) } #[pyclassmethod] @@ -959,7 +966,8 @@ impl PyCSimple { }; // Create instance - let instance = PyCSimple::py_new(cls.clone(), (OptionalArg::Present(value),), vm)?; + let args = FuncArgs::new(vec![value], KwArgs::default()); + let instance = PyCSimple::slot_new(cls.clone(), args, vm)?; // Store base reference to keep dll alive if let Ok(simple_ref) = instance.clone().downcast::() { diff --git a/crates/vm/src/stdlib/ctypes/function.rs b/crates/vm/src/stdlib/ctypes/function.rs index 27e85c563ef..8784fd55ef5 100644 --- a/crates/vm/src/stdlib/ctypes/function.rs +++ b/crates/vm/src/stdlib/ctypes/function.rs @@ -186,14 +186,14 @@ impl Debug for PyCFuncPtr { impl Constructor for PyCFuncPtr { type Args = FuncArgs; - fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { + fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { // Handle different argument forms like CPython: // 1. Empty args: create uninitialized // 2. One integer argument: function address // 3. Tuple argument: (name, dll) form if args.args.is_empty() { - return Self { + return PyCFuncPtr { ptr: PyRwLock::new(None), needs_free: AtomicCell::new(false), arg_types: PyRwLock::new(None), @@ -211,7 +211,7 @@ impl Constructor for PyCFuncPtr { // Check if first argument is an integer (function address) if let Ok(addr) = first_arg.try_int(vm) { let ptr_val = addr.as_bigint().to_usize().unwrap_or(0); - return Self { + return PyCFuncPtr { ptr: PyRwLock::new(Some(CodePtr(ptr_val as *mut _))), needs_free: AtomicCell::new(false), arg_types: PyRwLock::new(None), @@ -270,7 +270,7 @@ impl Constructor for PyCFuncPtr { None }; - return Self { + return PyCFuncPtr { ptr: PyRwLock::new(code_ptr), needs_free: AtomicCell::new(false), arg_types: PyRwLock::new(None), @@ -313,7 +313,7 @@ impl Constructor for PyCFuncPtr { // Store the thunk as a Python object to keep it alive let thunk_ref: PyRef = thunk.into_ref(&vm.ctx); - return Self { + return PyCFuncPtr { ptr: PyRwLock::new(Some(code_ptr)), needs_free: AtomicCell::new(true), arg_types: PyRwLock::new(arg_type_vec), @@ -328,6 +328,10 @@ impl Constructor for PyCFuncPtr { Err(vm.new_type_error("Expected an integer address or a tuple")) } + + fn py_new(_cls: &Py, _args: Self::Args, _vm: &VirtualMachine) -> PyResult { + unreachable!("use slot_new") + } } impl Callable for PyCFuncPtr { diff --git a/crates/vm/src/stdlib/ctypes/pointer.rs b/crates/vm/src/stdlib/ctypes/pointer.rs index cd9ba8a7a15..d7fbd67b157 100644 --- a/crates/vm/src/stdlib/ctypes/pointer.rs +++ b/crates/vm/src/stdlib/ctypes/pointer.rs @@ -4,10 +4,11 @@ use rustpython_common::lock::PyRwLock; use crate::builtins::{PyType, PyTypeRef}; use crate::convert::ToPyObject; +use crate::function::FuncArgs; use crate::protocol::PyNumberMethods; use crate::stdlib::ctypes::PyCData; use crate::types::{AsNumber, Constructor}; -use crate::{AsObject, PyObjectRef, PyPayload, PyResult, VirtualMachine}; +use crate::{AsObject, Py, PyObjectRef, PyPayload, PyResult, VirtualMachine}; use super::util::StgInfo; @@ -75,7 +76,8 @@ pub struct PyCPointer { impl Constructor for PyCPointer { type Args = (crate::function::OptionalArg,); - fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { + fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { + let args: Self::Args = args.bind(vm)?; // Get the initial contents value if provided let initial_contents = args.0.into_option().unwrap_or_else(|| vm.ctx.none()); @@ -86,6 +88,10 @@ impl Constructor for PyCPointer { .into_ref_with_type(vm, cls) .map(Into::into) } + + fn py_new(_cls: &Py, _args: Self::Args, _vm: &VirtualMachine) -> PyResult { + unreachable!("use slot_new") + } } #[pyclass(flags(BASETYPE, IMMUTABLETYPE), with(Constructor))] diff --git a/crates/vm/src/stdlib/ctypes/structure.rs b/crates/vm/src/stdlib/ctypes/structure.rs index 1c842e21b5c..58acc26d4ce 100644 --- a/crates/vm/src/stdlib/ctypes/structure.rs +++ b/crates/vm/src/stdlib/ctypes/structure.rs @@ -25,9 +25,9 @@ pub struct PyCStructType { impl Constructor for PyCStructType { type Args = FuncArgs; - fn py_new(metatype: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { + fn slot_new(metatype: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { // 1. Create the new class using PyType::py_new - let new_class = crate::builtins::type_::PyType::py_new(metatype, args, vm)?; + let new_class = crate::builtins::type_::PyType::slot_new(metatype, args, vm)?; // 2. Process _fields_ if defined on the new class let new_type = new_class @@ -42,6 +42,10 @@ impl Constructor for PyCStructType { Ok(new_class) } + + fn py_new(_cls: &Py, _args: Self::Args, _vm: &VirtualMachine) -> PyResult { + unreachable!("use slot_new") + } } #[pyclass(flags(BASETYPE), with(AsNumber, Constructor))] @@ -239,7 +243,7 @@ impl Debug for PyCStructure { impl Constructor for PyCStructure { type Args = FuncArgs; - fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { + fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { // Get _fields_ from the class using get_attr to properly search MRO let fields_attr = cls.as_object().get_attr("_fields_", vm).ok(); @@ -326,6 +330,10 @@ impl Constructor for PyCStructure { Ok(py_instance.into()) } + + fn py_new(_cls: &Py, _args: Self::Args, _vm: &VirtualMachine) -> PyResult { + unreachable!("use slot_new") + } } // Note: GetAttr and SetAttr are not implemented here. diff --git a/crates/vm/src/stdlib/ctypes/union.rs b/crates/vm/src/stdlib/ctypes/union.rs index aa78d56c46b..d260cfc9ecf 100644 --- a/crates/vm/src/stdlib/ctypes/union.rs +++ b/crates/vm/src/stdlib/ctypes/union.rs @@ -29,9 +29,9 @@ impl Default for PyCUnionType { impl Constructor for PyCUnionType { type Args = FuncArgs; - fn py_new(metatype: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { + fn slot_new(metatype: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { // 1. Create the new class using PyType::py_new - let new_class = crate::builtins::type_::PyType::py_new(metatype, args, vm)?; + let new_class = crate::builtins::type_::PyType::slot_new(metatype, args, vm)?; // 2. Process _fields_ if defined on the new class let new_type = new_class @@ -46,6 +46,10 @@ impl Constructor for PyCUnionType { Ok(new_class) } + + fn py_new(_cls: &Py, _args: Self::Args, _vm: &VirtualMachine) -> PyResult { + unreachable!("use slot_new") + } } impl PyCUnionType { @@ -144,7 +148,7 @@ impl std::fmt::Debug for PyCUnion { impl Constructor for PyCUnion { type Args = FuncArgs; - fn py_new(cls: PyTypeRef, _args: Self::Args, vm: &VirtualMachine) -> PyResult { + fn slot_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { // Get _fields_ from the class let fields_attr = cls.as_object().get_attr("_fields_", vm).ok(); @@ -185,6 +189,10 @@ impl Constructor for PyCUnion { .into_ref_with_type(vm, cls) .map(Into::into) } + + fn py_new(_cls: &Py, _args: Self::Args, _vm: &VirtualMachine) -> PyResult { + unreachable!("use slot_new") + } } #[pyclass(flags(BASETYPE, IMMUTABLETYPE), with(Constructor, AsBuffer))] diff --git a/crates/vm/src/stdlib/functools.rs b/crates/vm/src/stdlib/functools.rs index 21724db8922..d5a42739e96 100644 --- a/crates/vm/src/stdlib/functools.rs +++ b/crates/vm/src/stdlib/functools.rs @@ -204,7 +204,11 @@ mod _functools { impl Constructor for PyPartial { type Args = FuncArgs; - fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { + fn py_new( + _cls: &crate::Py, + args: Self::Args, + vm: &VirtualMachine, + ) -> PyResult { let (func, args_slice) = args .args .split_first() @@ -230,15 +234,13 @@ mod _functools { final_keywords.set_item(vm.ctx.intern_str(key.as_str()), value, vm)?; } - let partial = Self { + Ok(Self { inner: PyRwLock::new(PyPartialInner { func: final_func, args: vm.ctx.new_tuple(final_args), keywords: final_keywords, }), - }; - - partial.into_ref_with_type(vm, cls).map(Into::into) + }) } } diff --git a/crates/vm/src/stdlib/io.rs b/crates/vm/src/stdlib/io.rs index c373f88d20b..c54f3b853dc 100644 --- a/crates/vm/src/stdlib/io.rs +++ b/crates/vm/src/stdlib/io.rs @@ -3637,20 +3637,18 @@ mod _io { #[allow(unused_variables)] fn py_new( - cls: PyTypeRef, + _cls: &Py, Self::Args { object, newline }: Self::Args, - vm: &VirtualMachine, - ) -> PyResult { + _vm: &VirtualMachine, + ) -> PyResult { let raw_bytes = object .flatten() .map_or_else(Vec::new, |v| v.as_bytes().to_vec()); - Self { + Ok(Self { buffer: PyRwLock::new(BufferedIO::new(Cursor::new(raw_bytes))), closed: AtomicCell::new(false), - } - .into_ref_with_type(vm, cls) - .map(Into::into) + }) } } @@ -3770,18 +3768,16 @@ mod _io { impl Constructor for BytesIO { type Args = OptionalArg>; - fn py_new(cls: PyTypeRef, object: Self::Args, vm: &VirtualMachine) -> PyResult { + fn py_new(_cls: &Py, object: Self::Args, _vm: &VirtualMachine) -> PyResult { let raw_bytes = object .flatten() .map_or_else(Vec::new, |input| input.as_bytes().to_vec()); - Self { + Ok(Self { buffer: PyRwLock::new(BufferedIO::new(Cursor::new(raw_bytes))), closed: AtomicCell::new(false), exports: AtomicCell::new(0), - } - .into_ref_with_type(vm, cls) - .map(Into::into) + }) } } diff --git a/crates/vm/src/stdlib/itertools.rs b/crates/vm/src/stdlib/itertools.rs index ba629a88770..2956654185d 100644 --- a/crates/vm/src/stdlib/itertools.rs +++ b/crates/vm/src/stdlib/itertools.rs @@ -7,7 +7,7 @@ mod decl { AsObject, Py, PyObjectRef, PyPayload, PyRef, PyResult, PyWeakRef, TryFromObject, VirtualMachine, builtins::{ - PyGenericAlias, PyInt, PyIntRef, PyList, PyTuple, PyTupleRef, PyTypeRef, int, + PyGenericAlias, PyInt, PyIntRef, PyList, PyTuple, PyTupleRef, PyType, PyTypeRef, int, tuple::IntoPyTuple, }, common::{ @@ -201,13 +201,11 @@ mod decl { type Args = CompressNewArgs; fn py_new( - cls: PyTypeRef, + _cls: &Py, Self::Args { data, selectors }: Self::Args, - vm: &VirtualMachine, - ) -> PyResult { - Self { data, selectors } - .into_ref_with_type(vm, cls) - .map(Into::into) + _vm: &VirtualMachine, + ) -> PyResult { + Ok(Self { data, selectors }) } } @@ -260,22 +258,20 @@ mod decl { type Args = CountNewArgs; fn py_new( - cls: PyTypeRef, + _cls: &Py, Self::Args { start, step }: Self::Args, vm: &VirtualMachine, - ) -> PyResult { + ) -> PyResult { let start = start.into_option().unwrap_or_else(|| vm.new_pyobj(0)); let step = step.into_option().unwrap_or_else(|| vm.new_pyobj(1)); if !PyNumber::check(&start) || !PyNumber::check(&step) { return Err(vm.new_type_error("a number is required")); } - Self { + Ok(Self { cur: PyRwLock::new(start), step, - } - .into_ref_with_type(vm, cls) - .map(Into::into) + }) } } @@ -327,14 +323,12 @@ mod decl { impl Constructor for PyItertoolsCycle { type Args = PyIter; - fn py_new(cls: PyTypeRef, iter: Self::Args, vm: &VirtualMachine) -> PyResult { - Self { + fn py_new(_cls: &Py, iter: Self::Args, _vm: &VirtualMachine) -> PyResult { + Ok(Self { iter, saved: PyRwLock::new(Vec::new()), index: AtomicCell::new(0), - } - .into_ref_with_type(vm, cls) - .map(Into::into) + }) } } @@ -386,10 +380,10 @@ mod decl { type Args = PyRepeatNewArgs; fn py_new( - cls: PyTypeRef, + _cls: &Py, Self::Args { object, times }: Self::Args, vm: &VirtualMachine, - ) -> PyResult { + ) -> PyResult { let times = match times.into_option() { Some(int) => { let val: isize = int.try_to_primitive(vm)?; @@ -398,9 +392,7 @@ mod decl { } None => None, }; - Self { object, times } - .into_ref_with_type(vm, cls) - .map(Into::into) + Ok(Self { object, times }) } } @@ -474,13 +466,11 @@ mod decl { type Args = StarmapNewArgs; fn py_new( - cls: PyTypeRef, + _cls: &Py, Self::Args { function, iterable }: Self::Args, - vm: &VirtualMachine, - ) -> PyResult { - Self { function, iterable } - .into_ref_with_type(vm, cls) - .map(Into::into) + _vm: &VirtualMachine, + ) -> PyResult { + Ok(Self { function, iterable }) } } @@ -536,20 +526,18 @@ mod decl { type Args = TakewhileNewArgs; fn py_new( - cls: PyTypeRef, + _cls: &Py, Self::Args { predicate, iterable, }: Self::Args, - vm: &VirtualMachine, - ) -> PyResult { - Self { + _vm: &VirtualMachine, + ) -> PyResult { + Ok(Self { predicate, iterable, stop_flag: AtomicCell::new(false), - } - .into_ref_with_type(vm, cls) - .map(Into::into) + }) } } @@ -624,20 +612,18 @@ mod decl { type Args = DropwhileNewArgs; fn py_new( - cls: PyTypeRef, + _cls: &Py, Self::Args { predicate, iterable, }: Self::Args, - vm: &VirtualMachine, - ) -> PyResult { - Self { + _vm: &VirtualMachine, + ) -> PyResult { + Ok(Self { predicate, iterable, start_flag: AtomicCell::new(false), - } - .into_ref_with_type(vm, cls) - .map(Into::into) + }) } } @@ -748,17 +734,15 @@ mod decl { type Args = GroupByArgs; fn py_new( - cls: PyTypeRef, + _cls: &Py, Self::Args { iterable, key }: Self::Args, - vm: &VirtualMachine, - ) -> PyResult { - Self { + _vm: &VirtualMachine, + ) -> PyResult { + Ok(Self { iterable, key_func: key.flatten(), state: PyMutex::new(GroupByState::default()), - } - .into_ref_with_type(vm, cls) - .map(Into::into) + }) } } @@ -1039,19 +1023,17 @@ mod decl { type Args = FilterFalseNewArgs; fn py_new( - cls: PyTypeRef, + _cls: &Py, Self::Args { predicate, iterable, }: Self::Args, - vm: &VirtualMachine, - ) -> PyResult { - Self { + _vm: &VirtualMachine, + ) -> PyResult { + Ok(Self { predicate, iterable, - } - .into_ref_with_type(vm, cls) - .map(Into::into) + }) } } @@ -1114,15 +1096,13 @@ mod decl { impl Constructor for PyItertoolsAccumulate { type Args = AccumulateArgs; - fn py_new(cls: PyTypeRef, args: AccumulateArgs, vm: &VirtualMachine) -> PyResult { - Self { + fn py_new(_cls: &Py, args: AccumulateArgs, _vm: &VirtualMachine) -> PyResult { + Ok(Self { iterable: args.iterable, bin_op: args.func.flatten(), initial: args.initial.flatten(), acc_value: PyRwLock::new(None), - } - .into_ref_with_type(vm, cls) - .map(Into::into) + }) } } @@ -1257,11 +1237,8 @@ mod decl { // TODO: make tee() a function, rename this class to itertools._tee and make // teedata a python class - fn py_new( - _cls: PyTypeRef, - Self::Args { iterable, n }: Self::Args, - vm: &VirtualMachine, - ) -> PyResult { + fn slot_new(_cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { + let TeeNewArgs { iterable, n } = args.bind(vm)?; let n = n.unwrap_or(2); let copyable = if iterable.class().has_attr(identifier!(vm, __copy__)) { @@ -1277,6 +1254,10 @@ mod decl { Ok(PyTuple::new_ref(tee_vec, &vm.ctx).into()) } + + fn py_new(_cls: &Py, _args: Self::Args, _vm: &VirtualMachine) -> PyResult { + unreachable!("use slot_new") + } } #[pyclass(with(IterNext, Iterable, Constructor))] @@ -1330,7 +1311,11 @@ mod decl { impl Constructor for PyItertoolsProduct { type Args = (PosArgs, ProductArgs); - fn py_new(cls: PyTypeRef, (iterables, args): Self::Args, vm: &VirtualMachine) -> PyResult { + fn py_new( + _cls: &Py, + (iterables, args): Self::Args, + vm: &VirtualMachine, + ) -> PyResult { let repeat = args.repeat.unwrap_or(1); let mut pools = Vec::new(); for arg in iterables.iter() { @@ -1342,14 +1327,12 @@ mod decl { let l = pools.len(); - Self { + Ok(Self { pools, idxs: PyRwLock::new(vec![0; l]), cur: AtomicCell::new(l.wrapping_sub(1)), stop: AtomicCell::new(false), - } - .into_ref_with_type(vm, cls) - .map(Into::into) + }) } } @@ -1485,10 +1468,10 @@ mod decl { type Args = CombinationsNewArgs; fn py_new( - cls: PyTypeRef, + _cls: &Py, Self::Args { iterable, r }: Self::Args, vm: &VirtualMachine, - ) -> PyResult { + ) -> PyResult { let pool: Vec<_> = iterable.try_to_value(vm)?; let r = r.as_bigint(); @@ -1499,15 +1482,13 @@ mod decl { let n = pool.len(); - Self { + Ok(Self { pool, indices: PyRwLock::new((0..r).collect()), result: PyRwLock::new(None), r: AtomicCell::new(r), exhausted: AtomicCell::new(r > n), - } - .into_ref_with_type(vm, cls) - .map(Into::into) + }) } } @@ -1618,10 +1599,10 @@ mod decl { type Args = CombinationsNewArgs; fn py_new( - cls: PyTypeRef, + _cls: &Py, Self::Args { iterable, r }: Self::Args, vm: &VirtualMachine, - ) -> PyResult { + ) -> PyResult { let pool: Vec<_> = iterable.try_to_value(vm)?; let r = r.as_bigint(); if r.is_negative() { @@ -1631,14 +1612,12 @@ mod decl { let n = pool.len(); - Self { + Ok(Self { pool, indices: PyRwLock::new(vec![0; r]), r: AtomicCell::new(r), exhausted: AtomicCell::new(n == 0 && r > 0), - } - .into_ref_with_type(vm, cls) - .map(Into::into) + }) } } @@ -1716,10 +1695,10 @@ mod decl { type Args = PermutationsNewArgs; fn py_new( - cls: PyTypeRef, + _cls: &Py, Self::Args { iterable, r }: Self::Args, vm: &VirtualMachine, - ) -> PyResult { + ) -> PyResult { let pool: Vec<_> = iterable.try_to_value(vm)?; let n = pool.len(); @@ -1740,16 +1719,14 @@ mod decl { None => n, }; - Self { + Ok(Self { pool, indices: PyRwLock::new((0..n).collect()), cycles: PyRwLock::new((0..r.min(n)).map(|i| n - i).collect()), result: PyRwLock::new(None), r: AtomicCell::new(r), exhausted: AtomicCell::new(r > n), - } - .into_ref_with_type(vm, cls) - .map(Into::into) + }) } } @@ -1847,15 +1824,17 @@ mod decl { impl Constructor for PyItertoolsZipLongest { type Args = (PosArgs, ZipLongestArgs); - fn py_new(cls: PyTypeRef, (iterators, args): Self::Args, vm: &VirtualMachine) -> PyResult { + fn py_new( + _cls: &Py, + (iterators, args): Self::Args, + vm: &VirtualMachine, + ) -> PyResult { let fillvalue = args.fillvalue.unwrap_or_none(vm); let iterators = iterators.into_vec(); - Self { + Ok(Self { iterators, fillvalue: PyRwLock::new(fillvalue), - } - .into_ref_with_type(vm, cls) - .map(Into::into) + }) } } @@ -1933,13 +1912,11 @@ mod decl { impl Constructor for PyItertoolsPairwise { type Args = PyIter; - fn py_new(cls: PyTypeRef, iterator: Self::Args, vm: &VirtualMachine) -> PyResult { - Self { + fn py_new(_cls: &Py, iterator: Self::Args, _vm: &VirtualMachine) -> PyResult { + Ok(Self { iterator, old: PyRwLock::new(None), - } - .into_ref_with_type(vm, cls) - .map(Into::into) + }) } } @@ -1997,14 +1974,14 @@ mod decl { type Args = BatchedNewArgs; fn py_new( - cls: PyTypeRef, + _cls: &Py, Self::Args { iterable_ref, n, strict, }: Self::Args, vm: &VirtualMachine, - ) -> PyResult { + ) -> PyResult { let n = n.as_bigint(); if n.lt(&BigInt::one()) { return Err(vm.new_value_error("n must be at least one")); @@ -2014,14 +1991,12 @@ mod decl { .ok_or(vm.new_overflow_error("Python int too large to convert to usize"))?; let iterable = iterable_ref.get_iter(vm)?; - Self { + Ok(Self { iterable, n: AtomicCell::new(n), exhausted: AtomicCell::new(false), strict: AtomicCell::new(strict), - } - .into_ref_with_type(vm, cls) - .map(Into::into) + }) } } diff --git a/crates/vm/src/stdlib/operator.rs b/crates/vm/src/stdlib/operator.rs index f13c00ac1de..d61adaea561 100644 --- a/crates/vm/src/stdlib/operator.rs +++ b/crates/vm/src/stdlib/operator.rs @@ -4,7 +4,7 @@ pub(crate) use _operator::make_module; mod _operator { use crate::{ AsObject, Py, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, - builtins::{PyInt, PyIntRef, PyStr, PyStrRef, PyTupleRef, PyTypeRef}, + builtins::{PyInt, PyIntRef, PyStr, PyStrRef, PyTupleRef, PyType, PyTypeRef}, common::wtf8::Wtf8, function::{ArgBytesLike, Either, FuncArgs, KwArgs, OptionalArg}, identifier, @@ -388,7 +388,7 @@ mod _operator { impl Constructor for PyAttrGetter { type Args = FuncArgs; - fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { + fn py_new(_cls: &Py, args: Self::Args, vm: &VirtualMachine) -> PyResult { let n_attr = args.args.len(); // Check we get no keyword and at least one positional. if !args.kwargs.is_empty() { @@ -405,7 +405,7 @@ mod _operator { return Err(vm.new_type_error("attribute name must be a string")); } } - Self { attrs }.into_ref_with_type(vm, cls).map(Into::into) + Ok(Self { attrs }) } } @@ -464,7 +464,7 @@ mod _operator { impl Constructor for PyItemGetter { type Args = FuncArgs; - fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { + fn py_new(_cls: &Py, args: Self::Args, vm: &VirtualMachine) -> PyResult { // Check we get no keyword and at least one positional. if !args.kwargs.is_empty() { return Err(vm.new_type_error("itemgetter() takes no keyword arguments")); @@ -472,9 +472,7 @@ mod _operator { if args.args.is_empty() { return Err(vm.new_type_error("itemgetter expected 1 argument, got 0.")); } - Self { items: args.args } - .into_ref_with_type(vm, cls) - .map(Into::into) + Ok(Self { items: args.args }) } } @@ -550,11 +548,13 @@ mod _operator { impl Constructor for PyMethodCaller { type Args = (PyObjectRef, FuncArgs); - fn py_new(cls: PyTypeRef, (name, args): Self::Args, vm: &VirtualMachine) -> PyResult { + fn py_new( + _cls: &Py, + (name, args): Self::Args, + vm: &VirtualMachine, + ) -> PyResult { if let Ok(name) = name.try_into_value(vm) { - Self { name, args } - .into_ref_with_type(vm, cls) - .map(Into::into) + Ok(Self { name, args }) } else { Err(vm.new_type_error("method name must be a string")) } diff --git a/crates/vm/src/stdlib/posix.rs b/crates/vm/src/stdlib/posix.rs index 6a6703f48a5..680e9914a03 100644 --- a/crates/vm/src/stdlib/posix.rs +++ b/crates/vm/src/stdlib/posix.rs @@ -24,7 +24,7 @@ pub(crate) fn make_module(vm: &VirtualMachine) -> PyRef { pub mod module { use crate::{ AsObject, Py, PyObjectRef, PyPayload, PyResult, VirtualMachine, - builtins::{PyDictRef, PyInt, PyListRef, PyStrRef, PyTupleRef, PyTypeRef, PyUtf8StrRef}, + builtins::{PyDictRef, PyInt, PyListRef, PyStrRef, PyTupleRef, PyType, PyUtf8StrRef}, convert::{IntoPyException, ToPyObject, TryFromObject}, function::{Either, KwArgs, OptionalArg}, ospath::{IOErrorBuilder, OsPath, OsPathOrFd}, @@ -832,12 +832,10 @@ pub mod module { impl Constructor for SchedParam { type Args = SchedParamArg; - fn py_new(cls: PyTypeRef, arg: Self::Args, vm: &VirtualMachine) -> PyResult { - Self { + fn py_new(_cls: &Py, arg: Self::Args, _vm: &VirtualMachine) -> PyResult { + Ok(Self { sched_priority: arg.sched_priority, - } - .into_ref_with_type(vm, cls) - .map(Into::into) + }) } } diff --git a/crates/vm/src/stdlib/thread.rs b/crates/vm/src/stdlib/thread.rs index 9e494456538..36252279397 100644 --- a/crates/vm/src/stdlib/thread.rs +++ b/crates/vm/src/stdlib/thread.rs @@ -6,7 +6,7 @@ pub(crate) use _thread::{RawRMutex, make_module}; pub(crate) mod _thread { use crate::{ AsObject, Py, PyPayload, PyRef, PyResult, VirtualMachine, - builtins::{PyDictRef, PyStr, PyTupleRef, PyTypeRef}, + builtins::{PyDictRef, PyStr, PyTupleRef, PyType, PyTypeRef}, convert::ToPyException, function::{ArgCallable, Either, FuncArgs, KwArgs, OptionalArg, PySetterValue}, types::{Constructor, GetAttr, Representable, SetAttr}, @@ -171,7 +171,8 @@ pub(crate) mod _thread { impl Constructor for Lock { type Args = FuncArgs; - fn py_new(_cls: PyTypeRef, _args: Self::Args, vm: &VirtualMachine) -> PyResult { + + fn py_new(_cls: &Py, _args: Self::Args, vm: &VirtualMachine) -> PyResult { Err(vm.new_type_error("cannot create '_thread.lock' instances")) } } diff --git a/crates/vm/src/stdlib/typevar.rs b/crates/vm/src/stdlib/typevar.rs index 4d56fb3ce3c..5509e547072 100644 --- a/crates/vm/src/stdlib/typevar.rs +++ b/crates/vm/src/stdlib/typevar.rs @@ -1,7 +1,7 @@ // spell-checker:ignore typevarobject funcobj use crate::{ - AsObject, Context, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, - builtins::{PyTupleRef, PyTypeRef, pystr::AsPyStr}, + AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, + builtins::{PyTupleRef, PyType, PyTypeRef, pystr::AsPyStr}, common::lock::PyMutex, function::{FuncArgs, IntoFuncArgs, PyComparisonValue}, protocol::PyNumberMethods, @@ -261,7 +261,15 @@ impl AsNumber for TypeVar { impl Constructor for TypeVar { type Args = FuncArgs; - fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { + fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { + let typevar = ::py_new(&cls, args, vm)?; + let obj = typevar.into_ref_with_type(vm, cls)?; + let obj_ref: PyObjectRef = obj.into(); + set_module_from_caller(&obj_ref, vm)?; + Ok(obj_ref) + } + + fn py_new(_cls: &Py, args: Self::Args, vm: &VirtualMachine) -> PyResult { let mut kwargs = args.kwargs; // Parse arguments manually let (name, constraints) = if args.args.is_empty() { @@ -353,7 +361,7 @@ impl Constructor for TypeVar { (vm.ctx.typing_no_default.clone().into(), vm.ctx.none()) }; - let typevar = Self { + Ok(Self { name, bound: parking_lot::Mutex::new(bound_obj), evaluate_bound, @@ -364,12 +372,7 @@ impl Constructor for TypeVar { covariant, contravariant, infer_variance, - }; - - let obj = typevar.into_ref_with_type(vm, cls)?; - let obj_ref: PyObjectRef = obj.into(); - set_module_from_caller(&obj_ref, vm)?; - Ok(obj_ref) + }) } } @@ -533,7 +536,7 @@ impl AsNumber for ParamSpec { impl Constructor for ParamSpec { type Args = FuncArgs; - fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { + fn slot_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { let mut kwargs = args.kwargs; // Parse arguments manually let name = if args.args.is_empty() { @@ -605,6 +608,10 @@ impl Constructor for ParamSpec { set_module_from_caller(&obj_ref, vm)?; Ok(obj_ref) } + + fn py_new(_cls: &Py, _args: Self::Args, _vm: &VirtualMachine) -> PyResult { + unreachable!("use slot_new") + } } impl Representable for ParamSpec { @@ -715,7 +722,7 @@ impl Iterable for TypeVarTuple { impl Constructor for TypeVarTuple { type Args = FuncArgs; - fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { + fn slot_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { let mut kwargs = args.kwargs; // Parse arguments manually let name = if args.args.is_empty() { @@ -763,6 +770,10 @@ impl Constructor for TypeVarTuple { set_module_from_caller(&obj_ref, vm)?; Ok(obj_ref) } + + fn py_new(_cls: &Py, _args: Self::Args, _vm: &VirtualMachine) -> PyResult { + unreachable!("use slot_new") + } } impl Representable for TypeVarTuple { @@ -805,10 +816,9 @@ impl ParamSpecArgs { impl Constructor for ParamSpecArgs { type Args = (PyObjectRef,); - fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { + fn py_new(_cls: &Py, args: Self::Args, _vm: &VirtualMachine) -> PyResult { let origin = args.0; - let psa = Self { __origin__: origin }; - psa.into_ref_with_type(vm, cls).map(Into::into) + Ok(Self { __origin__: origin }) } } @@ -884,10 +894,9 @@ impl ParamSpecKwargs { impl Constructor for ParamSpecKwargs { type Args = (PyObjectRef,); - fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { + fn py_new(_cls: &Py, args: Self::Args, _vm: &VirtualMachine) -> PyResult { let origin = args.0; - let psa = Self { __origin__: origin }; - psa.into_ref_with_type(vm, cls).map(Into::into) + Ok(Self { __origin__: origin }) } } diff --git a/crates/vm/src/stdlib/typing.rs b/crates/vm/src/stdlib/typing.rs index c014266935c..afa8bd6eb90 100644 --- a/crates/vm/src/stdlib/typing.rs +++ b/crates/vm/src/stdlib/typing.rs @@ -31,7 +31,7 @@ pub(crate) fn make_module(vm: &VirtualMachine) -> PyRef { pub(crate) mod decl { use crate::{ Py, PyObjectRef, PyPayload, PyResult, VirtualMachine, - builtins::{PyStrRef, PyTupleRef, PyTypeRef, pystr::AsPyStr}, + builtins::{PyStrRef, PyTupleRef, PyType, PyTypeRef, pystr::AsPyStr}, function::{FuncArgs, IntoFuncArgs}, types::{Constructor, Representable}, }; @@ -74,16 +74,16 @@ pub(crate) mod decl { } impl Constructor for NoDefault { - type Args = FuncArgs; - - fn py_new(_cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { - if !args.args.is_empty() || !args.kwargs.is_empty() { - return Err(vm.new_type_error("NoDefaultType takes no arguments")); - } + type Args = (); - // Return singleton instance from context + fn slot_new(_cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { + let _: () = args.bind(vm)?; Ok(vm.ctx.typing_no_default.clone().into()) } + + fn py_new(_cls: &Py, _args: Self::Args, _vm: &VirtualMachine) -> PyResult { + unreachable!("NoDefault is a singleton, use slot_new") + } } impl Representable for NoDefault { @@ -133,7 +133,7 @@ pub(crate) mod decl { impl Constructor for TypeAliasType { type Args = FuncArgs; - fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { + fn py_new(_cls: &Py, args: Self::Args, vm: &VirtualMachine) -> PyResult { // TypeAliasType(name, value, *, type_params=None) if args.args.len() < 2 { return Err(vm.new_type_error(format!( @@ -168,8 +168,7 @@ pub(crate) mod decl { vm.ctx.empty_tuple.clone() }; - let ta = Self::new(name, type_params, value); - ta.into_ref_with_type(vm, cls).map(Into::into) + Ok(Self::new(name, type_params, value)) } } diff --git a/crates/vm/src/types/slot.rs b/crates/vm/src/types/slot.rs index 834b3b5cb45..e3775058d44 100644 --- a/crates/vm/src/types/slot.rs +++ b/crates/vm/src/types/slot.rs @@ -779,18 +779,45 @@ impl PyType { } } +/// Trait for types that can be constructed via Python's `__new__` method. +/// +/// `slot_new` corresponds to the `__new__` type slot. +/// +/// In most cases, `__new__` simply initializes the payload and assigns a type, +/// so you only need to override `py_new`. The default `slot_new` implementation +/// will call `py_new` and then wrap the result with `into_ref_with_type`. +/// +/// However, if a subtype requires more than just payload initialization +/// (e.g., returning an existing object for optimization, setting attributes +/// after creation, or special handling of the class type), you should override +/// `slot_new` directly instead of `py_new`. +/// +/// # When to use `py_new` only (most common case): +/// - Simple payload initialization that just creates `Self` +/// - The type doesn't need special handling for subtypes +/// +/// # When to override `slot_new`: +/// - Returning existing objects (e.g., `PyInt`, `PyStr`, `PyBool` for optimization) +/// - Setting attributes or dict entries after object creation +/// - Special class type handling (e.g., `PyType` and its metaclasses) +/// - Post-creation mutations that require `PyRef` #[pyclass] -pub trait Constructor: PyPayload { +pub trait Constructor: PyPayload + std::fmt::Debug { type Args: FromArgs; + /// The type slot for `__new__`. Override this only when you need special + /// behavior beyond simple payload creation. #[inline] #[pyslot] fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { let args: Self::Args = args.bind(vm)?; - Self::py_new(cls, args, vm) + let payload = Self::py_new(&cls, args, vm)?; + payload.into_ref_with_type(vm, cls).map(Into::into) } - fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult; + /// Creates the payload for this type. In most cases, just implement this method + /// and let the default `slot_new` handle wrapping with the correct type. + fn py_new(cls: &Py, args: Self::Args, vm: &VirtualMachine) -> PyResult; } pub trait DefaultConstructor: PyPayload + Default + std::fmt::Debug { @@ -823,7 +850,7 @@ where Self::default().into_ref_with_type(vm, cls).map(Into::into) } - fn py_new(cls: PyTypeRef, _args: Self::Args, vm: &VirtualMachine) -> PyResult { + fn py_new(cls: &Py, _args: Self::Args, vm: &VirtualMachine) -> PyResult { Err(vm.new_type_error(format!("cannot create {} instances", cls.slot_name()))) } }