Skip to content

Commit 6ec8212

Browse files
committed
[GR-23238] make test_basic, test_error_message and test_intconversion in test_int pass
PullRequest: graalpython/1062
2 parents a13dfc6 + 15ff65d commit 6ec8212

File tree

3 files changed

+71
-26
lines changed

3 files changed

+71
-26
lines changed

graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_int.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
*graalpython.lib-python.3.test.test_int.IntTestCases.test_basic
2+
*graalpython.lib-python.3.test.test_int.IntTestCases.test_error_message
13
*graalpython.lib-python.3.test.test_int.IntTestCases.test_int_base_bad_types
24
*graalpython.lib-python.3.test.test_int.IntTestCases.test_int_subclass_with_index
35
*graalpython.lib-python.3.test.test_int.IntTestCases.test_int_subclass_with_int
6+
*graalpython.lib-python.3.test.test_int.IntTestCases.test_intconversion
47
*graalpython.lib-python.3.test.test_int.IntTestCases.test_issue31619
58
*graalpython.lib-python.3.test.test_int.IntTestCases.test_no_args
69
*graalpython.lib-python.3.test.test_int.IntTestCases.test_small_ints

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinConstructors.java

Lines changed: 66 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
import static com.oracle.graal.python.nodes.SpecialMethodNames.__COMPLEX__;
7272
import static com.oracle.graal.python.nodes.SpecialMethodNames.__INDEX__;
7373
import static com.oracle.graal.python.nodes.SpecialMethodNames.__INT__;
74+
import static com.oracle.graal.python.nodes.SpecialMethodNames.__REPR__;
7475
import static com.oracle.graal.python.nodes.SpecialMethodNames.__SETITEM__;
7576
import static com.oracle.graal.python.nodes.SpecialMethodNames.__TRUNC__;
7677
import static com.oracle.graal.python.runtime.exception.PythonErrorType.NotImplementedError;
@@ -1153,6 +1154,7 @@ public abstract static class IntNode extends PythonBuiltinNode {
11531154
@Child private LookupAndCallUnaryNode callIntNode;
11541155
@Child private LookupAndCallUnaryNode callIndexNode;
11551156
@Child private LookupAndCallUnaryNode callTruncNode;
1157+
@Child private LookupAndCallUnaryNode callReprNode;
11561158

11571159
public abstract Object executeWith(VirtualFrame frame, Object cls, Object arg, Object base);
11581160

@@ -1171,11 +1173,24 @@ private static Object stringToIntInternal(String num, int base) {
11711173
}
11721174
}
11731175

