From db5843adc88f2822846a8214e7d7af5d8c823976 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Wed, 17 Aug 2016 15:59:00 +0300 Subject: [PATCH] Desugar comparison operators as IrBinaryOperatorExpression. They are not exactly 'compareTo' calls (although annotated with a related 'compareTo' function), and require special treatment in BEs. --- .../IrOperatorExpressionGenerator.kt | 55 +++++++++++++------ .../psi2ir/generators/IrStatementGenerator.kt | 4 +- .../kotlin/ir/expressions/IrOperator.kt | 7 ++- .../ir/expressions/IrOperatorExpression.kt | 16 +++--- .../kotlin/ir/util/RenderIrElement.kt | 14 ++++- .../ir/irText/conventionComparisons.kt | 4 ++ .../ir/irText/conventionComparisons.txt | 29 ++++++++++ .../ir/irText/primitiveComparisons.kt | 4 ++ .../ir/irText/primitiveComparisons.txt | 29 ++++++++++ .../kotlin/ir/IrTextTestCaseGenerated.java | 12 ++++ 10 files changed, 142 insertions(+), 32 deletions(-) create mode 100644 compiler/testData/ir/irText/conventionComparisons.kt create mode 100644 compiler/testData/ir/irText/conventionComparisons.txt create mode 100644 compiler/testData/ir/irText/primitiveComparisons.kt create mode 100644 compiler/testData/ir/irText/primitiveComparisons.txt 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 3425f682fbe..ef873cacf06 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 @@ -19,34 +19,44 @@ package org.jetbrains.kotlin.psi2ir.generators import com.intellij.psi.tree.IElementType import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor +import org.jetbrains.kotlin.ir.expressions.IrBinaryOperatorExpressionImpl import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrOperator import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.KtArrayAccessExpression import org.jetbrains.kotlin.psi.KtBinaryExpression import org.jetbrains.kotlin.psi.KtExpression +import org.jetbrains.kotlin.psi.psiUtil.endOffset +import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi2ir.generators.values.* import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall import org.jetbrains.kotlin.types.expressions.OperatorConventions -val KT_OPERATOR_TO_IR_OPERATOR = hashMapOf( - KtTokens.PLUSEQ to IrOperator.PLUSEQ, - KtTokens.MINUSEQ to IrOperator.MINUSEQ, - KtTokens.MULTEQ to IrOperator.MULTEQ, - KtTokens.DIVEQ to IrOperator.DIVEQ, - KtTokens.PERCEQ to IrOperator.PERCEQ, +val KT_OPERATOR_TO_IR_OPERATOR: Map = + hashMapOf( + KtTokens.PLUSEQ to IrOperator.PLUSEQ, + KtTokens.MINUSEQ to IrOperator.MINUSEQ, + KtTokens.MULTEQ to IrOperator.MULTEQ, + KtTokens.DIVEQ to IrOperator.DIVEQ, + KtTokens.PERCEQ to IrOperator.PERCEQ, - KtTokens.PLUS to IrOperator.PLUS, - KtTokens.MINUS to IrOperator.MINUS, - KtTokens.MUL to IrOperator.MUL, - KtTokens.DIV to IrOperator.DIV, - KtTokens.PERC to IrOperator.PERC, - KtTokens.RANGE to IrOperator.RANGE -) + KtTokens.PLUS to IrOperator.PLUS, + KtTokens.MINUS to IrOperator.MINUS, + KtTokens.MUL to IrOperator.MUL, + KtTokens.DIV to IrOperator.DIV, + KtTokens.PERC to IrOperator.PERC, + KtTokens.RANGE to IrOperator.RANGE, + + KtTokens.LT to IrOperator.LT, + KtTokens.LTEQ to IrOperator.LTEQ, + KtTokens.GT to IrOperator.GT, + KtTokens.GTEQ to IrOperator.GTEQ + ) val AUGMENTED_ASSIGNMENTS = KtTokens.AUGMENTED_ASSIGNMENTS val BINARY_OPERATORS_WITH_CALLS = OperatorConventions.BINARY_OPERATION_NAMES.keys +val COMPARISON_OPERATORS = OperatorConventions.COMPARISON_OPERATIONS class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerator): IrGenerator { override val context: IrGeneratorContext get() = irStatementGenerator.context @@ -58,10 +68,24 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat KtTokens.EQ -> generateAssignment(expression) in AUGMENTED_ASSIGNMENTS -> generateAugmentedAssignment(expression, ktOperator) in BINARY_OPERATORS_WITH_CALLS -> generateBinaryOperatorWithConventionalCall(expression, ktOperator) + in COMPARISON_OPERATORS -> generateComparisonOperator(expression, ktOperator) else -> createDummyExpression(expression, ktOperator.toString()) } } + private fun generateComparisonOperator(expression: KtBinaryExpression, ktOperator: IElementType): IrExpression { + val irOperator = getIrOperator(ktOperator) + + val compareToCall = getResolvedCall(expression)!! + val compareToDescriptor = compareToCall.resultingDescriptor + + val irCallGenerator = IrCallGenerator(irStatementGenerator) + val irArgument0 = irCallGenerator.generateReceiver(expression.left!!, compareToCall.dispatchReceiver, compareToDescriptor.dispatchReceiverParameter)!! + val irArgument1 = irCallGenerator.generateValueArgument(compareToCall.valueArgumentsByIndex!![0], compareToDescriptor.valueParameters[0])!! + return IrBinaryOperatorExpressionImpl(expression.startOffset, expression.endOffset, context.builtIns.booleanType, + irOperator, compareToDescriptor, irArgument0, irArgument1) + } + private fun generateBinaryOperatorWithConventionalCall(expression: KtBinaryExpression, ktOperator: IElementType): IrExpression { val irOperator = getIrOperator(ktOperator) val operatorCall = getResolvedCall(expression)!! @@ -95,9 +119,8 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat } } - private fun getIrOperator(ktOperator: IElementType): IrOperator { - return KT_OPERATOR_TO_IR_OPERATOR[ktOperator] ?: TODO("Operator: $ktOperator") - } + private fun getIrOperator(ktOperator: IElementType): IrOperator = + KT_OPERATOR_TO_IR_OPERATOR[ktOperator] ?: TODO("Operator: $ktOperator") private fun generateAssignment(expression: KtBinaryExpression): IrExpression { val ktLeft = expression.left!! 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 01ddf00af7d..00c5cf2e202 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 @@ -157,9 +157,7 @@ class IrStatementGenerator( } val irStringTemplate = IrStringConcatenationExpressionImpl(expression.startOffset, expression.endOffset, getInferredTypeWithSmartcasts(expression)) - entries.forEach { it.expression!!.let { - irStringTemplate.addArgument(TODO()) - } } + entries.forEach { it.expression!!.let { irStringTemplate.addArgument(it.genExpr()) } } return irStringTemplate } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrOperator.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrOperator.kt index 902e62ea7cd..95610bd015a 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrOperator.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrOperator.kt @@ -16,7 +16,7 @@ package org.jetbrains.kotlin.ir.expressions -sealed class IrOperator(val debugName: String) { +abstract class IrOperator(val debugName: String) { override fun toString(): String = debugName object INVOKE : IrOperator("INVOKE") @@ -28,16 +28,17 @@ sealed class IrOperator(val debugName: String) { object EXCL : IrOperator("EXCL") object EXCLEXCL : IrOperator("EXCLEXCL") object ELVIS : IrOperator("ELVIS") - + object LT : IrOperator("LT") object GT : IrOperator("GT") object LTEQ : IrOperator("LTEQ") object GTEQ : IrOperator("GTEQ") - + object EQEQ : IrOperator("EQEQ") object EQEQEQ : IrOperator("EQEQEQ") object EXCLEQ : IrOperator("EXCLEQ") object EXCLEQEQ : IrOperator("EXCLEQEQ") + object IN : IrOperator("IN") object NOT_IN : IrOperator("NOT_IN") object ANDAND : IrOperator("ANDAND") diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrOperatorExpression.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrOperatorExpression.kt index ca2ddfd927f..c5c9e5c31d4 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrOperatorExpression.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrOperatorExpression.kt @@ -16,14 +16,14 @@ package org.jetbrains.kotlin.ir.expressions -import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.ir.* import org.jetbrains.kotlin.ir.visitors.IrElementVisitor import org.jetbrains.kotlin.types.KotlinType interface IrOperatorExpression : IrExpression { val operator: IrOperator - val relatedDescriptor: FunctionDescriptor? + val relatedDescriptor: CallableDescriptor? } interface IrUnaryOperatorExpression : IrOperatorExpression { @@ -40,14 +40,14 @@ class IrUnaryOperatorExpressionImpl( endOffset: Int, type: KotlinType?, override val operator: IrOperator, - override val relatedDescriptor: FunctionDescriptor? + override val relatedDescriptor: CallableDescriptor? ) : IrExpressionBase(startOffset, endOffset, type), IrUnaryOperatorExpression { constructor( startOffset: Int, endOffset: Int, type: KotlinType?, operator: IrOperator, - relatedDescriptor: FunctionDescriptor?, + relatedDescriptor: CallableDescriptor?, argument: IrExpression ) : this(startOffset, endOffset, type, operator, relatedDescriptor) { this.argument = argument @@ -90,14 +90,14 @@ class IrBinaryOperatorExpressionImpl( endOffset: Int, type: KotlinType?, override val operator: IrOperator, - override val relatedDescriptor: FunctionDescriptor? + override val relatedDescriptor: CallableDescriptor? ) : IrExpressionBase(startOffset, endOffset, type), IrBinaryOperatorExpression { constructor( startOffset: Int, endOffset: Int, type: KotlinType?, operator: IrOperator, - relatedDescriptor: FunctionDescriptor?, + relatedDescriptor: CallableDescriptor?, argument0: IrExpression, argument1: IrExpression ) : this(startOffset, endOffset, type, operator, relatedDescriptor) { @@ -144,7 +144,7 @@ class IrBinaryOperatorExpressionImpl( visitor.visitBinaryOperator(this, data) override fun acceptChildren(visitor: IrElementVisitor, data: D) { - argument0.acceptChildren(visitor, data) - argument1.acceptChildren(visitor, data) + argument0.accept(visitor, data) + argument1.accept(visitor, data) } } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/RenderIrElement.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/RenderIrElement.kt index 5763f992dc6..788c2debc69 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/RenderIrElement.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/RenderIrElement.kt @@ -99,6 +99,16 @@ class RenderIrElementVisitor : IrElementVisitor { "SET_PROPERTY ${if (expression.isSafe) "?." else "."}${expression.descriptor.name}" + "type=${expression.renderType()}" + override fun visitUnaryOperator(expression: IrUnaryOperatorExpression, data: Nothing?): String = + "UNARY_OP operator=${expression.operator} " + + "type=${expression.renderType()} " + + "related=${expression.relatedDescriptor?.render()}" + + override fun visitBinaryOperator(expression: IrBinaryOperatorExpression, data: Nothing?): String = + "BINARY_OP operator=${expression.operator} " + + "type=${expression.renderType()} " + + "related=${expression.relatedDescriptor?.render()}" + override fun visitStringConcatenation(expression: IrStringConcatenationExpression, data: Nothing?): String = "STRING_CONCATENATION type=${expression.renderType()}" @@ -125,8 +135,8 @@ class RenderIrElementVisitor : IrElementVisitor { internal fun IrDeclaration.name(): String = descriptor?.let { it.name.toString() } ?: "" - internal fun DeclarationDescriptor.render(): String = - DESCRIPTOR_RENDERER.render(this) + internal fun DeclarationDescriptor?.render(): String = + this?.let { DESCRIPTOR_RENDERER.render(it) } ?: "" internal fun IrExpression.renderType(): String = type.render() diff --git a/compiler/testData/ir/irText/conventionComparisons.kt b/compiler/testData/ir/irText/conventionComparisons.kt new file mode 100644 index 00000000000..a499300f653 --- /dev/null +++ b/compiler/testData/ir/irText/conventionComparisons.kt @@ -0,0 +1,4 @@ +fun test1(a: String, b: String) = a > b +fun test2(a: String, b: String) = a < b +fun test3(a: String, b: String) = a >= b +fun test4(a: String, b: String) = a <= b diff --git a/compiler/testData/ir/irText/conventionComparisons.txt b/compiler/testData/ir/irText/conventionComparisons.txt new file mode 100644 index 00000000000..a10084c41db --- /dev/null +++ b/compiler/testData/ir/irText/conventionComparisons.txt @@ -0,0 +1,29 @@ +IrFile /conventionComparisons.kt + IrFunction public fun test1(/*0*/ a: kotlin.String, /*1*/ b: kotlin.String): kotlin.Boolean + IrExpressionBody + BLOCK type= hasResult=false isDesugared=true + RETURN type= + BINARY_OP operator=GT type=kotlin.Boolean related=public open override /*1*/ fun compareTo(/*0*/ other: kotlin.String): kotlin.Int + GET_VAR a type=kotlin.String + GET_VAR b type=kotlin.String + IrFunction public fun test2(/*0*/ a: kotlin.String, /*1*/ b: kotlin.String): kotlin.Boolean + IrExpressionBody + BLOCK type= hasResult=false isDesugared=true + RETURN type= + BINARY_OP operator=LT type=kotlin.Boolean related=public open override /*1*/ fun compareTo(/*0*/ other: kotlin.String): kotlin.Int + GET_VAR a type=kotlin.String + GET_VAR b type=kotlin.String + IrFunction public fun test3(/*0*/ a: kotlin.String, /*1*/ b: kotlin.String): kotlin.Boolean + IrExpressionBody + BLOCK type= hasResult=false isDesugared=true + RETURN type= + BINARY_OP operator=GTEQ type=kotlin.Boolean related=public open override /*1*/ fun compareTo(/*0*/ other: kotlin.String): kotlin.Int + GET_VAR a type=kotlin.String + GET_VAR b type=kotlin.String + IrFunction public fun test4(/*0*/ a: kotlin.String, /*1*/ b: kotlin.String): kotlin.Boolean + IrExpressionBody + BLOCK type= hasResult=false isDesugared=true + RETURN type= + BINARY_OP operator=LTEQ type=kotlin.Boolean related=public open override /*1*/ fun compareTo(/*0*/ other: kotlin.String): kotlin.Int + GET_VAR a type=kotlin.String + GET_VAR b type=kotlin.String diff --git a/compiler/testData/ir/irText/primitiveComparisons.kt b/compiler/testData/ir/irText/primitiveComparisons.kt new file mode 100644 index 00000000000..3e64a3c8091 --- /dev/null +++ b/compiler/testData/ir/irText/primitiveComparisons.kt @@ -0,0 +1,4 @@ +fun test1(a: Int, b: Int) = a > b +fun test2(a: Int, b: Int) = a < b +fun test3(a: Int, b: Int) = a >= b +fun test4(a: Int, b: Int) = a <= b diff --git a/compiler/testData/ir/irText/primitiveComparisons.txt b/compiler/testData/ir/irText/primitiveComparisons.txt new file mode 100644 index 00000000000..639b38895cb --- /dev/null +++ b/compiler/testData/ir/irText/primitiveComparisons.txt @@ -0,0 +1,29 @@ +IrFile /primitiveComparisons.kt + IrFunction public fun test1(/*0*/ a: kotlin.Int, /*1*/ b: kotlin.Int): kotlin.Boolean + IrExpressionBody + BLOCK type= hasResult=false isDesugared=true + RETURN type= + BINARY_OP operator=GT type=kotlin.Boolean related=public open override /*1*/ fun compareTo(/*0*/ other: kotlin.Int): kotlin.Int + GET_VAR a type=kotlin.Int + GET_VAR b type=kotlin.Int + IrFunction public fun test2(/*0*/ a: kotlin.Int, /*1*/ b: kotlin.Int): kotlin.Boolean + IrExpressionBody + BLOCK type= hasResult=false isDesugared=true + RETURN type= + BINARY_OP operator=LT type=kotlin.Boolean related=public open override /*1*/ fun compareTo(/*0*/ other: kotlin.Int): kotlin.Int + GET_VAR a type=kotlin.Int + GET_VAR b type=kotlin.Int + IrFunction public fun test3(/*0*/ a: kotlin.Int, /*1*/ b: kotlin.Int): kotlin.Boolean + IrExpressionBody + BLOCK type= hasResult=false isDesugared=true + RETURN type= + BINARY_OP operator=GTEQ type=kotlin.Boolean related=public open override /*1*/ fun compareTo(/*0*/ other: kotlin.Int): kotlin.Int + GET_VAR a type=kotlin.Int + GET_VAR b type=kotlin.Int + IrFunction public fun test4(/*0*/ a: kotlin.Int, /*1*/ b: kotlin.Int): kotlin.Boolean + IrExpressionBody + BLOCK type= hasResult=false isDesugared=true + RETURN type= + BINARY_OP operator=LTEQ type=kotlin.Boolean related=public open override /*1*/ fun compareTo(/*0*/ other: kotlin.Int): kotlin.Int + GET_VAR a type=kotlin.Int + GET_VAR b type=kotlin.Int diff --git a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java index 5b1bc08924a..0658c4226ce 100644 --- a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java @@ -89,6 +89,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase { doTest(fileName); } + @TestMetadata("conventionComparisons.kt") + public void testConventionComparisons() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/conventionComparisons.kt"); + doTest(fileName); + } + @TestMetadata("destructuring1.kt") public void testDestructuring1() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/destructuring1.kt"); @@ -107,6 +113,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase { doTest(fileName); } + @TestMetadata("primitiveComparisons.kt") + public void testPrimitiveComparisons() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/primitiveComparisons.kt"); + doTest(fileName); + } + @TestMetadata("references.kt") public void testReferences() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/references.kt");