Intrinsics for 'reversed': generate in-const-bound ranges as countable
#KT-21323 In Progress
This commit is contained in:
+36
-4
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.resolve.constants.ByteValue
|
|||||||
import org.jetbrains.kotlin.resolve.constants.IntValue
|
import org.jetbrains.kotlin.resolve.constants.IntValue
|
||||||
import org.jetbrains.kotlin.resolve.constants.IntegerValueConstant
|
import org.jetbrains.kotlin.resolve.constants.IntegerValueConstant
|
||||||
import org.jetbrains.kotlin.resolve.constants.ShortValue
|
import org.jetbrains.kotlin.resolve.constants.ShortValue
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
class PrimitiveNumberRangeLiteralRangeValue(
|
class PrimitiveNumberRangeLiteralRangeValue(
|
||||||
@@ -40,21 +41,24 @@ class PrimitiveNumberRangeLiteralRangeValue(
|
|||||||
SimpleBoundedValue(codegen, rangeCall)
|
SimpleBoundedValue(codegen, rangeCall)
|
||||||
|
|
||||||
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression): ForLoopGenerator =
|
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression): ForLoopGenerator =
|
||||||
getConstRangeForInRangeLiteralGenerator(codegen, forExpression) ?:
|
createConstBoundedForInRangeLiteralGenerator(codegen, forExpression) ?:
|
||||||
ForInSimpleProgressionLoopGenerator.fromBoundedValueWithStep1(codegen, forExpression, getBoundedValue(codegen))
|
ForInSimpleProgressionLoopGenerator.fromBoundedValueWithStep1(codegen, forExpression, getBoundedValue(codegen))
|
||||||
|
|
||||||
override fun createForInReversedLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression): ForLoopGenerator =
|
override fun createForInReversedLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression): ForLoopGenerator =
|
||||||
// TODO const-bounded version
|
createConstBoundedRangeForInReversedRangeLiteralGenerator(codegen, forExpression) ?:
|
||||||
ForInSimpleProgressionLoopGenerator.fromBoundedValueWithStepMinus1(codegen, forExpression, getBoundedValue(codegen))
|
ForInSimpleProgressionLoopGenerator.fromBoundedValueWithStepMinus1(codegen, forExpression, getBoundedValue(codegen))
|
||||||
|
|
||||||
private fun getConstRangeForInRangeLiteralGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression): ForLoopGenerator? {
|
private fun createConstBoundedForInRangeLiteralGenerator(
|
||||||
|
codegen: ExpressionCodegen,
|
||||||
|
forExpression: KtForExpression
|
||||||
|
): ForLoopGenerator? {
|
||||||
val rhsExpression = rangeCall.valueArgumentsByIndex?.run { get(0).arguments[0].getArgumentExpression() } ?: return null
|
val rhsExpression = rangeCall.valueArgumentsByIndex?.run { get(0).arguments[0].getArgumentExpression() } ?: return null
|
||||||
val constValue = codegen.getCompileTimeConstant(rhsExpression).safeAs<IntegerValueConstant<*>>() ?: return null
|
val constValue = codegen.getCompileTimeConstant(rhsExpression).safeAs<IntegerValueConstant<*>>() ?: return null
|
||||||
val untilValue = when (constValue) {
|
val untilValue = when (constValue) {
|
||||||
is ByteValue -> constValue.value + 1
|
is ByteValue -> constValue.value + 1
|
||||||
is ShortValue -> constValue.value + 1
|
is ShortValue -> constValue.value + 1
|
||||||
is IntValue -> constValue.value + 1
|
is IntValue -> constValue.value + 1
|
||||||
else -> return null
|
else -> Int.MIN_VALUE
|
||||||
}
|
}
|
||||||
|
|
||||||
// Watch out for integer overflow
|
// Watch out for integer overflow
|
||||||
@@ -70,4 +74,32 @@ class PrimitiveNumberRangeLiteralRangeValue(
|
|||||||
step = 1
|
step = 1
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun createConstBoundedRangeForInReversedRangeLiteralGenerator(
|
||||||
|
codegen: ExpressionCodegen,
|
||||||
|
forExpression: KtForExpression
|
||||||
|
): ForLoopGenerator? {
|
||||||
|
val lhsExpression = rangeCall.extensionReceiver.safeAs<ExpressionReceiver>()?.expression ?: return null
|
||||||
|
val constValue = codegen.getCompileTimeConstant(lhsExpression).safeAs<IntegerValueConstant<*>>() ?: return null
|
||||||
|
val untilValue = when (constValue) {
|
||||||
|
is ByteValue -> constValue.value - 1
|
||||||
|
is ShortValue -> constValue.value - 1
|
||||||
|
is IntValue -> constValue.value - 1
|
||||||
|
else -> Int.MAX_VALUE
|
||||||
|
}
|
||||||
|
|
||||||
|
// Watch out for integer overflow
|
||||||
|
return if (untilValue == Int.MAX_VALUE)
|
||||||
|
null
|
||||||
|
else
|
||||||
|
ForInSimpleProgressionLoopGenerator(
|
||||||
|
codegen, forExpression,
|
||||||
|
startValue = codegen.generateCallSingleArgument(rangeCall),
|
||||||
|
isStartInclusive = true,
|
||||||
|
endValue = StackValue.integerConstant(untilValue, asmElementType),
|
||||||
|
isEndInclusive = false,
|
||||||
|
step = -1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+25
@@ -0,0 +1,25 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
import kotlin.test.*
|
||||||
|
|
||||||
|
fun intLow() = 4
|
||||||
|
fun intHigh() = 1
|
||||||
|
fun longLow() = 4L
|
||||||
|
fun longHigh() = 1L
|
||||||
|
fun charLow() = '4'
|
||||||
|
fun charHigh() = '1'
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
for (i in (intLow() .. intHigh()).reversed()) {
|
||||||
|
throw AssertionError("Loop should not be executed")
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i in (longLow() .. longHigh()).reversed()) {
|
||||||
|
throw AssertionError("Loop should not be executed")
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i in (charLow() .. charHigh()).reversed()) {
|
||||||
|
throw AssertionError("Loop should not be executed")
|
||||||
|
}
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
Vendored
+31
@@ -0,0 +1,31 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
import kotlin.test.*
|
||||||
|
|
||||||
|
fun intLow() = 1
|
||||||
|
fun intHigh() = 4
|
||||||
|
fun longLow() = 1L
|
||||||
|
fun longHigh() = 4L
|
||||||
|
fun charLow() = '1'
|
||||||
|
fun charHigh() = '4'
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
var sum = 0
|
||||||
|
for (i in (intLow() .. intHigh()).reversed()) {
|
||||||
|
sum = sum * 10 + i
|
||||||
|
}
|
||||||
|
assertEquals(4321, sum)
|
||||||
|
|
||||||
|
var sumL = 0L
|
||||||
|
for (i in (longLow() .. longHigh()).reversed()) {
|
||||||
|
sumL = sumL * 10 + i
|
||||||
|
}
|
||||||
|
assertEquals(4321L, sumL)
|
||||||
|
|
||||||
|
var sumC = 0
|
||||||
|
for (i in (charLow() .. charHigh()).reversed()) {
|
||||||
|
sumC = sumC * 10 + i.toInt() - '0'.toInt()
|
||||||
|
}
|
||||||
|
assertEquals(4321, sumC)
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
Vendored
+2
@@ -14,6 +14,8 @@ fun box(): String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 0 reversed
|
// 0 reversed
|
||||||
|
// 0 getStart
|
||||||
|
// 0 getEnd
|
||||||
// 0 getFirst
|
// 0 getFirst
|
||||||
// 0 getLast
|
// 0 getLast
|
||||||
// 0 getStep
|
// 0 getStep
|
||||||
+5
-1
@@ -24,6 +24,10 @@ fun box(): String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 0 reversed
|
// 0 reversed
|
||||||
|
// 0 getStart
|
||||||
|
// 0 getEnd
|
||||||
// 0 getFirst
|
// 0 getFirst
|
||||||
// 0 getLast
|
// 0 getLast
|
||||||
// 0 getStep
|
// 0 getStep
|
||||||
|
// 2 IF_ICMPEQ
|
||||||
|
// ^ 1 for char progression, 1 for long progression
|
||||||
+12
@@ -15247,11 +15247,23 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("forInReversedEmptyRangeLiteralWithNonConstBounds.kt")
|
||||||
|
public void testForInReversedEmptyRangeLiteralWithNonConstBounds() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/forInReversed/forInReversedEmptyRangeLiteralWithNonConstBounds.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("forInReversedRangeLiteral.kt")
|
@TestMetadata("forInReversedRangeLiteral.kt")
|
||||||
public void testForInReversedRangeLiteral() throws Exception {
|
public void testForInReversedRangeLiteral() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/forInReversed/forInReversedRangeLiteral.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/forInReversed/forInReversedRangeLiteral.kt");
|
||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("forInReversedRangeLiteralWithNonConstBounds.kt")
|
||||||
|
public void testForInReversedRangeLiteralWithNonConstBounds() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/forInReversed/forInReversedRangeLiteralWithNonConstBounds.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/box/ranges/forInUntil")
|
@TestMetadata("compiler/testData/codegen/box/ranges/forInUntil")
|
||||||
|
|||||||
@@ -15247,11 +15247,23 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("forInReversedEmptyRangeLiteralWithNonConstBounds.kt")
|
||||||
|
public void testForInReversedEmptyRangeLiteralWithNonConstBounds() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/forInReversed/forInReversedEmptyRangeLiteralWithNonConstBounds.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("forInReversedRangeLiteral.kt")
|
@TestMetadata("forInReversedRangeLiteral.kt")
|
||||||
public void testForInReversedRangeLiteral() throws Exception {
|
public void testForInReversedRangeLiteral() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/forInReversed/forInReversedRangeLiteral.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/forInReversed/forInReversedRangeLiteral.kt");
|
||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("forInReversedRangeLiteralWithNonConstBounds.kt")
|
||||||
|
public void testForInReversedRangeLiteralWithNonConstBounds() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/forInReversed/forInReversedRangeLiteralWithNonConstBounds.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/box/ranges/forInUntil")
|
@TestMetadata("compiler/testData/codegen/box/ranges/forInUntil")
|
||||||
|
|||||||
@@ -15247,11 +15247,23 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("forInReversedEmptyRangeLiteralWithNonConstBounds.kt")
|
||||||
|
public void testForInReversedEmptyRangeLiteralWithNonConstBounds() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/forInReversed/forInReversedEmptyRangeLiteralWithNonConstBounds.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("forInReversedRangeLiteral.kt")
|
@TestMetadata("forInReversedRangeLiteral.kt")
|
||||||
public void testForInReversedRangeLiteral() throws Exception {
|
public void testForInReversedRangeLiteral() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/forInReversed/forInReversedRangeLiteral.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/forInReversed/forInReversedRangeLiteral.kt");
|
||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("forInReversedRangeLiteralWithNonConstBounds.kt")
|
||||||
|
public void testForInReversedRangeLiteralWithNonConstBounds() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/forInReversed/forInReversedRangeLiteralWithNonConstBounds.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/box/ranges/forInUntil")
|
@TestMetadata("compiler/testData/codegen/box/ranges/forInUntil")
|
||||||
|
|||||||
+12
@@ -16663,11 +16663,23 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("forInReversedEmptyRangeLiteralWithNonConstBounds.kt")
|
||||||
|
public void testForInReversedEmptyRangeLiteralWithNonConstBounds() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/forInReversed/forInReversedEmptyRangeLiteralWithNonConstBounds.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("forInReversedRangeLiteral.kt")
|
@TestMetadata("forInReversedRangeLiteral.kt")
|
||||||
public void testForInReversedRangeLiteral() throws Exception {
|
public void testForInReversedRangeLiteral() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/forInReversed/forInReversedRangeLiteral.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/forInReversed/forInReversedRangeLiteral.kt");
|
||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("forInReversedRangeLiteralWithNonConstBounds.kt")
|
||||||
|
public void testForInReversedRangeLiteralWithNonConstBounds() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/forInReversed/forInReversedRangeLiteralWithNonConstBounds.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/box/ranges/forInUntil")
|
@TestMetadata("compiler/testData/codegen/box/ranges/forInUntil")
|
||||||
|
|||||||
Reference in New Issue
Block a user