Skip to content

Commit 7505328

Browse files
committed
[GR-9955] List.__imul__ doesn't work as expected.
PullRequest: graalpython-open/60
2 parents adb6ad4 + 27a44dc commit 7505328

File tree

3 files changed

+312
-4
lines changed

3 files changed

+312
-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: 256 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,257 @@ 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, @SuppressWarnings("unused") boolean right) {
1219+
return list;
1220+
}
1221+
1222+
@Specialization(guards = "isEmptyStorage(list)")
1223+
PList doEmptyInt(PList list, @SuppressWarnings("unused") 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+
} catch (ArithmeticException e) {
1268+
throw raise(OverflowError, MulNode.CANNOT_FIT_MESSAGE);
1269+
}
1270+
}
1271+
1272+
@Specialization(guards = "isIntStorage(list)")
1273+
PList doIntLong(PList list, long right) {
1274+
try {
1275+
return doIntInt(list, PInt.intValueExact(right));
1276+
} catch (ArithmeticException e) {
1277+
throw raise(OverflowError, MulNode.CANNOT_FIT_MESSAGE);
1278+
}
1279+
}
1280+
1281+
@Specialization(guards = "isIntStorage(list)")
1282+
PList doIntPInt(PList list, PInt right) {
1283+
try {
1284+
return doIntInt(list, right.intValueExact());
1285+
} catch (ArithmeticException e) {
1286+
throw raise(OverflowError, MulNode.CANNOT_FIT_MESSAGE);
1287+
}
1288+
}
1289+
1290+
@Specialization(guards = "isLongStorage(list)")
1291+
PList doLongBoolean(PList list, boolean right) {
1292+
return doLongInt(list, right ? 1 : 0);
1293+
}
1294+
1295+
@Specialization(guards = "isLongStorage(list)")
1296+
PList doLongInt(PList list, int right) {
1297+
LongSequenceStorage store = (LongSequenceStorage) list.getSequenceStorage();
1298+
if (right < 1) {
1299+
store.clear();
1300+
return list;
1301+
}
1302+
try {
1303+
LongSequenceStorage copy = (LongSequenceStorage) store.copy();
1304+
for (int i = 1; i < right; i++) {
1305+
store.extendWithLongStorage(copy);
1306+
}
1307+
return list;
1308+
} catch (OutOfMemoryError e) {
1309+
throw raise(MemoryError);
1310+
} catch (ArithmeticException e) {
1311+
throw raise(OverflowError, MulNode.CANNOT_FIT_MESSAGE);
1312+
}
1313+
}
1314+
1315+
@Specialization(guards = "isLongStorage(list)")
1316+
PList doLongLong(PList list, long right) {
1317+
try {
1318+
return doLongInt(list, PInt.intValueExact(right));
1319+
} catch (ArithmeticException e) {
1320+
throw raise(OverflowError, MulNode.CANNOT_FIT_MESSAGE);
1321+
}
1322+
}
1323+
1324+
@Specialization(guards = "isLongStorage(list)")
1325+
PList doLongPInt(PList list, PInt right) {
1326+
try {
1327+
return doLongInt(list, right.intValueExact());
1328+
} catch (ArithmeticException e) {
1329+
throw raise(OverflowError, MulNode.CANNOT_FIT_MESSAGE);
1330+
}
1331+
}
1332+
1333+
@Specialization(guards = "isDoubleStorage(list)")
1334+
PList doDoubleBoolean(PList list, boolean right) {
1335+
return doDoubleInt(list, right ? 1 : 0);
1336+
}
1337+
1338+
@Specialization(guards = "isDoubleStorage(list)")
1339+
PList doDoubleInt(PList list, int right) {
1340+
DoubleSequenceStorage store = (DoubleSequenceStorage) list.getSequenceStorage();
1341+
if (right < 1) {
1342+
store.clear();
1343+
return list;
1344+
}
1345+
try {
1346+
DoubleSequenceStorage copy = (DoubleSequenceStorage) store.copy();
1347+
for (int i = 1; i < right; i++) {
1348+
store.extendWithDoubleStorage(copy);
1349+
}
1350+
return list;
1351+
} catch (OutOfMemoryError e) {
1352+
throw raise(MemoryError);
1353+
} catch (ArithmeticException e) {
1354+
throw raise(OverflowError, MulNode.CANNOT_FIT_MESSAGE);
1355+
}
1356+
}
1357+
1358+
@Specialization(guards = "isDoubleStorage(list)")
1359+
PList doDoubleLong(PList list, long right) {
1360+
try {
1361+
return doDoubleInt(list, PInt.intValueExact(right));
1362+
} catch (ArithmeticException e) {
1363+
throw raise(OverflowError, MulNode.CANNOT_FIT_MESSAGE);
1364+
}
1365+
}
1366+
1367+
@Specialization(guards = "isDoubleStorage(list)")
1368+
PList doDoublePInt(PList list, PInt right) {
1369+
try {
1370+
return doLongInt(list, right.intValueExact());
1371+
} catch (ArithmeticException e) {
1372+
throw raise(OverflowError, MulNode.CANNOT_FIT_MESSAGE);
1373+
}
1374+
}
1375+
1376+
@Specialization(guards = "isObjectStorage(list)")
1377+
PList doObjectBoolean(PList list, boolean right) {
1378+
return doDoubleInt(list, right ? 1 : 0);
1379+
}
1380+
1381+
@Specialization(guards = "isObjectStorage(list)")
1382+
PList doObjectInt(PList list, int right) {
1383+
ObjectSequenceStorage store = (ObjectSequenceStorage) list.getSequenceStorage();
1384+
if (right < 1) {
1385+
store.clear();
1386+
return list;
1387+
}
1388+
try {
1389+
ObjectSequenceStorage copy = (ObjectSequenceStorage) store.copy();
1390+
for (int i = 1; i < right; i++) {
1391+
store.extend(copy);
1392+
}
1393+
return list;
1394+
} catch (OutOfMemoryError e) {
1395+
throw raise(MemoryError);
1396+
} catch (ArithmeticException e) {
1397+
throw raise(OverflowError, MulNode.CANNOT_FIT_MESSAGE);
1398+
}
1399+
}
1400+
1401+
@Specialization(guards = "isObjectStorage(list)")
1402+
PList doObjectLong(PList list, long right) {
1403+
try {
1404+
return doObjectInt(list, PInt.intValueExact(right));
1405+
} catch (ArithmeticException e) {
1406+
throw raise(OverflowError, MulNode.CANNOT_FIT_MESSAGE);
1407+
}
1408+
}
1409+
1410+
@Specialization(guards = "isObjectStorage(list)")
1411+
PList doObjectPInt(PList list, PInt right) {
1412+
try {
1413+
return doObjectInt(list, right.intValueExact());
1414+
} catch (ArithmeticException e) {
1415+
throw raise(OverflowError, MulNode.CANNOT_FIT_MESSAGE);
1416+
}
1417+
}
1418+
1419+
@Specialization(guards = {"!isInt(right)"})
1420+
Object doGeneric(PList list, Object right,
1421+
@Cached("create(__INDEX__)") LookupAndCallUnaryNode dispatchIndex,
1422+
@Cached("createIMulNode()") IMulNode imulNode) {
1423+
Object index = dispatchIndex.executeObject(right);
1424+
if (index != PNone.NO_VALUE) {
1425+
int iIndex;
1426+
try {
1427+
iIndex = convertToInt(index);
1428+
} catch (ArithmeticException e) {
1429+
throw raise(OverflowError, "cannot fit '%p' into an index-sized integer", index);
1430+
}
1431+
1432+
return imulNode.execute(list, iIndex);
1433+
}
1434+
throw raise(TypeError, "can't multiply sequence by non-int of type '%p'", right);
1435+
}
1436+
1437+
private int convertToInt(Object value) throws ArithmeticException {
1438+
if (value instanceof Integer) {
1439+
return (Integer) value;
1440+
}
1441+
if (value instanceof Boolean) {
1442+
return (Boolean) value ? 0 : 1;
1443+
}
1444+
if (value instanceof Long) {
1445+
return PInt.intValueExact((Long) value);
1446+
}
1447+
if (value instanceof PInt) {
1448+
return ((PInt) value).intValueExact();
1449+
}
1450+
throw raise(TypeError, "can't multiply sequence by non-int of type '%p'", value);
1451+
}
1452+
1453+
protected IMulNode createIMulNode() {
1454+
return ListBuiltinsFactory.IMulNodeFactory.create(new PNode[0]);
1455+
}
1456+
1457+
protected boolean isInt(Object value) {
1458+
return value instanceof Boolean || value instanceof Integer || value instanceof Long || value instanceof PInt;
1459+
}
1460+
}
1461+
12081462
@Builtin(name = __RMUL__, fixedNumOfArguments = 2)
12091463
@GenerateNodeFactory
12101464
abstract static class RMulNode extends MulNode {

0 commit comments

Comments
 (0)