JVM IR: fix operand type for CompareTo intrinsic
It's incorrect to take the first parameter type from the expression itself because it can be nullable if smart casts are used. And if it's nullable, it's mapped to the wrapper type and calling `comparisonOperandType` for it makes no sense. Instead, take the type from the callee function, as it's guaranteed to be mapped to a JVM primitive type. E.g. in `test1` function in the added test, the problem was that the dispatch receiver type of the call expression is `Double?`, which is mapped to `java/lang/Double`, whereas we clearly wanted to obtain the primitive `D` (double) type. #KT-52163 Fixed
This commit is contained in:
+16
-10
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.codegen.AsmUtil.comparisonOperandType
|
||||
import org.jetbrains.kotlin.codegen.BranchedValue
|
||||
import org.jetbrains.kotlin.codegen.NumberCompare
|
||||
import org.jetbrains.kotlin.codegen.ObjectCompare
|
||||
import org.jetbrains.kotlin.config.JvmTarget
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
|
||||
import org.jetbrains.kotlin.lexer.KtSingleValueToken
|
||||
@@ -39,18 +40,21 @@ import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
|
||||
object CompareTo : IntrinsicMethod() {
|
||||
private fun genInvoke(type: Type?, v: InstructionAdapter) {
|
||||
private fun genInvoke(type: Type?, v: InstructionAdapter, context: JvmBackendContext) {
|
||||
when (type) {
|
||||
Type.CHAR_TYPE, Type.BYTE_TYPE, Type.SHORT_TYPE, Type.INT_TYPE ->
|
||||
v.invokestatic(
|
||||
JvmSymbols.INTRINSICS_CLASS_NAME,
|
||||
"compare",
|
||||
"(II)I",
|
||||
false
|
||||
)
|
||||
v.invokestatic(JvmSymbols.INTRINSICS_CLASS_NAME, "compare", "(II)I", false)
|
||||
Type.LONG_TYPE -> v.invokestatic(JvmSymbols.INTRINSICS_CLASS_NAME, "compare", "(JJ)I", false)
|
||||
Type.FLOAT_TYPE -> v.invokestatic("java/lang/Float", "compare", "(FF)I", false)
|
||||
Type.DOUBLE_TYPE -> v.invokestatic("java/lang/Double", "compare", "(DD)I", false)
|
||||
Type.BOOLEAN_TYPE -> {
|
||||
// We could support it for JVM target 1.6, but it's prohibited now anyway (except for stdlib, which doesn't have such code),
|
||||
// so throwing an exception instead.
|
||||
check(context.state.target >= JvmTarget.JVM_1_8) {
|
||||
"Cannot generate boolean comparison for JVM target 1.6"
|
||||
}
|
||||
v.invokestatic("java/lang/Boolean", "compare", "(ZZ)I", false)
|
||||
}
|
||||
else -> throw UnsupportedOperationException()
|
||||
}
|
||||
}
|
||||
@@ -60,12 +64,14 @@ object CompareTo : IntrinsicMethod() {
|
||||
signature: JvmMethodSignature,
|
||||
context: JvmBackendContext
|
||||
): IrIntrinsicFunction {
|
||||
val callee = expression.symbol.owner
|
||||
val calleeParameter = callee.dispatchReceiverParameter ?: callee.extensionReceiverParameter!!
|
||||
val parameterType = comparisonOperandType(
|
||||
expressionType(expression.dispatchReceiver ?: expression.extensionReceiver!!, context),
|
||||
signature.valueParameters.single().asmType
|
||||
context.typeMapper.mapType(calleeParameter.type),
|
||||
signature.valueParameters.single().asmType,
|
||||
)
|
||||
return IrIntrinsicFunction.create(expression, signature, context, listOf(parameterType, parameterType)) {
|
||||
genInvoke(parameterType, it)
|
||||
genInvoke(parameterType, it, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user