diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_operator.py b/graalpython/com.oracle.graal.python.test/src/tests/test_operator.py index ed526c81d7..138f2cebc3 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/test_operator.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_operator.py @@ -67,3 +67,25 @@ def test_getitem(self): self.assertRaises(TypeError, operator.getitem) self.assertRaises(TypeError, operator.getitem, a, None) self.assertEqual(operator.getitem(a, 2), 2) + + def test_setitem_delitem_convert_index_before_type_error(self): + class RaisingIndex: + def __index__(self): + raise ZeroDivisionError + + class Plain: + pass + + self.assertRaises(ZeroDivisionError, operator.setitem, (), RaisingIndex(), 0) + self.assertRaises(ZeroDivisionError, operator.setitem, frozenset(), RaisingIndex(), 0) + self.assertRaises(ZeroDivisionError, operator.setitem, Plain(), RaisingIndex(), 0) + self.assertRaises(IndexError, operator.setitem, '', 2**100, 0) + self.assertRaises(ZeroDivisionError, operator.delitem, '', RaisingIndex()) + self.assertRaises(ZeroDivisionError, operator.delitem, Plain(), RaisingIndex()) + self.assertRaises(IndexError, operator.delitem, (), 2**100) + self.assertRaises(TypeError, operator.setitem, (), 2**40, 0) + self.assertRaises(TypeError, operator.delitem, '', 2**40) + self.assertRaises(TypeError, operator.setitem, (), 0, 0) + self.assertRaises(TypeError, operator.delitem, (), 'a') + self.assertRaises(TypeError, operator.setitem, 1, RaisingIndex(), 0) + self.assertRaises(TypeError, operator.delitem, list[int], RaisingIndex()) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyObjectDelItem.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyObjectDelItem.java index 14e3d3cc33..2055eb00a8 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyObjectDelItem.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyObjectDelItem.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -40,9 +40,11 @@ */ package com.oracle.graal.python.lib; +import static com.oracle.graal.python.builtins.PythonBuiltinClassType.IndexError; import static com.oracle.graal.python.builtins.PythonBuiltinClassType.TypeError; import com.oracle.graal.python.builtins.objects.PNone; +import com.oracle.graal.python.builtins.objects.ints.PInt; import com.oracle.graal.python.builtins.objects.list.ListBuiltins; import com.oracle.graal.python.builtins.objects.list.PList; import com.oracle.graal.python.builtins.objects.type.TpSlots; @@ -124,6 +126,17 @@ static void doSequence(VirtualFrame frame, Node inliningTarget, Object object, T callSqItem.execute(frame, inliningTarget, slots.sq_ass_item(), object, index, PNone.NO_VALUE); } + @Specialization(guards = {"slots.mp_ass_subscript() == null", "slots.sq_ass_item() == null", "slots.has_as_sequence()"}) + @InliningCutoff + static void doSequenceNoAssItem(VirtualFrame frame, Node inliningTarget, Object object, @SuppressWarnings("unused") TpSlots slots, Object key, + @Cached PyIndexCheckNode indexCheckNode, + @Cached PyNumberIndexNode indexNode) { + if (indexCheckNode.execute(inliningTarget, key) && indexNode.execute(frame, inliningTarget, key) instanceof PInt pint && pint.bitLength() >= Long.SIZE) { + throw PRaiseNode.raiseStatic(inliningTarget, IndexError, ErrorMessages.CANNOT_FIT_P_INTO_INDEXSIZED_INT, key); + } + throw PRaiseNode.raiseStatic(inliningTarget, TypeError, ErrorMessages.OBJ_DOES_NOT_SUPPORT_ITEM_DELETION, object); + } + @Fallback @InliningCutoff static void error(Object object, @SuppressWarnings("unused") TpSlots slots, @SuppressWarnings("unused") Object key, diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyObjectSetItem.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyObjectSetItem.java index 1ee239c79b..671e864b95 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyObjectSetItem.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyObjectSetItem.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -40,8 +40,10 @@ */ package com.oracle.graal.python.lib; +import static com.oracle.graal.python.builtins.PythonBuiltinClassType.IndexError; import static com.oracle.graal.python.builtins.PythonBuiltinClassType.TypeError; +import com.oracle.graal.python.builtins.objects.ints.PInt; import com.oracle.graal.python.builtins.objects.list.ListBuiltins; import com.oracle.graal.python.builtins.objects.list.PList; import com.oracle.graal.python.builtins.objects.type.TpSlots; @@ -131,6 +133,17 @@ static void doSequence(VirtualFrame frame, Node inliningTarget, Object object, T callSqItem.execute(frame, inliningTarget, slots.sq_ass_item(), object, index, value); } + @Specialization(guards = {"slots.mp_ass_subscript() == null", "slots.sq_ass_item() == null", "slots.has_as_sequence()"}) + @InliningCutoff + static void doSequenceNoAssItem(VirtualFrame frame, Node inliningTarget, Object object, @SuppressWarnings("unused") TpSlots slots, Object key, @SuppressWarnings("unused") Object value, + @Cached PyIndexCheckNode indexCheckNode, + @Cached PyNumberIndexNode indexNode) { + if (indexCheckNode.execute(inliningTarget, key) && indexNode.execute(frame, inliningTarget, key) instanceof PInt pint && pint.bitLength() >= Long.SIZE) { + throw PRaiseNode.raiseStatic(inliningTarget, IndexError, ErrorMessages.CANNOT_FIT_P_INTO_INDEXSIZED_INT, key); + } + throw PRaiseNode.raiseStatic(inliningTarget, TypeError, ErrorMessages.OBJ_DOES_NOT_SUPPORT_ITEM_ASSIGMENT, object); + } + @Fallback @InliningCutoff static void error(Object object, @SuppressWarnings("unused") TpSlots slots, @SuppressWarnings("unused") Object key, @SuppressWarnings("unused") Object value,