mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
disallow __new__, __init__ (#6446)
* disallow __new__, __init__ * migrate to Initializer * apply review
This commit is contained in:
@@ -63,6 +63,7 @@ impl FromStr for AttrName {
|
||||
|
||||
#[derive(Default)]
|
||||
struct ImplContext {
|
||||
is_trait: bool,
|
||||
attribute_items: ItemNursery,
|
||||
method_items: MethodNursery,
|
||||
getset_items: GetSetNursery,
|
||||
@@ -232,7 +233,10 @@ pub(crate) fn impl_pyclass_impl(attr: PunctuatedNestedMeta, item: Item) -> Resul
|
||||
}
|
||||
}
|
||||
Item::Trait(mut trai) => {
|
||||
let mut context = ImplContext::default();
|
||||
let mut context = ImplContext {
|
||||
is_trait: true,
|
||||
..Default::default()
|
||||
};
|
||||
let mut has_extend_slots = false;
|
||||
for item in &trai.items {
|
||||
let has = match item {
|
||||
@@ -710,21 +714,16 @@ pub(crate) fn impl_pyexception_impl(attr: PunctuatedNestedMeta, item: Item) -> R
|
||||
};
|
||||
|
||||
// Check if with(Constructor) is specified. If Constructor trait is used, don't generate slot_new
|
||||
let mut has_slot_new = false;
|
||||
|
||||
let mut extra_attrs = Vec::new();
|
||||
let mut with_items = vec![];
|
||||
for nested in &attr {
|
||||
if let NestedMeta::Meta(Meta::List(MetaList { path, nested, .. })) = nested {
|
||||
// If we already found the constructor trait, no need to keep looking for it
|
||||
if !has_slot_new && path.is_ident("with") {
|
||||
// Check if Constructor is in the list
|
||||
if path.is_ident("with") {
|
||||
for meta in nested {
|
||||
if let NestedMeta::Meta(Meta::Path(p)) = meta
|
||||
&& p.is_ident("Constructor")
|
||||
{
|
||||
has_slot_new = true;
|
||||
}
|
||||
with_items.push(meta.get_ident().expect("with() has non-ident item").clone());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
extra_attrs.push(NestedMeta::Meta(Meta::List(MetaList {
|
||||
path: path.clone(),
|
||||
@@ -734,43 +733,40 @@ pub(crate) fn impl_pyexception_impl(attr: PunctuatedNestedMeta, item: Item) -> R
|
||||
}
|
||||
}
|
||||
|
||||
let mut has_slot_init = false;
|
||||
let with_contains = |with_items: &[Ident], s: &str| {
|
||||
// Check if Constructor is in the list
|
||||
with_items.iter().any(|ident| ident == s)
|
||||
};
|
||||
|
||||
let syn::ItemImpl {
|
||||
generics,
|
||||
self_ty,
|
||||
items,
|
||||
..
|
||||
} = &imp;
|
||||
for item in items {
|
||||
// FIXME: better detection or correct wrapper implementation
|
||||
let Some(ident) = item.get_ident() else {
|
||||
continue;
|
||||
};
|
||||
let item_name = ident.to_string();
|
||||
match item_name.as_str() {
|
||||
"slot_new" => {
|
||||
has_slot_new = true;
|
||||
}
|
||||
"slot_init" => {
|
||||
has_slot_init = true;
|
||||
}
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: slot_new, slot_init must be Constructor or Initializer later
|
||||
|
||||
let slot_new = if has_slot_new {
|
||||
let slot_new = if with_contains(&with_items, "Constructor") {
|
||||
quote!()
|
||||
} else {
|
||||
with_items.push(Ident::new("Constructor", Span::call_site()));
|
||||
quote! {
|
||||
#[pyslot]
|
||||
pub fn slot_new(
|
||||
cls: ::rustpython_vm::builtins::PyTypeRef,
|
||||
args: ::rustpython_vm::function::FuncArgs,
|
||||
vm: &::rustpython_vm::VirtualMachine,
|
||||
) -> ::rustpython_vm::PyResult {
|
||||
<Self as ::rustpython_vm::class::PyClassDef>::Base::slot_new(cls, args, vm)
|
||||
impl ::rustpython_vm::types::Constructor for #self_ty {
|
||||
type Args = ::rustpython_vm::function::FuncArgs;
|
||||
|
||||
fn slot_new(
|
||||
cls: ::rustpython_vm::builtins::PyTypeRef,
|
||||
args: ::rustpython_vm::function::FuncArgs,
|
||||
vm: &::rustpython_vm::VirtualMachine,
|
||||
) -> ::rustpython_vm::PyResult {
|
||||
<Self as ::rustpython_vm::class::PyClassDef>::Base::slot_new(cls, args, vm)
|
||||
}
|
||||
fn py_new(
|
||||
_cls: &::rustpython_vm::Py<::rustpython_vm::builtins::PyType>,
|
||||
_args: Self::Args,
|
||||
_vm: &::rustpython_vm::VirtualMachine
|
||||
) -> ::rustpython_vm::PyResult<Self> {
|
||||
unreachable!("slot_new is defined")
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -779,19 +775,29 @@ pub(crate) fn impl_pyexception_impl(attr: PunctuatedNestedMeta, item: Item) -> R
|
||||
// from `BaseException` in `SimpleExtendsException` macro.
|
||||
// See: `(initproc)BaseException_init`
|
||||
// spell-checker:ignore initproc
|
||||
let slot_init = if has_slot_init {
|
||||
let slot_init = if with_contains(&with_items, "Initializer") {
|
||||
quote!()
|
||||
} else {
|
||||
// FIXME: this is a generic logic for types not only for exceptions
|
||||
with_items.push(Ident::new("Initializer", Span::call_site()));
|
||||
quote! {
|
||||
#[pyslot]
|
||||
#[pymethod(name="__init__")]
|
||||
pub fn slot_init(
|
||||
zelf: ::rustpython_vm::PyObjectRef,
|
||||
args: ::rustpython_vm::function::FuncArgs,
|
||||
vm: &::rustpython_vm::VirtualMachine,
|
||||
) -> ::rustpython_vm::PyResult<()> {
|
||||
<Self as ::rustpython_vm::class::PyClassDef>::Base::slot_init(zelf, args, vm)
|
||||
impl ::rustpython_vm::types::Initializer for #self_ty {
|
||||
type Args = ::rustpython_vm::function::FuncArgs;
|
||||
|
||||
fn slot_init(
|
||||
zelf: ::rustpython_vm::PyObjectRef,
|
||||
args: ::rustpython_vm::function::FuncArgs,
|
||||
vm: &::rustpython_vm::VirtualMachine,
|
||||
) -> ::rustpython_vm::PyResult<()> {
|
||||
<Self as ::rustpython_vm::class::PyClassDef>::Base::slot_init(zelf, args, vm)
|
||||
}
|
||||
|
||||
fn init(
|
||||
_zelf: ::rustpython_vm::PyRef<Self>,
|
||||
_args: Self::Args,
|
||||
_vm: &::rustpython_vm::VirtualMachine
|
||||
) -> ::rustpython_vm::PyResult<()> {
|
||||
unreachable!("slot_init is defined")
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -803,13 +809,13 @@ pub(crate) fn impl_pyexception_impl(attr: PunctuatedNestedMeta, item: Item) -> R
|
||||
};
|
||||
|
||||
Ok(quote! {
|
||||
#[pyclass(flags(BASETYPE, HAS_DICT) #extra_attrs_tokens)]
|
||||
#[pyclass(flags(BASETYPE, HAS_DICT), with(#(#with_items),*) #extra_attrs_tokens)]
|
||||
impl #generics #self_ty {
|
||||
#(#items)*
|
||||
|
||||
#slot_new
|
||||
#slot_init
|
||||
}
|
||||
|
||||
#slot_new
|
||||
#slot_init
|
||||
})
|
||||
}
|
||||
|
||||
@@ -892,6 +898,23 @@ where
|
||||
let item_meta = MethodItemMeta::from_attr(ident.clone(), &item_attr)?;
|
||||
|
||||
let py_name = item_meta.method_name()?;
|
||||
|
||||
// Disallow __new__ and __init__ as pymethod in impl blocks (not in traits)
|
||||
if !args.context.is_trait {
|
||||
if py_name == "__new__" {
|
||||
return Err(syn::Error::new(
|
||||
ident.span(),
|
||||
"#[pymethod] cannot define '__new__'. Use #[pyclass(with(Constructor))] instead.",
|
||||
));
|
||||
}
|
||||
if py_name == "__init__" {
|
||||
return Err(syn::Error::new(
|
||||
ident.span(),
|
||||
"#[pymethod] cannot define '__init__'. Use #[pyclass(with(Initializer))] instead.",
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
let raw = item_meta.raw()?;
|
||||
let sig_doc = text_signature(func.sig(), &py_name);
|
||||
|
||||
|
||||
@@ -1540,7 +1540,7 @@ mod _sqlite {
|
||||
size: Option<c_int>,
|
||||
}
|
||||
|
||||
#[pyclass(with(Constructor, IterNext, Iterable), flags(BASETYPE))]
|
||||
#[pyclass(with(Constructor, Initializer, IterNext, Iterable), flags(BASETYPE))]
|
||||
impl Cursor {
|
||||
fn new(
|
||||
connection: PyRef<Connection>,
|
||||
@@ -1571,24 +1571,6 @@ mod _sqlite {
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __init__(&self, _connection: PyRef<Connection>, _vm: &VirtualMachine) -> PyResult<()> {
|
||||
let mut guard = self.inner.lock();
|
||||
if guard.is_some() {
|
||||
// Already initialized (e.g., from a call to super().__init__)
|
||||
return Ok(());
|
||||
}
|
||||
*guard = Some(CursorInner {
|
||||
description: None,
|
||||
row_cast_map: vec![],
|
||||
lastrowid: -1,
|
||||
rowcount: -1,
|
||||
statement: None,
|
||||
closed: false,
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_cursor_state(inner: Option<&CursorInner>, vm: &VirtualMachine) -> PyResult<()> {
|
||||
match inner {
|
||||
Some(inner) if inner.closed => Err(new_programming_error(
|
||||
@@ -1949,6 +1931,27 @@ mod _sqlite {
|
||||
}
|
||||
}
|
||||
|
||||
impl Initializer for Cursor {
|
||||
type Args = PyRef<Connection>;
|
||||
|
||||
fn init(zelf: PyRef<Self>, _connection: Self::Args, _vm: &VirtualMachine) -> PyResult<()> {
|
||||
let mut guard = zelf.inner.lock();
|
||||
if guard.is_some() {
|
||||
// Already initialized (e.g., from a call to super().__init__)
|
||||
return Ok(());
|
||||
}
|
||||
*guard = Some(CursorInner {
|
||||
description: None,
|
||||
row_cast_map: vec![],
|
||||
lastrowid: -1,
|
||||
rowcount: -1,
|
||||
statement: None,
|
||||
closed: false,
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl SelfIter for Cursor {}
|
||||
impl IterNext for Cursor {
|
||||
fn next(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
|
||||
|
||||
@@ -7,7 +7,7 @@ pub(crate) mod ssl_error {
|
||||
use crate::vm::{
|
||||
PyPayload, PyRef, PyResult, VirtualMachine,
|
||||
builtins::{PyBaseExceptionRef, PyOSError, PyStrRef},
|
||||
types::Constructor,
|
||||
types::{Constructor, Initializer},
|
||||
};
|
||||
|
||||
// Error type constants - exposed as pyattr and available for internal use
|
||||
|
||||
@@ -2,11 +2,11 @@ use super::{PyDictRef, PyList, PyStr, PyStrRef, PyType, PyTypeRef};
|
||||
use crate::common::hash::PyHash;
|
||||
use crate::types::PyTypeFlags;
|
||||
use crate::{
|
||||
AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyResult, VirtualMachine,
|
||||
AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
|
||||
class::PyClassImpl,
|
||||
convert::ToPyResult,
|
||||
function::{Either, FuncArgs, PyArithmeticValue, PyComparisonValue, PySetterValue},
|
||||
types::{Constructor, PyComparisonOp},
|
||||
types::{Constructor, Initializer, PyComparisonOp},
|
||||
};
|
||||
use itertools::Itertools;
|
||||
|
||||
@@ -115,6 +115,18 @@ impl Constructor for PyBaseObject {
|
||||
}
|
||||
}
|
||||
|
||||
impl Initializer for PyBaseObject {
|
||||
type Args = FuncArgs;
|
||||
|
||||
fn slot_init(_zelf: PyObjectRef, _args: FuncArgs, _vm: &VirtualMachine) -> PyResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn init(_zelf: PyRef<Self>, _args: Self::Args, _vm: &VirtualMachine) -> PyResult<()> {
|
||||
unreachable!("slot_init is defined")
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: implement _PyType_GetSlotNames properly
|
||||
fn type_slot_names(typ: &Py<PyType>, vm: &VirtualMachine) -> PyResult<Option<super::PyListRef>> {
|
||||
// let attributes = typ.attributes.read();
|
||||
@@ -235,7 +247,7 @@ fn object_getstate_default(obj: &PyObject, required: bool, vm: &VirtualMachine)
|
||||
// getstate.call((), vm)
|
||||
// }
|
||||
|
||||
#[pyclass(with(Constructor), flags(BASETYPE))]
|
||||
#[pyclass(with(Constructor, Initializer), flags(BASETYPE))]
|
||||
impl PyBaseObject {
|
||||
#[pymethod(raw)]
|
||||
fn __getstate__(vm: &VirtualMachine, args: FuncArgs) -> PyResult {
|
||||
@@ -444,19 +456,17 @@ impl PyBaseObject {
|
||||
obj.str(vm)
|
||||
}
|
||||
|
||||
#[pyslot]
|
||||
#[pymethod]
|
||||
fn __init__(_zelf: PyObjectRef, _args: FuncArgs, _vm: &VirtualMachine) -> PyResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[pygetset]
|
||||
fn __class__(obj: PyObjectRef) -> PyTypeRef {
|
||||
obj.class().to_owned()
|
||||
}
|
||||
|
||||
#[pygetset(name = "__class__", setter)]
|
||||
fn set_class(instance: PyObjectRef, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
#[pygetset(setter)]
|
||||
fn set___class__(
|
||||
instance: PyObjectRef,
|
||||
value: PyObjectRef,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<()> {
|
||||
match value.downcast::<PyType>() {
|
||||
Ok(cls) => {
|
||||
let both_module = instance.class().fast_issubclass(vm.ctx.types.module_type)
|
||||
|
||||
@@ -43,13 +43,14 @@ pub(super) mod types {
|
||||
use super::*;
|
||||
use crate::PyPayload;
|
||||
use crate::builtins::PyGenericAlias;
|
||||
use crate::types::{Constructor, Initializer};
|
||||
|
||||
#[pyexception(name, base = PyBaseException, ctx = "base_exception_group")]
|
||||
#[derive(Debug)]
|
||||
#[repr(transparent)]
|
||||
pub struct PyBaseExceptionGroup(PyBaseException);
|
||||
|
||||
#[pyexception]
|
||||
#[pyexception(with(Constructor, Initializer))]
|
||||
impl PyBaseExceptionGroup {
|
||||
#[pyclassmethod]
|
||||
fn __class_getitem__(
|
||||
@@ -60,117 +61,6 @@ pub(super) mod types {
|
||||
PyGenericAlias::from_args(cls, args, vm)
|
||||
}
|
||||
|
||||
#[pyslot]
|
||||
fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
|
||||
// Validate exactly 2 positional arguments
|
||||
if args.args.len() != 2 {
|
||||
return Err(vm.new_type_error(format!(
|
||||
"BaseExceptionGroup.__new__() takes exactly 2 positional arguments ({} given)",
|
||||
args.args.len()
|
||||
)));
|
||||
}
|
||||
|
||||
// Validate message is str
|
||||
let message = args.args[0].clone();
|
||||
if !message.fast_isinstance(vm.ctx.types.str_type) {
|
||||
return Err(vm.new_type_error(format!(
|
||||
"argument 1 must be str, not {}",
|
||||
message.class().name()
|
||||
)));
|
||||
}
|
||||
|
||||
// Validate exceptions is a sequence (not set or None)
|
||||
let exceptions_arg = &args.args[1];
|
||||
|
||||
// Check for set/frozenset (not a sequence - unordered)
|
||||
if exceptions_arg.fast_isinstance(vm.ctx.types.set_type)
|
||||
|| exceptions_arg.fast_isinstance(vm.ctx.types.frozenset_type)
|
||||
{
|
||||
return Err(vm.new_type_error("second argument (exceptions) must be a sequence"));
|
||||
}
|
||||
|
||||
// Check for None
|
||||
if exceptions_arg.is(&vm.ctx.none) {
|
||||
return Err(vm.new_type_error("second argument (exceptions) must be a sequence"));
|
||||
}
|
||||
|
||||
let exceptions: Vec<PyObjectRef> = exceptions_arg.try_to_value(vm).map_err(|_| {
|
||||
vm.new_type_error("second argument (exceptions) must be a sequence")
|
||||
})?;
|
||||
|
||||
// Validate non-empty
|
||||
if exceptions.is_empty() {
|
||||
return Err(vm.new_value_error(
|
||||
"second argument (exceptions) must be a non-empty sequence".to_owned(),
|
||||
));
|
||||
}
|
||||
|
||||
// Validate all items are BaseException instances
|
||||
let mut has_non_exception = false;
|
||||
for (i, exc) in exceptions.iter().enumerate() {
|
||||
if !exc.fast_isinstance(vm.ctx.exceptions.base_exception_type) {
|
||||
return Err(vm.new_value_error(format!(
|
||||
"Item {} of second argument (exceptions) is not an exception",
|
||||
i
|
||||
)));
|
||||
}
|
||||
// Check if any exception is not an Exception subclass
|
||||
// With dynamic ExceptionGroup (inherits from both BaseExceptionGroup and Exception),
|
||||
// ExceptionGroup instances are automatically instances of Exception
|
||||
if !exc.fast_isinstance(vm.ctx.exceptions.exception_type) {
|
||||
has_non_exception = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the dynamic ExceptionGroup type
|
||||
let exception_group_type = crate::exception_group::exception_group();
|
||||
|
||||
// Determine the actual class to use
|
||||
let actual_cls = if cls.is(exception_group_type) {
|
||||
// ExceptionGroup cannot contain BaseExceptions that are not Exception
|
||||
if has_non_exception {
|
||||
return Err(
|
||||
vm.new_type_error("Cannot nest BaseExceptions in an ExceptionGroup")
|
||||
);
|
||||
}
|
||||
cls
|
||||
} else if cls.is(vm.ctx.exceptions.base_exception_group) {
|
||||
// Auto-convert to ExceptionGroup if all are Exception subclasses
|
||||
if !has_non_exception {
|
||||
exception_group_type.to_owned()
|
||||
} else {
|
||||
cls
|
||||
}
|
||||
} else {
|
||||
// User-defined subclass
|
||||
if has_non_exception && cls.fast_issubclass(vm.ctx.exceptions.exception_type) {
|
||||
return Err(vm.new_type_error(format!(
|
||||
"Cannot nest BaseExceptions in '{}'",
|
||||
cls.name()
|
||||
)));
|
||||
}
|
||||
cls
|
||||
};
|
||||
|
||||
// Create the exception with (message, exceptions_tuple) as args
|
||||
let exceptions_tuple = vm.ctx.new_tuple(exceptions);
|
||||
let init_args = vec![message, exceptions_tuple.into()];
|
||||
PyBaseException::new(init_args, vm)
|
||||
.into_ref_with_type(vm, actual_cls)
|
||||
.map(Into::into)
|
||||
}
|
||||
|
||||
#[pyslot]
|
||||
#[pymethod(name = "__init__")]
|
||||
fn slot_init(_zelf: PyObjectRef, _args: FuncArgs, _vm: &VirtualMachine) -> PyResult<()> {
|
||||
// CPython's BaseExceptionGroup.__init__ just calls BaseException.__init__
|
||||
// which stores args as-is. Since __new__ already set up the correct args
|
||||
// (message, exceptions_tuple), we don't need to do anything here.
|
||||
// This also allows subclasses to pass extra arguments to __new__ without
|
||||
// __init__ complaining about argument count.
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn derive(
|
||||
zelf: PyRef<PyBaseException>,
|
||||
@@ -351,6 +241,136 @@ pub(super) mod types {
|
||||
}
|
||||
}
|
||||
|
||||
impl Constructor for PyBaseExceptionGroup {
|
||||
type Args = crate::function::PosArgs;
|
||||
|
||||
fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
|
||||
let args: Self::Args = args.bind(vm)?;
|
||||
let args = args.into_vec();
|
||||
// Validate exactly 2 positional arguments
|
||||
if args.len() != 2 {
|
||||
return Err(vm.new_type_error(format!(
|
||||
"BaseExceptionGroup.__new__() takes exactly 2 positional arguments ({} given)",
|
||||
args.len()
|
||||
)));
|
||||
}
|
||||
|
||||
// Validate message is str
|
||||
let message = args[0].clone();
|
||||
if !message.fast_isinstance(vm.ctx.types.str_type) {
|
||||
return Err(vm.new_type_error(format!(
|
||||
"argument 1 must be str, not {}",
|
||||
message.class().name()
|
||||
)));
|
||||
}
|
||||
|
||||
// Validate exceptions is a sequence (not set or None)
|
||||
let exceptions_arg = &args[1];
|
||||
|
||||
// Check for set/frozenset (not a sequence - unordered)
|
||||
if exceptions_arg.fast_isinstance(vm.ctx.types.set_type)
|
||||
|| exceptions_arg.fast_isinstance(vm.ctx.types.frozenset_type)
|
||||
{
|
||||
return Err(vm.new_type_error("second argument (exceptions) must be a sequence"));
|
||||
}
|
||||
|
||||
// Check for None
|
||||
if exceptions_arg.is(&vm.ctx.none) {
|
||||
return Err(vm.new_type_error("second argument (exceptions) must be a sequence"));
|
||||
}
|
||||
|
||||
let exceptions: Vec<PyObjectRef> = exceptions_arg.try_to_value(vm).map_err(|_| {
|
||||
vm.new_type_error("second argument (exceptions) must be a sequence")
|
||||
})?;
|
||||
|
||||
// Validate non-empty
|
||||
if exceptions.is_empty() {
|
||||
return Err(vm.new_value_error(
|
||||
"second argument (exceptions) must be a non-empty sequence".to_owned(),
|
||||
));
|
||||
}
|
||||
|
||||
// Validate all items are BaseException instances
|
||||
let mut has_non_exception = false;
|
||||
for (i, exc) in exceptions.iter().enumerate() {
|
||||
if !exc.fast_isinstance(vm.ctx.exceptions.base_exception_type) {
|
||||
return Err(vm.new_value_error(format!(
|
||||
"Item {} of second argument (exceptions) is not an exception",
|
||||
i
|
||||
)));
|
||||
}
|
||||
// Check if any exception is not an Exception subclass
|
||||
// With dynamic ExceptionGroup (inherits from both BaseExceptionGroup and Exception),
|
||||
// ExceptionGroup instances are automatically instances of Exception
|
||||
if !exc.fast_isinstance(vm.ctx.exceptions.exception_type) {
|
||||
has_non_exception = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the dynamic ExceptionGroup type
|
||||
let exception_group_type = crate::exception_group::exception_group();
|
||||
|
||||
// Determine the actual class to use
|
||||
let actual_cls = if cls.is(exception_group_type) {
|
||||
// ExceptionGroup cannot contain BaseExceptions that are not Exception
|
||||
if has_non_exception {
|
||||
return Err(
|
||||
vm.new_type_error("Cannot nest BaseExceptions in an ExceptionGroup")
|
||||
);
|
||||
}
|
||||
cls
|
||||
} else if cls.is(vm.ctx.exceptions.base_exception_group) {
|
||||
// Auto-convert to ExceptionGroup if all are Exception subclasses
|
||||
if !has_non_exception {
|
||||
exception_group_type.to_owned()
|
||||
} else {
|
||||
cls
|
||||
}
|
||||
} else {
|
||||
// User-defined subclass
|
||||
if has_non_exception && cls.fast_issubclass(vm.ctx.exceptions.exception_type) {
|
||||
return Err(vm.new_type_error(format!(
|
||||
"Cannot nest BaseExceptions in '{}'",
|
||||
cls.name()
|
||||
)));
|
||||
}
|
||||
cls
|
||||
};
|
||||
|
||||
// Create the exception with (message, exceptions_tuple) as args
|
||||
let exceptions_tuple = vm.ctx.new_tuple(exceptions);
|
||||
let init_args = vec![message, exceptions_tuple.into()];
|
||||
PyBaseException::new(init_args, vm)
|
||||
.into_ref_with_type(vm, actual_cls)
|
||||
.map(Into::into)
|
||||
}
|
||||
|
||||
fn py_new(_cls: &Py<PyType>, _args: Self::Args, _vm: &VirtualMachine) -> PyResult<Self> {
|
||||
unimplemented!("use slot_new")
|
||||
}
|
||||
}
|
||||
|
||||
impl Initializer for PyBaseExceptionGroup {
|
||||
type Args = FuncArgs;
|
||||
|
||||
fn slot_init(
|
||||
_zelf: PyObjectRef,
|
||||
_args: ::rustpython_vm::function::FuncArgs,
|
||||
_vm: &::rustpython_vm::VirtualMachine,
|
||||
) -> ::rustpython_vm::PyResult<()> {
|
||||
// CPython's BaseExceptionGroup.__init__ just calls BaseException.__init__
|
||||
// which stores args as-is. Since __new__ already set up the correct args
|
||||
// (message, exceptions_tuple), we don't need to do anything here.
|
||||
// This also allows subclasses to pass extra arguments to __new__ without
|
||||
// __init__ complaining about argument count.
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn init(_zelf: PyRef<Self>, _args: Self::Args, _vm: &VirtualMachine) -> PyResult<()> {
|
||||
unreachable!("slot_init is defined")
|
||||
}
|
||||
}
|
||||
|
||||
// Helper functions for ExceptionGroup
|
||||
fn is_base_exception_group(obj: &PyObject, vm: &VirtualMachine) -> bool {
|
||||
obj.fast_isinstance(vm.ctx.exceptions.base_exception_group)
|
||||
|
||||
@@ -1371,18 +1371,19 @@ pub(super) mod types {
|
||||
#[repr(transparent)]
|
||||
pub struct PyStopIteration(PyException);
|
||||
|
||||
#[pyexception]
|
||||
impl PyStopIteration {
|
||||
#[pyslot]
|
||||
#[pymethod(name = "__init__")]
|
||||
pub(crate) fn slot_init(
|
||||
zelf: PyObjectRef,
|
||||
args: ::rustpython_vm::function::FuncArgs,
|
||||
vm: &::rustpython_vm::VirtualMachine,
|
||||
) -> ::rustpython_vm::PyResult<()> {
|
||||
#[pyexception(with(Initializer))]
|
||||
impl PyStopIteration {}
|
||||
|
||||
impl Initializer for PyStopIteration {
|
||||
type Args = FuncArgs;
|
||||
fn slot_init(zelf: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
|
||||
zelf.set_attr("value", vm.unwrap_or_none(args.args.first().cloned()), vm)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn init(_zelf: PyRef<Self>, _args: Self::Args, _vm: &VirtualMachine) -> PyResult<()> {
|
||||
unreachable!("slot_init is defined")
|
||||
}
|
||||
}
|
||||
|
||||
#[pyexception(name, base = PyException, ctx = "stop_async_iteration", impl)]
|
||||
@@ -1419,15 +1420,13 @@ pub(super) mod types {
|
||||
#[repr(transparent)]
|
||||
pub struct PyAttributeError(PyException);
|
||||
|
||||
#[pyexception]
|
||||
impl PyAttributeError {
|
||||
#[pyslot]
|
||||
#[pymethod(name = "__init__")]
|
||||
pub(crate) fn slot_init(
|
||||
zelf: PyObjectRef,
|
||||
args: ::rustpython_vm::function::FuncArgs,
|
||||
vm: &::rustpython_vm::VirtualMachine,
|
||||
) -> ::rustpython_vm::PyResult<()> {
|
||||
#[pyexception(with(Initializer))]
|
||||
impl PyAttributeError {}
|
||||
|
||||
impl Initializer for PyAttributeError {
|
||||
type Args = FuncArgs;
|
||||
|
||||
fn slot_init(zelf: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
|
||||
zelf.set_attr(
|
||||
"name",
|
||||
vm.unwrap_or_none(args.kwargs.get("name").cloned()),
|
||||
@@ -1440,6 +1439,10 @@ pub(super) mod types {
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn init(_zelf: PyRef<Self>, _args: Self::Args, _vm: &VirtualMachine) -> PyResult<()> {
|
||||
unreachable!("slot_init is defined")
|
||||
}
|
||||
}
|
||||
|
||||
#[pyexception(name, base = PyException, ctx = "buffer_error", impl)]
|
||||
@@ -1457,15 +1460,28 @@ pub(super) mod types {
|
||||
#[repr(transparent)]
|
||||
pub struct PyImportError(PyException);
|
||||
|
||||
#[pyexception]
|
||||
#[pyexception(with(Initializer))]
|
||||
impl PyImportError {
|
||||
#[pyslot]
|
||||
#[pymethod(name = "__init__")]
|
||||
pub(crate) fn slot_init(
|
||||
zelf: PyObjectRef,
|
||||
args: ::rustpython_vm::function::FuncArgs,
|
||||
vm: &::rustpython_vm::VirtualMachine,
|
||||
) -> ::rustpython_vm::PyResult<()> {
|
||||
#[pymethod]
|
||||
fn __reduce__(exc: PyBaseExceptionRef, vm: &VirtualMachine) -> PyTupleRef {
|
||||
let obj = exc.as_object().to_owned();
|
||||
let mut result: Vec<PyObjectRef> = vec![
|
||||
obj.class().to_owned().into(),
|
||||
vm.new_tuple((exc.get_arg(0).unwrap(),)).into(),
|
||||
];
|
||||
|
||||
if let Some(dict) = obj.dict().filter(|x| !x.is_empty()) {
|
||||
result.push(dict.into());
|
||||
}
|
||||
|
||||
result.into_pytuple(vm)
|
||||
}
|
||||
}
|
||||
|
||||
impl Initializer for PyImportError {
|
||||
type Args = FuncArgs;
|
||||
|
||||
fn slot_init(zelf: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
|
||||
let mut kwargs = args.kwargs.clone();
|
||||
let name = kwargs.swap_remove("name");
|
||||
let path = kwargs.swap_remove("path");
|
||||
@@ -1482,19 +1498,9 @@ pub(super) mod types {
|
||||
dict.set_item("path", vm.unwrap_or_none(path), vm)?;
|
||||
PyBaseException::slot_init(zelf, args, vm)
|
||||
}
|
||||
#[pymethod]
|
||||
fn __reduce__(exc: PyBaseExceptionRef, vm: &VirtualMachine) -> PyTupleRef {
|
||||
let obj = exc.as_object().to_owned();
|
||||
let mut result: Vec<PyObjectRef> = vec![
|
||||
obj.class().to_owned().into(),
|
||||
vm.new_tuple((exc.get_arg(0).unwrap(),)).into(),
|
||||
];
|
||||
|
||||
if let Some(dict) = obj.dict().filter(|x| !x.is_empty()) {
|
||||
result.push(dict.into());
|
||||
}
|
||||
|
||||
result.into_pytuple(vm)
|
||||
fn init(_zelf: PyRef<Self>, _args: Self::Args, _vm: &VirtualMachine) -> PyResult<()> {
|
||||
unreachable!("slot_init is defined")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1660,11 +1666,10 @@ pub(super) mod types {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyexception(with(Constructor))]
|
||||
impl PyOSError {
|
||||
#[pyslot]
|
||||
#[pymethod(name = "__init__")]
|
||||
pub fn slot_init(zelf: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
|
||||
impl Initializer for PyOSError {
|
||||
type Args = FuncArgs;
|
||||
|
||||
fn slot_init(zelf: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
|
||||
let len = args.args.len();
|
||||
let mut new_args = args;
|
||||
|
||||
@@ -1718,6 +1723,13 @@ pub(super) mod types {
|
||||
PyBaseException::slot_init(zelf, new_args, vm)
|
||||
}
|
||||
|
||||
fn init(_zelf: PyRef<Self>, _args: Self::Args, _vm: &VirtualMachine) -> PyResult<()> {
|
||||
unreachable!("slot_init is defined")
|
||||
}
|
||||
}
|
||||
|
||||
#[pyexception(with(Constructor, Initializer))]
|
||||
impl PyOSError {
|
||||
#[pymethod]
|
||||
fn __str__(exc: PyBaseExceptionRef, vm: &VirtualMachine) -> PyResult<PyStrRef> {
|
||||
let obj = exc.as_object().to_owned();
|
||||
@@ -2011,44 +2023,8 @@ pub(super) mod types {
|
||||
#[repr(transparent)]
|
||||
pub struct PySyntaxError(PyException);
|
||||
|
||||
#[pyexception]
|
||||
#[pyexception(with(Initializer))]
|
||||
impl PySyntaxError {
|
||||
#[pyslot]
|
||||
#[pymethod(name = "__init__")]
|
||||
fn slot_init(zelf: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
|
||||
let len = args.args.len();
|
||||
let new_args = args;
|
||||
|
||||
zelf.set_attr("print_file_and_line", vm.ctx.none(), vm)?;
|
||||
|
||||
if len == 2
|
||||
&& let Ok(location_tuple) = new_args.args[1]
|
||||
.clone()
|
||||
.downcast::<crate::builtins::PyTuple>()
|
||||
{
|
||||
let location_tup_len = location_tuple.len();
|
||||
for (i, &attr) in [
|
||||
"filename",
|
||||
"lineno",
|
||||
"offset",
|
||||
"text",
|
||||
"end_lineno",
|
||||
"end_offset",
|
||||
]
|
||||
.iter()
|
||||
.enumerate()
|
||||
{
|
||||
if location_tup_len > i {
|
||||
zelf.set_attr(attr, location_tuple[i].to_owned(), vm)?;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PyBaseException::slot_init(zelf, new_args, vm)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __str__(exc: PyBaseExceptionRef, vm: &VirtualMachine) -> PyStrRef {
|
||||
fn basename(filename: &str) -> &str {
|
||||
@@ -2097,6 +2073,48 @@ pub(super) mod types {
|
||||
}
|
||||
}
|
||||
|
||||
impl Initializer for PySyntaxError {
|
||||
type Args = FuncArgs;
|
||||
|
||||
fn slot_init(zelf: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
|
||||
let len = args.args.len();
|
||||
let new_args = args;
|
||||
|
||||
zelf.set_attr("print_file_and_line", vm.ctx.none(), vm)?;
|
||||
|
||||
if len == 2
|
||||
&& let Ok(location_tuple) = new_args.args[1]
|
||||
.clone()
|
||||
.downcast::<crate::builtins::PyTuple>()
|
||||
{
|
||||
let location_tup_len = location_tuple.len();
|
||||
for (i, &attr) in [
|
||||
"filename",
|
||||
"lineno",
|
||||
"offset",
|
||||
"text",
|
||||
"end_lineno",
|
||||
"end_offset",
|
||||
]
|
||||
.iter()
|
||||
.enumerate()
|
||||
{
|
||||
if location_tup_len > i {
|
||||
zelf.set_attr(attr, location_tuple[i].to_owned(), vm)?;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PyBaseException::slot_init(zelf, new_args, vm)
|
||||
}
|
||||
|
||||
fn init(_zelf: PyRef<Self>, _args: Self::Args, _vm: &VirtualMachine) -> PyResult<()> {
|
||||
unreachable!("slot_init is defined")
|
||||
}
|
||||
}
|
||||
|
||||
#[pyexception(
|
||||
name = "_IncompleteInputError",
|
||||
base = PySyntaxError,
|
||||
@@ -2106,17 +2124,19 @@ pub(super) mod types {
|
||||
#[repr(transparent)]
|
||||
pub struct PyIncompleteInputError(PySyntaxError);
|
||||
|
||||
#[pyexception]
|
||||
impl PyIncompleteInputError {
|
||||
#[pyslot]
|
||||
#[pymethod(name = "__init__")]
|
||||
pub(crate) fn slot_init(
|
||||
zelf: PyObjectRef,
|
||||
_args: FuncArgs,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<()> {
|
||||
#[pyexception(with(Initializer))]
|
||||
impl PyIncompleteInputError {}
|
||||
|
||||
impl Initializer for PyIncompleteInputError {
|
||||
type Args = FuncArgs;
|
||||
|
||||
fn slot_init(zelf: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
|
||||
zelf.set_attr("name", vm.ctx.new_str("SyntaxError"), vm)?;
|
||||
Ok(())
|
||||
PySyntaxError::slot_init(zelf, args, vm)
|
||||
}
|
||||
|
||||
fn init(_zelf: PyRef<Self>, _args: Self::Args, _vm: &VirtualMachine) -> PyResult<()> {
|
||||
unreachable!("slot_init is defined")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2155,26 +2175,8 @@ pub(super) mod types {
|
||||
#[repr(transparent)]
|
||||
pub struct PyUnicodeDecodeError(PyUnicodeError);
|
||||
|
||||
#[pyexception]
|
||||
#[pyexception(with(Initializer))]
|
||||
impl PyUnicodeDecodeError {
|
||||
#[pyslot]
|
||||
#[pymethod(name = "__init__")]
|
||||
pub(crate) fn slot_init(
|
||||
zelf: PyObjectRef,
|
||||
args: FuncArgs,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<()> {
|
||||
type Args = (PyStrRef, ArgBytesLike, isize, isize, PyStrRef);
|
||||
let (encoding, object, start, end, reason): Args = args.bind(vm)?;
|
||||
zelf.set_attr("encoding", encoding, vm)?;
|
||||
let object_as_bytes = vm.ctx.new_bytes(object.borrow_buf().to_vec());
|
||||
zelf.set_attr("object", object_as_bytes, vm)?;
|
||||
zelf.set_attr("start", vm.ctx.new_int(start), vm)?;
|
||||
zelf.set_attr("end", vm.ctx.new_int(end), vm)?;
|
||||
zelf.set_attr("reason", reason, vm)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __str__(exc: PyBaseExceptionRef, vm: &VirtualMachine) -> PyResult<String> {
|
||||
let Ok(object) = exc.as_object().get_attr("object", vm) else {
|
||||
@@ -2202,30 +2204,33 @@ pub(super) mod types {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyexception(name, base = PyUnicodeError, ctx = "unicode_encode_error")]
|
||||
#[derive(Debug)]
|
||||
#[repr(transparent)]
|
||||
pub struct PyUnicodeEncodeError(PyUnicodeError);
|
||||
impl Initializer for PyUnicodeDecodeError {
|
||||
type Args = FuncArgs;
|
||||
|
||||
#[pyexception]
|
||||
impl PyUnicodeEncodeError {
|
||||
#[pyslot]
|
||||
#[pymethod(name = "__init__")]
|
||||
pub(crate) fn slot_init(
|
||||
zelf: PyObjectRef,
|
||||
args: FuncArgs,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<()> {
|
||||
type Args = (PyStrRef, PyStrRef, isize, isize, PyStrRef);
|
||||
fn slot_init(zelf: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
|
||||
type Args = (PyStrRef, ArgBytesLike, isize, isize, PyStrRef);
|
||||
let (encoding, object, start, end, reason): Args = args.bind(vm)?;
|
||||
zelf.set_attr("encoding", encoding, vm)?;
|
||||
zelf.set_attr("object", object, vm)?;
|
||||
let object_as_bytes = vm.ctx.new_bytes(object.borrow_buf().to_vec());
|
||||
zelf.set_attr("object", object_as_bytes, vm)?;
|
||||
zelf.set_attr("start", vm.ctx.new_int(start), vm)?;
|
||||
zelf.set_attr("end", vm.ctx.new_int(end), vm)?;
|
||||
zelf.set_attr("reason", reason, vm)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn init(_zelf: PyRef<Self>, _args: Self::Args, _vm: &VirtualMachine) -> PyResult<()> {
|
||||
unreachable!("slot_init is defined")
|
||||
}
|
||||
}
|
||||
|
||||
#[pyexception(name, base = PyUnicodeError, ctx = "unicode_encode_error")]
|
||||
#[derive(Debug)]
|
||||
#[repr(transparent)]
|
||||
pub struct PyUnicodeEncodeError(PyUnicodeError);
|
||||
|
||||
#[pyexception(with(Initializer))]
|
||||
impl PyUnicodeEncodeError {
|
||||
#[pymethod]
|
||||
fn __str__(exc: PyBaseExceptionRef, vm: &VirtualMachine) -> PyResult<String> {
|
||||
let Ok(object) = exc.as_object().get_attr("object", vm) else {
|
||||
@@ -2254,22 +2259,13 @@ pub(super) mod types {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyexception(name, base = PyUnicodeError, ctx = "unicode_translate_error")]
|
||||
#[derive(Debug)]
|
||||
#[repr(transparent)]
|
||||
pub struct PyUnicodeTranslateError(PyUnicodeError);
|
||||
impl Initializer for PyUnicodeEncodeError {
|
||||
type Args = FuncArgs;
|
||||
|
||||
#[pyexception]
|
||||
impl PyUnicodeTranslateError {
|
||||
#[pyslot]
|
||||
#[pymethod(name = "__init__")]
|
||||
pub(crate) fn slot_init(
|
||||
zelf: PyObjectRef,
|
||||
args: FuncArgs,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<()> {
|
||||
type Args = (PyStrRef, isize, isize, PyStrRef);
|
||||
let (object, start, end, reason): Args = args.bind(vm)?;
|
||||
fn slot_init(zelf: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
|
||||
type Args = (PyStrRef, PyStrRef, isize, isize, PyStrRef);
|
||||
let (encoding, object, start, end, reason): Args = args.bind(vm)?;
|
||||
zelf.set_attr("encoding", encoding, vm)?;
|
||||
zelf.set_attr("object", object, vm)?;
|
||||
zelf.set_attr("start", vm.ctx.new_int(start), vm)?;
|
||||
zelf.set_attr("end", vm.ctx.new_int(end), vm)?;
|
||||
@@ -2277,6 +2273,18 @@ pub(super) mod types {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn init(_zelf: PyRef<Self>, _args: Self::Args, _vm: &VirtualMachine) -> PyResult<()> {
|
||||
unreachable!("slot_init is defined")
|
||||
}
|
||||
}
|
||||
|
||||
#[pyexception(name, base = PyUnicodeError, ctx = "unicode_translate_error")]
|
||||
#[derive(Debug)]
|
||||
#[repr(transparent)]
|
||||
pub struct PyUnicodeTranslateError(PyUnicodeError);
|
||||
|
||||
#[pyexception(with(Initializer))]
|
||||
impl PyUnicodeTranslateError {
|
||||
#[pymethod]
|
||||
fn __str__(exc: PyBaseExceptionRef, vm: &VirtualMachine) -> PyResult<String> {
|
||||
let Ok(object) = exc.as_object().get_attr("object", vm) else {
|
||||
@@ -2301,6 +2309,24 @@ pub(super) mod types {
|
||||
}
|
||||
}
|
||||
|
||||
impl Initializer for PyUnicodeTranslateError {
|
||||
type Args = FuncArgs;
|
||||
|
||||
fn slot_init(zelf: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
|
||||
type Args = (PyStrRef, isize, isize, PyStrRef);
|
||||
let (object, start, end, reason): Args = args.bind(vm)?;
|
||||
zelf.set_attr("object", object, vm)?;
|
||||
zelf.set_attr("start", vm.ctx.new_int(start), vm)?;
|
||||
zelf.set_attr("end", vm.ctx.new_int(end), vm)?;
|
||||
zelf.set_attr("reason", reason, vm)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn init(_zelf: PyRef<Self>, _args: Self::Args, _vm: &VirtualMachine) -> PyResult<()> {
|
||||
unreachable!("slot_init is defined")
|
||||
}
|
||||
}
|
||||
|
||||
/// JIT error.
|
||||
#[cfg(feature = "jit")]
|
||||
#[pyexception(name, base = PyException, ctx = "jit_error", impl)]
|
||||
|
||||
@@ -3,21 +3,57 @@ use super::{PY_CF_OPTIMIZED_AST, PY_CF_TYPE_COMMENTS, PY_COMPILE_FLAG_AST_ONLY};
|
||||
#[pymodule]
|
||||
pub(crate) mod _ast {
|
||||
use crate::{
|
||||
AsObject, Context, Py, PyObjectRef, PyPayload, PyResult, VirtualMachine,
|
||||
AsObject, Context, Py, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
|
||||
builtins::{PyStrRef, PyTupleRef, PyType, PyTypeRef},
|
||||
function::FuncArgs,
|
||||
types::Constructor,
|
||||
types::{Constructor, Initializer},
|
||||
};
|
||||
#[pyattr]
|
||||
#[pyclass(module = "_ast", name = "AST")]
|
||||
#[derive(Debug, PyPayload)]
|
||||
pub(crate) struct NodeAst;
|
||||
|
||||
#[pyclass(with(Constructor), flags(BASETYPE, HAS_DICT))]
|
||||
#[pyclass(with(Constructor, Initializer), flags(BASETYPE, HAS_DICT))]
|
||||
impl NodeAst {
|
||||
#[pyslot]
|
||||
#[pymethod]
|
||||
fn __init__(zelf: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
|
||||
#[pyattr]
|
||||
fn _fields(ctx: &Context) -> PyTupleRef {
|
||||
ctx.empty_tuple.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl Constructor for NodeAst {
|
||||
type Args = FuncArgs;
|
||||
|
||||
fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
|
||||
// AST nodes accept extra arguments (unlike object.__new__)
|
||||
// This matches CPython's behavior where AST has its own tp_new
|
||||
let dict = if cls
|
||||
.slots
|
||||
.flags
|
||||
.contains(crate::types::PyTypeFlags::HAS_DICT)
|
||||
{
|
||||
Some(vm.ctx.new_dict())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let zelf = vm.ctx.new_base_object(cls, dict);
|
||||
|
||||
// Initialize the instance with the provided arguments
|
||||
// FIXME: This is probably incorrect. Please check if init should be called outside of __new__
|
||||
Self::slot_init(zelf.clone(), args, vm)?;
|
||||
|
||||
Ok(zelf)
|
||||
}
|
||||
|
||||
fn py_new(_cls: &Py<PyType>, _args: Self::Args, _vm: &VirtualMachine) -> PyResult<Self> {
|
||||
unimplemented!("use slot_new")
|
||||
}
|
||||
}
|
||||
|
||||
impl Initializer for NodeAst {
|
||||
type Args = FuncArgs;
|
||||
|
||||
fn slot_init(zelf: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
|
||||
let fields = zelf.get_attr("_fields", vm)?;
|
||||
let fields: Vec<PyStrRef> = fields.try_to_value(vm)?;
|
||||
let n_args = args.args.len();
|
||||
@@ -47,37 +83,8 @@ pub(crate) mod _ast {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[pyattr]
|
||||
fn _fields(ctx: &Context) -> PyTupleRef {
|
||||
ctx.empty_tuple.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl Constructor for NodeAst {
|
||||
type Args = FuncArgs;
|
||||
|
||||
fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
|
||||
// AST nodes accept extra arguments (unlike object.__new__)
|
||||
// This matches CPython's behavior where AST has its own tp_new
|
||||
let dict = if cls
|
||||
.slots
|
||||
.flags
|
||||
.contains(crate::types::PyTypeFlags::HAS_DICT)
|
||||
{
|
||||
Some(vm.ctx.new_dict())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let zelf = vm.ctx.new_base_object(cls, dict);
|
||||
|
||||
// Initialize the instance with the provided arguments
|
||||
Self::__init__(zelf.clone(), args, vm)?;
|
||||
|
||||
Ok(zelf)
|
||||
}
|
||||
|
||||
fn py_new(_cls: &Py<PyType>, _args: Self::Args, _vm: &VirtualMachine) -> PyResult<Self> {
|
||||
unimplemented!("use slot_new")
|
||||
fn init(_zelf: PyRef<Self>, _args: Self::Args, _vm: &VirtualMachine) -> PyResult<()> {
|
||||
unreachable!("slot_init is defined")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user