Fix loop over a range literal up to MAX_VALUE

#KT-492 In Progress

For Byte, Char and Short explicit casting from Int is removed -- loop parameter
is already stored in an Int anyway. For Int and Long comparison "i < end" at
the beginning of the loop is replaced to "i != end" at the end of the loop + a
special check for an empty loop
This commit is contained in:
Alexander Udalov
2013-06-17 21:47:41 +04:00
parent f1a6d27d35
commit 33d6347876
10 changed files with 561 additions and 31 deletions
@@ -509,6 +509,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
Label continueLabel = new Label();
generator.beforeLoop();
generator.checkEmptyLoop(loopExit);
v.mark(loopEntry);
generator.conditionAndJump(loopExit);
@@ -518,7 +519,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
generator.body();
blockStackElements.pop();
v.mark(continueLabel);
generator.afterBody();
generator.afterBody(loopExit);
v.goTo(loopEntry);
@@ -583,6 +584,8 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
}
}
public abstract void checkEmptyLoop(@NotNull Label loopExit);
public abstract void conditionAndJump(@NotNull Label loopExit);
public void beforeBody() {
@@ -628,7 +631,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
protected abstract void assignToLoopParameter();
protected abstract void increment();
protected abstract void increment(@NotNull Label loopExit);
public void body() {
gen(forExpression.getBody(), Type.VOID_TYPE);
@@ -649,8 +652,8 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
return varIndex;
}
public void afterBody() {
increment();
public void afterBody(@NotNull Label loopExit) {
increment(loopExit);
v.mark(bodyEnd);
}
@@ -712,6 +715,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
v.store(iteratorVarIndex, asmTypeForIterator);
}
@Override
public void checkEmptyLoop(@NotNull Label loopExit) {
}
@Override
public void conditionAndJump(@NotNull Label loopExit) {
// tmp<iterator>.hasNext()
@@ -741,7 +748,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
}
@Override
protected void increment() {
protected void increment(@NotNull Label loopExit) {
}
}
@@ -777,6 +784,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
v.store(indexVar, Type.INT_TYPE);
}
@Override
public void checkEmptyLoop(@NotNull Label loopExit) {
}
@Override
public void conditionAndJump(@NotNull Label loopExit) {
v.load(indexVar, Type.INT_TYPE);
@@ -803,7 +814,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
}
@Override
protected void increment() {
protected void increment(@NotNull Label loopExit) {
v.iinc(indexVar, 1);
}
}
@@ -811,8 +822,13 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
private abstract class AbstractForInRangeLoopGenerator extends AbstractForLoopGenerator {
protected int endVar;
// True iff instead of comparing loopParameterVar < endVar at the beginning of an iteration we check whether
// loopParameterVar == endVar at the end of the iteration (and also if there should be any iterations at all, before the loop)
private final boolean checkEqualityInsteadOfComparison;
private AbstractForInRangeLoopGenerator(@NotNull JetForExpression forExpression) {
super(forExpression);
checkEqualityInsteadOfComparison = asmElementType.getSort() == Type.INT || asmElementType.getSort() == Type.LONG;
}
@Override
@@ -823,27 +839,41 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
storeRangeStartAndEnd();
}
@Override
public void checkEmptyLoop(@NotNull Label loopExit) {
if (!checkEqualityInsteadOfComparison) return;
v.load(loopParameterVar, asmElementType);
v.load(endVar, asmElementType);
if (asmElementType.getSort() == Type.INT) {
v.ificmpgt(loopExit);
}
else if (asmElementType.getSort() == Type.LONG) {
v.lcmp();
v.ifgt(loopExit);
}
else {
throw new IllegalStateException("Unexpected type for empty loop checking: " + asmElementType);
}
}
protected abstract void storeRangeStartAndEnd();
@Override
public void conditionAndJump(@NotNull Label loopExit) {
if (checkEqualityInsteadOfComparison) return;
v.load(loopParameterVar, asmElementType);
v.load(endVar, asmElementType);
int sort = asmElementType.getSort();
switch (sort) {
case Type.INT:
case Type.CHAR:
case Type.BYTE:
case Type.SHORT:
v.ificmpgt(loopExit);
break;
case Type.LONG:
v.lcmp();
v.ifgt(loopExit);
break;
case Type.FLOAT:
case Type.DOUBLE:
v.cmpg(asmElementType);
@@ -859,8 +889,27 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
protected void assignToLoopParameter() {
}
private void checkPostCondition(@NotNull Label loopExit) {
v.load(loopParameterVar, asmElementType);
v.load(endVar, asmElementType);
if (asmElementType.getSort() == Type.INT) {
v.ificmpeq(loopExit);
}
else if (asmElementType.getSort() == Type.LONG) {
v.lcmp();
v.ifeq(loopExit);
}
else {
throw new IllegalStateException("Unexpected type for equality: " + asmElementType);
}
}
@Override
protected void increment() {
protected void increment(@NotNull Label loopExit) {
if (checkEqualityInsteadOfComparison) {
checkPostCondition(loopExit);
}
int sort = asmElementType.getSort();
switch (sort) {
case Type.INT:
@@ -868,11 +917,6 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
case Type.BYTE:
case Type.SHORT:
v.iinc(loopParameterVar, 1);
if (sort != Type.INT) {
v.load(loopParameterVar, Type.INT_TYPE);
StackValue.coerce(Type.INT_TYPE, asmElementType, v);
v.store(loopParameterVar, asmElementType);
}
break;
case Type.LONG:
@@ -973,6 +1017,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
generateRangeOrProgressionProperty(asmLoopRangeType, "getIncrement", incrementType, incrementVar);
}
@Override
public void checkEmptyLoop(@NotNull Label loopExit) {
}
@Override
public void conditionAndJump(@NotNull Label loopExit) {
v.load(loopParameterVar, asmElementType);
@@ -1059,7 +1107,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
}
@Override
protected void increment() {
protected void increment(@NotNull Label loopExit) {
v.load(loopParameterVar, asmElementType);
v.load(incrementVar, asmElementType);
@@ -0,0 +1,68 @@
// Auto-generated by org.jetbrains.jet.generators.tests.GenerateRangesCodegenTestData. DO NOT EDIT!
import java.util.ArrayList
import java.lang as j
import java.lang.Integer.MAX_VALUE as MaxI
import java.lang.Integer.MIN_VALUE as MinI
import java.lang.Byte.MAX_VALUE as MaxB
import java.lang.Byte.MIN_VALUE as MinB
import java.lang.Short.MAX_VALUE as MaxS
import java.lang.Short.MIN_VALUE as MinS
import java.lang.Long.MAX_VALUE as MaxL
import java.lang.Long.MIN_VALUE as MinL
import java.lang.Character.MAX_VALUE as MaxC
import java.lang.Character.MIN_VALUE as MinC
fun box(): String {
val list1 = ArrayList<Int>()
val range1 = (MaxI - 2)..MaxI
for (i in range1) {
list1.add(i)
if (list1.size() > 23) break
}
if (list1 != listOf<Int>(MaxI - 2, MaxI - 1, MaxI)) {
return "Wrong elements for (MaxI - 2)..MaxI: $list1"
}
val list2 = ArrayList<Byte>()
val range2 = (MaxB - 2).toByte()..MaxB
for (i in range2) {
list2.add(i)
if (list2.size() > 23) break
}
if (list2 != listOf<Byte>((MaxB - 2).toByte(), (MaxB - 1).toByte(), MaxB)) {
return "Wrong elements for (MaxB - 2).toByte()..MaxB: $list2"
}
val list3 = ArrayList<Short>()
val range3 = (MaxS - 2).toShort()..MaxS
for (i in range3) {
list3.add(i)
if (list3.size() > 23) break
}
if (list3 != listOf<Short>((MaxS - 2).toShort(), (MaxS - 1).toShort(), MaxS)) {
return "Wrong elements for (MaxS - 2).toShort()..MaxS: $list3"
}
val list4 = ArrayList<Long>()
val range4 = (MaxL - 2).toLong()..MaxL
for (i in range4) {
list4.add(i)
if (list4.size() > 23) break
}
if (list4 != listOf<Long>((MaxL - 2).toLong(), (MaxL - 1).toLong(), MaxL)) {
return "Wrong elements for (MaxL - 2).toLong()..MaxL: $list4"
}
val list5 = ArrayList<Char>()
val range5 = (MaxC - 2).toChar()..MaxC
for (i in range5) {
list5.add(i)
if (list5.size() > 23) break
}
if (list5 != listOf<Char>((MaxC - 2).toChar(), (MaxC - 1).toChar(), MaxC)) {
return "Wrong elements for (MaxC - 2).toChar()..MaxC: $list5"
}
return "OK"
}
@@ -0,0 +1,68 @@
// Auto-generated by org.jetbrains.jet.generators.tests.GenerateRangesCodegenTestData. DO NOT EDIT!
import java.util.ArrayList
import java.lang as j
import java.lang.Integer.MAX_VALUE as MaxI
import java.lang.Integer.MIN_VALUE as MinI
import java.lang.Byte.MAX_VALUE as MaxB
import java.lang.Byte.MIN_VALUE as MinB
import java.lang.Short.MAX_VALUE as MaxS
import java.lang.Short.MIN_VALUE as MinS
import java.lang.Long.MAX_VALUE as MaxL
import java.lang.Long.MIN_VALUE as MinL
import java.lang.Character.MAX_VALUE as MaxC
import java.lang.Character.MIN_VALUE as MinC
fun box(): String {
val list1 = ArrayList<Int>()
val range1 = MaxI..MaxI
for (i in range1) {
list1.add(i)
if (list1.size() > 23) break
}
if (list1 != listOf<Int>(MaxI)) {
return "Wrong elements for MaxI..MaxI: $list1"
}
val list2 = ArrayList<Byte>()
val range2 = MaxB..MaxB
for (i in range2) {
list2.add(i)
if (list2.size() > 23) break
}
if (list2 != listOf<Byte>(MaxB)) {
return "Wrong elements for MaxB..MaxB: $list2"
}
val list3 = ArrayList<Short>()
val range3 = MaxS..MaxS
for (i in range3) {
list3.add(i)
if (list3.size() > 23) break
}
if (list3 != listOf<Short>(MaxS)) {
return "Wrong elements for MaxS..MaxS: $list3"
}
val list4 = ArrayList<Long>()
val range4 = MaxL..MaxL
for (i in range4) {
list4.add(i)
if (list4.size() > 23) break
}
if (list4 != listOf<Long>(MaxL)) {
return "Wrong elements for MaxL..MaxL: $list4"
}
val list5 = ArrayList<Char>()
val range5 = MaxC..MaxC
for (i in range5) {
list5.add(i)
if (list5.size() > 23) break
}
if (list5 != listOf<Char>(MaxC)) {
return "Wrong elements for MaxC..MaxC: $list5"
}
return "OK"
}
@@ -0,0 +1,68 @@
// Auto-generated by org.jetbrains.jet.generators.tests.GenerateRangesCodegenTestData. DO NOT EDIT!
import java.util.ArrayList
import java.lang as j
import java.lang.Integer.MAX_VALUE as MaxI
import java.lang.Integer.MIN_VALUE as MinI
import java.lang.Byte.MAX_VALUE as MaxB
import java.lang.Byte.MIN_VALUE as MinB
import java.lang.Short.MAX_VALUE as MaxS
import java.lang.Short.MIN_VALUE as MinS
import java.lang.Long.MAX_VALUE as MaxL
import java.lang.Long.MIN_VALUE as MinL
import java.lang.Character.MAX_VALUE as MaxC
import java.lang.Character.MIN_VALUE as MinC
fun box(): String {
val list1 = ArrayList<Int>()
val range1 = MaxI..MinI
for (i in range1) {
list1.add(i)
if (list1.size() > 23) break
}
if (list1 != listOf<Int>()) {
return "Wrong elements for MaxI..MinI: $list1"
}
val list2 = ArrayList<Byte>()
val range2 = MaxB..MinB
for (i in range2) {
list2.add(i)
if (list2.size() > 23) break
}
if (list2 != listOf<Byte>()) {
return "Wrong elements for MaxB..MinB: $list2"
}
val list3 = ArrayList<Short>()
val range3 = MaxS..MinS
for (i in range3) {
list3.add(i)
if (list3.size() > 23) break
}
if (list3 != listOf<Short>()) {
return "Wrong elements for MaxS..MinS: $list3"
}
val list4 = ArrayList<Long>()
val range4 = MaxL..MinL
for (i in range4) {
list4.add(i)
if (list4.size() > 23) break
}
if (list4 != listOf<Long>()) {
return "Wrong elements for MaxL..MinL: $list4"
}
val list5 = ArrayList<Char>()
val range5 = MaxC..MinC
for (i in range5) {
list5.add(i)
if (list5.size() > 23) break
}
if (list5 != listOf<Char>()) {
return "Wrong elements for MaxC..MinC: $list5"
}
return "OK"
}
@@ -0,0 +1,63 @@
// Auto-generated by org.jetbrains.jet.generators.tests.GenerateRangesCodegenTestData. DO NOT EDIT!
import java.util.ArrayList
import java.lang as j
import java.lang.Integer.MAX_VALUE as MaxI
import java.lang.Integer.MIN_VALUE as MinI
import java.lang.Byte.MAX_VALUE as MaxB
import java.lang.Byte.MIN_VALUE as MinB
import java.lang.Short.MAX_VALUE as MaxS
import java.lang.Short.MIN_VALUE as MinS
import java.lang.Long.MAX_VALUE as MaxL
import java.lang.Long.MIN_VALUE as MinL
import java.lang.Character.MAX_VALUE as MaxC
import java.lang.Character.MIN_VALUE as MinC
fun box(): String {
val list1 = ArrayList<Int>()
for (i in (MaxI - 2)..MaxI) {
list1.add(i)
if (list1.size() > 23) break
}
if (list1 != listOf<Int>(MaxI - 2, MaxI - 1, MaxI)) {
return "Wrong elements for (MaxI - 2)..MaxI: $list1"
}
val list2 = ArrayList<Byte>()
for (i in (MaxB - 2).toByte()..MaxB) {
list2.add(i)
if (list2.size() > 23) break
}
if (list2 != listOf<Byte>((MaxB - 2).toByte(), (MaxB - 1).toByte(), MaxB)) {
return "Wrong elements for (MaxB - 2).toByte()..MaxB: $list2"
}
val list3 = ArrayList<Short>()
for (i in (MaxS - 2).toShort()..MaxS) {
list3.add(i)
if (list3.size() > 23) break
}
if (list3 != listOf<Short>((MaxS - 2).toShort(), (MaxS - 1).toShort(), MaxS)) {
return "Wrong elements for (MaxS - 2).toShort()..MaxS: $list3"
}
val list4 = ArrayList<Long>()
for (i in (MaxL - 2).toLong()..MaxL) {
list4.add(i)
if (list4.size() > 23) break
}
if (list4 != listOf<Long>((MaxL - 2).toLong(), (MaxL - 1).toLong(), MaxL)) {
return "Wrong elements for (MaxL - 2).toLong()..MaxL: $list4"
}
val list5 = ArrayList<Char>()
for (i in (MaxC - 2).toChar()..MaxC) {
list5.add(i)
if (list5.size() > 23) break
}
if (list5 != listOf<Char>((MaxC - 2).toChar(), (MaxC - 1).toChar(), MaxC)) {
return "Wrong elements for (MaxC - 2).toChar()..MaxC: $list5"
}
return "OK"
}
@@ -0,0 +1,63 @@
// Auto-generated by org.jetbrains.jet.generators.tests.GenerateRangesCodegenTestData. DO NOT EDIT!
import java.util.ArrayList
import java.lang as j
import java.lang.Integer.MAX_VALUE as MaxI
import java.lang.Integer.MIN_VALUE as MinI
import java.lang.Byte.MAX_VALUE as MaxB
import java.lang.Byte.MIN_VALUE as MinB
import java.lang.Short.MAX_VALUE as MaxS
import java.lang.Short.MIN_VALUE as MinS
import java.lang.Long.MAX_VALUE as MaxL
import java.lang.Long.MIN_VALUE as MinL
import java.lang.Character.MAX_VALUE as MaxC
import java.lang.Character.MIN_VALUE as MinC
fun box(): String {
val list1 = ArrayList<Int>()
for (i in MaxI..MaxI) {
list1.add(i)
if (list1.size() > 23) break
}
if (list1 != listOf<Int>(MaxI)) {
return "Wrong elements for MaxI..MaxI: $list1"
}
val list2 = ArrayList<Byte>()
for (i in MaxB..MaxB) {
list2.add(i)
if (list2.size() > 23) break
}
if (list2 != listOf<Byte>(MaxB)) {
return "Wrong elements for MaxB..MaxB: $list2"
}
val list3 = ArrayList<Short>()
for (i in MaxS..MaxS) {
list3.add(i)
if (list3.size() > 23) break
}
if (list3 != listOf<Short>(MaxS)) {
return "Wrong elements for MaxS..MaxS: $list3"
}
val list4 = ArrayList<Long>()
for (i in MaxL..MaxL) {
list4.add(i)
if (list4.size() > 23) break
}
if (list4 != listOf<Long>(MaxL)) {
return "Wrong elements for MaxL..MaxL: $list4"
}
val list5 = ArrayList<Char>()
for (i in MaxC..MaxC) {
list5.add(i)
if (list5.size() > 23) break
}
if (list5 != listOf<Char>(MaxC)) {
return "Wrong elements for MaxC..MaxC: $list5"
}
return "OK"
}
@@ -0,0 +1,63 @@
// Auto-generated by org.jetbrains.jet.generators.tests.GenerateRangesCodegenTestData. DO NOT EDIT!
import java.util.ArrayList
import java.lang as j
import java.lang.Integer.MAX_VALUE as MaxI
import java.lang.Integer.MIN_VALUE as MinI
import java.lang.Byte.MAX_VALUE as MaxB
import java.lang.Byte.MIN_VALUE as MinB
import java.lang.Short.MAX_VALUE as MaxS
import java.lang.Short.MIN_VALUE as MinS
import java.lang.Long.MAX_VALUE as MaxL
import java.lang.Long.MIN_VALUE as MinL
import java.lang.Character.MAX_VALUE as MaxC
import java.lang.Character.MIN_VALUE as MinC
fun box(): String {
val list1 = ArrayList<Int>()
for (i in MaxI..MinI) {
list1.add(i)
if (list1.size() > 23) break
}
if (list1 != listOf<Int>()) {
return "Wrong elements for MaxI..MinI: $list1"
}
val list2 = ArrayList<Byte>()
for (i in MaxB..MinB) {
list2.add(i)
if (list2.size() > 23) break
}
if (list2 != listOf<Byte>()) {
return "Wrong elements for MaxB..MinB: $list2"
}
val list3 = ArrayList<Short>()
for (i in MaxS..MinS) {
list3.add(i)
if (list3.size() > 23) break
}
if (list3 != listOf<Short>()) {
return "Wrong elements for MaxS..MinS: $list3"
}
val list4 = ArrayList<Long>()
for (i in MaxL..MinL) {
list4.add(i)
if (list4.size() > 23) break
}
if (list4 != listOf<Long>()) {
return "Wrong elements for MaxL..MinL: $list4"
}
val list5 = ArrayList<Char>()
for (i in MaxC..MinC) {
list5.add(i)
if (list5.size() > 23) break
}
if (list5 != listOf<Char>()) {
return "Wrong elements for MaxC..MinC: $list5"
}
return "OK"
}
@@ -439,6 +439,21 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/ranges/expression/infiniteSteps.kt");
}
@TestMetadata("maxValueMinusTwoToMaxValue.kt")
public void testMaxValueMinusTwoToMaxValue() throws Exception {
doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/ranges/expression/maxValueMinusTwoToMaxValue.kt");
}
@TestMetadata("maxValueToMaxValue.kt")
public void testMaxValueToMaxValue() throws Exception {
doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/ranges/expression/maxValueToMaxValue.kt");
}
@TestMetadata("maxValueToMinValue.kt")
public void testMaxValueToMinValue() throws Exception {
doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/ranges/expression/maxValueToMinValue.kt");
}
@TestMetadata("nanEnds.kt")
public void testNanEnds() throws Exception {
doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/ranges/expression/nanEnds.kt");
@@ -542,6 +557,21 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/ranges/literal/infiniteSteps.kt");
}
@TestMetadata("maxValueMinusTwoToMaxValue.kt")
public void testMaxValueMinusTwoToMaxValue() throws Exception {
doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/ranges/literal/maxValueMinusTwoToMaxValue.kt");
}
@TestMetadata("maxValueToMaxValue.kt")
public void testMaxValueToMaxValue() throws Exception {
doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/ranges/literal/maxValueToMaxValue.kt");
}
@TestMetadata("maxValueToMinValue.kt")
public void testMaxValueToMinValue() throws Exception {
doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/ranges/literal/maxValueToMinValue.kt");
}
@TestMetadata("nanEnds.kt")
public void testNanEnds() throws Exception {
doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/ranges/literal/nanEnds.kt");
@@ -19,11 +19,15 @@ package org.jetbrains.jet.generators.tests;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.LineSeparator;
import com.intellij.util.containers.ContainerUtil;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -58,22 +62,29 @@ public class GenerateRangesCodegenTestData {
" }\n" +
"\n";
private static final Map<String, String> ELEMENT_TYPE_KNOWN_SUBSTRINGS = new ContainerUtil.ImmutableMapBuilder<String, String>()
.put("'", "Char")
.put("\"", "Char")
.put("Float.NaN", "Float")
.put("Double.NaN", "Double")
.put("MaxB", "Byte")
.put("MaxS", "Short")
.put("MaxL", "Long")
.put("MaxC", "Char")
.build();
private static String detectElementType(String rangeExpression) {
Matcher matcher = Pattern.compile("\\.to(\\w+)").matcher(rangeExpression);
if (matcher.find()) {
return matcher.group(1);
}
if (rangeExpression.contains("'") || rangeExpression.contains("\"")) {
return "Char";
}
if (Pattern.compile("\\d\\.\\d").matcher(rangeExpression).find()) {
return "Double";
}
if (rangeExpression.contains("Float.NaN")) {
return "Float";
}
if (rangeExpression.contains("Double.NaN")) {
return "Double";
for (String substring : ELEMENT_TYPE_KNOWN_SUBSTRINGS.keySet()) {
if (rangeExpression.contains(substring)) {
return ELEMENT_TYPE_KNOWN_SUBSTRINGS.get(substring);
}
}
return "Int";
}
@@ -89,7 +100,9 @@ public class GenerateRangesCodegenTestData {
.replace("\n", LineSeparator.getSystemLineSeparator().getSeparatorString());
}
private static void writeToFile(File file, CharSequence generatedBody) {
private static final List<String> INTEGER_PRIMITIVES = Arrays.asList("Integer", "Byte", "Short", "Long", "Character");
private static void writeToFile(File file, String generatedBody) {
PrintWriter out;
try {
//noinspection IOResourceOpenedButNotSafelyClosed
@@ -102,6 +115,14 @@ public class GenerateRangesCodegenTestData {
out.println("// Auto-generated by " + GenerateRangesCodegenTestData.class.getName() + ". DO NOT EDIT!");
out.println("import java.util.ArrayList");
out.println("import java.lang as j");
if (generatedBody.contains("Max") || generatedBody.contains("Min")) {
// Import min/max values, but only in case when the generated test case actually uses them (not to clutter tests which don't)
out.println();
for (String primitive : INTEGER_PRIMITIVES) {
out.println("import java.lang." + primitive + ".MAX_VALUE as Max" + primitive.charAt(0));
out.println("import java.lang." + primitive + ".MIN_VALUE as Min" + primitive.charAt(0));
}
}
out.println();
out.println("fun box(): String {");
out.print(generatedBody);
@@ -146,8 +167,8 @@ public class GenerateRangesCodegenTestData {
}
String fileName = testFunName + ".kt";
writeToFile(new File(AS_LITERAL_DIR, fileName), asLiteralBody);
writeToFile(new File(AS_EXPRESSION_DIR, fileName), asExpressionBody);
writeToFile(new File(AS_LITERAL_DIR, fileName), asLiteralBody.toString());
writeToFile(new File(AS_EXPRESSION_DIR, fileName), asExpressionBody.toString());
}
}
@@ -4,6 +4,17 @@ import kotlin.test.assertEquals
import org.junit.Test as test
import java.lang as j
import java.lang.Integer.MAX_VALUE as MaxI
import java.lang.Integer.MIN_VALUE as MinI
import java.lang.Byte.MAX_VALUE as MaxB
import java.lang.Byte.MIN_VALUE as MinB
import java.lang.Short.MAX_VALUE as MaxS
import java.lang.Short.MIN_VALUE as MinS
import java.lang.Long.MAX_VALUE as MaxL
import java.lang.Long.MIN_VALUE as MinL
import java.lang.Character.MAX_VALUE as MaxC
import java.lang.Character.MIN_VALUE as MinC
// Test data for codegen is generated from this class. If you change it, rerun GenerateTests
public class RangeIterationTest {
private fun <N> doTest(
@@ -280,4 +291,31 @@ public class RangeIterationTest {
doTest(j.Double.NaN downTo j.Double.NaN, j.Double.NaN, j.Double.NaN, -1.0, listOf())
doTest(j.Float.NaN downTo j.Float.NaN, j.Float.NaN, j.Float.NaN, -1.0.toFloat(), listOf())
}
}
test fun maxValueToMaxValue() {
doTest(MaxI..MaxI, MaxI, MaxI, 1, listOf(MaxI))
doTest(MaxB..MaxB, MaxB, MaxB, 1, listOf(MaxB))
doTest(MaxS..MaxS, MaxS, MaxS, 1, listOf(MaxS))
doTest(MaxL..MaxL, MaxL, MaxL, 1.toLong(), listOf(MaxL))
doTest(MaxC..MaxC, MaxC, MaxC, 1, listOf(MaxC))
}
test fun maxValueMinusTwoToMaxValue() {
doTest((MaxI - 2)..MaxI, MaxI - 2, MaxI, 1, listOf(MaxI - 2, MaxI - 1, MaxI))
doTest((MaxB - 2).toByte()..MaxB, (MaxB - 2).toByte(), MaxB, 1, listOf((MaxB - 2).toByte(), (MaxB - 1).toByte(), MaxB))
doTest((MaxS - 2).toShort()..MaxS, (MaxS - 2).toShort(), MaxS, 1, listOf((MaxS - 2).toShort(), (MaxS - 1).toShort(), MaxS))
doTest((MaxL - 2).toLong()..MaxL, (MaxL - 2).toLong(), MaxL, 1.toLong(), listOf((MaxL - 2).toLong(), (MaxL - 1).toLong(), MaxL))
doTest((MaxC - 2).toChar()..MaxC, (MaxC - 2).toChar(), MaxC, 1, listOf((MaxC - 2).toChar(), (MaxC - 1).toChar(), MaxC))
}
test fun maxValueToMinValue() {
doTest(MaxI..MinI, MaxI, MinI, 1, listOf())
doTest(MaxB..MinB, MaxB, MinB, 1, listOf())
doTest(MaxS..MinS, MaxS, MinS, 1, listOf())
doTest(MaxL..MinL, MaxL, MinL, 1.toLong(), listOf())
doTest(MaxC..MinC, MaxC, MinC, 1, listOf())
}
}