Desugar comparison operators as IrBinaryOperatorExpression.

They are not exactly 'compareTo' calls (although annotated with a related 'compareTo' function),
and require special treatment in BEs.
This commit is contained in:
Dmitry Petrov
2016-08-17 15:59:00 +03:00
committed by Dmitry Petrov
parent 1b018a6ead
commit db5843adc8
10 changed files with 142 additions and 32 deletions
@@ -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<IElementType, IrOperator> =
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!!
@@ -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
}
@@ -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")
@@ -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 <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
argument0.acceptChildren(visitor, data)
argument1.acceptChildren(visitor, data)
argument0.accept(visitor, data)
argument1.accept(visitor, data)
}
}
@@ -99,6 +99,16 @@ class RenderIrElementVisitor : IrElementVisitor<String, Nothing?> {
"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<String, Nothing?> {
internal fun IrDeclaration.name(): String =
descriptor?.let { it.name.toString() } ?: "<none>"
internal fun DeclarationDescriptor.render(): String =
DESCRIPTOR_RENDERER.render(this)
internal fun DeclarationDescriptor?.render(): String =
this?.let { DESCRIPTOR_RENDERER.render(it) } ?: "<none>"
internal fun IrExpression.renderType(): String =
type.render()
+4
View File
@@ -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
+29
View File
@@ -0,0 +1,29 @@
IrFile /conventionComparisons.kt
IrFunction public fun test1(/*0*/ a: kotlin.String, /*1*/ b: kotlin.String): kotlin.Boolean
IrExpressionBody
BLOCK type=<no-type> hasResult=false isDesugared=true
RETURN type=<no-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=<no-type> hasResult=false isDesugared=true
RETURN type=<no-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=<no-type> hasResult=false isDesugared=true
RETURN type=<no-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=<no-type> hasResult=false isDesugared=true
RETURN type=<no-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
+4
View File
@@ -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
+29
View File
@@ -0,0 +1,29 @@
IrFile /primitiveComparisons.kt
IrFunction public fun test1(/*0*/ a: kotlin.Int, /*1*/ b: kotlin.Int): kotlin.Boolean
IrExpressionBody
BLOCK type=<no-type> hasResult=false isDesugared=true
RETURN type=<no-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=<no-type> hasResult=false isDesugared=true
RETURN type=<no-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=<no-type> hasResult=false isDesugared=true
RETURN type=<no-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=<no-type> hasResult=false isDesugared=true
RETURN type=<no-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
@@ -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");