Handle equality checks for 'when' and data classes

This commit is contained in:
Dmitry Petrov
2018-02-06 17:51:12 +03:00
parent 299eb24ca9
commit 00325ae539
19 changed files with 631 additions and 89 deletions
@@ -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.ExplicitSmartCasts;
import org.jetbrains.kotlin.resolve.calls.smartcasts.ImplicitSmartCasts; import org.jetbrains.kotlin.resolve.calls.smartcasts.ImplicitSmartCasts;
import org.jetbrains.kotlin.resolve.calls.tower.KotlinResolutionCallbacksImpl; 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.constants.CompileTimeConstant;
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics; import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics;
import org.jetbrains.kotlin.resolve.scopes.LexicalScope; import org.jetbrains.kotlin.resolve.scopes.LexicalScope;
@@ -267,8 +268,7 @@ public interface BindingContext {
WritableSlice<KtFunction, KotlinResolutionCallbacksImpl.LambdaInfo> NEW_INFERENCE_LAMBDA_INFO = new BasicWritableSlice<>(DO_NOTHING); WritableSlice<KtFunction, KotlinResolutionCallbacksImpl.LambdaInfo> NEW_INFERENCE_LAMBDA_INFO = new BasicWritableSlice<>(DO_NOTHING);
WritableSlice<KtBinaryExpression, KotlinType> PRIMITIVE_NUMERIC_COMPARISON_TYPE = Slices.createSimpleSlice(); WritableSlice<KtExpression, PrimitiveNumericComparisonInfo> PRIMITIVE_NUMERIC_COMPARISON_INFO = Slices.createSimpleSlice();
WritableSlice<KtExpression, KotlinType> PRIMITIVE_NUMERIC_COMPARISON_OPERAND_TYPE = Slices.createSimpleSlice();
@SuppressWarnings("UnusedDeclaration") @SuppressWarnings("UnusedDeclaration")
@Deprecated // This field is needed only for the side effects of its initializer @Deprecated // This field is needed only for the side effects of its initializer
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtBinaryExpression import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.resolve.BindingContext 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.CallChecker
import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall 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.KotlinType
import org.jetbrains.kotlin.types.typeUtil.* import org.jetbrains.kotlin.types.typeUtil.*
class PrimitiveNumericComparisonInfo(
val comparisonType: KotlinType,
val leftType: KotlinType,
val rightType: KotlinType
)
object PrimitiveNumericComparisonCallChecker : CallChecker { object PrimitiveNumericComparisonCallChecker : CallChecker {
private val comparisonOperatorTokens = setOf(KtTokens.EQEQ, KtTokens.EXCLEQ, KtTokens.LT, KtTokens.LTEQ, KtTokens.GT, KtTokens.GTEQ) 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 leftExpr = binaryExpression.left ?: return
val rightExpr = binaryExpression.right ?: return val rightExpr = binaryExpression.right ?: return
val leftType = context.getInferredPrimitiveNumericType(leftExpr) ?: return val leftTypes = context.getStableTypesForExpression(leftExpr)
val rightType = context.getInferredPrimitiveNumericType(rightExpr) ?: return val rightTypes = context.getStableTypesForExpression(rightExpr)
context.trace.record(BindingContext.PRIMITIVE_NUMERIC_COMPARISON_OPERAND_TYPE, leftExpr, leftType) inferPrimitiveNumericComparisonType(context.trace, leftTypes, rightTypes, binaryExpression)
context.trace.record(BindingContext.PRIMITIVE_NUMERIC_COMPARISON_OPERAND_TYPE, rightExpr, rightType) }
val leastCommonType = leastCommonPrimitiveNumericType(leftType, rightType) fun inferPrimitiveNumericComparisonType(
trace: BindingTrace,
leftTypes: List<KotlinType>,
rightTypes: List<KotlinType>,
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 { private fun leastCommonPrimitiveNumericType(t1: KotlinType, t2: KotlinType): KotlinType {
@@ -60,14 +79,14 @@ object PrimitiveNumericComparisonCallChecker : CallChecker {
else -> this else -> this
} }
private fun CallCheckerContext.getInferredPrimitiveNumericType(expression: KtExpression): KotlinType? { private fun CallCheckerContext.getStableTypesForExpression(expression: KtExpression): List<KotlinType> {
val type = trace.bindingContext.getType(expression) ?: return null val type = trace.bindingContext.getType(expression) ?: return emptyList()
val dataFlowValue = DataFlowValueFactory.createDataFlowValue( val dataFlowValue = DataFlowValueFactory.createDataFlowValue(
expression, type, trace.bindingContext, resolutionContext.scope.ownerDescriptor 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) val stableTypes = dataFlowInfo.getStableTypes(dataFlowValue, languageVersionSettings)
return (listOf(type) + stableTypes).findPrimitiveType() return listOf(type) + stableTypes
} }
private fun List<KotlinType>.findPrimitiveType() = private fun List<KotlinType>.findPrimitiveType() =
@@ -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.DataFlowValue
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.util.CallMaker 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.*
import org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE import org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
@@ -259,7 +260,8 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
if (checkSmartCastToExpectedTypeInSubject( if (checkSmartCastToExpectedTypeInSubject(
contextBeforeSubject, subjectExpression, subjectType, contextBeforeSubject, subjectExpression, subjectType,
possibleCastType possibleCastType
)) { )
) {
return return
} }
} }
@@ -271,7 +273,8 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
if (checkSmartCastToExpectedTypeInSubject( if (checkSmartCastToExpectedTypeInSubject(
contextBeforeSubject, subjectExpression, subjectType, contextBeforeSubject, subjectExpression, subjectType,
notNullableType notNullableType
)) { )
) {
return return
} }
} }
@@ -384,7 +387,7 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
val expression = condition.expression val expression = condition.expression
if (expression != null) { if (expression != null) {
val basicDataFlowInfo = checkTypeForExpressionCondition( val basicDataFlowInfo = checkTypeForExpressionCondition(
context, expression, subjectType, subjectExpression == null, subjectDataFlowValue context, expression, subjectType, subjectExpression, subjectDataFlowValue
) )
val moduleDescriptor = DescriptorUtils.getContainingModule(context.scope.ownerDescriptor) val moduleDescriptor = DescriptorUtils.getContainingModule(context.scope.ownerDescriptor)
val dataFlowInfoFromES = val dataFlowInfoFromES =
@@ -404,14 +407,16 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
context: ExpressionTypingContext, context: ExpressionTypingContext,
expression: KtExpression, expression: KtExpression,
subjectType: KotlinType, subjectType: KotlinType,
conditionExpected: Boolean, subjectExpression: KtExpression?,
subjectDataFlowValue: DataFlowValue subjectDataFlowValue: DataFlowValue
): ConditionalDataFlowInfo { ): ConditionalDataFlowInfo {
var newContext = context var newContext = context
val typeInfo = facade.getTypeInfo(expression, newContext) val typeInfo = facade.getTypeInfo(expression, newContext)
val type = typeInfo.type ?: return noChange(newContext) val type = typeInfo.type ?: return noChange(newContext)
newContext = newContext.replaceDataFlowInfo(typeInfo.dataFlowInfo) newContext = newContext.replaceDataFlowInfo(typeInfo.dataFlowInfo)
if (conditionExpected) {
if (subjectExpression == null) { // condition expected
val booleanType = components.builtIns.booleanType val booleanType = components.builtIns.booleanType
val checkedTypeInfo = components.dataFlowAnalyzer.checkType(typeInfo, expression, newContext.replaceExpectedType(booleanType)) val checkedTypeInfo = components.dataFlowAnalyzer.checkType(typeInfo, expression, newContext.replaceExpectedType(booleanType))
if (KotlinTypeChecker.DEFAULT.equalTypes(booleanType, checkedTypeInfo.type ?: type)) { if (KotlinTypeChecker.DEFAULT.equalTypes(booleanType, checkedTypeInfo.type ?: type)) {
@@ -421,8 +426,21 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
} }
return noChange(newContext) return noChange(newContext)
} }
checkTypeCompatibility(newContext, type, subjectType, expression) checkTypeCompatibility(newContext, type, subjectType, expression)
val expressionDataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, type, newContext) 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) val result = noChange(newContext)
return ConditionalDataFlowInfo( return ConditionalDataFlowInfo(
result.thenInfo.equate( result.thenInfo.equate(
@@ -37,7 +37,7 @@ import org.jetbrains.kotlin.types.KotlinType
class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGeneratorExtension(statementGenerator) { class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGeneratorExtension(statementGenerator) {
fun generateAssignment(expression: KtBinaryExpression): IrExpression { fun generateAssignment(expression: KtBinaryExpression): IrExpression {
val ktLeft = expression.left!! val ktLeft = expression.left!!
val irRhs = statementGenerator.generateExpression(expression.right!!) val irRhs = expression.right!!.genExpr()
val irAssignmentReceiver = generateAssignmentReceiver(ktLeft, IrStatementOrigin.EQ) val irAssignmentReceiver = generateAssignmentReceiver(ktLeft, IrStatementOrigin.EQ)
return irAssignmentReceiver.assign(irRhs) return irAssignmentReceiver.assign(irRhs)
} }
@@ -52,7 +52,7 @@ class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGen
return irAssignmentReceiver.assign { irLValue -> return irAssignmentReceiver.assign { irLValue ->
val opCall = statementGenerator.pregenerateCallReceivers(opResolvedCall) val opCall = statementGenerator.pregenerateCallReceivers(opResolvedCall)
opCall.setExplicitReceiverValue(irLValue) opCall.setExplicitReceiverValue(irLValue)
opCall.irValueArgumentsByIndex[0] = statementGenerator.generateExpression(ktRight) opCall.irValueArgumentsByIndex[0] = ktRight.genExpr()
val irOpCall = CallGenerator(statementGenerator).generateCall(expression, opCall, origin) val irOpCall = CallGenerator(statementGenerator).generateCall(expression, opCall, origin)
if (isSimpleAssignment) { if (isSimpleAssignment) {
@@ -137,7 +137,7 @@ class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGen
origin origin
) )
else -> else ->
OnceExpressionValue(statementGenerator.generateExpression(ktLeft)) OnceExpressionValue(ktLeft.genExpr())
} }
} }
@@ -237,8 +237,8 @@ class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGen
ktLeft: KtArrayAccessExpression, ktLeft: KtArrayAccessExpression,
origin: IrStatementOrigin origin: IrStatementOrigin
): ArrayAccessAssignmentReceiver { ): ArrayAccessAssignmentReceiver {
val irArray = statementGenerator.generateExpression(ktLeft.arrayExpression!!) val irArray = ktLeft.arrayExpression!!.genExpr()
val irIndexExpressions = ktLeft.indexExpressions.map { statementGenerator.generateExpression(it) } val irIndexExpressions = ktLeft.indexExpressions.map { it.genExpr() }
val indexedGetResolvedCall = get(BindingContext.INDEXED_LVALUE_GET, ktLeft) val indexedGetResolvedCall = get(BindingContext.INDEXED_LVALUE_GET, ktLeft)
val indexedGetCall = indexedGetResolvedCall?.let { statementGenerator.pregenerateCallReceivers(it) } val indexedGetCall = indexedGetResolvedCall?.let { statementGenerator.pregenerateCallReceivers(it) }
@@ -40,8 +40,8 @@ class BranchingExpressionGenerator(statementGenerator: StatementGenerator) : Sta
var irElseBranch: IrExpression? = null var irElseBranch: IrExpression? = null
whenBranches@ while (true) { whenBranches@ while (true) {
val irCondition = statementGenerator.generateExpression(ktLastIf.condition!!) val irCondition = ktLastIf.condition!!.genExpr()
val irThenBranch = statementGenerator.generateExpression(ktLastIf.then!!) val irThenBranch = ktLastIf.then!!.genExpr()
irBranches.add(IrBranchImpl(irCondition, irThenBranch)) irBranches.add(IrBranchImpl(irCondition, irThenBranch))
val ktElse = ktLastIf.`else`?.deparenthesize() val ktElse = ktLastIf.`else`?.deparenthesize()
@@ -49,7 +49,7 @@ class BranchingExpressionGenerator(statementGenerator: StatementGenerator) : Sta
null -> break@whenBranches null -> break@whenBranches
is KtIfExpression -> ktLastIf = ktElse is KtIfExpression -> ktLastIf = ktElse
is KtExpression -> { is KtExpression -> {
irElseBranch = statementGenerator.generateExpression(ktElse) irElseBranch = ktElse.genExpr()
break@whenBranches break@whenBranches
} }
else -> throw AssertionError("Unexpected else expression: ${ktElse.text}") else -> throw AssertionError("Unexpected else expression: ${ktElse.text}")
@@ -85,7 +85,7 @@ class BranchingExpressionGenerator(statementGenerator: StatementGenerator) : Sta
fun generateWhenExpression(expression: KtWhenExpression): IrExpression { fun generateWhenExpression(expression: KtWhenExpression): IrExpression {
val irSubject = expression.subjectExpression?.let { 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) { for (ktEntry in expression.entries) {
if (ktEntry.isElse) { if (ktEntry.isElse) {
val irElseResult = statementGenerator.generateExpression(ktEntry.expression!!) val irElseResult = ktEntry.expression!!.genExpr()
irWhen.branches.add(IrBranchImpl.elseBranch(irElseResult)) irWhen.branches.add(IrBranchImpl.elseBranch(irElseResult))
break break
} }
@@ -117,10 +117,9 @@ class BranchingExpressionGenerator(statementGenerator: StatementGenerator) : Sta
else else
generateWhenConditionNoSubject(ktCondition) generateWhenConditionNoSubject(ktCondition)
irBranchCondition = irBranchCondition?.let { context.whenComma(it, irCondition) } ?: irCondition 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)) irWhen.branches.add(IrBranchImpl(irBranchCondition!!, irBranchResult))
} }
addElseBranchForExhaustiveWhenIfNeeded(irWhen, expression) addElseBranchForExhaustiveWhenIfNeeded(irWhen, expression)
@@ -163,7 +162,7 @@ class BranchingExpressionGenerator(statementGenerator: StatementGenerator) : Sta
} }
private fun generateWhenConditionNoSubject(ktCondition: KtWhenCondition): IrExpression = 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 { private fun generateWhenConditionWithSubject(ktCondition: KtWhenCondition, irSubject: IrVariable): IrExpression {
return when (ktCondition) { return when (ktCondition) {
@@ -204,10 +203,13 @@ class BranchingExpressionGenerator(statementGenerator: StatementGenerator) : Sta
} }
} }
private fun generateEqualsCondition(irSubject: IrVariable, ktCondition: KtWhenConditionWithExpression): IrBinaryPrimitiveImpl = private fun generateEqualsCondition(irSubject: IrVariable, ktCondition: KtWhenConditionWithExpression): IrExpression {
IrBinaryPrimitiveImpl( val ktExpression = ktCondition.expression
ktCondition.startOffset, ktCondition.endOffset, val irExpression = ktExpression!!.genExpr()
IrStatementOrigin.EQEQ, context.irBuiltIns.eqeqSymbol, return OperatorExpressionGenerator(statementGenerator).generateEquality(
irSubject.defaultLoad(), statementGenerator.generateExpression(ktCondition.expression!!) ktCondition.startOffset, ktCondition.endOffset, IrStatementOrigin.EQEQ,
irSubject.defaultLoad(), irExpression,
context.bindingContext[BindingContext.PRIMITIVE_NUMERIC_COMPARISON_INFO, ktExpression]
) )
}
} }
@@ -137,12 +137,9 @@ class DataClassMembersGenerator(declarationGenerator: DeclarationGenerator) : De
+irIfThenReturnFalse(irNotIs(irOther(), classDescriptor.defaultType)) +irIfThenReturnFalse(irNotIs(irOther(), classDescriptor.defaultType))
val otherWithCast = irTemporary(irAs(irOther(), classDescriptor.defaultType), "other_with_cast") val otherWithCast = irTemporary(irAs(irOther(), classDescriptor.defaultType), "other_with_cast")
for (property in properties) { for (property in properties) {
+irIfThenReturnFalse( val arg1 = irGet(irThis(), getPropertyGetterSymbol(property))
irNotEquals( val arg2 = irGet(irGet(otherWithCast.symbol), getPropertyGetterSymbol(property))
irGet(irThis(), getPropertyGetterSymbol(property)), +irIfThenReturnFalse(irNotEquals(arg1, arg2))
irGet(irGet(otherWithCast.symbol), getPropertyGetterSymbol(property))
)
)
} }
+irReturnTrue() +irReturnTrue()
} }
@@ -229,7 +226,8 @@ class DataClassMembersGenerator(declarationGenerator: DeclarationGenerator) : De
val typeConstructorDescriptor = property.type.constructor.declarationDescriptor val typeConstructorDescriptor = property.type.constructor.declarationDescriptor
val irPropertyStringValue = val irPropertyStringValue =
if (typeConstructorDescriptor is ClassDescriptor && if (typeConstructorDescriptor is ClassDescriptor &&
KotlinBuiltIns.isArrayOrPrimitiveArray(typeConstructorDescriptor)) KotlinBuiltIns.isArrayOrPrimitiveArray(typeConstructorDescriptor)
)
irCall(context.irBuiltIns.dataClassArrayMemberToStringSymbol).apply { irCall(context.irBuiltIns.dataClassArrayMemberToStringSymbol).apply {
putValueArgument(0, irPropertyValue) putValueArgument(0, irPropertyValue)
} }
@@ -46,19 +46,19 @@ class ErrorExpressionGenerator(statementGenerator: StatementGenerator) : Stateme
val type = getErrorExpressionType(ktCall) val type = getErrorExpressionType(ktCall)
val irErrorCall = IrErrorCallExpressionImpl(ktCall.startOffset, ktCall.endOffset, type, "") // TODO problem description? val irErrorCall = IrErrorCallExpressionImpl(ktCall.startOffset, ktCall.endOffset, type, "") // TODO problem description?
irErrorCall.explicitReceiver = (ktCall.parent as? KtDotQualifiedExpression)?.let { irErrorCall.explicitReceiver = (ktCall.parent as? KtDotQualifiedExpression)?.run {
statementGenerator.generateExpression(it.receiverExpression) receiverExpression.genExpr()
} }
ktCall.valueArguments.forEach { ktCall.valueArguments.forEach {
val ktArgument = it.getArgumentExpression() val ktArgument = it.getArgumentExpression()
if (ktArgument != null) { if (ktArgument != null) {
irErrorCall.addArgument(statementGenerator.generateExpression(ktArgument)) irErrorCall.addArgument(ktArgument.genExpr())
} }
} }
ktCall.lambdaArguments.forEach { ktCall.lambdaArguments.forEach {
irErrorCall.addArgument(statementGenerator.generateExpression(it.getArgumentExpression())) irErrorCall.addArgument(it.getArgumentExpression().genExpr())
} }
irErrorCall irErrorCall
@@ -73,7 +73,7 @@ class ErrorExpressionGenerator(statementGenerator: StatementGenerator) : Stateme
val irErrorCall = IrErrorCallExpressionImpl(ktName.startOffset, ktName.endOffset, type, "") // TODO problem description? val irErrorCall = IrErrorCallExpressionImpl(ktName.startOffset, ktName.endOffset, type, "") // TODO problem description?
irErrorCall.explicitReceiver = (ktName.parent as? KtDotQualifiedExpression)?.let { ktParent -> irErrorCall.explicitReceiver = (ktName.parent as? KtDotQualifiedExpression)?.let { ktParent ->
if (ktParent.receiverExpression == ktName) null if (ktParent.receiverExpression == ktName) null
else statementGenerator.generateExpression(ktParent.receiverExpression) else ktParent.receiverExpression.genExpr()
} }
irErrorCall irErrorCall
@@ -36,7 +36,7 @@ class LoopExpressionGenerator(statementGenerator: StatementGenerator) : Statemen
context.builtIns.unitType, IrStatementOrigin.WHILE_LOOP context.builtIns.unitType, IrStatementOrigin.WHILE_LOOP
) )
irLoop.condition = statementGenerator.generateExpression(ktWhile.condition!!) irLoop.condition = ktWhile.condition!!.genExpr()
statementGenerator.bodyGenerator.putLoop(ktWhile, irLoop) statementGenerator.bodyGenerator.putLoop(ktWhile, irLoop)
@@ -44,7 +44,7 @@ class LoopExpressionGenerator(statementGenerator: StatementGenerator) : Statemen
if (ktLoopBody is KtBlockExpression) if (ktLoopBody is KtBlockExpression)
generateWhileLoopBody(ktLoopBody) generateWhileLoopBody(ktLoopBody)
else else
statementGenerator.generateExpression(ktLoopBody) ktLoopBody.genExpr()
} }
irLoop.label = getLoopLabel(ktWhile) irLoop.label = getLoopLabel(ktWhile)
@@ -64,10 +64,10 @@ class LoopExpressionGenerator(statementGenerator: StatementGenerator) : Statemen
if (ktLoopBody is KtBlockExpression) if (ktLoopBody is KtBlockExpression)
generateDoWhileLoopBody(ktLoopBody) generateDoWhileLoopBody(ktLoopBody)
else else
statementGenerator.generateExpression(ktLoopBody) ktLoopBody.genExpr()
} }
irLoop.condition = statementGenerator.generateExpression(ktDoWhile.condition!!) irLoop.condition = ktDoWhile.condition!!.genExpr()
irLoop.label = getLoopLabel(ktDoWhile) irLoop.label = getLoopLabel(ktDoWhile)
@@ -79,14 +79,14 @@ class LoopExpressionGenerator(statementGenerator: StatementGenerator) : Statemen
private fun generateWhileLoopBody(ktLoopBody: KtBlockExpression): IrExpression = private fun generateWhileLoopBody(ktLoopBody: KtBlockExpression): IrExpression =
IrBlockImpl( IrBlockImpl(
ktLoopBody.startOffset, ktLoopBody.endOffset, context.builtIns.unitType, null, 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 = private fun generateDoWhileLoopBody(ktLoopBody: KtBlockExpression): IrExpression =
IrCompositeImpl( IrCompositeImpl(
ktLoopBody.startOffset, ktLoopBody.endOffset, context.builtIns.unitType, null, ktLoopBody.startOffset, ktLoopBody.endOffset, context.builtIns.unitType, null,
ktLoopBody.statements.map { statementGenerator.generateStatement(it) } ktLoopBody.statements.map { it.genStmt() }
) )
fun generateBreak(ktBreak: KtBreakExpression): IrExpression { fun generateBreak(ktBreak: KtBreakExpression): IrExpression {
@@ -199,7 +199,7 @@ class LoopExpressionGenerator(statementGenerator: StatementGenerator) : Statemen
} }
if (ktForBody != null) { if (ktForBody != null) {
irInnerBody.statements.add(statementGenerator.generateExpression(ktForBody)) irInnerBody.statements.add(ktForBody.genExpr())
} }
return irForBlock return irForBlock
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.psi2ir.findSingleFunction import org.jetbrains.kotlin.psi2ir.findSingleFunction
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall 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.resolve.constants.evaluate.ConstantExpressionEvaluator
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.isPrimitiveNumberType import org.jetbrains.kotlin.types.typeUtil.isPrimitiveNumberType
@@ -89,7 +90,7 @@ class OperatorExpressionGenerator(statementGenerator: StatementGenerator) : Stat
return IrTypeOperatorCallImpl( return IrTypeOperatorCallImpl(
expression.startOffset, expression.endOffset, resultType, irOperator, rhsType, 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( return IrTypeOperatorCallImpl(
expression.startOffset, expression.endOffset, context.builtIns.booleanType, irOperator, 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 { private fun generateElvis(expression: KtBinaryExpression): IrExpression {
val specialCallForElvis = getResolvedCall(expression)!! val specialCallForElvis = getResolvedCall(expression)!!
val resultType = specialCallForElvis.resultingDescriptor.returnType!! val resultType = specialCallForElvis.resultingDescriptor.returnType!!
val irArgument0 = statementGenerator.generateExpression(expression.left!!) val irArgument0 = expression.left!!.genExpr()
val irArgument1 = statementGenerator.generateExpression(expression.right!!) val irArgument1 = expression.right!!.genExpr()
return irBlock(expression, IrStatementOrigin.ELVIS, resultType) { return irBlock(expression, IrStatementOrigin.ELVIS, resultType) {
val temporary = irTemporary(irArgument0, "elvis_lhs") val temporary = irTemporary(irArgument0, "elvis_lhs")
@@ -140,8 +141,8 @@ class OperatorExpressionGenerator(statementGenerator: StatementGenerator) : Stat
} }
private fun generateBinaryBooleanOperator(expression: KtBinaryExpression, irOperator: IrStatementOrigin): IrExpression { private fun generateBinaryBooleanOperator(expression: KtBinaryExpression, irOperator: IrStatementOrigin): IrExpression {
val irArgument0 = statementGenerator.generateExpression(expression.left!!) val irArgument0 = expression.left!!.genExpr()
val irArgument1 = statementGenerator.generateExpression(expression.right!!) val irArgument1 = expression.right!!.genExpr()
return when (irOperator) { return when (irOperator) {
IrStatementOrigin.OROR -> IrStatementOrigin.OROR ->
context.oror(expression.startOffset, expression.endOffset, irArgument0, irArgument1) 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 { private fun generateIdentityOperator(expression: KtBinaryExpression, irOperator: IrStatementOrigin): IrExpression {
val irArgument0 = statementGenerator.generateExpression(expression.left!!) val irArgument0 = expression.left!!.genExpr()
val irArgument1 = statementGenerator.generateExpression(expression.right!!) val irArgument1 = expression.right!!.genExpr()
val irIdentityEquals = IrBinaryPrimitiveImpl( val irIdentityEquals = IrBinaryPrimitiveImpl(
expression.startOffset, expression.endOffset, irOperator, expression.startOffset, expression.endOffset, irOperator,
@@ -196,31 +197,27 @@ class OperatorExpressionGenerator(statementGenerator: StatementGenerator) : Stat
} }
} }
private fun KtExpression.generateAsPrimitiveNumericComparisonOperand(primitiveNumericComparisonType: KotlinType?) = private fun KtExpression.generateAsPrimitiveNumericComparisonOperand(
statementGenerator.generateExpression(this) expressionType: KotlinType?,
.promoteToPrimitiveNumericType( comparisonType: KotlinType?
getPrimitiveNumericComparisonOperandType(this), ) = genExpr().promoteToPrimitiveNumericType(expressionType, comparisonType)
primitiveNumericComparisonType
)
private fun getPrimitiveNumericComparisonType(ktExpression: KtBinaryExpression) = private fun getPrimitiveNumericComparisonInfo(ktExpression: KtBinaryExpression) =
context.bindingContext[BindingContext.PRIMITIVE_NUMERIC_COMPARISON_TYPE, ktExpression] context.bindingContext[BindingContext.PRIMITIVE_NUMERIC_COMPARISON_INFO, ktExpression]
private fun getPrimitiveNumericComparisonOperandType(ktExpression: KtExpression) =
context.bindingContext[BindingContext.PRIMITIVE_NUMERIC_COMPARISON_OPERAND_TYPE, ktExpression]
private fun generateEqualityOperator(expression: KtBinaryExpression, irOperator: IrStatementOrigin): IrExpression { 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 ?: context.irBuiltIns.eqeqSymbol
val irEquals = IrBinaryPrimitiveImpl( val irEquals = IrBinaryPrimitiveImpl(
expression.startOffset, expression.endOffset, expression.startOffset, expression.endOffset,
irOperator, irOperator,
eqeqSymbol, eqeqSymbol,
expression.left!!.generateAsPrimitiveNumericComparisonOperand(primitiveNumericComparisonType), expression.left!!.generateAsPrimitiveNumericComparisonOperand(comparisonInfo?.leftType, comparisonType),
expression.right!!.generateAsPrimitiveNumericComparisonOperand(primitiveNumericComparisonType) expression.right!!.generateAsPrimitiveNumericComparisonOperand(comparisonInfo?.rightType, comparisonType)
) )
return when (irOperator) { 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 { private fun IrExpression.promoteToPrimitiveNumericType(operandType: KotlinType?, targetType: KotlinType?): IrExpression {
if (targetType == null) return this if (targetType == null) return this
if (operandType == null) throw AssertionError("operandType should be non-null") if (operandType == null) throw AssertionError("operandType should be non-null")
@@ -290,14 +314,14 @@ class OperatorExpressionGenerator(statementGenerator: StatementGenerator) : Stat
val startOffset = expression.startOffset val startOffset = expression.startOffset
val endOffset = expression.endOffset val endOffset = expression.endOffset
val primitiveNumberComparisonType = getPrimitiveNumericComparisonType(expression) val comparisonInfo = getPrimitiveNumericComparisonInfo(expression)
return if (primitiveNumberComparisonType != null) { return if (comparisonInfo != null) {
IrBinaryPrimitiveImpl( IrBinaryPrimitiveImpl(
startOffset, endOffset, origin, startOffset, endOffset, origin,
getComparisonOperatorSymbol(origin, primitiveNumberComparisonType), getComparisonOperatorSymbol(origin, comparisonInfo.comparisonType),
expression.left!!.generateAsPrimitiveNumericComparisonOperand(primitiveNumberComparisonType), expression.left!!.generateAsPrimitiveNumericComparisonOperand(comparisonInfo.leftType, comparisonInfo.comparisonType),
expression.right!!.generateAsPrimitiveNumericComparisonOperand(primitiveNumberComparisonType) expression.right!!.generateAsPrimitiveNumericComparisonOperand(comparisonInfo.rightType, comparisonInfo.comparisonType)
) )
} else { } else {
IrBinaryPrimitiveImpl( IrBinaryPrimitiveImpl(
@@ -327,7 +351,7 @@ class OperatorExpressionGenerator(statementGenerator: StatementGenerator) : Stat
private fun generateExclExclOperator(expression: KtPostfixExpression, origin: IrStatementOrigin): IrExpression { private fun generateExclExclOperator(expression: KtPostfixExpression, origin: IrStatementOrigin): IrExpression {
val ktArgument = expression.baseExpression!! val ktArgument = expression.baseExpression!!
val irArgument = statementGenerator.generateExpression(ktArgument) val irArgument = ktArgument.genExpr()
val ktOperator = expression.operationReference val ktOperator = expression.operationReference
val resultType = irArgument.type.makeNotNullable() val resultType = irArgument.type.makeNotNullable()
@@ -39,7 +39,7 @@ class ReflectionReferencesGenerator(statementGenerator: StatementGenerator) : St
return if (lhs is DoubleColonLHS.Expression && !lhs.isObjectQualifier) { return if (lhs is DoubleColonLHS.Expression && !lhs.isObjectQualifier) {
IrGetClassImpl( IrGetClassImpl(
ktClassLiteral.startOffset, ktClassLiteral.endOffset, resultType, ktClassLiteral.startOffset, ktClassLiteral.endOffset, resultType,
statementGenerator.generateExpression(ktArgument) ktArgument.genExpr()
) )
} else { } else {
val typeConstructorDeclaration = lhs.type.constructor.declarationDescriptor val typeConstructorDeclaration = lhs.type.constructor.declarationDescriptor
@@ -407,4 +407,7 @@ class StatementGenerator(
abstract class StatementGeneratorExtension(val statementGenerator: StatementGenerator) : GeneratorWithScope { abstract class StatementGeneratorExtension(val statementGenerator: StatementGenerator) : GeneratorWithScope {
override val scope: Scope get() = statementGenerator.scope override val scope: Scope get() = statementGenerator.scope
override val context: GeneratorContext get() = statementGenerator.context override val context: GeneratorContext get() = statementGenerator.context
fun KtExpression.genExpr() = statementGenerator.generateExpression(this)
fun KtExpression.genStmt() = statementGenerator.generateStatement(this)
} }
@@ -30,7 +30,7 @@ class TryCatchExpressionGenerator(statementGenerator: StatementGenerator) : Stat
val resultType = getInferredTypeWithImplicitCastsOrFail(ktTry) val resultType = getInferredTypeWithImplicitCastsOrFail(ktTry)
val irTryCatch = IrTryImpl(ktTry.startOffset, ktTry.endOffset, resultType) val irTryCatch = IrTryImpl(ktTry.startOffset, ktTry.endOffset, resultType)
irTryCatch.tryResult = statementGenerator.generateExpression(ktTry.tryBlock) irTryCatch.tryResult = ktTry.tryBlock.genExpr()
for (ktCatchClause in ktTry.catchClauses) { for (ktCatchClause in ktTry.catchClauses) {
val ktCatchParameter = ktCatchClause.catchParameter!! val ktCatchParameter = ktCatchClause.catchParameter!!
@@ -45,13 +45,13 @@ class TryCatchExpressionGenerator(statementGenerator: StatementGenerator) : Stat
catchParameterDescriptor catchParameterDescriptor
) )
).apply { ).apply {
result = statementGenerator.generateExpression(ktCatchBody) result = ktCatchBody.genExpr()
} }
irTryCatch.catches.add(irCatch) irTryCatch.catches.add(irCatch)
} }
irTryCatch.finallyExpression = ktTry.finallyBlock?.let { statementGenerator.generateExpression(it.finalExpression) } irTryCatch.finallyExpression = ktTry.finallyBlock?.run { finalExpression.genExpr() }
return irTryCatch return irTryCatch
} }
+3 -1
View File
@@ -1,3 +1,5 @@
data class Test1(val x: Int, val y: String, val z: Any) data class Test1(val x: Int, val y: String, val z: Any)
data class Test2(val x: Any?) data class Test2(val x: Any?)
data class Test3(val d: Double, val dn: Double?, val f: Float, val df: Float?)
+240 -1
View File
@@ -270,4 +270,243 @@ FILE fqName:<root> fileName:/dataClasses.kt
CONST Boolean type=kotlin.Boolean value=false CONST Boolean type=kotlin.Boolean value=false
RETURN type=kotlin.Nothing from='equals(Any?): Boolean' RETURN type=kotlin.Nothing from='equals(Any?): Boolean'
CONST Boolean type=kotlin.Boolean value=true CONST Boolean type=kotlin.Boolean value=true
CLASS CLASS name:Test3 modality:FINAL visibility:public flags:data
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> 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:<get-d> visibility:public modality:FINAL <> ($this:Test3) returnType:Double flags:
$this: VALUE_PARAMETER name:<this> type:Test3 flags:
BLOCK_BODY
RETURN type=kotlin.Nothing from='<get-d>(): 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:<get-dn> visibility:public modality:FINAL <> ($this:Test3) returnType:Double? flags:
$this: VALUE_PARAMETER name:<this> type:Test3 flags:
BLOCK_BODY
RETURN type=kotlin.Nothing from='<get-dn>(): 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:<get-f> visibility:public modality:FINAL <> ($this:Test3) returnType:Float flags:
$this: VALUE_PARAMETER name:<this> type:Test3 flags:
BLOCK_BODY
RETURN type=kotlin.Nothing from='<get-f>(): 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:<get-df> visibility:public modality:FINAL <> ($this:Test3) returnType:Float? flags:
$this: VALUE_PARAMETER name:<this> type:Test3 flags:
BLOCK_BODY
RETURN type=kotlin.Nothing from='<get-df>(): 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:<this> type:Test3 flags:
BLOCK_BODY
RETURN type=kotlin.Nothing from='component1(): Double'
CALL '<get-d>(): 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:<this> type:Test3 flags:
BLOCK_BODY
RETURN type=kotlin.Nothing from='component2(): Double?'
CALL '<get-dn>(): 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:<this> type:Test3 flags:
BLOCK_BODY
RETURN type=kotlin.Nothing from='component3(): Float'
CALL '<get-f>(): 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:<this> type:Test3 flags:
BLOCK_BODY
RETURN type=kotlin.Nothing from='component4(): Float?'
CALL '<get-df>(): 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:<this> type:Test3 flags:
VALUE_PARAMETER name:d index:0 type:kotlin.Double flags:
EXPRESSION_BODY
CALL '<get-d>(): 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 '<get-dn>(): 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 '<get-f>(): 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 '<get-df>(): 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:<this> 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 '<get-d>(): 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 '<get-dn>(): 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 '<get-f>(): 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 '<get-df>(): 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:<this> 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 '<get-d>(): 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 '<get-dn>(): 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 '<get-f>(): 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 '<get-df>(): 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:<this> 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 '<get-d>(): Double' type=kotlin.Double origin=GET_PROPERTY
$this: GET_VAR 'this@Test3: Test3' type=Test3 origin=null
arg1: CALL '<get-d>(): 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 '<get-dn>(): Double?' type=kotlin.Double? origin=GET_PROPERTY
$this: GET_VAR 'this@Test3: Test3' type=Test3 origin=null
arg1: CALL '<get-dn>(): 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 '<get-f>(): Float' type=kotlin.Float origin=GET_PROPERTY
$this: GET_VAR 'this@Test3: Test3' type=Test3 origin=null
arg1: CALL '<get-f>(): 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 '<get-df>(): Float?' type=kotlin.Float? origin=GET_PROPERTY
$this: GET_VAR 'this@Test3: Test3' type=Test3 origin=null
arg1: CALL '<get-df>(): 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
@@ -0,0 +1,2 @@
fun test(x: Any) =
x == (if (x !is Double) null!! else x)
@@ -0,0 +1,27 @@
FILE fqName:<root> 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
@@ -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
}
}
@@ -0,0 +1,148 @@
FILE fqName:<root> 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
@@ -1010,6 +1010,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
doTest(fileName); 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") @TestMetadata("floatingPointCompareTo.kt")
public void testFloatingPointCompareTo() throws Exception { public void testFloatingPointCompareTo() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/expressions/floatingPointComparisons/floatingPointCompareTo.kt"); 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"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/expressions/floatingPointComparisons/nullableFloatingPointEqeq.kt");
doTest(fileName); doTest(fileName);
} }
@TestMetadata("whenByFloatingPoint.kt")
public void testWhenByFloatingPoint() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/expressions/floatingPointComparisons/whenByFloatingPoint.kt");
doTest(fileName);
}
} }
} }