diff --git a/.cspell.json b/.cspell.json index 6112c35d590..9f88a74f96d 100644 --- a/.cspell.json +++ b/.cspell.json @@ -60,6 +60,7 @@ "dedentations", "dedents", "deduped", + "downcastable", "downcasted", "dumpable", "emscripten", diff --git a/stdlib/src/array.rs b/stdlib/src/array.rs index 05d059e4242..2327c552366 100644 --- a/stdlib/src/array.rs +++ b/stdlib/src/array.rs @@ -667,7 +667,7 @@ mod array { ArrayContentType::from_char(spec).map_err(|err| vm.new_value_error(err))?; if let OptionalArg::Present(init) = init { - if let Some(init) = init.payload::() { + if let Some(init) = init.downcast_ref::() { match (spec, init.read().typecode()) { (spec, ch) if spec == ch => array.frombytes(&init.get_bytes()), (spec, 'u') => { @@ -681,7 +681,7 @@ mod array { } } } - } else if let Some(wtf8) = init.payload::() { + } else if let Some(wtf8) = init.downcast_ref::() { if spec == 'u' { let bytes = Self::_unicode_to_wchar_bytes(wtf8.as_wtf8(), array.itemsize()); array.frombytes_move(bytes); @@ -690,7 +690,7 @@ mod array { "cannot use a str to initialize an array with typecode '{spec}'" ))); } - } else if init.payload_is::() || init.payload_is::() { + } else if init.downcastable::() || init.downcastable::() { init.try_bytes_like(vm, |x| array.frombytes(x))?; } else if let Ok(iter) = ArgIterable::try_from_object(vm, init.clone()) { for obj in iter.iter(vm)? { @@ -765,7 +765,7 @@ mod array { let mut w = zelf.try_resizable(vm)?; if zelf.is(&obj) { w.imul(2, vm) - } else if let Some(array) = obj.payload::() { + } else if let Some(array) = obj.downcast_ref::() { w.iadd(&array.read(), vm) } else { let iter = ArgIterable::try_from_object(vm, obj)?; @@ -1013,7 +1013,7 @@ mod array { cloned = zelf.read().clone(); &cloned } else { - match value.payload::() { + match value.downcast_ref::() { Some(array) => { guard = array.read(); &*guard @@ -1059,7 +1059,7 @@ mod array { #[pymethod] fn __add__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult> { - if let Some(other) = other.payload::() { + if let Some(other) = other.downcast_ref::() { self.read() .add(&other.read(), vm) .map(|array| Self::from(array).into_ref(&vm.ctx)) @@ -1079,7 +1079,7 @@ mod array { ) -> PyResult> { if zelf.is(&other) { zelf.try_resizable(vm)?.imul(2, vm)?; - } else if let Some(other) = other.payload::() { + } else if let Some(other) = other.downcast_ref::() { zelf.try_resizable(vm)?.iadd(&other.read(), vm)?; } else { return Err(vm.new_type_error(format!( diff --git a/stdlib/src/csv.rs b/stdlib/src/csv.rs index a5add740f4a..bded06e37fa 100644 --- a/stdlib/src/csv.rs +++ b/stdlib/src/csv.rs @@ -269,7 +269,7 @@ mod _csv { mut _rest: FuncArgs, vm: &VirtualMachine, ) -> PyResult<()> { - let Some(name) = name.payload_if_subclass::(vm) else { + let Some(name) = name.downcast_ref::() else { return Err(vm.new_type_error("argument 0 must be a string")); }; let dialect = match dialect { @@ -290,7 +290,7 @@ mod _csv { mut _rest: FuncArgs, vm: &VirtualMachine, ) -> PyResult { - let Some(name) = name.payload_if_subclass::(vm) else { + let Some(name) = name.downcast_ref::() else { return Err(vm.new_exception_msg( super::_csv::error(vm), format!("argument 0 must be a string, not '{}'", name.class()), @@ -309,7 +309,7 @@ mod _csv { mut _rest: FuncArgs, vm: &VirtualMachine, ) -> PyResult<()> { - let Some(name) = name.payload_if_subclass::(vm) else { + let Some(name) = name.downcast_ref::() else { return Err(vm.new_exception_msg( super::_csv::error(vm), format!("argument 0 must be a string, not '{}'", name.class()), diff --git a/stdlib/src/select.rs b/stdlib/src/select.rs index d502313566b..b19fecc9fb0 100644 --- a/stdlib/src/select.rs +++ b/stdlib/src/select.rs @@ -350,7 +350,7 @@ mod decl { fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult { let timeout = if vm.is_none(&obj) { None - } else if let Some(float) = obj.payload::() { + } else if let Some(float) = obj.downcast_ref::() { let float = float.to_f64(); if float.is_nan() { return Err(vm.new_value_error("Invalid value NaN (not a number)")); diff --git a/stdlib/src/sqlite.rs b/stdlib/src/sqlite.rs index 7eb8f86db2b..744da0cf6ee 100644 --- a/stdlib/src/sqlite.rs +++ b/stdlib/src/sqlite.rs @@ -535,7 +535,7 @@ mod _sqlite { let access = ptr_to_str(access, vm)?; let val = callable.call((action, arg1, arg2, db_name, access), vm)?; - let Some(val) = val.payload::() else { + let Some(val) = val.downcast_ref::() else { return Ok(SQLITE_DENY); }; val.try_to_primitive::(vm) @@ -1897,18 +1897,18 @@ mod _sqlite { Ok(self .description .iter() - .map(|x| x.payload::().unwrap().as_slice()[0].clone()) + .map(|x| x.downcast_ref::().unwrap().as_slice()[0].clone()) .collect()) } fn subscript(&self, needle: &PyObject, vm: &VirtualMachine) -> PyResult { - if let Some(i) = needle.payload::() { + if let Some(i) = needle.downcast_ref::() { let i = i.try_to_primitive::(vm)?; self.data.getitem_by_index(vm, i) - } else if let Some(name) = needle.payload::() { + } else if let Some(name) = needle.downcast_ref::() { for (obj, i) in self.description.iter().zip(0..) { - let obj = &obj.payload::().unwrap().as_slice()[0]; - let Some(obj) = obj.payload::() else { + let obj = &obj.downcast_ref::().unwrap().as_slice()[0]; + let Some(obj) = obj.downcast_ref::() else { break; }; let a_iter = name.as_str().chars().flat_map(|x| x.to_uppercase()); @@ -1919,7 +1919,7 @@ mod _sqlite { } } Err(vm.new_index_error("No item with that key")) - } else if let Some(slice) = needle.payload::() { + } else if let Some(slice) = needle.downcast_ref::() { let list = self.data.getitem_by_slice(vm, slice.to_saturated(vm)?)?; Ok(vm.ctx.new_tuple(list).into()) } else { @@ -1962,7 +1962,7 @@ mod _sqlite { vm: &VirtualMachine, ) -> PyResult { op.eq_only(|| { - if let Some(other) = other.payload::() { + if let Some(other) = other.downcast_ref::() { let eq = vm .bool_eq(zelf.description.as_object(), other.description.as_object())? && vm.bool_eq(zelf.data.as_object(), other.data.as_object())?; @@ -2179,7 +2179,7 @@ mod _sqlite { let mut byte: u8 = 0; let ret = inner.blob.read_single(&mut byte, index); self.check(ret, vm).map(|_| vm.ctx.new_int(byte).into()) - } else if let Some(slice) = needle.payload::() { + } else if let Some(slice) = needle.downcast_ref::() { let blob_len = inner.blob.bytes(); let slice = slice.to_saturated(vm)?; let (range, step, length) = slice.adjust_indices(blob_len as usize); @@ -2220,7 +2220,7 @@ mod _sqlite { let inner = self.inner(vm)?; if let Some(index) = needle.try_index_opt(vm) { - let Some(value) = value.payload::() else { + let Some(value) = value.downcast_ref::() else { return Err(vm.new_type_error(format!( "'{}' object cannot be interpreted as an integer", value.class() @@ -2232,7 +2232,7 @@ mod _sqlite { Self::expect_write(blob_len, 1, index, vm)?; let ret = inner.blob.write_single(value, index); self.check(ret, vm) - } else if let Some(_slice) = needle.payload::() { + } else if let Some(_slice) = needle.downcast_ref::() { Err(vm.new_not_implemented_error("Blob slice assignment is not implemented")) // let blob_len = inner.blob.bytes(); // let slice = slice.to_saturated(vm)?; @@ -2645,15 +2645,15 @@ mod _sqlite { let ret = if vm.is_none(obj) { unsafe { sqlite3_bind_null(self.st, pos) } - } else if let Some(val) = obj.payload::() { + } else if let Some(val) = obj.downcast_ref::() { let val = val.try_to_primitive::(vm).map_err(|_| { vm.new_overflow_error("Python int too large to convert to SQLite INTEGER") })?; unsafe { sqlite3_bind_int64(self.st, pos, val) } - } else if let Some(val) = obj.payload::() { + } else if let Some(val) = obj.downcast_ref::() { let val = val.to_f64(); unsafe { sqlite3_bind_double(self.st, pos, val) } - } else if let Some(val) = obj.payload::() { + } else if let Some(val) = obj.downcast_ref::() { let (ptr, len) = str_to_ptr_len(val, vm)?; unsafe { sqlite3_bind_text(self.st, pos, ptr, len, SQLITE_TRANSIENT()) } } else if let Ok(buffer) = PyBuffer::try_from_borrowed_object(vm, obj) { @@ -2900,11 +2900,11 @@ mod _sqlite { unsafe { if vm.is_none(val) { sqlite3_result_null(self.ctx) - } else if let Some(val) = val.payload::() { + } else if let Some(val) = val.downcast_ref::() { sqlite3_result_int64(self.ctx, val.try_to_primitive(vm)?) - } else if let Some(val) = val.payload::() { + } else if let Some(val) = val.downcast_ref::() { sqlite3_result_double(self.ctx, val.to_f64()) - } else if let Some(val) = val.payload::() { + } else if let Some(val) = val.downcast_ref::() { let (ptr, len) = str_to_ptr_len(val, vm)?; sqlite3_result_text(self.ctx, ptr, len, SQLITE_TRANSIENT()) } else if let Ok(buffer) = PyBuffer::try_from_borrowed_object(vm, val) { diff --git a/stdlib/src/termios.rs b/stdlib/src/termios.rs index 5bd8395ec31..a9ae1375c6f 100644 --- a/stdlib/src/termios.rs +++ b/stdlib/src/termios.rs @@ -217,9 +217,12 @@ mod termios { )) })?; for (cc, x) in termios.c_cc.iter_mut().zip(cc.iter()) { - *cc = if let Some(c) = x.payload::().filter(|b| b.as_bytes().len() == 1) { + *cc = if let Some(c) = x + .downcast_ref::() + .filter(|b| b.as_bytes().len() == 1) + { c.as_bytes()[0] as _ - } else if let Some(i) = x.payload::() { + } else if let Some(i) = x.downcast_ref::() { i.try_to_primitive(vm)? } else { return Err(vm.new_type_error( diff --git a/vm/src/builtins/asyncgenerator.rs b/vm/src/builtins/asyncgenerator.rs index 05e8b51514f..f9389263980 100644 --- a/vm/src/builtins/asyncgenerator.rs +++ b/vm/src/builtins/asyncgenerator.rs @@ -344,7 +344,9 @@ impl PyAsyncGenAThrow { let ret = self.ag.inner.send(self.ag.as_object(), val, vm); if self.aclose { match ret { - Ok(PyIterReturn::Return(v)) if v.payload_is::() => { + Ok(PyIterReturn::Return(v)) + if v.downcastable::() => + { Err(self.yield_close(vm)) } other => other @@ -392,7 +394,7 @@ impl PyAsyncGenAThrow { fn ignored_close(&self, res: &PyResult) -> bool { res.as_ref().is_ok_and(|v| match v { - PyIterReturn::Return(obj) => obj.payload_is::(), + PyIterReturn::Return(obj) => obj.downcastable::(), PyIterReturn::StopIteration(_) => false, }) } diff --git a/vm/src/builtins/bool.rs b/vm/src/builtins/bool.rs index c21db81d569..a7569e2f889 100644 --- a/vm/src/builtins/bool.rs +++ b/vm/src/builtins/bool.rs @@ -57,7 +57,7 @@ impl PyObjectRef { Some(method_or_err) => { let method = method_or_err?; let bool_obj = method.call((), vm)?; - let int_obj = bool_obj.payload::().ok_or_else(|| { + let int_obj = bool_obj.downcast_ref::().ok_or_else(|| { vm.new_type_error(format!( "'{}' object cannot be interpreted as an integer", bool_obj.class().name() @@ -128,8 +128,8 @@ impl PyBool { let lhs = get_value(&lhs); let rhs = get_value(&rhs); (lhs || rhs).to_pyobject(vm) - } else if let Some(lhs) = lhs.payload::() { - lhs.__or__(rhs, vm).to_pyobject(vm) + } else if let Some(lhs) = lhs.downcast_ref::() { + lhs.__or__(rhs).to_pyobject(vm) } else { vm.ctx.not_implemented() } @@ -144,8 +144,8 @@ impl PyBool { let lhs = get_value(&lhs); let rhs = get_value(&rhs); (lhs && rhs).to_pyobject(vm) - } else if let Some(lhs) = lhs.payload::() { - lhs.__and__(rhs, vm).to_pyobject(vm) + } else if let Some(lhs) = lhs.downcast_ref::() { + lhs.__and__(rhs).to_pyobject(vm) } else { vm.ctx.not_implemented() } @@ -160,8 +160,8 @@ impl PyBool { let lhs = get_value(&lhs); let rhs = get_value(&rhs); (lhs ^ rhs).to_pyobject(vm) - } else if let Some(lhs) = lhs.payload::() { - lhs.__xor__(rhs, vm).to_pyobject(vm) + } else if let Some(lhs) = lhs.downcast_ref::() { + lhs.__xor__(rhs).to_pyobject(vm) } else { vm.ctx.not_implemented() } @@ -212,5 +212,5 @@ pub(crate) fn init(context: &Context) { // Retrieve inner int value: pub(crate) fn get_value(obj: &PyObject) -> bool { - !obj.payload::().unwrap().as_bigint().is_zero() + !obj.downcast_ref::().unwrap().as_bigint().is_zero() } diff --git a/vm/src/builtins/builtin_func.rs b/vm/src/builtins/builtin_func.rs index 51729b4ce65..464f47f13c9 100644 --- a/vm/src/builtins/builtin_func.rs +++ b/vm/src/builtins/builtin_func.rs @@ -213,7 +213,7 @@ impl Comparable for PyNativeMethod { _vm: &VirtualMachine, ) -> PyResult { op.eq_only(|| { - if let Some(other) = other.payload::() { + if let Some(other) = other.downcast_ref::() { let eq = match (zelf.func.zelf.as_ref(), other.func.zelf.as_ref()) { (Some(z), Some(o)) => z.is(o), (None, None) => true, diff --git a/vm/src/builtins/complex.rs b/vm/src/builtins/complex.rs index 11c78266498..a7a4049de88 100644 --- a/vm/src/builtins/complex.rs +++ b/vm/src/builtins/complex.rs @@ -58,7 +58,7 @@ impl PyObjectRef { /// Tries converting a python object into a complex, returns an option of whether the complex /// and whether the object was a complex originally or coerced into one pub fn try_complex(&self, vm: &VirtualMachine) -> PyResult> { - if let Some(complex) = self.payload_if_exact::(vm) { + if let Some(complex) = self.downcast_ref_if_exact::(vm) { return Ok(Some((complex.value, true))); } if let Some(method) = vm.get_method(self.clone(), identifier!(vm, __complex__)) { @@ -79,7 +79,7 @@ impl PyObjectRef { return Ok(Some((ret.value, true))); } else { - return match result.payload::() { + return match result.downcast_ref::() { Some(complex_obj) => Ok(Some((complex_obj.value, true))), None => Err(vm.new_type_error(format!( "__complex__ returned non-complex (type '{}')", @@ -90,7 +90,7 @@ impl PyObjectRef { } // `complex` does not have a `__complex__` by default, so subclasses might not either, // use the actual stored value in this case - if let Some(complex) = self.payload_if_subclass::(vm) { + if let Some(complex) = self.downcast_ref::() { return Ok(Some((complex.value, true))); } if let Some(float) = self.try_float_opt(vm) { @@ -105,7 +105,7 @@ pub fn init(context: &Context) { } fn to_op_complex(value: &PyObject, vm: &VirtualMachine) -> PyResult> { - let r = if let Some(complex) = value.payload_if_subclass::(vm) { + let r = if let Some(complex) = value.downcast_ref::() { Some(complex.value) } else { float::to_op_float(value, vm)?.map(|float| Complex64::new(float, 0.0)) @@ -175,7 +175,7 @@ impl Constructor for PyComplex { if let Some(c) = val.try_complex(vm)? { c - } else if let Some(s) = val.payload_if_subclass::(vm) { + } else if let Some(s) = val.downcast_ref::() { if args.imag.is_present() { return Err(vm.new_type_error( "complex() can't take second arg if first is a string", @@ -419,7 +419,7 @@ impl Comparable for PyComplex { vm: &VirtualMachine, ) -> PyResult { op.eq_only(|| { - let result = if let Some(other) = other.payload_if_subclass::(vm) { + let result = if let Some(other) = other.downcast_ref::() { if zelf.value.re.is_nan() && zelf.value.im.is_nan() && other.value.re.is_nan() diff --git a/vm/src/builtins/float.rs b/vm/src/builtins/float.rs index 4982615b048..33c99f6e146 100644 --- a/vm/src/builtins/float.rs +++ b/vm/src/builtins/float.rs @@ -57,9 +57,9 @@ impl From for PyFloat { } pub(crate) fn to_op_float(obj: &PyObject, vm: &VirtualMachine) -> PyResult> { - let v = if let Some(float) = obj.payload_if_subclass::(vm) { + let v = if let Some(float) = obj.downcast_ref::() { Some(float.value) - } else if let Some(int) = obj.payload_if_subclass::(vm) { + } else if let Some(int) = obj.downcast_ref::() { Some(try_bigint_to_f64(int.as_bigint(), vm)?) } else { None @@ -154,7 +154,7 @@ impl Constructor for PyFloat { fn float_from_string(val: PyObjectRef, vm: &VirtualMachine) -> PyResult { let (bytearray, buffer, buffer_lock, mapped_string); - let b = if let Some(s) = val.payload_if_subclass::(vm) { + let b = if let Some(s) = val.downcast_ref::() { use crate::common::str::PyKindStr; match s.as_str_kind() { PyKindStr::Ascii(s) => s.trim().as_bytes(), @@ -178,9 +178,9 @@ fn float_from_string(val: PyObjectRef, vm: &VirtualMachine) -> PyResult { // so we can just choose a known bad value PyKindStr::Wtf8(_) => b"", } - } else if let Some(bytes) = val.payload_if_subclass::(vm) { + } else if let Some(bytes) = val.downcast_ref::() { bytes.as_bytes() - } else if let Some(buf) = val.payload_if_subclass::(vm) { + } else if let Some(buf) = val.downcast_ref::() { bytearray = buf.borrow_buf(); &*bytearray } else if let Ok(b) = ArgBytesLike::try_from_borrowed_object(vm, &val) { @@ -521,13 +521,13 @@ impl Comparable for PyFloat { zelf: &Py, other: &PyObject, op: PyComparisonOp, - vm: &VirtualMachine, + _vm: &VirtualMachine, ) -> PyResult { - let ret = if let Some(other) = other.payload_if_subclass::(vm) { + let ret = if let Some(other) = other.downcast_ref::() { zelf.value .partial_cmp(&other.value) .map_or_else(|| op == PyComparisonOp::Ne, |ord| op.eval_ord(ord)) - } else if let Some(other) = other.payload_if_subclass::(vm) { + } else if let Some(other) = other.downcast_ref::() { let a = zelf.to_f64(); let b = other.as_bigint(); match op { @@ -633,7 +633,7 @@ impl PyFloat { // Retrieve inner float value: #[cfg(feature = "serde")] pub(crate) fn get_value(obj: &PyObject) -> f64 { - obj.payload::().unwrap().value + obj.downcast_ref::().unwrap().value } #[rustfmt::skip] // to avoid line splitting diff --git a/vm/src/builtins/int.rs b/vm/src/builtins/int.rs index 8ae8f30881d..ebeb1638fd4 100644 --- a/vm/src/builtins/int.rs +++ b/vm/src/builtins/int.rs @@ -293,12 +293,12 @@ impl PyInt { } #[inline] - fn int_op(&self, other: PyObjectRef, op: F, vm: &VirtualMachine) -> PyArithmeticValue + fn int_op(&self, other: PyObjectRef, op: F) -> PyArithmeticValue where F: Fn(&BigInt, &BigInt) -> BigInt, { let r = other - .payload_if_subclass::(vm) + .downcast_ref::() .map(|other| op(&self.value, &other.value)); PyArithmeticValue::from_option(r) } @@ -308,7 +308,7 @@ impl PyInt { where F: Fn(&BigInt, &BigInt) -> PyResult, { - if let Some(other) = other.payload_if_subclass::(vm) { + if let Some(other) = other.downcast_ref::() { op(&self.value, &other.value) } else { Ok(vm.ctx.not_implemented()) @@ -323,24 +323,24 @@ impl PyInt { impl PyInt { #[pymethod(name = "__radd__")] #[pymethod] - fn __add__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyArithmeticValue { - self.int_op(other, |a, b| a + b, vm) + fn __add__(&self, other: PyObjectRef) -> PyArithmeticValue { + self.int_op(other, |a, b| a + b) } #[pymethod] - fn __sub__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyArithmeticValue { - self.int_op(other, |a, b| a - b, vm) + fn __sub__(&self, other: PyObjectRef) -> PyArithmeticValue { + self.int_op(other, |a, b| a - b) } #[pymethod] - fn __rsub__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyArithmeticValue { - self.int_op(other, |a, b| b - a, vm) + fn __rsub__(&self, other: PyObjectRef) -> PyArithmeticValue { + self.int_op(other, |a, b| b - a) } #[pymethod(name = "__rmul__")] #[pymethod] - fn __mul__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyArithmeticValue { - self.int_op(other, |a, b| a * b, vm) + fn __mul__(&self, other: PyObjectRef) -> PyArithmeticValue { + self.int_op(other, |a, b| a * b) } #[pymethod] @@ -385,24 +385,24 @@ impl PyInt { #[pymethod(name = "__rxor__")] #[pymethod] - pub fn __xor__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyArithmeticValue { - self.int_op(other, |a, b| a ^ b, vm) + pub fn __xor__(&self, other: PyObjectRef) -> PyArithmeticValue { + self.int_op(other, |a, b| a ^ b) } #[pymethod(name = "__ror__")] #[pymethod] - pub fn __or__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyArithmeticValue { - self.int_op(other, |a, b| a | b, vm) + pub fn __or__(&self, other: PyObjectRef) -> PyArithmeticValue { + self.int_op(other, |a, b| a | b) } #[pymethod(name = "__rand__")] #[pymethod] - pub fn __and__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyArithmeticValue { - self.int_op(other, |a, b| a & b, vm) + pub fn __and__(&self, other: PyObjectRef) -> PyArithmeticValue { + self.int_op(other, |a, b| a & b) } fn modpow(&self, other: PyObjectRef, modulus: PyObjectRef, vm: &VirtualMachine) -> PyResult { - let modulus = match modulus.payload_if_subclass::(vm) { + let modulus = match modulus.downcast_ref::() { Some(val) => val.as_bigint(), None => return Ok(vm.ctx.not_implemented()), }; @@ -714,10 +714,10 @@ impl Comparable for PyInt { zelf: &Py, other: &PyObject, op: PyComparisonOp, - vm: &VirtualMachine, + _vm: &VirtualMachine, ) -> PyResult { let r = other - .payload_if_subclass::(vm) + .downcast_ref::() .map(|other| op.eval_ord(zelf.value.cmp(&other.value))); Ok(PyComparisonValue::from_option(r)) } @@ -757,14 +757,7 @@ impl PyInt { remainder: Some(|a, b, vm| Self::number_op(a, b, inner_mod, vm)), divmod: Some(|a, b, vm| Self::number_op(a, b, inner_divmod, vm)), power: Some(|a, b, c, vm| { - if let (Some(a), Some(b)) = ( - a.payload::(), - if b.payload_is::() { - Some(b) - } else { - None - }, - ) { + if let Some(a) = a.downcast_ref::() { if vm.is_none(c) { a.general_op(b.to_owned(), |a, b| inner_pow(a, b, vm), vm) } else { @@ -800,7 +793,7 @@ impl PyInt { F: FnOnce(&BigInt, &BigInt, &VirtualMachine) -> R, R: ToPyResult, { - if let (Some(a), Some(b)) = (a.payload::(), b.payload::()) { + if let (Some(a), Some(b)) = (a.downcast_ref::(), b.downcast_ref::()) { op(&a.value, &b.value, vm).to_pyresult(vm) } else { Ok(vm.ctx.not_implemented()) @@ -867,7 +860,7 @@ fn try_int_radix(obj: &PyObject, base: u32, vm: &VirtualMachine) -> PyResult &BigInt { - &obj.payload::().unwrap().value + &obj.downcast_ref::().unwrap().value } pub fn try_to_float(int: &BigInt, vm: &VirtualMachine) -> PyResult { diff --git a/vm/src/builtins/iter.rs b/vm/src/builtins/iter.rs index bea427e6969..f12da710ee6 100644 --- a/vm/src/builtins/iter.rs +++ b/vm/src/builtins/iter.rs @@ -59,7 +59,7 @@ impl PositionIterInternal { F: FnOnce(&T, usize) -> usize, { if let IterStatus::Active(obj) = &self.status { - if let Some(i) = state.payload::() { + if let Some(i) = state.downcast_ref::() { let i = i.try_to_primitive(vm).unwrap_or(0); self.position = f(obj, i); Ok(()) diff --git a/vm/src/builtins/list.rs b/vm/src/builtins/list.rs index 4f05390147e..e1faff465cf 100644 --- a/vm/src/builtins/list.rs +++ b/vm/src/builtins/list.rs @@ -131,7 +131,7 @@ impl PyList { } fn concat(&self, other: &PyObject, vm: &VirtualMachine) -> PyResult> { - let other = other.payload_if_subclass::(vm).ok_or_else(|| { + let other = other.downcast_ref::().ok_or_else(|| { vm.new_type_error(format!( "Cannot add {} and {}", Self::class(&vm.ctx).name(), @@ -346,9 +346,9 @@ where F: FnMut(PyObjectRef) -> PyResult, { use crate::builtins::PyTuple; - if let Some(tuple) = obj.payload_if_exact::(vm) { + if let Some(tuple) = obj.downcast_ref_if_exact::(vm) { tuple.iter().map(|x| f(x.clone())).collect() - } else if let Some(list) = obj.payload_if_exact::(vm) { + } else if let Some(list) = obj.downcast_ref_if_exact::(vm) { list.borrow_vec().iter().map(|x| f(x.clone())).collect() } else { let iter = obj.to_owned().get_iter(vm)?; diff --git a/vm/src/builtins/mappingproxy.rs b/vm/src/builtins/mappingproxy.rs index 5ba6597e1f7..d3acc91e9bb 100644 --- a/vm/src/builtins/mappingproxy.rs +++ b/vm/src/builtins/mappingproxy.rs @@ -63,9 +63,7 @@ impl Constructor for PyMappingProxy { fn py_new(cls: PyTypeRef, mapping: Self::Args, vm: &VirtualMachine) -> PyResult { if let Some(methods) = PyMapping::find_methods(&mapping) { - if mapping.payload_if_subclass::(vm).is_none() - && mapping.payload_if_subclass::(vm).is_none() - { + if !mapping.downcastable::() && !mapping.downcastable::() { return Self { mapping: MappingProxyInner::Mapping(ArgMapping::with_methods( mapping, diff --git a/vm/src/builtins/memory.rs b/vm/src/builtins/memory.rs index 33fd19573b4..5cad60ec3b5 100644 --- a/vm/src/builtins/memory.rs +++ b/vm/src/builtins/memory.rs @@ -75,7 +75,7 @@ impl PyMemoryView { /// this should be the main entrance to create the memoryview /// to avoid the chained memoryview pub fn from_object(obj: &PyObject, vm: &VirtualMachine) -> PyResult { - if let Some(other) = obj.payload::() { + if let Some(other) = obj.downcast_ref::() { Ok(other.new_view()) } else { let buffer = PyBuffer::try_from_borrowed_object(vm, obj)?; @@ -330,7 +330,7 @@ impl PyMemoryView { return Ok(false); } - if let Some(other) = other.payload::() { + if let Some(other) = other.downcast_ref::() { if other.released.load() { return Ok(false); } @@ -665,7 +665,7 @@ impl PyMemoryView { if needle.is(&vm.ctx.ellipsis) { return Ok(zelf.into()); } - if let Some(tuple) = needle.payload::() { + if let Some(tuple) = needle.downcast_ref::() { if tuple.is_empty() { return zelf.unpack_single(0, vm); } @@ -864,7 +864,7 @@ impl Py { // TODO: merge branches when we got conditional if let if needle.is(&vm.ctx.ellipsis) { return self.pack_single(0, value, vm); - } else if let Some(tuple) = needle.payload::() { + } else if let Some(tuple) = needle.downcast_ref::() { if tuple.is_empty() { return self.pack_single(0, value, vm); } @@ -907,15 +907,15 @@ enum SubscriptNeedle { impl TryFromObject for SubscriptNeedle { fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult { // TODO: number protocol - if let Some(i) = obj.payload::() { + if let Some(i) = obj.downcast_ref::() { Ok(Self::Index(i.try_to_primitive(vm)?)) - } else if obj.payload_is::() { + } else if obj.downcastable::() { Ok(Self::Slice(unsafe { obj.downcast_unchecked::() })) } else if let Ok(i) = obj.try_index(vm) { Ok(Self::Index(i.try_to_primitive(vm)?)) } else { - if let Some(tuple) = obj.payload::() { - if tuple.iter().all(|x| x.payload_is::()) { + if let Some(tuple) = obj.downcast_ref::() { + if tuple.iter().all(|x| x.downcastable::()) { let v = tuple .iter() .map(|x| { @@ -924,7 +924,7 @@ impl TryFromObject for SubscriptNeedle { }) .try_collect()?; return Ok(Self::MultiIndex(v)); - } else if tuple.iter().all(|x| x.payload_is::()) { + } else if tuple.iter().all(|x| x.downcastable::()) { return Err(vm.new_not_implemented_error( "multi-dimensional slicing is not implemented", )); diff --git a/vm/src/builtins/range.rs b/vm/src/builtins/range.rs index 2d6ea92b192..7ce40c24bba 100644 --- a/vm/src/builtins/range.rs +++ b/vm/src/builtins/range.rs @@ -165,7 +165,7 @@ impl PyRange { } // pub fn get_value(obj: &PyObject) -> PyRange { -// obj.payload::().unwrap().clone() +// obj.downcast_ref::().unwrap().clone() // } pub fn init(context: &Context) { @@ -677,7 +677,7 @@ fn range_iter_reduce( // Silently clips state (i.e index) in range [0, usize::MAX]. fn range_state(length: &BigInt, state: PyObjectRef, vm: &VirtualMachine) -> PyResult { - if let Some(i) = state.payload::() { + if let Some(i) = state.downcast_ref::() { let mut index = i.as_bigint(); let max_usize = BigInt::from(usize::MAX); if index > length { diff --git a/vm/src/builtins/set.rs b/vm/src/builtins/set.rs index c4fd116f6a3..7cf20a17f7e 100644 --- a/vm/src/builtins/set.rs +++ b/vm/src/builtins/set.rs @@ -474,7 +474,7 @@ impl PySetInner { F: Fn(&PyObject, &VirtualMachine) -> PyResult, { op(item, vm).or_else(|original_err| { - item.payload_if_subclass::(vm) + item.downcast_ref::() // Keep original error around. .ok_or(original_err) .and_then(|set| { diff --git a/vm/src/builtins/str.rs b/vm/src/builtins/str.rs index 73349c61419..fe7ad6a98a8 100644 --- a/vm/src/builtins/str.rs +++ b/vm/src/builtins/str.rs @@ -549,7 +549,7 @@ impl PyStr { impl PyStr { #[pymethod] fn __add__(zelf: PyRef, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { - if let Some(other) = other.payload::() { + if let Some(other) = other.downcast_ref::() { let bytes = zelf.as_wtf8().py_add(other.as_wtf8()); Ok(unsafe { // SAFETY: `kind` is safely decided @@ -569,7 +569,7 @@ impl PyStr { } fn _contains(&self, needle: &PyObject, vm: &VirtualMachine) -> PyResult { - if let Some(needle) = needle.payload::() { + if let Some(needle) = needle.downcast_ref::() { Ok(memchr::memmem::find(self.as_bytes(), needle.as_bytes()).is_some()) } else { Err(vm.new_type_error(format!( @@ -1374,9 +1374,9 @@ impl PyStr { for c in self.as_str().chars() { match table.get_item(&*(c as u32).to_pyobject(vm), vm) { Ok(value) => { - if let Some(text) = value.payload::() { + if let Some(text) = value.downcast_ref::() { translated.push_str(text.as_str()); - } else if let Some(bigint) = value.payload::() { + } else if let Some(bigint) = value.downcast_ref::() { let ch = bigint .as_bigint() .to_u32() @@ -1438,13 +1438,13 @@ impl PyStr { Ok(dict) => { for (key, val) in dict { // FIXME: ints are key-compatible - if let Some(num) = key.payload::() { + if let Some(num) = key.downcast_ref::() { new_dict.set_item( &*num.as_bigint().to_i32().to_pyobject(vm), val, vm, )?; - } else if let Some(string) = key.payload::() { + } else if let Some(string) = key.downcast_ref::() { if string.len() == 1 { let num_value = string.as_str().chars().next().unwrap() as u32; new_dict.set_item(&*num_value.to_pyobject(vm), val, vm)?; diff --git a/vm/src/builtins/type.rs b/vm/src/builtins/type.rs index f2a4fde3b9b..94334d4a88b 100644 --- a/vm/src/builtins/type.rs +++ b/vm/src/builtins/type.rs @@ -592,7 +592,7 @@ impl PyType { PyType::resolve_mro(&cls.bases.read()).map_err(|msg| vm.new_type_error(msg))?; for subclass in cls.subclasses.write().iter() { let subclass = subclass.upgrade().unwrap(); - let subclass: &PyType = subclass.payload().unwrap(); + let subclass: &Py = subclass.downcast_ref().unwrap(); update_mro_recursively(subclass, vm)?; } Ok(()) diff --git a/vm/src/builtins/union.rs b/vm/src/builtins/union.rs index c7abd634ef5..962f3b5eb21 100644 --- a/vm/src/builtins/union.rs +++ b/vm/src/builtins/union.rs @@ -153,7 +153,7 @@ impl PyUnion { pub fn is_unionable(obj: PyObjectRef, vm: &VirtualMachine) -> bool { obj.class().is(vm.ctx.types.none_type) - || obj.payload_if_subclass::(vm).is_some() + || obj.downcastable::() || obj.class().is(vm.ctx.types.generic_alias_type) || obj.class().is(vm.ctx.types.union_type) } diff --git a/vm/src/cformat.rs b/vm/src/cformat.rs index feca96c8332..6957c6dbb74 100644 --- a/vm/src/cformat.rs +++ b/vm/src/cformat.rs @@ -63,7 +63,7 @@ fn spec_format_bytes( obj => { if let Some(method) = vm.get_method(obj.clone(), identifier!(vm, __int__)) { let result = method?.call((), vm)?; - if let Some(i) = result.payload::() { + if let Some(i) = result.downcast_ref::() { return Ok(spec.format_number(i.as_bigint()).into_bytes()); } } @@ -76,7 +76,7 @@ fn spec_format_bytes( }) } _ => { - if let Some(i) = obj.payload::() { + if let Some(i) = obj.downcast_ref::() { Ok(spec.format_number(i.as_bigint()).into_bytes()) } else { Err(vm.new_type_error(format!( @@ -101,17 +101,17 @@ fn spec_format_bytes( Ok(spec.format_float(value.into()).into_bytes()) } CFormatType::Character(CCharacterType::Character) => { - if let Some(i) = obj.payload::() { + if let Some(i) = obj.downcast_ref::() { let ch = i .try_to_primitive::(vm) .map_err(|_| vm.new_overflow_error("%c arg not in range(256)"))?; return Ok(spec.format_char(ch)); } - if let Some(b) = obj.payload::() { + if let Some(b) = obj.downcast_ref::() { if b.len() == 1 { return Ok(spec.format_char(b.as_bytes()[0])); } - } else if let Some(ba) = obj.payload::() { + } else if let Some(ba) = obj.downcast_ref::() { let buf = ba.borrow_buf(); if buf.len() == 1 { return Ok(spec.format_char(buf[0])); @@ -158,7 +158,7 @@ fn spec_format_string( obj => { if let Some(method) = vm.get_method(obj.clone(), identifier!(vm, __int__)) { let result = method?.call((), vm)?; - if let Some(i) = result.payload::() { + if let Some(i) = result.downcast_ref::() { return Ok(spec.format_number(i.as_bigint()).into()); } } @@ -171,7 +171,7 @@ fn spec_format_string( }) } _ => { - if let Some(i) = obj.payload::() { + if let Some(i) = obj.downcast_ref::() { Ok(spec.format_number(i.as_bigint()).into()) } else { Err(vm.new_type_error(format!( @@ -187,7 +187,7 @@ fn spec_format_string( Ok(spec.format_float(value.into()).into()) } CFormatType::Character(CCharacterType::Character) => { - if let Some(i) = obj.payload::() { + if let Some(i) = obj.downcast_ref::() { let ch = i .as_bigint() .to_u32() @@ -195,7 +195,7 @@ fn spec_format_string( .ok_or_else(|| vm.new_overflow_error("%c arg not in range(0x110000)"))?; return Ok(spec.format_char(ch)); } - if let Some(s) = obj.payload::() { + if let Some(s) = obj.downcast_ref::() { if let Ok(ch) = s.as_wtf8().code_points().exactly_one() { return Ok(spec.format_char(ch)); } @@ -211,7 +211,7 @@ fn try_update_quantity_from_element( ) -> PyResult { match element { Some(width_obj) => { - if let Some(i) = width_obj.payload::() { + if let Some(i) = width_obj.downcast_ref::() { let i = i.try_to_primitive::(vm)?.unsigned_abs(); Ok(CFormatQuantity::Amount(i as usize)) } else { @@ -228,7 +228,7 @@ fn try_conversion_flag_from_tuple( ) -> PyResult { match element { Some(width_obj) => { - if let Some(i) = width_obj.payload::() { + if let Some(i) = width_obj.downcast_ref::() { let i = i.try_to_primitive::(vm)?; let flags = if i < 0 { CConversionFlags::LEFT_ADJUST @@ -299,7 +299,7 @@ pub(crate) fn cformat_bytes( // literal only return if is_mapping || values_obj - .payload::() + .downcast_ref::() .is_some_and(|e| e.is_empty()) { for (_, part) in format.iter_mut() { @@ -335,7 +335,7 @@ pub(crate) fn cformat_bytes( } // tuple - let values = if let Some(tup) = values_obj.payload_if_subclass::(vm) { + let values = if let Some(tup) = values_obj.downcast_ref::() { tup.as_slice() } else { std::slice::from_ref(&values_obj) @@ -393,7 +393,7 @@ pub(crate) fn cformat_string( // literal only return if is_mapping || values_obj - .payload::() + .downcast_ref::() .is_some_and(|e| e.is_empty()) { for (_, part) in format.iter() { @@ -428,7 +428,7 @@ pub(crate) fn cformat_string( } // tuple - let values = if let Some(tup) = values_obj.payload_if_subclass::(vm) { + let values = if let Some(tup) = values_obj.downcast_ref::() { tup.as_slice() } else { std::slice::from_ref(&values_obj) diff --git a/vm/src/codecs.rs b/vm/src/codecs.rs index b31222cfee9..dac637c396d 100644 --- a/vm/src/codecs.rs +++ b/vm/src/codecs.rs @@ -852,7 +852,7 @@ impl<'a> EncodeErrorHandler> for ErrorsHandler<'_> { let res = handler.call((encode_exc.clone(),), vm)?; let tuple_err = || vm.new_type_error("encoding error handler must return (str/bytes, int) tuple"); - let (replace, restart) = match res.payload::().map(|tup| tup.as_slice()) { + let (replace, restart) = match res.downcast_ref::().map(|tup| tup.as_slice()) { Some([replace, restart]) => (replace.clone(), restart), _ => return Err(tuple_err()), }; @@ -910,7 +910,7 @@ impl<'a> DecodeErrorHandler> for ErrorsHandler<'_> { } let data = &*ctx.data; let tuple_err = || vm.new_type_error("decoding error handler must return (str, int) tuple"); - match res.payload::().map(|tup| tup.as_slice()) { + match res.downcast_ref::().map(|tup| tup.as_slice()) { Some([replace, restart]) => { let replace = replace .downcast_ref::() diff --git a/vm/src/convert/transmute_from.rs b/vm/src/convert/transmute_from.rs index 908188f0d10..c1b4b79384e 100644 --- a/vm/src/convert/transmute_from.rs +++ b/vm/src/convert/transmute_from.rs @@ -17,7 +17,7 @@ unsafe impl TransmuteFromObject for PyRef { fn check(vm: &VirtualMachine, obj: &PyObject) -> PyResult<()> { let class = T::class(&vm.ctx); if obj.fast_isinstance(class) { - if obj.payload_is::() { + if obj.downcastable::() { Ok(()) } else { Err(vm.new_downcast_runtime_error(class, obj)) diff --git a/vm/src/convert/try_from.rs b/vm/src/convert/try_from.rs index a875ffa231e..3fda682d402 100644 --- a/vm/src/convert/try_from.rs +++ b/vm/src/convert/try_from.rs @@ -124,7 +124,7 @@ impl<'a, T: PyPayload> TryFromBorrowedObject<'a> for &'a Py { impl TryFromObject for std::time::Duration { fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult { - if let Some(float) = obj.payload::() { + if let Some(float) = obj.downcast_ref::() { let f = float.to_f64(); if f < 0.0 { return Err(vm.new_value_error("negative duration")); diff --git a/vm/src/dict_inner.rs b/vm/src/dict_inner.rs index 000a22b6e33..02e237afb00 100644 --- a/vm/src/dict_inner.rs +++ b/vm/src/dict_inner.rs @@ -777,7 +777,7 @@ impl DictKey for Py { fn key_eq(&self, vm: &VirtualMachine, other_key: &PyObject) -> PyResult { if self.is(other_key) { Ok(true) - } else if let Some(pystr) = other_key.payload_if_exact::(vm) { + } else if let Some(pystr) = other_key.downcast_ref_if_exact::(vm) { Ok(self.as_wtf8() == pystr.as_wtf8()) } else { vm.bool_eq(self.as_object(), other_key) @@ -875,7 +875,7 @@ impl DictKey for str { } fn key_eq(&self, vm: &VirtualMachine, other_key: &PyObject) -> PyResult { - if let Some(pystr) = other_key.payload_if_exact::(vm) { + if let Some(pystr) = other_key.downcast_ref_if_exact::(vm) { Ok(pystr.as_wtf8() == self) } else { // Fall back to PyObjectRef implementation. @@ -936,7 +936,7 @@ impl DictKey for Wtf8 { } fn key_eq(&self, vm: &VirtualMachine, other_key: &PyObject) -> PyResult { - if let Some(pystr) = other_key.payload_if_exact::(vm) { + if let Some(pystr) = other_key.downcast_ref_if_exact::(vm) { Ok(pystr.as_wtf8() == self) } else { // Fall back to PyObjectRef implementation. @@ -997,7 +997,7 @@ impl DictKey for [u8] { } fn key_eq(&self, vm: &VirtualMachine, other_key: &PyObject) -> PyResult { - if let Some(pystr) = other_key.payload_if_exact::(vm) { + if let Some(pystr) = other_key.downcast_ref_if_exact::(vm) { Ok(pystr.as_bytes() == self) } else { // Fall back to PyObjectRef implementation. @@ -1053,7 +1053,7 @@ impl DictKey for usize { } fn key_eq(&self, vm: &VirtualMachine, other_key: &PyObject) -> PyResult { - if let Some(int) = other_key.payload_if_exact::(vm) { + if let Some(int) = other_key.downcast_ref_if_exact::(vm) { if let Some(i) = int.as_bigint().to_usize() { Ok(i == *self) } else { diff --git a/vm/src/exceptions.rs b/vm/src/exceptions.rs index 1e816145dd2..a443887bce4 100644 --- a/vm/src/exceptions.rs +++ b/vm/src/exceptions.rs @@ -1445,7 +1445,7 @@ pub(super) mod types { if (2..=5).contains(&len) { let errno = &args[0]; errno - .payload_if_subclass::(vm) + .downcast_ref::() .and_then(|errno| errno.try_to_primitive::(vm).ok()) .and_then(|errno| super::errno_to_exc_type(errno, vm)) .and_then(|typ| vm.invoke_exception(typ.to_owned(), args.to_vec()).ok()) diff --git a/vm/src/frame.rs b/vm/src/frame.rs index bf07bcbc2b6..59cfc0ac68b 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -733,7 +733,7 @@ impl ExecutingFrame<'_> { .pop_multiple(size.get(arg) as usize) .as_slice() .iter() - .map(|pyobj| pyobj.payload::().unwrap()) + .map(|pyobj| pyobj.downcast_ref::().unwrap()) .collect::(); let str_obj = vm.ctx.new_str(s); self.push_value(str_obj.into()); @@ -1077,7 +1077,7 @@ impl ExecutingFrame<'_> { } bytecode::Instruction::GetAwaitable => { let awaited_obj = self.pop_value(); - let awaitable = if awaited_obj.payload_is::() { + let awaitable = if awaited_obj.downcastable::() { awaited_obj } else { let await_method = vm.get_method_or_type_error( @@ -1595,7 +1595,7 @@ impl ExecutingFrame<'_> { let kwarg_names = kwarg_names .as_slice() .iter() - .map(|pyobj| pyobj.payload::().unwrap().as_str().to_owned()); + .map(|pyobj| pyobj.downcast_ref::().unwrap().as_str().to_owned()); FuncArgs::with_kwargs_names(args, kwarg_names) } @@ -1607,7 +1607,7 @@ impl ExecutingFrame<'_> { // Use keys() method for all mapping objects to preserve order Self::iterate_mapping_keys(vm, &kw_obj, "argument after **", |key| { let key_str = key - .payload_if_subclass::(vm) + .downcast_ref::() .ok_or_else(|| vm.new_type_error("keywords must be strings"))?; let value = kw_obj.get_item(&*key, vm)?; kwargs.insert(key_str.as_str().to_owned(), value); @@ -2337,7 +2337,7 @@ impl fmt::Debug for Frame { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let state = self.state.lock(); let stack_str = state.stack.iter().fold(String::new(), |mut s, elem| { - if elem.payload_is::() { + if elem.downcastable::() { s.push_str("\n > {frame}"); } else { std::fmt::write(&mut s, format_args!("\n > {elem:?}")).unwrap(); diff --git a/vm/src/macros.rs b/vm/src/macros.rs index 4554a65c26e..171558b9a93 100644 --- a/vm/src/macros.rs +++ b/vm/src/macros.rs @@ -145,7 +145,7 @@ macro_rules! match_class { } }; (match ($obj:expr) { ref $binding:ident @ $class:ty => $expr:expr, $($rest:tt)* }) => { - match $obj.payload::<$class>() { + match $obj.downcast_ref::<$class>() { ::std::option::Option::Some($binding) => $expr, ::std::option::Option::None => $crate::match_class!(match ($obj) { $($rest)* }), } @@ -160,7 +160,7 @@ macro_rules! match_class { // An arm taken when the object is an instance of the specified built-in // class. (match ($obj:expr) { $class:ty => $expr:expr, $($rest:tt)* }) => { - if $obj.payload_is::<$class>() { + if $obj.downcastable::<$class>() { $expr } else { $crate::match_class!(match ($obj) { $($rest)* }) diff --git a/vm/src/object/core.rs b/vm/src/object/core.rs index f0f438e3aa6..1e95c69ea27 100644 --- a/vm/src/object/core.rs +++ b/vm/src/object/core.rs @@ -534,24 +534,13 @@ impl PyObjectRef { /// another downcast can be attempted without unnecessary cloning. #[inline(always)] pub fn downcast(self) -> Result, Self> { - if self.payload_is::() { + if self.downcastable::() { Ok(unsafe { self.downcast_unchecked() }) } else { Err(self) } } - #[inline(always)] - pub fn downcast_ref(&self) -> Option<&Py> { - if self.payload_is::() { - // SAFETY: just checked that the payload is T, and PyRef is repr(transparent) over - // PyObjectRef - Some(unsafe { &*(self as *const Self as *const PyRef) }) - } else { - None - } - } - /// Force to downcast this reference to a subclass. /// /// # Safety @@ -566,15 +555,6 @@ impl PyObjectRef { } } - /// # Safety - /// T must be the exact payload type - #[inline(always)] - pub unsafe fn downcast_unchecked_ref(&self) -> &Py { - debug_assert!(self.payload_is::()); - // SAFETY: requirements forwarded from caller - unsafe { &*(self as *const Self as *const PyRef) } - } - // ideally we'd be able to define these in pyobject.rs, but method visibility rules are weird /// Attempt to downcast this reference to the specific class that is associated `T`. @@ -589,10 +569,10 @@ impl PyObjectRef { if self.class().is(T::class(&vm.ctx)) { // TODO: is this always true? assert!( - self.payload_is::(), + self.downcastable::(), "obj.__class__ is T::class() but payload is not T" ); - // SAFETY: just asserted that payload_is::() + // SAFETY: just asserted that downcastable::() Ok(unsafe { PyRefExact::new_unchecked(PyRef::from_obj_unchecked(self)) }) } else { Err(self) @@ -670,6 +650,7 @@ impl PyObject { &inner.payload } + #[deprecated(note = "use downcast_ref instead")] #[inline(always)] pub fn payload(&self) -> Option<&T> { if self.payload_is::() { @@ -688,12 +669,14 @@ impl PyObject { self.0.typ.swap_to_temporary_refs(typ, vm); } + #[deprecated(note = "use downcast_ref_if_exact instead")] #[inline(always)] pub fn payload_if_exact( &self, vm: &VirtualMachine, ) -> Option<&T> { if self.class().is(T::class(&vm.ctx)) { + #[allow(deprecated)] self.payload() } else { None @@ -722,18 +705,27 @@ impl PyObject { } } + #[deprecated(note = "use downcast_ref instead")] #[inline(always)] pub fn payload_if_subclass(&self, vm: &VirtualMachine) -> Option<&T> { if self.class().fast_issubclass(T::class(&vm.ctx)) { + #[allow(deprecated)] self.payload() } else { None } } + /// Check if this object can be downcast to T. + #[inline(always)] + pub fn downcastable(&self) -> bool { + self.payload_is::() + } + + /// Attempt to downcast this reference to a subclass. #[inline(always)] pub fn downcast_ref(&self) -> Option<&Py> { - if self.payload_is::() { + if self.downcastable::() { // SAFETY: just checked that the payload is T, and PyRef is repr(transparent) over // PyObjectRef Some(unsafe { self.downcast_unchecked_ref::() }) @@ -756,7 +748,7 @@ impl PyObject { /// T must be the exact payload type #[inline(always)] pub unsafe fn downcast_unchecked_ref(&self) -> &Py { - debug_assert!(self.payload_is::()); + debug_assert!(self.downcastable::()); // SAFETY: requirements forwarded from caller unsafe { &*(self as *const Self as *const Py) } } @@ -1045,7 +1037,7 @@ impl PyRef { /// Safety: payload type of `obj` must be `T` #[inline(always)] unsafe fn from_obj_unchecked(obj: PyObjectRef) -> Self { - debug_assert!(obj.payload_is::()); + debug_assert!(obj.downcast_ref::().is_some()); let obj = ManuallyDrop::new(obj); Self { ptr: obj.ptr.cast(), diff --git a/vm/src/protocol/number.rs b/vm/src/protocol/number.rs index ec5f6d9795f..b103fdddd69 100644 --- a/vm/src/protocol/number.rs +++ b/vm/src/protocol/number.rs @@ -25,7 +25,7 @@ impl PyObject { pub fn try_index_opt(&self, vm: &VirtualMachine) -> Option> { if let Some(i) = self.downcast_ref_if_exact::(vm) { Some(Ok(i.to_owned())) - } else if let Some(i) = self.payload::() { + } else if let Some(i) = self.downcast_ref::() { Some(Ok(vm.ctx.new_bigint(i.as_bigint()))) } else { self.to_number().index(vm) @@ -75,11 +75,11 @@ impl PyObject { ret.class() )) }) - } else if let Some(s) = self.payload::() { + } else if let Some(s) = self.downcast_ref::() { try_convert(self, s.as_wtf8().trim().as_bytes(), vm) - } else if let Some(bytes) = self.payload::() { + } else if let Some(bytes) = self.downcast_ref::() { try_convert(self, bytes, vm) - } else if let Some(bytearray) = self.payload::() { + } else if let Some(bytearray) = self.downcast_ref::() { try_convert(self, &bytearray.borrow_buf(), vm) } else if let Ok(buffer) = ArgBytesLike::try_from_borrowed_object(vm, self) { // TODO: replace to PyBuffer @@ -450,7 +450,7 @@ impl<'a> PyNumber<'a> { methods.int.load().is_some() || methods.index.load().is_some() || methods.float.load().is_some() - || obj.payload_is::() + || obj.downcastable::() } } diff --git a/vm/src/protocol/object.rs b/vm/src/protocol/object.rs index 498db0b26e6..aade5a18e42 100644 --- a/vm/src/protocol/object.rs +++ b/vm/src/protocol/object.rs @@ -93,7 +93,7 @@ impl PyObject { // PyObject *PyObject_GetAIter(PyObject *o) pub fn get_aiter(&self, vm: &VirtualMachine) -> PyResult { - if self.payload_is::() { + if self.downcastable::() { vm.call_special_method(self, identifier!(vm, __aiter__), ()) } else { Err(vm.new_type_error("wrong argument type")) diff --git a/vm/src/protocol/sequence.rs b/vm/src/protocol/sequence.rs index 6d9eb56151b..fb71446a5a4 100644 --- a/vm/src/protocol/sequence.rs +++ b/vm/src/protocol/sequence.rs @@ -337,9 +337,9 @@ impl PySequence<'_> { where F: FnMut(&PyObject) -> PyResult, { - if let Some(tuple) = self.obj.payload_if_exact::(vm) { + if let Some(tuple) = self.obj.downcast_ref_if_exact::(vm) { tuple.iter().map(|x| f(x.as_ref())).collect() - } else if let Some(list) = self.obj.payload_if_exact::(vm) { + } else if let Some(list) = self.obj.downcast_ref_if_exact::(vm) { list.borrow_vec().iter().map(|x| f(x.as_ref())).collect() } else { let iter = self.obj.to_owned().get_iter(vm)?; diff --git a/vm/src/py_serde.rs b/vm/src/py_serde.rs index 6c23f924e1e..f9a5f4bc060 100644 --- a/vm/src/py_serde.rs +++ b/vm/src/py_serde.rs @@ -62,7 +62,7 @@ impl serde::Serialize for PyObjectSerializer<'_> { } seq.end() }; - if let Some(s) = self.pyobject.payload::() { + if let Some(s) = self.pyobject.downcast_ref::() { serializer.serialize_str(s.as_ref()) } else if self.pyobject.fast_isinstance(self.vm.ctx.types.float_type) { serializer.serialize_f64(float::get_value(self.pyobject)) @@ -80,9 +80,9 @@ impl serde::Serialize for PyObjectSerializer<'_> { } else { serializer.serialize_i64(v.to_i64().ok_or_else(int_too_large)?) } - } else if let Some(list) = self.pyobject.payload_if_subclass::(self.vm) { + } else if let Some(list) = self.pyobject.downcast_ref::() { serialize_seq_elements(serializer, &list.borrow_vec()) - } else if let Some(tuple) = self.pyobject.payload_if_subclass::(self.vm) { + } else if let Some(tuple) = self.pyobject.downcast_ref::() { serialize_seq_elements(serializer, tuple) } else if self.pyobject.fast_isinstance(self.vm.ctx.types.dict_type) { let dict: PyDictRef = self.pyobject.to_owned().downcast().unwrap(); diff --git a/vm/src/sliceable.rs b/vm/src/sliceable.rs index 7d175d033e1..786b66fb36a 100644 --- a/vm/src/sliceable.rs +++ b/vm/src/sliceable.rs @@ -263,12 +263,12 @@ impl SequenceIndex { obj: &PyObject, type_name: &str, ) -> PyResult { - if let Some(i) = obj.payload::() { + if let Some(i) = obj.downcast_ref::() { // TODO: number protocol i.try_to_primitive(vm) .map_err(|_| vm.new_index_error("cannot fit 'int' into an index-sized integer")) .map(Self::Int) - } else if let Some(slice) = obj.payload::() { + } else if let Some(slice) = obj.downcast_ref::() { slice.to_saturated(vm).map(Self::Slice) } else if let Some(i) = obj.try_index_opt(vm) { // TODO: __index__ for indices is no more supported? diff --git a/vm/src/stdlib/collections.rs b/vm/src/stdlib/collections.rs index 6d1cdf1f02d..651a470bfa3 100644 --- a/vm/src/stdlib/collections.rs +++ b/vm/src/stdlib/collections.rs @@ -365,7 +365,7 @@ mod _collections { } fn concat(&self, other: &PyObject, vm: &VirtualMachine) -> PyResult { - if let Some(o) = other.payload_if_subclass::(vm) { + if let Some(o) = other.downcast_ref::() { let mut deque = self.borrow_deque().clone(); let elements = o.borrow_deque().clone(); deque.extend(elements); @@ -446,7 +446,7 @@ mod _collections { let maxlen = if let Some(obj) = maxlen.into_option() { if !vm.is_none(&obj) { let maxlen: isize = obj - .payload::() + .downcast_ref::() .ok_or_else(|| vm.new_type_error("an integer is required."))? .try_to_primitive(vm)?; diff --git a/vm/src/stdlib/ctypes/array.rs b/vm/src/stdlib/ctypes/array.rs index 0880c6b63b7..82306c8b0b1 100644 --- a/vm/src/stdlib/ctypes/array.rs +++ b/vm/src/stdlib/ctypes/array.rs @@ -108,8 +108,8 @@ impl PyCArray { impl PyCArray { pub fn to_arg(&self, _vm: &VirtualMachine) -> PyResult { let value = self.value.read(); - let py_bytes = value.payload::().unwrap(); - let bytes = py_bytes.as_ref().to_vec(); + let py_bytes = value.downcast_ref::().unwrap(); + let bytes = py_bytes.payload().to_vec(); Ok(libffi::middle::Arg::new(&bytes)) } } diff --git a/vm/src/stdlib/ctypes/function.rs b/vm/src/stdlib/ctypes/function.rs index 4ecff564b87..034b1bd0723 100644 --- a/vm/src/stdlib/ctypes/function.rs +++ b/vm/src/stdlib/ctypes/function.rs @@ -43,14 +43,14 @@ impl Function { let args = args .iter() .map(|arg| { - if let Some(arg) = arg.payload_if_subclass::(vm) { + if let Some(arg) = arg.downcast_ref::() { let converted = ffi_type_from_str(&arg._type_); return match converted { Some(t) => Ok(t), None => Err(vm.new_type_error("Invalid type")), // TODO: add type name }; } - if let Some(arg) = arg.payload_if_subclass::(vm) { + if let Some(arg) = arg.downcast_ref::() { let t = arg.typ.read(); let ty_attributes = t.attributes.read(); let ty_pystr = ty_attributes @@ -107,10 +107,10 @@ impl Function { .enumerate() .map(|(count, arg)| { // none type check - if let Some(d) = arg.payload_if_subclass::(vm) { + if let Some(d) = arg.downcast_ref::() { return Ok(d.to_arg(self.args[count].clone(), vm).unwrap()); } - if let Some(d) = arg.payload_if_subclass::(vm) { + if let Some(d) = arg.downcast_ref::() { return Ok(d.to_arg(vm).unwrap()); } Err(vm.new_type_error("Expected a ctypes simple type")) diff --git a/vm/src/stdlib/io.rs b/vm/src/stdlib/io.rs index c546a0c46fe..edbc29cb8c0 100644 --- a/vm/src/stdlib/io.rs +++ b/vm/src/stdlib/io.rs @@ -2370,7 +2370,7 @@ mod _io { codec.get_incremental_encoder(Some(errors.to_owned()), vm)?; let encoding_name = vm.get_attribute_opt(incremental_encoder.clone(), "name")?; let encode_func = encoding_name.and_then(|name| { - let name = name.payload::()?; + let name = name.downcast_ref::()?; match name.as_str() { "utf-8" => Some(textio_encode_utf8 as EncodeFunc), _ => None, @@ -3090,7 +3090,7 @@ mod _io { obj.class().name() )) })?; - let flags = flags.payload::().ok_or_else(state_err)?; + let flags = flags.downcast_ref::().ok_or_else(state_err)?; let flags = flags.try_to_primitive(vm)?; Ok((buf, flags)) } @@ -4273,7 +4273,7 @@ mod fileio { fn init(zelf: PyRef, args: Self::Args, vm: &VirtualMachine) -> PyResult<()> { // TODO: let atomic_flag_works let name = args.name; - let arg_fd = if let Some(i) = name.payload::() { + let arg_fd = if let Some(i) = name.downcast_ref::() { let fd = i.try_to_primitive(vm)?; if fd < 0 { return Err(vm.new_value_error("negative file descriptor")); diff --git a/vm/src/stdlib/itertools.rs b/vm/src/stdlib/itertools.rs index 63b2d390ca8..8bc4ef79709 100644 --- a/vm/src/stdlib/itertools.rs +++ b/vm/src/stdlib/itertools.rs @@ -1699,7 +1699,7 @@ mod decl { let r = match r.flatten() { Some(r) => { let val = r - .payload::() + .downcast_ref::() .ok_or_else(|| vm.new_type_error("Expected int as r"))? .as_bigint(); diff --git a/vm/src/stdlib/operator.rs b/vm/src/stdlib/operator.rs index 0d5a3092014..4fd74734ec1 100644 --- a/vm/src/stdlib/operator.rs +++ b/vm/src/stdlib/operator.rs @@ -229,7 +229,7 @@ mod _operator { v.class().name() ))); } - v.payload::().unwrap().try_to_primitive(vm) + v.downcast_ref::().unwrap().try_to_primitive(vm) }) .unwrap_or(Ok(0))?; obj.length_hint(default, vm) diff --git a/vm/src/stdlib/os.rs b/vm/src/stdlib/os.rs index 19f5e44b34a..f47b1fe284a 100644 --- a/vm/src/stdlib/os.rs +++ b/vm/src/stdlib/os.rs @@ -801,7 +801,7 @@ pub(super) mod _os { let mut vec_args = Vec::from(r); loop { if let Ok(obj) = vec_args.iter().exactly_one() { - match obj.payload::() { + match obj.downcast_ref::() { Some(t) => { vec_args = Vec::from(t.as_slice()); } @@ -1045,7 +1045,7 @@ pub(super) mod _os { #[pyfunction] fn utime(args: UtimeArgs, vm: &VirtualMachine) -> PyResult<()> { - let parse_tup = |tup: &PyTuple| -> Option<(PyObjectRef, PyObjectRef)> { + let parse_tup = |tup: &Py| -> Option<(PyObjectRef, PyObjectRef)> { if tup.len() != 2 { None } else { @@ -1065,17 +1065,16 @@ pub(super) mod _os { let ns_in_sec: PyObjectRef = vm.ctx.new_int(1_000_000_000).into(); let ns_to_dur = |obj: PyObjectRef| { let divmod = vm._divmod(&obj, &ns_in_sec)?; - let (div, rem) = - divmod - .payload::() - .and_then(parse_tup) - .ok_or_else(|| { - vm.new_type_error(format!( - "{}.__divmod__() must return a 2-tuple, not {}", - obj.class().name(), - divmod.class().name() - )) - })?; + let (div, rem) = divmod + .downcast_ref::() + .and_then(parse_tup) + .ok_or_else(|| { + vm.new_type_error(format!( + "{}.__divmod__() must return a 2-tuple, not {}", + obj.class().name(), + divmod.class().name() + )) + })?; let secs = div.try_index(vm)?.try_to_primitive(vm)?; let ns = rem.try_index(vm)?.try_to_primitive(vm)?; Ok(Duration::new(secs, ns)) diff --git a/vm/src/stdlib/sre.rs b/vm/src/stdlib/sre.rs index 33fc977f2c6..b950db9e1ff 100644 --- a/vm/src/stdlib/sre.rs +++ b/vm/src/stdlib/sre.rs @@ -99,7 +99,7 @@ mod _sre { // re.Scanner has no official API and in CPython's implement // isbytes will be hanging (-1) // here is just a hack to let re.Scanner works only with str not bytes - let isbytes = !vm.is_none(&pattern) && !pattern.payload_is::(); + let isbytes = !vm.is_none(&pattern) && !pattern.downcastable::(); let code = code.try_to_value(vm)?; Ok(Pattern { pattern, @@ -155,7 +155,7 @@ mod _sre { for trunk in trunks { let index: usize = trunk[0] - .payload::() + .downcast_ref::() .ok_or_else(|| vm.new_type_error("expected usize"))? .try_to_primitive(vm)?; items.push((index, trunk[1].clone())); @@ -218,7 +218,7 @@ mod _sre { where F: FnOnce(&Wtf8) -> PyResult, { - let string = string.payload::().ok_or_else(|| { + let string = string.downcast_ref::().ok_or_else(|| { vm.new_type_error(format!("expected string got '{}'", string.class())) })?; f(string.as_wtf8()) diff --git a/vm/src/stdlib/weakref.rs b/vm/src/stdlib/weakref.rs index bfec54e9c68..bedfad9abbd 100644 --- a/vm/src/stdlib/weakref.rs +++ b/vm/src/stdlib/weakref.rs @@ -56,7 +56,7 @@ mod _weakref { dict._as_dict_inner() .delete_if(vm, &*key, |wr| { let wr = wr - .payload::() + .downcast_ref::() .ok_or_else(|| vm.new_type_error("not a weakref"))?; Ok(wr.is_dead()) }) diff --git a/vm/src/types/slot.rs b/vm/src/types/slot.rs index 704ec3edf0f..88e0f231cbf 100644 --- a/vm/src/types/slot.rs +++ b/vm/src/types/slot.rs @@ -192,7 +192,7 @@ pub(crate) type DelFunc = fn(&PyObject, &VirtualMachine) -> PyResult<()>; // slot_sq_length pub(crate) fn len_wrapper(obj: &PyObject, vm: &VirtualMachine) -> PyResult { let ret = vm.call_special_method(obj, identifier!(vm, __len__), ())?; - let len = ret.payload::().ok_or_else(|| { + let len = ret.downcast_ref::().ok_or_else(|| { vm.new_type_error(format!( "'{}' object cannot be interpreted as an integer", ret.class() @@ -262,7 +262,7 @@ fn repr_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult { fn hash_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult { let hash_obj = vm.call_special_method(zelf, identifier!(vm, __hash__), ())?; let py_int = hash_obj - .payload_if_subclass::(vm) + .downcast_ref::() .ok_or_else(|| vm.new_type_error("__hash__ method should return an integer"))?; let big_int = py_int.as_bigint(); let hash: PyHash = big_int diff --git a/vm/src/vm/interpreter.rs b/vm/src/vm/interpreter.rs index 02c71bf1360..efe06d24171 100644 --- a/vm/src/vm/interpreter.rs +++ b/vm/src/vm/interpreter.rs @@ -161,7 +161,7 @@ mod tests { let a = vm.new_pyobj(crate::common::ascii!("Hello ")); let b = vm.new_pyobj(4_i32); let res = vm._mul(&a, &b).unwrap(); - let value = res.payload::().unwrap(); + let value = res.downcast_ref::().unwrap(); assert_eq!(value.as_str(), "Hello Hello Hello Hello ") }) } diff --git a/vm/src/vm/mod.rs b/vm/src/vm/mod.rs index b147f8528b7..78f5ec309cc 100644 --- a/vm/src/vm/mod.rs +++ b/vm/src/vm/mod.rs @@ -657,9 +657,9 @@ impl VirtualMachine { let cls = value.class(); let list_borrow; let slice = if cls.is(self.ctx.types.tuple_type) { - value.payload::().unwrap().as_slice() + value.downcast_ref::().unwrap().as_slice() } else if cls.is(self.ctx.types.list_type) { - list_borrow = value.payload::().unwrap().borrow_vec(); + list_borrow = value.downcast_ref::().unwrap().borrow_vec(); &list_borrow } else { return self.map_py_iter(value, func); diff --git a/vm/src/vm/vm_ops.rs b/vm/src/vm/vm_ops.rs index 00ba2d0f664..f0e495c8db8 100644 --- a/vm/src/vm/vm_ops.rs +++ b/vm/src/vm/vm_ops.rs @@ -119,7 +119,7 @@ impl VirtualMachine { } }; let hint = result - .payload_if_subclass::(self) + .downcast_ref::() .ok_or_else(|| { self.new_type_error(format!( "'{}' object cannot be interpreted as an integer", diff --git a/wasm/lib/src/convert.rs b/wasm/lib/src/convert.rs index 9d83f70cebc..94476ff226a 100644 --- a/wasm/lib/src/convert.rs +++ b/wasm/lib/src/convert.rs @@ -41,7 +41,7 @@ pub fn py_err_to_js_err(vm: &VirtualMachine, py_err: &PyBaseExceptionRef) -> JsV }; let js_arg = js_arg .as_ref() - .and_then(|x| x.payload::()); + .and_then(|x| x.downcast_ref::()); match js_arg { Some(val) => val.value.clone(), None => { @@ -134,7 +134,7 @@ pub fn py_to_js(vm: &VirtualMachine, py_obj: PyObjectRef) -> JsValue { } // the browser module might not be injected if vm.try_class("_js", "Promise").is_ok() { - if let Some(py_prom) = py_obj.payload::() { + if let Some(py_prom) = py_obj.downcast_ref::() { return py_prom.as_js(vm).into(); } }