[FIR2IR] More accurate equals intrinsic for double/float types
This commit is contained in:
committed by
TeamCityServer
parent
b4fada82ae
commit
82591bb107
+43
-25
@@ -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!!
|
||||
|
||||
Vendored
+1
@@ -113,3 +113,4 @@ fun Float.test6fr(x: Any): Boolean {
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+2
-1
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user