mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
slot for numeric ops (#6619)
* fix sequence_repeat wrappers * slot for numeric ops * fix bpo-37619
This commit is contained in:
1 parent
d3e2fa47cc
commit
b19312b403
17 files changed
+60
-90
No files matched your search
@@ -1060,7 +1060,6 @@ mod array {
|
||||
self.delitem_inner(&needle, vm)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __add__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
|
||||
if let Some(other) = other.downcast_ref::<Self>() {
|
||||
self.read()
|
||||
@@ -1074,7 +1073,6 @@ mod array {
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __iadd__(
|
||||
zelf: PyRef<Self>,
|
||||
other: PyObjectRef,
|
||||
@@ -1093,15 +1091,12 @@ mod array {
|
||||
Ok(zelf)
|
||||
}
|
||||
|
||||
#[pymethod(name = "__rmul__")]
|
||||
#[pymethod]
|
||||
fn __mul__(&self, value: isize, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
|
||||
self.read()
|
||||
.mul(value, vm)
|
||||
.map(|x| Self::from(x).into_ref(&vm.ctx))
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __imul__(zelf: PyRef<Self>, value: isize, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
|
||||
zelf.try_resizable(vm)?.imul(value, vm)?;
|
||||
Ok(zelf)
|
||||
|
||||
@@ -215,7 +215,6 @@ impl PyByteArray {
|
||||
size_of::<Self>() + self.borrow_buf().len() * size_of::<u8>()
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __add__(&self, other: ArgBytesLike) -> Self {
|
||||
self.inner().add(&other.borrow_buf()).into()
|
||||
}
|
||||
@@ -229,7 +228,6 @@ impl PyByteArray {
|
||||
self.inner().contains(needle, vm)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __iadd__(
|
||||
zelf: PyRef<Self>,
|
||||
other: ArgBytesLike,
|
||||
@@ -524,29 +522,20 @@ impl PyByteArray {
|
||||
self.inner().title().into()
|
||||
}
|
||||
|
||||
#[pymethod(name = "__rmul__")]
|
||||
#[pymethod]
|
||||
fn __mul__(&self, value: ArgSize, vm: &VirtualMachine) -> PyResult<Self> {
|
||||
self.repeat(value.into(), vm)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __imul__(zelf: PyRef<Self>, value: ArgSize, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
|
||||
Self::irepeat(&zelf, value.into(), vm)?;
|
||||
Ok(zelf)
|
||||
}
|
||||
|
||||
#[pymethod(name = "__mod__")]
|
||||
fn mod_(&self, values: PyObjectRef, vm: &VirtualMachine) -> PyResult<Self> {
|
||||
fn __mod__(&self, values: PyObjectRef, vm: &VirtualMachine) -> PyResult<Self> {
|
||||
let formatted = self.inner().cformat(values, vm)?;
|
||||
Ok(formatted.into())
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __rmod__(&self, _values: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef {
|
||||
vm.ctx.not_implemented()
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn reverse(&self) {
|
||||
self.borrow_buf_mut().reverse();
|
||||
@@ -822,7 +811,7 @@ impl AsNumber for PyByteArray {
|
||||
static AS_NUMBER: PyNumberMethods = PyNumberMethods {
|
||||
remainder: Some(|a, b, vm| {
|
||||
if let Some(a) = a.downcast_ref::<PyByteArray>() {
|
||||
a.mod_(b.to_owned(), vm).to_pyresult(vm)
|
||||
a.__mod__(b.to_owned(), vm).to_pyresult(vm)
|
||||
} else {
|
||||
Ok(vm.ctx.not_implemented())
|
||||
}
|
||||
|
||||
@@ -224,7 +224,6 @@ impl PyBytes {
|
||||
size_of::<Self>() + self.len() * size_of::<u8>()
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __add__(&self, other: ArgBytesLike) -> Vec<u8> {
|
||||
self.inner.add(&other.borrow_buf())
|
||||
}
|
||||
@@ -512,23 +511,15 @@ impl PyBytes {
|
||||
self.inner.title().into()
|
||||
}
|
||||
|
||||
#[pymethod(name = "__rmul__")]
|
||||
#[pymethod]
|
||||
fn __mul__(zelf: PyRef<Self>, value: ArgIndex, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
|
||||
zelf.repeat(value.into_int_ref().try_to_primitive(vm)?, vm)
|
||||
}
|
||||
|
||||
#[pymethod(name = "__mod__")]
|
||||
fn mod_(&self, values: PyObjectRef, vm: &VirtualMachine) -> PyResult<Self> {
|
||||
fn __mod__(&self, values: PyObjectRef, vm: &VirtualMachine) -> PyResult<Self> {
|
||||
let formatted = self.inner.cformat(values, vm)?;
|
||||
Ok(formatted.into())
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __rmod__(&self, _values: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef {
|
||||
vm.ctx.not_implemented()
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __getnewargs__(&self, vm: &VirtualMachine) -> PyTupleRef {
|
||||
let param: Vec<PyObjectRef> = self.elements().map(|x| x.to_pyobject(vm)).collect();
|
||||
@@ -677,7 +668,7 @@ impl AsNumber for PyBytes {
|
||||
static AS_NUMBER: PyNumberMethods = PyNumberMethods {
|
||||
remainder: Some(|a, b, vm| {
|
||||
if let Some(a) = a.downcast_ref::<PyBytes>() {
|
||||
a.mod_(b.to_owned(), vm).to_pyresult(vm)
|
||||
a.__mod__(b.to_owned(), vm).to_pyresult(vm)
|
||||
} else {
|
||||
Ok(vm.ctx.not_implemented())
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use crate::{
|
||||
class::PyClassImpl,
|
||||
common::hash::PyHash,
|
||||
convert::{ToPyObject, ToPyResult},
|
||||
function::{FuncArgs, PyMethodDef, PyMethodFlags, PySetterValue},
|
||||
function::{ArgSize, FuncArgs, PyMethodDef, PyMethodFlags, PySetterValue},
|
||||
protocol::{PyNumberBinaryFunc, PyNumberTernaryFunc, PyNumberUnaryFunc},
|
||||
types::{
|
||||
Callable, Comparable, DelFunc, DescrGetFunc, DescrSetFunc, GenericMethod, GetDescriptor,
|
||||
@@ -593,8 +593,8 @@ impl SlotFunc {
|
||||
func(obj.sequence_unchecked(), &other, vm)
|
||||
}
|
||||
SlotFunc::SeqRepeat(func) => {
|
||||
let (n,): (isize,) = args.bind(vm)?;
|
||||
func(obj.sequence_unchecked(), n, vm)
|
||||
let (n,): (ArgSize,) = args.bind(vm)?;
|
||||
func(obj.sequence_unchecked(), n.into(), vm)
|
||||
}
|
||||
SlotFunc::SeqItem(func) => {
|
||||
let (index,): (isize,) = args.bind(vm)?;
|
||||
@@ -774,6 +774,15 @@ impl Callable for PyMethodWrapper {
|
||||
type Args = FuncArgs;
|
||||
|
||||
fn call(zelf: &Py<Self>, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
|
||||
// bpo-37619: Check type compatibility before calling wrapped slot
|
||||
if !zelf.obj.fast_isinstance(zelf.wrapper.typ) {
|
||||
return Err(vm.new_type_error(format!(
|
||||
"descriptor '{}' requires a '{}' object but received a '{}'",
|
||||
zelf.wrapper.name.as_str(),
|
||||
zelf.wrapper.typ.name(),
|
||||
zelf.obj.class().name()
|
||||
)));
|
||||
}
|
||||
zelf.wrapper.wrapped.call(zelf.obj.clone(), args, vm)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -293,7 +293,6 @@ impl PyDict {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __or__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
let other_dict: Result<PyDictRef, _> = other.downcast();
|
||||
if let Ok(other) = other_dict {
|
||||
@@ -403,13 +402,11 @@ impl PyRef<PyDict> {
|
||||
PyDictReverseKeyIterator::new(self)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __ior__(self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult<Self> {
|
||||
self.merge_object(other, vm)?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __ror__(self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
let other_dict: Result<Self, _> = other.downcast();
|
||||
if let Ok(other) = other_dict {
|
||||
@@ -1046,38 +1043,30 @@ trait ViewSetOps: DictView {
|
||||
PySetInner::from_iter(iter, vm)
|
||||
}
|
||||
|
||||
#[pymethod(name = "__rxor__")]
|
||||
#[pymethod]
|
||||
fn __xor__(zelf: PyRef<Self>, other: ArgIterable, vm: &VirtualMachine) -> PyResult<PySet> {
|
||||
let zelf = Self::to_set(zelf, vm)?;
|
||||
let inner = zelf.symmetric_difference(other, vm)?;
|
||||
Ok(PySet { inner })
|
||||
}
|
||||
|
||||
#[pymethod(name = "__rand__")]
|
||||
#[pymethod]
|
||||
fn __and__(zelf: PyRef<Self>, other: ArgIterable, vm: &VirtualMachine) -> PyResult<PySet> {
|
||||
let zelf = Self::to_set(zelf, vm)?;
|
||||
let inner = zelf.intersection(other, vm)?;
|
||||
Ok(PySet { inner })
|
||||
}
|
||||
|
||||
#[pymethod(name = "__ror__")]
|
||||
#[pymethod]
|
||||
fn __or__(zelf: PyRef<Self>, other: ArgIterable, vm: &VirtualMachine) -> PyResult<PySet> {
|
||||
let zelf = Self::to_set(zelf, vm)?;
|
||||
let inner = zelf.union(other, vm)?;
|
||||
Ok(PySet { inner })
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __sub__(zelf: PyRef<Self>, other: ArgIterable, vm: &VirtualMachine) -> PyResult<PySet> {
|
||||
let zelf = Self::to_set(zelf, vm)?;
|
||||
let inner = zelf.difference(other, vm)?;
|
||||
Ok(PySet { inner })
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __rsub__(zelf: PyRef<Self>, other: ArgIterable, vm: &VirtualMachine) -> PyResult<PySet> {
|
||||
let left = PySetInner::from_iter(other.iter(vm)?, vm)?;
|
||||
let right = ArgIterable::try_from_object(vm, Self::iter(zelf, vm)?)?;
|
||||
|
||||
@@ -236,12 +236,10 @@ impl PyGenericAlias {
|
||||
Err(vm.new_type_error("issubclass() argument 2 cannot be a parameterized generic"))
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __ror__(zelf: PyObjectRef, other: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef {
|
||||
type_::or_(other, zelf, vm)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __or__(zelf: PyObjectRef, other: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef {
|
||||
type_::or_(zelf, other, vm)
|
||||
}
|
||||
|
||||
@@ -145,7 +145,6 @@ impl PyList {
|
||||
Ok(Self::from(elements).into_ref(&vm.ctx))
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __add__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
|
||||
self.concat(&other, vm)
|
||||
}
|
||||
@@ -160,7 +159,6 @@ impl PyList {
|
||||
Ok(zelf.to_owned().into())
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __iadd__(
|
||||
zelf: PyRef<Self>,
|
||||
other: PyObjectRef,
|
||||
@@ -240,13 +238,10 @@ impl PyList {
|
||||
self._setitem(&needle, value, vm)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
#[pymethod(name = "__rmul__")]
|
||||
fn __mul__(&self, n: ArgSize, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
|
||||
self.repeat(n.into(), vm)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __imul__(zelf: PyRef<Self>, n: ArgSize, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
|
||||
Self::irepeat(zelf, n.into(), vm)
|
||||
}
|
||||
|
||||
@@ -191,7 +191,6 @@ impl PyMappingProxy {
|
||||
)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __ior__(&self, _args: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
Err(vm.new_type_error(format!(
|
||||
r#""'|=' is not supported by {}; use '|' instead""#,
|
||||
@@ -199,8 +198,6 @@ impl PyMappingProxy {
|
||||
)))
|
||||
}
|
||||
|
||||
#[pymethod(name = "__ror__")]
|
||||
#[pymethod]
|
||||
fn __or__(&self, args: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
vm._or(self.copy(vm)?.as_ref(), args.as_ref())
|
||||
}
|
||||
|
||||
@@ -541,7 +541,6 @@ impl Py<PyStr> {
|
||||
)
|
||||
)]
|
||||
impl PyStr {
|
||||
#[pymethod]
|
||||
fn __add__(zelf: PyRef<Self>, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
if let Some(other) = other.downcast_ref::<Self>() {
|
||||
let bytes = zelf.as_wtf8().py_add(other.as_wtf8());
|
||||
@@ -636,8 +635,6 @@ impl PyStr {
|
||||
core::mem::size_of::<Self>() + self.byte_len() * core::mem::size_of::<u8>()
|
||||
}
|
||||
|
||||
#[pymethod(name = "__rmul__")]
|
||||
#[pymethod]
|
||||
fn __mul__(zelf: PyRef<Self>, value: ArgSize, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
|
||||
Self::repeat(zelf, value.into(), vm)
|
||||
}
|
||||
@@ -947,16 +944,10 @@ impl PyStr {
|
||||
&& self.char_all(|c| GeneralCategory::of(c) == GeneralCategory::DecimalNumber)
|
||||
}
|
||||
|
||||
#[pymethod(name = "__mod__")]
|
||||
fn modulo(&self, values: PyObjectRef, vm: &VirtualMachine) -> PyResult<Wtf8Buf> {
|
||||
fn __mod__(&self, values: PyObjectRef, vm: &VirtualMachine) -> PyResult<Wtf8Buf> {
|
||||
cformat_string(vm, self.as_wtf8(), values)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __rmod__(&self, _values: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef {
|
||||
vm.ctx.not_implemented()
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn format(&self, args: FuncArgs, vm: &VirtualMachine) -> PyResult<Wtf8Buf> {
|
||||
let format_str =
|
||||
@@ -1564,7 +1555,7 @@ impl AsNumber for PyStr {
|
||||
static AS_NUMBER: PyNumberMethods = PyNumberMethods {
|
||||
remainder: Some(|a, b, vm| {
|
||||
if let Some(a) = a.downcast_ref::<PyStr>() {
|
||||
a.modulo(b.to_owned(), vm).to_pyresult(vm)
|
||||
a.__mod__(b.to_owned(), vm).to_pyresult(vm)
|
||||
} else {
|
||||
Ok(vm.ctx.not_implemented())
|
||||
}
|
||||
|
||||
@@ -263,7 +263,6 @@ impl<T> PyTuple<PyRef<T>> {
|
||||
with(AsMapping, AsNumber, AsSequence, Hashable, Comparable, Iterable, Constructor, Representable)
|
||||
)]
|
||||
impl PyTuple {
|
||||
#[pymethod]
|
||||
fn __add__(
|
||||
zelf: PyRef<Self>,
|
||||
other: PyObjectRef,
|
||||
@@ -302,8 +301,6 @@ impl PyTuple {
|
||||
self.elements.len()
|
||||
}
|
||||
|
||||
#[pymethod(name = "__rmul__")]
|
||||
#[pymethod]
|
||||
fn __mul__(zelf: PyRef<Self>, value: ArgSize, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
|
||||
Self::repeat(zelf, value.into(), vm)
|
||||
}
|
||||
|
||||
@@ -951,12 +951,10 @@ impl PyType {
|
||||
)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
pub fn __ror__(zelf: PyObjectRef, other: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef {
|
||||
or_(other, zelf, vm)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
pub fn __or__(zelf: PyObjectRef, other: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef {
|
||||
or_(zelf, other, vm)
|
||||
}
|
||||
|
||||
@@ -136,8 +136,6 @@ impl PyUnion {
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(name = "__ror__")]
|
||||
#[pymethod]
|
||||
fn __or__(zelf: PyObjectRef, other: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef {
|
||||
type_::or_(zelf, other, vm)
|
||||
}
|
||||
|
||||
@@ -332,8 +332,6 @@ mod _collections {
|
||||
Ok(deque)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
#[pymethod(name = "__rmul__")]
|
||||
fn __mul__(&self, n: isize, vm: &VirtualMachine) -> PyResult<Self> {
|
||||
let deque = self._mul(n, vm)?;
|
||||
Ok(Self {
|
||||
@@ -343,7 +341,6 @@ mod _collections {
|
||||
})
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __imul__(zelf: PyRef<Self>, n: isize, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
|
||||
let mul_deque = zelf._mul(n, vm)?;
|
||||
*zelf.borrow_deque_mut() = mul_deque;
|
||||
@@ -379,7 +376,6 @@ mod _collections {
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __iadd__(
|
||||
zelf: PyRef<Self>,
|
||||
other: PyObjectRef,
|
||||
|
||||
@@ -137,7 +137,6 @@ impl PyCPointerType {
|
||||
)))
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __mul__(cls: PyTypeRef, n: isize, vm: &VirtualMachine) -> PyResult {
|
||||
use super::array::array_type_from_ctype;
|
||||
|
||||
|
||||
@@ -488,7 +488,6 @@ impl PyCSimpleType {
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __mul__(cls: PyTypeRef, n: isize, vm: &VirtualMachine) -> PyResult {
|
||||
PyCSimple::repeat(cls, n, vm)
|
||||
}
|
||||
|
||||
@@ -393,7 +393,6 @@ impl PyCStructType {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __mul__(cls: PyTypeRef, n: isize, vm: &VirtualMachine) -> PyResult {
|
||||
use super::array::array_type_from_ctype;
|
||||
|
||||
|
||||
+42
-12
@@ -438,6 +438,16 @@ fn sequence_contains_wrapper(
|
||||
contains_wrapper(seq.obj, needle, vm)
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn sequence_repeat_wrapper(seq: PySequence<'_>, n: isize, vm: &VirtualMachine) -> PyResult {
|
||||
vm.call_special_method(seq.obj, identifier!(vm, __mul__), (n,))
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn sequence_inplace_repeat_wrapper(seq: PySequence<'_>, n: isize, vm: &VirtualMachine) -> PyResult {
|
||||
vm.call_special_method(seq.obj, identifier!(vm, __imul__), (n,))
|
||||
}
|
||||
|
||||
fn repr_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<PyRef<PyStr>> {
|
||||
let ret = vm.call_special_method(zelf, identifier!(vm, __repr__), ())?;
|
||||
ret.downcast::<PyStr>().map_err(|obj| {
|
||||
@@ -1294,12 +1304,16 @@ impl PyType {
|
||||
accessor.inherit_from_mro(self);
|
||||
}
|
||||
}
|
||||
SlotAccessor::SqRepeat | SlotAccessor::SqInplaceRepeat => {
|
||||
// Sequence repeat uses sq_repeat slot - no generic wrapper needed
|
||||
// (handled by number protocol fallback)
|
||||
if !ADD {
|
||||
accessor.inherit_from_mro(self);
|
||||
}
|
||||
SlotAccessor::SqRepeat => {
|
||||
update_sub_slot!(as_sequence, repeat, sequence_repeat_wrapper, SeqRepeat)
|
||||
}
|
||||
SlotAccessor::SqInplaceRepeat => {
|
||||
update_sub_slot!(
|
||||
as_sequence,
|
||||
inplace_repeat,
|
||||
sequence_inplace_repeat_wrapper,
|
||||
SeqRepeat
|
||||
)
|
||||
}
|
||||
SlotAccessor::SqItem => {
|
||||
update_sub_slot!(as_sequence, item, sequence_getitem_wrapper, SeqItem)
|
||||
@@ -1348,28 +1362,44 @@ impl PyType {
|
||||
) -> Option<T> {
|
||||
use crate::builtins::descriptor::PyWrapper;
|
||||
|
||||
// Helper to check if a class is a subclass of another by checking MRO
|
||||
let is_subclass_of = |subclass_mro: &[PyRef<PyType>], superclass: &Py<PyType>| -> bool {
|
||||
subclass_mro.iter().any(|c| c.is(superclass))
|
||||
};
|
||||
|
||||
// Helper to extract slot from an attribute if it's a wrapper descriptor
|
||||
let try_extract = |attr: &PyObjectRef| -> Option<T> {
|
||||
// and the wrapper's type is compatible with the given class.
|
||||
// bpo-37619: wrapper descriptor from wrong class should not be used directly.
|
||||
let try_extract = |attr: &PyObjectRef, for_class_mro: &[PyRef<PyType>]| -> Option<T> {
|
||||
if attr.class().is(ctx.types.wrapper_descriptor_type) {
|
||||
attr.downcast_ref::<PyWrapper>()
|
||||
.and_then(|wrapper| extract(&wrapper.wrapped))
|
||||
attr.downcast_ref::<PyWrapper>().and_then(|wrapper| {
|
||||
// Only extract slot if for_class is a subclass of wrapper.typ
|
||||
if is_subclass_of(for_class_mro, wrapper.typ) {
|
||||
extract(&wrapper.wrapped)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
let mro = self.mro.read();
|
||||
|
||||
// Look up in self's dict first
|
||||
if let Some(attr) = self.attributes.read().get(name).cloned() {
|
||||
if let Some(func) = try_extract(&attr) {
|
||||
if let Some(func) = try_extract(&attr, &mro) {
|
||||
return Some(func);
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
// Look up in MRO (mro[0] is self, so skip it)
|
||||
for cls in self.mro.read()[1..].iter() {
|
||||
for (i, cls) in mro[1..].iter().enumerate() {
|
||||
if let Some(attr) = cls.attributes.read().get(name).cloned() {
|
||||
if let Some(func) = try_extract(&attr) {
|
||||
// Use the slice starting from this class in MRO
|
||||
if let Some(func) = try_extract(&attr, &mro[i + 1..]) {
|
||||
return Some(func);
|
||||
}
|
||||
return None;
|
||||
|
||||
Reference in new issue
Block a user