1174-
private Object stringToInt(LazyPythonClass cls, String number, int base) {
1176+
private Object stringToInt(VirtualFrame frame, LazyPythonClass cls, String number, int base, Object origObj) {
11751177
Object value = stringToIntInternal(number, base);
11761178
if (value == null) {
11771179
invalidValueProfile.enter();
1178-
throw raise(ValueError, ErrorMessages.INVALID_LITERAL_FOR_INT_WITH_BASE, base, number);
1180+
if (callReprNode == null) {
1181+
CompilerDirectives.transferToInterpreterAndInvalidate();
1182+
callReprNode = insert(LookupAndCallUnaryNode.create(__REPR__));
1183+
}
1184+
Object str = callReprNode.executeObject(frame, origObj);
1185+
if (PGuards.isString(str)) {
1186+
throw raise(ValueError, ErrorMessages.INVALID_LITERAL_FOR_INT_WITH_BASE, base, str);
1187+
} else {
1188+
// During the formatting of "ValueError: invalid literal ..." exception,
1189+
// CPython attempts to raise "TypeError: __repr__ returned non-string",
1190+
// which gets later overwitten with the original "ValueError",
1191+
// but without any message (since the message formatting failed)
1192+
throw raise(ValueError);
1193+
}
11791194
}
11801195
return createInt(cls, value);
11811196
}
@@ -1204,7 +1219,7 @@ private Object createInt(LazyPythonClass cls, Object value) {
12041219
}
12051220

12061221
private void checkBase(int base) {
1207-
if (invalidBase.profile((base < 2 || base > 32) && base != 0)) {
1222+
if (invalidBase.profile((base < 2 || base > 36) && base != 0)) {
12081223
throw raise(ValueError, ErrorMessages.BASE_OUT_OF_RANGE_FOR_INT);
12091224
}
12101225
}
@@ -1403,8 +1418,8 @@ long createLongBase10(@SuppressWarnings("unused") LazyPythonClass cls, String ar
14031418
}
14041419

14051420
@Specialization(guards = "isNoValue(base)")
1406-
Object createInt(LazyPythonClass cls, String arg, @SuppressWarnings("unused") PNone base) {
1407-
return stringToInt(cls, arg, 10);
1421+
Object createInt(VirtualFrame frame, LazyPythonClass cls, String arg, @SuppressWarnings("unused") PNone base) {
1422+
return stringToInt(frame, cls, arg, 10, arg);
14081423
}
14091424

14101425
@Specialization(guards = "isPrimitiveInt(cls)", rewriteOn = NumberFormatException.class)
@@ -1420,17 +1435,17 @@ long parseLong(@SuppressWarnings("unused") LazyPythonClass cls, String arg, int
14201435
}
14211436

14221437
@Specialization
1423-
Object parsePIntError(LazyPythonClass cls, String number, int base) {
1438+
Object parsePIntError(VirtualFrame frame, LazyPythonClass cls, String number, int base) {
14241439
checkBase(base);
1425-
return stringToInt(cls, number, base);
1440+
return stringToInt(frame, cls, number, base, number);
14261441
}
14271442

14281443
@Specialization(guards = "!isNoValue(base)", limit = "getCallSiteInlineCacheMaxDepth()")
14291444
Object createIntError(VirtualFrame frame, LazyPythonClass cls, String number, Object base,
14301445
@CachedLibrary("base") PythonObjectLibrary lib) {
14311446
int intBase = lib.asSizeWithState(base, PArguments.getThreadState(frame));
14321447
checkBase(intBase);
1433-
return stringToInt(cls, number, intBase);
1448+
return stringToInt(frame, cls, number, intBase, number);
14341449
}
14351450

14361451
// PIBytesLike
@@ -1448,7 +1463,7 @@ long parseLong(VirtualFrame frame, LazyPythonClass cls, PIBytesLike arg, int bas
14481463
@Specialization
14491464
Object parseBytesError(VirtualFrame frame, LazyPythonClass cls, PIBytesLike arg, int base) {
14501465
checkBase(base);
1451-
return stringToInt(cls, toString(frame, arg), base);
1466+
return stringToInt(frame, cls, toString(frame, arg), base, arg);
14521467
}
14531468

14541469
@Specialization(guards = "isNoValue(base)")
@@ -1469,8 +1484,8 @@ long createLong(@SuppressWarnings("unused") LazyPythonClass cls, PString arg, @S
14691484
}
14701485

14711486
@Specialization(guards = "isNoValue(base)")
1472-
Object parsePInt(LazyPythonClass cls, PString arg, @SuppressWarnings("unused") PNone base) {
1473-
return stringToInt(cls, arg.getValue(), 10);
1487+
Object parsePInt(VirtualFrame frame, LazyPythonClass cls, PString arg, @SuppressWarnings("unused") PNone base) {
1488+
return stringToInt(frame, cls, arg.getValue(), 10, arg);
14741489
}
14751490

14761491
@Specialization(guards = "isPrimitiveInt(cls)", rewriteOn = NumberFormatException.class)
@@ -1486,9 +1501,9 @@ long parseLong(@SuppressWarnings("unused") LazyPythonClass cls, PString arg, int
14861501
}
14871502

14881503
@Specialization
1489-
Object parsePInt(LazyPythonClass cls, PString arg, int base) {
1504+
Object parsePInt(VirtualFrame frame, LazyPythonClass cls, PString arg, int base) {
14901505
checkBase(base);
1491-
return stringToInt(cls, arg.getValue(), base);
1506+
return stringToInt(frame, cls, arg.getValue(), base, arg);
14921507
}
14931508

14941509
// other
@@ -1512,28 +1527,42 @@ Object createInt(LazyPythonClass cls, @SuppressWarnings("unused") PNone none, @S
15121527
}
15131528

15141529
@SuppressWarnings("unused")
1515-
@Specialization(guards = {"!isString(arg)", "!isNoValue(base)"})
1530+
@Specialization(guards = {"!isString(arg)", "!isBytes(arg)", "!isNoValue(base)"})
15161531
Object fail(LazyPythonClass cls, Object arg, Object base) {
1517-
throw raise(TypeError, ErrorMessages.INT_CANT_CONVERT_STRING_EITH_EXPL_BASE);
1532+
throw raise(TypeError, ErrorMessages.INT_CANT_CONVERT_STRING_WITH_EXPL_BASE);
15181533
}
15191534

15201535
@Specialization(guards = {"isNoValue(base)", "!isNoValue(obj)", "!isHandledType(obj)"})
15211536
Object createIntGeneric(VirtualFrame frame, LazyPythonClass cls, Object obj, @SuppressWarnings("unused") PNone base) {
1537+
// This method (together with callInt and callIndex) reflects the logic of PyNumber_Long
1538+
// in CPython. We don't use PythonObjectLibrary here since the original CPython function
1539+
// does not use any of the conversion functions (such as _PyLong_AsInt or
1540+
// PyNumber_Index) either, but it reimplements the logic in a slightly different way
1541+
// (e.g. trying __int__ before __index__ whereas _PyLong_AsInt does it the other way)
1542+
// and also with specific exception messages which are expected by Python unittests.
1543+
// This unfortunately means that this method relies on the internal logic of NO_VALUE
1544+
// return values representing missing magic methods which should be ideally hidden
1545+
// by PythonObjectLibrary.
15221546
Object result = callInt(frame, obj);
15231547
if (result == PNone.NO_VALUE) {
15241548
result = callIndex(frame, obj);
15251549
if (result == PNone.NO_VALUE) {
1526-
result = callTrunc(frame, obj);
1527-
if (result == PNone.NO_VALUE) {
1550+
Object truncResult = callTrunc(frame, obj);
1551+
if (truncResult == PNone.NO_VALUE) {
15281552
throw raise(TypeError, ErrorMessages.ARG_MUST_BE_STRING_OR_BYTELIKE_OR_NUMBER, "int()", obj);
1529-
} else if (!isIntegerType(result)) {
1530-
throw raise(TypeError, ErrorMessages.RETURNED_NON_INT, "__trunc__", result);
15311553
}
1532-
} else if (!isIntegerType(result)) {
1533-
throw raise(TypeError, ErrorMessages.RETURNED_NON_INT, "__index__", result);
1554+
if (isIntegerType(truncResult)) {
1555+
result = truncResult;
1556+
} else {
1557+
result = callIndex(frame, truncResult);
1558+
if (result == PNone.NO_VALUE) {
1559+
result = callInt(frame, obj);
1560+
if (result == PNone.NO_VALUE) {
1561+
throw raise(TypeError, ErrorMessages.RETURNED_NON_INTEGRAL, "__trunc__", truncResult);
1562+
}
1563+
}
1564+
}
15341565
}
1535-
} else if (!isIntegerType(result)) {
1536-
throw raise(TypeError, ErrorMessages.RETURNED_NON_INT, "__int__", result);
15371566
}
15381567
return createInt(cls, result);
15391568
}
@@ -1551,19 +1580,31 @@ protected static FloatBuiltins.IntNode createFloatInt() {
15511580
}
15521581

15531582
private Object callInt(VirtualFrame frame, Object obj) {
1583+
// The case when the result is NO_VALUE (i.e. the object does not provide __int__)
1584+
// is handled in createIntGeneric
15541585
if (callIntNode == null) {
15551586
CompilerDirectives.transferToInterpreterAndInvalidate();
15561587
callIntNode = insert(LookupAndCallUnaryNode.create(__INT__));
15571588
}
1558-
return callIntNode.executeObject(frame, obj);
1589+
Object result = callIntNode.executeObject(frame, obj);
1590+
if (result != PNone.NO_VALUE && !isIntegerType(result)) {
1591+
throw raise(TypeError, ErrorMessages.RETURNED_NON_INT, "__int__", result);
1592+
}
1593+
return result;
15591594
}
15601595

15611596
private Object callIndex(VirtualFrame frame, Object obj) {
15621597
if (callIndexNode == null) {
15631598
CompilerDirectives.transferToInterpreterAndInvalidate();
15641599
callIndexNode = insert(LookupAndCallUnaryNode.create(__INDEX__));
15651600
}
1566-
return callIndexNode.executeObject(frame, obj);
1601+
Object result = callIndexNode.executeObject(frame, obj);
1602+
// the case when the result is NO_VALUE (i.e. the object does not provide __index__)
1603+
// is handled in createIntGeneric
1604+
if (result != PNone.NO_VALUE && !isIntegerType(result)) {
1605+
throw raise(TypeError, ErrorMessages.RETURNED_NON_INT, "__index__", result);
1606+
}
1607+
return result;
15671608
}
15681609

15691610
private Object callTrunc(VirtualFrame frame, Object obj) {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/ErrorMessages.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ public abstract class ErrorMessages {
248248
public static final String INDEX_RETURNED_NON_INT = "__index__ returned non-int (type %p)";
249249
public static final String INSTANCE_EX_MAY_NOT_HAVE_SEP_VALUE = "instance exception may not have a separate value";
250250
public static final String INSTANCE_HAS_NO_ATTR_S = "%s instance has no attribute '%s'";
251-
public static final String INT_CANT_CONVERT_STRING_EITH_EXPL_BASE = "int() can't convert non-string with explicit base";
251+
public static final String INT_CANT_CONVERT_STRING_WITH_EXPL_BASE = "int() can't convert non-string with explicit base";
252252
public static final String INT_TOO_LARGE_TO_CONVERT_TO_FLOAT = "int too large to convert to float";
253253
public static final String INTEGER_DIVISION_BY_ZERO = "ZeroDivisionError: integer division or modulo by zero";
254254
public static final String INTEGER_DIVISION_RESULT_TOO_LARGE = "integer division result too large for a float";
@@ -406,6 +406,7 @@ public abstract class ErrorMessages {
406406
public static final String RETURNED_NON_INT = "%s returned a non-int (type %p)";
407407
public static final String P_S_RETURNED_NON_INT = "%p.%s returned a non int (type %p)";
408408
public static final String RETURNED_NON_INTEGER = "%s returned a non-integer";
409+
public static final String RETURNED_NON_INTEGRAL = "%s returned non-Integral (type %p)";
409410
public static final String RETURNED_NON_LONG = "%p.%s returned a non long (type %p)";
410411
public static final String RETURNED_NON_STRING = "%s returned non-string (type %p)";
411412
public static final String P_S_RETURNED_NON_STRING = "%p.%s returned non-string (type %p)";

0 commit comments

Comments
 (0)