Handle equality checks for 'when' and data classes
This commit is contained in:
@@ -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
|
||||||
|
|||||||
+29
-10
@@ -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() =
|
||||||
|
|||||||
+23
-5
@@ -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(
|
||||||
|
|||||||
+5
-5
@@ -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) }
|
||||||
|
|||||||
+15
-13
@@ -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]
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+5
-7
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-5
@@ -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
|
||||||
|
|||||||
+7
-7
@@ -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
|
||||||
|
|||||||
+53
-29
@@ -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()
|
||||||
|
|||||||
+1
-1
@@ -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)
|
||||||
}
|
}
|
||||||
+3
-3
@@ -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
@@ -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
@@ -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
|
||||||
|
|||||||
+2
@@ -0,0 +1,2 @@
|
|||||||
|
fun test(x: Any) =
|
||||||
|
x == (if (x !is Double) null!! else x)
|
||||||
+27
@@ -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
|
||||||
+48
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
+148
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user