diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 41d1dd24b84..1ae21c4ccd2 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -509,6 +509,7 @@ public class ExpressionCodegen extends JetVisitor 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 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 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 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 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 implem v.store(iteratorVarIndex, asmTypeForIterator); } + @Override + public void checkEmptyLoop(@NotNull Label loopExit) { + } + @Override public void conditionAndJump(@NotNull Label loopExit) { // tmp.hasNext() @@ -741,7 +748,7 @@ public class ExpressionCodegen extends JetVisitor implem } @Override - protected void increment() { + protected void increment(@NotNull Label loopExit) { } } @@ -777,6 +784,10 @@ public class ExpressionCodegen extends JetVisitor 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 implem } @Override - protected void increment() { + protected void increment(@NotNull Label loopExit) { v.iinc(indexVar, 1); } } @@ -811,8 +822,13 @@ public class ExpressionCodegen extends JetVisitor 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 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 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 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 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 implem } @Override - protected void increment() { + protected void increment(@NotNull Label loopExit) { v.load(loopParameterVar, asmElementType); v.load(incrementVar, asmElementType); diff --git a/compiler/testData/codegen/boxWithStdlib/ranges/expression/maxValueMinusTwoToMaxValue.kt b/compiler/testData/codegen/boxWithStdlib/ranges/expression/maxValueMinusTwoToMaxValue.kt new file mode 100644 index 00000000000..ddca33a8b2c --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/ranges/expression/maxValueMinusTwoToMaxValue.kt @@ -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() + val range1 = (MaxI - 2)..MaxI + for (i in range1) { + list1.add(i) + if (list1.size() > 23) break + } + if (list1 != listOf(MaxI - 2, MaxI - 1, MaxI)) { + return "Wrong elements for (MaxI - 2)..MaxI: $list1" + } + + val list2 = ArrayList() + val range2 = (MaxB - 2).toByte()..MaxB + for (i in range2) { + list2.add(i) + if (list2.size() > 23) break + } + if (list2 != listOf((MaxB - 2).toByte(), (MaxB - 1).toByte(), MaxB)) { + return "Wrong elements for (MaxB - 2).toByte()..MaxB: $list2" + } + + val list3 = ArrayList() + val range3 = (MaxS - 2).toShort()..MaxS + for (i in range3) { + list3.add(i) + if (list3.size() > 23) break + } + if (list3 != listOf((MaxS - 2).toShort(), (MaxS - 1).toShort(), MaxS)) { + return "Wrong elements for (MaxS - 2).toShort()..MaxS: $list3" + } + + val list4 = ArrayList() + val range4 = (MaxL - 2).toLong()..MaxL + for (i in range4) { + list4.add(i) + if (list4.size() > 23) break + } + if (list4 != listOf((MaxL - 2).toLong(), (MaxL - 1).toLong(), MaxL)) { + return "Wrong elements for (MaxL - 2).toLong()..MaxL: $list4" + } + + val list5 = ArrayList() + val range5 = (MaxC - 2).toChar()..MaxC + for (i in range5) { + list5.add(i) + if (list5.size() > 23) break + } + if (list5 != listOf((MaxC - 2).toChar(), (MaxC - 1).toChar(), MaxC)) { + return "Wrong elements for (MaxC - 2).toChar()..MaxC: $list5" + } + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/ranges/expression/maxValueToMaxValue.kt b/compiler/testData/codegen/boxWithStdlib/ranges/expression/maxValueToMaxValue.kt new file mode 100644 index 00000000000..0ddb0f8dc26 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/ranges/expression/maxValueToMaxValue.kt @@ -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() + val range1 = MaxI..MaxI + for (i in range1) { + list1.add(i) + if (list1.size() > 23) break + } + if (list1 != listOf(MaxI)) { + return "Wrong elements for MaxI..MaxI: $list1" + } + + val list2 = ArrayList() + val range2 = MaxB..MaxB + for (i in range2) { + list2.add(i) + if (list2.size() > 23) break + } + if (list2 != listOf(MaxB)) { + return "Wrong elements for MaxB..MaxB: $list2" + } + + val list3 = ArrayList() + val range3 = MaxS..MaxS + for (i in range3) { + list3.add(i) + if (list3.size() > 23) break + } + if (list3 != listOf(MaxS)) { + return "Wrong elements for MaxS..MaxS: $list3" + } + + val list4 = ArrayList() + val range4 = MaxL..MaxL + for (i in range4) { + list4.add(i) + if (list4.size() > 23) break + } + if (list4 != listOf(MaxL)) { + return "Wrong elements for MaxL..MaxL: $list4" + } + + val list5 = ArrayList() + val range5 = MaxC..MaxC + for (i in range5) { + list5.add(i) + if (list5.size() > 23) break + } + if (list5 != listOf(MaxC)) { + return "Wrong elements for MaxC..MaxC: $list5" + } + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/ranges/expression/maxValueToMinValue.kt b/compiler/testData/codegen/boxWithStdlib/ranges/expression/maxValueToMinValue.kt new file mode 100644 index 00000000000..42f641c76e8 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/ranges/expression/maxValueToMinValue.kt @@ -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() + val range1 = MaxI..MinI + for (i in range1) { + list1.add(i) + if (list1.size() > 23) break + } + if (list1 != listOf()) { + return "Wrong elements for MaxI..MinI: $list1" + } + + val list2 = ArrayList() + val range2 = MaxB..MinB + for (i in range2) { + list2.add(i) + if (list2.size() > 23) break + } + if (list2 != listOf()) { + return "Wrong elements for MaxB..MinB: $list2" + } + + val list3 = ArrayList() + val range3 = MaxS..MinS + for (i in range3) { + list3.add(i) + if (list3.size() > 23) break + } + if (list3 != listOf()) { + return "Wrong elements for MaxS..MinS: $list3" + } + + val list4 = ArrayList() + val range4 = MaxL..MinL + for (i in range4) { + list4.add(i) + if (list4.size() > 23) break + } + if (list4 != listOf()) { + return "Wrong elements for MaxL..MinL: $list4" + } + + val list5 = ArrayList() + val range5 = MaxC..MinC + for (i in range5) { + list5.add(i) + if (list5.size() > 23) break + } + if (list5 != listOf()) { + return "Wrong elements for MaxC..MinC: $list5" + } + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/ranges/literal/maxValueMinusTwoToMaxValue.kt b/compiler/testData/codegen/boxWithStdlib/ranges/literal/maxValueMinusTwoToMaxValue.kt new file mode 100644 index 00000000000..e5aa948b769 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/ranges/literal/maxValueMinusTwoToMaxValue.kt @@ -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() + for (i in (MaxI - 2)..MaxI) { + list1.add(i) + if (list1.size() > 23) break + } + if (list1 != listOf(MaxI - 2, MaxI - 1, MaxI)) { + return "Wrong elements for (MaxI - 2)..MaxI: $list1" + } + + val list2 = ArrayList() + for (i in (MaxB - 2).toByte()..MaxB) { + list2.add(i) + if (list2.size() > 23) break + } + if (list2 != listOf((MaxB - 2).toByte(), (MaxB - 1).toByte(), MaxB)) { + return "Wrong elements for (MaxB - 2).toByte()..MaxB: $list2" + } + + val list3 = ArrayList() + for (i in (MaxS - 2).toShort()..MaxS) { + list3.add(i) + if (list3.size() > 23) break + } + if (list3 != listOf((MaxS - 2).toShort(), (MaxS - 1).toShort(), MaxS)) { + return "Wrong elements for (MaxS - 2).toShort()..MaxS: $list3" + } + + val list4 = ArrayList() + for (i in (MaxL - 2).toLong()..MaxL) { + list4.add(i) + if (list4.size() > 23) break + } + if (list4 != listOf((MaxL - 2).toLong(), (MaxL - 1).toLong(), MaxL)) { + return "Wrong elements for (MaxL - 2).toLong()..MaxL: $list4" + } + + val list5 = ArrayList() + for (i in (MaxC - 2).toChar()..MaxC) { + list5.add(i) + if (list5.size() > 23) break + } + if (list5 != listOf((MaxC - 2).toChar(), (MaxC - 1).toChar(), MaxC)) { + return "Wrong elements for (MaxC - 2).toChar()..MaxC: $list5" + } + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/ranges/literal/maxValueToMaxValue.kt b/compiler/testData/codegen/boxWithStdlib/ranges/literal/maxValueToMaxValue.kt new file mode 100644 index 00000000000..c0c9e1a49d7 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/ranges/literal/maxValueToMaxValue.kt @@ -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() + for (i in MaxI..MaxI) { + list1.add(i) + if (list1.size() > 23) break + } + if (list1 != listOf(MaxI)) { + return "Wrong elements for MaxI..MaxI: $list1" + } + + val list2 = ArrayList() + for (i in MaxB..MaxB) { + list2.add(i) + if (list2.size() > 23) break + } + if (list2 != listOf(MaxB)) { + return "Wrong elements for MaxB..MaxB: $list2" + } + + val list3 = ArrayList() + for (i in MaxS..MaxS) { + list3.add(i) + if (list3.size() > 23) break + } + if (list3 != listOf(MaxS)) { + return "Wrong elements for MaxS..MaxS: $list3" + } + + val list4 = ArrayList() + for (i in MaxL..MaxL) { + list4.add(i) + if (list4.size() > 23) break + } + if (list4 != listOf(MaxL)) { + return "Wrong elements for MaxL..MaxL: $list4" + } + + val list5 = ArrayList() + for (i in MaxC..MaxC) { + list5.add(i) + if (list5.size() > 23) break + } + if (list5 != listOf(MaxC)) { + return "Wrong elements for MaxC..MaxC: $list5" + } + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/ranges/literal/maxValueToMinValue.kt b/compiler/testData/codegen/boxWithStdlib/ranges/literal/maxValueToMinValue.kt new file mode 100644 index 00000000000..8722f4f4e1b --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/ranges/literal/maxValueToMinValue.kt @@ -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() + for (i in MaxI..MinI) { + list1.add(i) + if (list1.size() > 23) break + } + if (list1 != listOf()) { + return "Wrong elements for MaxI..MinI: $list1" + } + + val list2 = ArrayList() + for (i in MaxB..MinB) { + list2.add(i) + if (list2.size() > 23) break + } + if (list2 != listOf()) { + return "Wrong elements for MaxB..MinB: $list2" + } + + val list3 = ArrayList() + for (i in MaxS..MinS) { + list3.add(i) + if (list3.size() > 23) break + } + if (list3 != listOf()) { + return "Wrong elements for MaxS..MinS: $list3" + } + + val list4 = ArrayList() + for (i in MaxL..MinL) { + list4.add(i) + if (list4.size() > 23) break + } + if (list4 != listOf()) { + return "Wrong elements for MaxL..MinL: $list4" + } + + val list5 = ArrayList() + for (i in MaxC..MinC) { + list5.add(i) + if (list5.size() > 23) break + } + if (list5 != listOf()) { + return "Wrong elements for MaxC..MinC: $list5" + } + + return "OK" +} diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index 96533c05d3e..26cc88726d3 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -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"); diff --git a/generators/org/jetbrains/jet/generators/tests/GenerateRangesCodegenTestData.java b/generators/org/jetbrains/jet/generators/tests/GenerateRangesCodegenTestData.java index 94809600e8a..fabedee33f9 100644 --- a/generators/org/jetbrains/jet/generators/tests/GenerateRangesCodegenTestData.java +++ b/generators/org/jetbrains/jet/generators/tests/GenerateRangesCodegenTestData.java @@ -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 ELEMENT_TYPE_KNOWN_SUBSTRINGS = new ContainerUtil.ImmutableMapBuilder() + .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 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()); } } diff --git a/libraries/stdlib/test/language/RangeIterationTest.kt b/libraries/stdlib/test/language/RangeIterationTest.kt index d7251c454bb..37fcd7e9e48 100644 --- a/libraries/stdlib/test/language/RangeIterationTest.kt +++ b/libraries/stdlib/test/language/RangeIterationTest.kt @@ -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 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()) } -} \ No newline at end of file + + 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()) + } +}