From 7112cebc7e14fe7539950e2f7aa42809732e0cd0 Mon Sep 17 00:00:00 2001 From: Jeongseop Lim Date: Fri, 7 Aug 2026 21:45:49 +0900 Subject: [PATCH] Format slice repr members with repr() instead of toString() The tp_repr slot delegated to the Java debug toString() of PSlice, which appends each member with String.valueOf. CPython's slice_repr formats all three with %R, so a non-integer member leaked its internal representation: slice(()) printed slice(None, tuple(EmptySequenceStorage[]), None). Signed-off-by: Jeongseop Lim --- .../src/tests/test_slice.py | 21 ++++++++++++++++++- .../builtins/objects/slice/SliceBuiltins.java | 17 +++++++++------ 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_slice.py b/graalpython/com.oracle.graal.python.test/src/tests/test_slice.py index 7ce131a8d4..af681f65b9 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/test_slice.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_slice.py @@ -1,4 +1,4 @@ -# Copyright (c) 2018, 2025, Oracle and/or its affiliates. +# Copyright (c) 2018, 2026, Oracle and/or its affiliates. # Copyright (c) 2013, Regents of the University of California # # All rights reserved. @@ -196,6 +196,25 @@ def __index__(self): assert "slice indices must be integers" in str(e) +def test_repr(): + assert repr(slice(1, 2, 3)) == "slice(1, 2, 3)" + assert repr(slice(1, 2)) == "slice(1, 2, None)" + assert repr(slice(None)) == "slice(None, None, None)" + assert repr(slice(2**70)) == "slice(None, 1180591620717411303424, None)" + # each member is formatted with repr(), not with a debug representation + assert repr(slice(())) == "slice(None, (), None)" + assert repr(slice((1,))) == "slice(None, (1,), None)" + assert repr(slice([])) == "slice(None, [], None)" + assert repr(slice("")) == "slice(None, '', None)" + assert repr(slice(True, 2)) == "slice(True, 2, None)" + + class Custom: + def __repr__(self): + return "" + + assert repr(slice(Custom())) == "slice(None, , None)" + + def test_slice_eq(): # Note: large numbers that do not get interned when boxed... assert slice(2, 10000, 10) == slice(2, 10000, 10) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/slice/SliceBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/slice/SliceBuiltins.java index 9858fb8777..5bdc203a3f 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/slice/SliceBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/slice/SliceBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. * Copyright (c) 2014, Regents of the University of California * * All rights reserved. @@ -27,7 +27,6 @@ import static com.oracle.graal.python.nodes.SpecialMethodNames.J___REDUCE__; import static com.oracle.graal.python.runtime.exception.PythonErrorType.ValueError; -import static com.oracle.graal.python.util.PythonUtils.toTruffleStringUncached; import java.util.List; @@ -46,11 +45,13 @@ import com.oracle.graal.python.builtins.objects.slice.SliceNodes.ComputeIndices; import com.oracle.graal.python.builtins.objects.slice.SliceNodes.SliceCastToToBigInt; import com.oracle.graal.python.builtins.objects.slice.SliceNodes.SliceExactCastToInt; +import com.oracle.graal.python.builtins.objects.str.StringUtils.SimpleTruffleStringFormatNode; import com.oracle.graal.python.builtins.objects.tuple.PTuple; import com.oracle.graal.python.builtins.objects.type.TpSlots; import com.oracle.graal.python.builtins.objects.type.slots.TpSlotHashFun.HashBuiltinNode; import com.oracle.graal.python.builtins.objects.type.slots.TpSlotRichCompare.RichCmpBuiltinNode; import com.oracle.graal.python.lib.PyObjectHashNode; +import com.oracle.graal.python.lib.PyObjectReprAsTruffleStringNode; import com.oracle.graal.python.lib.PyObjectRichCompare; import com.oracle.graal.python.lib.PyObjectRichCompareBool; import com.oracle.graal.python.lib.PySliceNew; @@ -65,7 +66,6 @@ import com.oracle.graal.python.nodes.object.GetClassNode; import com.oracle.graal.python.runtime.exception.PException; import com.oracle.graal.python.runtime.object.PFactory; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Cached.Exclusive; @@ -122,9 +122,14 @@ static Object threeArgs(@SuppressWarnings("unused") Object cls, Object start, Ob @GenerateNodeFactory abstract static class ReprNode extends PythonUnaryBuiltinNode { @Specialization - @TruffleBoundary - public static TruffleString repr(PSlice self) { - return toTruffleStringUncached(self.toString()); + static TruffleString repr(VirtualFrame frame, PSlice self, + @Bind Node inliningTarget, + @Cached PyObjectReprAsTruffleStringNode reprNode, + @Cached SimpleTruffleStringFormatNode simpleTruffleStringFormatNode) { + return simpleTruffleStringFormatNode.format("slice(%s, %s, %s)", + reprNode.execute(frame, inliningTarget, self.getStart()), + reprNode.execute(frame, inliningTarget, self.getStop()), + reprNode.execute(frame, inliningTarget, self.getStep())); } }