From 87fea8fdf64f515ab978d8d02f47a3235e04446e Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Sun, 14 Jun 2026 16:01:00 +0300 Subject: [PATCH 1/5] nits --- crates/vm/src/datastack.rs | 5 +++-- crates/vm/src/intern.rs | 7 ++++++- crates/vm/src/scope.rs | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/crates/vm/src/datastack.rs b/crates/vm/src/datastack.rs index 7529263ac7e..101369fba57 100644 --- a/crates/vm/src/datastack.rs +++ b/crates/vm/src/datastack.rs @@ -23,8 +23,9 @@ const MINIMUM_OVERHEAD: usize = 1000 * core::mem::size_of::(); /// Alignment for all data stack allocations. const ALIGN: usize = 16; -/// Header for a data stack chunk. The usable data region starts right after -/// this header (aligned to `ALIGN`). +/// Header for a data stack chunk. +/// +/// The usable data region starts right after this header (aligned to [`ALIGN`]). #[repr(C)] struct DataStackChunk { /// Previous chunk in the linked list (NULL for the root chunk). diff --git a/crates/vm/src/intern.rs b/crates/vm/src/intern.rs index 981732f2dd2..b475b4d9daa 100644 --- a/crates/vm/src/intern.rs +++ b/crates/vm/src/intern.rs @@ -151,7 +151,7 @@ impl PyInterned { pub fn as_str(&self) -> &str { self.inner .to_str() - .unwrap_or_else(|| panic!("interned str is always valid UTF-8")) + .expect("interned str is always valid UTF-8") } } @@ -257,6 +257,7 @@ mod sealed { /// A sealed marker trait for `DictKey` types that always become an exact instance of `str` pub trait InternableString: sealed::SealedInternable + ToPyObject + AsRef { type Interned: MaybeInternedString + ?Sized; + fn into_pyref_exact(self, str_type: PyTypeRef) -> PyRefExact; } @@ -271,6 +272,7 @@ impl InternableString for String { impl InternableString for &str { type Interned = str; + #[inline] fn into_pyref_exact(self, str_type: PyTypeRef) -> PyRefExact { self.to_owned().into_pyref_exact(str_type) @@ -279,6 +281,7 @@ impl InternableString for &str { impl InternableString for Wtf8Buf { type Interned = Wtf8; + fn into_pyref_exact(self, str_type: PyTypeRef) -> PyRefExact { let obj = PyRef::new_ref(PyStr::from(self), str_type, None); unsafe { PyRefExact::new_unchecked(obj) } @@ -287,6 +290,7 @@ impl InternableString for Wtf8Buf { impl InternableString for &Wtf8 { type Interned = Wtf8; + fn into_pyref_exact(self, str_type: PyTypeRef) -> PyRefExact { self.to_owned().into_pyref_exact(str_type) } @@ -294,6 +298,7 @@ impl InternableString for &Wtf8 { impl InternableString for PyRefExact { type Interned = Py; + #[inline] fn into_pyref_exact(self, _str_type: PyTypeRef) -> PyRefExact { self diff --git a/crates/vm/src/scope.rs b/crates/vm/src/scope.rs index 966e953cdf3..772d5c176c8 100644 --- a/crates/vm/src/scope.rs +++ b/crates/vm/src/scope.rs @@ -17,7 +17,7 @@ impl fmt::Debug for Scope { impl Scope { #[inline] #[must_use] - pub fn new(locals: Option, globals: PyDictRef) -> Self { + pub const fn new(locals: Option, globals: PyDictRef) -> Self { Self { locals, globals } } From f03198fcf3f4d8e36fa9569dd2b29aa6f42d4386 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Sun, 14 Jun 2026 16:13:54 +0300 Subject: [PATCH 2/5] explicit_deref_methods --- Cargo.toml | 1 + crates/common/src/borrow.rs | 2 +- crates/common/src/format.rs | 2 +- crates/vm/src/builtins/list.rs | 4 ++-- crates/vm/src/builtins/set.rs | 17 +++++++++++------ crates/vm/src/builtins/type.rs | 8 ++++---- crates/vm/src/object/core.rs | 6 +++--- 7 files changed, 23 insertions(+), 17 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e1f76408ecf..197585756e6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -386,6 +386,7 @@ cloned_instead_of_copied = "warn" collapsible_else_if = "warn" comparison_chain = "warn" duration_suboptimal_units = "warn" +explicit_deref_methods = "warn" explicit_into_iter_loop = "warn" explicit_iter_loop = "warn" filter_map_next = "warn" diff --git a/crates/common/src/borrow.rs b/crates/common/src/borrow.rs index d8389479b33..2be5f8275c8 100644 --- a/crates/common/src/borrow.rs +++ b/crates/common/src/borrow.rs @@ -68,7 +68,7 @@ impl Deref for BorrowedValue<'_, T> { impl fmt::Display for BorrowedValue<'_, str> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self.deref(), f) + fmt::Display::fmt(&**self, f) } } diff --git a/crates/common/src/format.rs b/crates/common/src/format.rs index af20b5746c8..ea459886914 100644 --- a/crates/common/src/format.rs +++ b/crates/common/src/format.rs @@ -1054,7 +1054,7 @@ impl FormatSpec { cmp::max(0, (w as i32) - (num_chars as i32) - (sign_str.len() as i32)) }); - let magnitude_str = magnitude_str.deref(); + let magnitude_str = &**magnitude_str; match align { FormatAlign::Left => format!( "{}{}{}", diff --git a/crates/vm/src/builtins/list.rs b/crates/vm/src/builtins/list.rs index 2edb48852ec..2bdbaf63cde 100644 --- a/crates/vm/src/builtins/list.rs +++ b/crates/vm/src/builtins/list.rs @@ -398,13 +398,13 @@ impl PyList { let (mut elements, version_before) = { let mut guard = self.elements.write(); let version_before = self.mutation_counter.load(Ordering::Relaxed); - (core::mem::take(guard.deref_mut()), version_before) + (core::mem::take(&mut *guard), version_before) }; let res = do_sort(vm, &mut elements, options.key, options.reverse); let mutated = { let mut guard = self.elements.write(); let mutated = self.mutation_counter.load(Ordering::Relaxed) != version_before; - core::mem::swap(guard.deref_mut(), &mut elements); + core::mem::swap(&mut *guard, &mut elements); mutated }; res?; diff --git a/crates/vm/src/builtins/set.rs b/crates/vm/src/builtins/set.rs index 136470c1813..8b38223fce1 100644 --- a/crates/vm/src/builtins/set.rs +++ b/crates/vm/src/builtins/set.rs @@ -5,12 +5,17 @@ use super::{ IterStatus, PositionIterInternal, PyDict, PyDictRef, PyGenericAlias, PyTupleRef, PyType, PyTypeRef, builtins_iter, }; -use crate::common::lock::LazyLock; use crate::{ AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject, atomic_func, class::PyClassImpl, - common::{ascii, hash::PyHash, lock::PyMutex, rc::PyRc, wtf8::Wtf8Buf}, + common::{ + ascii, + hash::PyHash, + lock::{LazyLock, PyMutex}, + rc::PyRc, + wtf8::Wtf8Buf, + }, convert::ToPyResult, dict_inner::{self, DictSize}, function::{ArgIterable, FuncArgs, OptionalArg, PosArgs, PyArithmeticValue, PyComparisonValue}, @@ -24,9 +29,7 @@ use crate::{ utils::collection_repr, vm::VirtualMachine, }; -use alloc::fmt; -use core::borrow::Borrow; -use core::ops::Deref; +use core::{borrow::Borrow, fmt}; use rustpython_common::{ atomic::{Ordering, PyAtomic, Radium}, hash, @@ -924,10 +927,12 @@ impl Representable for PySet { fn repr_wtf8(zelf: &crate::Py, vm: &VirtualMachine) -> PyResult { let class = zelf.class(); let borrowed_name = class.name(); - let class_name = borrowed_name.deref(); + let class_name = &*borrowed_name; + if zelf.inner.len() == 0 { return Ok(Wtf8Buf::from(format!("{class_name}()"))); } + if let Some(_guard) = ReprGuard::enter(vm, zelf.as_object()) { let name = (class_name != "set").then_some(class_name); zelf.inner.repr(name, vm) diff --git a/crates/vm/src/builtins/type.rs b/crates/vm/src/builtins/type.rs index c097a18a516..b3980c2c789 100644 --- a/crates/vm/src/builtins/type.rs +++ b/crates/vm/src/builtins/type.rs @@ -1281,14 +1281,14 @@ impl Py { where F: Fn(&Self) -> R, { - self.mro.read().iter().map(|x| x.deref()).map(f).collect() + self.mro.read().iter().map(|x| &**x).map(f).collect() } pub fn mro_collect(&self) -> Vec> { self.mro .read() .iter() - .map(|x| x.deref()) + .map(|x| &**x) .map(|x| x.to_owned()) .collect() } @@ -2926,12 +2926,12 @@ fn best_base<'a>(bases: &'a [PyTypeRef], vm: &VirtualMachine) -> PyResult<&'a Py let candidate = solid_base(base_i, vm); if winner.is_none() { winner = Some(candidate); - base = Some(base_i.deref()); + base = Some(&**base_i); } else if winner.unwrap().fast_issubclass(candidate) { // Do nothing } else if candidate.fast_issubclass(winner.unwrap()) { winner = Some(candidate); - base = Some(base_i.deref()); + base = Some(&**base_i); } else { return Err(vm.new_type_error("multiple bases have instance layout conflict")); } diff --git a/crates/vm/src/object/core.rs b/crates/vm/src/object/core.rs index 57b190ca324..b06a8f38e11 100644 --- a/crates/vm/src/object/core.rs +++ b/crates/vm/src/object/core.rs @@ -1489,7 +1489,7 @@ impl PyObject { #[inline(always)] pub fn class(&self) -> &Py { - self.0.typ.deref() + &self.0.typ } pub fn set_class(&self, typ: PyTypeRef, vm: &VirtualMachine) { @@ -2130,7 +2130,7 @@ where { #[inline] fn eq(&self, other: &Self) -> bool { - self.deref().eq(other.deref()) + self.deref().eq(&**other) } } @@ -2407,7 +2407,7 @@ where { #[inline] fn eq(&self, other: &Self) -> bool { - self.deref().eq(other.deref()) + self.deref().eq(&**other) } } From 18753da9c2035e86ee163aa9d816de6dee28e76c Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Sun, 14 Jun 2026 16:36:44 +0300 Subject: [PATCH 3/5] significant_drop_in_scrutinee --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 197585756e6..fd6ddfbf9b1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -373,6 +373,7 @@ needless_collect = "warn" or_fun_call = "warn" redundant_clone = "warn" search_is_some = "warn" +significant_drop_in_scrutinee = "warn" single_option_map = "warn" trait_duplication_in_bounds = "warn" unused_peekable = "warn" From fde2f66db14470a1eda7d5a78df471db8750b601 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Sun, 14 Jun 2026 16:36:54 +0300 Subject: [PATCH 4/5] stdlib --- crates/stdlib/src/_asyncio.rs | 49 +++++++++++++++++++++-------------- crates/stdlib/src/_sqlite3.rs | 3 ++- crates/stdlib/src/array.rs | 12 ++++++--- crates/stdlib/src/ssl.rs | 3 ++- 4 files changed, 42 insertions(+), 25 deletions(-) diff --git a/crates/stdlib/src/_asyncio.rs b/crates/stdlib/src/_asyncio.rs index ee5e207d4d4..48be4115ed6 100644 --- a/crates/stdlib/src/_asyncio.rs +++ b/crates/stdlib/src/_asyncio.rs @@ -224,10 +224,12 @@ pub(crate) mod _asyncio { } FutureState::Finished => { self.fut_log_tb.store(false, Ordering::Relaxed); - if let Some(exc) = self.fut_exception.read().clone() { + let fut_exception = self.fut_exception.read().clone(); + if let Some(exc) = fut_exception { let exc: PyBaseExceptionRef = exc.downcast().unwrap(); // Restore the original traceback to prevent traceback accumulation - if let Some(tb) = self.fut_exception_tb.read().clone() { + let fut_exception_tb = self.fut_exception_tb.read().clone(); + if let Some(tb) = fut_exception_tb { let _ = exc.set___traceback__(tb, vm); } Err(exc) @@ -612,7 +614,8 @@ pub(crate) mod _asyncio { fn _callbacks(&self, vm: &VirtualMachine) -> PyObjectRef { let mut result = Vec::new(); - if let Some(cb0) = self.fut_callback0.read().clone() { + let fut_callback0 = self.fut_callback0.read().clone(); + if let Some(cb0) = fut_callback0 { let ctx0 = self .fut_context0 .read() @@ -621,7 +624,8 @@ pub(crate) mod _asyncio { result.push(vm.ctx.new_tuple(vec![cb0, ctx0]).into()); } - if let Some(callbacks) = self.fut_callbacks.read().clone() { + let fut_callbacks = self.fut_callbacks.read().clone(); + if let Some(callbacks) = fut_callbacks { let list: PyListRef = callbacks.downcast().unwrap(); for item in list.borrow_vec().iter() { result.push(item.clone()); @@ -792,16 +796,12 @@ pub(crate) mod _asyncio { return Ok(()); } - let exc = zelf.fut_exception.read().clone(); - let exc = match exc { - Some(e) => e, - None => return Ok(()), + let Some(exc) = zelf.fut_exception.read().clone() else { + return Ok(()); }; - let loop_obj = zelf.fut_loop.read().clone(); - let loop_obj = match loop_obj { - Some(l) => l, - None => return Ok(()), + let Some(loop_obj) = zelf.fut_loop.read().clone() else { + return Ok(()); }; // Create context dict for call_exception_handler @@ -816,7 +816,8 @@ pub(crate) mod _asyncio { context.set_item(vm.ctx.intern_str("exception"), exc, vm)?; context.set_item(vm.ctx.intern_str("future"), zelf.to_owned().into(), vm)?; - if let Some(tb) = zelf.fut_source_tb.read().clone() { + let fut_source_tb = zelf.fut_source_tb.read().clone(); + if let Some(tb) = fut_source_tb { context.set_item(vm.ctx.intern_str("source_traceback"), tb, vm)?; } @@ -1248,12 +1249,15 @@ pub(crate) mod _asyncio { FutureState::Cancelled => Err(self.make_cancelled_error_impl(vm)), FutureState::Finished => { self.base.fut_log_tb.store(false, Ordering::Relaxed); - if let Some(exc) = self.base.fut_exception.read().clone() { + let fut_exception = self.base.fut_exception.read().clone(); + if let Some(exc) = fut_exception { let exc: PyBaseExceptionRef = exc.downcast().unwrap(); // Restore the original traceback to prevent traceback accumulation - if let Some(tb) = self.base.fut_exception_tb.read().clone() { + let fut_exception_tb = self.base.fut_exception_tb.read().clone(); + if let Some(tb) = fut_exception_tb { let _ = exc.set___traceback__(tb, vm); } + Err(exc) } else { Ok(self @@ -1517,7 +1521,8 @@ pub(crate) mod _asyncio { let msg_value = args.msg.flatten(); - if let Some(fut_waiter) = self.task_fut_waiter.read().clone() { + let task_fut_waiter = self.task_fut_waiter.read().clone(); + if let Some(fut_waiter) = task_fut_waiter { // Call cancel with msg=msg keyword argument let cancel_args = if let Some(ref m) = msg_value { FuncArgs::new( @@ -1795,7 +1800,9 @@ pub(crate) mod _asyncio { #[pygetset] fn _callbacks(&self, vm: &VirtualMachine) -> PyObjectRef { let mut result: Vec = Vec::new(); - if let Some(cb) = self.base.fut_callback0.read().clone() { + + let fut_callback0 = self.base.fut_callback0.read().clone(); + if let Some(cb) = fut_callback0 { let ctx = self .base .fut_context0 @@ -1804,6 +1811,7 @@ pub(crate) mod _asyncio { .unwrap_or_else(|| vm.ctx.none()); result.push(vm.ctx.new_tuple(vec![cb, ctx]).into()); } + if let Some(callbacks) = self.base.fut_callbacks.read().clone() && let Ok(list) = callbacks.downcast::() { @@ -1811,6 +1819,7 @@ pub(crate) mod _asyncio { result.push(item.clone()); } } + // Return None if no callbacks if result.is_empty() { vm.ctx.none() @@ -1859,7 +1868,8 @@ pub(crate) mod _asyncio { )?; context.set_item(vm.ctx.intern_str("task"), zelf.to_owned().into(), vm)?; - if let Some(tb) = zelf.base.fut_source_tb.read().clone() { + let fut_source_tb = zelf.base.fut_source_tb.read().clone(); + if let Some(tb) = fut_source_tb { context.set_item(vm.ctx.intern_str("source_traceback"), tb, vm)?; } @@ -1896,7 +1906,8 @@ pub(crate) mod _asyncio { context.set_item(vm.ctx.intern_str("exception"), exc, vm)?; context.set_item(vm.ctx.intern_str("future"), zelf.to_owned().into(), vm)?; - if let Some(tb) = zelf.base.fut_source_tb.read().clone() { + let fut_source_tb = zelf.base.fut_source_tb.read().clone(); + if let Some(tb) = fut_source_tb { context.set_item(vm.ctx.intern_str("source_traceback"), tb, vm)?; } diff --git a/crates/stdlib/src/_sqlite3.rs b/crates/stdlib/src/_sqlite3.rs index 5dfdf6f4f1e..cbe9b85c63c 100644 --- a/crates/stdlib/src/_sqlite3.rs +++ b/crates/stdlib/src/_sqlite3.rs @@ -1520,7 +1520,8 @@ mod _sqlite3 { #[pygetset] fn autocommit(&self, vm: &VirtualMachine) -> PyObjectRef { - match *self.autocommit.lock() { + let mode = *self.autocommit.lock(); + match mode { AutocommitMode::Enabled => vm.ctx.true_value.clone().into(), AutocommitMode::Disabled => vm.ctx.false_value.clone().into(), AutocommitMode::Legacy => vm.ctx.new_int(LEGACY_TRANSACTION_CONTROL).into(), diff --git a/crates/stdlib/src/array.rs b/crates/stdlib/src/array.rs index e5f8e11a0a0..a496643fcb3 100644 --- a/crates/stdlib/src/array.rs +++ b/crates/stdlib/src/array.rs @@ -660,7 +660,8 @@ pub mod array { if let OptionalArg::Present(init) = init { if let Some(init) = init.downcast_ref::() { - match (spec, init.read().typecode()) { + let value = init.read().typecode(); + match (spec, value) { (spec, ch) if spec == ch => array.frombytes(&init.get_bytes()), (spec, 'u') => { return Err(vm.new_type_error(format!( @@ -1406,12 +1407,15 @@ pub mod array { } impl SelfIter for PyArrayIter {} + impl IterNext for PyArrayIter { fn next(zelf: &Py, vm: &VirtualMachine) -> PyResult { zelf.internal.lock().next(|array, pos| { - Ok(match array.read().get(pos, vm) { - Some(item) => PyIterReturn::Return(item?), - None => PyIterReturn::StopIteration(None), + let value = array.read().get(pos, vm); + Ok(if let Some(item) = value { + PyIterReturn::Return(item?) + } else { + PyIterReturn::StopIteration(None) }) }) } diff --git a/crates/stdlib/src/ssl.rs b/crates/stdlib/src/ssl.rs index 121e25ed11b..d4a01c9b131 100644 --- a/crates/stdlib/src/ssl.rs +++ b/crates/stdlib/src/ssl.rs @@ -3413,7 +3413,8 @@ mod _ssl { // Initialize connection if not already done if conn_guard.is_none() { // Check for pending context change (from SNI callback) - if let Some(new_ctx) = self.pending_context.write().take() { + let pending_context = self.pending_context.write().take(); + if let Some(new_ctx) = pending_context { *self.context.write() = new_ctx; } From e139075b4284820defa2ece88553b8285ce81bd8 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Sun, 14 Jun 2026 17:01:42 +0300 Subject: [PATCH 5/5] vm --- crates/vm/src/builtins/classmethod.rs | 8 +++++--- crates/vm/src/builtins/property.rs | 24 ++++++++++++++++-------- crates/vm/src/builtins/staticmethod.rs | 9 ++++++--- crates/vm/src/exceptions.rs | 11 +++++++---- crates/vm/src/object/core.rs | 3 ++- crates/vm/src/stdlib/_ctypes/base.rs | 6 ++++-- crates/vm/src/stdlib/_ctypes/pointer.rs | 3 ++- crates/vm/src/stdlib/_thread.rs | 3 ++- crates/vm/src/types/slot.rs | 6 ++++-- 9 files changed, 48 insertions(+), 25 deletions(-) diff --git a/crates/vm/src/builtins/classmethod.rs b/crates/vm/src/builtins/classmethod.rs index f2821c3f16f..a6c69eb50c7 100644 --- a/crates/vm/src/builtins/classmethod.rs +++ b/crates/vm/src/builtins/classmethod.rs @@ -170,9 +170,11 @@ impl PyClassMethod { #[pygetset] fn __isabstractmethod__(&self, vm: &VirtualMachine) -> PyObjectRef { - match vm.get_attribute_opt(self.callable.lock().clone(), "__isabstractmethod__") { - Ok(Some(is_abstract)) => is_abstract, - _ => vm.ctx.new_bool(false).into(), + let callable = self.callable.lock().clone(); + if let Ok(Some(is_abstract)) = vm.get_attribute_opt(callable, "__isabstractmethod__") { + is_abstract + } else { + vm.ctx.new_bool(false).into() } } diff --git a/crates/vm/src/builtins/property.rs b/crates/vm/src/builtins/property.rs index d01477dfcbf..cff5a8a60d0 100644 --- a/crates/vm/src/builtins/property.rs +++ b/crates/vm/src/builtins/property.rs @@ -54,9 +54,12 @@ impl GetDescriptor for PyProperty { ) -> PyResult { let (zelf, obj) = Self::_unwrap(&zelf_obj, obj, vm)?; if vm.is_none(&obj) { - Ok(zelf_obj) - } else if let Some(getter) = zelf.getter.read().clone() { - // Clone and release lock before calling Python code to prevent deadlock + return Ok(zelf_obj); + } + + // Clone and release lock before calling Python code to prevent deadlock + let value = zelf.getter.read().clone(); + if let Some(getter) = value { getter.call((obj,), vm) } else { let error_msg = zelf.format_property_error(&obj, "getter", vm)?; @@ -74,7 +77,8 @@ impl PyProperty { // Returns the name if available, None if not found, or propagates errors fn get_property_name(&self, vm: &VirtualMachine) -> PyResult> { // First check if name was set via __set_name__ - if let Some(name) = self.name.read().clone() { + let value = self.name.read().clone(); + if let Some(name) = value { return Ok(Some(name)); } @@ -110,7 +114,8 @@ impl PyProperty { match value { PySetterValue::Assign(value) => { // Clone and release lock before calling Python code to prevent deadlock - if let Some(setter) = zelf.setter.read().clone() { + let set = zelf.setter.read().clone(); + if let Some(setter) = set { setter.call((obj, value), vm).map(drop) } else { let error_msg = zelf.format_property_error(&obj, "setter", vm)?; @@ -119,7 +124,8 @@ impl PyProperty { } PySetterValue::Delete => { // Clone and release lock before calling Python code to prevent deadlock - if let Some(deleter) = zelf.deleter.read().clone() { + let del = zelf.deleter.read().clone(); + if let Some(deleter) = del { deleter.call((obj,), vm).map(drop) } else { let error_msg = zelf.format_property_error(&obj, "deleter", vm)?; @@ -224,7 +230,8 @@ impl PyProperty { Self::init(new_prop_ref.clone(), args, vm)?; // Copy the name if it exists - if let Some(name) = zelf.name.read().clone() { + let value = zelf.name.read().clone(); + if let Some(name) = value { *new_prop_ref.name.write() = Some(name); } @@ -296,7 +303,8 @@ impl PyProperty { #[pygetset(setter)] fn set___isabstractmethod__(&self, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { // Clone and release lock before calling Python code to prevent deadlock - if let Some(getter) = self.getter.read().clone() { + let maybe_getter = self.getter.read().clone(); + if let Some(getter) = maybe_getter { getter.set_attr("__isabstractmethod__", value, vm)?; } Ok(()) diff --git a/crates/vm/src/builtins/staticmethod.rs b/crates/vm/src/builtins/staticmethod.rs index 55b03ce7700..3a8d451b3dc 100644 --- a/crates/vm/src/builtins/staticmethod.rs +++ b/crates/vm/src/builtins/staticmethod.rs @@ -144,9 +144,12 @@ impl PyStaticMethod { #[pygetset] fn __isabstractmethod__(&self, vm: &VirtualMachine) -> PyObjectRef { - match vm.get_attribute_opt(self.callable.lock().clone(), "__isabstractmethod__") { - Ok(Some(is_abstract)) => is_abstract, - _ => vm.ctx.new_bool(false).into(), + let callable = self.callable.lock().clone(); + + if let Ok(Some(is_abstract)) = vm.get_attribute_opt(callable, "__isabstractmethod__") { + is_abstract + } else { + vm.ctx.new_bool(false).into() } } diff --git a/crates/vm/src/exceptions.rs b/crates/vm/src/exceptions.rs index 25f10d28baa..df22f4d822d 100644 --- a/crates/vm/src/exceptions.rs +++ b/crates/vm/src/exceptions.rs @@ -134,7 +134,9 @@ impl VirtualMachine { exc: &Py, ) -> Result<(), W::Error> { let vm = self; - if let Some(tb) = exc.traceback.read().clone() { + + let traceback = exc.traceback.read().clone(); + if let Some(tb) = traceback { writeln!(output, "Traceback (most recent call last):")?; for tb in tb.iter() { write_traceback_entry(output, &tb)?; @@ -162,9 +164,10 @@ impl VirtualMachine { ), }?; - match offer_suggestions(exc, vm) { - Some(suggestions) => writeln!(output, ". Did you mean: '{suggestions}'?"), - None => writeln!(output), + if let Some(suggestions) = offer_suggestions(exc, vm) { + writeln!(output, ". Did you mean: '{suggestions}'?") + } else { + writeln!(output) } } diff --git a/crates/vm/src/object/core.rs b/crates/vm/src/object/core.rs index b06a8f38e11..36bc0df0c74 100644 --- a/crates/vm/src/object/core.rs +++ b/crates/vm/src/object/core.rs @@ -1835,7 +1835,8 @@ impl PyObject { result.push(dict_ref.into()); } for slot in &ext.slots { - if let Some(val) = slot.write().take() { + let value = slot.write().take(); + if let Some(val) = value { result.push(val); } } diff --git a/crates/vm/src/stdlib/_ctypes/base.rs b/crates/vm/src/stdlib/_ctypes/base.rs index 765bacd19a0..a339e362786 100644 --- a/crates/vm/src/stdlib/_ctypes/base.rs +++ b/crates/vm/src/stdlib/_ctypes/base.rs @@ -709,7 +709,8 @@ impl PyCData { let key = self.unique_key(index); // If we have a base object, find root and store there - if let Some(base_obj) = self.base.read().clone() { + let base = self.base.read().clone(); + if let Some(base_obj) = base { // Find root by walking up the base chain let root_obj = Self::find_root_object(&base_obj); Self::store_in_object(&root_obj, &key, keep, vm)?; @@ -761,7 +762,8 @@ impl PyCData { /// Uses unique_key (hierarchical) so nested fields don't collide. pub fn keep_alive(&self, index: usize, obj: PyObjectRef) { let key = self.unique_key(index); - if let Some(base_obj) = self.base.read().clone() { + let base = self.base.read().clone(); + if let Some(base_obj) = base { let root = Self::find_root_object(&base_obj); if let Some(cdata) = root.downcast_ref::() { cdata.kept_refs.write().insert(key, obj); diff --git a/crates/vm/src/stdlib/_ctypes/pointer.rs b/crates/vm/src/stdlib/_ctypes/pointer.rs index be165ee9f8b..36d86282efd 100644 --- a/crates/vm/src/stdlib/_ctypes/pointer.rs +++ b/crates/vm/src/stdlib/_ctypes/pointer.rs @@ -373,7 +373,8 @@ impl PyCPointer { zelf.0.keep_ref(1, value.clone(), vm)?; // KeepRef: store GetKeepedObjects(dst) at index 0 - if let Some(kept) = cdata.objects.read().clone() { + let objects = cdata.objects.read().clone(); + if let Some(kept) = objects { zelf.0.keep_ref(0, kept, vm)?; } diff --git a/crates/vm/src/stdlib/_thread.rs b/crates/vm/src/stdlib/_thread.rs index 93d42676b4e..89014f27481 100644 --- a/crates/vm/src/stdlib/_thread.rs +++ b/crates/vm/src/stdlib/_thread.rs @@ -944,7 +944,8 @@ pub(crate) mod _thread { let thread_id = current_thread_id(); // Fast path: check if dict exists under lock - if let Some(dict) = self.inner.data.lock().get(&thread_id).cloned() { + let value = self.inner.data.lock().get(&thread_id).cloned(); + if let Some(dict) = value { return dict; } diff --git a/crates/vm/src/types/slot.rs b/crates/vm/src/types/slot.rs index c982811fc32..a56d1c493f9 100644 --- a/crates/vm/src/types/slot.rs +++ b/crates/vm/src/types/slot.rs @@ -1552,7 +1552,8 @@ impl PyType { let mro = self.mro.read(); // Look up in self's dict first - if let Some(attr) = self.attributes.read().get(name).cloned() { + let attr_name = self.attributes.read().get(name).cloned(); + if let Some(attr) = attr_name { if let Some(func) = try_extract(&attr, &mro) { return SlotLookupResult::NativeSlot(func); } @@ -1561,7 +1562,8 @@ impl PyType { // Look up in MRO (mro[0] is self, so skip it) for (i, cls) in mro[1..].iter().enumerate() { - if let Some(attr) = cls.attributes.read().get(name).cloned() { + let attr_name = cls.attributes.read().get(name).cloned(); + if let Some(attr) = attr_name { // Use the slice starting from this class in MRO if let Some(func) = try_extract(&attr, &mro[i + 1..]) { return SlotLookupResult::NativeSlot(func);