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:
committed by
Dmitry Petrov
parent
1b018a6ead
commit
db5843adc8
+39
-16
@@ -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!!
|
||||
|
||||
+1
-3
@@ -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()
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user