Change toIrConst extension function logic

For now this function check not value, but type. By ir type it create
right ir const
This commit is contained in:
Ivan Kylchik
2020-06-11 15:36:45 +03:00
parent 3155f56d8a
commit af6ed5ca43
5 changed files with 60 additions and 61 deletions
@@ -407,13 +407,13 @@ class IrInterpreter(irModule: IrModuleFragment, private val bodyMap: Map<IdSigna
} }
private suspend fun interpretConst(expression: IrConst<*>): ExecutionResult { private suspend fun interpretConst(expression: IrConst<*>): ExecutionResult {
fun getSignedType(unsignedClassName: String): IrType { fun getSignedType(unsignedType: IrType): IrType {
return when (unsignedClassName) { return when {
"UByte" -> irBuiltIns.byteType unsignedType.isUByte() -> irBuiltIns.byteType
"UShort" -> irBuiltIns.shortType unsignedType.isUShort() -> irBuiltIns.shortType
"UInt" -> irBuiltIns.intType unsignedType.isUInt() -> irBuiltIns.intType
"ULong" -> irBuiltIns.longType unsignedType.isULong() -> irBuiltIns.longType
else -> throw InterpreterException("Unsupported unsigned class $unsignedClassName") else -> throw InterpreterException("Unsupported unsigned class ${unsignedType.render()}")
} }
} }
@@ -421,7 +421,7 @@ class IrInterpreter(irModule: IrModuleFragment, private val bodyMap: Map<IdSigna
val unsignedClass = expression.type.classOrNull!! val unsignedClass = expression.type.classOrNull!!
val constructor = unsignedClass.constructors.single().owner val constructor = unsignedClass.constructors.single().owner
val constructorCall = IrConstructorCallImpl.fromSymbolOwner(constructor.returnType, constructor.symbol) val constructorCall = IrConstructorCallImpl.fromSymbolOwner(constructor.returnType, constructor.symbol)
constructorCall.putValueArgument(0, expression.value.toIrConst(getSignedType(unsignedClass.owner.name.asString()))) constructorCall.putValueArgument(0, expression.value.toIrConst(getSignedType(expression.type)))
constructorCall.interpret() constructorCall.interpret()
} else { } else {
@@ -622,7 +622,7 @@ class IrInterpreter(irModule: IrModuleFragment, private val bodyMap: Map<IdSigna
IrTypeOperator.CAST, IrTypeOperator.IMPLICIT_CAST -> { IrTypeOperator.CAST, IrTypeOperator.IMPLICIT_CAST -> {
if (!isErased && !stack.peekReturnValue().isSubtypeOf(typeOperand)) { if (!isErased && !stack.peekReturnValue().isSubtypeOf(typeOperand)) {
val convertibleClassName = stack.popReturnValue().irClass.fqNameWhenAvailable val convertibleClassName = stack.popReturnValue().irClass.fqNameWhenAvailable
throw ClassCastException("$convertibleClassName cannot be cast to ${typeOperand.getFqName(withNullableSymbol = true)}") throw ClassCastException("$convertibleClassName cannot be cast to ${typeOperand.render()}")
} }
} }
IrTypeOperator.SAFE_CAST -> { IrTypeOperator.SAFE_CAST -> {
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classifierOrFail import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.types.classifierOrNull import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
import org.jetbrains.kotlin.ir.util.render
enum class ReturnLabel { enum class ReturnLabel {
NEXT, RETURN, BREAK_LOOP, BREAK_WHEN, CONTINUE, EXCEPTION NEXT, RETURN, BREAK_LOOP, BREAK_WHEN, CONTINUE, EXCEPTION
@@ -46,7 +47,7 @@ fun ExecutionResult.implicitCastIfNeeded(expectedType: IrType, actualType: IrTyp
if (!actualState.isSubtypeOf(expectedType)) { if (!actualState.isSubtypeOf(expectedType)) {
val convertibleClassName = stack.popReturnValue().irClass.fqNameWhenAvailable val convertibleClassName = stack.popReturnValue().irClass.fqNameWhenAvailable
throw ClassCastException("$convertibleClassName cannot be cast to ${expectedType.getFqName(withNullableSymbol = true)}") throw ClassCastException("$convertibleClassName cannot be cast to ${expectedType.render()}")
} }
return this return this
} }
@@ -42,20 +42,18 @@ fun IrFunctionAccessExpression.getBody(): IrBody? {
fun State.toIrExpression(expression: IrExpression): IrExpression { fun State.toIrExpression(expression: IrExpression): IrExpression {
val start = expression.startOffset val start = expression.startOffset
val end = expression.endOffset val end = expression.endOffset
val type = expression.type.makeNotNull()
return when (this) { return when (this) {
is Primitive<*> -> is Primitive<*> ->
when (this.value) { when {
// toIrConst call is necessary to replace ir offsets this.value == null -> this.value.toIrConst(type, start, end)
is Boolean, is Char, is Byte, is Short, is Int, is Long, is String, is Float, is Double -> type.isPrimitiveType() || type.isString() -> this.value.toIrConst(type, start, end)
this.value.toIrConst(this.type, start, end)
null -> this.value.toIrConst(this.type, start, end)
else -> expression // TODO support for arrays else -> expression // TODO support for arrays
} }
is Complex -> { is Complex -> {
val type = this.irClass.defaultType.toKotlinType() val stateType = this.irClass.defaultType.toKotlinType()
when { when {
UnsignedTypes.isUnsignedType(type) -> UnsignedTypes.isUnsignedType(stateType) -> (this.fields.single().state as Primitive<*>).value.toIrConst(type, start, end)
(this.fields.single().state as Primitive<*>).value.toIrConst(this.irClass.defaultType, start, end)
else -> expression else -> expression
} }
} }
@@ -74,18 +72,23 @@ fun Any?.toState(irType: IrType): State {
} }
fun Any?.toIrConst(irType: IrType, startOffset: Int = UNDEFINED_OFFSET, endOffset: Int = UNDEFINED_OFFSET): IrConst<*> { fun Any?.toIrConst(irType: IrType, startOffset: Int = UNDEFINED_OFFSET, endOffset: Int = UNDEFINED_OFFSET): IrConst<*> {
return when (this) { val constType = irType.makeNotNull()
is Boolean -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.Boolean, this) return when {
is Char -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.Char, this) this == null -> IrConstImpl.constNull(startOffset, endOffset, irType)
is Byte -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.Byte, this) constType.isBoolean() -> IrConstImpl.boolean(startOffset, endOffset, constType, this as Boolean)
is Short -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.Short, this) constType.isChar() -> IrConstImpl.char(startOffset, endOffset, constType, this as Char)
is Int -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.Int, this) constType.isByte() -> IrConstImpl.byte(startOffset, endOffset, constType, (this as Number).toByte())
is Long -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.Long, this) constType.isShort() -> IrConstImpl.short(startOffset, endOffset, constType, (this as Number).toShort())
is String -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.String, this) constType.isInt() -> IrConstImpl.int(startOffset, endOffset, constType, (this as Number).toInt())
is Float -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.Float, this) constType.isLong() -> IrConstImpl.long(startOffset, endOffset, constType, (this as Number).toLong())
is Double -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.Double, this) constType.isString() -> IrConstImpl.string(startOffset, endOffset, constType, this as String)
null -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.Null, this) constType.isFloat() -> IrConstImpl.float(startOffset, endOffset, constType, (this as Number).toFloat())
else -> throw UnsupportedOperationException("Unsupported const element type ${this::class}") constType.isDouble() -> IrConstImpl.double(startOffset, endOffset, constType, (this as Number).toDouble())
constType.isUByte() -> IrConstImpl.byte(startOffset, endOffset, constType, (this as Number).toByte())
constType.isUShort() -> IrConstImpl.short(startOffset, endOffset, constType, (this as Number).toShort())
constType.isUInt() -> IrConstImpl.int(startOffset, endOffset, constType, (this as Number).toInt())
constType.isULong() -> IrConstImpl.long(startOffset, endOffset, constType, (this as Number).toLong())
else -> throw UnsupportedOperationException("Unsupported const element type ${constType.render()}")
} }
} }
@@ -112,25 +115,21 @@ fun IrAnnotationContainer.getEvaluateIntrinsicValue(): String? {
return (this.getAnnotation(evaluateIntrinsicAnnotation).getValueArgument(0) as IrConst<*>).value.toString() return (this.getAnnotation(evaluateIntrinsicAnnotation).getValueArgument(0) as IrConst<*>).value.toString()
} }
fun getPrimitiveClass(fqName: String, asObject: Boolean = false): Class<*>? { fun getPrimitiveClass(irType: IrType, asObject: Boolean = false): Class<*>? {
return when (fqName) { return when {
"kotlin.Boolean" -> if (asObject) Boolean::class.javaObjectType else Boolean::class.java irType.isBoolean() -> if (asObject) Boolean::class.javaObjectType else Boolean::class.java
"kotlin.Char" -> if (asObject) Char::class.javaObjectType else Char::class.java irType.isChar() -> if (asObject) Char::class.javaObjectType else Char::class.java
"kotlin.Byte" -> if (asObject) Byte::class.javaObjectType else Byte::class.java irType.isByte() -> if (asObject) Byte::class.javaObjectType else Byte::class.java
"kotlin.Short" -> if (asObject) Short::class.javaObjectType else Short::class.java irType.isShort() -> if (asObject) Short::class.javaObjectType else Short::class.java
"kotlin.Int" -> if (asObject) Int::class.javaObjectType else Int::class.java irType.isInt() -> if (asObject) Int::class.javaObjectType else Int::class.java
"kotlin.Long" -> if (asObject) Long::class.javaObjectType else Long::class.java irType.isLong() -> if (asObject) Long::class.javaObjectType else Long::class.java
"kotlin.String" -> if (asObject) String::class.javaObjectType else String::class.java irType.isString() -> if (asObject) String::class.javaObjectType else String::class.java
"kotlin.Float" -> if (asObject) Float::class.javaObjectType else Float::class.java irType.isFloat() -> if (asObject) Float::class.javaObjectType else Float::class.java
"kotlin.Double" -> if (asObject) Double::class.javaObjectType else Double::class.java irType.isDouble() -> if (asObject) Double::class.javaObjectType else Double::class.java
else -> null else -> null
} }
} }
fun IrType.getFqName(withNullableSymbol: Boolean = false): String? {
return this.classOrNull?.owner?.fqNameWhenAvailable?.asString()?.let { if (this.isNullable() && withNullableSymbol) "$it?" else it }
}
fun IrFunction.getArgsForMethodInvocation(args: List<Variable>): List<Any?> { fun IrFunction.getArgsForMethodInvocation(args: List<Variable>): List<Any?> {
val argsValues = args.map { val argsValues = args.map {
when (val state = it.state) { when (val state = it.state) {
@@ -159,15 +158,15 @@ fun IrFunction.getLastOverridden(): IrFunction {
} }
fun List<Any?>.toPrimitiveStateArray(type: IrType): Primitive<*> { fun List<Any?>.toPrimitiveStateArray(type: IrType): Primitive<*> {
return when (type.getFqName()) { return when {
"kotlin.ByteArray" -> Primitive(ByteArray(size) { i -> (this[i] as Number).toByte() }, type) type.isByteArray() -> Primitive(ByteArray(size) { i -> (this[i] as Number).toByte() }, type)
"kotlin.CharArray" -> Primitive(CharArray(size) { i -> this[i] as Char }, type) type.isCharArray() -> Primitive(CharArray(size) { i -> this[i] as Char }, type)
"kotlin.ShortArray" -> Primitive(ShortArray(size) { i -> (this[i] as Number).toShort() }, type) type.isShortArray() -> Primitive(ShortArray(size) { i -> (this[i] as Number).toShort() }, type)
"kotlin.IntArray" -> Primitive(IntArray(size) { i -> (this[i] as Number).toInt() }, type) type.isIntArray() -> Primitive(IntArray(size) { i -> (this[i] as Number).toInt() }, type)
"kotlin.LongArray" -> Primitive(LongArray(size) { i -> (this[i] as Number).toLong() }, type) type.isLongArray() -> Primitive(LongArray(size) { i -> (this[i] as Number).toLong() }, type)
"kotlin.FloatArray" -> Primitive(FloatArray(size) { i -> (this[i] as Number).toFloat() }, type) type.isFloatArray() -> Primitive(FloatArray(size) { i -> (this[i] as Number).toFloat() }, type)
"kotlin.DoubleArray" -> Primitive(DoubleArray(size) { i -> (this[i] as Number).toDouble() }, type) type.isDoubleArray() -> Primitive(DoubleArray(size) { i -> (this[i] as Number).toDouble() }, type)
"kotlin.BooleanArray" -> Primitive(BooleanArray(size) { i -> this[i].toString().toBoolean() }, type) type.isBooleanArray() -> Primitive(BooleanArray(size) { i -> this[i].toString().toBoolean() }, type)
else -> Primitive<Array<*>>(this.toTypedArray(), type) else -> Primitive<Array<*>>(this.toTypedArray(), type)
} }
} }
@@ -5,7 +5,6 @@
package org.jetbrains.kotlin.backend.common.interpreter.state package org.jetbrains.kotlin.backend.common.interpreter.state
import org.jetbrains.kotlin.backend.common.interpreter.getFqName
import org.jetbrains.kotlin.backend.common.interpreter.getLastOverridden import org.jetbrains.kotlin.backend.common.interpreter.getLastOverridden
import org.jetbrains.kotlin.backend.common.interpreter.stack.Variable import org.jetbrains.kotlin.backend.common.interpreter.stack.Variable
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrClass
@@ -13,6 +12,7 @@ import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.util.nameForIrSerialization import org.jetbrains.kotlin.ir.util.nameForIrSerialization
import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.utils.addToStdlib.cast import org.jetbrains.kotlin.utils.addToStdlib.cast
class Lambda(val irFunction: IrFunction, override val irClass: IrClass) : State { class Lambda(val irFunction: IrFunction, override val irClass: IrClass) : State {
@@ -29,9 +29,9 @@ class Lambda(val irFunction: IrFunction, override val irClass: IrClass) : State
} }
override fun toString(): String { override fun toString(): String {
val receiver = (irFunction.dispatchReceiverParameter?.type ?: irFunction.extensionReceiverParameter?.type)?.getFqName(true) val receiver = (irFunction.dispatchReceiverParameter?.type ?: irFunction.extensionReceiverParameter?.type)?.render()
val arguments = irFunction.valueParameters.map { it.type.getFqName(true) }.joinToString(prefix = "(", postfix = ")") val arguments = irFunction.valueParameters.joinToString(prefix = "(", postfix = ")") { it.type.render() }
val returnType = irFunction.returnType.getFqName(true) val returnType = irFunction.returnType.render()
return ("$arguments -> $returnType").let { if (receiver != null) "$receiver.$it" else it } return ("$arguments -> $returnType").let { if (receiver != null) "$receiver.$it" else it }
} }
} }
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.backend.common.interpreter.state
import org.jetbrains.kotlin.backend.common.interpreter.builtins.evaluateIntrinsicAnnotation import org.jetbrains.kotlin.backend.common.interpreter.builtins.evaluateIntrinsicAnnotation
import org.jetbrains.kotlin.backend.common.interpreter.getEvaluateIntrinsicValue import org.jetbrains.kotlin.backend.common.interpreter.getEvaluateIntrinsicValue
import org.jetbrains.kotlin.backend.common.interpreter.getFqName
import org.jetbrains.kotlin.backend.common.interpreter.getPrimitiveClass import org.jetbrains.kotlin.backend.common.interpreter.getPrimitiveClass
import org.jetbrains.kotlin.backend.common.interpreter.hasAnnotation import org.jetbrains.kotlin.backend.common.interpreter.hasAnnotation
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
@@ -124,14 +123,14 @@ class Wrapper(val value: Any, override val irClass: IrClass) : Complex(irClass,
} }
private fun IrType.getClass(asObject: Boolean): Class<out Any> { private fun IrType.getClass(asObject: Boolean): Class<out Any> {
val fqName = this.getFqName() ?: return Any::class.java // null if this.isTypeParameter()
val owner = this.classOrNull?.owner val owner = this.classOrNull?.owner
return when { return when {
this.isPrimitiveType() -> getPrimitiveClass(fqName, asObject)!! this.isPrimitiveType() -> getPrimitiveClass(this.makeNotNull(), asObject)!!
this.isArray() -> if (asObject) Array<Any?>::class.javaObjectType else Array<Any?>::class.java this.isArray() -> if (asObject) Array<Any?>::class.javaObjectType else Array<Any?>::class.java
//TODO primitive array //TODO primitive array
owner.hasAnnotation(evaluateIntrinsicAnnotation) -> Class.forName(owner!!.getEvaluateIntrinsicValue()) owner.hasAnnotation(evaluateIntrinsicAnnotation) -> Class.forName(owner!!.getEvaluateIntrinsicValue())
else -> { else -> {
val fqName = owner?.fqNameWhenAvailable?.asString() ?: return Any::class.java // null if this.isTypeParameter()
val javaClassId = JavaToKotlinClassMap.mapKotlinToJava(FqNameUnsafe(fqName)) val javaClassId = JavaToKotlinClassMap.mapKotlinToJava(FqNameUnsafe(fqName))
val className = javaClassId?.asSingleFqName()?.asString() ?: fqName val className = javaClassId?.asSingleFqName()?.asString() ?: fqName
Class.forName(className.replaceDotWithDollarForInnerClasses()) Class.forName(className.replaceDotWithDollarForInnerClasses())