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 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<IElementType, IrBinaryOperator>(
|
||||
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<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
|
||||
)
|
||||
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)
|
||||
|
||||
+27
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+4
-2
@@ -17,11 +17,13 @@ IrFile /elvis.kt
|
||||
IrExpressionBody
|
||||
BLOCK type=<no-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=<no-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=<no-type>
|
||||
LITERAL String type=kotlin.String value=''
|
||||
RETURN type=<no-type>
|
||||
|
||||
+6
-3
@@ -19,7 +19,8 @@ IrFile /smartCasts.kt
|
||||
IrExpressionBody
|
||||
BLOCK type=<no-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=<no-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=<no-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=<no-type>
|
||||
LITERAL String type=kotlin.String value=''
|
||||
RETURN type=<no-type>
|
||||
@@ -51,7 +53,8 @@ IrFile /smartCasts.kt
|
||||
IrExpressionBody
|
||||
BLOCK type=<no-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=<no-type>
|
||||
LITERAL String type=kotlin.String value=''
|
||||
RETURN type=<no-type>
|
||||
|
||||
@@ -15,7 +15,8 @@ IrFile /smartCastsWithDestructuring.kt
|
||||
IrExpressionBody
|
||||
BLOCK type=<no-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=<no-type>
|
||||
BLOCK type=<no-type> hasResult=false operator=SYNTHETIC_BLOCK
|
||||
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");
|
||||
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