Skip to content

Commit 5376c38

Browse files
authored
Merge pull request RustPython#3772 from falsetru/fix-index-check
Saturate list index on usize.
2 parents 2c8197f + 805c955 commit 5376c38

File tree

3 files changed

+24
-11
lines changed

3 files changed

+24
-11
lines changed

Lib/test/list_tests.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -363,8 +363,6 @@ def __eq__(self, other):
363363
# verify that original order and values are retained.
364364
self.assertIs(x, y)
365365

366-
# TODO: RUSTPYTHON
367-
@unittest.expectedFailure
368366
def test_index(self):
369367
super().test_index()
370368
a = self.type2test([-2, -1, 0, 0, 1, 2])

vm/src/builtins/list.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::{PositionIterInternal, PyGenericAlias, PyTupleRef, PyType, PyTypeRef};
1+
use super::{PositionIterInternal, PyGenericAlias, PyIntRef, PyTupleRef, PyType, PyTypeRef};
22
use crate::common::lock::{
33
PyMappedRwLockReadGuard, PyMutex, PyRwLock, PyRwLockReadGuard, PyRwLockWriteGuard,
44
};
@@ -10,7 +10,7 @@ use crate::{
1010
protocol::{PyIterReturn, PyMappingMethods, PySequence, PySequenceMethods},
1111
recursion::ReprGuard,
1212
sequence::{MutObjectSequenceOp, SequenceExt, SequenceMutExt},
13-
sliceable::{saturate_index, SequenceIndex, SliceableSequenceMutOp, SliceableSequenceOp},
13+
sliceable::{pyint_saturate_index, SequenceIndex, SliceableSequenceMutOp, SliceableSequenceOp},
1414
types::{
1515
AsMapping, AsSequence, Comparable, Constructor, Hashable, Initializer, IterNext,
1616
IterNextIterable, Iterable, PyComparisonOp, Unconstructible, Unhashable,
@@ -271,15 +271,17 @@ impl PyList {
271271
fn index(
272272
&self,
273273
needle: PyObjectRef,
274-
start: OptionalArg<isize>,
275-
stop: OptionalArg<isize>,
274+
start: OptionalArg<PyObjectRef>,
275+
stop: OptionalArg<PyObjectRef>,
276276
vm: &VirtualMachine,
277277
) -> PyResult<usize> {
278278
let len = self.len();
279-
let start = start.map(|i| saturate_index(i, len)).unwrap_or(0);
280-
let stop = stop
281-
.map(|i| saturate_index(i, len))
282-
.unwrap_or(isize::MAX as usize);
279+
let saturate = |obj: PyObjectRef, len| -> PyResult<_> {
280+
obj.try_into_value(vm)
281+
.map(|int: PyIntRef| pyint_saturate_index(int, len))
282+
};
283+
let start = start.map_or(Ok(0), |obj| saturate(obj, len))?;
284+
let stop = stop.map_or(Ok(len), |obj| saturate(obj, len))?;
283285
let index = self.mut_index_range(vm, &needle, start..stop)?;
284286
if let Some(index) = index.into() {
285287
Ok(index)

vm/src/sliceable.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// export through slicable module, not slice.
22
use crate::{
3-
builtins::{int::PyInt, slice::PySlice},
3+
builtins::{int::PyInt, slice::PySlice, PyIntRef},
44
AsObject, PyObject, PyResult, VirtualMachine,
55
};
66
use num_traits::{Signed, ToPrimitive};
@@ -320,6 +320,19 @@ pub fn saturate_index(p: isize, len: usize) -> usize {
320320
p as usize
321321
}
322322

323+
// Saturate p in range [0, len] inclusive
324+
pub fn pyint_saturate_index(p: PyIntRef, len: usize) -> usize {
325+
let bigint = p.as_bigint();
326+
if bigint.is_negative() {
327+
bigint
328+
.abs()
329+
.try_into()
330+
.map_or(0, |abs| len.saturating_sub(abs))
331+
} else {
332+
bigint.try_into().unwrap_or(len)
333+
}
334+
}
335+
323336
/// A saturated slice with values ranging in [isize::MIN, isize::MAX]. Used for
324337
/// slicable sequences that require indices in the aforementioned range.
325338
///

0 commit comments

Comments
 (0)