Type operators.
This commit is contained in:
committed by
Dmitry Petrov
parent
5709826096
commit
d6040d8570
+50
-51
@@ -19,66 +19,65 @@ package org.jetbrains.kotlin.psi2ir.generators
|
|||||||
import com.intellij.psi.tree.IElementType
|
import com.intellij.psi.tree.IElementType
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrBinaryOperator
|
import org.jetbrains.kotlin.ir.expressions.IrBinaryOperator
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrOperator
|
import org.jetbrains.kotlin.ir.expressions.IrOperator
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrTypeOperator
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
|
|
||||||
|
|
||||||
fun getIrBinaryOperator(ktOperator: IElementType): IrBinaryOperator? =
|
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? =
|
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? =
|
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<IElementType, IrBinaryOperator>(
|
fun getIrTypeOperator(ktOperator: IElementType): IrTypeOperator? =
|
||||||
KtTokens.EQ to IrOperator.EQ,
|
when (ktOperator) {
|
||||||
|
KtTokens.IS_KEYWORD -> IrTypeOperator.INSTANCEOF
|
||||||
KtTokens.PLUSEQ to IrOperator.PLUSEQ,
|
KtTokens.NOT_IS -> IrTypeOperator.NOT_INSTANCEOF
|
||||||
KtTokens.MINUSEQ to IrOperator.MINUSEQ,
|
KtTokens.AS_KEYWORD -> IrTypeOperator.CAST
|
||||||
KtTokens.MULTEQ to IrOperator.MULTEQ,
|
KtTokens.AS_SAFE -> IrTypeOperator.SAFE_CAST
|
||||||
KtTokens.DIVEQ to IrOperator.DIVEQ,
|
else -> null
|
||||||
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<IElementType, IrOperator>(
|
|
||||||
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<IElementType, IrOperator>(
|
|
||||||
KtTokens.PLUSPLUS to IrOperator.POSTFIX_INCR,
|
|
||||||
KtTokens.MINUSMINUS to IrOperator.POSTFIX_DECR,
|
|
||||||
KtTokens.EXCLEXCL to IrOperator.EXCLEXCL
|
|
||||||
)
|
|
||||||
|
|
||||||
val AUGMENTED_ASSIGNMENTS =
|
val AUGMENTED_ASSIGNMENTS =
|
||||||
setOf(IrOperator.PLUSEQ, IrOperator.MINUSEQ, IrOperator.MULTEQ, IrOperator.DIVEQ, IrOperator.PERCEQ)
|
setOf(IrOperator.PLUSEQ, IrOperator.MINUSEQ, IrOperator.MULTEQ, IrOperator.DIVEQ, IrOperator.PERCEQ)
|
||||||
|
|||||||
+27
@@ -52,6 +52,33 @@ class OperatorExpressionGenerator(val statementGenerator: StatementGenerator): I
|
|||||||
TODO("not implemented")
|
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 {
|
fun generateBinaryExpression(expression: KtBinaryExpression): IrExpression {
|
||||||
val ktOperator = expression.operationReference.getReferencedNameElementType()
|
val ktOperator = expression.operationReference.getReferencedNameElementType()
|
||||||
if (ktOperator == KtTokens.IDENTIFIER) {
|
if (ktOperator == KtTokens.IDENTIFIER) {
|
||||||
|
|||||||
@@ -247,6 +247,12 @@ class StatementGenerator(
|
|||||||
override fun visitPostfixExpression(expression: KtPostfixExpression, data: Nothing?): IrStatement =
|
override fun visitPostfixExpression(expression: KtPostfixExpression, data: Nothing?): IrStatement =
|
||||||
OperatorExpressionGenerator(this).generatePostfixExpression(expression)
|
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 {
|
override fun visitIfExpression(expression: KtIfExpression, data: Nothing?): IrStatement {
|
||||||
val resultType = getInferredTypeWithSmartcasts(expression)
|
val resultType = getInferredTypeWithSmartcasts(expression)
|
||||||
val irWhen = IrWhenExpressionImpl(expression.startOffset, expression.endOffset, resultType)
|
val irWhen = IrWhenExpressionImpl(expression.startOffset, expression.endOffset, resultType)
|
||||||
@@ -273,4 +279,6 @@ class StatementGenerator(
|
|||||||
|
|
||||||
return irWhen
|
return irWhen
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-2
@@ -17,11 +17,13 @@ IrFile /elvis.kt
|
|||||||
IrExpressionBody
|
IrExpressionBody
|
||||||
BLOCK type=<no-type> hasResult=false operator=null
|
BLOCK type=<no-type> hasResult=false operator=null
|
||||||
WHEN subject=null type=kotlin.Unit
|
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=<no-type>
|
then: RETURN type=<no-type>
|
||||||
LITERAL String type=kotlin.String value=''
|
LITERAL String type=kotlin.String value=''
|
||||||
WHEN subject=null type=kotlin.Unit
|
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=<no-type>
|
then: RETURN type=<no-type>
|
||||||
LITERAL String type=kotlin.String value=''
|
LITERAL String type=kotlin.String value=''
|
||||||
RETURN type=<no-type>
|
RETURN type=<no-type>
|
||||||
|
|||||||
+6
-3
@@ -19,7 +19,8 @@ IrFile /smartCasts.kt
|
|||||||
IrExpressionBody
|
IrExpressionBody
|
||||||
BLOCK type=<no-type> hasResult=false operator=null
|
BLOCK type=<no-type> hasResult=false operator=null
|
||||||
WHEN subject=null type=kotlin.Unit
|
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=<no-type>
|
then: RETURN type=<no-type>
|
||||||
CALL .println type=kotlin.Unit operator=null
|
CALL .println type=kotlin.Unit operator=null
|
||||||
message: GET_PROPERTY .length type=kotlin.Int operator=null
|
message: GET_PROPERTY .length type=kotlin.Int operator=null
|
||||||
@@ -40,7 +41,8 @@ IrFile /smartCasts.kt
|
|||||||
IrExpressionBody
|
IrExpressionBody
|
||||||
BLOCK type=<no-type> hasResult=false operator=null
|
BLOCK type=<no-type> hasResult=false operator=null
|
||||||
WHEN subject=null type=kotlin.Unit
|
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=<no-type>
|
then: RETURN type=<no-type>
|
||||||
LITERAL String type=kotlin.String value=''
|
LITERAL String type=kotlin.String value=''
|
||||||
RETURN type=<no-type>
|
RETURN type=<no-type>
|
||||||
@@ -51,7 +53,8 @@ IrFile /smartCasts.kt
|
|||||||
IrExpressionBody
|
IrExpressionBody
|
||||||
BLOCK type=<no-type> hasResult=false operator=null
|
BLOCK type=<no-type> hasResult=false operator=null
|
||||||
WHEN subject=null type=kotlin.Unit
|
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=<no-type>
|
then: RETURN type=<no-type>
|
||||||
LITERAL String type=kotlin.String value=''
|
LITERAL String type=kotlin.String value=''
|
||||||
RETURN type=<no-type>
|
RETURN type=<no-type>
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ IrFile /smartCastsWithDestructuring.kt
|
|||||||
IrExpressionBody
|
IrExpressionBody
|
||||||
BLOCK type=<no-type> hasResult=false operator=null
|
BLOCK type=<no-type> hasResult=false operator=null
|
||||||
WHEN subject=null type=kotlin.Unit
|
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=<no-type>
|
then: RETURN type=<no-type>
|
||||||
BLOCK type=<no-type> hasResult=false operator=SYNTHETIC_BLOCK
|
BLOCK type=<no-type> hasResult=false operator=SYNTHETIC_BLOCK
|
||||||
VAR val tmp0: I1
|
VAR val tmp0: I1
|
||||||
|
|||||||
@@ -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
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
IrFile /typeOperators.kt
|
||||||
|
DUMMY IThing
|
||||||
|
IrFunction public fun test1(/*0*/ x: kotlin.Any): kotlin.Boolean
|
||||||
|
IrExpressionBody
|
||||||
|
BLOCK type=<no-type> hasResult=false operator=null
|
||||||
|
RETURN type=<no-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=<no-type> hasResult=false operator=null
|
||||||
|
RETURN type=<no-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=<no-type> hasResult=false operator=null
|
||||||
|
RETURN type=<no-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=<no-type> hasResult=false operator=null
|
||||||
|
RETURN type=<no-type>
|
||||||
|
TYPE_OP operator=SAFE_CAST typeOperand=IThing
|
||||||
|
GET_VAR x type=kotlin.Any operator=null
|
||||||
@@ -208,4 +208,10 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
|
|||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/stringPlus.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/stringPlus.kt");
|
||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("typeOperators.kt")
|
||||||
|
public void testTypeOperators() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/typeOperators.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user