Add payload views and Py handle shortcuts (#8812)

* Add payload views and Py handle shortcuts

PyTuple::payload_slice, PyBytes::payload_bytes, and PyStr::payload_wtf8
expose the payload data. Common payload methods are forwarded from Py<T>.

Assisted-by: Grok CLI:grok-4.7

* Call PyTuple::as_slice from payload_slice

`&*self` tripped clippy borrow_deref_ref and needless_borrow.

Assisted-by: Grok CLI:grok-4.7

* Use Element.is_empty in the truth-value check

len() != 0 trips clippy::len_zero once is_empty is available.

Assisted-by: Grok CLI:grok-4.7

* Drop redundant payload view aliases

as_bytes, as_wtf8, and as_slice already forward to the payload methods.

Assisted-by: Grok CLI:grok-4.7

* Forward more payload methods from Py handles

Frame iframe, bytearray buffer, set add, exception args and traceback,
and length or lookup helpers are available on Py<T>.

Assisted-by: Grok CLI:grok-4.7

* Read type slots through payload in macros

Generated subclass checks and MRO slot inheritance no longer use Deref
to reach PyType.slots or attributes.

Assisted-by: Grok CLI:grok-4.7

* Index a few tuples through as_slice

These Py<PyTuple> indexes no longer rely on Deref to [T].

Assisted-by: Grok CLI:grok-4.7

* Read type slots through Py<PyType>::slots

obj.class().slots and builtin type slots now call slots() instead of
the payload field.

Assisted-by: Grok CLI:grok-4.7

* Read type version and heap layout through Py<PyType>

Inline-cache checks use tp_version_tag(). Heap-type weakref checks use
heaptype_ext().

Assisted-by: Grok CLI:grok-4.7

* Call slots() on Py type handles

Type creation, type methods, and frame specialization read slots through
Py<PyType> instead of the payload field.

Assisted-by: Grok CLI:grok-4.7

* Use as_bytes, as_slice, and traceback accessors

Bytes lengths go through as_bytes(). Tuple len, emptiness, and
iteration go through as_slice(). Exception handles use traceback().

Assisted-by: Grok CLI:grok-4.7

* Drop shortcuts that only forward payload methods

Tuple length and iteration go through as_slice. Dict and list expose
len. Set add stays on the payload.

Assisted-by: Grok CLI:grok-4.7

* Drop dict and list len shortcuts

len without is_empty fails clippy. Tuple element lookup uses
as_slice().get instead of iter().nth.

Assisted-by: Grok CLI:grok-4.7
This commit is contained in:
Jeong, YunWon authored and GitHub committed 2026-09-25 20:07:06 +09:00
1 parent 5d15791e11
commit 0ebc6570e3
43 files changed
+286 -201

No files matched your search

+1 -1
View File
@@ -257,7 +257,7 @@ pub unsafe extern "C" fn PyException_GetTraceback(exc: *mut PyObject) -> *mut Py
with_vm(|vm| {
let exc = unsafe { exc.assume_borrowed_and_cast::<PyBaseException>(vm) }?;
let tb = exc
.__traceback__()
.traceback()
.map(|tb| tb.into_object().into_raw().as_ptr())
.unwrap_or_default();
Ok(tb)
+1 -1
View File
@@ -764,7 +764,7 @@ pub(crate) fn impl_pyclass(attr: PunctuatedNestedMeta, item: Item) -> Result<Tok
#[inline]
unsafe fn validate_downcastable_from(obj: &::rustpython_vm::PyObject) -> bool {
<Self as ::rustpython_vm::class::PyClassDef>::BASICSIZE <= obj.class().slots.basicsize && obj.class().fast_issubclass(<Self as ::rustpython_vm::class::StaticType>::static_type())
<Self as ::rustpython_vm::class::PyClassDef>::BASICSIZE <= obj.class().payload().slots.basicsize && obj.class().fast_issubclass(<Self as ::rustpython_vm::class::StaticType>::static_type())
}
fn class(ctx: &::rustpython_vm::vm::Context) -> &'static ::rustpython_vm::Py<::rustpython_vm::builtins::PyType> {
+2 -2
View File
@@ -755,7 +755,7 @@ impl ModuleItem for ClassItem {
// module resolution, e.g. TypeAliasType)
{
let module_key = rustpython_vm::identifier!(ctx, __module__);
let has_module_getset = new_class.attributes
let has_module_getset = new_class.payload().attributes
.get(module_key)
.is_some_and(|v| v.downcastable::<rustpython_vm::builtins::PyGetSet>());
if !has_module_getset {
@@ -849,7 +849,7 @@ impl ModuleItem for StructSequenceItem {
let new_class = <#pytype_ident as ::rustpython_vm::class::PyClassImpl>::make_static_type();
{
let module_key = rustpython_vm::identifier!(ctx, __module__);
let has_module_getset = new_class.attributes
let has_module_getset = new_class.payload().attributes
.get(module_key)
.is_some_and(|v| v.downcastable::<rustpython_vm::builtins::PyGetSet>());
if !has_module_getset {
+2 -2
View File
@@ -322,7 +322,7 @@ pub(crate) mod _asyncio {
// Save the original traceback for later restoration
if let Ok(exc_ref) = exc.clone().downcast::<PyBaseException>() {
let tb = exc_ref.__traceback__().map(|tb| tb.into());
let tb = exc_ref.traceback().map(|tb| tb.into());
*zelf.fut_exception_tb.write() = tb;
}
@@ -2296,7 +2296,7 @@ pub(crate) mod _asyncio {
} else {
task.base.fut_state.store(FutureState::Finished);
// Save the original traceback for later restoration
let tb = exc.__traceback__().map(|tb| tb.into());
let tb = exc.traceback().map(|tb| tb.into());
*task.base.fut_exception_tb.write() = tb;
*task.base.fut_exception.write() = Some(exc.clone().into());
task.base.fut_log_tb.store(true, Ordering::Relaxed);
+5 -1
View File
@@ -239,6 +239,10 @@ pub(crate) mod _elementtree {
self.inner.read().children.len()
}
fn is_empty(&self) -> bool {
self.len() == 0
}
fn child(&self, index: usize) -> Option<PyObjectRef> {
self.inner.read().children.get(index).cloned()
}
@@ -1209,7 +1213,7 @@ pub(crate) mod _elementtree {
None,
vm,
)?;
Ok(zelf.len() != 0)
Ok(!zelf.is_empty())
}),
..PyNumberMethods::NOT_IMPLEMENTED
};
+1 -1
View File
@@ -52,7 +52,7 @@ impl PyObject {
#[cold]
#[inline(never)]
fn try_to_bool_slow(&self, vm: &VirtualMachine) -> PyResult<bool> {
let slots = &self.class().slots;
let slots = self.class().slots();
// 1. Try nb_bool slot first
if let Some(nb_bool) = slots.as_number.boolean.load() {
+12 -5
View File
@@ -550,6 +550,11 @@ impl PyBytes {
#[pyclass]
impl Py<PyBytes> {
#[inline]
pub fn as_bytes(&self) -> &[u8] {
self.payload().as_bytes()
}
#[pymethod]
fn __reduce_ex__(
&self,
@@ -637,7 +642,7 @@ impl AsBuffer for PyBytes {
fn as_buffer(zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<PyBuffer> {
let buf = PyBuffer::new(
zelf.to_owned().into(),
BufferDescriptor::simple(zelf.len(), true),
BufferDescriptor::simple(zelf.as_bytes().len(), true),
&BUFFER_METHODS,
);
Ok(buf)
@@ -647,7 +652,9 @@ impl AsBuffer for PyBytes {
impl AsMapping for PyBytes {
fn as_mapping() -> &'static PyMappingMethods {
static AS_MAPPING: LazyLock<PyMappingMethods> = LazyLock::new(|| PyMappingMethods {
length: atomic_func!(|mapping, _vm| Ok(PyBytes::mapping_downcast(mapping).len())),
length: atomic_func!(|mapping, _vm| {
Ok(PyBytes::mapping_downcast(mapping).as_bytes().len())
}),
subscript: atomic_func!(
|mapping, needle, vm| PyBytes::mapping_downcast(mapping)._getitem(needle, vm)
),
@@ -660,7 +667,7 @@ impl AsMapping for PyBytes {
impl AsSequence for PyBytes {
fn as_sequence() -> &'static PySequenceMethods {
static AS_SEQUENCE: LazyLock<PySequenceMethods> = LazyLock::new(|| PySequenceMethods {
length: atomic_func!(|seq, _vm| Ok(PyBytes::sequence_downcast(seq).len())),
length: atomic_func!(|seq, _vm| Ok(PyBytes::sequence_downcast(seq).as_bytes().len())),
concat: atomic_func!(|seq, other, vm| {
PyBytes::sequence_downcast(seq)
.inner
@@ -769,7 +776,7 @@ impl PyPayload for PyBytesIterator {
impl PyBytesIterator {
#[pymethod]
fn __length_hint__(&self) -> usize {
self.internal.lock().length_hint(|obj| obj.len())
self.internal.lock().length_hint(|obj| obj.as_bytes().len())
}
#[pymethod]
@@ -787,7 +794,7 @@ impl PyBytesIterator {
fn __setstate__(&self, state: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
self.internal
.lock()
.set_state(&state, |obj, pos| pos.min(obj.len()), vm)
.set_state(&state, |obj, pos| pos.min(obj.as_bytes().len()), vm)
}
}
+1 -1
View File
@@ -560,5 +560,5 @@ fn vectorcall_float(
#[rustfmt::skip] // to avoid line splitting
pub(crate) fn init(context: &'static Context) {
PyFloat::extend_class(context, context.types.float_type);
context.types.float_type.slots.vectorcall.store(Some(vectorcall_float));
context.types.float_type.slots().vectorcall.store(Some(vectorcall_float));
}
+2 -2
View File
@@ -369,11 +369,11 @@ fn subs_tvars(
for arg in sub_params.iter() {
if let Some(idx) = tuple_index(params.as_slice(), arg) {
let param = &params[idx];
let param = &params.as_slice()[idx];
let substituted_arg = &arg_items[idx];
// Check if this is a TypeVarTuple (has tp_iter)
if param.class().slots.iter.load().is_some()
if param.class().slots().iter.load().is_some()
&& substituted_arg.try_to_ref::<PyTuple>(vm).is_ok()
{
// TypeVarTuple case - extend with tuple elements
+13 -1
View File
@@ -128,6 +128,18 @@ impl ToPyObject for Vec<PyObjectRef> {
}
}
impl Py<PyList> {
#[inline]
pub fn borrow_vec(&self) -> PyMappedRwLockReadGuard<'_, [PyObjectRef]> {
self.payload().borrow_vec()
}
#[inline]
pub fn borrow_vec_mut(&self) -> PyRwLockWriteGuard<'_, Vec<PyObjectRef>> {
self.payload().borrow_vec_mut()
}
}
impl PyList {
#[deprecated(note = "use PyList::from(...).into_ref() instead")]
pub fn new_ref(elements: Vec<PyObjectRef>, ctx: &Context) -> PyRef<Self> {
@@ -792,7 +804,7 @@ fn object_lt(
vm: &VirtualMachine,
) -> PyResult<bool> {
#[allow(unpredictable_function_pointer_comparisons)]
if a.class().slots.richcompare.load() != Some(cmp) {
if a.class().slots().richcompare.load() != Some(cmp) {
return a.rich_compare_bool(b, PyComparisonOp::Lt, vm);
}
match cmp(a, b, PyComparisonOp::Lt, vm)? {
+6 -1
View File
@@ -1474,7 +1474,12 @@ static BUFFER_WRAPPER_METHODS: BufferMethods = BufferMethods {
// A native release runs when the memoryview itself is torn down; only a
// Python-level hook on a foreign exporter has to be called here.
if !mv.buffer.obj.is(&wrapper.exporter)
&& wrapper.exporter.class().slots.python_release_buffer.load()
&& wrapper
.exporter
.class()
.slots()
.python_release_buffer
.load()
{
call_python_release_buffer(&wrapper.exporter, mv.clone());
}
+13 -9
View File
@@ -186,7 +186,7 @@ fn type_slot_names(typ: &Py<PyType>, vm: &VirtualMachine) -> PyResult<Option<sup
// object_getstate_default
fn object_getstate_default(obj: &PyObject, required: bool, vm: &VirtualMachine) -> PyResult {
// Check itemsize
if required && obj.class().slots.itemsize > 0 {
if required && obj.class().slots().itemsize > 0 {
return Err(vm.new_type_error(format!("cannot pickle {:.200} objects", obj.class().name())));
}
@@ -205,22 +205,22 @@ fn object_getstate_default(obj: &PyObject, required: bool, vm: &VirtualMachine)
if required {
// Start with PyBaseObject_Type's basicsize
let mut basicsize = vm.ctx.types.object_type.slots.basicsize;
let mut basicsize = vm.ctx.types.object_type.slots().basicsize;
// Add __dict__ size if type has dict
if obj.class().slots.flags.has_feature(PyTypeFlags::HAS_DICT) {
if obj.class().slots().flags.has_feature(PyTypeFlags::HAS_DICT) {
basicsize += core::mem::size_of::<PyObjectRef>();
}
// Add __weakref__ size if type has weakref support
let has_weakref = if let Some(ref ext) = obj.class().heaptype_ext {
let has_weakref = if let Some(ext) = obj.class().heaptype_ext() {
match &ext.slots {
None => true, // Heap type without __slots__ has automatic weakref
Some(slots) => slots.iter().any(|s| s.as_bytes() == b"__weakref__"),
}
} else {
let weakref_name = vm.ctx.intern_str("__weakref__");
obj.class().attributes.contains(weakref_name)
obj.class().attributes().contains(weakref_name)
};
if has_weakref {
basicsize += core::mem::size_of::<PyObjectRef>();
@@ -232,7 +232,7 @@ fn object_getstate_default(obj: &PyObject, required: bool, vm: &VirtualMachine)
}
// Fail if actual type's basicsize > expected basicsize
if obj.class().slots.basicsize > basicsize {
if obj.class().slots().basicsize > basicsize {
return Err(vm.new_type_error(format!("cannot pickle '{}' object", obj.class().name())));
}
}
@@ -326,7 +326,7 @@ impl PyBaseObject {
}
}
PyComparisonOp::Ne => {
let cmp = zelf.class().slots.richcompare.load().unwrap();
let cmp = zelf.class().slots().richcompare.load().unwrap();
let value = match cmp(zelf, other, PyComparisonOp::Eq, vm)? {
Either::A(obj) => PyArithmeticValue::from_object(vm, obj)
.map(|obj| obj.try_to_bool(vm))
@@ -524,7 +524,7 @@ impl PyBaseObject {
#[pymethod]
fn __sizeof__(zelf: PyObjectRef) -> usize {
zelf.class().slots.basicsize
zelf.class().slots().basicsize
}
}
@@ -580,7 +580,11 @@ pub fn object_generic_set_dict(
pub(crate) fn init(ctx: &'static Context) {
// Manually set alloc/init slots - derive macro doesn't generate extend_slots
// for trait impl that overrides #[pyslot] method
ctx.types.object_type.slots.alloc.store(Some(generic_alloc));
ctx.types
.object_type
.slots()
.alloc
.store(Some(generic_alloc));
ctx.types
.object_type
.slots
+10
View File
@@ -629,6 +629,16 @@ impl PyStr {
}
impl Py<PyStr> {
#[inline]
pub fn as_wtf8(&self) -> &Wtf8 {
self.payload().as_wtf8()
}
#[inline]
pub fn as_bytes(&self) -> &[u8] {
self.payload().as_bytes()
}
pub fn as_utf8(&self) -> Option<&Py<PyUtf8Str>> {
if self.is_utf8() {
// SAFETY: is_utf8() guarantees the PyUtf8Str invariant.
+34 -35
View File
@@ -295,7 +295,7 @@ impl<'a, R> core::iter::IntoIterator for &'a PyTuple<R> {
type IntoIter = core::slice::Iter<'a, R>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
self.as_slice().iter()
}
}
@@ -304,7 +304,7 @@ impl<'a, R> core::iter::IntoIterator for &'a Py<PyTuple<R>> {
type IntoIter = core::slice::Iter<'a, R>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
PyTuple::as_slice(self).iter()
}
}
@@ -313,23 +313,6 @@ impl<R> PyTuple<R> {
pub fn as_slice(&self) -> &[R] {
&self.elements
}
#[inline]
#[must_use]
pub fn len(&self) -> usize {
self.elements.len()
}
#[inline]
#[must_use]
pub fn is_empty(&self) -> bool {
self.elements.is_empty()
}
#[inline]
pub fn iter(&self) -> core::slice::Iter<'_, R> {
self.elements.iter()
}
}
impl PyTuple<PyObjectRef> {
@@ -367,7 +350,7 @@ impl PyTuple<PyObjectRef> {
}
fn repeat(zelf: PyRef<Self>, value: isize, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
Ok(if zelf.elements.is_empty() || value == 0 {
Ok(if zelf.as_slice().is_empty() || value == 0 {
vm.ctx.empty_tuple.clone()
} else if value == 1 && zelf.class().is(vm.ctx.types.tuple_type) {
// Special case: when some `tuple` is multiplied by `1`,
@@ -387,6 +370,11 @@ impl PyTuple<PyObjectRef> {
}
impl Py<PyTuple> {
#[inline]
pub fn as_slice(&self) -> &[PyObjectRef] {
self.payload().as_slice()
}
pub fn extract_tuple<'a, T: FromPyTuple<'a>>(&'a self, vm: &VirtualMachine) -> PyResult<T> {
T::from_pytuple(self, vm)
}
@@ -433,12 +421,13 @@ impl PyTuple {
vm: &VirtualMachine,
) -> PyArithmeticValue<PyRef<Self>> {
let added = other.downcast::<Self>().map(|other| {
if other.elements.is_empty() && zelf.class().is(vm.ctx.types.tuple_type) {
if other.as_slice().is_empty() && zelf.class().is(vm.ctx.types.tuple_type) {
zelf
} else if zelf.elements.is_empty() && other.class().is(vm.ctx.types.tuple_type) {
} else if zelf.as_slice().is_empty() && other.class().is(vm.ctx.types.tuple_type) {
other
} else {
let elements = zelf
.as_slice()
.iter()
.chain(other.as_slice())
.cloned()
@@ -466,7 +455,7 @@ impl PyTuple {
#[inline]
#[must_use]
pub fn __len__(&self) -> usize {
self.elements.len()
self.as_slice().len()
}
fn __mul__(zelf: PyRef<Self>, value: ArgSize, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
@@ -500,8 +489,8 @@ impl PyTuple {
range: OptionalRangeArgs,
vm: &VirtualMachine,
) -> PyResult<usize> {
let (start, stop) = range.saturate(self.len(), vm)?;
for (index, element) in self.elements.iter().enumerate().take(stop).skip(start) {
let (start, stop) = range.saturate(self.as_slice().len(), vm)?;
for (index, element) in self.as_slice().iter().enumerate().take(stop).skip(start) {
if vm.identical_or_equal(element, &needle)? {
return Ok(index);
}
@@ -548,7 +537,9 @@ impl PyTuple {
impl AsMapping for PyTuple {
fn as_mapping() -> &'static PyMappingMethods {
static AS_MAPPING: LazyLock<PyMappingMethods> = LazyLock::new(|| PyMappingMethods {
length: atomic_func!(|mapping, _vm| Ok(PyTuple::mapping_downcast(mapping).len())),
length: atomic_func!(|mapping, _vm| {
Ok(PyTuple::mapping_downcast(mapping).as_slice().len())
}),
subscript: atomic_func!(
|mapping, needle, vm| PyTuple::mapping_downcast(mapping)._getitem(needle, vm)
),
@@ -595,7 +586,7 @@ impl AsNumber for PyTuple {
static AS_NUMBER: PyNumberMethods = PyNumberMethods {
boolean: Some(|number, _vm| {
let zelf = number.obj.downcast_ref::<PyTuple>().unwrap();
Ok(!zelf.elements.is_empty())
Ok(!zelf.as_slice().is_empty())
}),
..PyNumberMethods::NOT_IMPLEMENTED
};
@@ -621,9 +612,10 @@ impl Comparable for PyTuple {
return Ok(res.into());
}
let other = class_or_notimplemented!(Self, other);
zelf.iter()
zelf.as_slice()
.iter()
.map(|o| &**o)
.richcompare(other.iter().map(|o| &**o), op, vm)
.richcompare(other.as_slice().iter().map(|o| &**o), op, vm)
.map(PyComparisonValue::Implemented)
}
}
@@ -640,13 +632,20 @@ impl Iterable for PyTuple {
impl Representable for PyTuple {
#[inline]
fn repr(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<PyStrRef> {
let s = if zelf.is_empty() {
let s = if zelf.as_slice().is_empty() {
vm.ctx.intern_str("()").to_owned()
} else if let Some(_guard) = ReprGuard::enter(vm, zelf.as_object()) {
let s = if zelf.len() == 1 {
wtf8_concat!("(", zelf.elements[0].repr(vm)?.as_wtf8(), ",)")
let s = if zelf.as_slice().len() == 1 {
wtf8_concat!("(", zelf.as_slice()[0].repr(vm)?.as_wtf8(), ",)")
} else {
collection_repr(None, "(", ")", "()", zelf.elements.iter().map(|o| &**o), vm)?
collection_repr(
None,
"(",
")",
"()",
zelf.as_slice().iter().map(|o| &**o),
vm,
)?
};
vm.ctx.new_str(s)
} else {
@@ -713,14 +712,14 @@ impl PyPayload for PyTupleIterator {
impl PyTupleIterator {
#[pymethod]
fn __length_hint__(&self) -> usize {
self.internal.lock().length_hint(|obj| obj.len())
self.internal.lock().length_hint(|obj| obj.as_slice().len())
}
#[pymethod]
fn __setstate__(&self, state: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
self.internal
.lock()
.set_state(&state, |obj, pos| pos.min(obj.len()), vm)
.set_state(&state, |obj, pos| pos.min(obj.as_slice().len()), vm)
}
#[pymethod]
+36 -14
View File
@@ -797,7 +797,7 @@ impl PyType {
interpreter_id: HeapTypeExt::creating_interpreter_id(),
};
let bases = PyTuple::new_ref_typed(bases, ctx);
let base = bases[0].clone();
let base = bases.as_slice()[0].clone();
Self::new_heap_inner(
base,
@@ -1651,6 +1651,26 @@ impl PyType {
}
impl Py<PyType> {
#[inline]
pub fn slots(&self) -> &PyTypeSlots {
&self.payload().slots
}
#[inline]
pub fn attributes(&self) -> &TypeNamespace {
&self.payload().attributes
}
#[inline]
pub fn tp_version_tag(&self) -> &AtomicU32 {
&self.payload().tp_version_tag
}
#[inline]
pub fn heaptype_ext(&self) -> Option<&HeapTypeExt> {
self.payload().heaptype_ext.as_deref()
}
pub fn is_subtype(&self, other: &Self) -> bool {
is_subtype_with_mro(&self.mro.read(), self, other)
}
@@ -1722,7 +1742,7 @@ impl PyType {
fn set_bases(zelf: &Py<Self>, bases_tuple: PyTupleRef, vm: &VirtualMachine) -> PyResult<()> {
// TODO: Assigning to __bases__ is only used in typing.NamedTupleMeta.__new__
// Rather than correctly re-initializing the class, we are skipping a few steps for now
if zelf.slots.flags.has_feature(PyTypeFlags::IMMUTABLETYPE) {
if zelf.slots().flags.has_feature(PyTypeFlags::IMMUTABLETYPE) {
return Err(vm.new_type_error(format!(
"cannot set '__bases__' attribute of immutable type '{}'",
zelf.name()
@@ -3015,7 +3035,7 @@ impl GetAttr for PyType {
let zelf_attr = zelf.get_attr(name);
if let Some(attr) = zelf_attr {
let descr_get = attr.class().slots.descr_get.load();
let descr_get = attr.class().slots().descr_get.load();
if let Some(descr_get) = descr_get {
descr_get(attr.as_object(), None, Some(zelf.as_object()), vm)
} else {
@@ -3058,7 +3078,7 @@ impl Py<PyType> {
// CPython returns None if __doc__ is not in the type's own dict
if let Some(doc_attr) = self.get_direct_attr(vm.ctx.intern_str("__doc__")) {
// If it's a descriptor, call its __get__ method
let descr_get = doc_attr.class().slots.descr_get.load();
let descr_get = doc_attr.class().slots().descr_get.load();
if let Some(descr_get) = descr_get {
descr_get(doc_attr.as_object(), None, Some(self.as_object()), vm)
} else {
@@ -3135,7 +3155,7 @@ impl SetAttr for PyType {
vm: &VirtualMachine,
) -> PyResult<()> {
let attr_name = vm.ctx.intern_str(attr_name.as_wtf8());
if zelf.slots.flags.has_feature(PyTypeFlags::IMMUTABLETYPE) {
if zelf.slots().flags.has_feature(PyTypeFlags::IMMUTABLETYPE) {
return Err(vm.new_type_error(format!(
"cannot set '{}' attribute of immutable type '{}'",
attr_name,
@@ -3143,7 +3163,7 @@ impl SetAttr for PyType {
)));
}
if let Some(attr) = zelf.get_class_attr(attr_name) {
let descr_set = attr.class().slots.descr_set.load();
let descr_set = attr.class().slots().descr_set.load();
if let Some(descriptor) = descr_set {
return descriptor(&attr, zelf.to_owned().into(), value, vm);
}
@@ -3160,9 +3180,9 @@ impl SetAttr for PyType {
zelf.modified_inner();
let prev_value = if let PySetterValue::Assign(value) = value {
zelf.attributes.insert(attr_name, value)
zelf.attributes().insert(attr_name, value)
} else {
let prev_value = zelf.attributes.remove(attr_name);
let prev_value = zelf.attributes().remove(attr_name);
if prev_value.is_none() {
return Err(vm.new_attribute_error(format!(
"type object '{}' has no attribute '{}'",
@@ -3203,8 +3223,10 @@ impl Callable for PyType {
}
}
let Some(slot_new) = zelf.slots.new.load() else {
return Err(vm.new_type_error(format!("cannot create '{}' instances", zelf.slots.name)));
let Some(slot_new) = zelf.slots().new.load() else {
return Err(
vm.new_type_error(format!("cannot create '{}' instances", zelf.slots().name))
);
};
// Both the new and init slots consume args, so the init call gets a
@@ -3223,7 +3245,7 @@ impl Callable for PyType {
// so a mismatch is conservative: if it ever compared unequal for the
// wrapper it would only take the slower cloning path, never the fast
// path incorrectly.
if zelf.slots.init.load().is_none()
if zelf.slots().init.load().is_none()
&& !zelf.is(vm.ctx.types.type_type)
&& crate::types::fn_addr(slot_new)
!= crate::types::fn_addr(crate::types::new_wrapper as crate::types::NewFunc)
@@ -3239,7 +3261,7 @@ impl Callable for PyType {
return Ok(obj);
}
if let Some(init_method) = obj.class().slots.init.load() {
if let Some(init_method) = obj.class().slots().init.load() {
init_method(&obj, init_args, vm)?;
}
Ok(obj)
@@ -3406,10 +3428,10 @@ fn vectorcall_type(
if nargs == 1 && no_kwargs {
return Ok(args[0].obj_type());
}
} else if zelf.slots.call.load().is_none() && zelf.slots.new.load().is_some() {
} else if zelf.slots().call.load().is_none() && zelf.slots().new.load().is_some() {
// Per-type constructor vectorcall for non-callable types (dict, list, int, etc.)
// Also guard on slots.new to avoid dispatching for DISALLOW_INSTANTIATION types.
if let Some(type_vc) = zelf.slots.vectorcall.load() {
if let Some(type_vc) = zelf.slots().vectorcall.load() {
return type_vc(zelf_obj, args, nargs, kwnames, vm);
}
}
+2 -2
View File
@@ -365,7 +365,7 @@ fn dedup_and_flatten_args(args: &Py<PyTuple>, vm: &VirtualMachine) -> PyResult<U
pub fn make_union(args: &Py<PyTuple>, vm: &VirtualMachine) -> PyResult {
let result = dedup_and_flatten_args(args, vm)?;
Ok(match result.args.len() {
1 => result.args[0].to_owned(),
1 => result.args.as_slice()[0].to_owned(),
_ => PyUnion::from_components(result, vm)?.to_pyobject(vm),
})
}
@@ -383,7 +383,7 @@ impl PyUnion {
Ok(if new_args.is_empty() {
make_union(&new_args, vm)?
} else {
let mut tmp = new_args[0].to_owned();
let mut tmp = new_args.as_slice()[0].to_owned();
for arg in new_args.iter().skip(1) {
tmp = vm._or(&tmp, arg)?;
}
+2 -2
View File
@@ -23,7 +23,7 @@ impl PyPayload for PyWeakProxy {
#[inline]
unsafe fn validate_downcastable_from(obj: &PyObject) -> bool {
<Self as ::rustpython_vm::class::PyClassDef>::BASICSIZE <= obj.class().slots.basicsize
<Self as ::rustpython_vm::class::PyClassDef>::BASICSIZE <= obj.class().slots().basicsize
&& obj
.class()
.fast_issubclass(<Self as ::rustpython_vm::class::StaticType>::static_type())
@@ -170,7 +170,7 @@ impl Iterable for PyWeakProxy {
impl IterNext for PyWeakProxy {
fn next(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
let obj = zelf.try_upgrade(vm)?;
if obj.class().slots.iternext.load().is_none() {
if obj.class().slots().iternext.load().is_none() {
return Err(vm.new_type_error("Weakref proxy referenced a non-iterator"));
}
PyIter::new(obj).next(vm)
+1 -1
View File
@@ -57,7 +57,7 @@ fn collect_bytes(
// which knows what it was being asked to do, rather than by the
// iteration protocol saying the object is not iterable.
let cls = obj.class();
if cls.slots.iter.load().is_none() && !cls.has_attr(identifier!(vm, __getitem__)) {
if cls.slots().iter.load().is_none() && !cls.has_attr(identifier!(vm, __getitem__)) {
return Err(vm.new_type_error(unusable(&cls.name())));
}
let value = |x: PyObjectRef| value_from_object_with(vm, &x, element);
+2 -2
View File
@@ -138,7 +138,7 @@ fn spec_format_bytes(
// CPython parity: bytes `%c` accepts a single byte or any object
// with `__index__` in range(256).
if let Some(b) = obj.downcast_ref::<PyBytes>() {
if b.len() == 1 {
if b.as_bytes().len() == 1 {
return Ok(spec.format_char(b.as_bytes()[0]));
}
} else if let Some(ba) = obj.downcast_ref::<PyByteArray>() {
@@ -155,7 +155,7 @@ fn spec_format_bytes(
// A bytes-like argument that is not one byte long is named by
// its length rather than by its type.
let what = if let Some(b) = obj.downcast_ref::<PyBytes>() {
format!("a bytes object of length {}", b.len())
format!("a bytes object of length {}", b.as_bytes().len())
} else if let Some(ba) = obj.downcast_ref::<PyByteArray>() {
format!("a bytearray object of length {}", ba.borrow_buf().len())
} else {
+9 -9
View File
@@ -24,7 +24,7 @@ pub fn add_operators(class: &'static Py<PyType>, ctx: &Context) {
// Special handling for __hash__ = None
if def.name == "__hash__"
&& class.slots.hash.load().is_some_and(|h| {
&& class.slots().hash.load().is_some_and(|h| {
fn_addr(h) == fn_addr(hash_not_implemented as crate::types::HashFunc)
})
{
@@ -40,13 +40,13 @@ pub fn add_operators(class: &'static Py<PyType>, ctx: &Context) {
}
// Get the slot function wrapped in SlotFunc
let Some(slot_func) = def.accessor.get_slot_func_with_op(&class.slots, def.op) else {
let Some(slot_func) = def.accessor.get_slot_func_with_op(class.slots(), def.op) else {
continue;
};
// Check if attribute already exists in dict
let attr_name = ctx.intern_str(def.name);
if class.attributes.contains(attr_name) {
if class.attributes().contains(attr_name) {
continue;
}
@@ -157,7 +157,7 @@ pub trait PyClassImpl: PyClassDef {
{
// NOTE: `is_created_with_flags` if only available when debug_assertions is true
#[cfg(debug_assertions)]
debug_assert!(class.slots.flags.is_created_with_flags());
debug_assert!(class.slots().flags.is_created_with_flags());
let _ = ctx.intern_str(Self::NAME); // intern type name
@@ -181,7 +181,7 @@ pub trait PyClassImpl: PyClassDef {
// Only set __doc__ if it doesn't already exist (e.g., as a member descriptor)
// This matches CPython's behavior in type_dict_set_doc
let doc_attr_name = identifier!(ctx, __doc__);
if class.attributes.get(doc_attr_name).is_none() {
if class.attributes().get(doc_attr_name).is_none() {
class.set_attr(doc_attr_name, ctx.new_str(doc).into());
}
}
@@ -191,7 +191,7 @@ pub trait PyClassImpl: PyClassDef {
// Don't overwrite a getset descriptor for __module__ (e.g. TypeAliasType
// has an instance-level __module__ getset that should not be replaced)
let has_getset = class
.attributes
.attributes()
.get(module_key)
.is_some_and(|v| v.downcastable::<crate::builtins::PyGetSet>());
if !has_getset {
@@ -202,8 +202,8 @@ pub trait PyClassImpl: PyClassDef {
// Don't add __new__ attribute if slot_new is inherited from object
// (Python doesn't add __new__ to __dict__ for inherited slots)
// Exception: object itself should have __new__ in its dict
if let Some(slot_new) = class.slots.new.load() {
let object_new = ctx.types.object_type.slots.new.load();
if let Some(slot_new) = class.slots().new.load() {
let object_new = ctx.types.object_type.slots().new.load();
let is_object_itself = core::ptr::eq(class, ctx.types.object_type);
let is_inherited_from_object = !is_object_itself
&& object_new.is_some_and(|obj_new| fn_addr(slot_new) == fn_addr(obj_new));
@@ -224,7 +224,7 @@ pub trait PyClassImpl: PyClassDef {
class.inherit_slots(base);
}
class.extend_methods(class.slots.methods, ctx);
class.extend_methods(class.slots().methods, ctx);
}
#[must_use]
+1 -1
View File
@@ -655,7 +655,7 @@ pub(crate) fn unraisable_while_closing(
) {
// Explicit close() leaves the traceback to the caller frame.
// Finalize has no caller frame, so attach the generator site here.
if e.__traceback__().is_none()
if e.traceback().is_none()
&& let Some(frame) = coro.frame_opt()
{
let lasti = frame.lasti().saturating_mul(2);
+10 -5
View File
@@ -358,11 +358,11 @@ impl VirtualMachine {
0 => vec![],
1 => {
let args0_repr = if str_single {
varargs[0]
varargs.as_slice()[0]
.str(vm)
.unwrap_or_else(|_| PyStr::from("<element str() failed>").into_ref(&vm.ctx))
} else {
varargs[0].repr(vm).unwrap_or_else(|_| {
varargs.as_slice()[0].repr(vm).unwrap_or_else(|_| {
PyStr::from("<element repr() failed>").into_ref(&vm.ctx)
})
};
@@ -383,7 +383,7 @@ impl VirtualMachine {
&self,
exc: PyBaseExceptionRef,
) -> (PyObjectRef, PyObjectRef, PyObjectRef) {
let tb = exc.__traceback__().to_pyobject(self);
let tb = exc.traceback().to_pyobject(self);
let class = exc.class().to_owned();
(class.into(), exc.into(), tb)
}
@@ -777,6 +777,11 @@ impl PyBaseException {
#[pyclass]
impl Py<PyBaseException> {
#[inline]
pub fn traceback(&self) -> Option<PyTracebackRef> {
self.payload().__traceback__()
}
#[pymethod]
pub(super) fn __str__(&self, vm: &VirtualMachine) -> PyStrRef {
let str_args = vm.exception_args_as_string(&self.args(), true);
@@ -1249,7 +1254,7 @@ impl serde::Serialize for SerializeException<'_, '_> {
s.end()
}
}
self.exc.__traceback__().map(Tracebacks)
self.exc.traceback().map(Tracebacks)
};
struc.serialize_field("traceback", &tbs)?;
struc.serialize_field(
@@ -3413,7 +3418,7 @@ pub fn exception_group_match(
let wrapped = eg_type.call((vm.ctx.new_str(""), excs), vm)?;
// Copy traceback from original exception
if let Ok(exc) = exc_value.to_owned().downcast::<types::PyBaseException>()
&& let Some(tb) = exc.__traceback__()
&& let Some(tb) = exc.traceback()
&& let Ok(wrapped_exc) = wrapped.clone().downcast::<types::PyBaseException>()
{
wrapped_exc.set_traceback(Some(tb));
+61 -55
View File
@@ -2670,7 +2670,7 @@ pub(crate) fn trampoline_handle_exception(
// Add traceback entry at the call site.
if let Some((loc, _end_loc)) = exec.code.locations.get(idx) {
let next = exception.__traceback__();
let next = exception.traceback();
let new_traceback = PyTraceback::new(next, exec.frame_object(vm), idx as u32 * 2, loc.line);
exception.set_traceback(Some(new_traceback.into_ref(&vm.ctx)));
}
@@ -3513,7 +3513,7 @@ impl ExecutingFrame<'_> {
let exc_type: PyObjectRef = exc.class().to_owned().into();
let exc_value: PyObjectRef = exc.to_owned().into();
let exc_tb: PyObjectRef = exc
.__traceback__()
.traceback()
.map_or_else(|| vm.ctx.none(), |tb| -> PyObjectRef { tb.into() });
let tuple = vm.ctx.new_tuple(vec![exc_type, exc_value, exc_tb]).into();
vm.trace_event(crate::protocol::TraceEvent::Exception, Some(tuple))?;
@@ -3588,7 +3588,7 @@ impl ExecutingFrame<'_> {
Ok(_) => {}
Err(exception) => {
if let Some((loc, _end_loc)) = self.code.locations.get(idx) {
let next = exception.__traceback__();
let next = exception.traceback();
let new_traceback = PyTraceback::new(
next,
self.frame_object(vm),
@@ -3697,7 +3697,7 @@ impl ExecutingFrame<'_> {
vm: &VirtualMachine,
) -> FrameResult {
if let Some((loc, _end_loc)) = frame.code.locations.get(idx) {
let next = exception.__traceback__();
let next = exception.traceback();
let new_traceback = PyTraceback::new(
next,
frame.frame_object(vm),
@@ -3780,14 +3780,14 @@ impl ExecutingFrame<'_> {
// Check if the exception already has traceback entries before
// we add ours. If it does, it was propagated from a callee
// function and we should not re-contextualize it.
let had_prior_traceback = exception.__traceback__().is_some();
let had_prior_traceback = exception.traceback().is_some();
// PyTraceBack_Here always adds a new entry without
// checking for duplicates. Each time an exception passes through
// a frame (e.g., in a loop with repeated raise statements),
// a new traceback entry is added.
if let Some((loc, _end_loc)) = frame.code.locations.get(idx) {
let next = exception.__traceback__();
let next = exception.traceback();
let new_traceback = PyTraceback::new(
next,
@@ -3999,7 +3999,7 @@ impl ExecutingFrame<'_> {
let idx = self.lasti().saturating_sub(1) as usize;
if idx < self.code.locations.len() {
let (loc, _end_loc) = self.code.locations[idx];
let next = err.__traceback__();
let next = err.traceback();
let new_traceback =
PyTraceback::new(next, self.frame_object(vm), idx as u32 * 2, loc.line);
err.set_traceback(Some(new_traceback.into_ref(&vm.ctx)));
@@ -4057,7 +4057,7 @@ impl ExecutingFrame<'_> {
let idx = self.lasti().saturating_sub(1) as usize;
if idx < self.code.locations.len() {
let (loc, _end_loc) = self.code.locations[idx];
let next = err.__traceback__();
let next = err.traceback();
let new_traceback = PyTraceback::new(
next,
self.frame_object(vm),
@@ -4106,7 +4106,7 @@ impl ExecutingFrame<'_> {
let idx = self.lasti().saturating_sub(1) as usize;
if idx < self.code.locations.len() {
let (loc, _end_loc) = self.code.locations[idx];
let next = exception.__traceback__();
let next = exception.traceback();
let new_traceback =
PyTraceback::new(next, self.frame_object(vm), idx as u32 * 2, loc.line);
exception.set_traceback(Some(new_traceback.into_ref(&vm.ctx)));
@@ -4907,7 +4907,7 @@ impl ExecutingFrame<'_> {
// Only rewrite the error if the type is truly not iterable
// (no __iter__ and no __getitem__). Preserve original TypeError
// from custom iterables that raise during iteration.
let not_iterable = iterable.class().slots.iter.load().is_none()
let not_iterable = iterable.class().slots().iter.load().is_none()
&& iterable
.get_class_attr(vm.ctx.intern_str("__getitem__"))
.is_none();
@@ -6004,7 +6004,7 @@ impl ExecutingFrame<'_> {
let type_version = self.code.instructions.read_cache_u32(cache_base + 1);
if type_version != 0
&& owner.class().tp_version_tag.load(Acquire) == type_version
&& owner.class().tp_version_tag().load(Acquire) == type_version
&& let Some(func) = self.try_read_cached_descriptor(cache_base, type_version)
{
let owner = self.pop_stackref();
@@ -6023,7 +6023,7 @@ impl ExecutingFrame<'_> {
let type_version = self.code.instructions.read_cache_u32(cache_base + 1);
if type_version != 0
&& owner.class().tp_version_tag.load(Acquire) == type_version
&& owner.class().tp_version_tag().load(Acquire) == type_version
&& !owner.has_instance_dict()
&& let Some(func) = self.try_read_cached_descriptor(cache_base, type_version)
{
@@ -6043,7 +6043,8 @@ impl ExecutingFrame<'_> {
let owner = self.top_value();
let type_version = self.code.instructions.read_cache_u32(cache_base + 1);
if type_version != 0 && owner.class().tp_version_tag.load(Acquire) == type_version {
if type_version != 0 && owner.class().tp_version_tag().load(Acquire) == type_version
{
// Check instance dict doesn't shadow the method.
let shadowed = match self.shadowing_instance_attr(cache_base, attr_name, vm) {
Ok(shadowed) => shadowed.is_some(),
@@ -6071,7 +6072,8 @@ impl ExecutingFrame<'_> {
let owner = self.top_value();
let type_version = self.code.instructions.read_cache_u32(cache_base + 1);
if type_version != 0 && owner.class().tp_version_tag.load(Acquire) == type_version {
if type_version != 0 && owner.class().tp_version_tag().load(Acquire) == type_version
{
// Type version matches — no data descriptor for this attr.
// Try direct dict lookup, skipping full descriptor protocol.
if let Some(dict) = owner.dict()
@@ -6094,7 +6096,7 @@ impl ExecutingFrame<'_> {
let type_version = self.code.instructions.read_cache_u32(cache_base + 1);
if type_version != 0
&& owner.class().tp_version_tag.load(Acquire) == type_version
&& owner.class().tp_version_tag().load(Acquire) == type_version
&& let Some(dict) = owner.dict()
{
// Try the cached entry index first; a hit is an identity
@@ -6132,7 +6134,7 @@ impl ExecutingFrame<'_> {
let type_version = self.code.instructions.read_cache_u32(cache_base + 1);
if type_version != 0
&& owner.class().tp_version_tag.load(Acquire) == type_version
&& owner.class().tp_version_tag().load(Acquire) == type_version
&& let Some(module) = owner.downcast_ref_if_exact::<PyModule>(vm)
&& let Ok(value) = module.get_attr(attr_name, vm)
{
@@ -6155,7 +6157,7 @@ impl ExecutingFrame<'_> {
let type_version = self.code.instructions.read_cache_u32(cache_base + 1);
if type_version != 0
&& owner.class().tp_version_tag.load(Acquire) == type_version
&& owner.class().tp_version_tag().load(Acquire) == type_version
&& let Some(attr) = self.try_read_cached_descriptor(cache_base, type_version)
{
self.pop_stackref();
@@ -6177,7 +6179,8 @@ impl ExecutingFrame<'_> {
let owner = self.top_value();
let type_version = self.code.instructions.read_cache_u32(cache_base + 1);
if type_version != 0 && owner.class().tp_version_tag.load(Acquire) == type_version {
if type_version != 0 && owner.class().tp_version_tag().load(Acquire) == type_version
{
// Instance dict has priority — check if attr is shadowed
if let Some(value) = self.shadowing_instance_attr(cache_base, attr_name, vm)? {
self.pop_stackref();
@@ -6240,7 +6243,7 @@ impl ExecutingFrame<'_> {
&& metaclass_version != 0
&& let Some(owner_type) = owner.downcast_ref::<PyType>()
&& owner_type.tp_version_tag.load(Acquire) == type_version
&& owner.class().tp_version_tag.load(Acquire) == metaclass_version
&& owner.class().tp_version_tag().load(Acquire) == metaclass_version
&& let Some(attr) = self.try_read_cached_descriptor(cache_base, type_version)
{
self.pop_stackref();
@@ -6265,7 +6268,7 @@ impl ExecutingFrame<'_> {
&& !self.specialization_eval_frame_active(vm)
&& type_version != 0
&& func_version != 0
&& owner.class().tp_version_tag.load(Acquire) == type_version
&& owner.class().tp_version_tag().load(Acquire) == type_version
&& let Some(func_obj) =
self.try_read_cached_descriptor(cache_base, type_version)
&& let Some(func) = func_obj.downcast_ref_if_exact::<PyFunction>(vm)
@@ -6289,7 +6292,8 @@ impl ExecutingFrame<'_> {
let owner = self.top_value();
let type_version = self.code.instructions.read_cache_u32(cache_base + 1);
if type_version != 0 && owner.class().tp_version_tag.load(Acquire) == type_version {
if type_version != 0 && owner.class().tp_version_tag().load(Acquire) == type_version
{
let slot_offset =
self.code.instructions.read_cache_u32(cache_base + 3) as i32 as isize;
if let Some(value) = owner.get_slot(slot_offset) {
@@ -6315,7 +6319,7 @@ impl ExecutingFrame<'_> {
if type_version != 0
&& !self.specialization_eval_frame_active(vm)
&& owner.class().tp_version_tag.load(Acquire) == type_version
&& owner.class().tp_version_tag().load(Acquire) == type_version
&& let Some(fget_obj) =
self.try_read_cached_descriptor(cache_base, type_version)
&& let Some(func) = fget_obj.downcast_ref_if_exact::<PyFunction>(vm)
@@ -6338,7 +6342,7 @@ impl ExecutingFrame<'_> {
let type_version = self.code.instructions.read_cache_u32(cache_base + 1);
if type_version != 0
&& owner.class().tp_version_tag.load(Acquire) == type_version
&& owner.class().tp_version_tag().load(Acquire) == type_version
&& let Some(dict) = owner.dict()
{
self.pop_stackref(); // owner
@@ -6360,7 +6364,7 @@ impl ExecutingFrame<'_> {
let type_version = self.code.instructions.read_cache_u32(cache_base + 1);
if type_version != 0
&& owner.class().tp_version_tag.load(Acquire) == type_version
&& owner.class().tp_version_tag().load(Acquire) == type_version
&& let Some(dict) = owner.dict()
{
self.pop_stackref(); // owner
@@ -6376,7 +6380,7 @@ impl ExecutingFrame<'_> {
let type_version = self.code.instructions.read_cache_u32(cache_base + 1);
let version_match = type_version != 0 && {
let owner = self.top_value();
owner.class().tp_version_tag.load(Acquire) == type_version
owner.class().tp_version_tag().load(Acquire) == type_version
};
if version_match {
@@ -6462,7 +6466,7 @@ impl ExecutingFrame<'_> {
let owner = self.nth_value(1);
if !self.specialization_eval_frame_active(vm)
&& type_version != 0
&& owner.class().tp_version_tag.load(Acquire) == type_version
&& owner.class().tp_version_tag().load(Acquire) == type_version
&& let Some((func, func_version)) =
owner.class().get_cached_getitem_for_specialization()
&& func.func_version() == func_version
@@ -7128,7 +7132,7 @@ impl ExecutingFrame<'_> {
let nargs: u32 = arg.into();
let callable = self.nth_value(nargs + 1);
if let Some(cls) = callable.downcast_ref::<PyType>()
&& cls.slots.vectorcall.load().is_some()
&& cls.slots().vectorcall.load().is_some()
{
let (callable, args_vec) = self.take_call_args(nargs as usize);
let effective_nargs = args_vec.len();
@@ -7153,12 +7157,12 @@ impl ExecutingFrame<'_> {
&& !self_or_null_is_some
&& cached_version != 0
&& let Some(cls) = callable.downcast_ref::<PyType>()
&& cls.tp_version_tag.load(Acquire) == cached_version
&& cls.tp_version_tag().load(Acquire) == cached_version
&& let Some((init_func, init_func_version)) =
cls.get_cached_init_for_specialization(cached_version)
&& init_func.func_version() == init_func_version
&& init_func.has_exact_argcount(nargs + 1)
&& let Some(cls_alloc) = cls.slots.alloc.load()
&& let Some(cls_alloc) = cls.slots().alloc.load()
{
// The specialization runs `__init__` directly with no
// interpreter-visible trampoline frame. Deopt when the
@@ -7510,14 +7514,14 @@ impl ExecutingFrame<'_> {
if let Some(descr) = cls.get_direct_attr(attr_name) {
let descr_cls = descr.class();
if descr_cls
.slots
.slots()
.flags
.has_feature(PyTypeFlags::METHOD_DESCRIPTOR)
{
// Method descriptor: push unbound func + self
// CALL will prepend self as first positional arg
found = Some((descr, true));
} else if let Some(descr_get) = descr_cls.slots.descr_get.load() {
} else if let Some(descr_get) = descr_cls.slots().descr_get.load() {
// Has __get__ but not METHOD_DESCRIPTOR: bind it
let bound = descr_get(
&descr,
@@ -7695,7 +7699,8 @@ impl ExecutingFrame<'_> {
let cache_base = instr_idx + 1;
let obj = self.top_value();
let cached_version = self.code.instructions.read_cache_u32(cache_base + 1);
if cached_version != 0 && obj.class().tp_version_tag.load(Acquire) == cached_version
if cached_version != 0
&& obj.class().tp_version_tag().load(Acquire) == cached_version
{
self.pop_stackref();
self.push_bool_or_fused_jump(instruction.cache_entries(), true, vm);
@@ -8775,7 +8780,7 @@ impl ExecutingFrame<'_> {
// Stack: [callable, self_or_null]
let callable = self.nth_value(1);
let func_str = Self::object_function_str(callable, vm);
let not_iterable = args_obj.class().slots.iter.load().is_none()
let not_iterable = args_obj.class().slots().iter.load().is_none()
&& args_obj
.get_class_attr(vm.ctx.intern_str("__getitem__"))
.is_none();
@@ -9157,7 +9162,7 @@ impl ExecutingFrame<'_> {
fn execute_unpack_ex(&mut self, vm: &VirtualMachine, before: u8, after: u32) -> FrameResult {
let (before, after) = (before as usize, after as usize);
let value = self.pop_value();
let not_iterable = value.class().slots.iter.load().is_none()
let not_iterable = value.class().slots().iter.load().is_none()
&& value
.get_class_attr(vm.ctx.intern_str("__getitem__"))
.is_none();
@@ -9686,7 +9691,7 @@ impl ExecutingFrame<'_> {
// General path — iterate up to `size + 1` elements to avoid
// consuming the entire iterator (fixes hang on infinite sequences).
let not_iterable = value.class().slots.iter.load().is_none()
let not_iterable = value.class().slots().iter.load().is_none()
&& value
.get_class_attr(vm.ctx.intern_str("__getitem__"))
.is_none();
@@ -10073,7 +10078,7 @@ impl ExecutingFrame<'_> {
}
// Only specialize if getattro is the default (PyBaseObject::getattro)
let is_default_getattro = cls.slots.getattro.load().is_some_and(|f| {
let is_default_getattro = cls.slots().getattro.load().is_some_and(|f| {
crate::types::fn_addr(f)
== crate::types::fn_addr(PyBaseObject::getattro as crate::types::GetattroFunc)
});
@@ -10147,7 +10152,7 @@ impl ExecutingFrame<'_> {
}
let cls_attr = cls.get_attr(attr_name);
let class_has_dict = cls.slots.flags.has_feature(PyTypeFlags::HAS_DICT);
let class_has_dict = cls.slots().flags.has_feature(PyTypeFlags::HAS_DICT);
if oparg.is_method() {
// Method specialization
@@ -10186,12 +10191,12 @@ impl ExecutingFrame<'_> {
// Regular attribute access
let has_data_descr = cls_attr.as_ref().is_some_and(|descr| {
let descr_cls = descr.class();
descr_cls.slots.descr_get.load().is_some()
&& descr_cls.slots.descr_set.load().is_some()
descr_cls.slots().descr_get.load().is_some()
&& descr_cls.slots().descr_set.load().is_some()
});
let has_descr_get = cls_attr
.as_ref()
.is_some_and(|descr| descr.class().slots.descr_get.load().is_some());
.is_some_and(|descr| descr.class().slots().descr_get.load().is_some());
if has_data_descr {
// Check for member descriptor (slot access)
@@ -10332,7 +10337,7 @@ impl ExecutingFrame<'_> {
let (mcl_attr, mut metaclass_version) = mcl.lookup_ref_and_version_interned(attr_name, _vm);
if let Some(ref attr) = mcl_attr {
let attr_class = attr.class();
if attr_class.slots.descr_set.load().is_some() {
if attr_class.slots().descr_set.load().is_some() {
// Data descriptor on metaclass — can't specialize
unsafe {
self.code.instructions.write_adaptive_counter(
@@ -10549,7 +10554,7 @@ impl ExecutingFrame<'_> {
let cls = a.class();
// Check the cheap gates before the __getitem__ lookup, which
// takes the global type lock and may allocate a version tag.
if cls.slots.flags.has_feature(PyTypeFlags::HEAPTYPE)
if cls.slots().flags.has_feature(PyTypeFlags::HEAPTYPE)
&& !self.specialization_eval_frame_active(vm)
{
let (getitem, type_version) =
@@ -11058,7 +11063,7 @@ impl ExecutingFrame<'_> {
// type/str/tuple(x) and class-call specializations
if let Some(cls) = callable.downcast_ref::<PyType>() {
if cls.slots.flags.has_feature(PyTypeFlags::IMMUTABLETYPE) {
if cls.slots().flags.has_feature(PyTypeFlags::IMMUTABLETYPE) {
if !self_or_null_is_some && nargs == 1 {
let new_op = if callable.is(&vm.ctx.types.type_type.as_object()) {
Some(Instruction::CallType1)
@@ -11074,7 +11079,7 @@ impl ExecutingFrame<'_> {
return;
}
}
if cls.slots.vectorcall.load().is_some() {
if cls.slots().vectorcall.load().is_some() {
self.specialize_at(instr_idx, cache_base, Instruction::CallBuiltinClass);
return;
}
@@ -11090,15 +11095,15 @@ impl ExecutingFrame<'_> {
}
// CallAllocAndEnterInit: heap type with default __new__
if !self_or_null_is_some && cls.slots.flags.has_feature(PyTypeFlags::HEAPTYPE) {
if !self_or_null_is_some && cls.slots().flags.has_feature(PyTypeFlags::HEAPTYPE) {
// Capture the version before inspecting tp_new/tp_alloc so a
// concurrently installed __new__ invalidates the version this
// specialization is cached against.
let type_version = cls.version_for_specialization(vm);
let object_new = vm.ctx.types.object_type.slots.new.load();
let cls_new = cls.slots.new.load();
let object_alloc = vm.ctx.types.object_type.slots.alloc.load();
let cls_alloc = cls.slots.alloc.load();
let object_new = vm.ctx.types.object_type.slots().new.load();
let cls_new = cls.slots().new.load();
let object_alloc = vm.ctx.types.object_type.slots().alloc.load();
let cls_alloc = cls.slots().alloc.load();
if let (Some(cls_new_fn), Some(obj_new_fn), Some(cls_alloc_fn), Some(obj_alloc_fn)) =
(cls_new, object_new, cls_alloc, object_alloc)
&& crate::types::fn_addr(cls_new_fn) == crate::types::fn_addr(obj_new_fn)
@@ -11502,14 +11507,14 @@ impl ExecutingFrame<'_> {
Some(Instruction::ToBoolList)
} else if cls.is(PyStr::class(&vm.ctx)) {
Some(Instruction::ToBoolStr)
} else if cls.slots.flags.has_feature(PyTypeFlags::HEAPTYPE) {
} else if cls.slots().flags.has_feature(PyTypeFlags::HEAPTYPE) {
// Capture the version before inspecting the bool/len slots so a
// concurrently installed __bool__/__len__ invalidates the version
// the ToBoolAlwaysTrue guard is cached against.
let type_version = cls.version_for_specialization(vm);
let has_bool_or_len = cls.slots.as_number.boolean.load().is_some()
|| cls.slots.as_mapping.length.load().is_some()
|| cls.slots.as_sequence.length.load().is_some();
let has_bool_or_len = cls.slots().as_number.boolean.load().is_some()
|| cls.slots().as_mapping.length.load().is_some()
|| cls.slots().as_sequence.length.load().is_some();
if !has_bool_or_len {
if type_version != 0 {
unsafe {
@@ -11977,7 +11982,7 @@ impl ExecutingFrame<'_> {
}
// Only specialize if setattr is the default (generic_setattr)
let is_default_setattr = cls.slots.setattro.load().is_some_and(|f| {
let is_default_setattr = cls.slots().setattro.load().is_some_and(|f| {
crate::types::fn_addr(f)
== crate::types::fn_addr(PyBaseObject::slot_setattro as crate::types::SetattroFunc)
});
@@ -11997,7 +12002,8 @@ impl ExecutingFrame<'_> {
let cls_attr = cls.get_attr(attr_name);
let has_data_descr = cls_attr.as_ref().is_some_and(|descr| {
let descr_cls = descr.class();
descr_cls.slots.descr_get.load().is_some() && descr_cls.slots.descr_set.load().is_some()
descr_cls.slots().descr_get.load().is_some()
&& descr_cls.slots().descr_set.load().is_some()
});
if has_data_descr {
+1 -1
View File
@@ -271,7 +271,7 @@ pub fn remove_importlib_frames(vm: &VirtualMachine, exc: &Py<PyBaseException>) {
let always_trim = exc.fast_isinstance(vm.ctx.exceptions.import_error);
if let Some(tb) = exc.__traceback__() {
if let Some(tb) = exc.traceback() {
let trimmed_tb = remove_importlib_frames_inner(vm, Some(tb), always_trim).0;
exc.set_traceback(trimmed_tb);
}
+2 -2
View File
@@ -2110,7 +2110,7 @@ impl PyObject {
// __del__ should only be called once (like _PyGC_FINALIZED check in GIL_DISABLED)
// We call __del__ BEFORE clearing weakrefs to allow the finalizer to access
// the object's weak references if needed.
let del = self.class().slots.del.load();
let del = self.class().slots().del.load();
if let Some(slot_del) = del
&& !self.gc_finalized()
{
@@ -2228,7 +2228,7 @@ impl PyObject {
/// This allows proper resurrection detection.
/// PyObject_CallFinalizerFromDealloc
pub fn try_call_finalizer(&self) {
let del = self.class().slots.del.load();
let del = self.class().slots().del.load();
if let Some(slot_del) = del
&& !self.gc_finalized()
&& self
+2 -2
View File
@@ -312,7 +312,7 @@ impl PyBuffer {
}
// slot_bf_releasebuffer: a Python-level `__release_buffer__` runs first,
// then the exporter's own release so export counts stay balanced.
if self.obj.class().slots.python_release_buffer.load() {
if self.obj.class().slots().python_release_buffer.load() {
crate::builtins::memory::release_buffer_call_python(self);
}
(self.methods.release)(self)
@@ -368,7 +368,7 @@ impl PyObject {
/// `__buffer__` is not mistaken for "not a buffer".
#[must_use]
pub fn check_buffer(&self) -> bool {
self.class().slots.as_buffer.load().is_some()
self.class().slots().as_buffer.load().is_some()
}
}
+1 -1
View File
@@ -66,7 +66,7 @@ pub struct PyCallable<'a> {
impl<'a> PyCallable<'a> {
pub fn new(obj: &'a PyObject) -> Option<Self> {
let slots = &obj.class().slots;
let slots = obj.class().slots();
let call = slots.call.load()?;
let vectorcall = slots.vectorcall.load();
Some(PyCallable {
+2 -2
View File
@@ -26,7 +26,7 @@ unsafe impl<O: Borrow<PyObject>> Traverse for PyIter<O> {
impl PyIter<PyObjectRef> {
pub fn check(obj: &PyObject) -> bool {
obj.class().slots.iternext.load().is_some()
obj.class().slots().iternext.load().is_some()
}
}
@@ -136,7 +136,7 @@ impl TryFromObject for PyIter<PyObjectRef> {
// in the vm when a for loop is entered. Next, it is used when the builtin
// function 'iter' is called.
fn try_from_object(vm: &VirtualMachine, iter_target: PyObjectRef) -> PyResult<Self> {
let get_iter = iter_target.class().slots.iter.load();
let get_iter = iter_target.class().slots().iter.load();
if let Some(get_iter) = get_iter {
let iter = get_iter(iter_target, vm)?;
if Self::check(&iter) {
+1 -1
View File
@@ -113,7 +113,7 @@ impl PyMapping<'_> {
#[inline]
#[must_use]
pub fn slots(&self) -> &PyMappingSlots {
&self.obj.class().slots.as_mapping
&self.obj.class().slots().as_mapping
}
#[inline]
+5 -5
View File
@@ -661,12 +661,12 @@ impl PyNumber<'_> {
// PyIndex_Check
#[must_use]
pub fn is_index(self) -> bool {
self.class().slots.as_number.index.load().is_some()
self.class().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| {
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) {
@@ -695,7 +695,7 @@ and may be removed in a future version of Python.",
#[inline]
pub fn index(self, vm: &VirtualMachine) -> Option<PyResult<PyIntRef>> {
self.class().slots.as_number.index.load().map(|f| {
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) {
@@ -724,7 +724,7 @@ and may be removed in a future version of Python.",
#[inline]
pub fn float(self, vm: &VirtualMachine) -> Option<PyResult<PyRef<PyFloat>>> {
self.class().slots.as_number.float.load().map(|f| {
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) {
@@ -756,7 +756,7 @@ and may be removed in a future version of Python.",
// PyNumber_Check - slots are now inherited
#[must_use]
pub fn check(obj: &PyObject) -> bool {
let methods = &obj.class().slots.as_number;
let methods = &obj.class().slots().as_number;
let has_number = methods.int.load().is_some()
|| methods.index.load().is_some()
|| methods.float.load().is_some();
+9 -9
View File
@@ -134,7 +134,7 @@ impl PyObject {
#[inline]
pub(crate) fn get_attr_inner(&self, attr_name: &Py<PyStr>, vm: &VirtualMachine) -> PyResult {
vm_trace!("object.__getattribute__: {:?} {:?}", self, attr_name);
let getattro = self.class().slots.getattro.load().unwrap();
let getattro = self.class().slots().getattro.load().unwrap();
getattro(self, attr_name, vm).inspect_err(|exc| {
vm.set_attribute_error_context(exc, self.to_owned(), attr_name.to_owned());
})
@@ -191,7 +191,7 @@ impl PyObject {
.interned_str(attr_name)
.and_then(|attr_name| self.get_class_attr(attr_name));
if let Some(attr) = &descr
&& let Some(descriptor) = attr.class().slots.descr_set.load()
&& let Some(descriptor) = attr.class().slots().descr_set.load()
{
return descriptor(attr, self.to_owned(), value, vm);
}
@@ -205,7 +205,7 @@ impl PyObject {
}
// Only a type that left __setattr__ alone can be told about the
// missing __dict__, since overriding it is what hides the slot.
let generic_setattro = self.class().slots.setattro.load().is_some_and(|f| {
let generic_setattro = self.class().slots().setattro.load().is_some_and(|f| {
crate::types::fn_addr(f)
== crate::types::fn_addr(
PyBaseObject::slot_setattro as crate::types::SetattroFunc,
@@ -338,7 +338,7 @@ impl PyObject {
) -> PyResult<Either<PyObjectRef, bool>> {
let swapped = op.swapped();
let call_cmp = |obj: &Self, other: &Self, op| {
let Some(cmp) = obj.class().slots.richcompare.load() else {
let Some(cmp) = obj.class().slots().richcompare.load() else {
return Ok(PyArithmeticValue::NotImplemented);
};
let r = match cmp(obj, other, op, vm)? {
@@ -420,7 +420,7 @@ impl PyObject {
pub fn repr(&self, vm: &VirtualMachine) -> PyResult<PyRef<PyStr>> {
vm.with_recursion("while getting the repr of an object", || {
self.class().slots.repr.load().map_or_else(
self.class().slots().repr.load().map_or_else(
|| {
Err(vm.new_runtime_error(format!(
"BUG: object of type '{}' has no __repr__ method. This is a bug in RustPython.",
@@ -460,7 +460,7 @@ impl PyObject {
Err(obj) => obj,
};
// TODO: replace to obj.class().slots.str
// TODO: replace to obj.class().slots().str
let Some(str_method) = vm.get_special_method(&obj, identifier!(vm, __str__))? else {
return obj.repr(vm);
};
@@ -720,7 +720,7 @@ impl PyObject {
}
pub fn hash(&self, vm: &VirtualMachine) -> PyResult<PyHash> {
if let Some(hash) = self.class().slots.hash.load() {
if let Some(hash) = self.class().slots().hash.load() {
return vm.with_recursion("while hashing", || hash(self, vm));
}
@@ -837,7 +837,7 @@ impl PyObject {
// A type carrying a sequence table turns the deletion down in
// PySequence_DelItem's words instead; every heap type carries one.
let name = self.class().slot_name();
let msg = if seq.slots().has_any() || self.class().heaptype_ext.is_some() {
let msg = if seq.slots().has_any() || self.class().heaptype_ext().is_some() {
format!("'{name}' object doesn't support item deletion")
} else {
format!("'{name}' object does not support item deletion")
@@ -859,7 +859,7 @@ impl PyObject {
return Ok(None);
};
let descr_get = res.class().slots.descr_get.load();
let descr_get = res.class().slots().descr_get.load();
if let Some(descr_get) = descr_get {
descr_get(res.as_object(), Some(self), Some(obj_cls.as_object()), vm).map(Some)
} else {
+1 -1
View File
@@ -153,7 +153,7 @@ impl PySequence<'_> {
#[inline]
#[must_use]
pub fn slots(&self) -> &PySequenceSlots {
&self.obj.class().slots.as_sequence
&self.obj.class().slots().as_sequence
}
#[must_use]
+1 -1
View File
@@ -287,7 +287,7 @@ mod _codecs {
#[pyfunction]
fn escape_encode(args: EscapeEncodeArgs, _vm: &VirtualMachine) -> (Vec<u8>, usize) {
let encoded = encodings::escape::encode(args.data.as_bytes());
(encoded, args.data.len())
(encoded, args.data.as_bytes().len())
}
#[derive(FromArgs)]
+2 -2
View File
@@ -751,8 +751,8 @@ impl Constructor for PyCFuncPtr {
.ok_or_else(|| vm.new_type_error("Expected a string"))?
.to_string();
let dll = tuple
.iter()
.nth(1)
.as_slice()
.get(1)
.ok_or_else(|| vm.new_type_error("Expected a tuple with at least 2 elements"))?
.clone();
+2 -2
View File
@@ -90,7 +90,7 @@ fn set_primitive(_type_: &str, value: &PyObject, vm: &VirtualMachine) -> PyResul
// c_set: accepts bytes(len=1), bytearray(len=1), or int(0-255)
if value
.downcast_ref_if_exact::<PyBytes>(vm)
.is_some_and(|v| v.len() == 1)
.is_some_and(|v| v.as_bytes().len() == 1)
|| value
.downcast_ref_if_exact::<PyByteArray>(vm)
.is_some_and(|v| v.borrow_buf().len() == 1)
@@ -303,7 +303,7 @@ impl PyCSimpleType {
// c_char: 1 byte character
Some("c") => {
if let Some(bytes) = value.downcast_ref::<PyBytes>()
&& bytes.len() == 1
&& bytes.as_bytes().len() == 1
{
return create_simple_with_value("c", &value);
}
+1 -1
View File
@@ -634,7 +634,7 @@ impl SetAttr for PyCStructType {
// Check for data descriptor first
if let Some(attr) = pytype.get_class_attr(attr_name_interned) {
let descr_set = attr.class().slots.descr_set.load();
let descr_set = attr.class().slots().descr_set.load();
if let Some(descriptor) = descr_set {
return descriptor(&attr, pytype.to_owned().into(), value, vm);
}
+1 -1
View File
@@ -487,7 +487,7 @@ impl SetAttr for PyCUnionType {
// 1. First, do PyType's setattro (PyType_Type.tp_setattro first)
// Check for data descriptor first
if let Some(attr) = pytype.get_class_attr(attr_name_interned) {
let descr_set = attr.class().slots.descr_set.load();
let descr_set = attr.class().slots().descr_set.load();
if let Some(descriptor) = descr_set {
descriptor(&attr, pytype.to_owned().into(), value.clone(), vm)?;
// After successful setattro, check if _fields_ and call process_fields
+1 -1
View File
@@ -3431,7 +3431,7 @@ mod _io {
num_to_skip -= n_decoded;
break;
}
skip_bytes -= dec_buffer.len() as isize;
skip_bytes -= dec_buffer.as_bytes().len() as isize;
skip_back = 1;
} else {
skip_bytes -= skip_back;
+1 -1
View File
@@ -71,7 +71,7 @@ pub fn offer_suggestions(exc: &Py<PyBaseException>, vm: &VirtualMachine) -> Opti
if vm.is_none(&name) {
return None;
}
let tb = exc.__traceback__()?;
let tb = exc.traceback()?;
let tb = tb.iter().last().unwrap_or(tb);
let varnames = tb.frame.iframe().code().to_owned().co_varnames(vm);
+21 -10
View File
@@ -427,14 +427,16 @@ impl SlotAccessor {
macro_rules! inherit_main {
($slot:ident) => {{
let inherited = mro.iter().find_map(|cls| cls.slots.$slot.load());
let inherited = mro.iter().find_map(|cls| cls.payload().slots.$slot.load());
typ.slots.$slot.store(inherited);
}};
}
macro_rules! inherit_number {
($slot:ident) => {{
let inherited = mro.iter().find_map(|cls| cls.slots.as_number.$slot.load());
let inherited = mro
.iter()
.find_map(|cls| cls.payload().slots.as_number.$slot.load());
typ.slots.as_number.$slot.store(inherited);
}};
}
@@ -443,14 +445,16 @@ impl SlotAccessor {
($slot:ident) => {{
let inherited = mro
.iter()
.find_map(|cls| cls.slots.as_sequence.$slot.load());
.find_map(|cls| cls.payload().slots.as_sequence.$slot.load());
typ.slots.as_sequence.$slot.store(inherited);
}};
}
macro_rules! inherit_mapping {
($slot:ident) => {{
let inherited = mro.iter().find_map(|cls| cls.slots.as_mapping.$slot.load());
let inherited = mro
.iter()
.find_map(|cls| cls.payload().slots.as_mapping.$slot.load());
typ.slots.as_mapping.$slot.store(inherited);
}};
}
@@ -469,8 +473,8 @@ impl SlotAccessor {
// vectorcall as a constructor fast path (call=None).
// See vectorcall_type() in type.rs for the dual-use design rationale.
let inherited_vc = mro.iter().find_map(|cls| {
if cls.slots.call.load().is_some() {
cls.slots.vectorcall.load()
if cls.payload().slots.call.load().is_some() {
cls.payload().slots.vectorcall.load()
} else {
None
}
@@ -543,13 +547,19 @@ impl SlotAccessor {
// Buffer protocol
Self::BfGetBuffer => {
let inherited = mro.iter().find_map(|cls| cls.slots.as_buffer.load());
let inherited = mro
.iter()
.find_map(|cls| cls.payload().slots.as_buffer.load());
typ.slots.as_buffer.store(inherited);
}
Self::BfReleaseBuffer => {
let has_release = mro.iter().any(|cls| cls.slots.has_release_buffer.load());
let has_release = mro
.iter()
.any(|cls| cls.payload().slots.has_release_buffer.load());
typ.slots.has_release_buffer.store(has_release);
let py_release = mro.iter().any(|cls| cls.slots.python_release_buffer.load());
let py_release = mro
.iter()
.any(|cls| cls.payload().slots.python_release_buffer.load());
typ.slots.python_release_buffer.store(py_release);
}
@@ -623,7 +633,8 @@ impl SlotAccessor {
&& let Some(base_val) = base.slots.init.load()
{
let slot_defined = base.base.deref().is_none_or(|bb| {
bb.slots.init.load().map(|v| fn_addr(v)) != Some(fn_addr(base_val))
bb.payload().slots.init.load().map(|v| fn_addr(v))
!= Some(fn_addr(base_val))
});
if slot_defined {
typ.slots.init.store(Some(base_val));
+2 -2
View File
@@ -1637,7 +1637,7 @@ impl VirtualMachine {
let unraisablehook = sys_module.get_attr("unraisablehook", self).unwrap();
let exc_type = e.class().to_owned();
let exc_traceback = e.__traceback__().to_pyobject(self); // TODO: actual traceback
let exc_traceback = e.traceback().to_pyobject(self); // TODO: actual traceback
let exc_value = e.into();
let args = stdlib::sys::UnraisableHookArgsData {
exc_type,
@@ -3439,7 +3439,7 @@ impl VirtualMachine {
attr_name: impl AsPyStr<'a>,
) -> PyResult<Option<PyObjectRef>> {
let attr_name = attr_name.as_pystr(&self.ctx);
let getattro = obj.class().slots.getattro.load().unwrap();
let getattro = obj.class().slots().getattro.load().unwrap();
let result = if fn_addr(getattro) == fn_addr(PyBaseObject::getattro as GetattroFunc) {
obj.generic_getattr_opt(attr_name, None, self)
} else {
+1 -1
View File
@@ -109,7 +109,7 @@ impl VirtualMachine {
obj: Option<&PyObject>,
cls: Option<&PyObject>,
) -> Option<PyResult> {
let descr_get = descr.class().slots.descr_get.load()?;
let descr_get = descr.class().slots().descr_get.load()?;
Some(descr_get(descr, obj, cls, self))
}
+2 -2
View File
@@ -292,7 +292,7 @@ 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().slots().as_number.left_binary_op(iop_slot) {
let x = slot(a, b, self)?;
if !x.is(&self.ctx.not_implemented) {
return Ok(x);
@@ -419,7 +419,7 @@ 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().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);