diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/OperatorConventions.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/OperatorConventions.kt index ece98b48d4d..c18982883db 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/OperatorConventions.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/OperatorConventions.kt @@ -19,66 +19,65 @@ package org.jetbrains.kotlin.psi2ir.generators import com.intellij.psi.tree.IElementType import org.jetbrains.kotlin.ir.expressions.IrBinaryOperator import org.jetbrains.kotlin.ir.expressions.IrOperator +import org.jetbrains.kotlin.ir.expressions.IrTypeOperator import org.jetbrains.kotlin.lexer.KtTokens fun getIrBinaryOperator(ktOperator: IElementType): IrBinaryOperator? = - KT_TOKEN_TO_IR_BINARY_OPERATOR[ktOperator] + when (ktOperator) { + KtTokens.EQ -> IrOperator.EQ + KtTokens.PLUSEQ -> IrOperator.PLUSEQ + KtTokens.MINUSEQ -> IrOperator.MINUSEQ + KtTokens.MULTEQ -> IrOperator.MULTEQ + KtTokens.DIVEQ -> IrOperator.DIVEQ + KtTokens.PERCEQ -> IrOperator.PERCEQ + KtTokens.PLUS -> IrOperator.PLUS + KtTokens.MINUS -> IrOperator.MINUS + KtTokens.MUL -> IrOperator.MUL + KtTokens.DIV -> IrOperator.DIV + KtTokens.PERC -> IrOperator.PERC + KtTokens.RANGE -> IrOperator.RANGE + KtTokens.LT -> IrOperator.LT + KtTokens.LTEQ -> IrOperator.LTEQ + KtTokens.GT -> IrOperator.GT + KtTokens.GTEQ -> IrOperator.GTEQ + KtTokens.EQEQ -> IrOperator.EQEQ + KtTokens.EXCLEQ -> IrOperator.EXCLEQ + KtTokens.EQEQEQ -> IrOperator.EQEQEQ + KtTokens.EXCLEQEQEQ -> IrOperator.EXCLEQEQ + KtTokens.IN_KEYWORD -> IrOperator.IN + KtTokens.NOT_IN -> IrOperator.NOT_IN + KtTokens.ANDAND -> IrOperator.ANDAND + KtTokens.OROR -> IrOperator.OROR + KtTokens.ELVIS -> IrOperator.ELVIS + else -> null + } fun getIrPrefixOperator(ktOperator: IElementType): IrOperator? = - KT_TOKEN_TO_IR_PREFIX_OPERATOR[ktOperator] + when (ktOperator) { + KtTokens.PLUSPLUS -> IrOperator.PREFIX_INCR + KtTokens.MINUSMINUS -> IrOperator.PREFIX_DECR + KtTokens.EXCL -> IrOperator.EXCL + KtTokens.MINUS -> IrOperator.UMINUS + else -> null + } fun getIrPostfixOperator(ktOperator: IElementType): IrOperator? = - KT_TOKEN_TO_IR_POSTFIX_OPERATOR[ktOperator] + when (ktOperator) { + KtTokens.PLUSPLUS -> IrOperator.POSTFIX_INCR + KtTokens.MINUSMINUS -> IrOperator.POSTFIX_DECR + KtTokens.EXCLEXCL -> IrOperator.EXCLEXCL + else -> null + } -private val KT_TOKEN_TO_IR_BINARY_OPERATOR = mapOf( - KtTokens.EQ to IrOperator.EQ, - - 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.LT to IrOperator.LT, - KtTokens.LTEQ to IrOperator.LTEQ, - KtTokens.GT to IrOperator.GT, - KtTokens.GTEQ to IrOperator.GTEQ, - - KtTokens.EQEQ to IrOperator.EQEQ, - KtTokens.EXCLEQ to IrOperator.EXCLEQ, - - KtTokens.EQEQEQ to IrOperator.EQEQEQ, - KtTokens.EXCLEQEQEQ to IrOperator.EXCLEQEQ, - - KtTokens.IN_KEYWORD to IrOperator.IN, - KtTokens.NOT_IN to IrOperator.NOT_IN, - - KtTokens.ANDAND to IrOperator.ANDAND, - KtTokens.OROR to IrOperator.OROR, - - KtTokens.ELVIS to IrOperator.ELVIS -) - -private val KT_TOKEN_TO_IR_PREFIX_OPERATOR = mapOf( - KtTokens.PLUSPLUS to IrOperator.PREFIX_INCR, - KtTokens.MINUSMINUS to IrOperator.PREFIX_DECR, - KtTokens.EXCL to IrOperator.EXCL, - KtTokens.MINUS to IrOperator.UMINUS -) - -private val KT_TOKEN_TO_IR_POSTFIX_OPERATOR = mapOf( - KtTokens.PLUSPLUS to IrOperator.POSTFIX_INCR, - KtTokens.MINUSMINUS to IrOperator.POSTFIX_DECR, - KtTokens.EXCLEXCL to IrOperator.EXCLEXCL -) +fun getIrTypeOperator(ktOperator: IElementType): IrTypeOperator? = + when (ktOperator) { + KtTokens.IS_KEYWORD -> IrTypeOperator.INSTANCEOF + KtTokens.NOT_IS -> IrTypeOperator.NOT_INSTANCEOF + KtTokens.AS_KEYWORD -> IrTypeOperator.CAST + KtTokens.AS_SAFE -> IrTypeOperator.SAFE_CAST + else -> null + } val AUGMENTED_ASSIGNMENTS = setOf(IrOperator.PLUSEQ, IrOperator.MINUSEQ, IrOperator.MULTEQ, IrOperator.DIVEQ, IrOperator.PERCEQ) diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/OperatorExpressionGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/OperatorExpressionGenerator.kt index 0e64d5fb0c5..245c9a12b0c 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/OperatorExpressionGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/OperatorExpressionGenerator.kt @@ -52,6 +52,33 @@ class OperatorExpressionGenerator(val statementGenerator: StatementGenerator): I TODO("not implemented") } + fun generateCastExpression(expression: KtBinaryExpressionWithTypeRHS): IrExpression { + val ktOperator = expression.operationReference.getReferencedNameElementType() + val irOperator = getIrTypeOperator(ktOperator) + val rhsType = getOrFail(BindingContext.TYPE, expression.right!!) + + val resultType = when (irOperator) { + IrTypeOperator.CAST -> + rhsType + IrTypeOperator.SAFE_CAST -> + rhsType.makeNullable() + else -> + throw AssertionError("Unexpected IrTypeOperator: $irOperator") + } + + return IrTypeOperatorExpressionImpl(expression.startOffset, expression.endOffset, resultType, irOperator, rhsType, + statementGenerator.generateExpression(expression.left)) + } + + fun generateInstanceOfExpression(expression: KtIsExpression): IrStatement { + val ktOperator = expression.operationReference.getReferencedNameElementType() + val irOperator = getIrTypeOperator(ktOperator)!! + val againstType = getOrFail(BindingContext.TYPE, expression.typeReference) + + return IrTypeOperatorExpressionImpl(expression.startOffset, expression.endOffset, context.builtIns.booleanType, irOperator, + againstType, statementGenerator.generateExpression(expression.leftHandSide)) + } + fun generateBinaryExpression(expression: KtBinaryExpression): IrExpression { val ktOperator = expression.operationReference.getReferencedNameElementType() if (ktOperator == KtTokens.IDENTIFIER) { diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt index abad9d8377e..2491003f4ce 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt @@ -247,6 +247,12 @@ class StatementGenerator( override fun visitPostfixExpression(expression: KtPostfixExpression, data: Nothing?): IrStatement = OperatorExpressionGenerator(this).generatePostfixExpression(expression) + override fun visitBinaryWithTypeRHSExpression(expression: KtBinaryExpressionWithTypeRHS, data: Nothing?): IrStatement = + OperatorExpressionGenerator(this).generateCastExpression(expression) + + override fun visitIsExpression(expression: KtIsExpression, data: Nothing?): IrStatement = + OperatorExpressionGenerator(this).generateInstanceOfExpression(expression) + override fun visitIfExpression(expression: KtIfExpression, data: Nothing?): IrStatement { val resultType = getInferredTypeWithSmartcasts(expression) val irWhen = IrWhenExpressionImpl(expression.startOffset, expression.endOffset, resultType) @@ -273,4 +279,6 @@ class StatementGenerator( return irWhen } + + } diff --git a/compiler/testData/ir/irText/elvis.txt b/compiler/testData/ir/irText/elvis.txt index feaa34a9fc1..93ea4b3aea2 100644 --- a/compiler/testData/ir/irText/elvis.txt +++ b/compiler/testData/ir/irText/elvis.txt @@ -17,11 +17,13 @@ IrFile /elvis.kt IrExpressionBody BLOCK type= hasResult=false operator=null WHEN subject=null type=kotlin.Unit - if: DUMMY KtIsExpression type=kotlin.Boolean + if: TYPE_OP operator=NOT_INSTANCEOF typeOperand=kotlin.String + GET_VAR b type=kotlin.Any? operator=null then: RETURN type= LITERAL String type=kotlin.String value='' WHEN subject=null type=kotlin.Unit - if: DUMMY KtIsExpression type=kotlin.Boolean + if: TYPE_OP operator=NOT_INSTANCEOF typeOperand=kotlin.String? + GET_VAR a type=kotlin.Any? operator=null then: RETURN type= LITERAL String type=kotlin.String value='' RETURN type= diff --git a/compiler/testData/ir/irText/smartCasts.txt b/compiler/testData/ir/irText/smartCasts.txt index 4624aa63961..ac4f30942cb 100644 --- a/compiler/testData/ir/irText/smartCasts.txt +++ b/compiler/testData/ir/irText/smartCasts.txt @@ -19,7 +19,8 @@ IrFile /smartCasts.kt IrExpressionBody BLOCK type= hasResult=false operator=null WHEN subject=null type=kotlin.Unit - if: DUMMY KtIsExpression type=kotlin.Boolean + if: TYPE_OP operator=NOT_INSTANCEOF typeOperand=kotlin.String + GET_VAR x type=kotlin.Any operator=null then: RETURN type= CALL .println type=kotlin.Unit operator=null message: GET_PROPERTY .length type=kotlin.Int operator=null @@ -40,7 +41,8 @@ IrFile /smartCasts.kt IrExpressionBody BLOCK type= hasResult=false operator=null WHEN subject=null type=kotlin.Unit - if: DUMMY KtIsExpression type=kotlin.Boolean + if: TYPE_OP operator=NOT_INSTANCEOF typeOperand=kotlin.String + GET_VAR x type=kotlin.Any operator=null then: RETURN type= LITERAL String type=kotlin.String value='' RETURN type= @@ -51,7 +53,8 @@ IrFile /smartCasts.kt IrExpressionBody BLOCK type= hasResult=false operator=null WHEN subject=null type=kotlin.Unit - if: DUMMY KtIsExpression type=kotlin.Boolean + if: TYPE_OP operator=NOT_INSTANCEOF typeOperand=kotlin.String + GET_VAR x type=kotlin.Any operator=null then: RETURN type= LITERAL String type=kotlin.String value='' RETURN type= diff --git a/compiler/testData/ir/irText/smartCastsWithDestructuring.txt b/compiler/testData/ir/irText/smartCastsWithDestructuring.txt index d5010411248..e5bad7aa5d9 100644 --- a/compiler/testData/ir/irText/smartCastsWithDestructuring.txt +++ b/compiler/testData/ir/irText/smartCastsWithDestructuring.txt @@ -15,7 +15,8 @@ IrFile /smartCastsWithDestructuring.kt IrExpressionBody BLOCK type= hasResult=false operator=null WHEN subject=null type=kotlin.Unit - if: DUMMY KtIsExpression type=kotlin.Boolean + if: TYPE_OP operator=NOT_INSTANCEOF typeOperand=I2 + GET_VAR x type=I1 operator=null then: RETURN type= BLOCK type= hasResult=false operator=SYNTHETIC_BLOCK VAR val tmp0: I1 diff --git a/compiler/testData/ir/irText/typeOperators.kt b/compiler/testData/ir/irText/typeOperators.kt new file mode 100644 index 00000000000..cc1d67f214d --- /dev/null +++ b/compiler/testData/ir/irText/typeOperators.kt @@ -0,0 +1,6 @@ +interface IThing + +fun test1(x: Any) = x is IThing +fun test2(x: Any) = x !is IThing +fun test3(x: Any) = x as IThing +fun test4(x: Any) = x as? IThing \ No newline at end of file diff --git a/compiler/testData/ir/irText/typeOperators.txt b/compiler/testData/ir/irText/typeOperators.txt new file mode 100644 index 00000000000..b6b416841b7 --- /dev/null +++ b/compiler/testData/ir/irText/typeOperators.txt @@ -0,0 +1,26 @@ +IrFile /typeOperators.kt + DUMMY IThing + IrFunction public fun test1(/*0*/ x: kotlin.Any): kotlin.Boolean + IrExpressionBody + BLOCK type= hasResult=false operator=null + RETURN type= + TYPE_OP operator=INSTANCEOF typeOperand=IThing + GET_VAR x type=kotlin.Any operator=null + IrFunction public fun test2(/*0*/ x: kotlin.Any): kotlin.Boolean + IrExpressionBody + BLOCK type= hasResult=false operator=null + RETURN type= + TYPE_OP operator=NOT_INSTANCEOF typeOperand=IThing + GET_VAR x type=kotlin.Any operator=null + IrFunction public fun test3(/*0*/ x: kotlin.Any): IThing + IrExpressionBody + BLOCK type= hasResult=false operator=null + RETURN type= + TYPE_OP operator=CAST typeOperand=IThing + GET_VAR x type=kotlin.Any operator=null + IrFunction public fun test4(/*0*/ x: kotlin.Any): IThing? + IrExpressionBody + BLOCK type= hasResult=false operator=null + RETURN type= + TYPE_OP operator=SAFE_CAST typeOperand=IThing + GET_VAR x type=kotlin.Any operator=null diff --git a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java index 9f5e45772cc..1fde8ead47e 100644 --- a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java @@ -208,4 +208,10 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/stringPlus.kt"); doTest(fileName); } + + @TestMetadata("typeOperators.kt") + public void testTypeOperators() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/typeOperators.kt"); + doTest(fileName); + } }