'?:' (currently represented as binary expression with operator ELVIS)

This commit is contained in:
Dmitry Petrov
2016-08-17 18:04:34 +03:00
committed by Dmitry Petrov
parent 0d94c3aeb4
commit 8de21aadfa
6 changed files with 76 additions and 3 deletions
@@ -54,7 +54,12 @@ internal val KT_TOKEN_TO_IR_OPERATOR =
KtTokens.EXCLEQEQEQ to IrOperator.EXCLEQEQ,
KtTokens.IN_KEYWORD to IrOperator.IN,
KtTokens.NOT_IN to IrOperator.NOT_IN
KtTokens.NOT_IN to IrOperator.NOT_IN,
KtTokens.ANDAND to IrOperator.ANDAND,
KtTokens.OROR to IrOperator.OROR,
KtTokens.ELVIS to IrOperator.ELVIS
)
internal val AUGMENTED_ASSIGNMENTS =
@@ -74,3 +79,6 @@ internal val IDENTITY_OPERATORS =
internal val IN_OPERATORS =
setOf(IrOperator.IN, IrOperator.NOT_IN)
internal val BINARY_BOOLEAN_OPERATORS =
setOf(IrOperator.ANDAND, IrOperator.OROR)
@@ -44,16 +44,39 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat
return when (irOperator) {
null -> createDummyExpression(expression, ktOperator.toString())
IrOperator.EQ -> generateAssignment(expression)
IrOperator.ELVIS -> generateElvis(expression)
in AUGMENTED_ASSIGNMENTS -> generateAugmentedAssignment(expression, irOperator)
in BINARY_OPERATORS_DESUGARED_TO_CALLS -> generateBinaryOperatorWithConventionalCall(expression, irOperator)
in COMPARISON_OPERATORS -> generateComparisonOperator(expression, irOperator)
in EQUALITY_OPERATORS -> generateEqualityOperator(expression, irOperator)
in IDENTITY_OPERATORS -> generateIdentityOperator(expression, irOperator)
in IN_OPERATORS -> generateInOperator(expression, irOperator)
in BINARY_BOOLEAN_OPERATORS -> generateBinaryBooleanOperator(expression, irOperator)
else -> createDummyExpression(expression, ktOperator.toString())
}
}
private fun generateElvis(expression: KtBinaryExpression): IrExpression {
// TODO desugar '?:' to 'if'?
val specialCallForElvis = getResolvedCall(expression)!!
val returnType = specialCallForElvis.resultingDescriptor.returnType!!
val irArgument0 = irStatementGenerator.generateExpression(expression.left!!).toExpectedType(returnType.makeNullable())
val irArgument1 = irStatementGenerator.generateExpression(expression.right!!).toExpectedType(returnType)
return IrBinaryOperatorExpressionImpl(
expression.startOffset, expression.endOffset, returnType,
IrOperator.ELVIS, null, irArgument0, irArgument1
)
}
private fun generateBinaryBooleanOperator(expression: KtBinaryExpression, irOperator: IrOperator): IrExpression {
val irArgument0 = irStatementGenerator.generateExpression(expression.left!!).toExpectedType(context.builtIns.booleanType)
val irArgument1 = irStatementGenerator.generateExpression(expression.right!!).toExpectedType(context.builtIns.booleanType)
return IrBinaryOperatorExpressionImpl(
expression.startOffset, expression.endOffset, context.builtIns.booleanType,
irOperator, null, irArgument0, irArgument1
)
}
private fun generateInOperator(expression: KtBinaryExpression, irOperator: IrOperator): IrExpression {
val operatorCall = getResolvedCall(expression)!!
@@ -102,10 +102,12 @@ class IrStatementGenerator(
override fun visitReturnExpression(expression: KtReturnExpression, data: Nothing?): IrStatement {
val returnTarget = getReturnExpressionTarget(expression)
val irReturnedExpression = expression.returnedExpression?.let {
it.genExpr().toExpectedType(returnTarget.returnType)
}
return IrReturnExpressionImpl(
expression.startOffset, expression.endOffset,
returnTarget,
expression.returnedExpression?.let { it.genExpr().toExpectedType(returnTarget.returnType) }
returnTarget, irReturnedExpression
)
}
+8
View File
@@ -0,0 +1,8 @@
fun test1(a: Any?, b: Any) = a ?: b
fun test2(a: String?, b: Any) = a ?: b
fun test3(a: Any?, b: Any?): String {
if (b !is String) return ""
if (a !is String?) return ""
return a ?: b
}
+26
View File
@@ -0,0 +1,26 @@
IrFile /elvis.kt
IrFunction public fun test1(/*0*/ a: kotlin.Any?, /*1*/ b: kotlin.Any): kotlin.Any
IrExpressionBody
BLOCK type=<no-type> hasResult=false isDesugared=true
RETURN type=<no-type>
BINARY_OP operator=ELVIS type=kotlin.Any related=null
GET_VAR a type=kotlin.Any?
GET_VAR b type=kotlin.Any
IrFunction public fun test2(/*0*/ a: kotlin.String?, /*1*/ b: kotlin.Any): kotlin.Any
IrExpressionBody
BLOCK type=<no-type> hasResult=false isDesugared=true
RETURN type=<no-type>
BINARY_OP operator=ELVIS type=kotlin.Any related=null
GET_VAR a type=kotlin.String?
GET_VAR b type=kotlin.Any
IrFunction public fun test3(/*0*/ a: kotlin.Any?, /*1*/ b: kotlin.Any?): kotlin.String
IrExpressionBody
BLOCK type=<no-type> hasResult=false isDesugared=false
DUMMY KtIfExpression type=kotlin.Unit
DUMMY KtIfExpression type=kotlin.Unit
RETURN type=<no-type>
BINARY_OP operator=ELVIS type=kotlin.String related=null
TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.String?
GET_VAR a type=kotlin.Any?
TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.String
GET_VAR b type=kotlin.Any?
@@ -107,6 +107,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
doTest(fileName);
}
@TestMetadata("elvis.kt")
public void testElvis() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/elvis.kt");
doTest(fileName);
}
@TestMetadata("equality.kt")
public void testEquality() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/equality.kt");