Resolve number slots via MRO in PyNumber and operator, ensure inherit… · RustPython/RustPython@b6e8a87 · GitHub
Skip to content

Commit b6e8a87

Browse files
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>
1 parent 6b25fe5 commit b6e8a87

3 files changed

Lines changed: 126 additions & 97 deletions

File tree

Lib/ctypes/__init__.py

Lines changed: 1 addition & 3 deletions

vm/src/protocol/number.rs

Lines changed: 110 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -443,117 +443,140 @@ impl<'a> PyNumber<'a> {
443443

444444
// PyNumber_Check
445445
pub fn check(obj: &PyObject) -> bool {
446-
let methods = &obj.class().slots.as_number;
447-
methods.int.load().is_some()
448-
|| methods.index.load().is_some()
449-
|| methods.float.load().is_some()
450-
|| obj.downcastable::<PyComplex>()
446+
let cls = &obj.class();
447+
// TODO: when we finally have a proper slot inheritance, mro_find_map can be removed
448+
// methods.int.load().is_some()
449+
// || methods.index.load().is_some()
450+
// || methods.float.load().is_some()
451+
// || obj.downcastable::<PyComplex>()
452+
let has_number = cls
453+
.mro_find_map(|x| {
454+
let methods = &x.slots.as_number;
455+
if methods.int.load().is_some()
456+
|| methods.index.load().is_some()
457+
|| methods.float.load().is_some()
458+
{
459+
Some(())
460+
} else {
461+
None
462+
}
463+
})
464+
.is_some();
465+
has_number || obj.downcastable::<PyComplex>()
451466
}
452467
}
453468

454469
impl PyNumber<'_> {
455470
// PyIndex_Check
456471
pub fn is_index(self) -> bool {
457-
self.class().slots.as_number.index.load().is_some()
472+
self.class()
473+
.mro_find_map(|x| x.slots.as_number.index.load())
474+
.is_some()
458475
}
459476

460477
#[inline]
461478
pub fn int(self, vm: &VirtualMachine) -> Option<PyResult<PyIntRef>> {
462-
self.class().slots.as_number.int.load().map(|f| {
463-
let ret = f(self, vm)?;
464-
465-
if let Some(ret) = ret.downcast_ref_if_exact::<PyInt>(vm) {
466-
return Ok(ret.to_owned());
467-
}
468-
469-
let ret_class = ret.class().to_owned();
470-
if let Some(ret) = ret.downcast_ref::<PyInt>() {
471-
warnings::warn(
472-
vm.ctx.exceptions.deprecation_warning,
473-
format!(
474-
"__int__ returned non-int (type {ret_class}). \
479+
self.class()
480+
.mro_find_map(|x| x.slots.as_number.int.load())
481+
.map(|f| {
482+
let ret = f(self, vm)?;
483+
484+
if let Some(ret) = ret.downcast_ref_if_exact::<PyInt>(vm) {
485+
return Ok(ret.to_owned());
486+
}
487+
488+
let ret_class = ret.class().to_owned();
489+
if let Some(ret) = ret.downcast_ref::<PyInt>() {
490+
warnings::warn(
491+
vm.ctx.exceptions.deprecation_warning,
492+
format!(
493+
"__int__ returned non-int (type {ret_class}). \
475494
The ability to return an instance of a strict subclass of int \
476495
is deprecated, and may be removed in a future version of Python."
477-
),
478-
1,
479-
vm,
480-
)?;
481-
482-
Ok(ret.to_owned())
483-
} else {
484-
Err(vm.new_type_error(format!(
485-
"{}.__int__ returned non-int(type {})",
486-
self.class(),
487-
ret_class
488-
)))
489-
}
490-
})
496+
),
497+
1,
498+
vm,
499+
)?;
500+
501+
Ok(ret.to_owned())
502+
} else {
503+
Err(vm.new_type_error(format!(
504+
"{}.__int__ returned non-int(type {})",
505+
self.class(),
506+
ret_class
507+
)))
508+
}
509+
})
491510
}
492511

