From 287e0533b11ede095547bd7d613bc962b48c89af Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Sat, 7 Mar 2026 17:52:44 +0100 Subject: [PATCH 1/3] Fix (ish) hanging tests in `test_list.py` --- Lib/test/test_list.py | 3 +- crates/vm/src/builtins/list.rs | 77 +++++++++++++++++++++++++++++++--- 2 files changed, 72 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_list.py b/Lib/test/test_list.py index e320a2008a8..fd00b5e1479 100644 --- a/Lib/test/test_list.py +++ b/Lib/test/test_list.py @@ -228,7 +228,6 @@ class L(list): pass with self.assertRaises(TypeError): (3,) + L([1,2]) - @unittest.skip("TODO: RUSTPYTHON; hang") def test_equal_operator_modifying_operand(self): # test fix for seg fault reported in bpo-38588 part 2. class X: @@ -254,7 +253,7 @@ def __eq__(self, other): list4 = [1] self.assertFalse(list3 == list4) - @unittest.skip("TODO: RUSTPYTHON; hang") + @unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: TypeError not raised def test_lt_operator_modifying_operand(self): # See gh-120298 class evil: diff --git a/crates/vm/src/builtins/list.rs b/crates/vm/src/builtins/list.rs index c13dea57169..83cea88657e 100644 --- a/crates/vm/src/builtins/list.rs +++ b/crates/vm/src/builtins/list.rs @@ -13,7 +13,6 @@ use crate::{ class::PyClassImpl, convert::ToPyObject, function::{ArgSize, FuncArgs, OptionalArg, PyComparisonValue}, - iter::PyExactSizeIterator, protocol::{PyIterReturn, PyMappingMethods, PySequenceMethods}, recursion::ReprGuard, sequence::{MutObjectSequenceOp, OptionalRangeArgs, SequenceExt, SequenceMutExt}, @@ -547,11 +546,77 @@ impl Comparable for PyList { return Ok(res.into()); } let other = class_or_notimplemented!(Self, other); - let a = &*zelf.borrow_vec(); - let b = &*other.borrow_vec(); - a.iter() - .richcompare(b.iter(), op, vm) - .map(PyComparisonValue::Implemented) + + let mut zlen = zelf.__len__(); + let mut olen = other.__len__(); + if matches!(op, PyComparisonOp::Eq | PyComparisonOp::Ne) && (zlen != olen) { + // Shortcut: if the lengths differ, the lists differ + return Ok(PyComparisonValue::Implemented(matches!( + op, + PyComparisonOp::Ne + ))); + } + + let mut zelements = zelf.borrow_vec().to_vec(); + let mut oelements = other.borrow_vec().to_vec(); + + // Search for the first index where items are different. + let mut i = 0; + while i < zlen || i < olen { + if zelements.len() != zlen { + // Comparison mutated the list; refetch it. + zelements = zelf.borrow_vec().to_vec(); + } + + if oelements.len() != olen { + // Comparison mutated the list; refetch it. + oelements = other.borrow_vec().to_vec(); + } + + let zitem = &zelements[i]; + let oitem = &oelements[i]; + + if !vm.bool_eq(zitem, oitem)? { + break; + } + + // Refetch list sizes as calling the comparison may mutate the list. + zlen = zelf.__len__(); + olen = other.__len__(); + + i += 1; + } + + zlen = zelf.__len__(); + olen = other.__len__(); + if i >= zlen || i >= olen { + // No more items to compare -- compare sizes + let res = match op { + PyComparisonOp::Eq => zlen == olen, + PyComparisonOp::Ne => zlen != olen, + PyComparisonOp::Lt => zlen < olen, + PyComparisonOp::Le => zlen <= olen, + PyComparisonOp::Gt => zlen > olen, + PyComparisonOp::Ge => zlen >= olen, + }; + + return Ok(PyComparisonValue::Implemented(res)); + }; + + // We have an item that differs -- shortcuts for EQ/NE. + match op { + PyComparisonOp::Eq => return Ok(PyComparisonValue::Implemented(false)), + PyComparisonOp::Ne => return Ok(PyComparisonValue::Implemented(true)), + _ => {} + } + + // Compare the final item again using the proper operator. + zelements = zelf.borrow_vec().to_vec(); + oelements = other.borrow_vec().to_vec(); + let zitem = &zelements[i]; + let oitem = &oelements[i]; + let res = vm.identical_or_equal(zitem, oitem)?; + Ok(PyComparisonValue::Implemented(res)) } } From 1a79e328605416683d756e8a2e4841ef07129ab1 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Sat, 7 Mar 2026 18:43:21 +0100 Subject: [PATCH 2/3] cspell --- .cspell.dict/rust-more.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.cspell.dict/rust-more.txt b/.cspell.dict/rust-more.txt index af20aef568d..6c3a9cb9b91 100644 --- a/.cspell.dict/rust-more.txt +++ b/.cspell.dict/rust-more.txt @@ -51,6 +51,8 @@ muldiv nanos nonoverlapping objclass +oelements +olen peekable pemfile powc @@ -91,3 +93,5 @@ widestring winapi winresource winsock +zelements +zlen From 9ddfc67b13c94ee29e0c5d79e53e23a7946e804a Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Sat, 7 Mar 2026 20:16:04 +0100 Subject: [PATCH 3/3] Fix cond --- crates/vm/src/builtins/list.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/vm/src/builtins/list.rs b/crates/vm/src/builtins/list.rs index 83cea88657e..fda7ba3573b 100644 --- a/crates/vm/src/builtins/list.rs +++ b/crates/vm/src/builtins/list.rs @@ -562,7 +562,7 @@ impl Comparable for PyList { // Search for the first index where items are different. let mut i = 0; - while i < zlen || i < olen { + while i < zlen && i < olen { if zelements.len() != zlen { // Comparison mutated the list; refetch it. zelements = zelf.borrow_vec().to_vec();