mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
Add new_payload_exception helper for constructing built-in payload exceptions (#8403)
* Add new_payload_exception helper for built-in payload exceptions * Use new_payload_exception for SystemExit raise sites * Use new_payload_exception for BlockingIoError raise sites * Use new_payload_exception for OSError errno dispatch in slot_new * Run rustfmt * Run clippy * Add type guard to new_payload_exception and extract new_system_exit * Extract new_system_exit and fix stale expect messages The four SystemExit raise sites repeated the same construction, so route them through a new_system_exit helper next to new_stop_iteration. The expect messages still described invoke_exception's downcast failure, which no longer applies after moving to new_payload_exception. * Update crates/vm/src/vm/vm_new.rs --------- Co-authored-by: Jeong, YunWon <69878+youknowone@users.noreply.github.com>
This commit is contained in:
1 parent
6b747b5a76
commit
862797d1ce
7 files changed
+82
-51
No files matched your search
@@ -1389,14 +1389,8 @@ impl OSErrorBuilder {
|
||||
vec![strerror.to_pyobject(vm)]
|
||||
};
|
||||
|
||||
let payload = PyOSError::py_new(&exc_type, args.clone().into(), vm)
|
||||
.expect("new_os_error usage error");
|
||||
let os_error = payload
|
||||
.into_ref_with_type_lazy_dict(vm, exc_type)
|
||||
.expect("new_os_error usage error");
|
||||
PyOSError::slot_init(os_error.as_object().to_owned(), args.into(), vm)
|
||||
.expect("new_os_error usage error");
|
||||
os_error
|
||||
vm.new_payload_exception::<PyOSError>(exc_type, args.into())
|
||||
.expect("new_os_error usage error")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2148,7 +2142,10 @@ pub(super) mod types {
|
||||
.downcast_ref::<PyInt>()
|
||||
.and_then(|errno| errno.try_to_primitive::<i32>(vm).ok())
|
||||
.and_then(|errno| super::errno_to_exc_type(errno, vm))
|
||||
.and_then(|typ| vm.invoke_exception(typ, args_vec).ok())
|
||||
.and_then(|typ| {
|
||||
vm.new_payload_exception::<Self>(typ.to_owned(), args_vec.into())
|
||||
.ok()
|
||||
})
|
||||
{
|
||||
return error.to_pyresult(vm);
|
||||
}
|
||||
|
||||
+35
-25
@@ -20,7 +20,8 @@ cfg_select! {
|
||||
}
|
||||
|
||||
use crate::{
|
||||
AsObject, PyObject, PyObjectRef, PyResult, TryFromObject, VirtualMachine, builtins::PyModule,
|
||||
AsObject, PyObject, PyObjectRef, PyResult, TryFromObject, VirtualMachine,
|
||||
builtins::{PyModule, PyOSError},
|
||||
};
|
||||
pub use _io::{OpenArgs, io_open as open};
|
||||
use rustpython_host_env::io as host_io;
|
||||
@@ -943,14 +944,17 @@ mod _io {
|
||||
Some(n) => n,
|
||||
None => {
|
||||
// BlockingIOError(errno, msg, characters_written=0)
|
||||
return Err(vm.invoke_exception(
|
||||
vm.ctx.exceptions.blocking_io_error,
|
||||
vec![
|
||||
vm.new_pyobj(EAGAIN),
|
||||
vm.new_pyobj("write could not complete without blocking"),
|
||||
vm.new_pyobj(0),
|
||||
],
|
||||
)?);
|
||||
return Err(vm
|
||||
.new_payload_exception::<PyOSError>(
|
||||
vm.ctx.exceptions.blocking_io_error.to_owned(),
|
||||
vec![
|
||||
vm.new_pyobj(EAGAIN),
|
||||
vm.new_pyobj("write could not complete without blocking"),
|
||||
vm.new_pyobj(0),
|
||||
]
|
||||
.into(),
|
||||
)?
|
||||
.upcast());
|
||||
}
|
||||
};
|
||||
self.write_pos += n as Offset;
|
||||
@@ -1154,14 +1158,17 @@ mod _io {
|
||||
self.buffer[self.write_end as usize..][..avail].copy_from_slice(&buf[..avail]);
|
||||
self.write_end += avail as Offset;
|
||||
self.pos += avail as Offset;
|
||||
return Err(vm.invoke_exception(
|
||||
vm.ctx.exceptions.blocking_io_error,
|
||||
vec![
|
||||
vm.new_pyobj(EAGAIN),
|
||||
vm.new_pyobj("write could not complete without blocking"),
|
||||
vm.new_pyobj(avail),
|
||||
],
|
||||
)?);
|
||||
return Err(vm
|
||||
.new_payload_exception::<PyOSError>(
|
||||
vm.ctx.exceptions.blocking_io_error.to_owned(),
|
||||
vec![
|
||||
vm.new_pyobj(EAGAIN),
|
||||
vm.new_pyobj("write could not complete without blocking"),
|
||||
vm.new_pyobj(avail),
|
||||
]
|
||||
.into(),
|
||||
)?
|
||||
.upcast());
|
||||
}
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
@@ -1200,14 +1207,17 @@ mod _io {
|
||||
self.write_end = buffer_size;
|
||||
// BlockingIOError(errno, msg, characters_written)
|
||||
let chars_written = written + buffer_len;
|
||||
return Err(vm.invoke_exception(
|
||||
vm.ctx.exceptions.blocking_io_error,
|
||||
vec![
|
||||
vm.new_pyobj(EAGAIN),
|
||||
vm.new_pyobj("write could not complete without blocking"),
|
||||
vm.new_pyobj(chars_written),
|
||||
],
|
||||
)?);
|
||||
return Err(vm
|
||||
.new_payload_exception::<PyOSError>(
|
||||
vm.ctx.exceptions.blocking_io_error.to_owned(),
|
||||
vec![
|
||||
vm.new_pyobj(EAGAIN),
|
||||
vm.new_pyobj("write could not complete without blocking"),
|
||||
vm.new_pyobj(chars_written),
|
||||
]
|
||||
.into(),
|
||||
)?
|
||||
.upcast());
|
||||
}
|
||||
None => break,
|
||||
}
|
||||
|
||||
@@ -635,7 +635,7 @@ pub(crate) mod _thread {
|
||||
|
||||
#[pyfunction]
|
||||
fn exit(vm: &VirtualMachine) -> PyResult {
|
||||
Err(vm.invoke_exception(vm.ctx.exceptions.system_exit, vec![])?)
|
||||
Err(vm.new_system_exit(vec![].into()))
|
||||
}
|
||||
|
||||
thread_local!(static SENTINELS: RefCell<Vec<PyRef<Lock>>> = const { RefCell::new(Vec::new()) });
|
||||
|
||||
@@ -1041,7 +1041,7 @@ mod builtins {
|
||||
#[pyfunction]
|
||||
pub(super) fn exit(exit_code_arg: OptionalArg<PyObjectRef>, vm: &VirtualMachine) -> PyResult {
|
||||
let code = exit_code_arg.unwrap_or_else(|| vm.ctx.new_int(0).into());
|
||||
Err(vm.invoke_exception(vm.ctx.exceptions.system_exit, vec![code])?)
|
||||
Err(vm.new_system_exit(vec![code].into()))
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, FromArgs)]
|
||||
|
||||
@@ -776,8 +776,7 @@ pub mod sys {
|
||||
} else {
|
||||
vec![status]
|
||||
};
|
||||
let exc = vm.invoke_exception(vm.ctx.exceptions.system_exit, args)?;
|
||||
Err(exc)
|
||||
Err(vm.new_system_exit(args.into()))
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
|
||||
@@ -2737,7 +2737,7 @@ impl VirtualMachine {
|
||||
if self.state.finalizing.load(Ordering::Acquire) && !self.is_main_thread() {
|
||||
// once finalization starts,
|
||||
// non-main Python threads should stop running bytecode.
|
||||
return Err(self.invoke_exception(self.ctx.exceptions.system_exit, vec![])?);
|
||||
return Err(self.new_system_exit(vec![].into()));
|
||||
}
|
||||
|
||||
// Suspend this thread if stop-the-world is in progress
|
||||
|
||||
+37
-12
@@ -12,17 +12,18 @@ use rustpython_compiler::{CompileError, ParseError};
|
||||
use crate::{
|
||||
AsObject, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult,
|
||||
builtins::{
|
||||
PyBaseException, PyBaseExceptionRef, PyBytesRef, PyDictRef, PyModule, PyOSError, PyStrRef,
|
||||
PyType, PyTypeRef,
|
||||
PyBaseException, PyBaseExceptionRef, PyBytesRef, PyDictRef, PyModule, PyOSError,
|
||||
PyStopIteration, PyStrRef, PySystemExit, PyType, PyTypeRef,
|
||||
builtin_func::PyNativeFunction,
|
||||
descriptor::PyMethodDescriptor,
|
||||
tuple::{IntoPyTuple, PyTupleRef},
|
||||
},
|
||||
convert::{ToPyException, ToPyObject},
|
||||
exceptions::OSErrorBuilder,
|
||||
function::{IntoPyNativeFn, PyMethodFlags},
|
||||
function::{FuncArgs, IntoPyNativeFn, PyMethodFlags},
|
||||
scope::Scope,
|
||||
set_attrs,
|
||||
types::{Constructor, Initializer},
|
||||
vm::VirtualMachine,
|
||||
};
|
||||
|
||||
@@ -353,6 +354,26 @@ impl VirtualMachine {
|
||||
.expect("vm.new_exception() called with an invalid exception type")
|
||||
}
|
||||
|
||||
/// Construct a built-in exception type that carries a payload, directly
|
||||
/// (`py_new` + `slot_init`), without routing through `PyType::call`.
|
||||
/// Only valid for a built-in `T` whose exact type is known at compile time.
|
||||
pub fn new_payload_exception<T>(&self, cls: PyTypeRef, args: FuncArgs) -> PyResult<PyRef<T>>
|
||||
where
|
||||
T: Constructor<Args = FuncArgs> + Initializer,
|
||||
{
|
||||
debug_assert_eq!(
|
||||
cls.slots.basicsize,
|
||||
size_of::<T>(),
|
||||
"vm.new_payload_exception::<{}>() called with mismatched type '{}'",
|
||||
core::any::type_name::<T>(),
|
||||
cls.name()
|
||||
);
|
||||
let payload = T::py_new(&cls, args.clone(), self)?;
|
||||
let exc = payload.into_ref_with_type_lazy_dict(self, cls)?;
|
||||
T::slot_init(exc.as_object().to_owned(), args, self)?;
|
||||
Ok(exc)
|
||||
}
|
||||
|
||||
pub fn new_os_error(&self, msg: impl ToPyObject) -> PyRef<PyBaseException> {
|
||||
self.new_os_subtype_error(self.ctx.exceptions.os_error.to_owned(), None, msg)
|
||||
.upcast()
|
||||
@@ -905,16 +926,20 @@ impl VirtualMachine {
|
||||
exc
|
||||
}
|
||||
|
||||
pub fn new_stop_iteration(&self, value: Option<PyObjectRef>) -> PyBaseExceptionRef {
|
||||
let stop_iteration_error = self.ctx.exceptions.stop_iteration;
|
||||
let args = if let Some(value) = value {
|
||||
vec![value]
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
let exc = self.invoke_exception(stop_iteration_error, args);
|
||||
pub fn new_system_exit(&self, args: FuncArgs) -> PyBaseExceptionRef {
|
||||
self.new_payload_exception::<PySystemExit>(self.ctx.exceptions.system_exit.to_owned(), args)
|
||||
.expect("SystemExit construction from internal args is infallible")
|
||||
.upcast()
|
||||
}
|
||||
|
||||
exc.expect("StopIteration is a BaseException Subclass.")
|
||||
pub fn new_stop_iteration(&self, value: Option<PyObjectRef>) -> PyBaseExceptionRef {
|
||||
let args: FuncArgs = value.map(|v| vec![v]).unwrap_or_default().into();
|
||||
self.new_payload_exception::<PyStopIteration>(
|
||||
self.ctx.exceptions.stop_iteration.to_owned(),
|
||||
args,
|
||||
)
|
||||
.expect("StopIteration construction from internal args is infallible")
|
||||
.upcast()
|
||||
}
|
||||
|
||||
fn new_downcast_error(
|
||||
|
||||
Reference in new issue
Block a user