From 00325ae539d5d18633c4049070affec5f56daa54 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Tue, 6 Feb 2018 17:51:12 +0300 Subject: [PATCH] Handle equality checks for 'when' and data classes --- .../kotlin/resolve/BindingContext.java | 4 +- .../PrimitiveNumericComparisonCallChecker.kt | 39 ++- .../PatternMatchingTypingVisitor.kt | 28 +- .../psi2ir/generators/AssignmentGenerator.kt | 10 +- .../BranchingExpressionGenerator.kt | 28 +- .../generators/DataClassMembersGenerator.kt | 12 +- .../generators/ErrorExpressionGenerator.kt | 10 +- .../generators/LoopExpressionGenerator.kt | 14 +- .../generators/OperatorExpressionGenerator.kt | 82 +++--- .../ReflectionReferencesGenerator.kt | 2 +- .../psi2ir/generators/StatementGenerator.kt | 3 + .../generators/TryCatchExpressionGenerator.kt | 6 +- .../testData/ir/irText/classes/dataClasses.kt | 4 +- .../ir/irText/classes/dataClasses.txt | 241 +++++++++++++++++- .../eqeqRhsConditionPossiblyAffectingLhs.kt | 2 + .../eqeqRhsConditionPossiblyAffectingLhs.txt | 27 ++ .../whenByFloatingPoint.kt | 48 ++++ .../whenByFloatingPoint.txt | 148 +++++++++++ .../kotlin/ir/IrTextTestCaseGenerated.java | 12 + 19 files changed, 631 insertions(+), 89 deletions(-) create mode 100644 compiler/testData/ir/irText/expressions/floatingPointComparisons/eqeqRhsConditionPossiblyAffectingLhs.kt create mode 100644 compiler/testData/ir/irText/expressions/floatingPointComparisons/eqeqRhsConditionPossiblyAffectingLhs.txt create mode 100644 compiler/testData/ir/irText/expressions/floatingPointComparisons/whenByFloatingPoint.kt create mode 100644 compiler/testData/ir/irText/expressions/floatingPointComparisons/whenByFloatingPoint.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java index 2bccd237853..17448a60cf1 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java @@ -40,6 +40,7 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue; import org.jetbrains.kotlin.resolve.calls.smartcasts.ExplicitSmartCasts; import org.jetbrains.kotlin.resolve.calls.smartcasts.ImplicitSmartCasts; import org.jetbrains.kotlin.resolve.calls.tower.KotlinResolutionCallbacksImpl; +import org.jetbrains.kotlin.resolve.checkers.PrimitiveNumericComparisonInfo; import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant; import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics; import org.jetbrains.kotlin.resolve.scopes.LexicalScope; @@ -267,8 +268,7 @@ public interface BindingContext { WritableSlice NEW_INFERENCE_LAMBDA_INFO = new BasicWritableSlice<>(DO_NOTHING); - WritableSlice PRIMITIVE_NUMERIC_COMPARISON_TYPE = Slices.createSimpleSlice(); - WritableSlice PRIMITIVE_NUMERIC_COMPARISON_OPERAND_TYPE = Slices.createSimpleSlice(); + WritableSlice PRIMITIVE_NUMERIC_COMPARISON_INFO = Slices.createSimpleSlice(); @SuppressWarnings("UnusedDeclaration") @Deprecated // This field is needed only for the side effects of its initializer diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/PrimitiveNumericComparisonCallChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/PrimitiveNumericComparisonCallChecker.kt index 13c9fcd7c14..c1633727b9f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/PrimitiveNumericComparisonCallChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/PrimitiveNumericComparisonCallChecker.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.KtBinaryExpression import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall @@ -17,6 +18,12 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.typeUtil.* +class PrimitiveNumericComparisonInfo( + val comparisonType: KotlinType, + val leftType: KotlinType, + val rightType: KotlinType +) + object PrimitiveNumericComparisonCallChecker : CallChecker { private val comparisonOperatorTokens = setOf(KtTokens.EQEQ, KtTokens.EXCLEQ, KtTokens.LT, KtTokens.LTEQ, KtTokens.GT, KtTokens.GTEQ) @@ -29,15 +36,27 @@ object PrimitiveNumericComparisonCallChecker : CallChecker { val leftExpr = binaryExpression.left ?: return val rightExpr = binaryExpression.right ?: return - val leftType = context.getInferredPrimitiveNumericType(leftExpr) ?: return - val rightType = context.getInferredPrimitiveNumericType(rightExpr) ?: return + val leftTypes = context.getStableTypesForExpression(leftExpr) + val rightTypes = context.getStableTypesForExpression(rightExpr) - context.trace.record(BindingContext.PRIMITIVE_NUMERIC_COMPARISON_OPERAND_TYPE, leftExpr, leftType) - context.trace.record(BindingContext.PRIMITIVE_NUMERIC_COMPARISON_OPERAND_TYPE, rightExpr, rightType) + inferPrimitiveNumericComparisonType(context.trace, leftTypes, rightTypes, binaryExpression) + } - val leastCommonType = leastCommonPrimitiveNumericType(leftType, rightType) + fun inferPrimitiveNumericComparisonType( + trace: BindingTrace, + leftTypes: List, + rightTypes: List, + comparison: KtExpression + ) { + val leftPrimitiveType = leftTypes.findPrimitiveType() ?: return + val rightPrimitiveType = rightTypes.findPrimitiveType() ?: return + val leastCommonType = leastCommonPrimitiveNumericType(leftPrimitiveType, rightPrimitiveType) - context.trace.record(BindingContext.PRIMITIVE_NUMERIC_COMPARISON_TYPE, binaryExpression, leastCommonType) + trace.record( + BindingContext.PRIMITIVE_NUMERIC_COMPARISON_INFO, + comparison, + PrimitiveNumericComparisonInfo(leastCommonType, leftPrimitiveType, rightPrimitiveType) + ) } private fun leastCommonPrimitiveNumericType(t1: KotlinType, t2: KotlinType): KotlinType { @@ -60,14 +79,14 @@ object PrimitiveNumericComparisonCallChecker : CallChecker { else -> this } - private fun CallCheckerContext.getInferredPrimitiveNumericType(expression: KtExpression): KotlinType? { - val type = trace.bindingContext.getType(expression) ?: return null + private fun CallCheckerContext.getStableTypesForExpression(expression: KtExpression): List { + val type = trace.bindingContext.getType(expression) ?: return emptyList() val dataFlowValue = DataFlowValueFactory.createDataFlowValue( expression, type, trace.bindingContext, resolutionContext.scope.ownerDescriptor ) - val dataFlowInfo = trace.get(BindingContext.EXPRESSION_TYPE_INFO, expression)?.dataFlowInfo ?: return null + val dataFlowInfo = trace.get(BindingContext.EXPRESSION_TYPE_INFO, expression)?.dataFlowInfo ?: return emptyList() val stableTypes = dataFlowInfo.getStableTypes(dataFlowValue, languageVersionSettings) - return (listOf(type) + stableTypes).findPrimitiveType() + return listOf(type) + stableTypes } private fun List.findPrimitiveType() = diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.kt index 3ba9182e2ab..7d406ce28b1 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.kt @@ -34,6 +34,7 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory import org.jetbrains.kotlin.resolve.calls.util.CallMaker +import org.jetbrains.kotlin.resolve.checkers.PrimitiveNumericComparisonCallChecker import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE import org.jetbrains.kotlin.types.checker.KotlinTypeChecker @@ -259,7 +260,8 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping if (checkSmartCastToExpectedTypeInSubject( contextBeforeSubject, subjectExpression, subjectType, possibleCastType - )) { + ) + ) { return } } @@ -271,7 +273,8 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping if (checkSmartCastToExpectedTypeInSubject( contextBeforeSubject, subjectExpression, subjectType, notNullableType - )) { + ) + ) { return } } @@ -384,7 +387,7 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping val expression = condition.expression if (expression != null) { val basicDataFlowInfo = checkTypeForExpressionCondition( - context, expression, subjectType, subjectExpression == null, subjectDataFlowValue + context, expression, subjectType, subjectExpression, subjectDataFlowValue ) val moduleDescriptor = DescriptorUtils.getContainingModule(context.scope.ownerDescriptor) val dataFlowInfoFromES = @@ -404,14 +407,16 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping context: ExpressionTypingContext, expression: KtExpression, subjectType: KotlinType, - conditionExpected: Boolean, + subjectExpression: KtExpression?, subjectDataFlowValue: DataFlowValue ): ConditionalDataFlowInfo { + var newContext = context val typeInfo = facade.getTypeInfo(expression, newContext) val type = typeInfo.type ?: return noChange(newContext) newContext = newContext.replaceDataFlowInfo(typeInfo.dataFlowInfo) - if (conditionExpected) { + + if (subjectExpression == null) { // condition expected val booleanType = components.builtIns.booleanType val checkedTypeInfo = components.dataFlowAnalyzer.checkType(typeInfo, expression, newContext.replaceExpectedType(booleanType)) if (KotlinTypeChecker.DEFAULT.equalTypes(booleanType, checkedTypeInfo.type ?: type)) { @@ -421,8 +426,21 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping } return noChange(newContext) } + checkTypeCompatibility(newContext, type, subjectType, expression) val expressionDataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, type, newContext) + + val subjectStableTypes = + listOf(subjectType) + context.dataFlowInfo.getStableTypes(subjectDataFlowValue, components.languageVersionSettings) + val expressionStableTypes = + listOf(type) + newContext.dataFlowInfo.getStableTypes(expressionDataFlowValue, components.languageVersionSettings) + PrimitiveNumericComparisonCallChecker.inferPrimitiveNumericComparisonType( + context.trace, + subjectStableTypes, + expressionStableTypes, + expression + ) + val result = noChange(newContext) return ConditionalDataFlowInfo( result.thenInfo.equate( diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/AssignmentGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/AssignmentGenerator.kt index 309eb3d2c43..f638374fc15 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/AssignmentGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/AssignmentGenerator.kt @@ -37,7 +37,7 @@ import org.jetbrains.kotlin.types.KotlinType class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGeneratorExtension(statementGenerator) { fun generateAssignment(expression: KtBinaryExpression): IrExpression { val ktLeft = expression.left!! - val irRhs = statementGenerator.generateExpression(expression.right!!) + val irRhs = expression.right!!.genExpr() val irAssignmentReceiver = generateAssignmentReceiver(ktLeft, IrStatementOrigin.EQ) return irAssignmentReceiver.assign(irRhs) } @@ -52,7 +52,7 @@ class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGen return irAssignmentReceiver.assign { irLValue -> val opCall = statementGenerator.pregenerateCallReceivers(opResolvedCall) opCall.setExplicitReceiverValue(irLValue) - opCall.irValueArgumentsByIndex[0] = statementGenerator.generateExpression(ktRight) + opCall.irValueArgumentsByIndex[0] = ktRight.genExpr() val irOpCall = CallGenerator(statementGenerator).generateCall(expression, opCall, origin) if (isSimpleAssignment) { @@ -137,7 +137,7 @@ class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGen origin ) else -> - OnceExpressionValue(statementGenerator.generateExpression(ktLeft)) + OnceExpressionValue(ktLeft.genExpr()) } } @@ -237,8 +237,8 @@ class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGen ktLeft: KtArrayAccessExpression, origin: IrStatementOrigin ): ArrayAccessAssignmentReceiver { - val irArray = statementGenerator.generateExpression(ktLeft.arrayExpression!!) - val irIndexExpressions = ktLeft.indexExpressions.map { statementGenerator.generateExpression(it) } + val irArray = ktLeft.arrayExpression!!.genExpr() + val irIndexExpressions = ktLeft.indexExpressions.map { it.genExpr() } val indexedGetResolvedCall = get(BindingContext.INDEXED_LVALUE_GET, ktLeft) val indexedGetCall = indexedGetResolvedCall?.let { statementGenerator.pregenerateCallReceivers(it) } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BranchingExpressionGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BranchingExpressionGenerator.kt index a96a116a3ea..b6f90f0cfa8 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BranchingExpressionGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BranchingExpressionGenerator.kt @@ -40,8 +40,8 @@ class BranchingExpressionGenerator(statementGenerator: StatementGenerator) : Sta var irElseBranch: IrExpression? = null whenBranches@ while (true) { - val irCondition = statementGenerator.generateExpression(ktLastIf.condition!!) - val irThenBranch = statementGenerator.generateExpression(ktLastIf.then!!) + val irCondition = ktLastIf.condition!!.genExpr() + val irThenBranch = ktLastIf.then!!.genExpr() irBranches.add(IrBranchImpl(irCondition, irThenBranch)) val ktElse = ktLastIf.`else`?.deparenthesize() @@ -49,7 +49,7 @@ class BranchingExpressionGenerator(statementGenerator: StatementGenerator) : Sta null -> break@whenBranches is KtIfExpression -> ktLastIf = ktElse is KtExpression -> { - irElseBranch = statementGenerator.generateExpression(ktElse) + irElseBranch = ktElse.genExpr() break@whenBranches } else -> throw AssertionError("Unexpected else expression: ${ktElse.text}") @@ -85,7 +85,7 @@ class BranchingExpressionGenerator(statementGenerator: StatementGenerator) : Sta fun generateWhenExpression(expression: KtWhenExpression): IrExpression { val irSubject = expression.subjectExpression?.let { - scope.createTemporaryVariable(statementGenerator.generateExpression(it), "subject") + scope.createTemporaryVariable(it.genExpr(), "subject") } @@ -104,7 +104,7 @@ class BranchingExpressionGenerator(statementGenerator: StatementGenerator) : Sta for (ktEntry in expression.entries) { if (ktEntry.isElse) { - val irElseResult = statementGenerator.generateExpression(ktEntry.expression!!) + val irElseResult = ktEntry.expression!!.genExpr() irWhen.branches.add(IrBranchImpl.elseBranch(irElseResult)) break } @@ -117,10 +117,9 @@ class BranchingExpressionGenerator(statementGenerator: StatementGenerator) : Sta else generateWhenConditionNoSubject(ktCondition) irBranchCondition = irBranchCondition?.let { context.whenComma(it, irCondition) } ?: irCondition - } - val irBranchResult = statementGenerator.generateExpression(ktEntry.expression!!) + val irBranchResult = ktEntry.expression!!.genExpr() irWhen.branches.add(IrBranchImpl(irBranchCondition!!, irBranchResult)) } addElseBranchForExhaustiveWhenIfNeeded(irWhen, expression) @@ -163,7 +162,7 @@ class BranchingExpressionGenerator(statementGenerator: StatementGenerator) : Sta } private fun generateWhenConditionNoSubject(ktCondition: KtWhenCondition): IrExpression = - statementGenerator.generateExpression((ktCondition as KtWhenConditionWithExpression).expression!!) + (ktCondition as KtWhenConditionWithExpression).expression!!.genExpr() private fun generateWhenConditionWithSubject(ktCondition: KtWhenCondition, irSubject: IrVariable): IrExpression { return when (ktCondition) { @@ -204,10 +203,13 @@ class BranchingExpressionGenerator(statementGenerator: StatementGenerator) : Sta } } - private fun generateEqualsCondition(irSubject: IrVariable, ktCondition: KtWhenConditionWithExpression): IrBinaryPrimitiveImpl = - IrBinaryPrimitiveImpl( - ktCondition.startOffset, ktCondition.endOffset, - IrStatementOrigin.EQEQ, context.irBuiltIns.eqeqSymbol, - irSubject.defaultLoad(), statementGenerator.generateExpression(ktCondition.expression!!) + private fun generateEqualsCondition(irSubject: IrVariable, ktCondition: KtWhenConditionWithExpression): IrExpression { + val ktExpression = ktCondition.expression + val irExpression = ktExpression!!.genExpr() + return OperatorExpressionGenerator(statementGenerator).generateEquality( + ktCondition.startOffset, ktCondition.endOffset, IrStatementOrigin.EQEQ, + irSubject.defaultLoad(), irExpression, + context.bindingContext[BindingContext.PRIMITIVE_NUMERIC_COMPARISON_INFO, ktExpression] ) + } } \ No newline at end of file diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DataClassMembersGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DataClassMembersGenerator.kt index 126e6ad5b4c..def476910a5 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DataClassMembersGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DataClassMembersGenerator.kt @@ -137,12 +137,9 @@ class DataClassMembersGenerator(declarationGenerator: DeclarationGenerator) : De +irIfThenReturnFalse(irNotIs(irOther(), classDescriptor.defaultType)) val otherWithCast = irTemporary(irAs(irOther(), classDescriptor.defaultType), "other_with_cast") for (property in properties) { - +irIfThenReturnFalse( - irNotEquals( - irGet(irThis(), getPropertyGetterSymbol(property)), - irGet(irGet(otherWithCast.symbol), getPropertyGetterSymbol(property)) - ) - ) + val arg1 = irGet(irThis(), getPropertyGetterSymbol(property)) + val arg2 = irGet(irGet(otherWithCast.symbol), getPropertyGetterSymbol(property)) + +irIfThenReturnFalse(irNotEquals(arg1, arg2)) } +irReturnTrue() } @@ -229,7 +226,8 @@ class DataClassMembersGenerator(declarationGenerator: DeclarationGenerator) : De val typeConstructorDescriptor = property.type.constructor.declarationDescriptor val irPropertyStringValue = if (typeConstructorDescriptor is ClassDescriptor && - KotlinBuiltIns.isArrayOrPrimitiveArray(typeConstructorDescriptor)) + KotlinBuiltIns.isArrayOrPrimitiveArray(typeConstructorDescriptor) + ) irCall(context.irBuiltIns.dataClassArrayMemberToStringSymbol).apply { putValueArgument(0, irPropertyValue) } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ErrorExpressionGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ErrorExpressionGenerator.kt index e89c6cff895..047d108e286 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ErrorExpressionGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ErrorExpressionGenerator.kt @@ -46,19 +46,19 @@ class ErrorExpressionGenerator(statementGenerator: StatementGenerator) : Stateme val type = getErrorExpressionType(ktCall) val irErrorCall = IrErrorCallExpressionImpl(ktCall.startOffset, ktCall.endOffset, type, "") // TODO problem description? - irErrorCall.explicitReceiver = (ktCall.parent as? KtDotQualifiedExpression)?.let { - statementGenerator.generateExpression(it.receiverExpression) + irErrorCall.explicitReceiver = (ktCall.parent as? KtDotQualifiedExpression)?.run { + receiverExpression.genExpr() } ktCall.valueArguments.forEach { val ktArgument = it.getArgumentExpression() if (ktArgument != null) { - irErrorCall.addArgument(statementGenerator.generateExpression(ktArgument)) + irErrorCall.addArgument(ktArgument.genExpr()) } } ktCall.lambdaArguments.forEach { - irErrorCall.addArgument(statementGenerator.generateExpression(it.getArgumentExpression())) + irErrorCall.addArgument(it.getArgumentExpression().genExpr()) } irErrorCall @@ -73,7 +73,7 @@ class ErrorExpressionGenerator(statementGenerator: StatementGenerator) : Stateme val irErrorCall = IrErrorCallExpressionImpl(ktName.startOffset, ktName.endOffset, type, "") // TODO problem description? irErrorCall.explicitReceiver = (ktName.parent as? KtDotQualifiedExpression)?.let { ktParent -> if (ktParent.receiverExpression == ktName) null - else statementGenerator.generateExpression(ktParent.receiverExpression) + else ktParent.receiverExpression.genExpr() } irErrorCall diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/LoopExpressionGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/LoopExpressionGenerator.kt index e0015f3f53e..a91a3c9df29 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/LoopExpressionGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/LoopExpressionGenerator.kt @@ -36,7 +36,7 @@ class LoopExpressionGenerator(statementGenerator: StatementGenerator) : Statemen context.builtIns.unitType, IrStatementOrigin.WHILE_LOOP ) - irLoop.condition = statementGenerator.generateExpression(ktWhile.condition!!) + irLoop.condition = ktWhile.condition!!.genExpr() statementGenerator.bodyGenerator.putLoop(ktWhile, irLoop) @@ -44,7 +44,7 @@ class LoopExpressionGenerator(statementGenerator: StatementGenerator) : Statemen if (ktLoopBody is KtBlockExpression) generateWhileLoopBody(ktLoopBody) else - statementGenerator.generateExpression(ktLoopBody) + ktLoopBody.genExpr() } irLoop.label = getLoopLabel(ktWhile) @@ -64,10 +64,10 @@ class LoopExpressionGenerator(statementGenerator: StatementGenerator) : Statemen if (ktLoopBody is KtBlockExpression) generateDoWhileLoopBody(ktLoopBody) else - statementGenerator.generateExpression(ktLoopBody) + ktLoopBody.genExpr() } - irLoop.condition = statementGenerator.generateExpression(ktDoWhile.condition!!) + irLoop.condition = ktDoWhile.condition!!.genExpr() irLoop.label = getLoopLabel(ktDoWhile) @@ -79,14 +79,14 @@ class LoopExpressionGenerator(statementGenerator: StatementGenerator) : Statemen private fun generateWhileLoopBody(ktLoopBody: KtBlockExpression): IrExpression = IrBlockImpl( ktLoopBody.startOffset, ktLoopBody.endOffset, context.builtIns.unitType, null, - ktLoopBody.statements.map { statementGenerator.generateStatement(it) } + ktLoopBody.statements.map { it.genStmt() } ) private fun generateDoWhileLoopBody(ktLoopBody: KtBlockExpression): IrExpression = IrCompositeImpl( ktLoopBody.startOffset, ktLoopBody.endOffset, context.builtIns.unitType, null, - ktLoopBody.statements.map { statementGenerator.generateStatement(it) } + ktLoopBody.statements.map { it.genStmt() } ) fun generateBreak(ktBreak: KtBreakExpression): IrExpression { @@ -199,7 +199,7 @@ class LoopExpressionGenerator(statementGenerator: StatementGenerator) : Statemen } if (ktForBody != null) { - irInnerBody.statements.add(statementGenerator.generateExpression(ktForBody)) + irInnerBody.statements.add(ktForBody.genExpr()) } return irForBlock diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/OperatorExpressionGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/OperatorExpressionGenerator.kt index 7585b627c39..43891189930 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/OperatorExpressionGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/OperatorExpressionGenerator.kt @@ -33,6 +33,7 @@ import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi2ir.findSingleFunction import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.kotlin.resolve.checkers.PrimitiveNumericComparisonInfo import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.typeUtil.isPrimitiveNumberType @@ -89,7 +90,7 @@ class OperatorExpressionGenerator(statementGenerator: StatementGenerator) : Stat return IrTypeOperatorCallImpl( expression.startOffset, expression.endOffset, resultType, irOperator, rhsType, - statementGenerator.generateExpression(expression.left) + expression.left.genExpr() ) } @@ -100,7 +101,7 @@ class OperatorExpressionGenerator(statementGenerator: StatementGenerator) : Stat return IrTypeOperatorCallImpl( expression.startOffset, expression.endOffset, context.builtIns.booleanType, irOperator, - againstType, statementGenerator.generateExpression(expression.leftHandSide) + againstType, expression.leftHandSide.genExpr() ) } @@ -130,8 +131,8 @@ class OperatorExpressionGenerator(statementGenerator: StatementGenerator) : Stat private fun generateElvis(expression: KtBinaryExpression): IrExpression { val specialCallForElvis = getResolvedCall(expression)!! val resultType = specialCallForElvis.resultingDescriptor.returnType!! - val irArgument0 = statementGenerator.generateExpression(expression.left!!) - val irArgument1 = statementGenerator.generateExpression(expression.right!!) + val irArgument0 = expression.left!!.genExpr() + val irArgument1 = expression.right!!.genExpr() return irBlock(expression, IrStatementOrigin.ELVIS, resultType) { val temporary = irTemporary(irArgument0, "elvis_lhs") @@ -140,8 +141,8 @@ class OperatorExpressionGenerator(statementGenerator: StatementGenerator) : Stat } private fun generateBinaryBooleanOperator(expression: KtBinaryExpression, irOperator: IrStatementOrigin): IrExpression { - val irArgument0 = statementGenerator.generateExpression(expression.left!!) - val irArgument1 = statementGenerator.generateExpression(expression.right!!) + val irArgument0 = expression.left!!.genExpr() + val irArgument1 = expression.right!!.genExpr() return when (irOperator) { IrStatementOrigin.OROR -> context.oror(expression.startOffset, expression.endOffset, irArgument0, irArgument1) @@ -173,8 +174,8 @@ class OperatorExpressionGenerator(statementGenerator: StatementGenerator) : Stat } private fun generateIdentityOperator(expression: KtBinaryExpression, irOperator: IrStatementOrigin): IrExpression { - val irArgument0 = statementGenerator.generateExpression(expression.left!!) - val irArgument1 = statementGenerator.generateExpression(expression.right!!) + val irArgument0 = expression.left!!.genExpr() + val irArgument1 = expression.right!!.genExpr() val irIdentityEquals = IrBinaryPrimitiveImpl( expression.startOffset, expression.endOffset, irOperator, @@ -196,31 +197,27 @@ class OperatorExpressionGenerator(statementGenerator: StatementGenerator) : Stat } } - private fun KtExpression.generateAsPrimitiveNumericComparisonOperand(primitiveNumericComparisonType: KotlinType?) = - statementGenerator.generateExpression(this) - .promoteToPrimitiveNumericType( - getPrimitiveNumericComparisonOperandType(this), - primitiveNumericComparisonType - ) + private fun KtExpression.generateAsPrimitiveNumericComparisonOperand( + expressionType: KotlinType?, + comparisonType: KotlinType? + ) = genExpr().promoteToPrimitiveNumericType(expressionType, comparisonType) - private fun getPrimitiveNumericComparisonType(ktExpression: KtBinaryExpression) = - context.bindingContext[BindingContext.PRIMITIVE_NUMERIC_COMPARISON_TYPE, ktExpression] - - private fun getPrimitiveNumericComparisonOperandType(ktExpression: KtExpression) = - context.bindingContext[BindingContext.PRIMITIVE_NUMERIC_COMPARISON_OPERAND_TYPE, ktExpression] + private fun getPrimitiveNumericComparisonInfo(ktExpression: KtBinaryExpression) = + context.bindingContext[BindingContext.PRIMITIVE_NUMERIC_COMPARISON_INFO, ktExpression] private fun generateEqualityOperator(expression: KtBinaryExpression, irOperator: IrStatementOrigin): IrExpression { - val primitiveNumericComparisonType = getPrimitiveNumericComparisonType(expression) + val comparisonInfo = getPrimitiveNumericComparisonInfo(expression) + val comparisonType = comparisonInfo?.comparisonType - val eqeqSymbol = context.irBuiltIns.ieee754equalsFunByOperandType[primitiveNumericComparisonType]?.symbol + val eqeqSymbol = context.irBuiltIns.ieee754equalsFunByOperandType[comparisonType]?.symbol ?: context.irBuiltIns.eqeqSymbol val irEquals = IrBinaryPrimitiveImpl( expression.startOffset, expression.endOffset, irOperator, eqeqSymbol, - expression.left!!.generateAsPrimitiveNumericComparisonOperand(primitiveNumericComparisonType), - expression.right!!.generateAsPrimitiveNumericComparisonOperand(primitiveNumericComparisonType) + expression.left!!.generateAsPrimitiveNumericComparisonOperand(comparisonInfo?.leftType, comparisonType), + expression.right!!.generateAsPrimitiveNumericComparisonOperand(comparisonInfo?.rightType, comparisonType) ) return when (irOperator) { @@ -238,6 +235,33 @@ class OperatorExpressionGenerator(statementGenerator: StatementGenerator) : Stat } } + fun generateEquality( + startOffset: Int, + endOffset: Int, + irOperator: IrStatementOrigin, + arg1: IrExpression, + arg2: IrExpression, + comparisonInfo: PrimitiveNumericComparisonInfo? + ): IrExpression = + if (comparisonInfo != null) { + val comparisonType = comparisonInfo.comparisonType + val eqeqSymbol = + context.irBuiltIns.ieee754equalsFunByOperandType[comparisonType]?.symbol + ?: context.irBuiltIns.eqeqSymbol + IrBinaryPrimitiveImpl( + startOffset, endOffset, irOperator, + eqeqSymbol, + arg1.promoteToPrimitiveNumericType(comparisonInfo.leftType, comparisonType), + arg2.promoteToPrimitiveNumericType(comparisonInfo.rightType, comparisonType) + ) + } else { + IrBinaryPrimitiveImpl( + startOffset, endOffset, irOperator, + context.irBuiltIns.eqeqSymbol, + arg1, arg2 + ) + } + private fun IrExpression.promoteToPrimitiveNumericType(operandType: KotlinType?, targetType: KotlinType?): IrExpression { if (targetType == null) return this if (operandType == null) throw AssertionError("operandType should be non-null") @@ -290,14 +314,14 @@ class OperatorExpressionGenerator(statementGenerator: StatementGenerator) : Stat val startOffset = expression.startOffset val endOffset = expression.endOffset - val primitiveNumberComparisonType = getPrimitiveNumericComparisonType(expression) + val comparisonInfo = getPrimitiveNumericComparisonInfo(expression) - return if (primitiveNumberComparisonType != null) { + return if (comparisonInfo != null) { IrBinaryPrimitiveImpl( startOffset, endOffset, origin, - getComparisonOperatorSymbol(origin, primitiveNumberComparisonType), - expression.left!!.generateAsPrimitiveNumericComparisonOperand(primitiveNumberComparisonType), - expression.right!!.generateAsPrimitiveNumericComparisonOperand(primitiveNumberComparisonType) + getComparisonOperatorSymbol(origin, comparisonInfo.comparisonType), + expression.left!!.generateAsPrimitiveNumericComparisonOperand(comparisonInfo.leftType, comparisonInfo.comparisonType), + expression.right!!.generateAsPrimitiveNumericComparisonOperand(comparisonInfo.rightType, comparisonInfo.comparisonType) ) } else { IrBinaryPrimitiveImpl( @@ -327,7 +351,7 @@ class OperatorExpressionGenerator(statementGenerator: StatementGenerator) : Stat private fun generateExclExclOperator(expression: KtPostfixExpression, origin: IrStatementOrigin): IrExpression { val ktArgument = expression.baseExpression!! - val irArgument = statementGenerator.generateExpression(ktArgument) + val irArgument = ktArgument.genExpr() val ktOperator = expression.operationReference val resultType = irArgument.type.makeNotNullable() diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ReflectionReferencesGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ReflectionReferencesGenerator.kt index 6a5ad8f3fb4..69ab8bbffca 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ReflectionReferencesGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ReflectionReferencesGenerator.kt @@ -39,7 +39,7 @@ class ReflectionReferencesGenerator(statementGenerator: StatementGenerator) : St return if (lhs is DoubleColonLHS.Expression && !lhs.isObjectQualifier) { IrGetClassImpl( ktClassLiteral.startOffset, ktClassLiteral.endOffset, resultType, - statementGenerator.generateExpression(ktArgument) + ktArgument.genExpr() ) } else { val typeConstructorDeclaration = lhs.type.constructor.declarationDescriptor diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt index f66abd44ad9..6866d42f3da 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt @@ -407,4 +407,7 @@ class StatementGenerator( abstract class StatementGeneratorExtension(val statementGenerator: StatementGenerator) : GeneratorWithScope { override val scope: Scope get() = statementGenerator.scope override val context: GeneratorContext get() = statementGenerator.context + + fun KtExpression.genExpr() = statementGenerator.generateExpression(this) + fun KtExpression.genStmt() = statementGenerator.generateStatement(this) } \ No newline at end of file diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/TryCatchExpressionGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/TryCatchExpressionGenerator.kt index 98fe4bf329e..bc431732cfa 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/TryCatchExpressionGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/TryCatchExpressionGenerator.kt @@ -30,7 +30,7 @@ class TryCatchExpressionGenerator(statementGenerator: StatementGenerator) : Stat val resultType = getInferredTypeWithImplicitCastsOrFail(ktTry) val irTryCatch = IrTryImpl(ktTry.startOffset, ktTry.endOffset, resultType) - irTryCatch.tryResult = statementGenerator.generateExpression(ktTry.tryBlock) + irTryCatch.tryResult = ktTry.tryBlock.genExpr() for (ktCatchClause in ktTry.catchClauses) { val ktCatchParameter = ktCatchClause.catchParameter!! @@ -45,13 +45,13 @@ class TryCatchExpressionGenerator(statementGenerator: StatementGenerator) : Stat catchParameterDescriptor ) ).apply { - result = statementGenerator.generateExpression(ktCatchBody) + result = ktCatchBody.genExpr() } irTryCatch.catches.add(irCatch) } - irTryCatch.finallyExpression = ktTry.finallyBlock?.let { statementGenerator.generateExpression(it.finalExpression) } + irTryCatch.finallyExpression = ktTry.finallyBlock?.run { finalExpression.genExpr() } return irTryCatch } diff --git a/compiler/testData/ir/irText/classes/dataClasses.kt b/compiler/testData/ir/irText/classes/dataClasses.kt index 6aac50c8493..cf06270263d 100644 --- a/compiler/testData/ir/irText/classes/dataClasses.kt +++ b/compiler/testData/ir/irText/classes/dataClasses.kt @@ -1,3 +1,5 @@ data class Test1(val x: Int, val y: String, val z: Any) -data class Test2(val x: Any?) \ No newline at end of file +data class Test2(val x: Any?) + +data class Test3(val d: Double, val dn: Double?, val f: Float, val df: Float?) \ No newline at end of file diff --git a/compiler/testData/ir/irText/classes/dataClasses.txt b/compiler/testData/ir/irText/classes/dataClasses.txt index f9debd03098..410a503420a 100644 --- a/compiler/testData/ir/irText/classes/dataClasses.txt +++ b/compiler/testData/ir/irText/classes/dataClasses.txt @@ -270,4 +270,243 @@ FILE fqName: fileName:/dataClasses.kt CONST Boolean type=kotlin.Boolean value=false RETURN type=kotlin.Nothing from='equals(Any?): Boolean' CONST Boolean type=kotlin.Boolean value=true - + CLASS CLASS name:Test3 modality:FINAL visibility:public flags:data + $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:Test3 flags: + CONSTRUCTOR visibility:public <> (d:kotlin.Double, dn:kotlin.Double?, f:kotlin.Float, df:kotlin.Float?) returnType:Test3 flags: + VALUE_PARAMETER name:d index:0 type:kotlin.Double flags: + VALUE_PARAMETER name:dn index:1 type:kotlin.Double? flags: + VALUE_PARAMETER name:f index:2 type:kotlin.Float flags: + VALUE_PARAMETER name:df index:3 type:kotlin.Float? flags: + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'constructor Any()' + INSTANCE_INITIALIZER_CALL classDescriptor='Test3' + PROPERTY name:d type:kotlin.Double visibility:public modality:FINAL flags:val + FIELD PROPERTY_BACKING_FIELD name:d type:kotlin.Double visibility:public + EXPRESSION_BODY + GET_VAR 'value-parameter d: Double' type=kotlin.Double origin=INITIALIZE_PROPERTY_FROM_PARAMETER + FUN DEFAULT_PROPERTY_ACCESSOR name: visibility:public modality:FINAL <> ($this:Test3) returnType:Double flags: + $this: VALUE_PARAMETER name: type:Test3 flags: + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): Double' + GET_FIELD 'd: Double' type=kotlin.Double origin=null + receiver: GET_VAR 'this@Test3: Test3' type=Test3 origin=null + PROPERTY name:dn type:kotlin.Double? visibility:public modality:FINAL flags:val + FIELD PROPERTY_BACKING_FIELD name:dn type:kotlin.Double? visibility:public + EXPRESSION_BODY + GET_VAR 'value-parameter dn: Double?' type=kotlin.Double? origin=INITIALIZE_PROPERTY_FROM_PARAMETER + FUN DEFAULT_PROPERTY_ACCESSOR name: visibility:public modality:FINAL <> ($this:Test3) returnType:Double? flags: + $this: VALUE_PARAMETER name: type:Test3 flags: + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): Double?' + GET_FIELD 'dn: Double?' type=kotlin.Double? origin=null + receiver: GET_VAR 'this@Test3: Test3' type=Test3 origin=null + PROPERTY name:f type:kotlin.Float visibility:public modality:FINAL flags:val + FIELD PROPERTY_BACKING_FIELD name:f type:kotlin.Float visibility:public + EXPRESSION_BODY + GET_VAR 'value-parameter f: Float' type=kotlin.Float origin=INITIALIZE_PROPERTY_FROM_PARAMETER + FUN DEFAULT_PROPERTY_ACCESSOR name: visibility:public modality:FINAL <> ($this:Test3) returnType:Float flags: + $this: VALUE_PARAMETER name: type:Test3 flags: + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): Float' + GET_FIELD 'f: Float' type=kotlin.Float origin=null + receiver: GET_VAR 'this@Test3: Test3' type=Test3 origin=null + PROPERTY name:df type:kotlin.Float? visibility:public modality:FINAL flags:val + FIELD PROPERTY_BACKING_FIELD name:df type:kotlin.Float? visibility:public + EXPRESSION_BODY + GET_VAR 'value-parameter df: Float?' type=kotlin.Float? origin=INITIALIZE_PROPERTY_FROM_PARAMETER + FUN DEFAULT_PROPERTY_ACCESSOR name: visibility:public modality:FINAL <> ($this:Test3) returnType:Float? flags: + $this: VALUE_PARAMETER name: type:Test3 flags: + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): Float?' + GET_FIELD 'df: Float?' type=kotlin.Float? origin=null + receiver: GET_VAR 'this@Test3: Test3' type=Test3 origin=null + FUN GENERATED_DATA_CLASS_MEMBER name:component1 visibility:public modality:FINAL <> ($this:Test3) returnType:Double flags: + $this: VALUE_PARAMETER name: type:Test3 flags: + BLOCK_BODY + RETURN type=kotlin.Nothing from='component1(): Double' + CALL '(): Double' type=kotlin.Double origin=GET_PROPERTY + $this: GET_VAR 'this@Test3: Test3' type=Test3 origin=null + FUN GENERATED_DATA_CLASS_MEMBER name:component2 visibility:public modality:FINAL <> ($this:Test3) returnType:Double? flags: + $this: VALUE_PARAMETER name: type:Test3 flags: + BLOCK_BODY + RETURN type=kotlin.Nothing from='component2(): Double?' + CALL '(): Double?' type=kotlin.Double? origin=GET_PROPERTY + $this: GET_VAR 'this@Test3: Test3' type=Test3 origin=null + FUN GENERATED_DATA_CLASS_MEMBER name:component3 visibility:public modality:FINAL <> ($this:Test3) returnType:Float flags: + $this: VALUE_PARAMETER name: type:Test3 flags: + BLOCK_BODY + RETURN type=kotlin.Nothing from='component3(): Float' + CALL '(): Float' type=kotlin.Float origin=GET_PROPERTY + $this: GET_VAR 'this@Test3: Test3' type=Test3 origin=null + FUN GENERATED_DATA_CLASS_MEMBER name:component4 visibility:public modality:FINAL <> ($this:Test3) returnType:Float? flags: + $this: VALUE_PARAMETER name: type:Test3 flags: + BLOCK_BODY + RETURN type=kotlin.Nothing from='component4(): Float?' + CALL '(): Float?' type=kotlin.Float? origin=GET_PROPERTY + $this: GET_VAR 'this@Test3: Test3' type=Test3 origin=null + FUN GENERATED_DATA_CLASS_MEMBER name:copy visibility:public modality:FINAL <> ($this:Test3, d:kotlin.Double, dn:kotlin.Double?, f:kotlin.Float, df:kotlin.Float?) returnType:Test3 flags: + $this: VALUE_PARAMETER name: type:Test3 flags: + VALUE_PARAMETER name:d index:0 type:kotlin.Double flags: + EXPRESSION_BODY + CALL '(): Double' type=kotlin.Double origin=GET_PROPERTY + $this: GET_VAR 'this@Test3: Test3' type=Test3 origin=null + VALUE_PARAMETER name:dn index:1 type:kotlin.Double? flags: + EXPRESSION_BODY + CALL '(): Double?' type=kotlin.Double? origin=GET_PROPERTY + $this: GET_VAR 'this@Test3: Test3' type=Test3 origin=null + VALUE_PARAMETER name:f index:2 type:kotlin.Float flags: + EXPRESSION_BODY + CALL '(): Float' type=kotlin.Float origin=GET_PROPERTY + $this: GET_VAR 'this@Test3: Test3' type=Test3 origin=null + VALUE_PARAMETER name:df index:3 type:kotlin.Float? flags: + EXPRESSION_BODY + CALL '(): Float?' type=kotlin.Float? origin=GET_PROPERTY + $this: GET_VAR 'this@Test3: Test3' type=Test3 origin=null + BLOCK_BODY + RETURN type=kotlin.Nothing from='copy(Double = ..., Double? = ..., Float = ..., Float? = ...): Test3' + CALL 'constructor Test3(Double, Double?, Float, Float?)' type=Test3 origin=null + d: GET_VAR 'value-parameter d: Double = ...' type=kotlin.Double origin=null + dn: GET_VAR 'value-parameter dn: Double? = ...' type=kotlin.Double? origin=null + f: GET_VAR 'value-parameter f: Float = ...' type=kotlin.Float origin=null + df: GET_VAR 'value-parameter df: Float? = ...' type=kotlin.Float? origin=null + FUN GENERATED_DATA_CLASS_MEMBER name:toString visibility:public modality:OPEN <> ($this:Test3) returnType:String flags: + $this: VALUE_PARAMETER name: type:Test3 flags: + BLOCK_BODY + RETURN type=kotlin.Nothing from='toString(): String' + STRING_CONCATENATION type=kotlin.String + CONST String type=kotlin.String value=Test3( + CONST String type=kotlin.String value=d= + CALL '(): Double' type=kotlin.Double origin=GET_PROPERTY + $this: GET_VAR 'this@Test3: Test3' type=Test3 origin=null + CONST String type=kotlin.String value=, + CONST String type=kotlin.String value=dn= + CALL '(): Double?' type=kotlin.Double? origin=GET_PROPERTY + $this: GET_VAR 'this@Test3: Test3' type=Test3 origin=null + CONST String type=kotlin.String value=, + CONST String type=kotlin.String value=f= + CALL '(): Float' type=kotlin.Float origin=GET_PROPERTY + $this: GET_VAR 'this@Test3: Test3' type=Test3 origin=null + CONST String type=kotlin.String value=, + CONST String type=kotlin.String value=df= + CALL '(): Float?' type=kotlin.Float? origin=GET_PROPERTY + $this: GET_VAR 'this@Test3: Test3' type=Test3 origin=null + CONST String type=kotlin.String value=) + FUN GENERATED_DATA_CLASS_MEMBER name:hashCode visibility:public modality:OPEN <> ($this:Test3) returnType:Int flags: + $this: VALUE_PARAMETER name: type:Test3 flags: + BLOCK_BODY + VAR IR_TEMPORARY_VARIABLE name:tmp0_result type:kotlin.Int flags:var + CONST Int type=kotlin.Int value=0 + SET_VAR 'tmp0_result: Int' type=kotlin.Unit origin=EQ + CALL 'hashCode(): Int' type=kotlin.Int origin=null + $this: CALL '(): Double' type=kotlin.Double origin=GET_PROPERTY + $this: GET_VAR 'this@Test3: Test3' type=Test3 origin=null + SET_VAR 'tmp0_result: Int' type=kotlin.Unit origin=EQ + CALL 'plus(Int): Int' type=kotlin.Int origin=null + $this: CALL 'times(Int): Int' type=kotlin.Int origin=null + $this: GET_VAR 'tmp0_result: Int' type=kotlin.Int origin=null + other: CONST Int type=kotlin.Int value=31 + other: BLOCK type=kotlin.Int origin=null + VAR IR_TEMPORARY_VARIABLE name:tmp1 type:kotlin.Double? flags:val + CALL '(): Double?' type=kotlin.Double? origin=GET_PROPERTY + $this: GET_VAR 'this@Test3: Test3' type=Test3 origin=null + WHEN type=kotlin.Int origin=null + BRANCH + if: CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EQEQ + arg0: GET_VAR 'tmp1: Double?' type=kotlin.Double? origin=null + arg1: CONST Null type=kotlin.Nothing? value=null + then: CONST Int type=kotlin.Int value=0 + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: CALL 'hashCode(): Int' type=kotlin.Int origin=null + $this: GET_VAR 'tmp1: Double?' type=kotlin.Double? origin=null + SET_VAR 'tmp0_result: Int' type=kotlin.Unit origin=EQ + CALL 'plus(Int): Int' type=kotlin.Int origin=null + $this: CALL 'times(Int): Int' type=kotlin.Int origin=null + $this: GET_VAR 'tmp0_result: Int' type=kotlin.Int origin=null + other: CONST Int type=kotlin.Int value=31 + other: CALL 'hashCode(): Int' type=kotlin.Int origin=null + $this: CALL '(): Float' type=kotlin.Float origin=GET_PROPERTY + $this: GET_VAR 'this@Test3: Test3' type=Test3 origin=null + SET_VAR 'tmp0_result: Int' type=kotlin.Unit origin=EQ + CALL 'plus(Int): Int' type=kotlin.Int origin=null + $this: CALL 'times(Int): Int' type=kotlin.Int origin=null + $this: GET_VAR 'tmp0_result: Int' type=kotlin.Int origin=null + other: CONST Int type=kotlin.Int value=31 + other: BLOCK type=kotlin.Int origin=null + VAR IR_TEMPORARY_VARIABLE name:tmp2 type:kotlin.Float? flags:val + CALL '(): Float?' type=kotlin.Float? origin=GET_PROPERTY + $this: GET_VAR 'this@Test3: Test3' type=Test3 origin=null + WHEN type=kotlin.Int origin=null + BRANCH + if: CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EQEQ + arg0: GET_VAR 'tmp2: Float?' type=kotlin.Float? origin=null + arg1: CONST Null type=kotlin.Nothing? value=null + then: CONST Int type=kotlin.Int value=0 + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: CALL 'hashCode(): Int' type=kotlin.Int origin=null + $this: GET_VAR 'tmp2: Float?' type=kotlin.Float? origin=null + RETURN type=kotlin.Nothing from='hashCode(): Int' + GET_VAR 'tmp0_result: Int' type=kotlin.Int origin=null + FUN GENERATED_DATA_CLASS_MEMBER name:equals visibility:public modality:OPEN <> ($this:Test3, other:kotlin.Any?) returnType:Boolean flags: + $this: VALUE_PARAMETER name: type:Test3 flags: + VALUE_PARAMETER name:other index:0 type:kotlin.Any? flags: + BLOCK_BODY + WHEN type=kotlin.Unit origin=null + BRANCH + if: CALL 'EQEQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EQEQEQ + arg0: GET_VAR 'this@Test3: Test3' type=Test3 origin=null + arg1: GET_VAR 'value-parameter other: Any?' type=kotlin.Any? origin=null + then: RETURN type=kotlin.Nothing from='equals(Any?): Boolean' + CONST Boolean type=kotlin.Boolean value=true + WHEN type=kotlin.Unit origin=null + BRANCH + if: TYPE_OP type=kotlin.Boolean origin=NOT_INSTANCEOF typeOperand=Test3 + GET_VAR 'value-parameter other: Any?' type=kotlin.Any? origin=null + then: RETURN type=kotlin.Nothing from='equals(Any?): Boolean' + CONST Boolean type=kotlin.Boolean value=false + VAR IR_TEMPORARY_VARIABLE name:tmp0_other_with_cast type:Test3 flags:val + TYPE_OP type=Test3 origin=CAST typeOperand=Test3 + GET_VAR 'value-parameter other: Any?' type=kotlin.Any? origin=null + WHEN type=kotlin.Unit origin=null + BRANCH + if: CALL 'NOT(Boolean): Boolean' type=kotlin.Boolean origin=EXCLEQ + arg0: CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EXCLEQ + arg0: CALL '(): Double' type=kotlin.Double origin=GET_PROPERTY + $this: GET_VAR 'this@Test3: Test3' type=Test3 origin=null + arg1: CALL '(): Double' type=kotlin.Double origin=GET_PROPERTY + $this: GET_VAR 'tmp0_other_with_cast: Test3' type=Test3 origin=null + then: RETURN type=kotlin.Nothing from='equals(Any?): Boolean' + CONST Boolean type=kotlin.Boolean value=false + WHEN type=kotlin.Unit origin=null + BRANCH + if: CALL 'NOT(Boolean): Boolean' type=kotlin.Boolean origin=EXCLEQ + arg0: CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EXCLEQ + arg0: CALL '(): Double?' type=kotlin.Double? origin=GET_PROPERTY + $this: GET_VAR 'this@Test3: Test3' type=Test3 origin=null + arg1: CALL '(): Double?' type=kotlin.Double? origin=GET_PROPERTY + $this: GET_VAR 'tmp0_other_with_cast: Test3' type=Test3 origin=null + then: RETURN type=kotlin.Nothing from='equals(Any?): Boolean' + CONST Boolean type=kotlin.Boolean value=false + WHEN type=kotlin.Unit origin=null + BRANCH + if: CALL 'NOT(Boolean): Boolean' type=kotlin.Boolean origin=EXCLEQ + arg0: CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EXCLEQ + arg0: CALL '(): Float' type=kotlin.Float origin=GET_PROPERTY + $this: GET_VAR 'this@Test3: Test3' type=Test3 origin=null + arg1: CALL '(): Float' type=kotlin.Float origin=GET_PROPERTY + $this: GET_VAR 'tmp0_other_with_cast: Test3' type=Test3 origin=null + then: RETURN type=kotlin.Nothing from='equals(Any?): Boolean' + CONST Boolean type=kotlin.Boolean value=false + WHEN type=kotlin.Unit origin=null + BRANCH + if: CALL 'NOT(Boolean): Boolean' type=kotlin.Boolean origin=EXCLEQ + arg0: CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EXCLEQ + arg0: CALL '(): Float?' type=kotlin.Float? origin=GET_PROPERTY + $this: GET_VAR 'this@Test3: Test3' type=Test3 origin=null + arg1: CALL '(): Float?' type=kotlin.Float? origin=GET_PROPERTY + $this: GET_VAR 'tmp0_other_with_cast: Test3' type=Test3 origin=null + then: RETURN type=kotlin.Nothing from='equals(Any?): Boolean' + CONST Boolean type=kotlin.Boolean value=false + RETURN type=kotlin.Nothing from='equals(Any?): Boolean' + CONST Boolean type=kotlin.Boolean value=true diff --git a/compiler/testData/ir/irText/expressions/floatingPointComparisons/eqeqRhsConditionPossiblyAffectingLhs.kt b/compiler/testData/ir/irText/expressions/floatingPointComparisons/eqeqRhsConditionPossiblyAffectingLhs.kt new file mode 100644 index 00000000000..ef474386a07 --- /dev/null +++ b/compiler/testData/ir/irText/expressions/floatingPointComparisons/eqeqRhsConditionPossiblyAffectingLhs.kt @@ -0,0 +1,2 @@ +fun test(x: Any) = + x == (if (x !is Double) null!! else x) \ No newline at end of file diff --git a/compiler/testData/ir/irText/expressions/floatingPointComparisons/eqeqRhsConditionPossiblyAffectingLhs.txt b/compiler/testData/ir/irText/expressions/floatingPointComparisons/eqeqRhsConditionPossiblyAffectingLhs.txt new file mode 100644 index 00000000000..8b0c335cc03 --- /dev/null +++ b/compiler/testData/ir/irText/expressions/floatingPointComparisons/eqeqRhsConditionPossiblyAffectingLhs.txt @@ -0,0 +1,27 @@ +FILE fqName: fileName:/eqeqRhsConditionPossiblyAffectingLhs.kt + FUN name:test visibility:public modality:FINAL <> (x:kotlin.Any) returnType:Boolean flags: + VALUE_PARAMETER name:x index:0 type:kotlin.Any flags: + BLOCK_BODY + RETURN type=kotlin.Nothing from='test(Any): Boolean' + CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EQEQ + arg0: GET_VAR 'value-parameter x: Any' type=kotlin.Any origin=null + arg1: WHEN type=kotlin.Double origin=null + BRANCH + if: TYPE_OP type=kotlin.Boolean origin=NOT_INSTANCEOF typeOperand=kotlin.Double + GET_VAR 'value-parameter x: Any' type=kotlin.Any origin=null + then: BLOCK type=kotlin.Nothing origin=EXCLEXCL + VAR IR_TEMPORARY_VARIABLE name:tmp0_notnull type:kotlin.Nothing? flags:val + CONST Null type=kotlin.Nothing? value=null + WHEN type=kotlin.Nothing origin=null + BRANCH + if: CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EQEQ + arg0: GET_VAR 'tmp0_notnull: Nothing?' type=kotlin.Nothing? origin=null + arg1: CONST Null type=kotlin.Nothing? value=null + then: CALL 'THROW_NPE(): Nothing' type=kotlin.Nothing origin=EXCLEXCL + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: GET_VAR 'tmp0_notnull: Nothing?' type=kotlin.Nothing? origin=null + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: TYPE_OP type=kotlin.Double origin=IMPLICIT_CAST typeOperand=kotlin.Double + GET_VAR 'value-parameter x: Any' type=kotlin.Any origin=null diff --git a/compiler/testData/ir/irText/expressions/floatingPointComparisons/whenByFloatingPoint.kt b/compiler/testData/ir/irText/expressions/floatingPointComparisons/whenByFloatingPoint.kt new file mode 100644 index 00000000000..d5638ae92ce --- /dev/null +++ b/compiler/testData/ir/irText/expressions/floatingPointComparisons/whenByFloatingPoint.kt @@ -0,0 +1,48 @@ +fun testSimple(x: Double) = + when (x) { + 0.0 -> 0 + else -> 1 + } + +fun testSmartCastInWhenSubject(x: Any): Int { + if (x !is Double) return -1 + return when (x) { + 0.0 -> 0 + else -> 1 + } +} + +fun testSmartCastInWhenCondition(x: Double, y: Any): Int { + if (y !is Double) return -1 + return when (x) { + y -> 0 + else -> 1 + } +} + +fun testSmartCastInWhenConditionInBranch(x: Any) = + when (x) { + !is Double -> -1 + 0.0 -> 0 + else -> 1 + } + +fun testSmartCastToDifferentTypes(x: Any, y: Any): Int { + if (x !is Double) return -1 + if (y !is Float) return -1 + return when (x) { + y -> 0 + else -> 1 + } +} + +fun foo(x: Double) = x + +fun testWithPrematureExitInConditionSubexpression(x: Any): Int { + return when (x) { + foo( + if (x !is Double) return 42 else x + ) -> 0 + else -> 1 + } +} \ No newline at end of file diff --git a/compiler/testData/ir/irText/expressions/floatingPointComparisons/whenByFloatingPoint.txt b/compiler/testData/ir/irText/expressions/floatingPointComparisons/whenByFloatingPoint.txt new file mode 100644 index 00000000000..7909958b5d9 --- /dev/null +++ b/compiler/testData/ir/irText/expressions/floatingPointComparisons/whenByFloatingPoint.txt @@ -0,0 +1,148 @@ +FILE fqName: fileName:/whenByFloatingPoint.kt + FUN name:testSimple visibility:public modality:FINAL <> (x:kotlin.Double) returnType:Int flags: + VALUE_PARAMETER name:x index:0 type:kotlin.Double flags: + BLOCK_BODY + RETURN type=kotlin.Nothing from='testSimple(Double): Int' + BLOCK type=kotlin.Int origin=WHEN + VAR IR_TEMPORARY_VARIABLE name:tmp0_subject type:kotlin.Double flags:val + GET_VAR 'value-parameter x: Double' type=kotlin.Double origin=null + WHEN type=kotlin.Int origin=WHEN + BRANCH + if: CALL 'ieee754equals(Double?, Double?): Boolean' type=kotlin.Boolean origin=EQEQ + arg0: GET_VAR 'tmp0_subject: Double' type=kotlin.Double origin=null + arg1: CONST Double type=kotlin.Double value=0.0 + then: CONST Int type=kotlin.Int value=0 + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: CONST Int type=kotlin.Int value=1 + FUN name:testSmartCastInWhenSubject visibility:public modality:FINAL <> (x:kotlin.Any) returnType:Int flags: + VALUE_PARAMETER name:x index:0 type:kotlin.Any flags: + BLOCK_BODY + WHEN type=kotlin.Unit origin=null + BRANCH + if: TYPE_OP type=kotlin.Boolean origin=NOT_INSTANCEOF typeOperand=kotlin.Double + GET_VAR 'value-parameter x: Any' type=kotlin.Any origin=null + then: RETURN type=kotlin.Nothing from='testSmartCastInWhenSubject(Any): Int' + CONST Int type=kotlin.Int value=-1 + RETURN type=kotlin.Nothing from='testSmartCastInWhenSubject(Any): Int' + BLOCK type=kotlin.Int origin=WHEN + VAR IR_TEMPORARY_VARIABLE name:tmp0_subject type:kotlin.Any flags:val + GET_VAR 'value-parameter x: Any' type=kotlin.Any origin=null + WHEN type=kotlin.Int origin=WHEN + BRANCH + if: CALL 'ieee754equals(Double?, Double?): Boolean' type=kotlin.Boolean origin=EQEQ + arg0: TYPE_OP type=kotlin.Double origin=IMPLICIT_CAST typeOperand=kotlin.Double + GET_VAR 'tmp0_subject: Any' type=kotlin.Any origin=null + arg1: CONST Double type=kotlin.Double value=0.0 + then: CONST Int type=kotlin.Int value=0 + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: CONST Int type=kotlin.Int value=1 + FUN name:testSmartCastInWhenCondition visibility:public modality:FINAL <> (x:kotlin.Double, y:kotlin.Any) returnType:Int flags: + VALUE_PARAMETER name:x index:0 type:kotlin.Double flags: + VALUE_PARAMETER name:y index:1 type:kotlin.Any flags: + BLOCK_BODY + WHEN type=kotlin.Unit origin=null + BRANCH + if: TYPE_OP type=kotlin.Boolean origin=NOT_INSTANCEOF typeOperand=kotlin.Double + GET_VAR 'value-parameter y: Any' type=kotlin.Any origin=null + then: RETURN type=kotlin.Nothing from='testSmartCastInWhenCondition(Double, Any): Int' + CONST Int type=kotlin.Int value=-1 + RETURN type=kotlin.Nothing from='testSmartCastInWhenCondition(Double, Any): Int' + BLOCK type=kotlin.Int origin=WHEN + VAR IR_TEMPORARY_VARIABLE name:tmp0_subject type:kotlin.Double flags:val + GET_VAR 'value-parameter x: Double' type=kotlin.Double origin=null + WHEN type=kotlin.Int origin=WHEN + BRANCH + if: CALL 'ieee754equals(Double?, Double?): Boolean' type=kotlin.Boolean origin=EQEQ + arg0: GET_VAR 'tmp0_subject: Double' type=kotlin.Double origin=null + arg1: TYPE_OP type=kotlin.Double origin=IMPLICIT_CAST typeOperand=kotlin.Double + GET_VAR 'value-parameter y: Any' type=kotlin.Any origin=null + then: CONST Int type=kotlin.Int value=0 + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: CONST Int type=kotlin.Int value=1 + FUN name:testSmartCastInWhenConditionInBranch visibility:public modality:FINAL <> (x:kotlin.Any) returnType:Int flags: + VALUE_PARAMETER name:x index:0 type:kotlin.Any flags: + BLOCK_BODY + RETURN type=kotlin.Nothing from='testSmartCastInWhenConditionInBranch(Any): Int' + BLOCK type=kotlin.Int origin=WHEN + VAR IR_TEMPORARY_VARIABLE name:tmp0_subject type:kotlin.Any flags:val + GET_VAR 'value-parameter x: Any' type=kotlin.Any origin=null + WHEN type=kotlin.Int origin=WHEN + BRANCH + if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=kotlin.Double + GET_VAR 'tmp0_subject: Any' type=kotlin.Any origin=null + then: CONST Int type=kotlin.Int value=-1 + BRANCH + if: CALL 'ieee754equals(Double?, Double?): Boolean' type=kotlin.Boolean origin=EQEQ + arg0: TYPE_OP type=kotlin.Double origin=IMPLICIT_CAST typeOperand=kotlin.Double + GET_VAR 'tmp0_subject: Any' type=kotlin.Any origin=null + arg1: CONST Double type=kotlin.Double value=0.0 + then: CONST Int type=kotlin.Int value=0 + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: CONST Int type=kotlin.Int value=1 + FUN name:testSmartCastToDifferentTypes visibility:public modality:FINAL <> (x:kotlin.Any, y:kotlin.Any) returnType:Int flags: + VALUE_PARAMETER name:x index:0 type:kotlin.Any flags: + VALUE_PARAMETER name:y index:1 type:kotlin.Any flags: + BLOCK_BODY + WHEN type=kotlin.Unit origin=null + BRANCH + if: TYPE_OP type=kotlin.Boolean origin=NOT_INSTANCEOF typeOperand=kotlin.Double + GET_VAR 'value-parameter x: Any' type=kotlin.Any origin=null + then: RETURN type=kotlin.Nothing from='testSmartCastToDifferentTypes(Any, Any): Int' + CONST Int type=kotlin.Int value=-1 + WHEN type=kotlin.Unit origin=null + BRANCH + if: TYPE_OP type=kotlin.Boolean origin=NOT_INSTANCEOF typeOperand=kotlin.Float + GET_VAR 'value-parameter y: Any' type=kotlin.Any origin=null + then: RETURN type=kotlin.Nothing from='testSmartCastToDifferentTypes(Any, Any): Int' + CONST Int type=kotlin.Int value=-1 + RETURN type=kotlin.Nothing from='testSmartCastToDifferentTypes(Any, Any): Int' + BLOCK type=kotlin.Int origin=WHEN + VAR IR_TEMPORARY_VARIABLE name:tmp0_subject type:kotlin.Any flags:val + GET_VAR 'value-parameter x: Any' type=kotlin.Any origin=null + WHEN type=kotlin.Int origin=WHEN + BRANCH + if: CALL 'ieee754equals(Double?, Double?): Boolean' type=kotlin.Boolean origin=EQEQ + arg0: TYPE_OP type=kotlin.Double origin=IMPLICIT_CAST typeOperand=kotlin.Double + GET_VAR 'tmp0_subject: Any' type=kotlin.Any origin=null + arg1: CALL 'toDouble(): Double' type=kotlin.Double origin=null + $this: TYPE_OP type=kotlin.Float origin=IMPLICIT_CAST typeOperand=kotlin.Float + GET_VAR 'value-parameter y: Any' type=kotlin.Any origin=null + then: CONST Int type=kotlin.Int value=0 + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: CONST Int type=kotlin.Int value=1 + FUN name:foo visibility:public modality:FINAL <> (x:kotlin.Double) returnType:Double flags: + VALUE_PARAMETER name:x index:0 type:kotlin.Double flags: + BLOCK_BODY + RETURN type=kotlin.Nothing from='foo(Double): Double' + GET_VAR 'value-parameter x: Double' type=kotlin.Double origin=null + FUN name:testWithPrematureExitInConditionSubexpression visibility:public modality:FINAL <> (x:kotlin.Any) returnType:Int flags: + VALUE_PARAMETER name:x index:0 type:kotlin.Any flags: + BLOCK_BODY + RETURN type=kotlin.Nothing from='testWithPrematureExitInConditionSubexpression(Any): Int' + BLOCK type=kotlin.Int origin=WHEN + VAR IR_TEMPORARY_VARIABLE name:tmp0_subject type:kotlin.Any flags:val + GET_VAR 'value-parameter x: Any' type=kotlin.Any origin=null + WHEN type=kotlin.Int origin=WHEN + BRANCH + if: CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EQEQ + arg0: GET_VAR 'tmp0_subject: Any' type=kotlin.Any origin=null + arg1: CALL 'foo(Double): Double' type=kotlin.Double origin=null + x: WHEN type=kotlin.Double origin=null + BRANCH + if: TYPE_OP type=kotlin.Boolean origin=NOT_INSTANCEOF typeOperand=kotlin.Double + GET_VAR 'value-parameter x: Any' type=kotlin.Any origin=null + then: RETURN type=kotlin.Nothing from='testWithPrematureExitInConditionSubexpression(Any): Int' + CONST Int type=kotlin.Int value=42 + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: TYPE_OP type=kotlin.Double origin=IMPLICIT_CAST typeOperand=kotlin.Double + GET_VAR 'value-parameter x: Any' type=kotlin.Any origin=null + then: CONST Int type=kotlin.Int value=0 + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: CONST Int type=kotlin.Int value=1 diff --git a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java index e99cc595f5f..f32bbb4dc7e 100644 --- a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java @@ -1010,6 +1010,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase { doTest(fileName); } + @TestMetadata("eqeqRhsConditionPossiblyAffectingLhs.kt") + public void testEqeqRhsConditionPossiblyAffectingLhs() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/expressions/floatingPointComparisons/eqeqRhsConditionPossiblyAffectingLhs.kt"); + doTest(fileName); + } + @TestMetadata("floatingPointCompareTo.kt") public void testFloatingPointCompareTo() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/expressions/floatingPointComparisons/floatingPointCompareTo.kt"); @@ -1051,6 +1057,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/expressions/floatingPointComparisons/nullableFloatingPointEqeq.kt"); doTest(fileName); } + + @TestMetadata("whenByFloatingPoint.kt") + public void testWhenByFloatingPoint() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/expressions/floatingPointComparisons/whenByFloatingPoint.kt"); + doTest(fileName); + } } }