Type operators.

This commit is contained in:
Dmitry Petrov
2016-08-19 11:33:44 +03:00
committed by Dmitry Petrov
parent 5709826096
commit d6040d8570
9 changed files with 135 additions and 57 deletions
@@ -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)
@@ -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
View File
@@ -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
View File
@@ -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
+6
View File
@@ -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
View File
@@ -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);
}
} }