mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
Resolve number slots via MRO in PyNumber and operator, ensure inherit… (#6222)
* Resolve number slots via MRO in PyNumber and operator, ensure inherited and dynamically added methods are found. Use class().mro_find_map() to mimic the same behaviour as CPython. Signed-off-by: Yash Suthar <yashsuthar983@gmail.com>
This commit is contained in:
1 parent
6b25fe5c95
commit
b6e8a875ac
3 files changed
+117
-88
No files matched your search
Vendored
+1
-3
@@ -299,9 +299,7 @@ def create_unicode_buffer(init, size=None):
|
||||
return buf
|
||||
elif isinstance(init, int):
|
||||
_sys.audit("ctypes.create_unicode_buffer", None, init)
|
||||
# XXX: RUSTPYTHON
|
||||
# buftype = c_wchar * init
|
||||
buftype = c_wchar.__mul__(init)
|
||||
buftype = c_wchar * init
|
||||
buf = buftype()
|
||||
return buf
|
||||
raise TypeError(init)
|
||||
|
||||
+101
-78
@@ -443,117 +443,140 @@ impl<'a> PyNumber<'a> {
|
||||
|
||||
// PyNumber_Check
|
||||
pub fn check(obj: &PyObject) -> bool {
|
||||
let methods = &obj.class().slots.as_number;
|
||||
methods.int.load().is_some()
|
||||
|| methods.index.load().is_some()
|
||||
|| methods.float.load().is_some()
|
||||
|| obj.downcastable::<PyComplex>()
|
||||
let cls = &obj.class();
|
||||
// TODO: when we finally have a proper slot inheritance, mro_find_map can be removed
|
||||
// methods.int.load().is_some()
|
||||
// || methods.index.load().is_some()
|
||||
// || methods.float.load().is_some()
|
||||
// || obj.downcastable::<PyComplex>()
|
||||
let has_number = cls
|
||||
.mro_find_map(|x| {
|
||||
let methods = &x.slots.as_number;
|
||||
if methods.int.load().is_some()
|
||||
|| methods.index.load().is_some()
|
||||
|| methods.float.load().is_some()
|
||||
{
|
||||
Some(())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.is_some();
|
||||
has_number || obj.downcastable::<PyComplex>()
|
||||
}
|
||||
}
|
||||
|
||||
impl PyNumber<'_> {
|
||||
// PyIndex_Check
|
||||
pub fn is_index(self) -> bool {
|
||||
self.class().slots.as_number.index.load().is_some()
|
||||
self.class()
|
||||
.mro_find_map(|x| x.slots.as_number.index.load())
|
||||
.is_some()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn int(self, vm: &VirtualMachine) -> Option<PyResult<PyIntRef>> {
|
||||
self.class().slots.as_number.int.load().map(|f| {
|
||||
let ret = f(self, vm)?;
|
||||
self.class()
|
||||
.mro_find_map(|x| x.slots.as_number.int.load())
|
||||
.map(|f| {
|
||||
let ret = f(self, vm)?;
|
||||
|
||||
if let Some(ret) = ret.downcast_ref_if_exact::<PyInt>(vm) {
|
||||
return Ok(ret.to_owned());
|
||||
}
|
||||
if let Some(ret) = ret.downcast_ref_if_exact::<PyInt>(vm) {
|
||||
return Ok(ret.to_owned());
|
||||
}
|
||||
|
||||
let ret_class = ret.class().to_owned();
|
||||
if let Some(ret) = ret.downcast_ref::<PyInt>() {
|
||||
warnings::warn(
|
||||
vm.ctx.exceptions.deprecation_warning,
|
||||
format!(
|
||||
"__int__ returned non-int (type {ret_class}). \
|
||||
let ret_class = ret.class().to_owned();
|
||||
if let Some(ret) = ret.downcast_ref::<PyInt>() {
|
||||
warnings::warn(
|
||||
vm.ctx.exceptions.deprecation_warning,
|
||||
format!(
|
||||
"__int__ returned non-int (type {ret_class}). \
|
||||
The ability to return an instance of a strict subclass of int \
|
||||
is deprecated, and may be removed in a future version of Python."
|
||||
),
|
||||
1,
|
||||
vm,
|
||||
)?;
|
||||
),
|
||||
1,
|
||||
vm,
|
||||
)?;
|
||||
|
||||
Ok(ret.to_owned())
|
||||
} else {
|
||||
Err(vm.new_type_error(format!(
|
||||
"{}.__int__ returned non-int(type {})",
|
||||
self.class(),
|
||||
ret_class
|
||||
)))
|
||||
}
|
||||
})
|
||||
Ok(ret.to_owned())
|
||||
} else {
|
||||
Err(vm.new_type_error(format!(
|
||||
"{}.__int__ returned non-int(type {})",
|
||||
self.class(),
|
||||
ret_class
|
||||
)))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn index(self, vm: &VirtualMachine) -> Option<PyResult<PyIntRef>> {
|
||||
self.class().slots.as_number.index.load().map(|f| {
|
||||
let ret = f(self, vm)?;
|
||||
self.class()
|
||||
.mro_find_map(|x| x.slots.as_number.index.load())
|
||||
.map(|f| {
|
||||
let ret = f(self, vm)?;
|
||||
|
||||
if let Some(ret) = ret.downcast_ref_if_exact::<PyInt>(vm) {
|
||||
return Ok(ret.to_owned());
|
||||
}
|
||||
if let Some(ret) = ret.downcast_ref_if_exact::<PyInt>(vm) {
|
||||
return Ok(ret.to_owned());
|
||||
}
|
||||
|
||||
let ret_class = ret.class().to_owned();
|
||||
if let Some(ret) = ret.downcast_ref::<PyInt>() {
|
||||
warnings::warn(
|
||||
vm.ctx.exceptions.deprecation_warning,
|
||||
format!(
|
||||
"__index__ returned non-int (type {ret_class}). \
|
||||
let ret_class = ret.class().to_owned();
|
||||
if let Some(ret) = ret.downcast_ref::<PyInt>() {
|
||||
warnings::warn(
|
||||
vm.ctx.exceptions.deprecation_warning,
|
||||
format!(
|
||||
"__index__ returned non-int (type {ret_class}). \
|
||||
The ability to return an instance of a strict subclass of int \
|
||||
is deprecated, and may be removed in a future version of Python."
|
||||
),
|
||||
1,
|
||||
vm,
|
||||
)?;
|
||||
),
|
||||
1,
|
||||
vm,
|
||||
)?;
|
||||
|
||||
Ok(ret.to_owned())
|
||||
} else {
|
||||
Err(vm.new_type_error(format!(
|
||||
"{}.__index__ returned non-int(type {})",
|
||||
self.class(),
|
||||
ret_class
|
||||
)))
|
||||
}
|
||||
})
|
||||
Ok(ret.to_owned())
|
||||
} else {
|
||||
Err(vm.new_type_error(format!(
|
||||
"{}.__index__ returned non-int(type {})",
|
||||
self.class(),
|
||||
ret_class
|
||||
)))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn float(self, vm: &VirtualMachine) -> Option<PyResult<PyRef<PyFloat>>> {
|
||||
self.class().slots.as_number.float.load().map(|f| {
|
||||
let ret = f(self, vm)?;
|
||||
self.class()
|
||||
.mro_find_map(|x| x.slots.as_number.float.load())
|
||||
.map(|f| {
|
||||
let ret = f(self, vm)?;
|
||||
|
||||
if let Some(ret) = ret.downcast_ref_if_exact::<PyFloat>(vm) {
|
||||
return Ok(ret.to_owned());
|
||||
}
|
||||
if let Some(ret) = ret.downcast_ref_if_exact::<PyFloat>(vm) {
|
||||
return Ok(ret.to_owned());
|
||||
}
|
||||
|
||||
let ret_class = ret.class().to_owned();
|
||||
if let Some(ret) = ret.downcast_ref::<PyFloat>() {
|
||||
warnings::warn(
|
||||
vm.ctx.exceptions.deprecation_warning,
|
||||
format!(
|
||||
"__float__ returned non-float (type {ret_class}). \
|
||||
let ret_class = ret.class().to_owned();
|
||||
if let Some(ret) = ret.downcast_ref::<PyFloat>() {
|
||||
warnings::warn(
|
||||
vm.ctx.exceptions.deprecation_warning,
|
||||
format!(
|
||||
"__float__ returned non-float (type {ret_class}). \
|
||||
The ability to return an instance of a strict subclass of float \
|
||||
is deprecated, and may be removed in a future version of Python."
|
||||
),
|
||||
1,
|
||||
vm,
|
||||
)?;
|
||||
),
|
||||
1,
|
||||
vm,
|
||||
)?;
|
||||
|
||||
Ok(ret.to_owned())
|
||||
} else {
|
||||
Err(vm.new_type_error(format!(
|
||||
"{}.__float__ returned non-float(type {})",
|
||||
self.class(),
|
||||
ret_class
|
||||
)))
|
||||
}
|
||||
})
|
||||
Ok(ret.to_owned())
|
||||
} else {
|
||||
Err(vm.new_type_error(format!(
|
||||
"{}.__float__ returned non-float(type {})",
|
||||
self.class(),
|
||||
ret_class
|
||||
)))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+15
-7
@@ -160,11 +160,12 @@ impl VirtualMachine {
|
||||
let class_a = a.class();
|
||||
let class_b = b.class();
|
||||
|
||||
let slot_a = class_a.slots.as_number.left_binary_op(op_slot);
|
||||
// Look up number slots across MRO for inheritance
|
||||
let slot_a = class_a.mro_find_map(|x| x.slots.as_number.left_binary_op(op_slot));
|
||||
let mut slot_b = None;
|
||||
|
||||
if !class_a.is(class_b) {
|
||||
let slot_bb = class_b.slots.as_number.right_binary_op(op_slot);
|
||||
let slot_bb = class_b.mro_find_map(|x| x.slots.as_number.right_binary_op(op_slot));
|
||||
if slot_bb.map(|x| x as usize) != slot_a.map(|x| x as usize) {
|
||||
slot_b = slot_bb;
|
||||
}
|
||||
@@ -230,7 +231,10 @@ impl VirtualMachine {
|
||||
iop_slot: PyNumberBinaryOp,
|
||||
op_slot: PyNumberBinaryOp,
|
||||
) -> PyResult {
|
||||
if let Some(slot) = a.class().slots.as_number.left_binary_op(iop_slot) {
|
||||
if let Some(slot) = a
|
||||
.class()
|
||||
.mro_find_map(|x| x.slots.as_number.left_binary_op(iop_slot))
|
||||
{
|
||||
let x = slot(a, b, self)?;
|
||||
if !x.is(&self.ctx.not_implemented) {
|
||||
return Ok(x);
|
||||
@@ -266,11 +270,12 @@ impl VirtualMachine {
|
||||
let class_b = b.class();
|
||||
let class_c = c.class();
|
||||
|
||||
let slot_a = class_a.slots.as_number.left_ternary_op(op_slot);
|
||||
// Look up number slots across MRO for inheritance
|
||||
let slot_a = class_a.mro_find_map(|x| x.slots.as_number.left_ternary_op(op_slot));
|
||||
let mut slot_b = None;
|
||||
|
||||
if !class_a.is(class_b) {
|
||||
let slot_bb = class_b.slots.as_number.right_ternary_op(op_slot);
|
||||
let slot_bb = class_b.mro_find_map(|x| x.slots.as_number.right_ternary_op(op_slot));
|
||||
if slot_bb.map(|x| x as usize) != slot_a.map(|x| x as usize) {
|
||||
slot_b = slot_bb;
|
||||
}
|
||||
@@ -299,7 +304,7 @@ impl VirtualMachine {
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(slot_c) = class_c.slots.as_number.left_ternary_op(op_slot)
|
||||
if let Some(slot_c) = class_c.mro_find_map(|x| x.slots.as_number.left_ternary_op(op_slot))
|
||||
&& slot_a.is_some_and(|slot_a| !std::ptr::fn_addr_eq(slot_a, slot_c))
|
||||
&& slot_b.is_some_and(|slot_b| !std::ptr::fn_addr_eq(slot_b, slot_c))
|
||||
{
|
||||
@@ -338,7 +343,10 @@ impl VirtualMachine {
|
||||
op_slot: PyNumberTernaryOp,
|
||||
op_str: &str,
|
||||
) -> PyResult {
|
||||
if let Some(slot) = a.class().slots.as_number.left_ternary_op(iop_slot) {
|
||||
if let Some(slot) = a
|
||||
.class()
|
||||
.mro_find_map(|x| x.slots.as_number.left_ternary_op(iop_slot))
|
||||
{
|
||||
let x = slot(a, b, c, self)?;
|
||||
if !x.is(&self.ctx.not_implemented) {
|
||||
return Ok(x);
|
||||
|
||||
Reference in new issue
Block a user