IR: add isUnsignedType/getUnsignedType

This commit is contained in:
Alexander Udalov
2021-02-25 13:54:27 +01:00
parent 0ebdf7c3c4
commit 820762ca16
4 changed files with 40 additions and 24 deletions
@@ -5,13 +5,13 @@
package org.jetbrains.kotlin.ir.interpreter
import org.jetbrains.kotlin.ir.interpreter.builtins.compileTimeAnnotation
import org.jetbrains.kotlin.ir.interpreter.builtins.contractsDslAnnotation
import org.jetbrains.kotlin.ir.interpreter.builtins.evaluateIntrinsicAnnotation
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.interpreter.builtins.compileTimeAnnotation
import org.jetbrains.kotlin.ir.interpreter.builtins.contractsDslAnnotation
import org.jetbrains.kotlin.ir.interpreter.builtins.evaluateIntrinsicAnnotation
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
@@ -45,7 +45,7 @@ class IrCompileTimeChecker(
parentType?.isPrimitiveType() == true -> (this as IrFunction).name.asString() !in setOf("inc", "dec", "rangeTo", "hashCode")
parentType?.isString() == true -> (this as IrDeclarationWithName).name.asString() !in setOf("subSequence", "hashCode")
parentType?.isAny() == true -> (this as IrFunction).name.asString() == "toString" && expression?.dispatchReceiver !is IrGetObjectValue
parent?.isObject == true -> parent.parentClassOrNull?.defaultType?.let { it.isPrimitiveType() || it.isUnsigned() } == true
parent?.isObject == true -> parent.parentClassOrNull?.defaultType?.let { it.isPrimitiveType() || it.isUnsignedType() } == true
else -> false
}
}
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.ir.interpreter
import org.jetbrains.kotlin.builtins.UnsignedType
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.*
@@ -417,21 +418,20 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns, private val bodyMap: Map
}
private fun interpretConst(expression: IrConst<*>): ExecutionResult {
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()}")
}
fun getSignedType(unsignedType: IrType): IrType? = when (unsignedType.getUnsignedType()) {
UnsignedType.UBYTE -> irBuiltIns.byteType
UnsignedType.USHORT -> irBuiltIns.shortType
UnsignedType.UINT -> irBuiltIns.intType
UnsignedType.ULONG -> irBuiltIns.longType
else -> null
}
return if (expression.type.isUnsigned()) {
val signedType = getSignedType(expression.type)
return if (signedType != null) {
val unsignedClass = expression.type.classOrNull!!
val constructor = unsignedClass.constructors.single().owner
val constructorCall = IrConstructorCallImpl.fromSymbolOwner(constructor.returnType, constructor.symbol)
constructorCall.putValueArgument(0, expression.value.toIrConst(getSignedType(expression.type)))
constructorCall.putValueArgument(0, expression.value.toIrConst(signedType))
constructorCall.interpret()
} else {
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.ir.interpreter
import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.builtins.UnsignedType
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.*
@@ -48,7 +49,7 @@ internal fun State.toIrExpression(expression: IrExpression): IrExpression {
is Complex -> {
val stateType = this.irClass.defaultType
when {
stateType.isUnsigned() -> (this.fields.single().state as Primitive<*>).value.toIrConst(type, start, end)
stateType.isUnsignedType() -> (this.fields.single().state as Primitive<*>).value.toIrConst(type, start, end)
else -> expression
}
}
@@ -79,13 +80,15 @@ fun Any?.toIrConst(irType: IrType, startOffset: Int = UNDEFINED_OFFSET, endOffse
PrimitiveType.FLOAT -> IrConstImpl.float(startOffset, endOffset, constType, (this as Number).toFloat())
PrimitiveType.LONG -> IrConstImpl.long(startOffset, endOffset, constType, (this as Number).toLong())
PrimitiveType.DOUBLE -> IrConstImpl.double(startOffset, endOffset, constType, (this as Number).toDouble())
else -> when {
constType.isString() -> IrConstImpl.string(startOffset, endOffset, constType, this as String)
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()}")
null -> when (constType.getUnsignedType()) {
UnsignedType.UBYTE -> IrConstImpl.byte(startOffset, endOffset, constType, (this as Number).toByte())
UnsignedType.USHORT -> IrConstImpl.short(startOffset, endOffset, constType, (this as Number).toShort())
UnsignedType.UINT -> IrConstImpl.int(startOffset, endOffset, constType, (this as Number).toInt())
UnsignedType.ULONG -> IrConstImpl.long(startOffset, endOffset, constType, (this as Number).toLong())
null -> when {
constType.isString() -> IrConstImpl.string(startOffset, endOffset, constType, this as String)
else -> throw UnsupportedOperationException("Unsupported const element type ${constType.render()}")
}
}
}
}
@@ -213,8 +216,6 @@ internal fun State?.getCorrectReceiverByFunction(irFunction: IrFunction): State?
internal fun IrFunction.getCapitalizedFileName() = this.file.name.replace(".kt", "Kt").capitalizeAsciiOnly()
internal fun IrType.isUnsigned() = this.isUByte() || this.isUShort() || this.isUInt() || this.isULong()
internal fun IrType.isPrimitiveArray(): Boolean {
return this.getClass()?.fqNameWhenAvailable?.toUnsafe()?.let { StandardNames.isPrimitiveArray(it) } ?: false
}
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.ir.types
import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.builtins.UnsignedType
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
@@ -100,6 +101,20 @@ fun IrType.getPrimitiveType(): PrimitiveType? =
idSignatureToPrimitiveType[classifier.signature]
else null
fun IrType.isUnsignedType(hasQuestionMark: Boolean = false): Boolean =
this is IrSimpleType && hasQuestionMark == this.hasQuestionMark && getUnsignedType() != null
fun IrType.getUnsignedType(): UnsignedType? =
if (this is IrSimpleType && classifier is IrClassSymbol)
when (classifier.signature) {
IdSignatureValues.uByte -> UnsignedType.UBYTE
IdSignatureValues.uShort -> UnsignedType.USHORT
IdSignatureValues.uInt -> UnsignedType.UINT
IdSignatureValues.uLong -> UnsignedType.ULONG
else -> null
}
else null
fun IrType.isMarkedNullable() = (this as? IrSimpleType)?.hasQuestionMark ?: false
fun IrType.isUnit() = isNotNullClassType(IdSignatureValues.unit)