Support Long and Char in const-bounded counter loop generation

If the loop end value is a compile-time constant (best we can do now),
and it is safe to iterate over a given range using "naive" for loop
(using '<=' or '>=' in loop condition),
generate such loops for Longs and Chars as well Ints (Bytes, Shorts).
This commit is contained in:
Dmitry Petrov
2017-12-11 17:54:00 +03:00
parent df2b8d01d8
commit a4c29b3587
14 changed files with 252 additions and 42 deletions
@@ -187,6 +187,9 @@ public abstract class StackValue {
else if (type == Type.BYTE_TYPE || type == Type.SHORT_TYPE || type == Type.INT_TYPE) {
return constant(Integer.valueOf(value), type);
}
else if (type == Type.CHAR_TYPE) {
return constant(Character.valueOf((char) value), type);
}
else {
throw new AssertionError("Unexpected integer type: " + type);
}
@@ -27,10 +27,7 @@ import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtForExpression
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.constants.ByteValue
import org.jetbrains.kotlin.resolve.constants.IntValue
import org.jetbrains.kotlin.resolve.constants.IntegerValueConstant
import org.jetbrains.kotlin.resolve.constants.ShortValue
import org.jetbrains.kotlin.resolve.constants.*
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
@@ -82,18 +79,61 @@ class PrimitiveNumberRangeLiteralRangeValue(
startValue: StackValue,
endExpression: KtExpression,
step: Int
) : ForLoopGenerator? {
): ForLoopGenerator? {
val endConstValue = codegen.getCompileTimeConstant(endExpression).safeAs<IntegerValueConstant<*>>() ?: return null
val endIntValue = when (endConstValue) {
is ByteValue -> endConstValue.value.toInt()
is ShortValue -> endConstValue.value.toInt()
is IntValue -> endConstValue.value
else -> return null
}
return if (isProhibitedIntConstEndValue(step, endIntValue))
null
else
return when (endConstValue) {
is ByteValue -> {
val endIntValue = endConstValue.value.toInt()
if (isProhibitedIntConstEndValue(step, endIntValue))
null
else
createConstBoundedIntForLoopGenerator(codegen, forExpression, startValue, endIntValue, step)
}
is ShortValue -> {
val endIntValue = endConstValue.value.toInt()
if (isProhibitedIntConstEndValue(step, endIntValue))
null
else
createConstBoundedIntForLoopGenerator(codegen, forExpression, startValue, endIntValue, step)
}
is IntValue -> {
val endIntValue = endConstValue.value
if (isProhibitedIntConstEndValue(step, endIntValue))
null
else
createConstBoundedIntForLoopGenerator(codegen, forExpression, startValue, endIntValue, step)
}
is CharValue -> {
val endCharValue = endConstValue.value
if (isProhibitedCharConstEndValue(step, endCharValue))
null
else
createConstBoundedIntForLoopGenerator(codegen, forExpression, startValue, endCharValue.toInt(), step)
}
is LongValue -> {
val endLongValue = endConstValue.value
if (isProhibitedLongConstEndValue(step, endLongValue))
null
else
createConstBoundedLongForLoopGenerator(codegen, forExpression, startValue, endLongValue, step)
}
else -> null
}
}
private fun createConstBoundedIntForLoopGenerator(
codegen: ExpressionCodegen,
forExpression: KtForExpression,
startValue: StackValue,
endIntValue: Int,
step: Int
): ForLoopGenerator? =
ForInDefinitelySafeSimpleProgressionLoopGenerator(
codegen, forExpression,
startValue = startValue,
@@ -102,9 +142,30 @@ class PrimitiveNumberRangeLiteralRangeValue(
isEndInclusive = true,
step = step
)
}
private fun createConstBoundedLongForLoopGenerator(
codegen: ExpressionCodegen,
forExpression: KtForExpression,
startValue: StackValue,
endLongValue: Long,
step: Int
): ForLoopGenerator? =
ForInDefinitelySafeSimpleProgressionLoopGenerator(
codegen, forExpression,
startValue = startValue,
isStartInclusive = true,
endValue = StackValue.constant(endLongValue, asmElementType),
isEndInclusive = true,
step = step
)
private fun isProhibitedCharConstEndValue(step: Int, endValue: Char) =
endValue == if (step == 1) java.lang.Character.MAX_VALUE else java.lang.Character.MIN_VALUE
private fun isProhibitedIntConstEndValue(step: Int, endValue: Int) =
endValue == if (step == 1) Int.MAX_VALUE else Int.MIN_VALUE
private fun isProhibitedLongConstEndValue(step: Int, endValue: Long) =
endValue == if (step == 1) Long.MAX_VALUE else Long.MIN_VALUE
}