[FIR2IR] More accurate equals intrinsic for double/float types

This commit is contained in:
Ivan Kochurkin
2021-10-18 20:29:42 +03:00
committed by TeamCityServer
parent b4fada82ae
commit 82591bb107
6 changed files with 47 additions and 29 deletions
@@ -7,7 +7,7 @@ package org.jetbrains.kotlin.fir.backend.generators
import org.jetbrains.kotlin.fir.backend.*
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.isMarkedNullable
import org.jetbrains.kotlin.fir.types.isNullable
import org.jetbrains.kotlin.ir.builders.primitiveOp1
import org.jetbrains.kotlin.ir.builders.primitiveOp2
@@ -15,9 +15,12 @@ import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.types.isDoubleOrFloatWithoutNullability
import org.jetbrains.kotlin.ir.util.getSimpleFunction
@@ -158,28 +161,44 @@ internal class OperatorExpressionGenerator(
comparisonInfo: PrimitiveConeNumericComparisonInfo?,
isLeftType: Boolean
): IrExpression {
return visitor.convertToIrExpression(this).asComparisonOperand(
if (isLeftType) comparisonInfo?.leftType else comparisonInfo?.rightType,
comparisonInfo?.comparisonType,
noImplicitCast = comparisonInfo?.leftType == comparisonInfo?.rightType
)
}
val isOriginalNullable = (this as? FirExpressionWithSmartcast)?.originalExpression?.typeRef?.isMarkedNullable ?: false
val irExpression = visitor.convertToIrExpression(this)
val operandType = if (isLeftType) comparisonInfo?.leftType else comparisonInfo?.rightType
val targetType = comparisonInfo?.comparisonType
val noImplicitCast = comparisonInfo?.leftType == comparisonInfo?.rightType
private fun IrExpression.asComparisonOperand(
operandType: ConeClassLikeType?,
targetType: ConeClassLikeType?,
noImplicitCast: Boolean
): IrExpression {
fun eraseImplicitCast(): IrExpression {
return if (noImplicitCast &&
this is IrTypeOperatorCall &&
this.operator == IrTypeOperator.IMPLICIT_CAST &&
!this.type.isDoubleOrFloatWithoutNullability()
) {
this.argument
} else {
this
if (irExpression is IrTypeOperatorCall) {
val isDoubleOrFloatWithoutNullability = irExpression.type.isDoubleOrFloatWithoutNullability()
if (noImplicitCast && !isDoubleOrFloatWithoutNullability && irExpression.operator == IrTypeOperator.IMPLICIT_CAST) {
return irExpression.argument
} else {
val simpleType = irExpression.type as? IrSimpleType
if (isDoubleOrFloatWithoutNullability &&
isOriginalNullable &&
simpleType?.hasQuestionMark == false
) {
// Make it compatible with IR lowering
val nullableDoubleOrFloatType = IrSimpleTypeImpl(
simpleType.classifier,
true,
simpleType.arguments,
simpleType.annotations,
simpleType.abbreviation
)
return IrTypeOperatorCallImpl(
irExpression.startOffset,
irExpression.endOffset,
nullableDoubleOrFloatType,
irExpression.operator,
nullableDoubleOrFloatType,
irExpression.argument
)
}
}
}
return irExpression
}
if (targetType == null) {
@@ -195,21 +214,20 @@ internal class OperatorExpressionGenerator(
typeConverter.classIdToSymbolMap[operandClassId]?.getSimpleFunction("to${targetType.lookupTag.classId.shortClassName.asString()}")
?: error("No conversion function for $operandType ~> $targetType")
val dispatchReceiver = this@asComparisonOperand
val unsafeIrCall = IrCallImpl(
startOffset, endOffset,
irExpression.startOffset, irExpression.endOffset,
conversionFunction.owner.returnType,
conversionFunction,
valueArgumentsCount = 0,
typeArgumentsCount = 0
).also {
it.dispatchReceiver = dispatchReceiver
it.dispatchReceiver = irExpression
}
return if (operandType.isNullable) {
val (receiverVariable, receiverVariableSymbol) =
components.createTemporaryVariableForSafeCallConstruction(dispatchReceiver, conversionScope)
components.createTemporaryVariableForSafeCallConstruction(irExpression, conversionScope)
unsafeIrCall.dispatchReceiver = IrGetValueImpl(startOffset, endOffset, receiverVariableSymbol)
unsafeIrCall.dispatchReceiver = IrGetValueImpl(irExpression.startOffset, irExpression.endOffset, receiverVariableSymbol)
components.createSafeCallConstruction(receiverVariable, receiverVariableSymbol, unsafeIrCall)
} else {
@@ -1,5 +1,4 @@
// !LANGUAGE: +ProperIeee754Comparisons
// IGNORE_BACKEND_FIR: JVM_IR
fun equals5(a: Any?, b: Any?) = if (a is Double && b is Double?) a == b else null!!
fun equals6(a: Any?, b: Any?) = if (a is Double? && b is Double) a == b else null!!
@@ -1,5 +1,4 @@
// !LANGUAGE: +ProperIeee754Comparisons
// IGNORE_BACKEND_FIR: JVM_IR
fun equals5(a: Any?, b: Any?) = if (a is Float && b is Float?) a == b else null!!
fun equals6(a: Any?, b: Any?) = if (a is Float? && b is Float) a == b else null!!
@@ -113,3 +113,4 @@ fun Float.test6fr(x: Any): Boolean {
else -> false
}
}
@@ -94,7 +94,7 @@ FILE fqName:<root> fileName:/nullableFloatingPointEqeq.kt
if: CONST Boolean type=kotlin.Boolean value=true
then: CALL 'public open fun toDouble (): kotlin.Double declared in kotlin.Int' type=kotlin.Double origin=null
$this: GET_VAR 'val tmp_2: kotlin.Int? [val] declared in <root>.testDI2' type=kotlin.Int? origin=null
arg1: TYPE_OP type=kotlin.Double origin=IMPLICIT_CAST typeOperand=kotlin.Double
arg1: TYPE_OP type=kotlin.Double? origin=IMPLICIT_CAST typeOperand=kotlin.Double?
GET_VAR 'y: kotlin.Any? declared in <root>.testDI2' type=kotlin.Any? origin=null
BRANCH
if: CONST Boolean type=kotlin.Boolean value=true
@@ -39,7 +39,8 @@ fun testDI2(x: Any?, y: Any?): Boolean {
EQEQ(arg0 = tmp2_safe_receiver, arg1 = null) -> null
else -> tmp2_safe_receiver.toDouble()
}
}, arg1 = y /*as Double */)
}, arg1 = y /*as Double? */)
else -> false
}
}