diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/IrOperatorConventions.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/IrOperatorConventions.kt index 5a7e095543b..4ba86a02ee3 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/IrOperatorConventions.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/IrOperatorConventions.kt @@ -54,7 +54,12 @@ internal val KT_TOKEN_TO_IR_OPERATOR = KtTokens.EXCLEQEQEQ to IrOperator.EXCLEQEQ, KtTokens.IN_KEYWORD to IrOperator.IN, - KtTokens.NOT_IN to IrOperator.NOT_IN + KtTokens.NOT_IN to IrOperator.NOT_IN, + + KtTokens.ANDAND to IrOperator.ANDAND, + KtTokens.OROR to IrOperator.OROR, + + KtTokens.ELVIS to IrOperator.ELVIS ) internal val AUGMENTED_ASSIGNMENTS = @@ -74,3 +79,6 @@ internal val IDENTITY_OPERATORS = internal val IN_OPERATORS = setOf(IrOperator.IN, IrOperator.NOT_IN) + +internal val BINARY_BOOLEAN_OPERATORS = + setOf(IrOperator.ANDAND, IrOperator.OROR) \ No newline at end of file diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/IrOperatorExpressionGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/IrOperatorExpressionGenerator.kt index 38b69a6632a..2dd0535efd2 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/IrOperatorExpressionGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/IrOperatorExpressionGenerator.kt @@ -44,16 +44,39 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat return when (irOperator) { null -> createDummyExpression(expression, ktOperator.toString()) IrOperator.EQ -> generateAssignment(expression) + IrOperator.ELVIS -> generateElvis(expression) in AUGMENTED_ASSIGNMENTS -> generateAugmentedAssignment(expression, irOperator) in BINARY_OPERATORS_DESUGARED_TO_CALLS -> generateBinaryOperatorWithConventionalCall(expression, irOperator) in COMPARISON_OPERATORS -> generateComparisonOperator(expression, irOperator) in EQUALITY_OPERATORS -> generateEqualityOperator(expression, irOperator) in IDENTITY_OPERATORS -> generateIdentityOperator(expression, irOperator) in IN_OPERATORS -> generateInOperator(expression, irOperator) + in BINARY_BOOLEAN_OPERATORS -> generateBinaryBooleanOperator(expression, irOperator) else -> createDummyExpression(expression, ktOperator.toString()) } } + private fun generateElvis(expression: KtBinaryExpression): IrExpression { + // TODO desugar '?:' to 'if'? + val specialCallForElvis = getResolvedCall(expression)!! + val returnType = specialCallForElvis.resultingDescriptor.returnType!! + val irArgument0 = irStatementGenerator.generateExpression(expression.left!!).toExpectedType(returnType.makeNullable()) + val irArgument1 = irStatementGenerator.generateExpression(expression.right!!).toExpectedType(returnType) + return IrBinaryOperatorExpressionImpl( + expression.startOffset, expression.endOffset, returnType, + IrOperator.ELVIS, null, irArgument0, irArgument1 + ) + } + + private fun generateBinaryBooleanOperator(expression: KtBinaryExpression, irOperator: IrOperator): IrExpression { + val irArgument0 = irStatementGenerator.generateExpression(expression.left!!).toExpectedType(context.builtIns.booleanType) + val irArgument1 = irStatementGenerator.generateExpression(expression.right!!).toExpectedType(context.builtIns.booleanType) + return IrBinaryOperatorExpressionImpl( + expression.startOffset, expression.endOffset, context.builtIns.booleanType, + irOperator, null, irArgument0, irArgument1 + ) + } + private fun generateInOperator(expression: KtBinaryExpression, irOperator: IrOperator): IrExpression { val operatorCall = getResolvedCall(expression)!! diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/IrStatementGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/IrStatementGenerator.kt index 00c5cf2e202..32dd31d6791 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/IrStatementGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/IrStatementGenerator.kt @@ -102,10 +102,12 @@ class IrStatementGenerator( override fun visitReturnExpression(expression: KtReturnExpression, data: Nothing?): IrStatement { val returnTarget = getReturnExpressionTarget(expression) + val irReturnedExpression = expression.returnedExpression?.let { + it.genExpr().toExpectedType(returnTarget.returnType) + } return IrReturnExpressionImpl( expression.startOffset, expression.endOffset, - returnTarget, - expression.returnedExpression?.let { it.genExpr().toExpectedType(returnTarget.returnType) } + returnTarget, irReturnedExpression ) } diff --git a/compiler/testData/ir/irText/elvis.kt b/compiler/testData/ir/irText/elvis.kt new file mode 100644 index 00000000000..90ad805d735 --- /dev/null +++ b/compiler/testData/ir/irText/elvis.kt @@ -0,0 +1,8 @@ +fun test1(a: Any?, b: Any) = a ?: b +fun test2(a: String?, b: Any) = a ?: b + +fun test3(a: Any?, b: Any?): String { + if (b !is String) return "" + if (a !is String?) return "" + return a ?: b +} \ No newline at end of file diff --git a/compiler/testData/ir/irText/elvis.txt b/compiler/testData/ir/irText/elvis.txt new file mode 100644 index 00000000000..6cfdc21a236 --- /dev/null +++ b/compiler/testData/ir/irText/elvis.txt @@ -0,0 +1,26 @@ +IrFile /elvis.kt + IrFunction public fun test1(/*0*/ a: kotlin.Any?, /*1*/ b: kotlin.Any): kotlin.Any + IrExpressionBody + BLOCK type= hasResult=false isDesugared=true + RETURN type= + BINARY_OP operator=ELVIS type=kotlin.Any related=null + GET_VAR a type=kotlin.Any? + GET_VAR b type=kotlin.Any + IrFunction public fun test2(/*0*/ a: kotlin.String?, /*1*/ b: kotlin.Any): kotlin.Any + IrExpressionBody + BLOCK type= hasResult=false isDesugared=true + RETURN type= + BINARY_OP operator=ELVIS type=kotlin.Any related=null + GET_VAR a type=kotlin.String? + GET_VAR b type=kotlin.Any + IrFunction public fun test3(/*0*/ a: kotlin.Any?, /*1*/ b: kotlin.Any?): kotlin.String + IrExpressionBody + BLOCK type= hasResult=false isDesugared=false + DUMMY KtIfExpression type=kotlin.Unit + DUMMY KtIfExpression type=kotlin.Unit + RETURN type= + BINARY_OP operator=ELVIS type=kotlin.String related=null + TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.String? + GET_VAR a type=kotlin.Any? + TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.String + GET_VAR b type=kotlin.Any? diff --git a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java index 287abdc7422..850c613e970 100644 --- a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java @@ -107,6 +107,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase { doTest(fileName); } + @TestMetadata("elvis.kt") + public void testElvis() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/elvis.kt"); + doTest(fileName); + } + @TestMetadata("equality.kt") public void testEquality() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/equality.kt");