Resolve number slots via MRO in PyNumber and operator, ensure inherit… by YashSuthar983 · Pull Request #6222 · RustPython/RustPython · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions Lib/ctypes/__init__.py
197 changes: 110 additions & 87 deletions vm/src/protocol/number.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Comment thread
youknowone marked this conversation as resolved.
// 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)?;

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}). \
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());
}

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,
)?;

Ok(ret.to_owned())
} else {
Err(vm.new_type_error(format!(
"{}.__int__ returned non-int(type {})",
self.class(),
ret_class
)))
}
})
),
1,
vm,
)?;

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)?;

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}). \
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());
}

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,
)?;

Ok(ret.to_owned())
} else {
Err(vm.new_type_error(format!(
"{}.__index__ returned non-int(type {})",
self.class(),
ret_class
)))
}
})
),
1,
vm,
)?;

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)?;

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}). \
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());
}

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,
)?;

Ok(ret.to_owned())
} else {
Err(vm.new_type_error(format!(
"{}.__float__ returned non-float(type {})",
self.class(),
ret_class
)))
}
})
),
1,
vm,
)?;

Ok(ret.to_owned())
} else {
Err(vm.new_type_error(format!(
"{}.__float__ returned non-float(type {})",
self.class(),
ret_class
)))
}
})
}
}

Expand Down
22 changes: 15 additions & 7 deletions vm/src/vm/vm_ops.rs
Loading