Skip to content

Commit a406115

Browse files
committed
[GR-9955] List.__imul__ doesn't work as expected.
1 parent adb6ad4 commit a406115

File tree

3 files changed

+304
-4
lines changed

3 files changed

+304
-4
lines changed

graalpython/com.oracle.graal.python.test/src/tests/list_tests.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -554,7 +554,7 @@ def test_iadd(self):
554554
self.assertEqual(u, self.type2test("spameggs"))
555555

556556
self.assertRaises(TypeError, u.__iadd__, None)
557-
'''
557+
558558
def test_imul(self):
559559
u = self.type2test([0, 1])
560560
u *= 3
@@ -565,7 +565,7 @@ def test_imul(self):
565565
oldid = id(s)
566566
s *= 10
567567
self.assertEqual(id(s), oldid)
568-
'''
568+
569569
def test_extendedslicing(self):
570570
# subscript
571571
a = self.type2test([0,1,2,3,4])

graalpython/com.oracle.graal.python.test/src/tests/test_list.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,3 +479,57 @@ def __iadd__(self, value):
479479
a = [1,2]
480480
a += a
481481
self.assertEqual([1,2,1,2], a)
482+
483+
def test_imul_len(self):
484+
a = [1]
485+
a *= 0
486+
self.assertEqual(0, len(a))
487+
488+
a = [1]
489+
a *= 1
490+
self.assertEqual(1, len(a))
491+
492+
a = [1]
493+
a *= -11
494+
self.assertEqual(0, len(a))
495+
496+
a = [1]
497+
a *= 10
498+
self.assertEqual(10, len(a))
499+
500+
a = [1,2]
501+
a *= 4
502+
self.assertEqual(8, len(a))
503+
504+
def test_imul_01(self):
505+
class My():
506+
def __init__(self, value):
507+
self.value = value
508+
def __index__(self):
509+
return self.value + 1;
510+
l = [1]
511+
ob = My(10)
512+
l *= ob
513+
self.assertEqual(11, len(l))
514+
515+
def test_imul_02(self):
516+
class My():
517+
def __init__(self, value):
518+
self.value = value
519+
def __index__(self):
520+
return LONG_NUMBER*LONG_NUMBER
521+
l = [1]
522+
ob = My(10)
523+
self.assertRaises(OverflowError, l.__imul__, ob)
524+
525+
def test_imul_03(self):
526+
class My():
527+
def __init__(self, value):
528+
self.value = value
529+
def __index__(self):
530+
return 'Ahoj'
531+
l = [1]
532+
ob = My(10)
533+
self.assertRaises(TypeError, l.__imul__, ob)
534+
535+

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/list/ListBuiltins.java

