From c9dd446722fc8cc01b9f17050b5dd719694c112c Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Fri, 27 Jun 2025 21:19:00 +0900 Subject: [PATCH] slot_repr for structseq --- vm/src/protocol/object.rs | 18 ++++++++----- vm/src/types/structseq.rs | 53 +++++++++++++++++++++++---------------- 2 files changed, 43 insertions(+), 28 deletions(-) diff --git a/vm/src/protocol/object.rs b/vm/src/protocol/object.rs index 15794f694e..892607a1bd 100644 --- a/vm/src/protocol/object.rs +++ b/vm/src/protocol/object.rs @@ -330,12 +330,18 @@ impl PyObject { pub fn repr(&self, vm: &VirtualMachine) -> PyResult { vm.with_recursion("while getting the repr of an object", || { - match self.class().slots.repr.load() { - Some(slot) => slot(self, vm), - None => vm - .call_special_method(self, identifier!(vm, __repr__), ())? - .try_into_value(vm), // TODO: remove magic method call once __repr__ is fully ported to slot - } + // TODO: RustPython does not implement type slots inheritance yet + self.class() + .mro_find_map(|cls| cls.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.", + self.class().name() + ))) + }, + |repr| repr(self, vm), + ) }) } diff --git a/vm/src/types/structseq.rs b/vm/src/types/structseq.rs index 625398caf0..73e5b37a40 100644 --- a/vm/src/types/structseq.rs +++ b/vm/src/types/structseq.rs @@ -1,6 +1,6 @@ use crate::{ - AsObject, Py, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, - builtins::{PyBaseExceptionRef, PyTuple, PyTupleRef, PyType}, + AsObject, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, + builtins::{PyBaseExceptionRef, PyStrRef, PyTuple, PyTupleRef, PyType}, class::{PyClassImpl, StaticType}, vm::Context, }; @@ -47,31 +47,40 @@ pub trait PyStructSequence: StaticType + PyClassImpl + Sized + 'static { Ok(seq) } - #[pymethod] - fn __repr__(zelf: PyRef, vm: &VirtualMachine) -> PyResult { + #[pyslot] + fn slot_repr(zelf: &PyObject, vm: &VirtualMachine) -> PyResult { + let zelf = zelf + .downcast_ref::() + .ok_or_else(|| vm.new_type_error("unexpected payload for __repr__"))?; + let format_field = |(value, name): (&PyObjectRef, _)| { let s = value.repr(vm)?; Ok(format!("{name}={s}")) }; - let (body, suffix) = if let Some(_guard) = - rustpython_vm::recursion::ReprGuard::enter(vm, zelf.as_object()) - { - if Self::REQUIRED_FIELD_NAMES.len() == 1 { - let value = zelf.first().unwrap(); - let formatted = format_field((value, Self::REQUIRED_FIELD_NAMES[0]))?; - (formatted, ",") + let (body, suffix) = + if let Some(_guard) = rustpython_vm::recursion::ReprGuard::enter(vm, zelf.as_ref()) { + if Self::REQUIRED_FIELD_NAMES.len() == 1 { + let value = zelf.first().unwrap(); + let formatted = format_field((value, Self::REQUIRED_FIELD_NAMES[0]))?; + (formatted, ",") + } else { + let fields: PyResult> = zelf + .iter() + .zip(Self::REQUIRED_FIELD_NAMES.iter().copied()) + .map(format_field) + .collect(); + (fields?.join(", "), "") + } } else { - let fields: PyResult> = zelf - .iter() - .zip(Self::REQUIRED_FIELD_NAMES.iter().copied()) - .map(format_field) - .collect(); - (fields?.join(", "), "") - } - } else { - (String::new(), "...") - }; - Ok(format!("{}({}{})", Self::TP_NAME, body, suffix)) + (String::new(), "...") + }; + let repr_str = format!("{}({}{})", Self::TP_NAME, body, suffix); + Ok(vm.ctx.new_str(repr_str)) + } + + #[pymethod] + fn __repr__(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult { + Self::slot_repr(&zelf, vm) } #[pymethod]