diff --git a/vm/src/builtins/object.rs b/vm/src/builtins/object.rs index be14327542..d0e5ed9db2 100644 --- a/vm/src/builtins/object.rs +++ b/vm/src/builtins/object.rs @@ -400,11 +400,59 @@ impl PyBaseObject { } #[pyslot] - #[pymethod(magic)] - fn init(_zelf: PyObjectRef, _args: FuncArgs, _vm: &VirtualMachine) -> PyResult<()> { + fn slot_init(zelf: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> { + let typ = zelf.class(); + eprintln!("called init of {}", zelf.class().name()); + if typ.slots.init.load().map_or(0, |f| f as usize) + == vm + .ctx + .types + .object_type + .slots + .init + .load() + .map_or(0, |f| f as usize) + { + return Ok(()); + } + if !args.is_empty() { + // if typ.slots.init.load().map_or(0, |f| f as usize) != vm.ctx.types.object_type.slots.init.load().map_or(0, |f| f as usize) { + // return Err(vm.new_type_error(format!( + // "object.__init__() takes exactly one argument (the instance to initialize)", + // ))); + // } + if typ.slots.new.load().map_or(0, |f| f as usize) + == vm + .ctx + .types + .object_type + .slots + .new + .load() + .map_or(0, |f| f as usize) + { + return Err(vm.new_type_error(format!( + "{:.200}.__init__() takes exactly one argument (the instance to initialize)", + typ.name() + ))); + } + } Ok(()) } + #[pymethod(magic)] + fn init(zelf: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> { + if zelf.class().is(vm.ctx.types.object_type) { + return Ok(()); + } + eprintln!("{:?}", zelf.class().name()); + let init = zelf + .class() + .mro_find_map(|cls| cls.slots.init.load()) + .unwrap(); + (init)(zelf, args, vm) + } + #[pygetset(name = "__class__")] fn get_class(obj: PyObjectRef) -> PyTypeRef { obj.class().to_owned() diff --git a/vm/src/builtins/super.rs b/vm/src/builtins/super.rs index 442d162c78..d20757f751 100644 --- a/vm/src/builtins/super.rs +++ b/vm/src/builtins/super.rs @@ -125,8 +125,8 @@ impl Initializer for PySuper { (typ, obj) }; - let mut inner = PySuperInner::new(typ, obj, vm)?; - std::mem::swap(&mut inner, &mut zelf.inner.write()); + let inner = PySuperInner::new(typ, obj, vm)?; + let _ = std::mem::replace::<PySuperInner>(&mut zelf.inner.write(), inner); Ok(()) } @@ -173,14 +173,19 @@ impl GetAttr for PySuper { .skip(1) // skip su->type (if any) .collect(); for cls in mro.iter() { + println!("traversing mro: {}", cls.name()); if let Some(descr) = cls.get_direct_attr(name) { + // Only pass 'obj' param if this is instance-mode super (See https://bugs.python.org/issue743267) + let obj = if obj.is(&start_type) { + None + } else { + println!("getattr {}.{} as {}", obj.class().name(), name, cls.name()); + + Some(obj) + }; + let cls = cls.as_object().to_owned(); return vm - .call_get_descriptor_specific( - &descr, - // Only pass 'obj' param if this is instance-mode super (See https://bugs.python.org/issue743267) - if obj.is(&start_type) { None } else { Some(obj) }, - Some(start_type.as_object().to_owned()), - ) + .call_get_descriptor_specific(&descr, obj, Some(cls)) .unwrap_or(Ok(descr)); } } diff --git a/vm/src/builtins/type.rs b/vm/src/builtins/type.rs index a0c7ee58ff..fb653a4311 100644 --- a/vm/src/builtins/type.rs +++ b/vm/src/builtins/type.rs @@ -301,6 +301,9 @@ impl PyType { let mut slot_name_set = std::collections::HashSet::new(); for cls in self.mro.read().iter() { + if !cls.slots.flags.contains(PyTypeFlags::HEAPTYPE) { + continue; + } for &name in cls.attributes.read().keys() { if name == identifier!(ctx, __new__) { continue; diff --git a/vm/src/stdlib/ast/python.rs b/vm/src/stdlib/ast/python.rs index 74c4db888a..de1f0b4a85 100644 --- a/vm/src/stdlib/ast/python.rs +++ b/vm/src/stdlib/ast/python.rs @@ -15,7 +15,6 @@ pub(crate) mod _ast { #[pyclass(flags(BASETYPE, HAS_DICT))] impl NodeAst { #[pyslot] - #[pymethod(magic)] fn init(zelf: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> { let fields = zelf.get_attr("_fields", vm)?; let fields: Vec<PyStrRef> = fields.try_to_value(vm)?; diff --git a/vm/src/stdlib/io.rs b/vm/src/stdlib/io.rs index 3e1979e3d0..5301e8e311 100644 --- a/vm/src/stdlib/io.rs +++ b/vm/src/stdlib/io.rs @@ -1402,17 +1402,12 @@ mod _io { #[pyslot] fn slot_init(zelf: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> { let zelf: PyRef<Self> = zelf.try_into_value(vm)?; - zelf.__init__(args, vm) - } - - #[pymethod] - fn __init__(&self, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> { let (raw, BufferSize { buffer_size }): (PyObjectRef, _) = args.bind(vm).map_err(|e| { let msg = format!("{}() {}", Self::CLASS_NAME, *e.str(vm)); vm.new_exception_msg(e.class().to_owned(), msg) })?; - self.init(raw, BufferSize { buffer_size }, vm) + zelf.init(raw, BufferSize { buffer_size }, vm) } fn init( diff --git a/vm/src/types/slot.rs b/vm/src/types/slot.rs index e2121973ec..a9192e96f0 100644 --- a/vm/src/types/slot.rs +++ b/vm/src/types/slot.rs @@ -363,7 +363,10 @@ fn descr_set_wrapper( fn init_wrapper(obj: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> { let res = vm.call_special_method(&obj, identifier!(vm, __init__), args)?; if !vm.is_none(&res) { - return Err(vm.new_type_error("__init__ must return None".to_owned())); + return Err(vm.new_type_error(format!( + "__init__ should return None, not '{:.200}'", + res.class().name() + ))); } Ok(()) } @@ -511,6 +514,7 @@ impl PyType { update_slot!(descr_set, descr_set_wrapper); } _ if name == identifier!(ctx, __init__) => { + eprintln!("init of {:?}", self.name()); toggle_slot!(init, init_wrapper); } _ if name == identifier!(ctx, __new__) => { @@ -829,12 +833,6 @@ pub trait Initializer: PyPayload { Self::init(zelf, args, vm) } - #[pymethod] - #[inline] - fn __init__(zelf: PyRef<Self>, args: Self::Args, vm: &VirtualMachine) -> PyResult<()> { - Self::init(zelf, args, vm) - } - fn init(zelf: PyRef<Self>, args: Self::Args, vm: &VirtualMachine) -> PyResult<()>; }