Lines changed: 248 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import static com.oracle.graal.python.nodes.SpecialMethodNames.__LEN__;
3838
import static com.oracle.graal.python.nodes.SpecialMethodNames.__LT__;
3939
import static com.oracle.graal.python.nodes.SpecialMethodNames.__MUL__;
40+
import static com.oracle.graal.python.nodes.SpecialMethodNames.__IMUL__;
4041
import static com.oracle.graal.python.nodes.SpecialMethodNames.__NE__;
4142
import static com.oracle.graal.python.nodes.SpecialMethodNames.__REPR__;
4243
import static com.oracle.graal.python.nodes.SpecialMethodNames.__RMUL__;
@@ -1162,6 +1163,8 @@ protected boolean isNotSameStorage(PList left, PList right) {
11621163
@Builtin(name = __MUL__, fixedNumOfArguments = 2)
11631164
@GenerateNodeFactory
11641165
abstract static class MulNode extends PythonBuiltinNode {
1166+
public static String CANNOT_FIT_MESSAGE = "cannot fit 'int' into an index-sized integer";
1167+
11651168
@Specialization
11661169
PList doPListInt(PList left, boolean right,
11671170
@Cached("createClassProfile()") ValueProfile profile) {
@@ -1184,7 +1187,7 @@ PList doPListBigInt(PList left, long right,
11841187
try {
11851188
return doPListInt(left, PInt.intValueExact(right), profile);
11861189
} catch (ArithmeticException e) {
1187-
throw raise(OverflowError, "cannot fit 'int' into an index-sized integer");
1190+
throw raise(OverflowError, CANNOT_FIT_MESSAGE);
11881191
}
11891192
}
11901193

@@ -1194,7 +1197,7 @@ PList doPListBigInt(PList left, PInt right,
11941197
try {
11951198
return doPListInt(left, right.intValueExact(), profile);
11961199
} catch (ArithmeticException | OutOfMemoryError e) {
1197-
throw raise(OverflowError, "cannot fit 'int' into an index-sized integer");
1200+
throw raise(OverflowError, CANNOT_FIT_MESSAGE);
11981201
}
11991202
}
12001203

@@ -1205,6 +1208,249 @@ Object doGeneric(Object left, Object right) {
12051208
}
12061209
}
12071210

1211+
@Builtin(name = __IMUL__, fixedNumOfArguments = 2)
1212+
@GenerateNodeFactory
1213+
abstract static class IMulNode extends PythonBuiltinNode {
1214+
1215+
public abstract PList execute(PList list, Object value);
1216+
1217+
@Specialization(guards = "isEmptyStorage(list)")
1218+
PList doEmptyBoolean(PList list, boolean right) {
1219+
return list;
1220+
}
1221+
1222+
@Specialization(guards = "isEmptyStorage(list)")
1223+
PList doEmptyInt(PList list, int right) {
1224+
return list;
1225+
}
1226+
1227+
@Specialization(guards = "isEmptyStorage(list)")
1228+
PList doEmptyLong(PList list, long right) {
1229+
try {
1230+
PInt.intValueExact(right);
1231+
return list;
1232+
} catch (ArithmeticException e) {
1233+
throw raise(OverflowError, MulNode.CANNOT_FIT_MESSAGE);
1234+
}
1235+
}
1236+
1237+
@Specialization(guards = "isEmptyStorage(list)")
1238+
PList doEmptyPInt(PList list, PInt right) {
1239+
try {
1240+
right.intValueExact();
1241+
return list;
1242+
} catch (ArithmeticException e) {
1243+
throw raise(OverflowError, MulNode.CANNOT_FIT_MESSAGE);
1244+
}
1245+
}
1246+
1247+
@Specialization(guards = "isIntStorage(list)")
1248+
PList doIntBoolean(PList list, boolean right) {
1249+
return doIntInt(list, right ? 1 : 0);
1250+
}
1251+
1252+
@Specialization(guards = "isIntStorage(list)")
1253+
PList doIntInt(PList list, int right) {
1254+
IntSequenceStorage store = (IntSequenceStorage) list.getSequenceStorage();
1255+
if (right < 1) {
1256+
store.clear();
1257+
return list;
1258+
}
1259+
try {
1260+
IntSequenceStorage copy = (IntSequenceStorage) store.copy();
1261+
for (int i = 1; i < right; i++) {
1262+
store.extendWithIntStorage(copy);
1263+
}
1264+
return list;
1265+
} catch (OutOfMemoryError e) {
1266+
throw raise(MemoryError);
1267+
}
1268+
}
1269+
1270+
@Specialization(guards = "isIntStorage(list)")
1271+
PList doIntLong(PList list, long right) {
1272+
try {
1273+
return doIntInt(list, PInt.intValueExact(right));
1274+
} catch (ArithmeticException e) {
1275+
throw raise(OverflowError, MulNode.CANNOT_FIT_MESSAGE);
1276+
}
1277+
}
1278+
1279+
@Specialization(guards = "isIntStorage(list)")
1280+
PList doIntPInt(PList list, PInt right) {
1281+
try {
1282+
return doIntInt(list, right.intValueExact());
1283+
} catch (ArithmeticException e) {
1284+
throw raise(OverflowError, MulNode.CANNOT_FIT_MESSAGE);
1285+
}
1286+
}
1287+
1288+
@Specialization(guards = "isLongStorage(list)")
1289+
PList doLongBoolean(PList list, boolean right) {
1290+
return doLongInt(list, right ? 1 : 0);
1291+
}
1292+
1293+
@Specialization(guards = "isLongStorage(list)")
1294+
PList doLongInt(PList list, int right) {
1295+
LongSequenceStorage store = (LongSequenceStorage) list.getSequenceStorage();
1296+
if (right < 1) {
1297+
store.clear();
1298+
return list;
1299+
}
1300+
try {
1301+
LongSequenceStorage copy = (LongSequenceStorage) store.copy();
1302+
for (int i = 1; i < right; i++) {
1303+
store.extendWithLongStorage(copy);
1304+
}
1305+
return list;
1306+
} catch (OutOfMemoryError e) {
1307+
throw raise(MemoryError);
1308+
}
1309+
}
1310+
1311+
@Specialization(guards = "isLongStorage(list)")
1312+
PList doLongLong(PList list, long right) {
1313+
try {
1314+
return doLongInt(list, PInt.intValueExact(right));
1315+
} catch (ArithmeticException e) {
1316+
throw raise(OverflowError, MulNode.CANNOT_FIT_MESSAGE);
1317+
}
1318+
}
1319+
1320+
@Specialization(guards = "isLongStorage(list)")
1321+
PList doLongPInt(PList list, PInt right) {
1322+
try {
1323+
return doLongInt(list, right.intValueExact());
1324+
} catch (ArithmeticException e) {
1325+
throw raise(OverflowError, MulNode.CANNOT_FIT_MESSAGE);
1326+
}
1327+
}
1328+
1329+
@Specialization(guards = "isDoubleStorage(list)")
1330+
PList doDoubleBoolean(PList list, boolean right) {
1331+
return doDoubleInt(list, right ? 1 : 0);
1332+
}
1333+
1334+
@Specialization(guards = "isDoubleStorage(list)")
1335+
PList doDoubleInt(PList list, int right) {
1336+
DoubleSequenceStorage store = (DoubleSequenceStorage) list.getSequenceStorage();
1337+
if (right < 1) {
1338+
store.clear();
1339+
return list;
1340+
}
1341+
try {
1342+
DoubleSequenceStorage copy = (DoubleSequenceStorage) store.copy();
1343+
for (int i = 1; i < right; i++) {
1344+
store.extendWithDoubleStorage(copy);
1345+
}
1346+
return list;
1347+
} catch (OutOfMemoryError e) {
1348+
throw raise(MemoryError);
1349+
}
1350+
}
1351+
1352+
@Specialization(guards = "isDoubleStorage(list)")
1353+
PList doDoubleLong(PList list, long right) {
1354+
try {
1355+
return doDoubleInt(list, PInt.intValueExact(right));
1356+
} catch (ArithmeticException e) {
1357+
throw raise(OverflowError, MulNode.CANNOT_FIT_MESSAGE);
1358+
}
1359+
}
1360+
1361+
@Specialization(guards = "isDoubleStorage(list)")
1362+
PList doDoublePInt(PList list, PInt right) {
1363+
try {
1364+
return doLongInt(list, right.intValueExact());
1365+
} catch (ArithmeticException e) {
1366+
throw raise(OverflowError, MulNode.CANNOT_FIT_MESSAGE);
1367+
}
1368+
}
1369+
1370+
@Specialization(guards = "isObjectStorage(list)")
1371+
PList doObjectBoolean(PList list, boolean right) {
1372+
return doDoubleInt(list, right ? 1 : 0);
1373+
}
1374+
1375+
@Specialization(guards = "isObjectStorage(list)")
1376+
PList doObjectInt(PList list, int right) {
1377+
ObjectSequenceStorage store = (ObjectSequenceStorage) list.getSequenceStorage();
1378+
if (right < 1) {
1379+
store.clear();
1380+
return list;
1381+
}
1382+
try {
1383+
ObjectSequenceStorage copy = (ObjectSequenceStorage) store.copy();
1384+
for (int i = 1; i < right; i++) {
1385+
store.extend(copy);
1386+
}
1387+
return list;
1388+
} catch (OutOfMemoryError e) {
1389+
throw raise(MemoryError);
1390+
}
1391+
}
1392+
1393+
@Specialization(guards = "isObjectStorage(list)")
1394+
PList doObjectLong(PList list, long right) {
1395+
try {
1396+
return doObjectInt(list, PInt.intValueExact(right));
1397+
} catch (ArithmeticException e) {
1398+
throw raise(OverflowError, MulNode.CANNOT_FIT_MESSAGE);
1399+
}
1400+
}
1401+
1402+
@Specialization(guards = "isObjectStorage(list)")
1403+
PList doObjectPInt(PList list, PInt right) {
1404+
try {
1405+
return doObjectInt(list, right.intValueExact());
1406+
} catch (ArithmeticException e) {
1407+
throw raise(OverflowError, MulNode.CANNOT_FIT_MESSAGE);
1408+
}
1409+
}
1410+
1411+
@Specialization(guards = {"!isInt(right)"})
1412+
Object doGeneric(PList list, Object right,
1413+
@Cached("create(__INDEX__)") LookupAndCallUnaryNode dispatchIndex,
1414+
@Cached("createIMulNode()") IMulNode imulNode) {
1415+
Object index = dispatchIndex.executeObject(right);
1416+
if (index != PNone.NO_VALUE) {
1417+
int iIndex;
1418+
try {
1419+
iIndex = convertToInt(index);
1420+
} catch (ArithmeticException e) {
1421+
throw raise(OverflowError, "cannot fit '%p' into an index-sized integer", index);
1422+
}
1423+
1424+
return imulNode.execute(list, iIndex);
1425+
}
1426+
throw raise(TypeError, "can't multiply sequence by non-int of type '%p'", right);
1427+
}
1428+
1429+
private int convertToInt(Object value) throws ArithmeticException {
1430+
if (value instanceof Integer) {
1431+
return (Integer) value;
1432+
}
1433+
if (value instanceof Boolean) {
1434+
return (Boolean) value ? 0 : 1;
1435+
}
1436+
if (value instanceof Long) {
1437+
return PInt.intValueExact((Long) value);
1438+
}
1439+
if (value instanceof PInt) {
1440+
return ((PInt) value).intValueExact();
1441+
}
1442+
throw raise(TypeError, "can't multiply sequence by non-int of type '%p'", value);
1443+
}
1444+
1445+
protected IMulNode createIMulNode() {
1446+
return ListBuiltinsFactory.IMulNodeFactory.create(new PNode[0]);
1447+
}
1448+
1449+
protected boolean isInt(Object value) {
1450+
return value instanceof Boolean || value instanceof Integer || value instanceof Long || value instanceof PInt;
1451+
}
1452+
}
1453+
12081454
@Builtin(name = __RMUL__, fixedNumOfArguments = 2)
12091455
@GenerateNodeFactory
12101456
abstract static class RMulNode extends MulNode {

0 commit comments

Comments
 (0)