Skip to content

Commit 8908e50

Browse files
committed
py/sequence: Fix reverse slicing of lists.
1 parent e429daa commit 8908e50

2 files changed

Lines changed: 54 additions & 14 deletions

File tree

py/sequence.c

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,35 @@ bool mp_seq_get_fast_slice_indexes(mp_uint_t len, mp_obj_t slice, mp_bound_slice
5353
mp_int_t start, stop;
5454
mp_obj_slice_get(slice, &ostart, &ostop, &ostep);
5555

56+
if (ostep != mp_const_none && ostep != MP_OBJ_NEW_SMALL_INT(1)) {
57+
indexes->step = mp_obj_get_int(ostep);
58+
if (indexes->step == 0) {
59+
mp_raise_ValueError("slice step cannot be zero");
60+
}
61+
} else {
62+
indexes->step = 1;
63+
}
64+
5665
if (ostart == mp_const_none) {
57-
start = 0;
66+
if (indexes->step > 0) {
67+
start = 0;
68+
} else {
69+
start = len - 1;
70+
}
5871
} else {
5972
start = mp_obj_get_int(ostart);
6073
}
6174
if (ostop == mp_const_none) {
62-
stop = len;
75+
if (indexes->step > 0) {
76+
stop = len;
77+
} else {
78+
stop = 0;
79+
}
6380
} else {
6481
stop = mp_obj_get_int(ostop);
82+
if (stop >= 0 && indexes->step < 0) {
83+
stop += 1;
84+
}
6585
}
6686

6787
// Unlike subscription, out-of-bounds slice indexes are never error
@@ -70,29 +90,31 @@ bool mp_seq_get_fast_slice_indexes(mp_uint_t len, mp_obj_t slice, mp_bound_slice
7090
if (start < 0) {
7191
start = 0;
7292
}
73-
} else if ((mp_uint_t)start > len) {
93+
} else if (indexes->step > 0 && (mp_uint_t)start > len) {
7494
start = len;
95+
} else if (indexes->step < 0 && (mp_uint_t)start > len - 1) {
96+
start = len - 1;
7597
}
7698
if (stop < 0) {
7799
stop = len + stop;
100+
if (indexes->step < 0) {
101+
stop += 1;
102+
}
78103
} else if ((mp_uint_t)stop > len) {
79104
stop = len;
80105
}
81106

82107
// CPython returns empty sequence in such case, or point for assignment is at start
83-
if (start > stop) {
108+
if (indexes->step > 0 && start > stop) {
84109
stop = start;
110+
} else if (indexes->step < 0 && start < stop) {
111+
stop = start + 1;
85112
}
86113

87114
indexes->start = start;
88115
indexes->stop = stop;
89116

90-
if (ostep != mp_const_none && ostep != MP_OBJ_NEW_SMALL_INT(1)) {
91-
indexes->step = mp_obj_get_int(ostep);
92-
return false;
93-
}
94-
indexes->step = 1;
95-
return true;
117+
return indexes->step == 1;
96118
}
97119

98120
#endif
@@ -106,10 +128,9 @@ mp_obj_t mp_seq_extract_slice(mp_uint_t len, const mp_obj_t *seq, mp_bound_slice
106128
mp_obj_t res = mp_obj_new_list(0, NULL);
107129

108130
if (step < 0) {
109-
stop--;
110-
while (start <= stop) {
111-
mp_obj_list_append(res, seq[stop]);
112-
stop += step;
131+
while (start >= stop) {
132+
mp_obj_list_append(res, seq[start]);
133+
start += step;
113134
}
114135
} else {
115136
while (start < stop) {

tests/basics/list_slice_3arg.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,22 @@
77
print(x[::-1])
88
print(x[::2])
99
print(x[::-2])
10+
11+
x = list(range(5))
12+
print(x[:0:-1])
13+
print(x[:1:-1])
14+
print(x[:2:-1])
15+
print(x[0::-1])
16+
print(x[1::-1])
17+
print(x[2::-1])
18+
19+
x = list(range(5))
20+
print(x[0:0:-1])
21+
print(x[4:4:-1])
22+
print(x[5:5:-1])
23+
24+
x = list(range(10))
25+
print(x[-1:-1:-1])
26+
print(x[-1:-2:-1])
27+
print(x[-1:-11:-1])
28+
print(x[-10:-11:-1])

0 commit comments

Comments
 (0)