diff --git a/Lib/test/_test_atexit.py b/Lib/test/_test_atexit.py index 23ddfbae9..55d280833 100644 --- a/Lib/test/_test_atexit.py +++ b/Lib/test/_test_atexit.py @@ -45,8 +45,6 @@ class GeneralTest(unittest.TestCase): ('func2', (), {}), ('func1', (1, 2), {})]) - # TODO: RUSTPYTHON, AttributeError: module 'sys' has no attribute 'unraisablehook' - @unittest.expectedFailure def test_badargs(self): def func(): pass @@ -54,16 +52,12 @@ class GeneralTest(unittest.TestCase): # func() has no parameter, but it's called with 2 parameters self.assert_raises_unraisable(TypeError, func, 1 ,2) - # TODO: RUSTPYTHON, AttributeError: module 'sys' has no attribute 'unraisablehook' - @unittest.expectedFailure def test_raise(self): def raise_type_error(): raise TypeError self.assert_raises_unraisable(TypeError, raise_type_error) - # TODO: RUSTPYTHON, AttributeError: module 'sys' has no attribute 'unraisablehook' - @unittest.expectedFailure def test_raise_unnormalized(self): # bpo-10756: Make sure that an unnormalized exception is handled # properly. @@ -72,8 +66,6 @@ class GeneralTest(unittest.TestCase): self.assert_raises_unraisable(ZeroDivisionError, div_zero) - # TODO: RUSTPYTHON, AttributeError: module 'sys' has no attribute 'unraisablehook' - @unittest.expectedFailure def test_exit(self): self.assert_raises_unraisable(SystemExit, sys.exit) @@ -124,8 +116,6 @@ class GeneralTest(unittest.TestCase): atexit._run_exitfuncs() self.assertEqual(l, [5]) - # TODO: RUSTPYTHON, AttributeError: module 'sys' has no attribute 'unraisablehook' - @unittest.expectedFailure def test_atexit_with_unregistered_function(self): # See bpo-46025 for more info def func(): diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index bbd14e3a0..7b89520f5 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -1114,8 +1114,6 @@ class CommonBufferedTests: # a ValueError. self.assertRaises(ValueError, _with) - # TODO: RUSTPYTHON, sys.unraisablehook - @unittest.expectedFailure def test_error_through_destructor(self): # Test that the exception state is not modified by a destructor, # even if close() fails. @@ -2121,8 +2119,6 @@ class BufferedRWPairTest(unittest.TestCase): # Silence destructor error reader.close = lambda: None - # TODO: RUSTPYTHON, sys.unraisablehook - @unittest.expectedFailure def test_writer_close_error_on_close(self): def writer_close(): writer_non_existing @@ -2952,8 +2948,6 @@ class TextIOWrapperTest(unittest.TestCase): support.gc_collect() self.assertEqual(record, [1, 2, 3]) - # TODO: RUSTPYTHON, sys.unraisablehook - @unittest.expectedFailure def test_error_through_destructor(self): # Test that the exception state is not modified by a destructor, # even if close() fails. diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py index 8d59a5153..b2fcb1bfb 100644 --- a/Lib/test/test_signal.py +++ b/Lib/test/test_signal.py @@ -1291,8 +1291,7 @@ class StressTest(unittest.TestCase): # Python handler self.assertEqual(len(sigs), N, "Some signals were lost") - # TODO: RUSTPYTHON - @unittest.expectedFailure + @unittest.skip("TODO: RUSTPYTHON; hang") @unittest.skipUnless(hasattr(signal, "SIGUSR1"), "test needs SIGUSR1") def test_stress_modifying_handlers(self): diff --git a/Lib/test/test_thread.py b/Lib/test/test_thread.py index 81625429b..a8a403ce4 100644 --- a/Lib/test/test_thread.py +++ b/Lib/test/test_thread.py @@ -135,8 +135,6 @@ class ThreadRunningTests(BasicThreadTest): time.sleep(POLL_SLEEP) self.assertEqual(thread._count(), orig) - # TODO: RUSTPYTHON, AttributeError: module 'sys' has no attribute 'unraisablehook' - @unittest.expectedFailure def test_unraisable_exception(self): def task(): started.release() diff --git a/derive/src/pyclass.rs b/derive/src/pyclass.rs index 269582728..aacd817a1 100644 --- a/derive/src/pyclass.rs +++ b/derive/src/pyclass.rs @@ -112,7 +112,7 @@ pub(crate) fn impl_pyimpl(attr: AttributeArgs, item: Item) -> Result &'static ::rustpython_vm::builtins::PyTypeRef { - use rustpython_vm::pyclass::StaticType; + use rustpython_vm::class::StaticType; #typ::static_type() } } @@ -247,21 +247,21 @@ fn generate_class_def( let typ = Ident::new(&typ, ident.span()); quote! { fn static_metaclass() -> &'static ::rustpython_vm::builtins::PyTypeRef { - use rustpython_vm::pyclass::StaticType; + use rustpython_vm::class::StaticType; #typ::static_type() } } }); let tokens = quote! { - impl ::rustpython_vm::pyclass::PyClassDef for #ident { + impl ::rustpython_vm::class::PyClassDef for #ident { const NAME: &'static str = #name; const MODULE_NAME: Option<&'static str> = #module_name; const TP_NAME: &'static str = #module_class_name; const DOC: Option<&'static str> = #doc; } - impl ::rustpython_vm::pyclass::StaticType for #ident { + impl ::rustpython_vm::class::StaticType for #ident { fn static_cell() -> &'static ::rustpython_vm::common::static_cell::StaticCell<::rustpython_vm::builtins::PyTypeRef> { ::rustpython_vm::common::static_cell! { static CELL: ::rustpython_vm::builtins::PyTypeRef; diff --git a/derive/src/pymodule.rs b/derive/src/pymodule.rs index cffc3aaaa..fee1c9c2a 100644 --- a/derive/src/pymodule.rs +++ b/derive/src/pymodule.rs @@ -432,7 +432,7 @@ impl ModuleItem for ClassItem { class_meta.class_name()? }; let class_new = quote_spanned!(ident.span() => - let new_class = <#ident as ::rustpython_vm::pyclass::PyClassImpl>::make_class(&vm.ctx); + let new_class = <#ident as ::rustpython_vm::class::PyClassImpl>::make_class(&vm.ctx); new_class.set_str_attr("__module__", vm.new_pyobj(#module_name)); ); (class_name, class_new) diff --git a/derive/src/pypayload.rs b/derive/src/pypayload.rs index e382204ff..fd8ea4df6 100644 --- a/derive/src/pypayload.rs +++ b/derive/src/pypayload.rs @@ -8,7 +8,7 @@ pub(crate) fn impl_pypayload(input: DeriveInput) -> Result { let ret = quote! { impl ::rustpython_vm::PyPayload for #ty { fn class(_vm: &::rustpython_vm::VirtualMachine) -> &rustpython_vm::builtins::PyTypeRef { - ::static_type() + ::static_type() } } }; diff --git a/stdlib/src/json.rs b/stdlib/src/json.rs index 8abfd3523..61e7d9c7d 100644 --- a/stdlib/src/json.rs +++ b/stdlib/src/json.rs @@ -60,7 +60,8 @@ mod _json { parse_constant, ctx, } - .into_pyresult_with_type(vm, cls) + .into_ref_with_type(vm, cls) + .map(Into::into) } } diff --git a/stdlib/src/pystruct.rs b/stdlib/src/pystruct.rs index e104615a2..56668db88 100644 --- a/stdlib/src/pystruct.rs +++ b/stdlib/src/pystruct.rs @@ -250,7 +250,9 @@ pub(crate) mod _struct { fn py_new(cls: PyTypeRef, fmt: Self::Args, vm: &VirtualMachine) -> PyResult { let spec = fmt.format_spec(vm)?; let format = fmt.0; - PyStruct { spec, format }.into_pyresult_with_type(vm, cls) + PyStruct { spec, format } + .into_ref_with_type(vm, cls) + .map(Into::into) } } diff --git a/stdlib/src/random.rs b/stdlib/src/random.rs index fbd972517..b644f7a7d 100644 --- a/stdlib/src/random.rs +++ b/stdlib/src/random.rs @@ -73,7 +73,8 @@ mod _random { PyRandom { rng: PyMutex::default(), } - .into_pyresult_with_type(vm, cls) + .into_ref_with_type(vm, cls) + .map(Into::into) } } diff --git a/stdlib/src/select.rs b/stdlib/src/select.rs index cb05c93f7..39bf075e7 100644 --- a/stdlib/src/select.rs +++ b/stdlib/src/select.rs @@ -9,7 +9,7 @@ pub(crate) fn make_module(vm: &VirtualMachine) -> PyObjectRef { #[cfg(unix)] { - use crate::vm::pyclass::PyClassImpl; + use crate::vm::class::PyClassImpl; decl::poll::PyPoll::make_class(&vm.ctx); } diff --git a/stdlib/src/socket.rs b/stdlib/src/socket.rs index b4c82481f..f77ae29cf 100644 --- a/stdlib/src/socket.rs +++ b/stdlib/src/socket.rs @@ -547,7 +547,7 @@ mod _socket { impl PySocket { #[pyslot] fn slot_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { - Self::default().into_pyresult_with_type(vm, cls) + Self::default().into_ref_with_type(vm, cls).map(Into::into) } #[pymethod(magic)] diff --git a/stdlib/src/ssl.rs b/stdlib/src/ssl.rs index e63548463..aa9ca79bd 100644 --- a/stdlib/src/ssl.rs +++ b/stdlib/src/ssl.rs @@ -489,7 +489,8 @@ mod _ssl { check_hostname: AtomicCell::new(check_hostname), protocol: proto, } - .into_pyresult_with_type(vm, cls) + .into_ref_with_type(vm, cls) + .map(Into::into) } } diff --git a/vm/src/builtins/asyncgenerator.rs b/vm/src/builtins/asyncgenerator.rs index 2649c6a16..1bede4e67 100644 --- a/vm/src/builtins/asyncgenerator.rs +++ b/vm/src/builtins/asyncgenerator.rs @@ -1,11 +1,11 @@ use super::{PyCode, PyGenericAlias, PyStrRef, PyTypeRef}; use crate::{ builtins::PyBaseExceptionRef, + class::PyClassImpl, coroutine::Coro, frame::FrameRef, function::OptionalArg, protocol::PyIterReturn, - pyclass::PyClassImpl, types::{Constructor, IterNext, IterNextIterable, Unconstructible}, AsObject, Context, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, }; diff --git a/vm/src/builtins/pybool.rs b/vm/src/builtins/bool.rs similarity index 98% rename from vm/src/builtins/pybool.rs rename to vm/src/builtins/bool.rs index 49f0edf0e..b51ceae6f 100644 --- a/vm/src/builtins/pybool.rs +++ b/vm/src/builtins/bool.rs @@ -1,6 +1,6 @@ use super::{PyInt, PyStrRef, PyTypeRef}; use crate::{ - convert::ToPyObject, function::OptionalArg, pyclass::PyClassImpl, types::Constructor, AsObject, + class::PyClassImpl, convert::ToPyObject, function::OptionalArg, types::Constructor, AsObject, Context, PyObject, PyObjectRef, PyPayload, PyResult, TryFromBorrowedObject, VirtualMachine, }; use num_bigint::Sign; diff --git a/vm/src/builtins/builtinfunc.rs b/vm/src/builtins/builtinfunc.rs index c2a35351c..b3c55ab15 100644 --- a/vm/src/builtins/builtinfunc.rs +++ b/vm/src/builtins/builtinfunc.rs @@ -1,8 +1,8 @@ -use super::{pytype, PyClassMethod, PyStaticMethod, PyStr, PyStrRef, PyTypeRef}; +use super::{type_, PyClassMethod, PyStaticMethod, PyStr, PyStrRef, PyTypeRef}; use crate::{ builtins::PyBoundMethod, + class::PyClassImpl, function::{FuncArgs, IntoPyNativeFunc, PyNativeFunc}, - pyclass::PyClassImpl, types::{Callable, Constructor, GetDescriptor, Unconstructible}, AsObject, Context, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, }; @@ -148,7 +148,7 @@ impl PyBuiltinFunction { #[pyproperty(magic)] fn text_signature(&self) -> Option { self.value.doc.as_ref().and_then(|doc| { - pytype::get_text_signature_from_internal_doc(self.value.name.as_str(), doc.as_str()) + type_::get_text_signature_from_internal_doc(self.value.name.as_str(), doc.as_str()) .map(|signature| signature.to_string()) }) } @@ -238,7 +238,7 @@ impl PyBuiltinMethod { #[pyproperty(magic)] fn text_signature(&self) -> Option { self.value.doc.as_ref().and_then(|doc| { - pytype::get_text_signature_from_internal_doc(self.value.name.as_str(), doc.as_str()) + type_::get_text_signature_from_internal_doc(self.value.name.as_str(), doc.as_str()) .map(|signature| signature.to_string()) }) } diff --git a/vm/src/builtins/bytearray.rs b/vm/src/builtins/bytearray.rs index 408cc6063..0a6269f8f 100644 --- a/vm/src/builtins/bytearray.rs +++ b/vm/src/builtins/bytearray.rs @@ -11,6 +11,7 @@ use crate::{ ByteInnerNewOptions, ByteInnerPaddingOptions, ByteInnerSplitOptions, ByteInnerTranslateOptions, DecodeArgs, PyBytesInner, }, + class::PyClassImpl, common::{ atomic::{AtomicUsize, Ordering}, lock::{ @@ -26,7 +27,6 @@ use crate::{ BufferDescriptor, BufferMethods, BufferResizeGuard, PyBuffer, PyIterReturn, PyMappingMethods, PySequenceMethods, }, - pyclass::PyClassImpl, sliceable::{SequenceIndex, SliceableSequenceMutOp, SliceableSequenceOp}, types::{ AsBuffer, AsMapping, AsSequence, Callable, Comparable, Constructor, Hashable, IterNext, @@ -100,7 +100,9 @@ pub(crate) fn init(context: &Context) { impl PyByteArray { #[pyslot] fn slot_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { - PyByteArray::default().into_pyresult_with_type(vm, cls) + PyByteArray::default() + .into_ref_with_type(vm, cls) + .map(Into::into) } #[pymethod(magic)] diff --git a/vm/src/builtins/bytes.rs b/vm/src/builtins/bytes.rs index 99e404ca6..910314bec 100644 --- a/vm/src/builtins/bytes.rs +++ b/vm/src/builtins/bytes.rs @@ -6,6 +6,7 @@ use crate::{ bytes_decode, ByteInnerFindOptions, ByteInnerNewOptions, ByteInnerPaddingOptions, ByteInnerSplitOptions, ByteInnerTranslateOptions, DecodeArgs, PyBytesInner, }, + class::PyClassImpl, common::{hash::PyHash, lock::PyMutex}, convert::{ToPyObject, ToPyResult}, function::{ArgBytesLike, ArgIterable, OptionalArg, OptionalOption, PyComparisonValue}, @@ -13,7 +14,6 @@ use crate::{ BufferDescriptor, BufferMethods, PyBuffer, PyIterReturn, PyMappingMethods, PySequenceMethods, }, - pyclass::PyClassImpl, sliceable::{SequenceIndex, SliceableSequenceOp}, types::{ AsBuffer, AsMapping, AsSequence, Callable, Comparable, Constructor, Hashable, IterNext, diff --git a/vm/src/builtins/classmethod.rs b/vm/src/builtins/classmethod.rs index d27a0279a..a01dc4569 100644 --- a/vm/src/builtins/classmethod.rs +++ b/vm/src/builtins/classmethod.rs @@ -1,7 +1,7 @@ use super::PyTypeRef; use crate::{ builtins::PyBoundMethod, - pyclass::PyClassImpl, + class::PyClassImpl, types::{Constructor, GetDescriptor}, AsObject, Context, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, }; @@ -61,7 +61,9 @@ impl Constructor for PyClassMethod { type Args = PyObjectRef; fn py_new(cls: PyTypeRef, callable: Self::Args, vm: &VirtualMachine) -> PyResult { - PyClassMethod { callable }.into_pyresult_with_type(vm, cls) + PyClassMethod { callable } + .into_ref_with_type(vm, cls) + .map(Into::into) } } diff --git a/vm/src/builtins/code.rs b/vm/src/builtins/code.rs index 91de46cfc..86dcc3603 100644 --- a/vm/src/builtins/code.rs +++ b/vm/src/builtins/code.rs @@ -5,8 +5,8 @@ use super::{PyStrRef, PyTupleRef, PyTypeRef}; use crate::{ bytecode::{self, BorrowedConstant, Constant, ConstantBag}, + class::{PyClassImpl, StaticType}, function::FuncArgs, - pyclass::{PyClassImpl, StaticType}, AsObject, Context, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, }; use num_traits::Zero; @@ -31,7 +31,7 @@ fn borrow_obj_constant(obj: &PyObject) -> BorrowedConstant { match_class!(match obj { ref i @ super::int::PyInt => { let value = i.as_bigint(); - if obj.class().is(super::pybool::PyBool::static_type()) { + if obj.class().is(super::bool_::PyBool::static_type()) { BorrowedConstant::Boolean { value: !value.is_zero(), } diff --git a/vm/src/builtins/complex.rs b/vm/src/builtins/complex.rs index efee5aeea..f33d4856f 100644 --- a/vm/src/builtins/complex.rs +++ b/vm/src/builtins/complex.rs @@ -1,12 +1,12 @@ use super::{float, PyStr, PyTypeRef}; use crate::{ + class::PyClassImpl, convert::ToPyObject, function::{ OptionalArg, OptionalOption, PyArithmeticValue::{self, *}, PyComparisonValue, }, - pyclass::PyClassImpl, types::{Comparable, Constructor, Hashable, PyComparisonOp}, AsObject, Context, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, }; @@ -142,7 +142,9 @@ impl Constructor for PyComplex { let value = parse_str(s.as_str().trim()).ok_or_else(|| { vm.new_value_error("complex() arg is a malformed string".to_owned()) })?; - return Self::from(value).into_pyresult_with_type(vm, cls); + return Self::from(value) + .into_ref_with_type(vm, cls) + .map(Into::into); } else { return Err(vm.new_type_error(format!( "complex() first argument must be a string or a number, not '{}'", @@ -184,7 +186,9 @@ impl Constructor for PyComplex { imag.re }; let value = Complex64::new(final_real, final_imag); - Self::from(value).into_pyresult_with_type(vm, cls) + Self::from(value) + .into_ref_with_type(vm, cls) + .map(Into::into) } } diff --git a/vm/src/builtins/coroutine.rs b/vm/src/builtins/coroutine.rs index 2460bd514..8a4de8cdd 100644 --- a/vm/src/builtins/coroutine.rs +++ b/vm/src/builtins/coroutine.rs @@ -1,10 +1,10 @@ use super::{PyCode, PyStrRef, PyTypeRef}; use crate::{ + class::PyClassImpl, coroutine::Coro, frame::FrameRef, function::OptionalArg, protocol::PyIterReturn, - pyclass::PyClassImpl, types::{Constructor, IterNext, IterNextIterable, Unconstructible}, AsObject, Context, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, }; diff --git a/vm/src/builtins/dict.rs b/vm/src/builtins/dict.rs index 3477062c5..36daa5c6c 100644 --- a/vm/src/builtins/dict.rs +++ b/vm/src/builtins/dict.rs @@ -5,9 +5,10 @@ use super::{ use crate::{ builtins::{ iter::{builtins_iter, builtins_reversed}, - pytype::PyAttributes, + type_::PyAttributes, PyTuple, }, + class::{PyClassDef, PyClassImpl}, common::ascii, convert::ToPyObject, dictdatatype::{self, DictKey}, @@ -15,7 +16,6 @@ use crate::{ ArgIterable, FuncArgs, KwArgs, OptionalArg, PyArithmeticValue::*, PyComparisonValue, }, protocol::{PyIterIter, PyIterReturn, PyMappingMethods, PySequenceMethods}, - pyclass::{PyClassDef, PyClassImpl}, recursion::ReprGuard, types::{ AsMapping, AsSequence, Callable, Comparable, Constructor, Hashable, IterNext, @@ -83,7 +83,9 @@ impl PyDict { #[pyslot] fn slot_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { - PyDict::default().into_pyresult_with_type(vm, cls) + PyDict::default() + .into_ref_with_type(vm, cls) + .map(Into::into) } #[pymethod(magic)] diff --git a/vm/src/builtins/enumerate.rs b/vm/src/builtins/enumerate.rs index c604956cf..c07b32a79 100644 --- a/vm/src/builtins/enumerate.rs +++ b/vm/src/builtins/enumerate.rs @@ -1,10 +1,10 @@ use super::{IterStatus, PositionIterInternal, PyGenericAlias, PyIntRef, PyTupleRef, PyTypeRef}; use crate::common::lock::{PyMutex, PyRwLock}; use crate::{ + class::PyClassImpl, convert::ToPyObject, function::OptionalArg, protocol::{PyIter, PyIterReturn}, - pyclass::PyClassImpl, types::{Constructor, IterNext, IterNextIterable}, AsObject, Context, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, }; @@ -44,7 +44,8 @@ impl Constructor for PyEnumerate { counter: PyRwLock::new(counter), iterator, } - .into_pyresult_with_type(vm, cls) + .into_ref_with_type(vm, cls) + .map(Into::into) } } diff --git a/vm/src/builtins/filter.rs b/vm/src/builtins/filter.rs index 7a76e415d..1455aec8c 100644 --- a/vm/src/builtins/filter.rs +++ b/vm/src/builtins/filter.rs @@ -1,7 +1,7 @@ use super::PyTypeRef; use crate::{ + class::PyClassImpl, protocol::{PyIter, PyIterReturn}, - pyclass::PyClassImpl, types::{Constructor, IterNext, IterNextIterable}, Context, PyObjectRef, PyPayload, PyResult, VirtualMachine, }; @@ -31,7 +31,8 @@ impl Constructor for PyFilter { predicate: function, iterator, } - .into_pyresult_with_type(vm, cls) + .into_ref_with_type(vm, cls) + .map(Into::into) } } diff --git a/vm/src/builtins/float.rs b/vm/src/builtins/float.rs index 46c59430c..5040ab358 100644 --- a/vm/src/builtins/float.rs +++ b/vm/src/builtins/float.rs @@ -1,6 +1,7 @@ use super::{try_bigint_to_f64, PyByteArray, PyBytes, PyInt, PyIntRef, PyStr, PyStrRef, PyTypeRef}; use crate::common::{float_ops, hash}; use crate::{ + class::PyClassImpl, convert::ToPyObject, format::FormatSpec, function::{ @@ -8,7 +9,6 @@ use crate::{ PyArithmeticValue::{self, *}, PyComparisonValue, }, - pyclass::PyClassImpl, types::{Comparable, Constructor, Hashable, PyComparisonOp}, AsObject, Context, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromBorrowedObject, TryFromObject, VirtualMachine, @@ -183,7 +183,9 @@ impl Constructor for PyFloat { } } }; - PyFloat::from(float_val).into_pyresult_with_type(vm, cls) + PyFloat::from(float_val) + .into_ref_with_type(vm, cls) + .map(Into::into) } } diff --git a/vm/src/builtins/frame.rs b/vm/src/builtins/frame.rs index b90b76949..e0b119cef 100644 --- a/vm/src/builtins/frame.rs +++ b/vm/src/builtins/frame.rs @@ -4,8 +4,8 @@ use super::{PyCode, PyDictRef, PyStrRef}; use crate::{ + class::PyClassImpl, frame::{Frame, FrameRef}, - pyclass::PyClassImpl, types::{Constructor, Unconstructible}, AsObject, Context, PyObjectRef, PyRef, PyResult, VirtualMachine, }; diff --git a/vm/src/builtins/function.rs b/vm/src/builtins/function.rs index 0eb1261fb..8b2ebdfed 100644 --- a/vm/src/builtins/function.rs +++ b/vm/src/builtins/function.rs @@ -9,9 +9,9 @@ use crate::common::lock::PyMutex; use crate::function::ArgMapping; use crate::{ bytecode, + class::PyClassImpl, frame::Frame, function::{FuncArgs, OptionalArg, PyComparisonValue}, - pyclass::PyClassImpl, scope::Scope, types::{Callable, Comparable, Constructor, GetAttr, GetDescriptor, PyComparisonOp}, AsObject, Context, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, @@ -485,7 +485,9 @@ impl Constructor for PyBoundMethod { Self::Args { function, object }: Self::Args, vm: &VirtualMachine, ) -> PyResult { - PyBoundMethod::new(object, function).into_pyresult_with_type(vm, cls) + PyBoundMethod::new(object, function) + .into_ref_with_type(vm, cls) + .map(Into::into) } } @@ -588,7 +590,9 @@ impl Constructor for PyCell { type Args = OptionalArg; fn py_new(cls: PyTypeRef, value: Self::Args, vm: &VirtualMachine) -> PyResult { - Self::new(value.into_option()).into_pyresult_with_type(vm, cls) + Self::new(value.into_option()) + .into_ref_with_type(vm, cls) + .map(Into::into) } } diff --git a/vm/src/builtins/function/jitfunc.rs b/vm/src/builtins/function/jitfunc.rs index 3163c280f..eae093641 100644 --- a/vm/src/builtins/function/jitfunc.rs +++ b/vm/src/builtins/function/jitfunc.rs @@ -1,5 +1,5 @@ use crate::{ - builtins::{float, int, pybool, PyBaseExceptionRef, PyDictRef, PyFunction, PyStrRef}, + builtins::{bool_, float, int, PyBaseExceptionRef, PyDictRef, PyFunction, PyStrRef}, bytecode::CodeFlags, convert::ToPyObject, function::FuncArgs, @@ -120,7 +120,7 @@ fn get_jit_value(vm: &VirtualMachine, obj: &PyObject) -> Result PyResult { - PyList::default().into_pyresult_with_type(vm, cls) + PyList::default() + .into_ref_with_type(vm, cls) + .map(Into::into) } #[pymethod(magic)] diff --git a/vm/src/builtins/map.rs b/vm/src/builtins/map.rs index 71a0b95d1..f245ee87f 100644 --- a/vm/src/builtins/map.rs +++ b/vm/src/builtins/map.rs @@ -1,8 +1,8 @@ use super::PyTypeRef; use crate::{ + class::PyClassImpl, function::PosArgs, protocol::{PyIter, PyIterReturn}, - pyclass::PyClassImpl, types::{Constructor, IterNext, IterNextIterable}, Context, PyObjectRef, PyPayload, PyResult, VirtualMachine, }; @@ -29,7 +29,9 @@ impl Constructor for PyMap { fn py_new(cls: PyTypeRef, (mapper, iterators): Self::Args, vm: &VirtualMachine) -> PyResult { let iterators = iterators.into_vec(); - PyMap { mapper, iterators }.into_pyresult_with_type(vm, cls) + PyMap { mapper, iterators } + .into_ref_with_type(vm, cls) + .map(Into::into) } } diff --git a/vm/src/builtins/mappingproxy.rs b/vm/src/builtins/mappingproxy.rs index b37f3ef4b..d886559af 100644 --- a/vm/src/builtins/mappingproxy.rs +++ b/vm/src/builtins/mappingproxy.rs @@ -2,10 +2,10 @@ use std::borrow::Cow; use super::{PyDict, PyGenericAlias, PyList, PyStr, PyStrRef, PyTuple, PyTypeRef}; use crate::{ + class::PyClassImpl, convert::ToPyObject, function::OptionalArg, protocol::{PyMapping, PyMappingMethods, PySequence, PySequenceMethods}, - pyclass::PyClassImpl, types::{AsMapping, AsSequence, Constructor, Iterable}, AsObject, Context, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject, VirtualMachine, @@ -53,7 +53,8 @@ impl Constructor for PyMappingProxy { Self { mapping: MappingProxyInner::Dict(mapping), } - .into_pyresult_with_type(vm, cls) + .into_ref_with_type(vm, cls) + .map(Into::into) } } } diff --git a/vm/src/builtins/memory.rs b/vm/src/builtins/memory.rs index 007a68b68..80986dd3c 100644 --- a/vm/src/builtins/memory.rs +++ b/vm/src/builtins/memory.rs @@ -4,6 +4,7 @@ use super::{ use crate::{ buffer::FormatSpec, bytesinner::bytes_to_hex, + class::PyClassImpl, common::{ borrow::{BorrowedValue, BorrowedValueMut}, hash::PyHash, @@ -14,7 +15,6 @@ use crate::{ protocol::{ BufferDescriptor, BufferMethods, PyBuffer, PyMappingMethods, PySequenceMethods, VecBuffer, }, - pyclass::PyClassImpl, sequence::SequenceOp, sliceable::wrap_index, types::{AsBuffer, AsMapping, AsSequence, Comparable, Constructor, Hashable, PyComparisonOp}, @@ -57,7 +57,7 @@ impl Constructor for PyMemoryView { fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult { let zelf = Self::from_object(&args.object, vm)?; - zelf.into_pyresult_with_type(vm, cls) + zelf.into_ref_with_type(vm, cls).map(Into::into) } } diff --git a/vm/src/builtins/mod.rs b/vm/src/builtins/mod.rs index 2abbd0833..b3fd1a317 100644 --- a/vm/src/builtins/mod.rs +++ b/vm/src/builtins/mod.rs @@ -54,14 +54,18 @@ pub(crate) mod object; pub use object::PyBaseObject; pub(crate) mod property; pub use property::PyProperty; -pub(crate) mod pybool; -pub use pybool::PyBool; +#[path = "bool.rs"] +pub(crate) mod bool_; +pub use bool_::PyBool; +#[path = "str.rs"] pub(crate) mod pystr; pub use pystr::{PyStr, PyStrRef}; -pub(crate) mod pysuper; -pub use pysuper::PySuper; -pub(crate) mod pytype; -pub use pytype::{PyType, PyTypeRef}; +#[path = "super.rs"] +pub(crate) mod super_; +pub use super_::PySuper; +#[path = "type.rs"] +pub(crate) mod type_; +pub use type_::{PyType, PyTypeRef}; pub(crate) mod range; pub use range::PyRange; pub(crate) mod set; @@ -82,8 +86,9 @@ pub(crate) mod weakref; pub use weakref::PyWeak; pub(crate) mod zip; pub use zip::PyZip; -pub(crate) mod pyunion; -pub use pyunion::PyUnion; +#[path = "union.rs"] +pub(crate) mod union_; +pub use union_::PyUnion; pub use float::try_to_bigint as try_f64_to_bigint; pub use int::try_to_float as try_bigint_to_f64; diff --git a/vm/src/builtins/module.rs b/vm/src/builtins/module.rs index 52e7c06ca..85d5dd092 100644 --- a/vm/src/builtins/module.rs +++ b/vm/src/builtins/module.rs @@ -1,8 +1,8 @@ use super::pystr::IntoPyStrRef; use super::{PyDictRef, PyStr, PyStrRef, PyTypeRef}; use crate::{ - convert::ToPyObject, function::FuncArgs, pyclass::PyClassImpl, types::GetAttr, AsObject, - Context, Py, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, + class::PyClassImpl, convert::ToPyObject, function::FuncArgs, types::GetAttr, AsObject, Context, + Py, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, }; #[pyclass(module = false, name = "module")] @@ -35,7 +35,7 @@ impl PyModule { #[pyslot] fn slot_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { - PyModule {}.into_pyresult_with_type(vm, cls) + PyModule {}.into_ref_with_type(vm, cls).map(Into::into) } #[pymethod(magic)] diff --git a/vm/src/builtins/namespace.rs b/vm/src/builtins/namespace.rs index 93541a3fd..c73a56cd3 100644 --- a/vm/src/builtins/namespace.rs +++ b/vm/src/builtins/namespace.rs @@ -1,8 +1,8 @@ use super::PyTypeRef; use crate::{ builtins::PyDict, + class::PyClassImpl, function::{FuncArgs, PyComparisonValue}, - pyclass::PyClassImpl, recursion::ReprGuard, types::{Comparable, Constructor, PyComparisonOp}, AsObject, Context, PyObject, PyPayload, PyRef, PyResult, VirtualMachine, @@ -25,7 +25,7 @@ impl Constructor for PyNamespace { type Args = FuncArgs; fn py_new(cls: PyTypeRef, _args: Self::Args, vm: &VirtualMachine) -> PyResult { - PyNamespace {}.into_pyresult_with_type(vm, cls) + PyNamespace {}.into_ref_with_type(vm, cls).map(Into::into) } } diff --git a/vm/src/builtins/object.rs b/vm/src/builtins/object.rs index 562bc520a..adfe67f09 100644 --- a/vm/src/builtins/object.rs +++ b/vm/src/builtins/object.rs @@ -1,8 +1,8 @@ use super::{PyDict, PyDictRef, PyList, PyStr, PyStrRef, PyType, PyTypeRef}; use crate::common::hash::PyHash; use crate::{ + class::PyClassImpl, function::{FuncArgs, PyArithmeticValue, PyComparisonValue}, - pyclass::PyClassImpl, types::PyComparisonOp, utils::Either, AsObject, Context, PyObject, PyObjectRef, PyPayload, PyResult, VirtualMachine, diff --git a/vm/src/builtins/property.rs b/vm/src/builtins/property.rs index c284a336e..63bb8a615 100644 --- a/vm/src/builtins/property.rs +++ b/vm/src/builtins/property.rs @@ -4,7 +4,7 @@ use super::PyTypeRef; use crate::common::lock::PyRwLock; use crate::{ - function::FuncArgs, pyclass::PyClassImpl, types::GetDescriptor, AsObject, Context, PyObjectRef, + class::PyClassImpl, function::FuncArgs, types::GetDescriptor, AsObject, Context, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject, VirtualMachine, }; @@ -95,7 +95,8 @@ impl PyProperty { deleter: PyRwLock::new(None), doc: PyRwLock::new(None), } - .into_pyresult_with_type(vm, cls) + .into_ref_with_type(vm, cls) + .map(Into::into) } #[pymethod(magic)] diff --git a/vm/src/builtins/range.rs b/vm/src/builtins/range.rs index 7ab3557ef..fb34d59d2 100644 --- a/vm/src/builtins/range.rs +++ b/vm/src/builtins/range.rs @@ -2,9 +2,9 @@ use super::{PyInt, PyIntRef, PySlice, PyTupleRef, PyTypeRef}; use crate::common::hash::PyHash; use crate::{ builtins::builtins_iter, + class::PyClassImpl, function::{FuncArgs, OptionalArg, PyComparisonValue}, protocol::{PyIterReturn, PyMappingMethods, PySequenceMethods}, - pyclass::PyClassImpl, types::{ AsMapping, AsSequence, Comparable, Constructor, Hashable, IterNext, IterNextIterable, Iterable, PyComparisonOp, Unconstructible, diff --git a/vm/src/builtins/set.rs b/vm/src/builtins/set.rs index 30d020b07..cca10eaf0 100644 --- a/vm/src/builtins/set.rs +++ b/vm/src/builtins/set.rs @@ -7,10 +7,10 @@ use super::{ }; use crate::common::{ascii, hash::PyHash, lock::PyMutex, rc::PyRc}; use crate::{ + class::PyClassImpl, dictdatatype::{self, DictSize}, function::{ArgIterable, FuncArgs, OptionalArg, PosArgs, PyArithmeticValue, PyComparisonValue}, protocol::{PyIterReturn, PySequenceMethods}, - pyclass::PyClassImpl, recursion::ReprGuard, types::{ AsSequence, Comparable, Constructor, Hashable, IterNext, IterNextIterable, Iterable, @@ -398,7 +398,7 @@ impl PySet { impl PySet { #[pyslot] fn slot_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { - PySet::default().into_pyresult_with_type(vm, cls) + PySet::default().into_ref_with_type(vm, cls).map(Into::into) } #[pymethod(magic)] @@ -725,7 +725,8 @@ impl Constructor for PyFrozenSet { if elements.is_empty() && cls.is(&vm.ctx.types.frozenset_type) { Ok(vm.ctx.empty_frozenset.clone().into()) } else { - Self::from_iter(vm, elements).and_then(|o| o.into_pyresult_with_type(vm, cls)) + Self::from_iter(vm, elements) + .and_then(|o| o.into_ref_with_type(vm, cls).map(Into::into)) } } } diff --git a/vm/src/builtins/singletons.rs b/vm/src/builtins/singletons.rs index 4790a4cf7..bc5718fbc 100644 --- a/vm/src/builtins/singletons.rs +++ b/vm/src/builtins/singletons.rs @@ -1,6 +1,6 @@ use super::PyTypeRef; use crate::{ - convert::ToPyObject, pyclass::PyClassImpl, types::Constructor, AsObject, Context, PyObjectRef, + class::PyClassImpl, convert::ToPyObject, types::Constructor, AsObject, Context, PyObjectRef, PyPayload, PyResult, VirtualMachine, }; diff --git a/vm/src/builtins/slice.rs b/vm/src/builtins/slice.rs index e06e4c60e..1b5d2849a 100644 --- a/vm/src/builtins/slice.rs +++ b/vm/src/builtins/slice.rs @@ -1,9 +1,9 @@ // sliceobject.{h,c} in CPython use super::{PyInt, PyIntRef, PyTupleRef, PyTypeRef}; use crate::{ + class::PyClassImpl, convert::ToPyObject, function::{FuncArgs, OptionalArg, PyComparisonValue}, - pyclass::PyClassImpl, types::{Comparable, Constructor, Hashable, PyComparisonOp, Unhashable}, AsObject, Context, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, }; @@ -101,7 +101,7 @@ impl PySlice { } } }; - slice.into_pyresult_with_type(vm, cls) + slice.into_ref_with_type(vm, cls).map(Into::into) } pub(crate) fn inner_indices( diff --git a/vm/src/builtins/staticmethod.rs b/vm/src/builtins/staticmethod.rs index 477bcc53d..39cf8f362 100644 --- a/vm/src/builtins/staticmethod.rs +++ b/vm/src/builtins/staticmethod.rs @@ -1,8 +1,8 @@ use super::{PyStr, PyTypeRef}; use crate::{ builtins::builtinfunc::PyBuiltinMethod, + class::PyClassImpl, function::{FuncArgs, IntoPyNativeFunc}, - pyclass::PyClassImpl, types::{Callable, Constructor, GetDescriptor}, Context, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, }; @@ -41,7 +41,9 @@ impl Constructor for PyStaticMethod { type Args = PyObjectRef; fn py_new(cls: PyTypeRef, callable: Self::Args, vm: &VirtualMachine) -> PyResult { - PyStaticMethod { callable }.into_pyresult_with_type(vm, cls) + PyStaticMethod { callable } + .into_ref_with_type(vm, cls) + .map(Into::into) } } diff --git a/vm/src/builtins/pystr.rs b/vm/src/builtins/str.rs similarity index 99% rename from vm/src/builtins/pystr.rs rename to vm/src/builtins/str.rs index 03cf3b61f..3eac4ea26 100644 --- a/vm/src/builtins/pystr.rs +++ b/vm/src/builtins/str.rs @@ -5,11 +5,11 @@ use super::{ }; use crate::{ anystr::{self, adjust_indices, AnyStr, AnyStrContainer, AnyStrWrapper}, + class::PyClassImpl, convert::{ToPyException, ToPyObject}, format::{FormatSpec, FormatString, FromTemplate}, function::{ArgIterable, FuncArgs, OptionalArg, OptionalOption, PyComparisonValue}, protocol::{PyIterReturn, PyMappingMethods, PySequenceMethods}, - pyclass::PyClassImpl, sequence::SequenceOp, sliceable::{SequenceIndex, SliceableSequenceOp}, types::{ @@ -320,7 +320,9 @@ impl Constructor for PyStr { if string.class().is(&cls) { Ok(string.into()) } else { - PyStr::from(string.as_str()).into_pyresult_with_type(vm, cls) + PyStr::from(string.as_str()) + .into_ref_with_type(vm, cls) + .map(Into::into) } } } diff --git a/vm/src/builtins/pysuper.rs b/vm/src/builtins/super.rs similarity index 98% rename from vm/src/builtins/pysuper.rs rename to vm/src/builtins/super.rs index 9d52dd5bb..ec94702c4 100644 --- a/vm/src/builtins/pysuper.rs +++ b/vm/src/builtins/super.rs @@ -5,8 +5,8 @@ See also [CPython source code.](https://github.com/python/cpython/blob/50b48572d use super::{PyStrRef, PyType, PyTypeRef}; use crate::{ + class::PyClassImpl, function::OptionalArg, - pyclass::PyClassImpl, types::{Constructor, GetAttr, GetDescriptor}, AsObject, Context, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, }; @@ -91,7 +91,9 @@ impl Constructor for PySuper { (typ, obj) }; - PySuper::new(typ, obj, vm)?.into_pyresult_with_type(vm, cls) + PySuper::new(typ, obj, vm)? + .into_ref_with_type(vm, cls) + .map(Into::into) } } diff --git a/vm/src/builtins/traceback.rs b/vm/src/builtins/traceback.rs index 924363554..ffd247a30 100644 --- a/vm/src/builtins/traceback.rs +++ b/vm/src/builtins/traceback.rs @@ -1,5 +1,5 @@ use super::PyTypeRef; -use crate::{frame::FrameRef, pyclass::PyClassImpl, Context, PyPayload, PyRef, VirtualMachine}; +use crate::{class::PyClassImpl, frame::FrameRef, Context, PyPayload, PyRef, VirtualMachine}; #[pyclass(module = false, name = "traceback")] #[derive(Debug)] diff --git a/vm/src/builtins/tuple.rs b/vm/src/builtins/tuple.rs index 18649735d..2c71de073 100644 --- a/vm/src/builtins/tuple.rs +++ b/vm/src/builtins/tuple.rs @@ -1,10 +1,10 @@ use super::{PositionIterInternal, PyGenericAlias, PyTypeRef}; use crate::common::{hash::PyHash, lock::PyMutex}; use crate::{ + class::PyClassImpl, convert::{ToPyObject, TransmuteFromObject, TryFromBorrowedObject}, function::{OptionalArg, PyArithmeticValue, PyComparisonValue}, protocol::{PyIterReturn, PyMappingMethods, PySequenceMethods}, - pyclass::PyClassImpl, recursion::ReprGuard, sequence::{ObjectSequenceOp, SequenceOp}, sliceable::{SequenceIndex, SliceableSequenceOp}, @@ -113,7 +113,8 @@ impl Constructor for PyTuple { Self { elements: elements.into_boxed_slice(), } - .into_pyresult_with_type(vm, cls) + .into_ref_with_type(vm, cls) + .map(Into::into) } } } diff --git a/vm/src/builtins/pytype.rs b/vm/src/builtins/type.rs similarity index 98% rename from vm/src/builtins/pytype.rs rename to vm/src/builtins/type.rs index 531e9254d..1527d1de7 100644 --- a/vm/src/builtins/pytype.rs +++ b/vm/src/builtins/type.rs @@ -1,6 +1,6 @@ use super::{ - mappingproxy::PyMappingProxy, object, pyunion, PyClassMethod, PyDictRef, PyList, - PyStaticMethod, PyStr, PyStrRef, PyTuple, PyTupleRef, PyWeak, + mappingproxy::PyMappingProxy, object, union_, PyClassMethod, PyDictRef, PyList, PyStaticMethod, + PyStr, PyStrRef, PyTuple, PyTupleRef, PyWeak, }; use crate::common::{ ascii, @@ -8,8 +8,8 @@ use crate::common::{ lock::{PyRwLock, PyRwLockReadGuard}, }; use crate::{ + class::{PyClassImpl, StaticType}, function::{FuncArgs, KwArgs, OptionalArg}, - pyclass::{PyClassImpl, StaticType}, types::{Callable, GetAttr, PyTypeFlags, PyTypeSlots, SetAttr}, AsObject, Context, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, }; @@ -402,12 +402,12 @@ impl PyType { #[pymethod(name = "__ror__")] #[pymethod(magic)] pub fn or(zelf: PyObjectRef, other: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef { - if !pyunion::is_unionable(zelf.clone(), vm) || !pyunion::is_unionable(other.clone(), vm) { + if !union_::is_unionable(zelf.clone(), vm) || !union_::is_unionable(other.clone(), vm) { return vm.ctx.not_implemented(); } let tuple = PyTuple::new_ref(vec![zelf, other], &vm.ctx); - pyunion::make_union(tuple, vm) + union_::make_union(tuple, vm) } #[pyslot] diff --git a/vm/src/builtins/pyunion.rs b/vm/src/builtins/union.rs similarity index 99% rename from vm/src/builtins/pyunion.rs rename to vm/src/builtins/union.rs index 510eaaf73..cddcc7ffb 100644 --- a/vm/src/builtins/pyunion.rs +++ b/vm/src/builtins/union.rs @@ -1,11 +1,11 @@ use super::genericalias; use crate::{ builtins::{PyFrozenSet, PyStr, PyStrRef, PyTuple, PyTupleRef, PyTypeRef}, + class::PyClassImpl, common::hash, convert::ToPyObject, function::PyComparisonValue, protocol::PyMappingMethods, - pyclass::PyClassImpl, types::{AsMapping, Comparable, GetAttr, Hashable, Iterable, PyComparisonOp}, AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject, VirtualMachine, diff --git a/vm/src/builtins/weakproxy.rs b/vm/src/builtins/weakproxy.rs index 2835ea5ec..7bb80bc45 100644 --- a/vm/src/builtins/weakproxy.rs +++ b/vm/src/builtins/weakproxy.rs @@ -1,7 +1,7 @@ use super::{PyStrRef, PyTypeRef, PyWeak}; use crate::{ + class::PyClassImpl, function::OptionalArg, - pyclass::PyClassImpl, types::{Constructor, SetAttr}, Context, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, }; @@ -48,7 +48,8 @@ impl Constructor for PyWeakProxy { PyWeakProxy { weak: referent.downgrade_with_typ(callback.into_option(), weak_cls.clone(), vm)?, } - .into_pyresult_with_type(vm, cls) + .into_ref_with_type(vm, cls) + .map(Into::into) } } diff --git a/vm/src/builtins/weakref.rs b/vm/src/builtins/weakref.rs index 4ff90c780..750025c3e 100644 --- a/vm/src/builtins/weakref.rs +++ b/vm/src/builtins/weakref.rs @@ -4,13 +4,13 @@ use crate::common::{ hash::{self, PyHash}, }; use crate::{ + class::PyClassImpl, function::OptionalArg, - pyclass::PyClassImpl, types::{Callable, Comparable, Constructor, Hashable, PyComparisonOp}, AsObject, Context, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, }; -pub use crate::pyobject::PyWeak; +pub use crate::object::PyWeak; #[derive(FromArgs)] pub struct WeakNewArgs { diff --git a/vm/src/builtins/zip.rs b/vm/src/builtins/zip.rs index 92db15e34..e7b666075 100644 --- a/vm/src/builtins/zip.rs +++ b/vm/src/builtins/zip.rs @@ -1,9 +1,9 @@ use super::PyTypeRef; use crate::{ builtins::PyTupleRef, + class::PyClassImpl, function::{ArgIntoBool, OptionalArg, PosArgs}, protocol::{PyIter, PyIterReturn}, - pyclass::PyClassImpl, types::{Constructor, IterNext, IterNextIterable}, AsObject, Context, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject, VirtualMachine, }; @@ -34,7 +34,9 @@ impl Constructor for PyZip { fn py_new(cls: PyTypeRef, (iterators, args): Self::Args, vm: &VirtualMachine) -> PyResult { let iterators = iterators.into_vec(); let strict = Radium::new(args.strict.unwrap_or(false)); - PyZip { iterators, strict }.into_pyresult_with_type(vm, cls) + PyZip { iterators, strict } + .into_ref_with_type(vm, cls) + .map(Into::into) } } diff --git a/vm/src/pyclass.rs b/vm/src/class.rs similarity index 98% rename from vm/src/pyclass.rs rename to vm/src/class.rs index f4634066d..a96e5108d 100644 --- a/vm/src/pyclass.rs +++ b/vm/src/class.rs @@ -2,7 +2,7 @@ use crate::{ builtins::{PyBaseObject, PyBoundMethod, PyType, PyTypeRef}, - pyobject::{PyObjectPayload, PyObjectRef, PyRef}, + object::{PyObjectPayload, PyObjectRef, PyRef}, types::{PyTypeFlags, PyTypeSlots}, vm::Context, }; diff --git a/vm/src/convert/transmute_from.rs b/vm/src/convert/transmute_from.rs index 1c112b61b..5931e106b 100644 --- a/vm/src/convert/transmute_from.rs +++ b/vm/src/convert/transmute_from.rs @@ -1,5 +1,5 @@ use crate::{ - pyobject::{AsObject, PyObject, PyPayload, PyRef, PyResult}, + object::{AsObject, PyObject, PyPayload, PyRef, PyResult}, vm::VirtualMachine, }; diff --git a/vm/src/convert/try_from.rs b/vm/src/convert/try_from.rs index 7489cb093..8a4158682 100644 --- a/vm/src/convert/try_from.rs +++ b/vm/src/convert/try_from.rs @@ -1,5 +1,5 @@ use crate::{ - pyobject::{AsObject, PyObject, PyObjectRef, PyPayload, PyRef, PyResult}, + object::{AsObject, PyObject, PyObjectRef, PyPayload, PyRef, PyResult}, vm::VirtualMachine, }; diff --git a/vm/src/exceptions.rs b/vm/src/exceptions.rs index 2fb79a972..30d42669c 100644 --- a/vm/src/exceptions.rs +++ b/vm/src/exceptions.rs @@ -4,10 +4,10 @@ use crate::{ builtins::{ traceback::PyTracebackRef, PyNone, PyStr, PyStrRef, PyTuple, PyTupleRef, PyType, PyTypeRef, }, + class::{PyClassImpl, StaticType}, convert::{ToPyException, ToPyObject}, function::{ArgIterable, FuncArgs}, py_io::{self, Write}, - pyclass::{PyClassImpl, StaticType}, stdlib::sys, suggestion::offer_suggestions, AsObject, Context, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject, VirtualMachine, @@ -427,7 +427,9 @@ impl PyBaseException { #[pyslot] pub(crate) fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { - PyBaseException::new(args.args, vm).into_pyresult_with_type(vm, cls) + PyBaseException::new(args.args, vm) + .into_ref_with_type(vm, cls) + .map(Into::into) } #[pymethod(magic)] diff --git a/vm/src/frame.rs b/vm/src/frame.rs index 16a6e2891..cc0535707 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -16,8 +16,8 @@ use crate::{ scope::Scope, stdlib::builtins, types::PyComparisonOp, - AsObject, PyMethod, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject, - VirtualMachine, + vm::PyMethod, + AsObject, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject, VirtualMachine, }; use indexmap::IndexMap; use itertools::Itertools; diff --git a/vm/src/function/arithmetic.rs b/vm/src/function/arithmetic.rs index 86dad0d29..b40e31e1b 100644 --- a/vm/src/function/arithmetic.rs +++ b/vm/src/function/arithmetic.rs @@ -1,6 +1,6 @@ use crate::{ convert::{ToPyObject, TryFromObject}, - pyobject::{AsObject, PyObjectRef, PyResult}, + object::{AsObject, PyObjectRef, PyResult}, VirtualMachine, }; diff --git a/vm/src/function/builtin.rs b/vm/src/function/builtin.rs index 761c6faa1..3c9a797a5 100644 --- a/vm/src/function/builtin.rs +++ b/vm/src/function/builtin.rs @@ -1,7 +1,6 @@ use super::{FromArgs, FuncArgs}; use crate::{ - convert::ToPyResult, pyobject::PyThreadingConstraint, PyPayload, PyRef, PyResult, - VirtualMachine, + convert::ToPyResult, object::PyThreadingConstraint, PyPayload, PyRef, PyResult, VirtualMachine, }; use std::marker::PhantomData; diff --git a/vm/src/intern.rs b/vm/src/intern.rs index f7dec3c9f..d43115d34 100644 --- a/vm/src/intern.rs +++ b/vm/src/intern.rs @@ -67,7 +67,7 @@ impl std::borrow::Borrow for CachedPyStrRef { } mod sealed { - use crate::{builtins::PyStr, pyobject::PyRefExact}; + use crate::{builtins::PyStr, object::PyRefExact}; pub trait SealedInternable {} diff --git a/vm/src/lib.rs b/vm/src/lib.rs index c4f2e9412..7f29a5b9e 100644 --- a/vm/src/lib.rs +++ b/vm/src/lib.rs @@ -38,15 +38,12 @@ pub use rustpython_derive::*; #[macro_use] pub(crate) mod macros; -#[path = "pyobject.rs"] -mod _pyobject; -#[path = "pyobjectrc.rs"] -mod _pyobjectrc; mod anystr; pub mod buffer; pub mod builtins; mod bytesinner; pub mod cformat; +pub mod class; mod codecs; pub mod convert; mod coroutine; @@ -62,10 +59,11 @@ mod frozen; pub mod function; pub mod import; mod intern; +pub mod object; +pub mod prelude; pub mod protocol; pub mod py_io; pub mod py_serde; -pub mod pyclass; pub mod readline; pub mod recursion; pub mod scope; @@ -77,18 +75,12 @@ pub mod suggestion; pub mod types; pub mod utils; pub mod version; -mod vm; - -mod pyobject { - pub use super::_pyobject::*; - pub use super::_pyobjectrc::*; -} +pub mod vm; pub use self::convert::{TryFromBorrowedObject, TryFromObject}; -// pyobject items -pub use self::pyobject::{AsObject, PyMethod, PyPayload, PyRefExact, PyResult}; -// pyobjectrc items -pub use self::pyobject::{Py, PyObject, PyObjectRef, PyRef, PyWeakRef}; +pub use self::object::{ + AsObject, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyRefExact, PyResult, PyWeakRef, +}; pub use self::types::PyStructSequence; pub use self::vm::{Context, InitParameter, Interpreter, Settings, VirtualMachine}; diff --git a/vm/src/macros.rs b/vm/src/macros.rs index 9f929d9ea..a12272c09 100644 --- a/vm/src/macros.rs +++ b/vm/src/macros.rs @@ -49,7 +49,7 @@ macro_rules! py_namespace { { let namespace = $crate::builtins::PyNamespace::new_ref(&$vm.ctx); $( - $vm.__module_set_attr($crate::pyobject::AsObject::as_object(&namespace), $name, $value).unwrap(); + $vm.__module_set_attr($crate::object::AsObject::as_object(&namespace), $name, $value).unwrap(); )* namespace } diff --git a/vm/src/pyobjectrc.rs b/vm/src/object/core.rs similarity index 96% rename from vm/src/pyobjectrc.rs rename to vm/src/object/core.rs index a1b17cefb..dda35f968 100644 --- a/vm/src/pyobjectrc.rs +++ b/vm/src/object/core.rs @@ -11,23 +11,30 @@ //! PyRef may looking like to be called as PyObjectWeak by the rule, //! but not to do to remember it is a PyRef object. -use crate::common::atomic::{OncePtr, PyAtomic, Radium}; -use crate::common::linked_list::{Link, LinkedList, Pointers}; -use crate::common::lock::{PyMutex, PyMutexGuard, PyRwLock}; -use crate::common::refcount::RefCount; +use super::{ + ext::{AsObject, PyResult}, + payload::PyObjectPayload, +}; +use crate::common::{ + atomic::{OncePtr, PyAtomic, Radium}, + linked_list::{Link, LinkedList, Pointers}, + lock::{PyMutex, PyMutexGuard, PyRwLock}, + refcount::RefCount, +}; use crate::{ - _pyobject::{AsObject, PyObjectPayload, PyResult}, - builtins::{PyBaseExceptionRef, PyDictRef, PyTypeRef}, + builtins::{PyDictRef, PyTypeRef}, vm::VirtualMachine, }; -use std::any::TypeId; -use std::borrow::Borrow; -use std::cell::UnsafeCell; -use std::fmt; -use std::marker::PhantomData; -use std::mem::ManuallyDrop; -use std::ops::Deref; -use std::ptr::{self, NonNull}; +use std::{ + any::TypeId, + borrow::Borrow, + cell::UnsafeCell, + fmt, + marker::PhantomData, + mem::ManuallyDrop, + ops::Deref, + ptr::{self, NonNull}, +}; // so, PyObjectRef is basically equivalent to `PyRc>`, except it's // only one pointer in width rather than 2. We do that by manually creating a vtable, and putting @@ -732,7 +739,8 @@ impl PyObject { let ret = crate::vm::thread::with_vm(self, |vm| { self.0.ref_count.inc(); if let Err(e) = slot_del(self, vm) { - print_del_error(e, self, vm); + let del_method = self.get_class_attr("__del__").unwrap(); + vm.run_unraisable(e, None, del_method); } self.0.ref_count.dec() }); @@ -804,26 +812,6 @@ impl Drop for PyObjectRef { } } -#[cold] -fn print_del_error(e: PyBaseExceptionRef, zelf: &PyObject, vm: &VirtualMachine) { - // exception in del will be ignored but printed - print!("Exception ignored in: ",); - let del_method = zelf.get_class_attr("__del__").unwrap(); - let repr = &del_method.repr(vm); - match repr { - Ok(v) => println!("{v}"), - Err(_) => println!("{}", del_method.class().name()), - } - let tb_module = vm.import("traceback", None, 0).unwrap(); - // TODO: set exc traceback - let print_stack = tb_module.get_attr("print_stack", vm).unwrap(); - vm.invoke(&print_stack, ()).unwrap(); - - if let Ok(repr) = e.as_object().repr(vm) { - println!("{}", repr.as_str()); - } -} - impl fmt::Debug for PyObjectRef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // SAFETY: the vtable contains functions that accept payload types that always match up @@ -1057,7 +1045,7 @@ macro_rules! partially_init { pub(crate) fn init_type_hierarchy() -> (PyTypeRef, PyTypeRef, PyTypeRef) { use crate::{ builtins::{object, PyType}, - pyclass::PyClassImpl, + class::PyClassImpl, }; use std::mem::MaybeUninit; diff --git a/vm/src/object/ext.rs b/vm/src/object/ext.rs new file mode 100644 index 000000000..762e72869 --- /dev/null +++ b/vm/src/object/ext.rs @@ -0,0 +1,276 @@ +use super::{ + core::{Py, PyObject, PyObjectRef, PyRef}, + payload::{PyObjectPayload, PyPayload}, +}; +use crate::common::lock::PyRwLockReadGuard; +use crate::{ + builtins::{PyBaseExceptionRef, PyType}, + convert::{ToPyObject, ToPyResult, TryFromObject}, + VirtualMachine, +}; +use std::{borrow::Borrow, fmt, ops::Deref}; + +/* Python objects and references. + +Okay, so each python object itself is an class itself (PyObject). Each +python object can have several references to it (PyObjectRef). These +references are Rc (reference counting) rust smart pointers. So when +all references are destroyed, the object itself also can be cleaned up. +Basically reference counting, but then done by rust. + +*/ + +/* + * Good reference: https://github.com/ProgVal/pythonvm-rust/blob/master/src/objects/mod.rs + */ + +/// Use this type for functions which return a python object or an exception. +/// Both the python object and the python exception are `PyObjectRef` types +/// since exceptions are also python objects. +pub type PyResult = Result; // A valid value, or an exception + +// TODO: remove these 2 impls +impl fmt::Display for PyObjectRef { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + (**self).fmt(f) + } +} +impl fmt::Display for PyObject { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "'{}' object", self.class().name()) + } +} + +impl fmt::Display for PyRef +where + T: PyObjectPayload + fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&**self, f) + } +} +impl fmt::Display for Py +where + T: PyObjectPayload + fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&**self, f) + } +} + +#[derive(Debug)] +pub struct PyRefExact { + inner: PyRef, +} + +impl PyRefExact { + /// # Safety + /// obj must have exact type for the payload + pub unsafe fn new_unchecked(obj: PyRef) -> Self { + Self { inner: obj } + } + + pub fn into_pyref(self) -> PyRef { + self.inner + } +} + +impl Clone for PyRefExact { + fn clone(&self) -> Self { + let inner = self.inner.clone(); + Self { inner } + } +} + +impl TryFromObject for PyRefExact { + fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult { + let target_cls = T::class(vm); + let cls = obj.class(); + if cls.is(target_cls) { + drop(cls); + let obj = obj + .downcast() + .map_err(|obj| vm.new_downcast_runtime_error(target_cls, &obj))?; + Ok(Self { inner: obj }) + } else if cls.fast_issubclass(target_cls) { + Err(vm.new_type_error(format!( + "Expected an exact instance of '{}', not a subclass '{}'", + target_cls.name(), + cls.name(), + ))) + } else { + Err(vm.new_type_error(format!( + "Expected type '{}', not '{}'", + target_cls.name(), + cls.name(), + ))) + } + } +} + +impl Deref for PyRefExact { + type Target = PyRef; + #[inline(always)] + fn deref(&self) -> &PyRef { + &self.inner + } +} + +impl ToPyObject for PyRefExact { + #[inline(always)] + fn to_pyobject(self, _vm: &VirtualMachine) -> PyObjectRef { + self.inner.into() + } +} + +pub trait AsObject +where + Self: Borrow, +{ + #[inline(always)] + fn as_object(&self) -> &PyObject { + self.borrow() + } + + #[inline(always)] + fn get_id(&self) -> usize { + self.as_object().unique_id() + } + + #[inline(always)] + fn is(&self, other: &T) -> bool + where + T: AsObject, + { + self.get_id() == other.get_id() + } + + #[inline(always)] + fn class(&self) -> PyLease<'_, PyType> { + self.as_object().lease_class() + } + + fn get_class_attr(&self, attr_name: &str) -> Option { + self.class().get_attr(attr_name) + } + + /// Determines if `obj` actually an instance of `cls`, this doesn't call __instancecheck__, so only + /// use this if `cls` is known to have not overridden the base __instancecheck__ magic method. + #[inline] + fn fast_isinstance(&self, cls: &Py) -> bool { + self.class().fast_issubclass(cls) + } +} + +impl AsObject for T where T: Borrow {} + +impl PyObject { + #[inline(always)] + fn unique_id(&self) -> usize { + self as *const PyObject as usize + } + + #[inline] + fn lease_class(&self) -> PyLease<'_, PyType> { + PyLease { + inner: self.class_lock().read(), + } + } +} + +// impl Borrow for PyRc { +// #[inline(always)] +// fn borrow(&self) -> &PyObject { +// unsafe { &*(&**self as *const T as *const PyObject) } +// } +// } + +/// A borrow of a reference to a Python object. This avoids having clone the `PyRef`/ +/// `PyObjectRef`, which isn't that cheap as that increments the atomic reference counter. +pub struct PyLease<'a, T: PyObjectPayload> { + inner: PyRwLockReadGuard<'a, PyRef>, +} + +impl<'a, T: PyObjectPayload + PyPayload> PyLease<'a, T> { + #[inline(always)] + pub fn into_owned(self) -> PyRef { + self.inner.clone() + } +} + +impl<'a, T: PyObjectPayload + PyPayload> Borrow for PyLease<'a, T> { + #[inline(always)] + fn borrow(&self) -> &PyObject { + self.inner.as_ref() + } +} + +impl<'a, T: PyObjectPayload + PyPayload> Deref for PyLease<'a, T> { + type Target = PyRef; + #[inline(always)] + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl<'a, T> fmt::Display for PyLease<'a, T> +where + T: PyPayload + fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&**self, f) + } +} + +impl ToPyObject for PyRef { + #[inline(always)] + fn to_pyobject(self, _vm: &VirtualMachine) -> PyObjectRef { + self.into() + } +} + +impl ToPyObject for PyObjectRef { + #[inline(always)] + fn to_pyobject(self, _vm: &VirtualMachine) -> PyObjectRef { + self + } +} + +impl ToPyObject for &PyObject { + #[inline(always)] + fn to_pyobject(self, _vm: &VirtualMachine) -> PyObjectRef { + self.to_owned() + } +} + +// Allows a built-in function to return any built-in object payload without +// explicitly implementing `ToPyObject`. +impl ToPyObject for T +where + T: PyPayload + Sized, +{ + #[inline(always)] + fn to_pyobject(self, vm: &VirtualMachine) -> PyObjectRef { + PyPayload::into_pyobject(self, vm) + } +} + +impl ToPyResult for T +where + T: ToPyObject, +{ + #[inline(always)] + fn to_pyresult(self, vm: &VirtualMachine) -> PyResult { + Ok(self.to_pyobject(vm)) + } +} + +impl ToPyResult for PyResult +where + T: ToPyObject, +{ + #[inline(always)] + fn to_pyresult(self, vm: &VirtualMachine) -> PyResult { + self.map(|res| T::to_pyobject(res, vm)) + } +} diff --git a/vm/src/object/mod.rs b/vm/src/object/mod.rs new file mode 100644 index 000000000..285063583 --- /dev/null +++ b/vm/src/object/mod.rs @@ -0,0 +1,7 @@ +mod core; +mod ext; +mod payload; + +pub use self::core::*; +pub use self::ext::*; +pub use self::payload::*; diff --git a/vm/src/object/payload.rs b/vm/src/object/payload.rs new file mode 100644 index 000000000..44b4f1174 --- /dev/null +++ b/vm/src/object/payload.rs @@ -0,0 +1,76 @@ +use super::{PyObject, PyObjectRef, PyRef, PyResult}; +use crate::{ + builtins::{PyBaseExceptionRef, PyTypeRef}, + types::PyTypeFlags, + vm::VirtualMachine, +}; + +cfg_if::cfg_if! { + if #[cfg(feature = "threading")] { + pub trait PyThreadingConstraint: Send + Sync {} + impl PyThreadingConstraint for T {} + } else { + pub trait PyThreadingConstraint {} + impl PyThreadingConstraint for T {} + } +} + +pub trait PyPayload: std::fmt::Debug + PyThreadingConstraint + Sized + 'static { + fn class(vm: &VirtualMachine) -> &PyTypeRef; + + #[inline] + fn into_pyobject(self, vm: &VirtualMachine) -> PyObjectRef { + self.into_ref(vm).into() + } + + #[inline(always)] + fn special_retrieve(_vm: &VirtualMachine, _obj: &PyObject) -> Option>> { + None + } + + #[inline] + fn _into_ref(self, cls: PyTypeRef, vm: &VirtualMachine) -> PyRef { + let dict = if cls.slots.flags.has_feature(PyTypeFlags::HAS_DICT) { + Some(vm.ctx.new_dict()) + } else { + None + }; + PyRef::new_ref(self, cls, dict) + } + + #[inline] + fn into_ref(self, vm: &VirtualMachine) -> PyRef { + let cls = Self::class(vm); + self._into_ref(cls.clone(), vm) + } + + #[inline] + fn into_ref_with_type(self, vm: &VirtualMachine, cls: PyTypeRef) -> PyResult> { + let exact_class = Self::class(vm); + if cls.fast_issubclass(exact_class) { + Ok(self._into_ref(cls, vm)) + } else { + #[cold] + #[inline(never)] + fn _into_ref_with_type_error( + vm: &VirtualMachine, + cls: &PyTypeRef, + exact_class: &PyTypeRef, + ) -> PyBaseExceptionRef { + vm.new_type_error(format!( + "'{}' is not a subtype of '{}'", + &cls.name(), + exact_class.name() + )) + } + Err(_into_ref_with_type_error(vm, &cls, exact_class)) + } + } +} + +pub trait PyObjectPayload: + std::any::Any + std::fmt::Debug + PyThreadingConstraint + 'static +{ +} + +impl PyObjectPayload for T {} diff --git a/vm/src/prelude.rs b/vm/src/prelude.rs new file mode 100644 index 000000000..f562d0656 --- /dev/null +++ b/vm/src/prelude.rs @@ -0,0 +1,6 @@ +pub use crate::{ + object::{ + AsObject, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyRefExact, PyResult, PyWeakRef, + }, + vm::{Context, InitParameter, Interpreter, Settings, VirtualMachine}, +}; diff --git a/vm/src/protocol/buffer.rs b/vm/src/protocol/buffer.rs index 4a6bd8afb..9f4c191be 100644 --- a/vm/src/protocol/buffer.rs +++ b/vm/src/protocol/buffer.rs @@ -6,7 +6,7 @@ use crate::{ borrow::{BorrowedValue, BorrowedValueMut}, lock::{MapImmutable, PyMutex, PyMutexGuard}, }, - pyobject::PyObjectPayload, + object::PyObjectPayload, sliceable::wrap_index, types::{Constructor, Unconstructible}, AsObject, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromBorrowedObject, diff --git a/vm/src/py_serde.rs b/vm/src/py_serde.rs index 0f0653ee2..695e77726 100644 --- a/vm/src/py_serde.rs +++ b/vm/src/py_serde.rs @@ -3,7 +3,7 @@ use num_traits::sign::Signed; use serde::de::{DeserializeSeed, Visitor}; use serde::ser::{Serialize, SerializeMap, SerializeSeq}; -use crate::builtins::{dict::PyDictRef, float, int, list::PyList, pybool, tuple::PyTuple, PyStr}; +use crate::builtins::{bool_, dict::PyDictRef, float, int, list::PyList, tuple::PyTuple, PyStr}; use crate::{AsObject, PyObject, PyObjectRef, VirtualMachine}; #[inline] @@ -67,7 +67,7 @@ impl<'s> serde::Serialize for PyObjectSerializer<'s> { } else if self.pyobject.fast_isinstance(&self.vm.ctx.types.float_type) { serializer.serialize_f64(float::get_value(self.pyobject)) } else if self.pyobject.fast_isinstance(&self.vm.ctx.types.bool_type) { - serializer.serialize_bool(pybool::get_value(self.pyobject)) + serializer.serialize_bool(bool_::get_value(self.pyobject)) } else if self.pyobject.fast_isinstance(&self.vm.ctx.types.int_type) { let v = int::get_value(self.pyobject); let int_too_large = || serde::ser::Error::custom("int too large to serialize"); diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs deleted file mode 100644 index cfd773529..000000000 --- a/vm/src/pyobject.rs +++ /dev/null @@ -1,495 +0,0 @@ -use crate::common::lock::PyRwLockReadGuard; -use crate::{ - builtins::{object, pystr, PyBaseExceptionRef, PyType, PyTypeRef}, - convert::{ToPyObject, ToPyResult, TryFromObject}, - function::IntoFuncArgs, - types::PyTypeFlags, - VirtualMachine, - _pyobjectrc::{Py, PyObject, PyObjectRef, PyRef}, -}; -use std::{any::Any, borrow::Borrow, fmt, ops::Deref}; - -/* Python objects and references. - -Okay, so each python object itself is an class itself (PyObject). Each -python object can have several references to it (PyObjectRef). These -references are Rc (reference counting) rust smart pointers. So when -all references are destroyed, the object itself also can be cleaned up. -Basically reference counting, but then done by rust. - -*/ - -/* - * Good reference: https://github.com/ProgVal/pythonvm-rust/blob/master/src/objects/mod.rs - */ - -/// Use this type for functions which return a python object or an exception. -/// Both the python object and the python exception are `PyObjectRef` types -/// since exceptions are also python objects. -pub type PyResult = Result; // A valid value, or an exception - -// TODO: remove these 2 impls -impl fmt::Display for PyObjectRef { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - (**self).fmt(f) - } -} -impl fmt::Display for PyObject { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "'{}' object", self.class().name()) - } -} - -impl fmt::Display for PyRef -where - T: PyObjectPayload + fmt::Display, -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&**self, f) - } -} -impl fmt::Display for Py -where - T: PyObjectPayload + fmt::Display, -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&**self, f) - } -} - -#[derive(Debug)] -pub struct PyRefExact { - inner: PyRef, -} - -impl PyRefExact { - /// # Safety - /// obj must have exact type for the payload - pub unsafe fn new_unchecked(obj: PyRef) -> Self { - Self { inner: obj } - } - - pub fn into_pyref(self) -> PyRef { - self.inner - } -} - -impl Clone for PyRefExact { - fn clone(&self) -> Self { - let inner = self.inner.clone(); - Self { inner } - } -} - -impl TryFromObject for PyRefExact { - fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult { - let target_cls = T::class(vm); - let cls = obj.class(); - if cls.is(target_cls) { - drop(cls); - let obj = obj - .downcast() - .map_err(|obj| vm.new_downcast_runtime_error(target_cls, &obj))?; - Ok(Self { inner: obj }) - } else if cls.fast_issubclass(target_cls) { - Err(vm.new_type_error(format!( - "Expected an exact instance of '{}', not a subclass '{}'", - target_cls.name(), - cls.name(), - ))) - } else { - Err(vm.new_type_error(format!( - "Expected type '{}', not '{}'", - target_cls.name(), - cls.name(), - ))) - } - } -} - -impl Deref for PyRefExact { - type Target = PyRef; - #[inline(always)] - fn deref(&self) -> &PyRef { - &self.inner - } -} - -impl ToPyObject for PyRefExact { - #[inline(always)] - fn to_pyobject(self, _vm: &VirtualMachine) -> PyObjectRef { - self.inner.into() - } -} - -pub trait AsObject -where - Self: Borrow, -{ - #[inline(always)] - fn as_object(&self) -> &PyObject { - self.borrow() - } - - #[inline(always)] - fn get_id(&self) -> usize { - self.as_object().unique_id() - } - - #[inline(always)] - fn is(&self, other: &T) -> bool - where - T: AsObject, - { - self.get_id() == other.get_id() - } - - #[inline(always)] - fn class(&self) -> PyLease<'_, PyType> { - self.as_object().lease_class() - } - - fn get_class_attr(&self, attr_name: &str) -> Option { - self.class().get_attr(attr_name) - } - - /// Determines if `obj` actually an instance of `cls`, this doesn't call __instancecheck__, so only - /// use this if `cls` is known to have not overridden the base __instancecheck__ magic method. - #[inline] - fn fast_isinstance(&self, cls: &Py) -> bool { - self.class().fast_issubclass(cls) - } -} - -impl AsObject for T where T: Borrow {} - -impl PyObject { - #[inline(always)] - fn unique_id(&self) -> usize { - self as *const PyObject as usize - } - - #[inline] - fn lease_class(&self) -> PyLease<'_, PyType> { - PyLease { - inner: self.class_lock().read(), - } - } -} - -// impl Borrow for PyRc { -// #[inline(always)] -// fn borrow(&self) -> &PyObject { -// unsafe { &*(&**self as *const T as *const PyObject) } -// } -// } - -/// A borrow of a reference to a Python object. This avoids having clone the `PyRef`/ -/// `PyObjectRef`, which isn't that cheap as that increments the atomic reference counter. -pub struct PyLease<'a, T: PyObjectPayload> { - inner: PyRwLockReadGuard<'a, PyRef>, -} - -impl<'a, T: PyObjectPayload + PyPayload> PyLease<'a, T> { - #[inline(always)] - pub fn into_owned(self) -> PyRef { - self.inner.clone() - } -} - -impl<'a, T: PyObjectPayload + PyPayload> Borrow for PyLease<'a, T> { - #[inline(always)] - fn borrow(&self) -> &PyObject { - self.inner.as_ref() - } -} - -impl<'a, T: PyObjectPayload + PyPayload> Deref for PyLease<'a, T> { - type Target = PyRef; - #[inline(always)] - fn deref(&self) -> &Self::Target { - &self.inner - } -} - -impl<'a, T> fmt::Display for PyLease<'a, T> -where - T: PyPayload + fmt::Display, -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&**self, f) - } -} - -impl ToPyObject for PyRef { - #[inline(always)] - fn to_pyobject(self, _vm: &VirtualMachine) -> PyObjectRef { - self.into() - } -} - -impl ToPyObject for PyObjectRef { - #[inline(always)] - fn to_pyobject(self, _vm: &VirtualMachine) -> PyObjectRef { - self - } -} - -impl ToPyObject for &PyObject { - #[inline(always)] - fn to_pyobject(self, _vm: &VirtualMachine) -> PyObjectRef { - self.to_owned() - } -} - -// Allows a built-in function to return any built-in object payload without -// explicitly implementing `ToPyObject`. -impl ToPyObject for T -where - T: PyPayload + Sized, -{ - #[inline(always)] - fn to_pyobject(self, vm: &VirtualMachine) -> PyObjectRef { - PyPayload::into_pyobject(self, vm) - } -} - -impl ToPyResult for T -where - T: ToPyObject, -{ - #[inline(always)] - fn to_pyresult(self, vm: &VirtualMachine) -> PyResult { - Ok(self.to_pyobject(vm)) - } -} - -impl ToPyResult for PyResult -where - T: ToPyObject, -{ - #[inline(always)] - fn to_pyresult(self, vm: &VirtualMachine) -> PyResult { - self.map(|res| T::to_pyobject(res, vm)) - } -} - -cfg_if::cfg_if! { - if #[cfg(feature = "threading")] { - pub trait PyThreadingConstraint: Send + Sync {} - impl PyThreadingConstraint for T {} - } else { - pub trait PyThreadingConstraint {} - impl PyThreadingConstraint for T {} - } -} - -pub trait PyPayload: fmt::Debug + PyThreadingConstraint + Sized + 'static { - fn class(vm: &VirtualMachine) -> &PyTypeRef; - - #[inline] - fn into_pyobject(self, vm: &VirtualMachine) -> PyObjectRef { - self.into_ref(vm).into() - } - - #[inline(always)] - fn special_retrieve(_vm: &VirtualMachine, _obj: &PyObject) -> Option>> { - None - } - - #[inline] - fn _into_ref(self, cls: PyTypeRef, vm: &VirtualMachine) -> PyRef { - let dict = if cls.slots.flags.has_feature(PyTypeFlags::HAS_DICT) { - Some(vm.ctx.new_dict()) - } else { - None - }; - PyRef::new_ref(self, cls, dict) - } - - #[inline] - fn into_ref(self, vm: &VirtualMachine) -> PyRef { - let cls = Self::class(vm); - self._into_ref(cls.clone(), vm) - } - - #[cold] - fn _into_ref_with_type_error( - vm: &VirtualMachine, - cls: &PyTypeRef, - exact_class: &PyTypeRef, - ) -> PyBaseExceptionRef { - vm.new_type_error(format!( - "'{}' is not a subtype of '{}'", - &cls.name(), - exact_class.name() - )) - } - - #[inline] - fn into_ref_with_type(self, vm: &VirtualMachine, cls: PyTypeRef) -> PyResult> { - let exact_class = Self::class(vm); - if cls.fast_issubclass(exact_class) { - Ok(self._into_ref(cls, vm)) - } else { - Err(Self::_into_ref_with_type_error(vm, &cls, exact_class)) - } - } - - #[inline] - fn into_pyresult_with_type(self, vm: &VirtualMachine, cls: PyTypeRef) -> PyResult { - self.into_ref_with_type(vm, cls).to_pyresult(vm) - } -} - -pub trait PyObjectPayload: Any + fmt::Debug + PyThreadingConstraint + 'static {} - -impl PyObjectPayload for T {} - -pub trait PyObjectWrap -where - Self: AsObject, -{ - fn into_object(self) -> PyObjectRef; -} - -impl From for PyObjectRef -where - T: PyObjectWrap, -{ - #[inline(always)] - fn from(py_ref: T) -> Self { - py_ref.into_object() - } -} - -#[derive(Debug)] -pub enum PyMethod { - Function { - target: PyObjectRef, - func: PyObjectRef, - }, - Attribute(PyObjectRef), -} - -impl PyMethod { - pub fn get(obj: PyObjectRef, name: pystr::PyStrRef, vm: &VirtualMachine) -> PyResult { - let cls = obj.class(); - let getattro = cls.mro_find_map(|cls| cls.slots.getattro.load()).unwrap(); - if getattro as usize != object::PyBaseObject::getattro as usize { - drop(cls); - return obj.get_attr(name, vm).map(Self::Attribute); - } - - let mut is_method = false; - - let cls_attr = match cls.get_attr(name.as_str()) { - Some(descr) => { - let descr_cls = descr.class(); - let descr_get = if descr_cls.slots.flags.has_feature(PyTypeFlags::METHOD_DESCR) { - is_method = true; - None - } else { - let descr_get = descr_cls.mro_find_map(|cls| cls.slots.descr_get.load()); - if let Some(descr_get) = descr_get { - if descr_cls - .mro_find_map(|cls| cls.slots.descr_set.load()) - .is_some() - { - drop(descr_cls); - let cls = cls.into_owned().into(); - return descr_get(descr, Some(obj), Some(cls), vm).map(Self::Attribute); - } - } - descr_get - }; - drop(descr_cls); - Some((descr, descr_get)) - } - None => None, - }; - - if let Some(dict) = obj.dict() { - if let Some(attr) = dict.get_item_opt(name.clone(), vm)? { - return Ok(Self::Attribute(attr)); - } - } - - if let Some((attr, descr_get)) = cls_attr { - match descr_get { - None if is_method => { - drop(cls); - Ok(Self::Function { - target: obj, - func: attr, - }) - } - Some(descr_get) => { - let cls = cls.into_owned().into(); - descr_get(attr, Some(obj), Some(cls), vm).map(Self::Attribute) - } - None => Ok(Self::Attribute(attr)), - } - } else if let Some(getter) = cls.get_attr("__getattr__") { - drop(cls); - vm.invoke(&getter, (obj, name)).map(Self::Attribute) - } else { - let exc = vm.new_attribute_error(format!( - "'{}' object has no attribute '{}'", - cls.name(), - name - )); - vm.set_attribute_error_context(&exc, obj.clone(), name); - Err(exc) - } - } - - pub(crate) fn get_special( - obj: PyObjectRef, - name: &str, - vm: &VirtualMachine, - ) -> PyResult> { - let obj_cls = obj.class(); - let func = match obj_cls.get_attr(name) { - Some(f) => f, - None => { - drop(obj_cls); - return Ok(Err(obj)); - } - }; - let meth = if func - .class() - .slots - .flags - .has_feature(PyTypeFlags::METHOD_DESCR) - { - drop(obj_cls); - Self::Function { target: obj, func } - } else { - let obj_cls = obj_cls.into_owned().into(); - let attr = vm - .call_get_descriptor_specific(func, Some(obj), Some(obj_cls)) - .unwrap_or_else(Ok)?; - Self::Attribute(attr) - }; - Ok(Ok(meth)) - } - - pub fn invoke(self, args: impl IntoFuncArgs, vm: &VirtualMachine) -> PyResult { - let (func, args) = match self { - PyMethod::Function { target, func } => (func, args.into_method_args(target, vm)), - PyMethod::Attribute(func) => (func, args.into_args(vm)), - }; - vm.invoke(&func, args) - } - - pub fn invoke_ref(&self, args: impl IntoFuncArgs, vm: &VirtualMachine) -> PyResult { - let (func, args) = match self { - PyMethod::Function { target, func } => { - (func, args.into_method_args(target.clone(), vm)) - } - PyMethod::Attribute(func) => (func, args.into_args(vm)), - }; - vm.invoke(func, args) - } -} diff --git a/vm/src/stdlib/ast.rs b/vm/src/stdlib/ast.rs index b30ed7819..917816e8a 100644 --- a/vm/src/stdlib/ast.rs +++ b/vm/src/stdlib/ast.rs @@ -7,7 +7,7 @@ mod gen; use crate::{ builtins::{self, PyStrRef, PyTypeRef}, - pyclass::{PyClassImpl, StaticType}, + class::{PyClassImpl, StaticType}, AsObject, Context, PyObject, PyObjectRef, PyPayload, PyResult, TryFromObject, VirtualMachine, }; use num_complex::Complex64; diff --git a/vm/src/stdlib/atexit.rs b/vm/src/stdlib/atexit.rs index 5a442874a..37127deea 100644 --- a/vm/src/stdlib/atexit.rs +++ b/vm/src/stdlib/atexit.rs @@ -33,24 +33,17 @@ mod atexit { } #[pyfunction] - pub fn _run_exitfuncs(vm: &VirtualMachine) -> PyResult<()> { - let mut last_exc = None; - for (func, args) in vm.state.atexit_funcs.lock().drain(..).rev() { + pub fn _run_exitfuncs(vm: &VirtualMachine) { + let funcs: Vec<_> = std::mem::take(&mut *vm.state.atexit_funcs.lock()); + for (func, args) in funcs.into_iter().rev() { if let Err(e) = vm.invoke(&func, args) { - last_exc = Some(e.clone()); - if !e.fast_isinstance(&vm.ctx.exceptions.system_exit) { - writeln!( - crate::stdlib::sys::PyStderr(vm), - "Error in atexit._run_exitfuncs:" - ); - vm.print_exception(e); + let exit = e.fast_isinstance(&vm.ctx.exceptions.system_exit); + vm.run_unraisable(e, Some("Error in atexit._run_exitfuncs".to_owned()), func); + if exit { + break; } } } - match last_exc { - None => Ok(()), - Some(e) => Err(e), - } } #[pyfunction] diff --git a/vm/src/stdlib/builtins.rs b/vm/src/stdlib/builtins.rs index 5e59e03b9..ed37670fa 100644 --- a/vm/src/stdlib/builtins.rs +++ b/vm/src/stdlib/builtins.rs @@ -1,7 +1,7 @@ //! Builtin function definitions. //! //! Implements the list of [builtin Python functions](https://docs.python.org/3/library/builtins.html). -use crate::{pyclass::PyClassImpl, PyObjectRef, VirtualMachine}; +use crate::{class::PyClassImpl, PyObjectRef, VirtualMachine}; /// Built-in functions, exceptions, and other objects. /// @@ -21,6 +21,7 @@ mod builtins { PyByteArray, PyBytes, PyBytesRef, PyCode, PyDictRef, PyStr, PyStrRef, PyTuple, PyTupleRef, PyType, }, + class::PyClassImpl, common::{hash::PyHash, str::to_ascii}, function::{ ArgBytesLike, ArgCallable, ArgIntoBool, ArgIterable, ArgMapping, FuncArgs, KwArgs, @@ -28,7 +29,6 @@ mod builtins { }, protocol::{PyIter, PyIterReturn}, py_io, - pyclass::PyClassImpl, readline::{Readline, ReadlineResult}, scope::Scope, stdlib::sys, diff --git a/vm/src/stdlib/collections.rs b/vm/src/stdlib/collections.rs index 4d94fbea5..18db84874 100644 --- a/vm/src/stdlib/collections.rs +++ b/vm/src/stdlib/collections.rs @@ -58,7 +58,9 @@ mod _collections { impl PyDeque { #[pyslot] fn slot_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { - PyDeque::default().into_pyresult_with_type(vm, cls) + PyDeque::default() + .into_ref_with_type(vm, cls) + .map(Into::into) } #[pymethod(magic)] @@ -605,7 +607,7 @@ mod _collections { let index = max(index, 0) as usize; iter.internal.lock().position = index; } - iter.into_pyresult_with_type(vm, cls) + iter.into_ref_with_type(vm, cls).map(Into::into) } } @@ -678,7 +680,7 @@ mod _collections { let index = max(index, 0) as usize; iter.internal.lock().position = index; } - iter.into_pyresult_with_type(vm, cls) + iter.into_ref_with_type(vm, cls).map(Into::into) } } diff --git a/vm/src/stdlib/io.rs b/vm/src/stdlib/io.rs index 0776c84af..4ba0424ba 100644 --- a/vm/src/stdlib/io.rs +++ b/vm/src/stdlib/io.rs @@ -99,6 +99,7 @@ mod _io { PyBaseExceptionRef, PyByteArray, PyBytes, PyBytesRef, PyIntRef, PyMemoryView, PyStr, PyStrRef, PyType, PyTypeRef, }, + class::StaticType, common::lock::{ PyMappedThreadMutexGuard, PyRwLock, PyRwLockReadGuard, PyRwLockWriteGuard, PyThreadMutex, PyThreadMutexGuard, @@ -110,7 +111,6 @@ mod _io { protocol::{ BufferDescriptor, BufferMethods, BufferResizeGuard, PyBuffer, PyIterReturn, VecBuffer, }, - pyclass::StaticType, recursion::ReprGuard, types::{Constructor, Destructor, IterNext, Iterable}, utils::Either, @@ -1667,7 +1667,7 @@ mod _io { impl BufferedReader { #[pyslot] fn slot_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { - Self::default().into_pyresult_with_type(vm, cls) + Self::default().into_ref_with_type(vm, cls).map(Into::into) } } @@ -1716,7 +1716,7 @@ mod _io { impl BufferedWriter { #[pyslot] fn slot_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { - Self::default().into_pyresult_with_type(vm, cls) + Self::default().into_ref_with_type(vm, cls).map(Into::into) } } @@ -1754,7 +1754,7 @@ mod _io { impl BufferedRandom { #[pyslot] fn slot_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { - Self::default().into_pyresult_with_type(vm, cls) + Self::default().into_ref_with_type(vm, cls).map(Into::into) } } @@ -1781,7 +1781,7 @@ mod _io { impl BufferedRWPair { #[pyslot] fn slot_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { - Self::default().into_pyresult_with_type(vm, cls) + Self::default().into_ref_with_type(vm, cls).map(Into::into) } #[pymethod(magic)] fn init( @@ -2176,7 +2176,7 @@ mod _io { impl TextIOWrapper { #[pyslot] fn slot_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { - Self::default().into_pyresult_with_type(vm, cls) + Self::default().into_ref_with_type(vm, cls).map(Into::into) } fn lock_opt( @@ -3059,7 +3059,8 @@ mod _io { buffer: PyRwLock::new(BufferedIO::new(Cursor::new(raw_bytes))), closed: AtomicCell::new(false), } - .into_pyresult_with_type(vm, cls) + .into_ref_with_type(vm, cls) + .map(Into::into) } } @@ -3194,7 +3195,8 @@ mod _io { closed: AtomicCell::new(false), exports: AtomicCell::new(0), } - .into_pyresult_with_type(vm, cls) + .into_ref_with_type(vm, cls) + .map(Into::into) } } @@ -3823,7 +3825,8 @@ mod fileio { mode: AtomicCell::new(Mode::empty()), seekable: AtomicCell::new(None), } - .into_pyresult_with_type(vm, cls) + .into_ref_with_type(vm, cls) + .map(Into::into) } #[pymethod(magic)] diff --git a/vm/src/stdlib/itertools.rs b/vm/src/stdlib/itertools.rs index 803886192..95ef9dd70 100644 --- a/vm/src/stdlib/itertools.rs +++ b/vm/src/stdlib/itertools.rs @@ -38,7 +38,8 @@ mod decl { cur_idx: AtomicCell::new(0), cached_iter: PyRwLock::new(None), } - .into_pyresult_with_type(vm, cls) + .into_ref_with_type(vm, cls) + .map(Into::into) } #[pyclassmethod] @@ -121,7 +122,9 @@ mod decl { Self::Args { data, selector }: Self::Args, vm: &VirtualMachine, ) -> PyResult { - PyItertoolsCompress { data, selector }.into_pyresult_with_type(vm, cls) + PyItertoolsCompress { data, selector } + .into_ref_with_type(vm, cls) + .map(Into::into) } } @@ -184,7 +187,8 @@ mod decl { cur: PyRwLock::new(start), step, } - .into_pyresult_with_type(vm, cls) + .into_ref_with_type(vm, cls) + .map(Into::into) } } @@ -218,7 +222,8 @@ mod decl { saved: PyRwLock::new(Vec::new()), index: AtomicCell::new(0), } - .into_pyresult_with_type(vm, cls) + .into_ref_with_type(vm, cls) + .map(Into::into) } } @@ -280,7 +285,9 @@ mod decl { } None => None, }; - PyItertoolsRepeat { object, times }.into_pyresult_with_type(vm, cls) + PyItertoolsRepeat { object, times } + .into_ref_with_type(vm, cls) + .map(Into::into) } } @@ -353,7 +360,9 @@ mod decl { Self::Args { function, iterable }: Self::Args, vm: &VirtualMachine, ) -> PyResult { - PyItertoolsStarmap { function, iterable }.into_pyresult_with_type(vm, cls) + PyItertoolsStarmap { function, iterable } + .into_ref_with_type(vm, cls) + .map(Into::into) } } @@ -407,7 +416,8 @@ mod decl { iterable, stop_flag: AtomicCell::new(false), } - .into_pyresult_with_type(vm, cls) + .into_ref_with_type(vm, cls) + .map(Into::into) } } @@ -471,7 +481,8 @@ mod decl { iterable, start_flag: AtomicCell::new(false), } - .into_pyresult_with_type(vm, cls) + .into_ref_with_type(vm, cls) + .map(Into::into) } } @@ -573,7 +584,8 @@ mod decl { grouper: None, }), } - .into_pyresult_with_type(vm, cls) + .into_ref_with_type(vm, cls) + .map(Into::into) } } @@ -784,7 +796,8 @@ mod decl { stop, step, } - .into_pyresult_with_type(vm, cls) + .into_ref_with_type(vm, cls) + .map(Into::into) } } @@ -847,7 +860,8 @@ mod decl { predicate, iterable, } - .into_pyresult_with_type(vm, cls) + .into_ref_with_type(vm, cls) + .map(Into::into) } } @@ -906,7 +920,8 @@ mod decl { initial: args.initial.flatten(), acc_value: PyRwLock::new(None), } - .into_pyresult_with_type(vm, cls) + .into_ref_with_type(vm, cls) + .map(Into::into) } } @@ -1091,7 +1106,8 @@ mod decl { cur: AtomicCell::new(l.wrapping_sub(1)), stop: AtomicCell::new(false), } - .into_pyresult_with_type(vm, cls) + .into_ref_with_type(vm, cls) + .map(Into::into) } } @@ -1193,7 +1209,8 @@ mod decl { r: AtomicCell::new(r), exhausted: AtomicCell::new(r > n), } - .into_pyresult_with_type(vm, cls) + .into_ref_with_type(vm, cls) + .map(Into::into) } } @@ -1283,7 +1300,8 @@ mod decl { r: AtomicCell::new(r), exhausted: AtomicCell::new(n == 0 && r > 0), } - .into_pyresult_with_type(vm, cls) + .into_ref_with_type(vm, cls) + .map(Into::into) } } @@ -1392,7 +1410,8 @@ mod decl { r: AtomicCell::new(r), exhausted: AtomicCell::new(r > n), } - .into_pyresult_with_type(vm, cls) + .into_ref_with_type(vm, cls) + .map(Into::into) } } @@ -1486,7 +1505,8 @@ mod decl { iterators, fillvalue, } - .into_pyresult_with_type(vm, cls) + .into_ref_with_type(vm, cls) + .map(Into::into) } } @@ -1542,7 +1562,8 @@ mod decl { iterator, old: PyRwLock::new(None), } - .into_pyresult_with_type(vm, cls) + .into_ref_with_type(vm, cls) + .map(Into::into) } } diff --git a/vm/src/stdlib/marshal.rs b/vm/src/stdlib/marshal.rs index fd5f50a27..5bcf17bea 100644 --- a/vm/src/stdlib/marshal.rs +++ b/vm/src/stdlib/marshal.rs @@ -10,8 +10,8 @@ mod decl { bytecode, convert::ToPyObject, function::ArgBytesLike, + object::AsObject, protocol::PyBuffer, - pyobject::AsObject, PyObjectRef, PyResult, TryFromObject, VirtualMachine, }; /// TODO diff --git a/vm/src/stdlib/operator.rs b/vm/src/stdlib/operator.rs index 2aedb6cc2..1f83294ad 100644 --- a/vm/src/stdlib/operator.rs +++ b/vm/src/stdlib/operator.rs @@ -490,7 +490,9 @@ mod _operator { return Err(vm.new_type_error("attribute name must be a string".to_owned())); } } - PyAttrGetter { attrs }.into_pyresult_with_type(vm, cls) + PyAttrGetter { attrs } + .into_ref_with_type(vm, cls) + .map(Into::into) } } @@ -555,7 +557,9 @@ mod _operator { if args.args.is_empty() { return Err(vm.new_type_error("itemgetter expected 1 argument, got 0.".to_owned())); } - PyItemGetter { items: args.args }.into_pyresult_with_type(vm, cls) + PyItemGetter { items: args.args } + .into_ref_with_type(vm, cls) + .map(Into::into) } } @@ -648,7 +652,9 @@ mod _operator { fn py_new(cls: PyTypeRef, (name, args): Self::Args, vm: &VirtualMachine) -> PyResult { if let Ok(name) = name.try_into_value(vm) { - PyMethodCaller { name, args }.into_pyresult_with_type(vm, cls) + PyMethodCaller { name, args } + .into_ref_with_type(vm, cls) + .map(Into::into) } else { Err(vm.new_type_error("method name must be a string".to_owned())) } diff --git a/vm/src/stdlib/posix.rs b/vm/src/stdlib/posix.rs index ab8635115..99044633a 100644 --- a/vm/src/stdlib/posix.rs +++ b/vm/src/stdlib/posix.rs @@ -583,7 +583,8 @@ pub mod module { SchedParam { sched_priority: arg.sched_priority, } - .into_pyresult_with_type(vm, cls) + .into_ref_with_type(vm, cls) + .map(Into::into) } } diff --git a/vm/src/stdlib/sys.rs b/vm/src/stdlib/sys.rs index 0204af2be..0c05e985e 100644 --- a/vm/src/stdlib/sys.rs +++ b/vm/src/stdlib/sys.rs @@ -1,6 +1,6 @@ use crate::{convert::ToPyObject, PyObject, PyResult, VirtualMachine}; -pub(crate) use sys::{MAXSIZE, MULTIARCH}; +pub(crate) use sys::{UnraisableHookArgs, MAXSIZE, MULTIARCH}; #[pymodule] mod sys { @@ -16,7 +16,7 @@ mod sys { types::PyStructSequence, version, vm::{Settings, VirtualMachine}, - PyObjectRef, PyRef, PyRefExact, PyResult, + AsObject, PyObjectRef, PyRef, PyRefExact, PyResult, }; use num_traits::ToPrimitive; use std::{env, mem, path}; @@ -448,6 +448,66 @@ mod sys { .into_struct_sequence(vm)) } + fn _unraisablehook(unraisable: UnraisableHookArgs, vm: &VirtualMachine) -> PyResult<()> { + use super::PyStderr; + + let stderr = PyStderr(vm); + if !vm.is_none(&unraisable.object) { + if !vm.is_none(&unraisable.err_msg) { + write!(stderr, "{}: ", unraisable.err_msg.str(vm)?); + } else { + write!(stderr, "Exception ignored in: "); + } + // exception in del will be ignored but printed + let repr = &unraisable.object.repr(vm); + let str = match repr { + Ok(v) => v.to_string(), + Err(_) => format!( + "", + unraisable.object.class().name() + ), + }; + writeln!(stderr, "{str}"); + } else if !vm.is_none(&unraisable.err_msg) { + writeln!(stderr, "{}:", unraisable.err_msg.str(vm)?); + } + + // TODO: print received unraisable.exc_traceback + let tb_module = vm.import("traceback", None, 0)?; + let print_stack = tb_module.get_attr("print_stack", vm)?; + vm.invoke(&print_stack, ())?; + + if vm.is_none(unraisable.exc_type.as_object()) { + // TODO: early return, but with what error? + } + assert!(unraisable + .exc_type + .fast_issubclass(&vm.ctx.exceptions.exception_type)); + + // TODO: print module name and qualname + + if !vm.is_none(&unraisable.exc_value) { + write!(stderr, ": "); + if let Ok(str) = unraisable.exc_value.str(vm) { + write!(stderr, "{}", str.as_str()); + } else { + write!(stderr, ""); + } + } + writeln!(stderr); + // TODO: call file.flush() + + Ok(()) + } + + #[pyattr] + #[pyfunction(name = "__unraisablehook__")] + fn unraisablehook(unraisable: UnraisableHookArgs, vm: &VirtualMachine) { + if let Err(e) = _unraisablehook(unraisable, vm) { + println!("{}", e.as_object().repr(vm).unwrap().as_str()); + } + } + #[pyattr] fn hash_info(vm: &VirtualMachine) -> PyTupleRef { PyHashInfo::INFO.into_struct_sequence(vm) @@ -672,6 +732,19 @@ mod sys { #[cfg(windows)] #[pyimpl(with(PyStructSequence))] impl WindowsVersion {} + + #[pyclass(noattr, module = "sys", name = "UnraisableHookArgs")] + #[derive(Debug, PyStructSequence, TryIntoPyStructSequence)] + pub struct UnraisableHookArgs { + pub exc_type: PyTypeRef, + pub exc_value: PyObjectRef, + pub exc_traceback: PyObjectRef, + pub err_msg: PyObjectRef, + pub object: PyObjectRef, + } + + #[pyimpl(with(PyStructSequence))] + impl UnraisableHookArgs {} } pub(crate) fn init_module(vm: &VirtualMachine, module: &PyObject, builtins: &PyObject) { diff --git a/vm/src/stdlib/thread.rs b/vm/src/stdlib/thread.rs index 87e5d4ecd..94498efa5 100644 --- a/vm/src/stdlib/thread.rs +++ b/vm/src/stdlib/thread.rs @@ -8,7 +8,6 @@ pub(crate) mod _thread { builtins::{PyDictRef, PyStrRef, PyTupleRef, PyTypeRef}, convert::ToPyException, function::{ArgCallable, FuncArgs, KwArgs, OptionalArg}, - py_io, types::{Constructor, GetAttr, SetAttr}, utils::Either, AsObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, @@ -17,7 +16,7 @@ pub(crate) mod _thread { lock_api::{RawMutex as RawMutexT, RawMutexTimed, RawReentrantMutex}, RawMutex, RawThreadId, }; - use std::{cell::RefCell, fmt, io::Write, thread, time::Duration}; + use std::{cell::RefCell, fmt, thread, time::Duration}; use thread_local::ThreadLocal; // TIMEOUT_MAX_IN_MICROSECONDS is a value in microseconds @@ -168,7 +167,8 @@ pub(crate) mod _thread { RLock { mu: RawRMutex::INIT, } - .into_pyresult_with_type(vm, cls) + .into_ref_with_type(vm, cls) + .map(Into::into) } #[pymethod] @@ -255,16 +255,11 @@ pub(crate) mod _thread { Ok(_obj) => {} Err(e) if e.fast_isinstance(&vm.ctx.exceptions.system_exit) => {} Err(exc) => { - // TODO: sys.unraisablehook - let stderr = std::io::stderr(); - let mut stderr = py_io::IoWriter(stderr.lock()); - let repr = func.as_ref().repr(vm).ok(); - let repr = repr - .as_ref() - .map_or("", |s| s.as_str()); - writeln!(*stderr, "Exception ignored in thread started by: {}", repr) - .and_then(|()| vm.write_exception(&mut stderr, &exc)) - .ok(); + vm.run_unraisable( + exc, + Some("Exception ignored in thread started by".to_owned()), + func.into(), + ); } } SENTINELS.with(|sents| { @@ -321,7 +316,8 @@ pub(crate) mod _thread { Local { data: ThreadLocal::new(), } - .into_pyresult_with_type(vm, cls) + .into_ref_with_type(vm, cls) + .map(Into::into) } } diff --git a/vm/src/types/structseq.rs b/vm/src/types/structseq.rs index 245190ac2..4d1af8525 100644 --- a/vm/src/types/structseq.rs +++ b/vm/src/types/structseq.rs @@ -1,6 +1,6 @@ use crate::{ builtins::{PyTuple, PyTupleRef, PyTypeRef}, - pyclass::{PyClassImpl, StaticType}, + class::{PyClassImpl, StaticType}, vm::Context, AsObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, }; diff --git a/vm/src/types/zoo.rs b/vm/src/types/zoo.rs index ec04ba9b3..bd7af4d4b 100644 --- a/vm/src/types/zoo.rs +++ b/vm/src/types/zoo.rs @@ -1,14 +1,13 @@ use crate::{ builtins::{ - asyncgenerator, builtinfunc, bytearray, bytes, classmethod, code, complex, coroutine, dict, - enumerate, filter, float, frame, function, generator, genericalias, getset, int, iter, - list, map, mappingproxy, memory, module, namespace, object, property, pybool, pystr, - pysuper, - pytype::{self, PyTypeRef}, - pyunion, range, set, singletons, slice, staticmethod, traceback, tuple, weakproxy, weakref, - zip, + asyncgenerator, bool_, builtinfunc, bytearray, bytes, classmethod, code, complex, + coroutine, dict, enumerate, filter, float, frame, function, generator, genericalias, + getset, int, iter, list, map, mappingproxy, memory, module, namespace, object, property, + pystr, range, set, singletons, slice, staticmethod, super_, traceback, tuple, + type_::{self, PyTypeRef}, + union_, weakproxy, weakref, zip, }, - pyclass::StaticType, + class::StaticType, vm::Context, }; @@ -93,16 +92,16 @@ pub struct TypeZoo { impl TypeZoo { #[cold] pub(crate) fn init() -> Self { - let (type_type, object_type, weakref_type) = crate::pyobject::init_type_hierarchy(); + let (type_type, object_type, weakref_type) = crate::object::init_type_hierarchy(); Self { // the order matters for type, object, weakref, and int - type_type: pytype::PyType::init_manually(type_type).clone(), + type_type: type_::PyType::init_manually(type_type).clone(), object_type: object::PyBaseObject::init_manually(object_type).clone(), weakref_type: weakref::PyWeak::init_manually(weakref_type).clone(), int_type: int::PyInt::init_bare_type().clone(), // types exposed as builtins - bool_type: pybool::PyBool::init_bare_type().clone(), + bool_type: bool_::PyBool::init_bare_type().clone(), bytearray_type: bytearray::PyByteArray::init_bare_type().clone(), bytes_type: bytes::PyBytes::init_bare_type().clone(), classmethod_type: classmethod::PyClassMethod::init_bare_type().clone(), @@ -121,7 +120,7 @@ impl TypeZoo { slice_type: slice::PySlice::init_bare_type().clone(), staticmethod_type: staticmethod::PyStaticMethod::init_bare_type().clone(), str_type: pystr::PyStr::init_bare_type().clone(), - super_type: pysuper::PySuper::init_bare_type().clone(), + super_type: super_::PySuper::init_bare_type().clone(), tuple_type: tuple::PyTuple::init_bare_type().clone(), zip_type: zip::PyZip::init_bare_type().clone(), @@ -175,14 +174,14 @@ impl TypeZoo { none_type: singletons::PyNone::init_bare_type().clone(), not_implemented_type: singletons::PyNotImplemented::init_bare_type().clone(), generic_alias_type: genericalias::PyGenericAlias::init_bare_type().clone(), - union_type: pyunion::PyUnion::init_bare_type().clone(), + union_type: union_::PyUnion::init_bare_type().clone(), } } /// Fill attributes of builtin types. #[cold] pub(crate) fn extend(context: &Context) { - pytype::init(context); + type_::init(context); object::init(context); list::init(context); set::init(context); @@ -206,13 +205,13 @@ impl TypeZoo { pystr::init(context); range::init(context); slice::init(context); - pysuper::init(context); + super_::init(context); iter::init(context); enumerate::init(context); filter::init(context); map::init(context); zip::init(context); - pybool::init(context); + bool_::init(context); code::init(context); frame::init(context); weakref::init(context); @@ -223,6 +222,6 @@ impl TypeZoo { mappingproxy::init(context); traceback::init(context); genericalias::init(context); - pyunion::init(context); + union_::init(context); } } diff --git a/vm/src/version.rs b/vm/src/version.rs index cd26435df..8b2d55919 100644 --- a/vm/src/version.rs +++ b/vm/src/version.rs @@ -47,7 +47,7 @@ impl VersionInfo { }; #[pyslot] fn slot_new( - _cls: crate::builtins::pytype::PyTypeRef, + _cls: crate::builtins::type_::PyTypeRef, _args: crate::function::FuncArgs, vm: &crate::VirtualMachine, ) -> crate::PyResult { diff --git a/vm/src/vm/context.rs b/vm/src/vm/context.rs index 049a4574e..c08d809c2 100644 --- a/vm/src/vm/context.rs +++ b/vm/src/vm/context.rs @@ -4,15 +4,15 @@ use crate::{ bytes, getset::{IntoPyGetterFunc, IntoPySetterFunc, PyGetSet}, object, pystr, - pytype::PyAttributes, + type_::PyAttributes, PyBaseException, PyDict, PyDictRef, PyEllipsis, PyFloat, PyFrozenSet, PyInt, PyIntRef, PyList, PyListRef, PyNone, PyNotImplemented, PyStr, PyTuple, PyTupleRef, PyType, PyTypeRef, }, + class::{PyClassImpl, StaticType}, exceptions, function::IntoPyNativeFunc, intern::{Internable, StringPool}, - pyclass::{PyClassImpl, StaticType}, - pyobject::{PyObjectPayload, PyObjectRef, PyPayload, PyRef, PyRefExact}, + object::{PyObjectPayload, PyObjectRef, PyPayload, PyRef, PyRefExact}, types::{PyTypeFlags, PyTypeSlots, TypeZoo}, }; use num_bigint::BigInt; diff --git a/vm/src/vm/method.rs b/vm/src/vm/method.rs new file mode 100644 index 000000000..1a0fc4415 --- /dev/null +++ b/vm/src/vm/method.rs @@ -0,0 +1,142 @@ +//! This module will be replaced once #3100 is done +//! Do not expose this type to outside of this crate + +use super::VirtualMachine; +use crate::{ + builtins::{PyBaseObject, PyStrRef}, + function::IntoFuncArgs, + object::{AsObject, PyObjectRef, PyResult}, + types::PyTypeFlags, +}; + +#[derive(Debug)] +pub enum PyMethod { + Function { + target: PyObjectRef, + func: PyObjectRef, + }, + Attribute(PyObjectRef), +} + +impl PyMethod { + pub fn get(obj: PyObjectRef, name: PyStrRef, vm: &VirtualMachine) -> PyResult { + let cls = obj.class(); + let getattro = cls.mro_find_map(|cls| cls.slots.getattro.load()).unwrap(); + if getattro as usize != PyBaseObject::getattro as usize { + drop(cls); + return obj.get_attr(name, vm).map(Self::Attribute); + } + + let mut is_method = false; + + let cls_attr = match cls.get_attr(name.as_str()) { + Some(descr) => { + let descr_cls = descr.class(); + let descr_get = if descr_cls.slots.flags.has_feature(PyTypeFlags::METHOD_DESCR) { + is_method = true; + None + } else { + let descr_get = descr_cls.mro_find_map(|cls| cls.slots.descr_get.load()); + if let Some(descr_get) = descr_get { + if descr_cls + .mro_find_map(|cls| cls.slots.descr_set.load()) + .is_some() + { + drop(descr_cls); + let cls = cls.into_owned().into(); + return descr_get(descr, Some(obj), Some(cls), vm).map(Self::Attribute); + } + } + descr_get + }; + drop(descr_cls); + Some((descr, descr_get)) + } + None => None, + }; + + if let Some(dict) = obj.dict() { + if let Some(attr) = dict.get_item_opt(name.clone(), vm)? { + return Ok(Self::Attribute(attr)); + } + } + + if let Some((attr, descr_get)) = cls_attr { + match descr_get { + None if is_method => { + drop(cls); + Ok(Self::Function { + target: obj, + func: attr, + }) + } + Some(descr_get) => { + let cls = cls.into_owned().into(); + descr_get(attr, Some(obj), Some(cls), vm).map(Self::Attribute) + } + None => Ok(Self::Attribute(attr)), + } + } else if let Some(getter) = cls.get_attr("__getattr__") { + drop(cls); + vm.invoke(&getter, (obj, name)).map(Self::Attribute) + } else { + let exc = vm.new_attribute_error(format!( + "'{}' object has no attribute '{}'", + cls.name(), + name + )); + vm.set_attribute_error_context(&exc, obj.clone(), name); + Err(exc) + } + } + + pub(crate) fn get_special( + obj: PyObjectRef, + name: &str, + vm: &VirtualMachine, + ) -> PyResult> { + let obj_cls = obj.class(); + let func = match obj_cls.get_attr(name) { + Some(f) => f, + None => { + drop(obj_cls); + return Ok(Err(obj)); + } + }; + let meth = if func + .class() + .slots + .flags + .has_feature(PyTypeFlags::METHOD_DESCR) + { + drop(obj_cls); + Self::Function { target: obj, func } + } else { + let obj_cls = obj_cls.into_owned().into(); + let attr = vm + .call_get_descriptor_specific(func, Some(obj), Some(obj_cls)) + .unwrap_or_else(Ok)?; + Self::Attribute(attr) + }; + Ok(Ok(meth)) + } + + pub fn invoke(self, args: impl IntoFuncArgs, vm: &VirtualMachine) -> PyResult { + let (func, args) = match self { + PyMethod::Function { target, func } => (func, args.into_method_args(target, vm)), + PyMethod::Attribute(func) => (func, args.into_args(vm)), + }; + vm.invoke(&func, args) + } + + #[allow(dead_code)] + pub fn invoke_ref(&self, args: impl IntoFuncArgs, vm: &VirtualMachine) -> PyResult { + let (func, args) = match self { + PyMethod::Function { target, func } => { + (func, args.into_method_args(target.clone(), vm)) + } + PyMethod::Attribute(func) => (func, args.into_args(vm)), + }; + vm.invoke(func, args) + } +} diff --git a/vm/src/vm/mod.rs b/vm/src/vm/mod.rs index 767892ac6..f9daf77a4 100644 --- a/vm/src/vm/mod.rs +++ b/vm/src/vm/mod.rs @@ -7,6 +7,7 @@ mod compile; mod context; mod interpreter; +mod method; mod setting; pub mod thread; mod vm_new; @@ -42,6 +43,7 @@ use std::{ pub use context::Context; pub use interpreter::Interpreter; +pub(crate) use method::PyMethod; pub use setting::Settings; // Objects are live when they are on stack, or referenced by a name (for now) @@ -282,6 +284,28 @@ impl VirtualMachine { self.run_frame_full(frame) } + #[cold] + pub fn run_unraisable(&self, e: PyBaseExceptionRef, msg: Option, object: PyObjectRef) { + use crate::stdlib::sys::UnraisableHookArgs; + + let sys_module = self.import("sys", None, 0).unwrap(); + let unraisablehook = sys_module.get_attr("unraisablehook", self).unwrap(); + + let exc_type = e.class().clone(); + let exc_traceback = e.traceback().to_pyobject(self); // TODO: actual traceback + let exc_value = e.into(); + let args = UnraisableHookArgs { + exc_type, + exc_value, + exc_traceback, + err_msg: self.new_pyobj(msg), + object, + }; + if let Err(e) = self.invoke(&unraisablehook, (args,)) { + println!("{}", e.as_object().repr(self).unwrap().as_str()); + } + } + #[inline(always)] pub fn run_frame_full(&self, frame: FrameRef) -> PyResult { match self.run_frame(frame)? { diff --git a/vm/src/vm/vm_object.rs b/vm/src/vm/vm_object.rs index 02849e9ed..4c98a4c08 100644 --- a/vm/src/vm/vm_object.rs +++ b/vm/src/vm/vm_object.rs @@ -1,8 +1,9 @@ +use super::PyMethod; use crate::{ builtins::{PyBaseExceptionRef, PyList, PyStr}, function::{FuncArgs, IntoFuncArgs}, + object::{AsObject, PyObject, PyObjectRef, PyPayload, PyResult}, vm::VirtualMachine, - AsObject, PyMethod, PyObject, PyObjectRef, PyPayload, PyResult, }; /// Trace events for sys.settrace and sys.setprofile. diff --git a/vm/src/vm/vm_ops.rs b/vm/src/vm/vm_ops.rs index 0a3d9738b..dc10479a2 100644 --- a/vm/src/vm/vm_ops.rs +++ b/vm/src/vm/vm_ops.rs @@ -1,10 +1,10 @@ +use super::{PyMethod, VirtualMachine}; use crate::{ builtins::{PyInt, PyIntRef}, function::PyArithmeticValue, + object::{AsObject, PyObject, PyObjectRef, PyResult}, protocol::PyIterReturn, types::PyComparisonOp, - vm::VirtualMachine, - AsObject, PyMethod, PyObject, PyObjectRef, PyResult, }; /// Collection of operators diff --git a/wasm/lib/src/browser_module.rs b/wasm/lib/src/browser_module.rs index 3b21432a3..77618236e 100644 --- a/wasm/lib/src/browser_module.rs +++ b/wasm/lib/src/browser_module.rs @@ -8,10 +8,10 @@ mod _browser { use js_sys::Promise; use rustpython_vm::{ builtins::{PyDictRef, PyStrRef}, + class::PyClassImpl, convert::ToPyObject, function::{ArgCallable, OptionalArg}, import::import_file, - pyclass::PyClassImpl, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, }; use wasm_bindgen::{prelude::*, JsCast};