[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.backend.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.*
|
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.fir.types.isNullable
|
||||||
import org.jetbrains.kotlin.ir.builders.primitiveOp1
|
import org.jetbrains.kotlin.ir.builders.primitiveOp1
|
||||||
import org.jetbrains.kotlin.ir.builders.primitiveOp2
|
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.IrCallImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
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.IrClassifierSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
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.classifierOrFail
|
||||||
|
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
||||||
import org.jetbrains.kotlin.ir.types.isDoubleOrFloatWithoutNullability
|
import org.jetbrains.kotlin.ir.types.isDoubleOrFloatWithoutNullability
|
||||||
import org.jetbrains.kotlin.ir.util.getSimpleFunction
|
import org.jetbrains.kotlin.ir.util.getSimpleFunction
|
||||||
|
|
||||||
@@ -158,28 +161,44 @@ internal class OperatorExpressionGenerator(
|
|||||||
comparisonInfo: PrimitiveConeNumericComparisonInfo?,
|
comparisonInfo: PrimitiveConeNumericComparisonInfo?,
|
||||||
isLeftType: Boolean
|
isLeftType: Boolean
|
||||||
): IrExpression {
|
): IrExpression {
|
||||||
return visitor.convertToIrExpression(this).asComparisonOperand(
|
val isOriginalNullable = (this as? FirExpressionWithSmartcast)?.originalExpression?.typeRef?.isMarkedNullable ?: false
|
||||||
if (isLeftType) comparisonInfo?.leftType else comparisonInfo?.rightType,
|
val irExpression = visitor.convertToIrExpression(this)
|
||||||
comparisonInfo?.comparisonType,
|
val operandType = if (isLeftType) comparisonInfo?.leftType else comparisonInfo?.rightType
|
||||||
noImplicitCast = comparisonInfo?.leftType == 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 {
|
fun eraseImplicitCast(): IrExpression {
|
||||||
return if (noImplicitCast &&
|
if (irExpression is IrTypeOperatorCall) {
|
||||||
this is IrTypeOperatorCall &&
|
val isDoubleOrFloatWithoutNullability = irExpression.type.isDoubleOrFloatWithoutNullability()
|
||||||
this.operator == IrTypeOperator.IMPLICIT_CAST &&
|
if (noImplicitCast && !isDoubleOrFloatWithoutNullability && irExpression.operator == IrTypeOperator.IMPLICIT_CAST) {
|
||||||
!this.type.isDoubleOrFloatWithoutNullability()
|
return irExpression.argument
|
||||||
) {
|
} else {
|
||||||
this.argument
|
val simpleType = irExpression.type as? IrSimpleType
|
||||||
} else {
|
if (isDoubleOrFloatWithoutNullability &&
|
||||||
this
|
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) {
|
if (targetType == null) {
|
||||||
@@ -195,21 +214,20 @@ internal class OperatorExpressionGenerator(
|
|||||||
typeConverter.classIdToSymbolMap[operandClassId]?.getSimpleFunction("to${targetType.lookupTag.classId.shortClassName.asString()}")
|
typeConverter.classIdToSymbolMap[operandClassId]?.getSimpleFunction("to${targetType.lookupTag.classId.shortClassName.asString()}")
|
||||||
?: error("No conversion function for $operandType ~> $targetType")
|
?: error("No conversion function for $operandType ~> $targetType")
|
||||||
|
|
||||||
val dispatchReceiver = this@asComparisonOperand
|
|
||||||
val unsafeIrCall = IrCallImpl(
|
val unsafeIrCall = IrCallImpl(
|
||||||
startOffset, endOffset,
|
irExpression.startOffset, irExpression.endOffset,
|
||||||
conversionFunction.owner.returnType,
|
conversionFunction.owner.returnType,
|
||||||
conversionFunction,
|
conversionFunction,
|
||||||
valueArgumentsCount = 0,
|
valueArgumentsCount = 0,
|
||||||
typeArgumentsCount = 0
|
typeArgumentsCount = 0
|
||||||
).also {
|
).also {
|
||||||
it.dispatchReceiver = dispatchReceiver
|
it.dispatchReceiver = irExpression
|
||||||
}
|
}
|
||||||
return if (operandType.isNullable) {
|
return if (operandType.isNullable) {
|
||||||
val (receiverVariable, receiverVariableSymbol) =
|
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)
|
components.createSafeCallConstruction(receiverVariable, receiverVariableSymbol, unsafeIrCall)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
// !LANGUAGE: +ProperIeee754Comparisons
|
// !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 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!!
|
fun equals6(a: Any?, b: Any?) = if (a is Double? && b is Double) a == b else null!!
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
// !LANGUAGE: +ProperIeee754Comparisons
|
// !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 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!!
|
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
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -94,7 +94,7 @@ FILE fqName:<root> fileName:/nullableFloatingPointEqeq.kt
|
|||||||
if: CONST Boolean type=kotlin.Boolean value=true
|
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
|
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
|
$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
|
GET_VAR 'y: kotlin.Any? declared in <root>.testDI2' type=kotlin.Any? origin=null
|
||||||
BRANCH
|
BRANCH
|
||||||
if: CONST Boolean type=kotlin.Boolean value=true
|
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
|
EQEQ(arg0 = tmp2_safe_receiver, arg1 = null) -> null
|
||||||
else -> tmp2_safe_receiver.toDouble()
|
else -> tmp2_safe_receiver.toDouble()
|
||||||
}
|
}
|
||||||
}, arg1 = y /*as Double */)
|
}, arg1 = y /*as Double? */)
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user