From af6ed5ca43ab8ac85610d5b9b4b94042007f574b Mon Sep 17 00:00:00 2001 From: Ivan Kylchik Date: Thu, 11 Jun 2020 15:36:45 +0300 Subject: [PATCH] Change toIrConst extension function logic For now this function check not value, but type. By ir type it create right ir const --- .../common/interpreter/IrInterpreter.kt | 18 ++-- .../backend/common/interpreter/Label.kt | 3 +- .../backend/common/interpreter/Utils.kt | 87 +++++++++---------- .../common/interpreter/state/Lambda.kt | 8 +- .../common/interpreter/state/Wrapper.kt | 5 +- 5 files changed, 60 insertions(+), 61 deletions(-) diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/IrInterpreter.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/IrInterpreter.kt index f276e78cb02..ce401e2cc20 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/IrInterpreter.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/IrInterpreter.kt @@ -407,13 +407,13 @@ class IrInterpreter(irModule: IrModuleFragment, private val bodyMap: Map): ExecutionResult { - fun getSignedType(unsignedClassName: String): IrType { - return when (unsignedClassName) { - "UByte" -> irBuiltIns.byteType - "UShort" -> irBuiltIns.shortType - "UInt" -> irBuiltIns.intType - "ULong" -> irBuiltIns.longType - else -> throw InterpreterException("Unsupported unsigned class $unsignedClassName") + fun getSignedType(unsignedType: IrType): IrType { + return when { + unsignedType.isUByte() -> irBuiltIns.byteType + unsignedType.isUShort() -> irBuiltIns.shortType + unsignedType.isUInt() -> irBuiltIns.intType + unsignedType.isULong() -> irBuiltIns.longType + else -> throw InterpreterException("Unsupported unsigned class ${unsignedType.render()}") } } @@ -421,7 +421,7 @@ class IrInterpreter(irModule: IrModuleFragment, private val bodyMap: Map { if (!isErased && !stack.peekReturnValue().isSubtypeOf(typeOperand)) { 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 -> { diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/Label.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/Label.kt index f68f0746f67..656ab2770ca 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/Label.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/Label.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.classifierOrFail import org.jetbrains.kotlin.ir.types.classifierOrNull import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable +import org.jetbrains.kotlin.ir.util.render enum class ReturnLabel { NEXT, RETURN, BREAK_LOOP, BREAK_WHEN, CONTINUE, EXCEPTION @@ -46,7 +47,7 @@ fun ExecutionResult.implicitCastIfNeeded(expectedType: IrType, actualType: IrTyp if (!actualState.isSubtypeOf(expectedType)) { 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 } diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/Utils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/Utils.kt index b842d815eeb..3ad85afdf8b 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/Utils.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/Utils.kt @@ -42,20 +42,18 @@ fun IrFunctionAccessExpression.getBody(): IrBody? { fun State.toIrExpression(expression: IrExpression): IrExpression { val start = expression.startOffset val end = expression.endOffset + val type = expression.type.makeNotNull() return when (this) { is Primitive<*> -> - when (this.value) { - // toIrConst call is necessary to replace ir offsets - is Boolean, is Char, is Byte, is Short, is Int, is Long, is String, is Float, is Double -> - this.value.toIrConst(this.type, start, end) - null -> this.value.toIrConst(this.type, start, end) + when { + this.value == null -> this.value.toIrConst(type, start, end) + type.isPrimitiveType() || type.isString() -> this.value.toIrConst(type, start, end) else -> expression // TODO support for arrays } is Complex -> { - val type = this.irClass.defaultType.toKotlinType() + val stateType = this.irClass.defaultType.toKotlinType() when { - UnsignedTypes.isUnsignedType(type) -> - (this.fields.single().state as Primitive<*>).value.toIrConst(this.irClass.defaultType, start, end) + UnsignedTypes.isUnsignedType(stateType) -> (this.fields.single().state as Primitive<*>).value.toIrConst(type, start, end) 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<*> { - return when (this) { - is Boolean -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.Boolean, this) - is Char -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.Char, this) - is Byte -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.Byte, this) - is Short -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.Short, this) - is Int -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.Int, this) - is Long -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.Long, this) - is String -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.String, this) - is Float -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.Float, this) - is Double -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.Double, this) - null -> IrConstImpl(startOffset, endOffset, irType, IrConstKind.Null, this) - else -> throw UnsupportedOperationException("Unsupported const element type ${this::class}") + val constType = irType.makeNotNull() + return when { + this == null -> IrConstImpl.constNull(startOffset, endOffset, irType) + constType.isBoolean() -> IrConstImpl.boolean(startOffset, endOffset, constType, this as Boolean) + constType.isChar() -> IrConstImpl.char(startOffset, endOffset, constType, this as Char) + constType.isByte() -> IrConstImpl.byte(startOffset, endOffset, constType, (this as Number).toByte()) + constType.isShort() -> IrConstImpl.short(startOffset, endOffset, constType, (this as Number).toShort()) + constType.isInt() -> IrConstImpl.int(startOffset, endOffset, constType, (this as Number).toInt()) + constType.isLong() -> IrConstImpl.long(startOffset, endOffset, constType, (this as Number).toLong()) + constType.isString() -> IrConstImpl.string(startOffset, endOffset, constType, this as String) + constType.isFloat() -> IrConstImpl.float(startOffset, endOffset, constType, (this as Number).toFloat()) + 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() } -fun getPrimitiveClass(fqName: String, asObject: Boolean = false): Class<*>? { - return when (fqName) { - "kotlin.Boolean" -> if (asObject) Boolean::class.javaObjectType else Boolean::class.java - "kotlin.Char" -> if (asObject) Char::class.javaObjectType else Char::class.java - "kotlin.Byte" -> if (asObject) Byte::class.javaObjectType else Byte::class.java - "kotlin.Short" -> if (asObject) Short::class.javaObjectType else Short::class.java - "kotlin.Int" -> if (asObject) Int::class.javaObjectType else Int::class.java - "kotlin.Long" -> if (asObject) Long::class.javaObjectType else Long::class.java - "kotlin.String" -> if (asObject) String::class.javaObjectType else String::class.java - "kotlin.Float" -> if (asObject) Float::class.javaObjectType else Float::class.java - "kotlin.Double" -> if (asObject) Double::class.javaObjectType else Double::class.java +fun getPrimitiveClass(irType: IrType, asObject: Boolean = false): Class<*>? { + return when { + irType.isBoolean() -> if (asObject) Boolean::class.javaObjectType else Boolean::class.java + irType.isChar() -> if (asObject) Char::class.javaObjectType else Char::class.java + irType.isByte() -> if (asObject) Byte::class.javaObjectType else Byte::class.java + irType.isShort() -> if (asObject) Short::class.javaObjectType else Short::class.java + irType.isInt() -> if (asObject) Int::class.javaObjectType else Int::class.java + irType.isLong() -> if (asObject) Long::class.javaObjectType else Long::class.java + irType.isString() -> if (asObject) String::class.javaObjectType else String::class.java + irType.isFloat() -> if (asObject) Float::class.javaObjectType else Float::class.java + irType.isDouble() -> if (asObject) Double::class.javaObjectType else Double::class.java 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): List { val argsValues = args.map { when (val state = it.state) { @@ -159,15 +158,15 @@ fun IrFunction.getLastOverridden(): IrFunction { } fun List.toPrimitiveStateArray(type: IrType): Primitive<*> { - return when (type.getFqName()) { - "kotlin.ByteArray" -> Primitive(ByteArray(size) { i -> (this[i] as Number).toByte() }, type) - "kotlin.CharArray" -> Primitive(CharArray(size) { i -> this[i] as Char }, type) - "kotlin.ShortArray" -> Primitive(ShortArray(size) { i -> (this[i] as Number).toShort() }, type) - "kotlin.IntArray" -> Primitive(IntArray(size) { i -> (this[i] as Number).toInt() }, type) - "kotlin.LongArray" -> Primitive(LongArray(size) { i -> (this[i] as Number).toLong() }, type) - "kotlin.FloatArray" -> Primitive(FloatArray(size) { i -> (this[i] as Number).toFloat() }, type) - "kotlin.DoubleArray" -> Primitive(DoubleArray(size) { i -> (this[i] as Number).toDouble() }, type) - "kotlin.BooleanArray" -> Primitive(BooleanArray(size) { i -> this[i].toString().toBoolean() }, type) + return when { + type.isByteArray() -> Primitive(ByteArray(size) { i -> (this[i] as Number).toByte() }, type) + type.isCharArray() -> Primitive(CharArray(size) { i -> this[i] as Char }, type) + type.isShortArray() -> Primitive(ShortArray(size) { i -> (this[i] as Number).toShort() }, type) + type.isIntArray() -> Primitive(IntArray(size) { i -> (this[i] as Number).toInt() }, type) + type.isLongArray() -> Primitive(LongArray(size) { i -> (this[i] as Number).toLong() }, type) + type.isFloatArray() -> Primitive(FloatArray(size) { i -> (this[i] as Number).toFloat() }, type) + type.isDoubleArray() -> Primitive(DoubleArray(size) { i -> (this[i] as Number).toDouble() }, type) + type.isBooleanArray() -> Primitive(BooleanArray(size) { i -> this[i].toString().toBoolean() }, type) else -> Primitive>(this.toTypedArray(), type) } } diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Lambda.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Lambda.kt index 3d81c3a38b9..f36e9704d42 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Lambda.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Lambda.kt @@ -5,7 +5,6 @@ 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.stack.Variable 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.expressions.IrCall import org.jetbrains.kotlin.ir.util.nameForIrSerialization +import org.jetbrains.kotlin.ir.util.render import org.jetbrains.kotlin.utils.addToStdlib.cast 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 { - val receiver = (irFunction.dispatchReceiverParameter?.type ?: irFunction.extensionReceiverParameter?.type)?.getFqName(true) - val arguments = irFunction.valueParameters.map { it.type.getFqName(true) }.joinToString(prefix = "(", postfix = ")") - val returnType = irFunction.returnType.getFqName(true) + val receiver = (irFunction.dispatchReceiverParameter?.type ?: irFunction.extensionReceiverParameter?.type)?.render() + val arguments = irFunction.valueParameters.joinToString(prefix = "(", postfix = ")") { it.type.render() } + val returnType = irFunction.returnType.render() return ("$arguments -> $returnType").let { if (receiver != null) "$receiver.$it" else it } } } \ No newline at end of file diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Wrapper.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Wrapper.kt index 36688dc1f63..3806a66a14f 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Wrapper.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/state/Wrapper.kt @@ -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.getEvaluateIntrinsicValue -import org.jetbrains.kotlin.backend.common.interpreter.getFqName import org.jetbrains.kotlin.backend.common.interpreter.getPrimitiveClass import org.jetbrains.kotlin.backend.common.interpreter.hasAnnotation 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 { - val fqName = this.getFqName() ?: return Any::class.java // null if this.isTypeParameter() val owner = this.classOrNull?.owner return when { - this.isPrimitiveType() -> getPrimitiveClass(fqName, asObject)!! + this.isPrimitiveType() -> getPrimitiveClass(this.makeNotNull(), asObject)!! this.isArray() -> if (asObject) Array::class.javaObjectType else Array::class.java //TODO primitive array owner.hasAnnotation(evaluateIntrinsicAnnotation) -> Class.forName(owner!!.getEvaluateIntrinsicValue()) else -> { + val fqName = owner?.fqNameWhenAvailable?.asString() ?: return Any::class.java // null if this.isTypeParameter() val javaClassId = JavaToKotlinClassMap.mapKotlinToJava(FqNameUnsafe(fqName)) val className = javaClassId?.asSingleFqName()?.asString() ?: fqName Class.forName(className.replaceDotWithDollarForInnerClasses())