Primitive number range literal as BoundedValue

This commit is contained in:
Dmitry Petrov
2017-07-05 16:23:27 +03:00
parent b693b54a2c
commit a3409b46b0
7 changed files with 62 additions and 123 deletions
@@ -24,7 +24,9 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.org.objectweb.asm.Type
private val RANGE_TO_ELEMENT_TYPE: Map<FqName, PrimitiveType> =
supportedRangeTypes().associateBy {
@@ -188,3 +190,20 @@ private fun isTopLevelInPackage(descriptor: DeclarationDescriptor, name: String,
val packageFqName = containingDeclaration.fqName.asString()
return packageName == packageFqName
}
fun getAsmRangeElementTypeForPrimitiveRange(rangeCallee: CallableDescriptor): Type {
val rangeType = rangeCallee.returnType!!
getPrimitiveRangeElementType(rangeType)?.let {
return AsmTypes.valueTypeForPrimitive(it)
}
val floatingPointElementType = getClosedFloatingPointRangeElementType(rangeType) ?:
throw AssertionError("Unexpected range type: $rangeType")
return when {
KotlinBuiltIns.isDouble(floatingPointElementType) -> Type.DOUBLE_TYPE
KotlinBuiltIns.isFloat(floatingPointElementType) -> Type.FLOAT_TYPE
else -> throw AssertionError("Unexpected ClosedFloatingPointRange element type: $floatingPointElementType")
}
}
@@ -17,17 +17,46 @@
package org.jetbrains.kotlin.codegen.range
import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.getAsmRangeElementTypeForPrimitiveRange
import org.jetbrains.kotlin.codegen.range.comparison.getComparisonGeneratorForPrimitiveType
import org.jetbrains.kotlin.codegen.range.forLoop.ForInRangeLiteralLoopGenerator
import org.jetbrains.kotlin.codegen.range.inExpression.InPrimitiveNumberRangeLiteralGenerator
import org.jetbrains.kotlin.codegen.range.inExpression.InContinuousRangeExpressionGenerator
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtForExpression
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
class PrimitiveNumberRangeLiteralRangeValue(
private val codegen: ExpressionCodegen,
rangeCall: ResolvedCall<out CallableDescriptor>
): PrimitiveNumberRangeIntrinsicRangeValue(rangeCall), BoundedValue {
private val asmElementType = getAsmRangeElementTypeForPrimitiveRange(rangeCall.resultingDescriptor)
private val from: ReceiverValue = rangeCall.dispatchReceiver ?: rangeCall.extensionReceiver!!
private val to: KtExpression = ExpressionCodegen.getSingleArgumentExpression(rangeCall)!!
class PrimitiveNumberRangeLiteralRangeValue(rangeCall: ResolvedCall<out CallableDescriptor>): PrimitiveNumberRangeIntrinsicRangeValue(rangeCall) {
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
ForInRangeLiteralLoopGenerator(codegen, forExpression, rangeCall)
override fun createIntrinsicInExpressionGenerator(codegen: ExpressionCodegen, operatorReference: KtSimpleNameExpression) =
InPrimitiveNumberRangeLiteralGenerator(codegen, operatorReference, rangeCall)
InContinuousRangeExpressionGenerator(operatorReference, this, getComparisonGeneratorForPrimitiveType(asmElementType))
override val instanceType: Type =
codegen.asmType(rangeCall.resultingDescriptor.returnType!!)
override fun putInstance(v: InstructionAdapter) {
codegen.invokeFunction(rangeCall.call, rangeCall, StackValue.none()).put(instanceType, v)
}
override fun putHighLow(v: InstructionAdapter, type: Type) {
codegen.gen(to).put(type, v)
codegen.generateReceiverValue(from, false).put(type, v)
}
override val isLowInclusive: Boolean = true
override val isHighInclusive: Boolean = true
}
@@ -84,7 +84,7 @@ private fun ExpressionCodegen.createIntrinsifiedRangeValueOrNull(rangeCall: Reso
return when {
isPrimitiveNumberRangeTo(rangeCallee) ->
PrimitiveNumberRangeLiteralRangeValue(rangeCall)
PrimitiveNumberRangeLiteralRangeValue(this, rangeCall)
isPrimitiveNumberDownTo(rangeCallee) ->
DownToProgressionRangeValue(rangeCall)
isPrimitiveNumberUntil(rangeCallee) ->
@@ -29,3 +29,11 @@ interface ComparisonGenerator {
fun jumpIfLess(v: InstructionAdapter, label: Label)
}
fun getComparisonGeneratorForPrimitiveType(type: Type): ComparisonGenerator =
when (type) {
Type.INT_TYPE, Type.SHORT_TYPE, Type.BYTE_TYPE, Type.CHAR_TYPE -> IntComparisonGenerator
Type.LONG_TYPE -> LongComparisonGenerator
Type.FLOAT_TYPE -> FloatComparisonGenerator
Type.DOUBLE_TYPE -> DoubleComparisonGenerator
else -> throw UnsupportedOperationException("Unexpected primitive type: " + type)
}
@@ -16,18 +16,12 @@
package org.jetbrains.kotlin.codegen.range.inExpression
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.getClosedFloatingPointRangeElementType
import org.jetbrains.kotlin.codegen.getPrimitiveRangeElementType
import org.jetbrains.kotlin.codegen.getAsmRangeElementTypeForPrimitiveRange
import org.jetbrains.kotlin.codegen.range.comparison.*
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
abstract class AbstractInPrimitiveNumberRangeExpressionGenerator(
codegen: ExpressionCodegen,
@@ -38,30 +32,5 @@ abstract class AbstractInPrimitiveNumberRangeExpressionGenerator(
codegen, operatorReference, isInclusiveHighBound,
getAsmRangeElementTypeForPrimitiveRange(rangeCall.resultingDescriptor)
) {
override val comparisonGenerator: ComparisonGenerator =
when (asmElementType) {
Type.INT_TYPE, Type.SHORT_TYPE, Type.BYTE_TYPE, Type.CHAR_TYPE -> IntComparisonGenerator
Type.LONG_TYPE -> LongComparisonGenerator
Type.FLOAT_TYPE -> FloatComparisonGenerator
Type.DOUBLE_TYPE -> DoubleComparisonGenerator
else -> throw UnsupportedOperationException("Unexpected type: " + asmElementType)
}
}
internal fun getAsmRangeElementTypeForPrimitiveRange(rangeCallee: CallableDescriptor): Type {
val rangeType = rangeCallee.returnType!!
getPrimitiveRangeElementType(rangeType)?.let {
return AsmTypes.valueTypeForPrimitive(it)
}
val floatingPointElementType = getClosedFloatingPointRangeElementType(rangeType) ?:
throw AssertionError("Unexpected range type: $rangeType")
return when {
KotlinBuiltIns.isDouble(floatingPointElementType) -> Type.DOUBLE_TYPE
KotlinBuiltIns.isFloat(floatingPointElementType) -> Type.FLOAT_TYPE
else -> throw AssertionError("Unexpected ClosedFloatingPointRange element type: $floatingPointElementType")
}
override val comparisonGenerator: ComparisonGenerator = getComparisonGeneratorForPrimitiveType(asmElementType)
}
@@ -1,48 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.codegen.range.inExpression
import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.range.comparison.ComparisonGenerator
import org.jetbrains.kotlin.codegen.range.comparison.ObjectComparisonGenerator
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
class InComparableRangeLiteralGenerator(
codegen: ExpressionCodegen,
operatorReference: KtSimpleNameExpression,
rangeCall: ResolvedCall<out CallableDescriptor>
) : AbstractInRangeWithKnownBoundsExpressionGenerator(
codegen, operatorReference, true,
Type.getType("Ljava/lang/Comparable;")
) {
private val from: ReceiverValue = rangeCall.extensionReceiver!!
private val to: KtExpression = ExpressionCodegen.getSingleArgumentExpression(rangeCall)!!
override fun genLowBound(): StackValue = codegen.generateReceiverValue(from, false)
override fun genHighBound(): StackValue = codegen.gen(to)
override val comparisonGenerator: ComparisonGenerator = ObjectComparisonGenerator
}
@@ -1,38 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.codegen.range.inExpression
import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
class InPrimitiveNumberRangeLiteralGenerator(
codegen: ExpressionCodegen,
operatorReference: KtSimpleNameExpression,
rangeCall: ResolvedCall<*>
) : AbstractInPrimitiveNumberRangeExpressionGenerator(codegen, operatorReference, rangeCall, isInclusiveHighBound = true) {
private val from: ReceiverValue = rangeCall.dispatchReceiver ?: rangeCall.extensionReceiver!!
private val to: KtExpression = ExpressionCodegen.getSingleArgumentExpression(rangeCall)!!
override fun genLowBound(): StackValue = codegen.generateReceiverValue(from, false)
override fun genHighBound(): StackValue = codegen.gen(to)
}