diff --git a/Lib/test/test_list.py b/Lib/test/test_list.py index 6dbe2d7a144..e320a2008a8 100644 --- a/Lib/test/test_list.py +++ b/Lib/test/test_list.py @@ -120,7 +120,6 @@ def test_list_resize_overflow(self): with self.assertRaises((MemoryError, OverflowError)): lst *= size - @unittest.skip("TODO: RUSTPYTHON; hangs") def test_repr_mutate(self): class Obj: @staticmethod diff --git a/crates/vm/src/builtins/list.rs b/crates/vm/src/builtins/list.rs index f74d4c4d62f..775a0d0c459 100644 --- a/crates/vm/src/builtins/list.rs +++ b/crates/vm/src/builtins/list.rs @@ -22,9 +22,10 @@ use crate::{ AsMapping, AsSequence, Comparable, Constructor, Initializer, IterNext, Iterable, PyComparisonOp, Representable, SelfIter, }, - utils::collection_repr, vm::VirtualMachine, }; +use rustpython_common::wtf8::Wtf8Buf; + use alloc::fmt; use core::ops::DerefMut; @@ -521,14 +522,40 @@ impl Representable for PyList { if zelf.__len__() == 0 { return Ok(vm.ctx.intern_str("[]").to_owned()); } + if let Some(_guard) = ReprGuard::enter(vm, zelf.as_object()) { // Clone elements before calling repr to release the read lock. // Element repr may mutate the list (e.g., list.clear()), which // needs a write lock and would deadlock if read lock is held. - let elements: Vec = zelf.borrow_vec().to_vec(); - Ok(vm - .ctx - .new_str(collection_repr(None, "[", "]", elements.iter(), vm)?)) + let mut writer = Wtf8Buf::new(); + writer.push_char('['); + + let mut elements = zelf.borrow_vec().to_vec(); + let mut size = zelf.__len__(); + let mut first = true; + let mut i = 0; + while i < size { + if elements.len() != size { + // `repr` mutated the list. refetch it. + elements = zelf.borrow_vec().to_vec(); + } + + let item = &elements[i]; + + if first { + first = false; + } else { + writer.push_str(", "); + } + + writer.push_wtf8(item.repr(vm)?.as_wtf8()); + + size = zelf.__len__(); // Refetch list size as `repr` may mutate the list. + i += 1; + } + + writer.push_char(']'); + Ok(vm.ctx.new_str(writer)) } else { Ok(vm.ctx.intern_str("[...]").to_owned()) }