Use elementKotlinType in primitive number range intrinsics

This commit is contained in:
Dmitry Petrov
2018-12-27 16:24:41 +03:00
parent 5ae8df4d88
commit d22a31cb90
5 changed files with 46 additions and 49 deletions
@@ -38,7 +38,7 @@ class ArrayIndicesRangeValue(rangeCall: ResolvedCall<out CallableDescriptor>) :
override fun getBoundedValue(codegen: ExpressionCodegen) =
SimpleBoundedValue(
codegen.asmType(rangeCall.resultingDescriptor.returnType!!),
StackValue.constant(0, elementType),
StackValue.constant(0, codegen.asmType(elementKotlinType), elementKotlinType),
true,
StackValue.operation(Type.INT_TYPE) { v ->
codegen.generateCallReceiver(rangeCall).put(codegen.asmType(expectedReceiverType), expectedReceiverType, v)
@@ -37,7 +37,7 @@ class CharSequenceIndicesRangeValue(rangeCall: ResolvedCall<out CallableDescript
override fun getBoundedValue(codegen: ExpressionCodegen) =
SimpleBoundedValue(
codegen.asmType(rangeCall.resultingDescriptor.returnType!!),
StackValue.constant(0, elementType),
StackValue.constant(0, codegen.asmType(elementKotlinType), elementKotlinType),
true,
StackValue.operation(Type.INT_TYPE) { v ->
codegen.generateCallReceiver(rangeCall).put(codegen.asmType(expectedReceiverType), expectedReceiverType, v)
@@ -37,7 +37,7 @@ class CollectionIndicesRangeValue(rangeCall: ResolvedCall<out CallableDescriptor
override fun getBoundedValue(codegen: ExpressionCodegen) =
SimpleBoundedValue(
codegen.asmType(rangeCall.resultingDescriptor.returnType!!),
StackValue.constant(0, elementType),
StackValue.constant(0, codegen.asmType(elementKotlinType), elementKotlinType),
true,
StackValue.operation(Type.INT_TYPE) { v ->
codegen.generateCallReceiver(rangeCall).put(codegen.asmType(expectedReceiverType), expectedReceiverType, v)
@@ -43,8 +43,6 @@ abstract class PrimitiveNumberRangeIntrinsicRangeValue(
rangeCall.resultingDescriptor.returnType?.let { getRangeOrProgressionElementType(it) }
?: throw AssertionError("Unexpected range ")
protected val elementType = getAsmRangeElementTypeForPrimitiveRangeOrProgression(rangeCall.resultingDescriptor)
override fun isIntrinsicInCall(resolvedCallForIn: ResolvedCall<out CallableDescriptor>) =
resolvedCallForIn.resultingDescriptor.let {
isPrimitiveRangeContains(it) ||
@@ -145,7 +143,7 @@ abstract class PrimitiveNumberRangeIntrinsicRangeValue(
codegen, forExpression,
startValue = startValue,
isStartInclusive = isStartInclusive,
endValue = StackValue.integerConstant(endIntValue, elementType),
endValue = StackValue.integerConstant(endIntValue, codegen.asmType(elementKotlinType)),
isEndInclusive = true,
comparisonGenerator = getComparisonGeneratorForKotlinType(elementKotlinType),
step = step
@@ -163,7 +161,7 @@ abstract class PrimitiveNumberRangeIntrinsicRangeValue(
codegen, forExpression,
startValue = startValue,
isStartInclusive = isStartInclusive,
endValue = StackValue.constant(endLongValue, elementType),
endValue = StackValue.constant(endLongValue, codegen.asmType(elementKotlinType), elementKotlinType),
isEndInclusive = true,
comparisonGenerator = getComparisonGeneratorForKotlinType(elementKotlinType),
step = step
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.codegen.AsmUtil.isPrimitiveNumberClassDescriptor
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.diagnostics.PsiDiagnosticUtils
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtForExpression
@@ -18,9 +19,8 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.org.objectweb.asm.Type
val supportedRangeTypes = listOf(PrimitiveType.CHAR, PrimitiveType.INT, PrimitiveType.LONG)
@@ -61,32 +61,52 @@ private fun getPrimitiveRangeOrProgressionElementType(
return map[fqName.toSafe()]
}
private const val CHAR_RANGE_FQN = "kotlin.ranges.CharRange"
private const val INT_RANGE_FQN = "kotlin.ranges.IntRange"
private const val LONG_RANGE_FQN = "kotlin.ranges.LongRange"
private const val CHAR_PROGRESSION_FQN = "kotlin.ranges.CharProgression"
private const val INT_PROGRESSION_FQN = "kotlin.ranges.IntProgression"
private const val LONG_PROGRESSION_FQN = "kotlin.ranges.LongProgression"
private const val CLOSED_FLOAT_RANGE_FQN = "kotlin.ranges.ClosedFloatRange"
private const val CLOSED_DOUBLE_RANGE_FQN = "kotlin.ranges.ClosedDoubleRange"
private const val CLOSED_RANGE_FQN = "kotlin.ranges.ClosedRange"
private const val CLOSED_FLOATING_POINT_RANGE_FQN = "kotlin.ranges.ClosedFloatingPointRange"
private const val COMPARABLE_RANGE_FQN = "kotlin.ranges.ComparableRange"
private const val UINT_RANGE_FQN = "kotlin.ranges.UIntRange"
private const val ULONG_RANGE_FQN = "kotlin.ranges.ULongRange"
fun getRangeOrProgressionElementType(rangeType: KotlinType): KotlinType? {
val rangeClassDescriptor = rangeType.constructor.declarationDescriptor as? ClassDescriptor ?: return null
val builtIns = rangeClassDescriptor.builtIns
return when (rangeClassDescriptor.fqNameSafe.asString()) {
"kotlin.ranges.CharRange" -> builtIns.charType
"kotlin.ranges.IntRange" -> builtIns.intType
"kotlin.ranges.LongRange" -> builtIns.longType
CHAR_RANGE_FQN -> builtIns.charType
INT_RANGE_FQN -> builtIns.intType
LONG_RANGE_FQN -> builtIns.longType
"kotlin.ranges.CharProgression" -> builtIns.charType
"kotlin.ranges.IntProgression" -> builtIns.intType
"kotlin.ranges.LongProgression" -> builtIns.longType
CHAR_PROGRESSION_FQN -> builtIns.charType
INT_PROGRESSION_FQN -> builtIns.intType
LONG_PROGRESSION_FQN -> builtIns.longType
"kotlin.ranges.ClosedFloatRange" -> builtIns.floatType
"kotlin.ranges.ClosedDoubleRange" -> builtIns.doubleType
CLOSED_FLOAT_RANGE_FQN -> builtIns.floatType
CLOSED_DOUBLE_RANGE_FQN -> builtIns.doubleType
"kotlin.ranges.ClosedRange" -> rangeType.arguments.singleOrNull()?.type
CLOSED_RANGE_FQN -> rangeType.arguments.singleOrNull()?.type
"kotlin.ranges.ClosedFloatingPointRange" -> rangeType.arguments.singleOrNull()?.type
CLOSED_FLOATING_POINT_RANGE_FQN -> rangeType.arguments.singleOrNull()?.type
"kotlin.ranges.ComparableRange" -> rangeType.arguments.singleOrNull()?.type
COMPARABLE_RANGE_FQN -> rangeType.arguments.singleOrNull()?.type
UINT_RANGE_FQN -> rangeClassDescriptor.findTypeInModuleByTopLevelClassFqName(KotlinBuiltIns.FQ_NAMES.uIntFqName)
ULONG_RANGE_FQN -> rangeClassDescriptor.findTypeInModuleByTopLevelClassFqName(KotlinBuiltIns.FQ_NAMES.uLongFqName)
else -> null
}
}
private fun DeclarationDescriptor.findTypeInModuleByTopLevelClassFqName(fqName: FqName) =
module.findClassAcrossModuleDependencies(ClassId.topLevel(fqName))?.defaultType
fun BindingContext.getElementType(forExpression: KtForExpression): KotlinType {
val loopRange = forExpression.loopRange!!
val nextCall = get(BindingContext.LOOP_RANGE_NEXT_RESOLVED_CALL, loopRange)
@@ -104,6 +124,14 @@ fun isPrimitiveNumberRangeTo(rangeTo: CallableDescriptor) =
"rangeTo" == rangeTo.name.asString() && isPrimitiveNumberClassDescriptor(rangeTo.containingDeclaration) ||
isPrimitiveRangeToExtension(rangeTo)
fun isUnsignedIntegerRangeTo(rangeTo: CallableDescriptor) =
"rangeTo" == rangeTo.name.asString() && isUnsignedIntegerClass(rangeTo.containingDeclaration)
fun isUnsignedIntegerClass(descriptor: DeclarationDescriptor) =
descriptor is ClassDescriptor && descriptor.defaultType.let { type ->
KotlinBuiltIns.isUByte(type) || KotlinBuiltIns.isUShort(type) || KotlinBuiltIns.isUInt(type) || KotlinBuiltIns.isULong(type)
}
private inline fun CallableDescriptor.isTopLevelExtensionOnType(
name: String,
packageFQN: String,
@@ -225,35 +253,6 @@ fun isClosedFloatingPointRangeContains(descriptor: CallableDescriptor): Boolean
return true
}
fun getClosedFloatingPointRangeElementType(rangeType: KotlinType): KotlinType? {
val classDescriptor = rangeType.constructor.declarationDescriptor as? ClassDescriptor ?: return null
if (!classDescriptor.isTopLevelInPackage("ClosedFloatingPointRange", "kotlin.ranges")) return null
return rangeType.arguments.singleOrNull()?.type
}
fun getAsmRangeElementTypeForPrimitiveRangeOrProgression(rangeCallee: CallableDescriptor): Type {
val rangeType = rangeCallee.returnType!!
getPrimitiveRangeElementType(rangeType)?.let {
return AsmTypes.valueTypeForPrimitive(it)
}
getPrimitiveProgressionElementType(rangeType)?.let {
return AsmTypes.valueTypeForPrimitive(it)
}
getClosedFloatingPointRangeElementType(rangeType)?.let {
when {
KotlinBuiltIns.isDouble(it) -> return Type.DOUBLE_TYPE
KotlinBuiltIns.isFloat(it) -> return Type.FLOAT_TYPE
else -> {
}
}
}
throw AssertionError("Unexpected range type: $rangeType")
}
fun isCharSequenceIterator(descriptor: CallableDescriptor) =
descriptor.isTopLevelExtensionOnType("iterator", "kotlin.text") {
it.constructor.declarationDescriptor?.isTopLevelInPackage("CharSequence", "kotlin")