Skip to content

Commit 6b84c2b

Browse files
authored
Merge pull request #3057 from eldpswp99/make-magic-method-new-to-follow-cpython
make magic method new to follow cpython way
2 parents 7a7a6bd + 00b33f8 commit 6b84c2b

File tree

5 files changed

+25
-47
lines changed

5 files changed

+25
-47
lines changed

vm/src/builtins/function.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -541,8 +541,6 @@ impl PyBoundMethod {
541541
// Special case: we work with `__new__`, which is not really a method.
542542
// It is a function, so its `__qualname__` is just `__new__`.
543543
// We need to add object's part manually.
544-
// Note: at the moment, `__new__` in the form of `tp_new_wrapper`
545-
// is the only instance of `builtin_function_or_method_type`.
546544
let obj_name = vm.get_attribute_opt(self.object.clone(), "__qualname__")?;
547545
let obj_name: Option<PyStrRef> = obj_name.and_then(|o| o.downcast().ok());
548546
return Ok(vm.ctx.new_utf8_str(format!(

vm/src/builtins/object.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
use super::dict::{PyDict, PyDictRef};
22
use super::list::PyList;
33
use super::pystr::{PyStr, PyStrRef};
4-
use super::pytype::PyTypeRef;
5-
use crate::builtins::pytype::PyType;
4+
use super::pytype::{PyType, PyTypeRef};
65
use crate::common::hash::PyHash;
76
use crate::function::FuncArgs;
87
use crate::slots::PyComparisonOp;
@@ -363,8 +362,8 @@ pub(crate) fn setattr(
363362
}
364363
}
365364

366-
pub fn init(context: &PyContext) {
367-
PyBaseObject::extend_class(context, &context.types.object_type);
365+
pub fn init(ctx: &PyContext) {
366+
PyBaseObject::extend_class(ctx, &ctx.types.object_type);
368367
}
369368

370369
fn common_reduce(obj: PyObjectRef, proto: usize, vm: &VirtualMachine) -> PyResult {

vm/src/builtins/pytype.rs

Lines changed: 15 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,19 @@ impl PyTypeRef {
239239

240240
#[pyimpl(with(SlotGetattro, SlotSetattro, Callable), flags(BASETYPE))]
241241
impl PyType {
242+
// bound method for every type
243+
pub(crate) fn __new__(zelf: PyRef<Self>, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
244+
let (subtype, args): (PyRef<Self>, FuncArgs) = args.bind(vm)?;
245+
if !subtype.issubclass(&zelf) {
246+
return Err(vm.new_type_error(format!(
247+
"{zelf}.__new__({subtype}): {subtype} is not a subtype of {zelf}",
248+
zelf = zelf.name(),
249+
subtype = subtype.name(),
250+
)));
251+
}
252+
call_tp_new(zelf, subtype, args, vm)
253+
}
254+
242255
#[pyproperty(name = "__mro__")]
243256
fn get_mro(zelf: PyRef<Self>) -> PyTuple {
244257
let elements: Vec<PyObjectRef> = zelf.iter_mro().map(|x| x.as_object().clone()).collect();
@@ -769,43 +782,20 @@ impl<T: DerefToPyType> DerefToPyType for &'_ T {
769782
}
770783
}
771784

772-
fn call_tp_new(
785+
pub(crate) fn call_tp_new(
773786
typ: PyTypeRef,
774787
subtype: PyTypeRef,
775-
mut args: FuncArgs,
788+
args: FuncArgs,
776789
vm: &VirtualMachine,
777790
) -> PyResult {
778791
for cls in typ.deref().iter_mro() {
779-
if let Some(new_meth) = cls.get_attr("__new__") {
780-
if !vm.ctx.is_tp_new_wrapper(&new_meth) {
781-
let new_meth = vm.call_if_get_descriptor(new_meth, typ.clone().into_object())?;
782-
args.prepend_arg(typ.clone().into_object());
783-
return vm.invoke(&new_meth, args);
784-
}
785-
}
786792
if let Some(tp_new) = cls.slots.new.load() {
787793
return tp_new(subtype, args, vm);
788794
}
789795
}
790796
unreachable!("Should be able to find a new slot somewhere in the mro")
791797
}
792798

793-
pub fn tp_new_wrapper(
794-
zelf: PyTypeRef,
795-
cls: PyTypeRef,
796-
args: FuncArgs,
797-
vm: &VirtualMachine,
798-
) -> PyResult {
799-
if !cls.issubclass(&zelf) {
800-
return Err(vm.new_type_error(format!(
801-
"{zelf}.__new__({cls}): {cls} is not a subtype of {zelf}",
802-
zelf = zelf.name(),
803-
cls = cls.name(),
804-
)));
805-
}
806-
call_tp_new(zelf, cls, args, vm)
807-
}
808-
809799
fn take_next_base(bases: &mut Vec<Vec<PyTypeRef>>) -> Option<PyTypeRef> {
810800
for base in bases.iter() {
811801
let head = base[0].clone();

vm/src/macros.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ macro_rules! py_class {
3030
$($crate::py_class!(@extract_slots($ctx, &mut slots, $name, $value));)*
3131
let py_class = $ctx.new_class($class_name, $class_base, slots);
3232
$($crate::py_class!(@extract_attrs($ctx, &py_class, $name, $value));)*
33-
$ctx.add_slot_wrappers(&py_class);
3433
py_class
3534
}
3635
};
@@ -50,7 +49,6 @@ macro_rules! extend_class {
5049
$(
5150
$class.set_str_attr($name, $value);
5251
)*
53-
$ctx.add_slot_wrappers(&$class);
5452
};
5553
}
5654

vm/src/pyobject.rs

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use crate::builtins::list::PyList;
2121
use crate::builtins::namespace::PyNamespace;
2222
use crate::builtins::object;
2323
use crate::builtins::pystr;
24-
use crate::builtins::pytype::{self, PyType, PyTypeRef};
24+
use crate::builtins::pytype::{PyType, PyTypeRef};
2525
use crate::builtins::set::{self, PyFrozenSet};
2626
use crate::builtins::singletons::{PyNone, PyNoneRef, PyNotImplemented, PyNotImplementedRef};
2727
use crate::builtins::slice::PyEllipsis;
@@ -123,7 +123,7 @@ impl PyContext {
123123

124124
let new_str = PyRef::new_ref(pystr::PyStr::from("__new__"), types.str_type.clone(), None);
125125
let tp_new_wrapper = create_object(
126-
PyNativeFuncDef::new(pytype::tp_new_wrapper.into_func(), new_str).into_function(),
126+
PyNativeFuncDef::new(PyType::__new__.into_func(), new_str).into_function(),
127127
&types.builtin_function_or_method_type,
128128
)
129129
.into_object();
@@ -384,17 +384,6 @@ impl PyContext {
384384
pub fn new_base_object(&self, class: PyTypeRef, dict: Option<PyDictRef>) -> PyObjectRef {
385385
PyObject::new(object::PyBaseObject, class, dict)
386386
}
387-
388-
pub fn add_slot_wrappers(&self, ty: &PyTypeRef) {
389-
let new_wrapper =
390-
self.new_bound_method(self.tp_new_wrapper.clone(), ty.clone().into_object());
391-
ty.set_str_attr("__new__", new_wrapper);
392-
}
393-
394-
pub fn is_tp_new_wrapper(&self, obj: &PyObjectRef) -> bool {
395-
obj.payload::<PyBoundMethod>()
396-
.map_or(false, |bound| bound.function.is(&self.tp_new_wrapper))
397-
}
398387
}
399388

400389
impl Default for PyContext {
@@ -994,13 +983,17 @@ pub trait PyClassImpl: PyClassDef {
994983
);
995984
}
996985
Self::impl_extend_class(ctx, class);
997-
ctx.add_slot_wrappers(class);
998986
if let Some(doc) = Self::DOC {
999987
class.set_str_attr("__doc__", ctx.new_utf8_str(doc));
1000988
}
1001989
if let Some(module_name) = Self::MODULE_NAME {
1002990
class.set_str_attr("__module__", ctx.new_utf8_str(module_name));
1003991
}
992+
if class.slots.new.load().is_some() {
993+
let bound =
994+
ctx.new_bound_method(ctx.tp_new_wrapper.clone(), class.clone().into_object());
995+
class.set_str_attr("__new__", bound);
996+
}
1004997
}
1005998

1006999
fn make_class(ctx: &PyContext) -> PyTypeRef

0 commit comments

Comments
 (0)