[FIR] Promote numeric types during comparisons
Added support for comparing platform types. Extracted logic to convert operator expressions to OperatorExpressionGenerator.
This commit is contained in:
committed by
Mikhail Glukhikh
parent
1d9967013b
commit
d4cbfcb79e
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.fir.*
|
||||
import org.jetbrains.kotlin.fir.backend.generators.CallAndReferenceGenerator
|
||||
import org.jetbrains.kotlin.fir.backend.generators.ClassMemberGenerator
|
||||
import org.jetbrains.kotlin.fir.backend.generators.OperatorExpressionGenerator
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.expressions.impl.FirElseIfTrueCondition
|
||||
@@ -21,42 +22,36 @@ import org.jetbrains.kotlin.fir.resolve.firSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.isIteratorNext
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.IntegerLiteralTypeApproximationTransformer
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirIntegerOperator
|
||||
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor
|
||||
import org.jetbrains.kotlin.fir.visitors.transformSingle
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.builders.IrGeneratorContextInterface
|
||||
import org.jetbrains.kotlin.ir.builders.constFalse
|
||||
import org.jetbrains.kotlin.ir.builders.constTrue
|
||||
import org.jetbrains.kotlin.ir.builders.elseBranch
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrFail
|
||||
import org.jetbrains.kotlin.ir.types.makeNotNull
|
||||
import org.jetbrains.kotlin.ir.types.makeNullable
|
||||
import org.jetbrains.kotlin.ir.util.constructors
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import java.util.*
|
||||
import org.jetbrains.kotlin.psi.KtBinaryExpression
|
||||
import org.jetbrains.kotlin.psi.KtForExpression
|
||||
|
||||
class Fir2IrVisitor(
|
||||
private val converter: Fir2IrConverter,
|
||||
private val components: Fir2IrComponents,
|
||||
fakeOverrideMode: FakeOverrideMode
|
||||
) : Fir2IrComponents by components, FirDefaultVisitor<IrElement, Any?>(), IrGeneratorContextInterface {
|
||||
companion object {
|
||||
private val NEGATED_OPERATIONS: Set<FirOperation> = EnumSet.of(FirOperation.NOT_EQ, FirOperation.NOT_IDENTITY)
|
||||
|
||||
private val UNARY_OPERATIONS: Set<FirOperation> = EnumSet.of(FirOperation.EXCL)
|
||||
}
|
||||
|
||||
private val integerApproximator = IntegerLiteralTypeApproximationTransformer(session.firSymbolProvider, session.inferenceContext)
|
||||
|
||||
@@ -66,6 +61,8 @@ class Fir2IrVisitor(
|
||||
|
||||
private val memberGenerator = ClassMemberGenerator(components, this, conversionScope, callGenerator, fakeOverrideMode)
|
||||
|
||||
private val operatorGenerator = OperatorExpressionGenerator(components, this, callGenerator)
|
||||
|
||||
private fun FirTypeRef.toIrType(): IrType = with(typeConverter) { toIrType() }
|
||||
|
||||
private fun <T : IrDeclaration> applyParentFromStackTo(declaration: T): T = conversionScope.applyParentFromStackTo(declaration)
|
||||
@@ -611,106 +608,11 @@ class Fir2IrVisitor(
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitComparisonExpression(comparisonExpression: FirComparisonExpression, data: Any?): IrElement {
|
||||
return comparisonExpression.convertWithOffsets { startOffset, endOffset ->
|
||||
generateComparisonCall(startOffset, endOffset, comparisonExpression)
|
||||
}
|
||||
}
|
||||
override fun visitComparisonExpression(comparisonExpression: FirComparisonExpression, data: Any?): IrElement =
|
||||
operatorGenerator.convertComparisonExpression(comparisonExpression)
|
||||
|
||||
private fun generateComparisonCall(
|
||||
startOffset: Int, endOffset: Int,
|
||||
comparisonExpression: FirComparisonExpression
|
||||
): IrExpression {
|
||||
val operation = comparisonExpression.operation
|
||||
|
||||
fun fallbackToRealCall(): IrExpression {
|
||||
val (symbol, origin) = getSymbolAndOriginForComparison(operation, irBuiltIns.intType.classifierOrFail)
|
||||
return primitiveOp2(
|
||||
startOffset, endOffset,
|
||||
symbol!!,
|
||||
irBuiltIns.booleanType,
|
||||
origin,
|
||||
visitFunctionCall(comparisonExpression.compareToCall, null),
|
||||
IrConstImpl.int(startOffset, endOffset, irBuiltIns.intType, 0)
|
||||
)
|
||||
}
|
||||
|
||||
val comparisonInfo = comparisonExpression.inferPrimitiveNumericComparisonInfo() ?: return fallbackToRealCall()
|
||||
val comparisonType = comparisonInfo.comparisonType
|
||||
|
||||
// Currently inferPrimitiveNumericComparisonInfo returns null for different primitive values
|
||||
// TODO: Support different primitive types as well and fix inferPrimitiveNumericComparisonInfo
|
||||
require(comparisonInfo.leftPrimitiveType == comparisonInfo.rightPrimitiveType && comparisonInfo.leftType == comparisonInfo.rightType) {
|
||||
"Contract for inferPrimitiveNumericComparisonInfo is violated"
|
||||
}
|
||||
|
||||
val simpleType = when ((comparisonType.type as? ConeClassLikeType)?.lookupTag?.classId) {
|
||||
StandardClassIds.Long -> irBuiltIns.longType
|
||||
StandardClassIds.Int -> irBuiltIns.intType
|
||||
StandardClassIds.Float -> irBuiltIns.floatType
|
||||
StandardClassIds.Double -> irBuiltIns.doubleType
|
||||
StandardClassIds.Char -> irBuiltIns.charType
|
||||
else -> return fallbackToRealCall()
|
||||
}
|
||||
|
||||
val (symbol, origin) = getSymbolAndOriginForComparison(operation, simpleType.classifierOrFail)
|
||||
|
||||
return primitiveOp2(
|
||||
startOffset, endOffset, symbol!!, irBuiltIns.booleanType, origin,
|
||||
convertToIrExpression(comparisonExpression.left), convertToIrExpression(comparisonExpression.right)
|
||||
)
|
||||
}
|
||||
|
||||
private fun getSymbolAndOriginForComparison(
|
||||
operation: FirOperation,
|
||||
classifier: IrClassifierSymbol
|
||||
): Pair<IrSimpleFunctionSymbol?, IrStatementOriginImpl> {
|
||||
return when (operation) {
|
||||
FirOperation.LT -> irBuiltIns.lessFunByOperandType[classifier] to IrStatementOrigin.LT
|
||||
FirOperation.GT -> irBuiltIns.greaterFunByOperandType[classifier] to IrStatementOrigin.GT
|
||||
FirOperation.LT_EQ -> irBuiltIns.lessOrEqualFunByOperandType[classifier] to IrStatementOrigin.LTEQ
|
||||
FirOperation.GT_EQ -> irBuiltIns.greaterOrEqualFunByOperandType[classifier] to IrStatementOrigin.GTEQ
|
||||
else -> error("Unexpected comparison operation: $operation")
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateOperatorCall(
|
||||
startOffset: Int, endOffset: Int, operation: FirOperation, arguments: List<FirExpression>
|
||||
): IrExpression {
|
||||
val (type, symbol, origin) = when (operation) {
|
||||
FirOperation.EQ -> Triple(irBuiltIns.booleanType, irBuiltIns.eqeqSymbol, IrStatementOrigin.EQEQ)
|
||||
FirOperation.NOT_EQ -> Triple(irBuiltIns.booleanType, irBuiltIns.eqeqSymbol, IrStatementOrigin.EXCLEQ)
|
||||
FirOperation.IDENTITY -> Triple(irBuiltIns.booleanType, irBuiltIns.eqeqeqSymbol, IrStatementOrigin.EQEQEQ)
|
||||
FirOperation.NOT_IDENTITY -> Triple(irBuiltIns.booleanType, irBuiltIns.eqeqeqSymbol, IrStatementOrigin.EXCLEQEQ)
|
||||
FirOperation.EXCL -> Triple(irBuiltIns.booleanType, irBuiltIns.booleanNotSymbol, IrStatementOrigin.EXCL)
|
||||
FirOperation.LT, FirOperation.GT,
|
||||
FirOperation.LT_EQ, FirOperation.GT_EQ,
|
||||
FirOperation.OTHER, FirOperation.ASSIGN, FirOperation.PLUS_ASSIGN,
|
||||
FirOperation.MINUS_ASSIGN, FirOperation.TIMES_ASSIGN,
|
||||
FirOperation.DIV_ASSIGN, FirOperation.REM_ASSIGN,
|
||||
FirOperation.IS, FirOperation.NOT_IS,
|
||||
FirOperation.AS, FirOperation.SAFE_AS
|
||||
-> {
|
||||
TODO("Should not be here: incompatible operation in FirOperatorCall: $operation")
|
||||
}
|
||||
}
|
||||
val result = if (operation in UNARY_OPERATIONS) {
|
||||
primitiveOp1(startOffset, endOffset, symbol, type, origin, convertToIrExpression(arguments[0]))
|
||||
} else {
|
||||
primitiveOp2(
|
||||
startOffset, endOffset, symbol, type, origin,
|
||||
convertToIrExpression(arguments[0]), convertToIrExpression(arguments[1])
|
||||
)
|
||||
}
|
||||
if (operation !in NEGATED_OPERATIONS) return result
|
||||
return primitiveOp1(startOffset, endOffset, irBuiltIns.booleanNotSymbol, irBuiltIns.booleanType, origin, result)
|
||||
}
|
||||
|
||||
override fun visitOperatorCall(operatorCall: FirOperatorCall, data: Any?): IrElement {
|
||||
return operatorCall.convertWithOffsets { startOffset, endOffset ->
|
||||
generateOperatorCall(startOffset, endOffset, operatorCall.operation, operatorCall.arguments)
|
||||
}
|
||||
}
|
||||
override fun visitOperatorCall(operatorCall: FirOperatorCall, data: Any?): IrElement =
|
||||
operatorGenerator.convertOperatorCall(operatorCall)
|
||||
|
||||
override fun visitStringConcatenationCall(stringConcatenationCall: FirStringConcatenationCall, data: Any?): IrElement {
|
||||
return stringConcatenationCall.convertWithOffsets { startOffset, endOffset ->
|
||||
|
||||
@@ -9,15 +9,14 @@ import org.jetbrains.kotlin.fir.*
|
||||
import org.jetbrains.kotlin.fir.expressions.FirComparisonExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.arguments
|
||||
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
||||
|
||||
class PrimitiveConeNumericComparisonInfo(
|
||||
val comparisonType: ConeKotlinType,
|
||||
val leftPrimitiveType: ConeClassLikeType,
|
||||
val rightPrimitiveType: ConeClassLikeType,
|
||||
val leftType: ConeKotlinType,
|
||||
val rightType: ConeKotlinType
|
||||
val comparisonType: ConeClassLikeType,
|
||||
val leftType: ConeClassLikeType,
|
||||
val rightType: ConeClassLikeType
|
||||
)
|
||||
|
||||
val FirComparisonExpression.left: FirExpression
|
||||
@@ -26,25 +25,39 @@ val FirComparisonExpression.left: FirExpression
|
||||
val FirComparisonExpression.right: FirExpression
|
||||
get() = compareToCall.arguments.getOrNull(0) ?: error("There should be a first arg for ${compareToCall.render()}")
|
||||
|
||||
fun FirComparisonExpression.inferPrimitiveNumericComparisonInfo(): PrimitiveConeNumericComparisonInfo? {
|
||||
fun FirComparisonExpression.inferPrimitiveNumericComparisonInfo(): PrimitiveConeNumericComparisonInfo? =
|
||||
inferPrimitiveNumericComparisonInfo(left, right)
|
||||
|
||||
fun inferPrimitiveNumericComparisonInfo(left: FirExpression, right: FirExpression): PrimitiveConeNumericComparisonInfo? {
|
||||
val leftType = left.typeRef.coneTypeSafe<ConeKotlinType>() ?: return null
|
||||
val rightType = right.typeRef.coneTypeSafe<ConeKotlinType>() ?: return null
|
||||
val leftPrimitiveOrNullableType = leftType.getPrimitiveTypeOrSupertype() ?: return null
|
||||
val rightPrimitiveOrNullableType = rightType.getPrimitiveTypeOrSupertype() ?: return null
|
||||
val leftPrimitiveType = leftPrimitiveOrNullableType.withNullability(ConeNullability.NOT_NULL)
|
||||
val rightPrimitiveType = rightPrimitiveOrNullableType.withNullability(ConeNullability.NOT_NULL)
|
||||
val leastCommonType = leastCommonPrimitiveNumericType(leftPrimitiveOrNullableType, rightPrimitiveOrNullableType)
|
||||
|
||||
// TODO: Support different types with coercion
|
||||
if (leftPrimitiveType != rightPrimitiveType) return null
|
||||
val leastCommonType = rightPrimitiveType
|
||||
|
||||
return PrimitiveConeNumericComparisonInfo(
|
||||
leastCommonType,
|
||||
leftPrimitiveType, rightPrimitiveType,
|
||||
leftPrimitiveOrNullableType, rightPrimitiveOrNullableType
|
||||
)
|
||||
return PrimitiveConeNumericComparisonInfo(leastCommonType, leftPrimitiveOrNullableType, rightPrimitiveOrNullableType)
|
||||
}
|
||||
|
||||
private fun leastCommonPrimitiveNumericType(t1: ConeClassLikeType, t2: ConeClassLikeType): ConeClassLikeType {
|
||||
val pt1 = t1.promoteIntegerTypeToIntIfRequired()
|
||||
val pt2 = t2.promoteIntegerTypeToIntIfRequired()
|
||||
|
||||
return when {
|
||||
pt1.isDouble() || pt2.isDouble() -> PrimitiveTypes.Double
|
||||
pt1.isFloat() || pt2.isFloat() -> PrimitiveTypes.Float
|
||||
pt1.isLong() || pt2.isLong() -> PrimitiveTypes.Long
|
||||
pt1.isInt() || pt2.isInt() -> PrimitiveTypes.Int
|
||||
else -> throw AssertionError("Unexpected types: t1=$t1, t2=$t2")
|
||||
}
|
||||
}
|
||||
|
||||
private fun ConeClassLikeType.promoteIntegerTypeToIntIfRequired(): ConeClassLikeType =
|
||||
when (lookupTag.classId) {
|
||||
StandardClassIds.Byte, StandardClassIds.Short -> PrimitiveTypes.Int
|
||||
StandardClassIds.Long, StandardClassIds.Int, StandardClassIds.Float, StandardClassIds.Double, StandardClassIds.Char -> this
|
||||
else -> throw AssertionError("Primitive number type expected: $this")
|
||||
}
|
||||
|
||||
private fun ConeKotlinType.getPrimitiveTypeOrSupertype(): ConeClassLikeType? =
|
||||
when {
|
||||
this is ConeTypeParameterType ->
|
||||
@@ -53,6 +66,8 @@ private fun ConeKotlinType.getPrimitiveTypeOrSupertype(): ConeClassLikeType? =
|
||||
}
|
||||
this is ConeClassLikeType && isPrimitiveNumberType() ->
|
||||
this
|
||||
this is ConeFlexibleType ->
|
||||
this.lowerBound.getPrimitiveTypeOrSupertype()
|
||||
else ->
|
||||
null
|
||||
}
|
||||
|
||||
+37
-28
@@ -33,9 +33,9 @@ import org.jetbrains.kotlin.ir.symbols.*
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrNull
|
||||
import org.jetbrains.kotlin.ir.types.makeNotNull
|
||||
import org.jetbrains.kotlin.ir.types.makeNullable
|
||||
import org.jetbrains.kotlin.psi.KtPropertyDelegate
|
||||
import org.jetbrains.kotlin.psi2ir.generators.hasNoSideEffects
|
||||
import java.lang.IllegalArgumentException
|
||||
|
||||
internal class CallAndReferenceGenerator(
|
||||
private val components: Fir2IrComponents,
|
||||
@@ -110,37 +110,46 @@ internal class CallAndReferenceGenerator(
|
||||
return convertToUnsafeIrCall(qualifiedAccess, typeRef, explicitReceiverExpression)
|
||||
}
|
||||
return qualifiedAccess.convertWithOffsets { startOffset, endOffset ->
|
||||
val type = typeRef.toIrType()
|
||||
val callableSymbol = (qualifiedAccess.calleeReference as? FirResolvedNamedReference)?.resolvedSymbol as? FirCallableSymbol<*>
|
||||
val typeShouldBeNotNull = callableSymbol?.fir?.returnTypeRef?.coneTypeSafe<ConeKotlinType>()?.isNullable == false
|
||||
val unsafeIrCall = convertToUnsafeIrCall(
|
||||
qualifiedAccess, typeRef, explicitReceiverExpression, makeNotNull = typeShouldBeNotNull
|
||||
val unsafeIrCall =
|
||||
convertToUnsafeIrCall(qualifiedAccess, typeRef, explicitReceiverExpression, makeNotNull = typeShouldBeNotNull)
|
||||
|
||||
convertToSafeIrCall(
|
||||
unsafeIrCall,
|
||||
explicitReceiverExpression!!,
|
||||
isDispatch = explicitReceiver == qualifiedAccess.dispatchReceiver
|
||||
)
|
||||
IrBlockImpl(startOffset, endOffset, type, IrStatementOrigin.SAFE_CALL).apply {
|
||||
val receiverVariable = declarationStorage.declareTemporaryVariable(explicitReceiverExpression!!).apply {
|
||||
parent = conversionScope.parentFromStack()
|
||||
}
|
||||
statements += receiverVariable
|
||||
statements += IrWhenImpl(startOffset, endOffset, type).apply {
|
||||
val variableSymbol = symbolTable.referenceValue(receiverVariable.descriptor)
|
||||
val condition = IrCallImpl(
|
||||
startOffset, endOffset, irBuiltIns.booleanType, irBuiltIns.eqeqSymbol, origin = IrStatementOrigin.EQEQ
|
||||
).apply {
|
||||
putValueArgument(0, IrGetValueImpl(startOffset, endOffset, variableSymbol))
|
||||
putValueArgument(1, IrConstImpl.constNull(startOffset, endOffset, irBuiltIns.nothingNType))
|
||||
}
|
||||
branches += IrBranchImpl(
|
||||
condition, IrConstImpl.constNull(startOffset, endOffset, irBuiltIns.nothingNType)
|
||||
)
|
||||
val newReceiver = IrGetValueImpl(startOffset, endOffset, variableSymbol)
|
||||
val replacedCall = unsafeIrCall.replaceReceiver(
|
||||
newReceiver, isDispatch = explicitReceiver == qualifiedAccess.dispatchReceiver
|
||||
)
|
||||
branches += IrElseBranchImpl(
|
||||
IrConstImpl.boolean(startOffset, endOffset, irBuiltIns.booleanType, true),
|
||||
replacedCall
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun convertToSafeIrCall(call: IrExpression, explicitReceiverExpression: IrExpression, isDispatch: Boolean): IrExpression {
|
||||
val startOffset = call.startOffset
|
||||
val endOffset = call.endOffset
|
||||
val receiverVariable = declarationStorage.declareTemporaryVariable(explicitReceiverExpression, "safe_receiver").apply {
|
||||
parent = conversionScope.parentFromStack()
|
||||
}
|
||||
val variableSymbol = symbolTable.referenceValue(receiverVariable.descriptor)
|
||||
|
||||
val resultType = call.type.makeNullable()
|
||||
return IrBlockImpl(startOffset, endOffset, resultType, IrStatementOrigin.SAFE_CALL).apply {
|
||||
statements += receiverVariable
|
||||
statements += IrWhenImpl(startOffset, endOffset, resultType).apply {
|
||||
val condition = IrCallImpl(
|
||||
startOffset, endOffset, irBuiltIns.booleanType, irBuiltIns.eqeqSymbol, origin = IrStatementOrigin.EQEQ
|
||||
).apply {
|
||||
putValueArgument(0, IrGetValueImpl(startOffset, endOffset, variableSymbol))
|
||||
putValueArgument(1, IrConstImpl.constNull(startOffset, endOffset, irBuiltIns.nothingNType))
|
||||
}
|
||||
branches += IrBranchImpl(
|
||||
condition, IrConstImpl.constNull(startOffset, endOffset, irBuiltIns.nothingNType)
|
||||
)
|
||||
val newReceiver = IrGetValueImpl(startOffset, endOffset, variableSymbol)
|
||||
val replacedCall = call.replaceReceiver(newReceiver, isDispatch)
|
||||
branches += IrElseBranchImpl(
|
||||
IrConstImpl.boolean(startOffset, endOffset, irBuiltIns.booleanType, true),
|
||||
replacedCall
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
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.isNullable
|
||||
import org.jetbrains.kotlin.ir.builders.primitiveOp1
|
||||
import org.jetbrains.kotlin.ir.builders.primitiveOp2
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
||||
import org.jetbrains.kotlin.ir.expressions.IrStatementOriginImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrFail
|
||||
import org.jetbrains.kotlin.ir.util.getSimpleFunction
|
||||
import java.util.*
|
||||
|
||||
internal class OperatorExpressionGenerator(
|
||||
private val components: Fir2IrComponents,
|
||||
private val visitor: Fir2IrVisitor,
|
||||
private val callGenerator: CallAndReferenceGenerator
|
||||
) : Fir2IrComponents by components {
|
||||
|
||||
companion object {
|
||||
private val NEGATED_OPERATIONS: Set<FirOperation> = EnumSet.of(FirOperation.NOT_EQ, FirOperation.NOT_IDENTITY)
|
||||
|
||||
private val UNARY_OPERATIONS: Set<FirOperation> = EnumSet.of(FirOperation.EXCL)
|
||||
}
|
||||
|
||||
fun convertComparisonExpression(comparisonExpression: FirComparisonExpression): IrExpression {
|
||||
return comparisonExpression.convertWithOffsets { startOffset, endOffset ->
|
||||
generateComparisonCall(startOffset, endOffset, comparisonExpression)
|
||||
}
|
||||
}
|
||||
|
||||
fun convertOperatorCall(operatorCall: FirOperatorCall): IrExpression {
|
||||
return operatorCall.convertWithOffsets { startOffset, endOffset ->
|
||||
generateOperatorCall(startOffset, endOffset, operatorCall.operation, operatorCall.arguments)
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateComparisonCall(
|
||||
startOffset: Int, endOffset: Int,
|
||||
comparisonExpression: FirComparisonExpression
|
||||
): IrExpression {
|
||||
val operation = comparisonExpression.operation
|
||||
|
||||
fun fallbackToRealCall(): IrExpression {
|
||||
val (symbol, origin) = getSymbolAndOriginForComparison(operation, irBuiltIns.intType.classifierOrFail)
|
||||
return primitiveOp2(
|
||||
startOffset, endOffset,
|
||||
symbol!!,
|
||||
irBuiltIns.booleanType,
|
||||
origin,
|
||||
comparisonExpression.compareToCall.accept(visitor, null) as IrExpression,
|
||||
IrConstImpl.int(startOffset, endOffset, irBuiltIns.intType, 0)
|
||||
)
|
||||
}
|
||||
|
||||
val comparisonInfo = comparisonExpression.inferPrimitiveNumericComparisonInfo() ?: return fallbackToRealCall()
|
||||
val comparisonType = comparisonInfo.comparisonType
|
||||
|
||||
val comparisonIrType = typeConverter.classIdToTypeMap[comparisonType.lookupTag.classId] ?: return fallbackToRealCall()
|
||||
val (symbol, origin) = getSymbolAndOriginForComparison(operation, comparisonIrType.classifierOrFail)
|
||||
|
||||
return primitiveOp2(
|
||||
startOffset, endOffset, symbol!!, irBuiltIns.booleanType, origin,
|
||||
visitor.convertToIrExpression(comparisonExpression.left).asComparisonOperand(comparisonInfo.leftType, comparisonType),
|
||||
visitor.convertToIrExpression(comparisonExpression.right).asComparisonOperand(comparisonInfo.rightType, comparisonType),
|
||||
)
|
||||
}
|
||||
|
||||
private fun getSymbolAndOriginForComparison(
|
||||
operation: FirOperation,
|
||||
classifier: IrClassifierSymbol
|
||||
): Pair<IrSimpleFunctionSymbol?, IrStatementOriginImpl> {
|
||||
return when (operation) {
|
||||
FirOperation.LT -> irBuiltIns.lessFunByOperandType[classifier] to IrStatementOrigin.LT
|
||||
FirOperation.GT -> irBuiltIns.greaterFunByOperandType[classifier] to IrStatementOrigin.GT
|
||||
FirOperation.LT_EQ -> irBuiltIns.lessOrEqualFunByOperandType[classifier] to IrStatementOrigin.LTEQ
|
||||
FirOperation.GT_EQ -> irBuiltIns.greaterOrEqualFunByOperandType[classifier] to IrStatementOrigin.GTEQ
|
||||
else -> error("Unexpected comparison operation: $operation")
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateOperatorCall(
|
||||
startOffset: Int, endOffset: Int, operation: FirOperation, arguments: List<FirExpression>
|
||||
): IrExpression {
|
||||
val (type, symbol, origin) = when (operation) {
|
||||
FirOperation.EQ -> Triple(irBuiltIns.booleanType, irBuiltIns.eqeqSymbol, IrStatementOrigin.EQEQ)
|
||||
FirOperation.NOT_EQ -> Triple(irBuiltIns.booleanType, irBuiltIns.eqeqSymbol, IrStatementOrigin.EXCLEQ)
|
||||
FirOperation.IDENTITY -> Triple(irBuiltIns.booleanType, irBuiltIns.eqeqeqSymbol, IrStatementOrigin.EQEQEQ)
|
||||
FirOperation.NOT_IDENTITY -> Triple(irBuiltIns.booleanType, irBuiltIns.eqeqeqSymbol, IrStatementOrigin.EXCLEQEQ)
|
||||
FirOperation.EXCL -> Triple(irBuiltIns.booleanType, irBuiltIns.booleanNotSymbol, IrStatementOrigin.EXCL)
|
||||
FirOperation.LT, FirOperation.GT,
|
||||
FirOperation.LT_EQ, FirOperation.GT_EQ,
|
||||
FirOperation.OTHER, FirOperation.ASSIGN, FirOperation.PLUS_ASSIGN,
|
||||
FirOperation.MINUS_ASSIGN, FirOperation.TIMES_ASSIGN,
|
||||
FirOperation.DIV_ASSIGN, FirOperation.REM_ASSIGN,
|
||||
FirOperation.IS, FirOperation.NOT_IS,
|
||||
FirOperation.AS, FirOperation.SAFE_AS
|
||||
-> {
|
||||
TODO("Should not be here: incompatible operation in FirOperatorCall: $operation")
|
||||
}
|
||||
}
|
||||
val result = if (operation in UNARY_OPERATIONS) {
|
||||
primitiveOp1(startOffset, endOffset, symbol, type, origin, visitor.convertToIrExpression(arguments[0]))
|
||||
} else {
|
||||
val comparisonInfo = inferPrimitiveNumericComparisonInfo(arguments[0], arguments[1])
|
||||
val comparisonType = comparisonInfo?.comparisonType
|
||||
primitiveOp2(
|
||||
startOffset, endOffset, symbol, type, origin,
|
||||
visitor.convertToIrExpression(arguments[0]).asComparisonOperand(comparisonInfo?.leftType, comparisonType),
|
||||
visitor.convertToIrExpression(arguments[1]).asComparisonOperand(comparisonInfo?.rightType, comparisonType)
|
||||
)
|
||||
}
|
||||
if (operation !in NEGATED_OPERATIONS) return result
|
||||
return primitiveOp1(startOffset, endOffset, irBuiltIns.booleanNotSymbol, irBuiltIns.booleanType, origin, result)
|
||||
}
|
||||
|
||||
private fun IrExpression.asComparisonOperand(
|
||||
operandType: ConeClassLikeType?,
|
||||
targetType: ConeClassLikeType?
|
||||
): IrExpression {
|
||||
if (targetType == null) return this
|
||||
if (operandType == null) throw AssertionError("operandType should be non-null")
|
||||
|
||||
val operandClassId = operandType.lookupTag.classId
|
||||
val targetClassId = targetType.lookupTag.classId
|
||||
if (operandClassId == targetClassId) return this
|
||||
val conversionFunction =
|
||||
typeConverter.classIdToSymbolMap[operandClassId]?.getSimpleFunction("to${targetType.lookupTag.classId.shortClassName.asString()}")
|
||||
?: throw AssertionError("No conversion function for $operandType ~> $targetType")
|
||||
|
||||
val dispatchReceiver = this@asComparisonOperand
|
||||
val unsafeIrCall = IrCallImpl(startOffset, endOffset, conversionFunction.owner.returnType, conversionFunction).also {
|
||||
it.dispatchReceiver = dispatchReceiver
|
||||
}
|
||||
return if (operandType.isNullable) {
|
||||
callGenerator.convertToSafeIrCall(unsafeIrCall, dispatchReceiver, isDispatch = true)
|
||||
} else {
|
||||
unsafeIrCall
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
//FILE: Holder.java
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
//FILE: JavaClass.java
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// !LANGUAGE: +ProperIeee754Comparisons +NewInference
|
||||
|
||||
fun box(): String {
|
||||
|
||||
-1
@@ -1,5 +1,4 @@
|
||||
// !LANGUAGE: +ProperIeee754Comparisons
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
fun ltDI(x: Any, y: Any) =
|
||||
x is Double && y is Int && x < y
|
||||
|
||||
|
||||
+6
-4
@@ -160,8 +160,9 @@ FILE fqName:<root> fileName:/floatingPointEqeq.kt
|
||||
if: CONST Boolean type=kotlin.Boolean value=true
|
||||
then: CONST Boolean type=kotlin.Boolean value=false
|
||||
then: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
|
||||
arg0: TYPE_OP type=kotlin.Float origin=IMPLICIT_CAST typeOperand=kotlin.Float
|
||||
GET_VAR 'x: kotlin.Any declared in <root>.testFD' type=kotlin.Any origin=null
|
||||
arg0: CALL 'public open fun toDouble (): kotlin.Double declared in kotlin.Float' type=kotlin.Double origin=null
|
||||
$this: TYPE_OP type=kotlin.Float origin=IMPLICIT_CAST typeOperand=kotlin.Float
|
||||
GET_VAR 'x: kotlin.Any declared in <root>.testFD' type=kotlin.Any origin=null
|
||||
arg1: TYPE_OP type=kotlin.Double origin=IMPLICIT_CAST typeOperand=kotlin.Double
|
||||
GET_VAR 'y: kotlin.Any declared in <root>.testFD' type=kotlin.Any origin=null
|
||||
BRANCH
|
||||
@@ -186,8 +187,9 @@ FILE fqName:<root> fileName:/floatingPointEqeq.kt
|
||||
then: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
|
||||
arg0: TYPE_OP type=kotlin.Double origin=IMPLICIT_CAST typeOperand=kotlin.Double
|
||||
GET_VAR 'x: kotlin.Any declared in <root>.testDF' type=kotlin.Any origin=null
|
||||
arg1: TYPE_OP type=kotlin.Float origin=IMPLICIT_CAST typeOperand=kotlin.Float
|
||||
GET_VAR 'y: kotlin.Any declared in <root>.testDF' type=kotlin.Any origin=null
|
||||
arg1: CALL 'public open fun toDouble (): kotlin.Double declared in kotlin.Float' type=kotlin.Double origin=null
|
||||
$this: TYPE_OP type=kotlin.Float origin=IMPLICIT_CAST typeOperand=kotlin.Float
|
||||
GET_VAR 'y: kotlin.Any declared in <root>.testDF' type=kotlin.Any origin=null
|
||||
BRANCH
|
||||
if: CONST Boolean type=kotlin.Boolean value=true
|
||||
then: CONST Boolean type=kotlin.Boolean value=false
|
||||
|
||||
Vendored
+6
-4
@@ -173,8 +173,9 @@ FILE fqName:<root> fileName:/floatingPointExcleq.kt
|
||||
then: CONST Boolean type=kotlin.Boolean value=false
|
||||
then: CALL 'public final fun not (): kotlin.Boolean [operator] declared in kotlin.Boolean' type=kotlin.Boolean origin=EXCLEQ
|
||||
$this: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EXCLEQ
|
||||
arg0: TYPE_OP type=kotlin.Float origin=IMPLICIT_CAST typeOperand=kotlin.Float
|
||||
GET_VAR 'x: kotlin.Any declared in <root>.testFD' type=kotlin.Any origin=null
|
||||
arg0: CALL 'public open fun toDouble (): kotlin.Double declared in kotlin.Float' type=kotlin.Double origin=null
|
||||
$this: TYPE_OP type=kotlin.Float origin=IMPLICIT_CAST typeOperand=kotlin.Float
|
||||
GET_VAR 'x: kotlin.Any declared in <root>.testFD' type=kotlin.Any origin=null
|
||||
arg1: TYPE_OP type=kotlin.Double origin=IMPLICIT_CAST typeOperand=kotlin.Double
|
||||
GET_VAR 'y: kotlin.Any declared in <root>.testFD' type=kotlin.Any origin=null
|
||||
BRANCH
|
||||
@@ -200,8 +201,9 @@ FILE fqName:<root> fileName:/floatingPointExcleq.kt
|
||||
$this: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EXCLEQ
|
||||
arg0: TYPE_OP type=kotlin.Double origin=IMPLICIT_CAST typeOperand=kotlin.Double
|
||||
GET_VAR 'x: kotlin.Any declared in <root>.testDF' type=kotlin.Any origin=null
|
||||
arg1: TYPE_OP type=kotlin.Float origin=IMPLICIT_CAST typeOperand=kotlin.Float
|
||||
GET_VAR 'y: kotlin.Any declared in <root>.testDF' type=kotlin.Any origin=null
|
||||
arg1: CALL 'public open fun toDouble (): kotlin.Double declared in kotlin.Float' type=kotlin.Double origin=null
|
||||
$this: TYPE_OP type=kotlin.Float origin=IMPLICIT_CAST typeOperand=kotlin.Float
|
||||
GET_VAR 'y: kotlin.Any declared in <root>.testDF' type=kotlin.Any origin=null
|
||||
BRANCH
|
||||
if: CONST Boolean type=kotlin.Boolean value=true
|
||||
then: CONST Boolean type=kotlin.Boolean value=false
|
||||
|
||||
-149
@@ -1,149 +0,0 @@
|
||||
FILE fqName:<root> fileName:/floatingPointLess.kt
|
||||
FUN name:test1d visibility:public modality:FINAL <> (x:kotlin.Double, y:kotlin.Double) returnType:kotlin.Boolean
|
||||
VALUE_PARAMETER name:x index:0 type:kotlin.Double
|
||||
VALUE_PARAMETER name:y index:1 type:kotlin.Double
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun test1d (x: kotlin.Double, y: kotlin.Double): kotlin.Boolean declared in <root>'
|
||||
CALL 'public final fun less (arg0: kotlin.Double, arg1: kotlin.Double): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=LT
|
||||
arg0: GET_VAR 'x: kotlin.Double declared in <root>.test1d' type=kotlin.Double origin=null
|
||||
arg1: GET_VAR 'y: kotlin.Double declared in <root>.test1d' type=kotlin.Double origin=null
|
||||
FUN name:test2d visibility:public modality:FINAL <> (x:kotlin.Double, y:kotlin.Any) returnType:kotlin.Boolean
|
||||
VALUE_PARAMETER name:x index:0 type:kotlin.Double
|
||||
VALUE_PARAMETER name:y index:1 type:kotlin.Any
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun test2d (x: kotlin.Double, y: kotlin.Any): kotlin.Boolean declared in <root>'
|
||||
WHEN type=kotlin.Boolean origin=ANDAND
|
||||
BRANCH
|
||||
if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=kotlin.Double
|
||||
GET_VAR 'y: kotlin.Any declared in <root>.test2d' type=kotlin.Any origin=null
|
||||
then: CALL 'public final fun less (arg0: kotlin.Double, arg1: kotlin.Double): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=LT
|
||||
arg0: GET_VAR 'x: kotlin.Double declared in <root>.test2d' type=kotlin.Double origin=null
|
||||
arg1: TYPE_OP type=kotlin.Double origin=IMPLICIT_CAST typeOperand=kotlin.Double
|
||||
GET_VAR 'y: kotlin.Any declared in <root>.test2d' type=kotlin.Any origin=null
|
||||
BRANCH
|
||||
if: CONST Boolean type=kotlin.Boolean value=true
|
||||
then: CONST Boolean type=kotlin.Boolean value=false
|
||||
FUN name:test3d visibility:public modality:FINAL <> (x:kotlin.Any, y:kotlin.Any) returnType:kotlin.Boolean
|
||||
VALUE_PARAMETER name:x index:0 type:kotlin.Any
|
||||
VALUE_PARAMETER name:y index:1 type:kotlin.Any
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun test3d (x: kotlin.Any, y: kotlin.Any): kotlin.Boolean declared in <root>'
|
||||
WHEN type=kotlin.Boolean origin=ANDAND
|
||||
BRANCH
|
||||
if: WHEN type=kotlin.Boolean origin=ANDAND
|
||||
BRANCH
|
||||
if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=kotlin.Double
|
||||
GET_VAR 'x: kotlin.Any declared in <root>.test3d' type=kotlin.Any origin=null
|
||||
then: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=kotlin.Double
|
||||
GET_VAR 'y: kotlin.Any declared in <root>.test3d' type=kotlin.Any origin=null
|
||||
BRANCH
|
||||
if: CONST Boolean type=kotlin.Boolean value=true
|
||||
then: CONST Boolean type=kotlin.Boolean value=false
|
||||
then: CALL 'public final fun less (arg0: kotlin.Double, arg1: kotlin.Double): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=LT
|
||||
arg0: TYPE_OP type=kotlin.Double origin=IMPLICIT_CAST typeOperand=kotlin.Double
|
||||
GET_VAR 'x: kotlin.Any declared in <root>.test3d' type=kotlin.Any origin=null
|
||||
arg1: TYPE_OP type=kotlin.Double origin=IMPLICIT_CAST typeOperand=kotlin.Double
|
||||
GET_VAR 'y: kotlin.Any declared in <root>.test3d' type=kotlin.Any origin=null
|
||||
BRANCH
|
||||
if: CONST Boolean type=kotlin.Boolean value=true
|
||||
then: CONST Boolean type=kotlin.Boolean value=false
|
||||
FUN name:test1f visibility:public modality:FINAL <> (x:kotlin.Float, y:kotlin.Float) returnType:kotlin.Boolean
|
||||
VALUE_PARAMETER name:x index:0 type:kotlin.Float
|
||||
VALUE_PARAMETER name:y index:1 type:kotlin.Float
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun test1f (x: kotlin.Float, y: kotlin.Float): kotlin.Boolean declared in <root>'
|
||||
CALL 'public final fun less (arg0: kotlin.Float, arg1: kotlin.Float): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=LT
|
||||
arg0: GET_VAR 'x: kotlin.Float declared in <root>.test1f' type=kotlin.Float origin=null
|
||||
arg1: GET_VAR 'y: kotlin.Float declared in <root>.test1f' type=kotlin.Float origin=null
|
||||
FUN name:test2f visibility:public modality:FINAL <> (x:kotlin.Float, y:kotlin.Any) returnType:kotlin.Boolean
|
||||
VALUE_PARAMETER name:x index:0 type:kotlin.Float
|
||||
VALUE_PARAMETER name:y index:1 type:kotlin.Any
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun test2f (x: kotlin.Float, y: kotlin.Any): kotlin.Boolean declared in <root>'
|
||||
WHEN type=kotlin.Boolean origin=ANDAND
|
||||
BRANCH
|
||||
if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=kotlin.Float
|
||||
GET_VAR 'y: kotlin.Any declared in <root>.test2f' type=kotlin.Any origin=null
|
||||
then: CALL 'public final fun less (arg0: kotlin.Float, arg1: kotlin.Float): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=LT
|
||||
arg0: GET_VAR 'x: kotlin.Float declared in <root>.test2f' type=kotlin.Float origin=null
|
||||
arg1: TYPE_OP type=kotlin.Float origin=IMPLICIT_CAST typeOperand=kotlin.Float
|
||||
GET_VAR 'y: kotlin.Any declared in <root>.test2f' type=kotlin.Any origin=null
|
||||
BRANCH
|
||||
if: CONST Boolean type=kotlin.Boolean value=true
|
||||
then: CONST Boolean type=kotlin.Boolean value=false
|
||||
FUN name:test3f visibility:public modality:FINAL <> (x:kotlin.Any, y:kotlin.Any) returnType:kotlin.Boolean
|
||||
VALUE_PARAMETER name:x index:0 type:kotlin.Any
|
||||
VALUE_PARAMETER name:y index:1 type:kotlin.Any
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun test3f (x: kotlin.Any, y: kotlin.Any): kotlin.Boolean declared in <root>'
|
||||
WHEN type=kotlin.Boolean origin=ANDAND
|
||||
BRANCH
|
||||
if: WHEN type=kotlin.Boolean origin=ANDAND
|
||||
BRANCH
|
||||
if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=kotlin.Float
|
||||
GET_VAR 'x: kotlin.Any declared in <root>.test3f' type=kotlin.Any origin=null
|
||||
then: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=kotlin.Float
|
||||
GET_VAR 'y: kotlin.Any declared in <root>.test3f' type=kotlin.Any origin=null
|
||||
BRANCH
|
||||
if: CONST Boolean type=kotlin.Boolean value=true
|
||||
then: CONST Boolean type=kotlin.Boolean value=false
|
||||
then: CALL 'public final fun less (arg0: kotlin.Float, arg1: kotlin.Float): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=LT
|
||||
arg0: TYPE_OP type=kotlin.Float origin=IMPLICIT_CAST typeOperand=kotlin.Float
|
||||
GET_VAR 'x: kotlin.Any declared in <root>.test3f' type=kotlin.Any origin=null
|
||||
arg1: TYPE_OP type=kotlin.Float origin=IMPLICIT_CAST typeOperand=kotlin.Float
|
||||
GET_VAR 'y: kotlin.Any declared in <root>.test3f' type=kotlin.Any origin=null
|
||||
BRANCH
|
||||
if: CONST Boolean type=kotlin.Boolean value=true
|
||||
then: CONST Boolean type=kotlin.Boolean value=false
|
||||
FUN name:testFD visibility:public modality:FINAL <> (x:kotlin.Any, y:kotlin.Any) returnType:kotlin.Boolean
|
||||
VALUE_PARAMETER name:x index:0 type:kotlin.Any
|
||||
VALUE_PARAMETER name:y index:1 type:kotlin.Any
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun testFD (x: kotlin.Any, y: kotlin.Any): kotlin.Boolean declared in <root>'
|
||||
WHEN type=kotlin.Boolean origin=ANDAND
|
||||
BRANCH
|
||||
if: WHEN type=kotlin.Boolean origin=ANDAND
|
||||
BRANCH
|
||||
if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=kotlin.Float
|
||||
GET_VAR 'x: kotlin.Any declared in <root>.testFD' type=kotlin.Any origin=null
|
||||
then: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=kotlin.Double
|
||||
GET_VAR 'y: kotlin.Any declared in <root>.testFD' type=kotlin.Any origin=null
|
||||
BRANCH
|
||||
if: CONST Boolean type=kotlin.Boolean value=true
|
||||
then: CONST Boolean type=kotlin.Boolean value=false
|
||||
then: CALL 'public final fun less (arg0: kotlin.Int, arg1: kotlin.Int): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=LT
|
||||
arg0: CALL 'public final fun compareTo (other: kotlin.Double): kotlin.Int [operator] declared in kotlin.Float' type=kotlin.Int origin=null
|
||||
$this: TYPE_OP type=kotlin.Float origin=IMPLICIT_CAST typeOperand=kotlin.Float
|
||||
GET_VAR 'x: kotlin.Any declared in <root>.testFD' type=kotlin.Any origin=null
|
||||
other: TYPE_OP type=kotlin.Double origin=IMPLICIT_CAST typeOperand=kotlin.Double
|
||||
GET_VAR 'y: kotlin.Any declared in <root>.testFD' type=kotlin.Any origin=null
|
||||
arg1: CONST Int type=kotlin.Int value=0
|
||||
BRANCH
|
||||
if: CONST Boolean type=kotlin.Boolean value=true
|
||||
then: CONST Boolean type=kotlin.Boolean value=false
|
||||
FUN name:testDF visibility:public modality:FINAL <> (x:kotlin.Any, y:kotlin.Any) returnType:kotlin.Boolean
|
||||
VALUE_PARAMETER name:x index:0 type:kotlin.Any
|
||||
VALUE_PARAMETER name:y index:1 type:kotlin.Any
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun testDF (x: kotlin.Any, y: kotlin.Any): kotlin.Boolean declared in <root>'
|
||||
WHEN type=kotlin.Boolean origin=ANDAND
|
||||
BRANCH
|
||||
if: WHEN type=kotlin.Boolean origin=ANDAND
|
||||
BRANCH
|
||||
if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=kotlin.Double
|
||||
GET_VAR 'x: kotlin.Any declared in <root>.testDF' type=kotlin.Any origin=null
|
||||
then: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=kotlin.Float
|
||||
GET_VAR 'y: kotlin.Any declared in <root>.testDF' type=kotlin.Any origin=null
|
||||
BRANCH
|
||||
if: CONST Boolean type=kotlin.Boolean value=true
|
||||
then: CONST Boolean type=kotlin.Boolean value=false
|
||||
then: CALL 'public final fun less (arg0: kotlin.Int, arg1: kotlin.Int): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=LT
|
||||
arg0: CALL 'public final fun compareTo (other: kotlin.Float): kotlin.Int [operator] declared in kotlin.Double' type=kotlin.Int origin=null
|
||||
$this: TYPE_OP type=kotlin.Double origin=IMPLICIT_CAST typeOperand=kotlin.Double
|
||||
GET_VAR 'x: kotlin.Any declared in <root>.testDF' type=kotlin.Any origin=null
|
||||
other: TYPE_OP type=kotlin.Float origin=IMPLICIT_CAST typeOperand=kotlin.Float
|
||||
GET_VAR 'y: kotlin.Any declared in <root>.testDF' type=kotlin.Any origin=null
|
||||
arg1: CONST Int type=kotlin.Int value=0
|
||||
BRANCH
|
||||
if: CONST Boolean type=kotlin.Boolean value=true
|
||||
then: CONST Boolean type=kotlin.Boolean value=false
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
fun test1d(x: Double, y: Double) = x < y
|
||||
fun test2d(x: Double, y: Any) = y is Double && x < y
|
||||
fun test3d(x: Any, y: Any) = x is Double && y is Double && x < y
|
||||
|
||||
Vendored
+3
-4
@@ -8,12 +8,11 @@ FILE fqName:<root> fileName:/nullableAnyAsIntToDouble.kt
|
||||
BRANCH
|
||||
if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=kotlin.Int
|
||||
GET_VAR 'x: kotlin.Any? declared in <root>.test' type=kotlin.Any? origin=null
|
||||
then: CALL 'public final fun less (arg0: kotlin.Int, arg1: kotlin.Int): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=LT
|
||||
arg0: CALL 'public final fun compareTo (other: kotlin.Double): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=null
|
||||
then: CALL 'public final fun less (arg0: kotlin.Double, arg1: kotlin.Double): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=LT
|
||||
arg0: CALL 'public open fun toDouble (): kotlin.Double declared in kotlin.Int' type=kotlin.Double origin=null
|
||||
$this: TYPE_OP type=kotlin.Int origin=IMPLICIT_CAST typeOperand=kotlin.Int
|
||||
GET_VAR 'x: kotlin.Any? declared in <root>.test' type=kotlin.Any? origin=null
|
||||
other: GET_VAR 'y: kotlin.Double declared in <root>.test' type=kotlin.Double origin=null
|
||||
arg1: CONST Int type=kotlin.Int value=0
|
||||
arg1: GET_VAR 'y: kotlin.Double declared in <root>.test' type=kotlin.Double origin=null
|
||||
BRANCH
|
||||
if: CONST Boolean type=kotlin.Boolean value=true
|
||||
then: CONST Boolean type=kotlin.Boolean value=false
|
||||
|
||||
Vendored
+42
-6
@@ -18,8 +18,20 @@ FILE fqName:<root> fileName:/nullableFloatingPointEqeq.kt
|
||||
GET_VAR 'y: kotlin.Any? declared in <root>.testDF' type=kotlin.Any? origin=null
|
||||
then: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
|
||||
arg0: GET_VAR 'x: kotlin.Double? declared in <root>.testDF' type=kotlin.Double? origin=null
|
||||
arg1: TYPE_OP type=kotlin.Float? origin=IMPLICIT_CAST typeOperand=kotlin.Float?
|
||||
GET_VAR 'y: kotlin.Any? declared in <root>.testDF' type=kotlin.Any? origin=null
|
||||
arg1: BLOCK type=kotlin.Double? origin=SAFE_CALL
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:kotlin.Float? [val]
|
||||
TYPE_OP type=kotlin.Float? origin=IMPLICIT_CAST typeOperand=kotlin.Float?
|
||||
GET_VAR 'y: kotlin.Any? declared in <root>.testDF' type=kotlin.Any? origin=null
|
||||
WHEN type=kotlin.Double? origin=null
|
||||
BRANCH
|
||||
if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
|
||||
arg0: GET_VAR 'val tmp_0: kotlin.Float? [val] declared in <root>.testDF' type=kotlin.Float? origin=null
|
||||
arg1: CONST Null type=kotlin.Nothing? value=null
|
||||
then: CONST Null type=kotlin.Nothing? value=null
|
||||
BRANCH
|
||||
if: CONST Boolean type=kotlin.Boolean value=true
|
||||
then: CALL 'public open fun toDouble (): kotlin.Double declared in kotlin.Float' type=kotlin.Double origin=null
|
||||
$this: GET_VAR 'val tmp_0: kotlin.Float? [val] declared in <root>.testDF' type=kotlin.Float? origin=null
|
||||
BRANCH
|
||||
if: CONST Boolean type=kotlin.Boolean value=true
|
||||
then: CONST Boolean type=kotlin.Boolean value=false
|
||||
@@ -34,8 +46,20 @@ FILE fqName:<root> fileName:/nullableFloatingPointEqeq.kt
|
||||
GET_VAR 'y: kotlin.Any? declared in <root>.testDI' type=kotlin.Any? origin=null
|
||||
then: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
|
||||
arg0: GET_VAR 'x: kotlin.Double? declared in <root>.testDI' type=kotlin.Double? origin=null
|
||||
arg1: TYPE_OP type=kotlin.Int? origin=IMPLICIT_CAST typeOperand=kotlin.Int?
|
||||
GET_VAR 'y: kotlin.Any? declared in <root>.testDI' type=kotlin.Any? origin=null
|
||||
arg1: BLOCK type=kotlin.Double? origin=SAFE_CALL
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp_1 type:kotlin.Int? [val]
|
||||
TYPE_OP type=kotlin.Int? origin=IMPLICIT_CAST typeOperand=kotlin.Int?
|
||||
GET_VAR 'y: kotlin.Any? declared in <root>.testDI' type=kotlin.Any? origin=null
|
||||
WHEN type=kotlin.Double? origin=null
|
||||
BRANCH
|
||||
if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
|
||||
arg0: GET_VAR 'val tmp_1: kotlin.Int? [val] declared in <root>.testDI' type=kotlin.Int? origin=null
|
||||
arg1: CONST Null type=kotlin.Nothing? value=null
|
||||
then: CONST Null type=kotlin.Nothing? value=null
|
||||
BRANCH
|
||||
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_1: kotlin.Int? [val] declared in <root>.testDI' type=kotlin.Int? origin=null
|
||||
BRANCH
|
||||
if: CONST Boolean type=kotlin.Boolean value=true
|
||||
then: CONST Boolean type=kotlin.Boolean value=false
|
||||
@@ -56,8 +80,20 @@ FILE fqName:<root> fileName:/nullableFloatingPointEqeq.kt
|
||||
if: CONST Boolean type=kotlin.Boolean value=true
|
||||
then: CONST Boolean type=kotlin.Boolean value=false
|
||||
then: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
|
||||
arg0: TYPE_OP type=kotlin.Int? origin=IMPLICIT_CAST typeOperand=kotlin.Int?
|
||||
GET_VAR 'x: kotlin.Any? declared in <root>.testDI2' type=kotlin.Any? origin=null
|
||||
arg0: BLOCK type=kotlin.Double? origin=SAFE_CALL
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp_2 type:kotlin.Int? [val]
|
||||
TYPE_OP type=kotlin.Int? origin=IMPLICIT_CAST typeOperand=kotlin.Int?
|
||||
GET_VAR 'x: kotlin.Any? declared in <root>.testDI2' type=kotlin.Any? origin=null
|
||||
WHEN type=kotlin.Double? origin=null
|
||||
BRANCH
|
||||
if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
|
||||
arg0: GET_VAR 'val tmp_2: kotlin.Int? [val] declared in <root>.testDI2' type=kotlin.Int? origin=null
|
||||
arg1: CONST Null type=kotlin.Nothing? value=null
|
||||
then: CONST Null type=kotlin.Nothing? value=null
|
||||
BRANCH
|
||||
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
|
||||
GET_VAR 'y: kotlin.Any? declared in <root>.testDI2' type=kotlin.Any? origin=null
|
||||
BRANCH
|
||||
|
||||
+14
-9
@@ -44,8 +44,9 @@ FILE fqName:<root> fileName:/typeParameterWithPrimitiveNumericSupertype.kt
|
||||
if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=kotlin.Float
|
||||
GET_VAR 'x: kotlin.Any declared in <root>.test2' type=kotlin.Any origin=null
|
||||
then: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
|
||||
arg0: TYPE_OP type=kotlin.Float origin=IMPLICIT_CAST typeOperand=kotlin.Float
|
||||
GET_VAR 'x: kotlin.Any declared in <root>.test2' type=kotlin.Any origin=null
|
||||
arg0: CALL 'public open fun toDouble (): kotlin.Double declared in kotlin.Float' type=kotlin.Double origin=null
|
||||
$this: TYPE_OP type=kotlin.Float origin=IMPLICIT_CAST typeOperand=kotlin.Float
|
||||
GET_VAR 'x: kotlin.Any declared in <root>.test2' type=kotlin.Any origin=null
|
||||
arg1: GET_VAR 'y: T of <root>.test2 declared in <root>.test2' type=T of <root>.test2 origin=null
|
||||
BRANCH
|
||||
if: CONST Boolean type=kotlin.Boolean value=true
|
||||
@@ -61,8 +62,9 @@ FILE fqName:<root> fileName:/typeParameterWithPrimitiveNumericSupertype.kt
|
||||
if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=kotlin.Int
|
||||
GET_VAR 'x: kotlin.Any declared in <root>.test3' type=kotlin.Any origin=null
|
||||
then: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
|
||||
arg0: TYPE_OP type=kotlin.Int origin=IMPLICIT_CAST typeOperand=kotlin.Int
|
||||
GET_VAR 'x: kotlin.Any declared in <root>.test3' type=kotlin.Any origin=null
|
||||
arg0: CALL 'public open fun toFloat (): kotlin.Float declared in kotlin.Int' type=kotlin.Float origin=null
|
||||
$this: TYPE_OP type=kotlin.Int origin=IMPLICIT_CAST typeOperand=kotlin.Int
|
||||
GET_VAR 'x: kotlin.Any declared in <root>.test3' type=kotlin.Any origin=null
|
||||
arg1: GET_VAR 'y: T of <root>.test3 declared in <root>.test3' type=T of <root>.test3 origin=null
|
||||
BRANCH
|
||||
if: CONST Boolean type=kotlin.Boolean value=true
|
||||
@@ -78,8 +80,9 @@ FILE fqName:<root> fileName:/typeParameterWithPrimitiveNumericSupertype.kt
|
||||
if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=kotlin.Int
|
||||
GET_VAR 'x: kotlin.Any declared in <root>.test4' type=kotlin.Any origin=null
|
||||
then: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
|
||||
arg0: TYPE_OP type=kotlin.Int origin=IMPLICIT_CAST typeOperand=kotlin.Int
|
||||
GET_VAR 'x: kotlin.Any declared in <root>.test4' type=kotlin.Any origin=null
|
||||
arg0: CALL 'public open fun toFloat (): kotlin.Float declared in kotlin.Int' type=kotlin.Float origin=null
|
||||
$this: TYPE_OP type=kotlin.Int origin=IMPLICIT_CAST typeOperand=kotlin.Int
|
||||
GET_VAR 'x: kotlin.Any declared in <root>.test4' type=kotlin.Any origin=null
|
||||
arg1: GET_VAR 'y: T of <root>.test4 declared in <root>.test4' type=T of <root>.test4 origin=null
|
||||
BRANCH
|
||||
if: CONST Boolean type=kotlin.Boolean value=true
|
||||
@@ -96,8 +99,9 @@ FILE fqName:<root> fileName:/typeParameterWithPrimitiveNumericSupertype.kt
|
||||
if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=kotlin.Int
|
||||
GET_VAR 'x: kotlin.Any declared in <root>.test5' type=kotlin.Any origin=null
|
||||
then: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
|
||||
arg0: TYPE_OP type=kotlin.Int origin=IMPLICIT_CAST typeOperand=kotlin.Int
|
||||
GET_VAR 'x: kotlin.Any declared in <root>.test5' type=kotlin.Any origin=null
|
||||
arg0: CALL 'public open fun toFloat (): kotlin.Float declared in kotlin.Int' type=kotlin.Float origin=null
|
||||
$this: TYPE_OP type=kotlin.Int origin=IMPLICIT_CAST typeOperand=kotlin.Int
|
||||
GET_VAR 'x: kotlin.Any declared in <root>.test5' type=kotlin.Any origin=null
|
||||
arg1: GET_VAR 'y: R of <root>.test5 declared in <root>.test5' type=R of <root>.test5 origin=null
|
||||
BRANCH
|
||||
if: CONST Boolean type=kotlin.Boolean value=true
|
||||
@@ -137,7 +141,8 @@ FILE fqName:<root> fileName:/typeParameterWithPrimitiveNumericSupertype.kt
|
||||
if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=kotlin.Double
|
||||
GET_VAR 'y: kotlin.Any declared in <root>.F.testCapturedType' type=kotlin.Any origin=null
|
||||
then: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
|
||||
arg0: GET_VAR 'x: T of <root>.F declared in <root>.F.testCapturedType' type=T of <root>.F origin=null
|
||||
arg0: CALL 'public open fun toDouble (): kotlin.Double declared in kotlin.Float' type=kotlin.Double origin=null
|
||||
$this: GET_VAR 'x: T of <root>.F declared in <root>.F.testCapturedType' type=T of <root>.F origin=null
|
||||
arg1: TYPE_OP type=kotlin.Double origin=IMPLICIT_CAST typeOperand=kotlin.Double
|
||||
GET_VAR 'y: kotlin.Any declared in <root>.F.testCapturedType' type=kotlin.Any origin=null
|
||||
BRANCH
|
||||
|
||||
Vendored
+3
-2
@@ -112,8 +112,9 @@ FILE fqName:<root> fileName:/whenByFloatingPoint.kt
|
||||
BRANCH
|
||||
if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
|
||||
arg0: GET_VAR 'val tmp_4: kotlin.Double [val] declared in <root>.testSmartCastToDifferentTypes' type=kotlin.Double origin=null
|
||||
arg1: TYPE_OP type=kotlin.Float origin=IMPLICIT_CAST typeOperand=kotlin.Float
|
||||
GET_VAR 'y: kotlin.Any declared in <root>.testSmartCastToDifferentTypes' type=kotlin.Any origin=null
|
||||
arg1: CALL 'public open fun toDouble (): kotlin.Double declared in kotlin.Float' type=kotlin.Double origin=null
|
||||
$this: TYPE_OP type=kotlin.Float origin=IMPLICIT_CAST typeOperand=kotlin.Float
|
||||
GET_VAR 'y: kotlin.Any declared in <root>.testSmartCastToDifferentTypes' type=kotlin.Any origin=null
|
||||
then: CONST Int type=kotlin.Int value=0
|
||||
BRANCH
|
||||
if: CONST Boolean type=kotlin.Boolean value=true
|
||||
|
||||
@@ -1,209 +0,0 @@
|
||||
FILE fqName:<root> fileName:/primitiveComparisons.kt
|
||||
FUN name:btest1 visibility:public modality:FINAL <> (a:kotlin.Byte, b:kotlin.Byte) returnType:kotlin.Boolean
|
||||
VALUE_PARAMETER name:a index:0 type:kotlin.Byte
|
||||
VALUE_PARAMETER name:b index:1 type:kotlin.Byte
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun btest1 (a: kotlin.Byte, b: kotlin.Byte): kotlin.Boolean declared in <root>'
|
||||
CALL 'public final fun greater (arg0: kotlin.Int, arg1: kotlin.Int): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=GT
|
||||
arg0: CALL 'public open fun compareTo (other: kotlin.Byte): kotlin.Int [operator] declared in kotlin.Byte' type=kotlin.Int origin=null
|
||||
$this: GET_VAR 'a: kotlin.Byte declared in <root>.btest1' type=kotlin.Byte origin=null
|
||||
other: GET_VAR 'b: kotlin.Byte declared in <root>.btest1' type=kotlin.Byte origin=null
|
||||
arg1: CONST Int type=kotlin.Int value=0
|
||||
FUN name:btest2 visibility:public modality:FINAL <> (a:kotlin.Byte, b:kotlin.Byte) returnType:kotlin.Boolean
|
||||
VALUE_PARAMETER name:a index:0 type:kotlin.Byte
|
||||
VALUE_PARAMETER name:b index:1 type:kotlin.Byte
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun btest2 (a: kotlin.Byte, b: kotlin.Byte): kotlin.Boolean declared in <root>'
|
||||
CALL 'public final fun less (arg0: kotlin.Int, arg1: kotlin.Int): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=LT
|
||||
arg0: CALL 'public open fun compareTo (other: kotlin.Byte): kotlin.Int [operator] declared in kotlin.Byte' type=kotlin.Int origin=null
|
||||
$this: GET_VAR 'a: kotlin.Byte declared in <root>.btest2' type=kotlin.Byte origin=null
|
||||
other: GET_VAR 'b: kotlin.Byte declared in <root>.btest2' type=kotlin.Byte origin=null
|
||||
arg1: CONST Int type=kotlin.Int value=0
|
||||
FUN name:btest3 visibility:public modality:FINAL <> (a:kotlin.Byte, b:kotlin.Byte) returnType:kotlin.Boolean
|
||||
VALUE_PARAMETER name:a index:0 type:kotlin.Byte
|
||||
VALUE_PARAMETER name:b index:1 type:kotlin.Byte
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun btest3 (a: kotlin.Byte, b: kotlin.Byte): kotlin.Boolean declared in <root>'
|
||||
CALL 'public final fun greaterOrEqual (arg0: kotlin.Int, arg1: kotlin.Int): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=GTEQ
|
||||
arg0: CALL 'public open fun compareTo (other: kotlin.Byte): kotlin.Int [operator] declared in kotlin.Byte' type=kotlin.Int origin=null
|
||||
$this: GET_VAR 'a: kotlin.Byte declared in <root>.btest3' type=kotlin.Byte origin=null
|
||||
other: GET_VAR 'b: kotlin.Byte declared in <root>.btest3' type=kotlin.Byte origin=null
|
||||
arg1: CONST Int type=kotlin.Int value=0
|
||||
FUN name:btest4 visibility:public modality:FINAL <> (a:kotlin.Byte, b:kotlin.Byte) returnType:kotlin.Boolean
|
||||
VALUE_PARAMETER name:a index:0 type:kotlin.Byte
|
||||
VALUE_PARAMETER name:b index:1 type:kotlin.Byte
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun btest4 (a: kotlin.Byte, b: kotlin.Byte): kotlin.Boolean declared in <root>'
|
||||
CALL 'public final fun lessOrEqual (arg0: kotlin.Int, arg1: kotlin.Int): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=LTEQ
|
||||
arg0: CALL 'public open fun compareTo (other: kotlin.Byte): kotlin.Int [operator] declared in kotlin.Byte' type=kotlin.Int origin=null
|
||||
$this: GET_VAR 'a: kotlin.Byte declared in <root>.btest4' type=kotlin.Byte origin=null
|
||||
other: GET_VAR 'b: kotlin.Byte declared in <root>.btest4' type=kotlin.Byte origin=null
|
||||
arg1: CONST Int type=kotlin.Int value=0
|
||||
FUN name:stest1 visibility:public modality:FINAL <> (a:kotlin.Short, b:kotlin.Short) returnType:kotlin.Boolean
|
||||
VALUE_PARAMETER name:a index:0 type:kotlin.Short
|
||||
VALUE_PARAMETER name:b index:1 type:kotlin.Short
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun stest1 (a: kotlin.Short, b: kotlin.Short): kotlin.Boolean declared in <root>'
|
||||
CALL 'public final fun greater (arg0: kotlin.Int, arg1: kotlin.Int): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=GT
|
||||
arg0: CALL 'public open fun compareTo (other: kotlin.Short): kotlin.Int [operator] declared in kotlin.Short' type=kotlin.Int origin=null
|
||||
$this: GET_VAR 'a: kotlin.Short declared in <root>.stest1' type=kotlin.Short origin=null
|
||||
other: GET_VAR 'b: kotlin.Short declared in <root>.stest1' type=kotlin.Short origin=null
|
||||
arg1: CONST Int type=kotlin.Int value=0
|
||||
FUN name:stest2 visibility:public modality:FINAL <> (a:kotlin.Short, b:kotlin.Short) returnType:kotlin.Boolean
|
||||
VALUE_PARAMETER name:a index:0 type:kotlin.Short
|
||||
VALUE_PARAMETER name:b index:1 type:kotlin.Short
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun stest2 (a: kotlin.Short, b: kotlin.Short): kotlin.Boolean declared in <root>'
|
||||
CALL 'public final fun less (arg0: kotlin.Int, arg1: kotlin.Int): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=LT
|
||||
arg0: CALL 'public open fun compareTo (other: kotlin.Short): kotlin.Int [operator] declared in kotlin.Short' type=kotlin.Int origin=null
|
||||
$this: GET_VAR 'a: kotlin.Short declared in <root>.stest2' type=kotlin.Short origin=null
|
||||
other: GET_VAR 'b: kotlin.Short declared in <root>.stest2' type=kotlin.Short origin=null
|
||||
arg1: CONST Int type=kotlin.Int value=0
|
||||
FUN name:stest3 visibility:public modality:FINAL <> (a:kotlin.Short, b:kotlin.Short) returnType:kotlin.Boolean
|
||||
VALUE_PARAMETER name:a index:0 type:kotlin.Short
|
||||
VALUE_PARAMETER name:b index:1 type:kotlin.Short
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun stest3 (a: kotlin.Short, b: kotlin.Short): kotlin.Boolean declared in <root>'
|
||||
CALL 'public final fun greaterOrEqual (arg0: kotlin.Int, arg1: kotlin.Int): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=GTEQ
|
||||
arg0: CALL 'public open fun compareTo (other: kotlin.Short): kotlin.Int [operator] declared in kotlin.Short' type=kotlin.Int origin=null
|
||||
$this: GET_VAR 'a: kotlin.Short declared in <root>.stest3' type=kotlin.Short origin=null
|
||||
other: GET_VAR 'b: kotlin.Short declared in <root>.stest3' type=kotlin.Short origin=null
|
||||
arg1: CONST Int type=kotlin.Int value=0
|
||||
FUN name:stest4 visibility:public modality:FINAL <> (a:kotlin.Short, b:kotlin.Short) returnType:kotlin.Boolean
|
||||
VALUE_PARAMETER name:a index:0 type:kotlin.Short
|
||||
VALUE_PARAMETER name:b index:1 type:kotlin.Short
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun stest4 (a: kotlin.Short, b: kotlin.Short): kotlin.Boolean declared in <root>'
|
||||
CALL 'public final fun lessOrEqual (arg0: kotlin.Int, arg1: kotlin.Int): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=LTEQ
|
||||
arg0: CALL 'public open fun compareTo (other: kotlin.Short): kotlin.Int [operator] declared in kotlin.Short' type=kotlin.Int origin=null
|
||||
$this: GET_VAR 'a: kotlin.Short declared in <root>.stest4' type=kotlin.Short origin=null
|
||||
other: GET_VAR 'b: kotlin.Short declared in <root>.stest4' type=kotlin.Short origin=null
|
||||
arg1: CONST Int type=kotlin.Int value=0
|
||||
FUN name:itest1 visibility:public modality:FINAL <> (a:kotlin.Int, b:kotlin.Int) returnType:kotlin.Boolean
|
||||
VALUE_PARAMETER name:a index:0 type:kotlin.Int
|
||||
VALUE_PARAMETER name:b index:1 type:kotlin.Int
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun itest1 (a: kotlin.Int, b: kotlin.Int): kotlin.Boolean declared in <root>'
|
||||
CALL 'public final fun greater (arg0: kotlin.Int, arg1: kotlin.Int): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=GT
|
||||
arg0: GET_VAR 'a: kotlin.Int declared in <root>.itest1' type=kotlin.Int origin=null
|
||||
arg1: GET_VAR 'b: kotlin.Int declared in <root>.itest1' type=kotlin.Int origin=null
|
||||
FUN name:itest2 visibility:public modality:FINAL <> (a:kotlin.Int, b:kotlin.Int) returnType:kotlin.Boolean
|
||||
VALUE_PARAMETER name:a index:0 type:kotlin.Int
|
||||
VALUE_PARAMETER name:b index:1 type:kotlin.Int
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun itest2 (a: kotlin.Int, b: kotlin.Int): kotlin.Boolean declared in <root>'
|
||||
CALL 'public final fun less (arg0: kotlin.Int, arg1: kotlin.Int): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=LT
|
||||
arg0: GET_VAR 'a: kotlin.Int declared in <root>.itest2' type=kotlin.Int origin=null
|
||||
arg1: GET_VAR 'b: kotlin.Int declared in <root>.itest2' type=kotlin.Int origin=null
|
||||
FUN name:itest3 visibility:public modality:FINAL <> (a:kotlin.Int, b:kotlin.Int) returnType:kotlin.Boolean
|
||||
VALUE_PARAMETER name:a index:0 type:kotlin.Int
|
||||
VALUE_PARAMETER name:b index:1 type:kotlin.Int
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun itest3 (a: kotlin.Int, b: kotlin.Int): kotlin.Boolean declared in <root>'
|
||||
CALL 'public final fun greaterOrEqual (arg0: kotlin.Int, arg1: kotlin.Int): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=GTEQ
|
||||
arg0: GET_VAR 'a: kotlin.Int declared in <root>.itest3' type=kotlin.Int origin=null
|
||||
arg1: GET_VAR 'b: kotlin.Int declared in <root>.itest3' type=kotlin.Int origin=null
|
||||
FUN name:itest4 visibility:public modality:FINAL <> (a:kotlin.Int, b:kotlin.Int) returnType:kotlin.Boolean
|
||||
VALUE_PARAMETER name:a index:0 type:kotlin.Int
|
||||
VALUE_PARAMETER name:b index:1 type:kotlin.Int
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun itest4 (a: kotlin.Int, b: kotlin.Int): kotlin.Boolean declared in <root>'
|
||||
CALL 'public final fun lessOrEqual (arg0: kotlin.Int, arg1: kotlin.Int): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=LTEQ
|
||||
arg0: GET_VAR 'a: kotlin.Int declared in <root>.itest4' type=kotlin.Int origin=null
|
||||
arg1: GET_VAR 'b: kotlin.Int declared in <root>.itest4' type=kotlin.Int origin=null
|
||||
FUN name:ltest1 visibility:public modality:FINAL <> (a:kotlin.Long, b:kotlin.Long) returnType:kotlin.Boolean
|
||||
VALUE_PARAMETER name:a index:0 type:kotlin.Long
|
||||
VALUE_PARAMETER name:b index:1 type:kotlin.Long
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun ltest1 (a: kotlin.Long, b: kotlin.Long): kotlin.Boolean declared in <root>'
|
||||
CALL 'public final fun greater (arg0: kotlin.Long, arg1: kotlin.Long): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=GT
|
||||
arg0: GET_VAR 'a: kotlin.Long declared in <root>.ltest1' type=kotlin.Long origin=null
|
||||
arg1: GET_VAR 'b: kotlin.Long declared in <root>.ltest1' type=kotlin.Long origin=null
|
||||
FUN name:ltest2 visibility:public modality:FINAL <> (a:kotlin.Long, b:kotlin.Long) returnType:kotlin.Boolean
|
||||
VALUE_PARAMETER name:a index:0 type:kotlin.Long
|
||||
VALUE_PARAMETER name:b index:1 type:kotlin.Long
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun ltest2 (a: kotlin.Long, b: kotlin.Long): kotlin.Boolean declared in <root>'
|
||||
CALL 'public final fun less (arg0: kotlin.Long, arg1: kotlin.Long): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=LT
|
||||
arg0: GET_VAR 'a: kotlin.Long declared in <root>.ltest2' type=kotlin.Long origin=null
|
||||
arg1: GET_VAR 'b: kotlin.Long declared in <root>.ltest2' type=kotlin.Long origin=null
|
||||
FUN name:ltest3 visibility:public modality:FINAL <> (a:kotlin.Long, b:kotlin.Long) returnType:kotlin.Boolean
|
||||
VALUE_PARAMETER name:a index:0 type:kotlin.Long
|
||||
VALUE_PARAMETER name:b index:1 type:kotlin.Long
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun ltest3 (a: kotlin.Long, b: kotlin.Long): kotlin.Boolean declared in <root>'
|
||||
CALL 'public final fun greaterOrEqual (arg0: kotlin.Long, arg1: kotlin.Long): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=GTEQ
|
||||
arg0: GET_VAR 'a: kotlin.Long declared in <root>.ltest3' type=kotlin.Long origin=null
|
||||
arg1: GET_VAR 'b: kotlin.Long declared in <root>.ltest3' type=kotlin.Long origin=null
|
||||
FUN name:ltest4 visibility:public modality:FINAL <> (a:kotlin.Long, b:kotlin.Long) returnType:kotlin.Boolean
|
||||
VALUE_PARAMETER name:a index:0 type:kotlin.Long
|
||||
VALUE_PARAMETER name:b index:1 type:kotlin.Long
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun ltest4 (a: kotlin.Long, b: kotlin.Long): kotlin.Boolean declared in <root>'
|
||||
CALL 'public final fun lessOrEqual (arg0: kotlin.Long, arg1: kotlin.Long): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=LTEQ
|
||||
arg0: GET_VAR 'a: kotlin.Long declared in <root>.ltest4' type=kotlin.Long origin=null
|
||||
arg1: GET_VAR 'b: kotlin.Long declared in <root>.ltest4' type=kotlin.Long origin=null
|
||||
FUN name:ftest1 visibility:public modality:FINAL <> (a:kotlin.Float, b:kotlin.Float) returnType:kotlin.Boolean
|
||||
VALUE_PARAMETER name:a index:0 type:kotlin.Float
|
||||
VALUE_PARAMETER name:b index:1 type:kotlin.Float
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun ftest1 (a: kotlin.Float, b: kotlin.Float): kotlin.Boolean declared in <root>'
|
||||
CALL 'public final fun greater (arg0: kotlin.Float, arg1: kotlin.Float): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=GT
|
||||
arg0: GET_VAR 'a: kotlin.Float declared in <root>.ftest1' type=kotlin.Float origin=null
|
||||
arg1: GET_VAR 'b: kotlin.Float declared in <root>.ftest1' type=kotlin.Float origin=null
|
||||
FUN name:ftest2 visibility:public modality:FINAL <> (a:kotlin.Float, b:kotlin.Float) returnType:kotlin.Boolean
|
||||
VALUE_PARAMETER name:a index:0 type:kotlin.Float
|
||||
VALUE_PARAMETER name:b index:1 type:kotlin.Float
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun ftest2 (a: kotlin.Float, b: kotlin.Float): kotlin.Boolean declared in <root>'
|
||||
CALL 'public final fun less (arg0: kotlin.Float, arg1: kotlin.Float): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=LT
|
||||
arg0: GET_VAR 'a: kotlin.Float declared in <root>.ftest2' type=kotlin.Float origin=null
|
||||
arg1: GET_VAR 'b: kotlin.Float declared in <root>.ftest2' type=kotlin.Float origin=null
|
||||
FUN name:ftest3 visibility:public modality:FINAL <> (a:kotlin.Float, b:kotlin.Float) returnType:kotlin.Boolean
|
||||
VALUE_PARAMETER name:a index:0 type:kotlin.Float
|
||||
VALUE_PARAMETER name:b index:1 type:kotlin.Float
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun ftest3 (a: kotlin.Float, b: kotlin.Float): kotlin.Boolean declared in <root>'
|
||||
CALL 'public final fun greaterOrEqual (arg0: kotlin.Float, arg1: kotlin.Float): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=GTEQ
|
||||
arg0: GET_VAR 'a: kotlin.Float declared in <root>.ftest3' type=kotlin.Float origin=null
|
||||
arg1: GET_VAR 'b: kotlin.Float declared in <root>.ftest3' type=kotlin.Float origin=null
|
||||
FUN name:ftest4 visibility:public modality:FINAL <> (a:kotlin.Float, b:kotlin.Float) returnType:kotlin.Boolean
|
||||
VALUE_PARAMETER name:a index:0 type:kotlin.Float
|
||||
VALUE_PARAMETER name:b index:1 type:kotlin.Float
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun ftest4 (a: kotlin.Float, b: kotlin.Float): kotlin.Boolean declared in <root>'
|
||||
CALL 'public final fun lessOrEqual (arg0: kotlin.Float, arg1: kotlin.Float): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=LTEQ
|
||||
arg0: GET_VAR 'a: kotlin.Float declared in <root>.ftest4' type=kotlin.Float origin=null
|
||||
arg1: GET_VAR 'b: kotlin.Float declared in <root>.ftest4' type=kotlin.Float origin=null
|
||||
FUN name:dtest1 visibility:public modality:FINAL <> (a:kotlin.Double, b:kotlin.Double) returnType:kotlin.Boolean
|
||||
VALUE_PARAMETER name:a index:0 type:kotlin.Double
|
||||
VALUE_PARAMETER name:b index:1 type:kotlin.Double
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun dtest1 (a: kotlin.Double, b: kotlin.Double): kotlin.Boolean declared in <root>'
|
||||
CALL 'public final fun greater (arg0: kotlin.Double, arg1: kotlin.Double): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=GT
|
||||
arg0: GET_VAR 'a: kotlin.Double declared in <root>.dtest1' type=kotlin.Double origin=null
|
||||
arg1: GET_VAR 'b: kotlin.Double declared in <root>.dtest1' type=kotlin.Double origin=null
|
||||
FUN name:dtest2 visibility:public modality:FINAL <> (a:kotlin.Double, b:kotlin.Double) returnType:kotlin.Boolean
|
||||
VALUE_PARAMETER name:a index:0 type:kotlin.Double
|
||||
VALUE_PARAMETER name:b index:1 type:kotlin.Double
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun dtest2 (a: kotlin.Double, b: kotlin.Double): kotlin.Boolean declared in <root>'
|
||||
CALL 'public final fun less (arg0: kotlin.Double, arg1: kotlin.Double): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=LT
|
||||
arg0: GET_VAR 'a: kotlin.Double declared in <root>.dtest2' type=kotlin.Double origin=null
|
||||
arg1: GET_VAR 'b: kotlin.Double declared in <root>.dtest2' type=kotlin.Double origin=null
|
||||
FUN name:dtest3 visibility:public modality:FINAL <> (a:kotlin.Double, b:kotlin.Double) returnType:kotlin.Boolean
|
||||
VALUE_PARAMETER name:a index:0 type:kotlin.Double
|
||||
VALUE_PARAMETER name:b index:1 type:kotlin.Double
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun dtest3 (a: kotlin.Double, b: kotlin.Double): kotlin.Boolean declared in <root>'
|
||||
CALL 'public final fun greaterOrEqual (arg0: kotlin.Double, arg1: kotlin.Double): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=GTEQ
|
||||
arg0: GET_VAR 'a: kotlin.Double declared in <root>.dtest3' type=kotlin.Double origin=null
|
||||
arg1: GET_VAR 'b: kotlin.Double declared in <root>.dtest3' type=kotlin.Double origin=null
|
||||
FUN name:dtest4 visibility:public modality:FINAL <> (a:kotlin.Double, b:kotlin.Double) returnType:kotlin.Boolean
|
||||
VALUE_PARAMETER name:a index:0 type:kotlin.Double
|
||||
VALUE_PARAMETER name:b index:1 type:kotlin.Double
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun dtest4 (a: kotlin.Double, b: kotlin.Double): kotlin.Boolean declared in <root>'
|
||||
CALL 'public final fun lessOrEqual (arg0: kotlin.Double, arg1: kotlin.Double): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=LTEQ
|
||||
arg0: GET_VAR 'a: kotlin.Double declared in <root>.dtest4' type=kotlin.Double origin=null
|
||||
arg1: GET_VAR 'b: kotlin.Double declared in <root>.dtest4' type=kotlin.Double origin=null
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
fun btest1(a: Byte, b: Byte) = a > b
|
||||
fun btest2(a: Byte, b: Byte) = a < b
|
||||
fun btest3(a: Byte, b: Byte) = a >= b
|
||||
|
||||
Reference in New Issue
Block a user