493512
#[inline]
494513
pub fn index(self, vm: &VirtualMachine) -> Option<PyResult<PyIntRef>> {
495-
self.class().slots.as_number.index.load().map(|f| {
496-
let ret = f(self, vm)?;
497-
498-
if let Some(ret) = ret.downcast_ref_if_exact::<PyInt>(vm) {
499-
return Ok(ret.to_owned());
500-
}
501-
502-
let ret_class = ret.class().to_owned();
503-
if let Some(ret) = ret.downcast_ref::<PyInt>() {
504-
warnings::warn(
505-
vm.ctx.exceptions.deprecation_warning,
506-
format!(
507-
"__index__ returned non-int (type {ret_class}). \
514+
self.class()
515+
.mro_find_map(|x| x.slots.as_number.index.load())
516+
.map(|f| {
517+
let ret = f(self, vm)?;
518+
519+
if let Some(ret) = ret.downcast_ref_if_exact::<PyInt>(vm) {
520+
return Ok(ret.to_owned());
521+
}
522+
523+
let ret_class = ret.class().to_owned();
524+
if let Some(ret) = ret.downcast_ref::<PyInt>() {
525+
warnings::warn(
526+
vm.ctx.exceptions.deprecation_warning,
527+
format!(
528+
"__index__ returned non-int (type {ret_class}). \
508529
The ability to return an instance of a strict subclass of int \
509530
is deprecated, and may be removed in a future version of Python."
510-
),
511-
1,
512-
vm,
513-
)?;
514-
515-
Ok(ret.to_owned())
516-
} else {
517-
Err(vm.new_type_error(format!(
518-
"{}.__index__ returned non-int(type {})",
519-
self.class(),
520-
ret_class
521-
)))
522-
}
523-
})
531+
),
532+
1,
533+
vm,
534+
)?;
535+
536+
Ok(ret.to_owned())
537+
} else {
538+
Err(vm.new_type_error(format!(
539+
"{}.__index__ returned non-int(type {})",
540+
self.class(),
541+
ret_class
542+
)))
543+
}
544+
})
524545
}
525546

526547
#[inline]
527548
pub fn float(self, vm: &VirtualMachine) -> Option<PyResult<PyRef<PyFloat>>> {
528-
self.class().slots.as_number.float.load().map(|f| {
529-
let ret = f(self, vm)?;
530-
531-
if let Some(ret) = ret.downcast_ref_if_exact::<PyFloat>(vm) {
532-
return Ok(ret.to_owned());
533-
}
534-
535-
let ret_class = ret.class().to_owned();
536-
if let Some(ret) = ret.downcast_ref::<PyFloat>() {
537-
warnings::warn(
538-
vm.ctx.exceptions.deprecation_warning,
539-
format!(
540-
"__float__ returned non-float (type {ret_class}). \
549+
self.class()
550+
.mro_find_map(|x| x.slots.as_number.float.load())
551+
.map(|f| {
552+
let ret = f(self, vm)?;
553+
554+
if let Some(ret) = ret.downcast_ref_if_exact::<PyFloat>(vm) {
555+
return Ok(ret.to_owned());
556+
}
557+
558+
let ret_class = ret.class().to_owned();
559+
if let Some(ret) = ret.downcast_ref::<PyFloat>() {
560+
warnings::warn(
561+
vm.ctx.exceptions.deprecation_warning,
562+
format!(
563+
"__float__ returned non-float (type {ret_class}). \
541564
The ability to return an instance of a strict subclass of float \
542565
is deprecated, and may be removed in a future version of Python."
543-
),
544-
1,
545-
vm,
546-
)?;
547-
548-
Ok(ret.to_owned())
549-
} else {
550-
Err(vm.new_type_error(format!(
551-
"{}.__float__ returned non-float(type {})",
552-
self.class(),
553-
ret_class
554-
)))
555-
}
556-
})
566+
),
567+
1,
568+
vm,
569+
)?;
570+
571+
Ok(ret.to_owned())
572+
} else {
573+
Err(vm.new_type_error(format!(
574+
"{}.__float__ returned non-float(type {})",
575+
self.class(),
576+
ret_class
577+
)))
578+
}
579+
})
557580
}
558581
}
559582

vm/src/vm/vm_ops.rs

Lines changed: 15 additions & 7 deletions

0 commit comments

Comments
 (0)