pri2ir: dynamic unary & binary expressions

NB1 Not every dynamic unary or binary expression is translated to
dynamic operator expressions literally. For example, assignments and
increments can have safe calls in LHS, which require some extra logic.

NB2 There are some open design questions left regarding how dynamic
expressions should actually be translated.
This commit is contained in:
Dmitry Petrov
2019-02-12 10:03:46 +03:00
parent 82701de87b
commit cf29dce4c2
15 changed files with 326 additions and 45 deletions
@@ -267,8 +267,13 @@ fun StatementGenerator.generateValueArgumentUsing(
when (valueArgument) {
is DefaultValueArgument ->
null
is ExpressionValueArgument ->
generateArgumentExpression(valueArgument.valueArgument!!.getArgumentExpression()!!)
is ExpressionValueArgument -> {
val valueArgument1 = valueArgument.valueArgument
?: throw AssertionError("No value argument: $valueArgument")
val argumentExpression = valueArgument1.getArgumentExpression()
?: throw AssertionError("No argument expression: $valueArgument1")
generateArgumentExpression(argumentExpression)
}
is VarargValueArgument ->
generateVarargExpressionUsing(valueArgument, valueParameter, generateArgumentExpression)
else ->
@@ -26,10 +26,7 @@ import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.util.referenceFunction
import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.load.java.sam.SamConstructorDescriptor
import org.jetbrains.kotlin.psi.KtArrayAccessExpression
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffsetSkippingComments
import org.jetbrains.kotlin.psi2ir.intermediate.*
@@ -41,7 +38,6 @@ import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.descriptorUtil.classValueType
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.util.OperatorNameConventions
import java.util.*
class CallGenerator(statementGenerator: StatementGenerator) : StatementGeneratorExtension(statementGenerator) {
@@ -237,19 +233,6 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator
return dispatchReceiver
}
private fun ResolvedCall<*>.isImplicitInvoke(): Boolean {
if (resultingDescriptor.name != OperatorNameConventions.INVOKE) return false
val callExpression = call.callElement as? KtCallExpression ?: return true
val calleeExpression = callExpression.calleeExpression as? KtSimpleNameExpression ?: return true
return calleeExpression.getReferencedName() != OperatorNameConventions.INVOKE.asString()
}
private fun ResolvedCall<*>.isImplicitGet(): Boolean =
resultingDescriptor.name == OperatorNameConventions.GET && call.callElement is KtArrayAccessExpression
private fun ResolvedCall<*>.isImplicitSet(): Boolean =
resultingDescriptor.name == OperatorNameConventions.SET && call.callElement is KtArrayAccessExpression
private fun generateFunctionCall(
functionDescriptor: FunctionDescriptor,
startOffset: Int,
@@ -269,12 +252,8 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator
operator
)
fun makeDynamicOperatorExpression(operator: IrDynamicOperator, dynamicReceiver: IrExpression) =
IrDynamicOperatorExpressionImpl(
startOffset, endOffset,
irType,
operator
).apply {
fun makeDynamicOperatorExpressionWithArguments(operator: IrDynamicOperator, dynamicReceiver: IrExpression) =
makeDynamicOperatorExpression(operator).apply {
receiver = dynamicReceiver
arguments.addAll(call.getValueArgumentsInParameterOrder().mapIndexed { index: Int, arg: IrExpression? ->
arg ?: throw AssertionError("No argument in dynamic call $functionDescriptor at position $index")
@@ -285,9 +264,9 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator
when {
call.original.isImplicitInvoke() ->
makeDynamicOperatorExpression(IrDynamicOperator.INVOKE, dynamicReceiver)
makeDynamicOperatorExpressionWithArguments(IrDynamicOperator.INVOKE, dynamicReceiver)
call.original.isImplicitGet() ->
makeDynamicOperatorExpression(IrDynamicOperator.ARRAY_ACCESS, dynamicReceiver)
makeDynamicOperatorExpressionWithArguments(IrDynamicOperator.ARRAY_ACCESS, dynamicReceiver)
call.original.isImplicitSet() ->
makeDynamicOperatorExpression(IrDynamicOperator.EQ).apply {
val args = call.getValueArgumentsInParameterOrder()
@@ -303,7 +282,7 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator
arguments.add(arg1)
}
else ->
makeDynamicOperatorExpression(
makeDynamicOperatorExpressionWithArguments(
IrDynamicOperator.INVOKE,
IrDynamicMemberExpressionImpl(
startOffset, endOffset, // TODO obtain more exact start/end offsets for explicit receiver expression
@@ -0,0 +1,57 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.psi2ir.generators
import org.jetbrains.kotlin.ir.expressions.IrDynamicOperator
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.util.OperatorNameConventions
internal fun ResolvedCall<*>.isImplicitInvoke(): Boolean {
if (resultingDescriptor.name != OperatorNameConventions.INVOKE) return false
val callExpression = call.callElement as? KtCallExpression ?: return true
val calleeExpression = callExpression.calleeExpression as? KtSimpleNameExpression ?: return true
return calleeExpression.getReferencedName() != OperatorNameConventions.INVOKE.asString()
}
internal fun ResolvedCall<*>.isImplicitGet(): Boolean =
resultingDescriptor.name == OperatorNameConventions.GET && call.callElement is KtArrayAccessExpression
internal fun ResolvedCall<*>.isImplicitSet(): Boolean =
resultingDescriptor.name == OperatorNameConventions.SET && call.callElement is KtArrayAccessExpression
internal fun KtElement.getDynamicOperator(): IrDynamicOperator {
return when (this) {
is KtUnaryExpression ->
when (operationToken) {
KtTokens.PLUS -> IrDynamicOperator.UNARY_PLUS
KtTokens.MINUS -> IrDynamicOperator.UNARY_MINUS
KtTokens.EXCL -> IrDynamicOperator.EXCL
else -> throw AssertionError("Unexpected unary operator expression: $text")
}
is KtBinaryExpression ->
when (operationToken) {
KtTokens.PLUS -> IrDynamicOperator.BINARY_PLUS
KtTokens.MINUS -> IrDynamicOperator.BINARY_MINUS
KtTokens.MUL -> IrDynamicOperator.MUL
KtTokens.DIV -> IrDynamicOperator.DIV
KtTokens.PERC -> IrDynamicOperator.MOD
KtTokens.LT -> IrDynamicOperator.LT
KtTokens.LTEQ -> IrDynamicOperator.LE
KtTokens.GT -> IrDynamicOperator.GT
KtTokens.GTEQ -> IrDynamicOperator.GE
KtTokens.ANDAND -> IrDynamicOperator.ANDAND
KtTokens.OROR -> IrDynamicOperator.OROR
KtTokens.EQEQ -> IrDynamicOperator.EQEQ
KtTokens.EQEQEQ -> IrDynamicOperator.EQEQEQ
KtTokens.EXCLEQ -> IrDynamicOperator.EXCLEQ
KtTokens.EXCLEQEQEQ -> IrDynamicOperator.EXCLEQEQ
else -> throw AssertionError("Unexpected binary operator expression: $text")
}
else -> throw AssertionError("Unexpected operator expression: $text")
}
}
@@ -20,10 +20,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.expressions.IrDynamicOperator
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
import org.jetbrains.kotlin.ir.expressions.IrTypeOperator
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.IrType
@@ -44,6 +41,7 @@ import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.checkers.PrimitiveNumericComparisonInfo
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.isDynamic
import org.jetbrains.kotlin.types.typeUtil.isPrimitiveNumberType
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
import org.jetbrains.kotlin.types.typeUtil.makeNullable
@@ -148,6 +146,51 @@ class OperatorExpressionGenerator(statementGenerator: StatementGenerator) : Stat
}
}
private fun isDynamicUnaryOperator(ktUnaryExpression: KtUnaryExpression): Boolean {
val arg = ktUnaryExpression.baseExpression ?: return false
val argType = context.bindingContext.getType(arg) ?: return false
return argType.isDynamic()
}
private fun isDynamicBinaryOperator(ktExpression: KtBinaryExpression): Boolean {
val lhs = ktExpression.left ?: return false
val lhsType = context.bindingContext.getType(lhs) ?: return false
return lhsType.isDynamic()
}
private fun generateDynamicUnaryExpression(ktExpression: KtUnaryExpression): IrExpression {
val ktArg = ktExpression.baseExpression ?: throw AssertionError("No arg in ${ktExpression.text}")
val kotlinType = context.bindingContext.getType(ktExpression) ?: throw AssertionError("No type for ${ktExpression.text}")
val operator = ktExpression.getDynamicOperator()
return IrDynamicOperatorExpressionImpl(
ktExpression.startOffsetSkippingComments,
ktExpression.endOffset,
kotlinType.toIrType(),
operator
).apply {
receiver = ktArg.genExpr()
}
}
private fun generateDynamicBinaryExpression(ktExpression: KtBinaryExpression): IrExpression {
val ktLeft = ktExpression.left ?: throw AssertionError("No LHS in ${ktExpression.text}")
val ktRight = ktExpression.right ?: throw AssertionError("No RHS in ${ktExpression.text}")
val kotlinType = context.bindingContext.getType(ktExpression) ?: throw AssertionError("No type for ${ktExpression.text}")
val operator = ktExpression.getDynamicOperator()
return IrDynamicOperatorExpressionImpl(
ktExpression.startOffsetSkippingComments,
ktExpression.endOffset,
kotlinType.toIrType(),
operator
).apply {
left = ktLeft.genExpr()
right = ktRight.genExpr()
}
}
private fun generateElvis(expression: KtBinaryExpression): IrExpression {
val specialCallForElvis = getResolvedCall(expression)!!
val resultType = specialCallForElvis.resultingDescriptor.returnType!!.toIrType()
@@ -165,14 +208,23 @@ class OperatorExpressionGenerator(statementGenerator: StatementGenerator) : Stat
}
}
private fun generateBinaryBooleanOperator(expression: KtBinaryExpression, irOperator: IrStatementOrigin): IrExpression {
val irArgument0 = expression.left!!.genExpr()
val irArgument1 = expression.right!!.genExpr()
private fun generateBinaryBooleanOperator(ktExpression: KtBinaryExpression, irOperator: IrStatementOrigin): IrExpression {
if (isDynamicBinaryOperator(ktExpression)) return generateDynamicBinaryExpression(ktExpression)
val ktLeft = ktExpression.left ?: throw AssertionError("No LHS in ${ktExpression.text}")
val ktRight = ktExpression.right ?: throw AssertionError("No RHS in ${ktExpression.text}")
val irArgument0 = ktLeft.genExpr()
val irArgument1 = ktRight.genExpr()
val startOffset = ktExpression.startOffsetSkippingComments
val endOffset = ktExpression.endOffset
return when (irOperator) {
IrStatementOrigin.OROR ->
context.oror(expression.startOffsetSkippingComments, expression.endOffset, irArgument0, irArgument1)
context.oror(startOffset, endOffset, irArgument0, irArgument1)
IrStatementOrigin.ANDAND ->
context.andand(expression.startOffsetSkippingComments, expression.endOffset, irArgument0, irArgument1)
context.andand(startOffset, endOffset, irArgument0, irArgument1)
else ->
throw AssertionError("Unexpected binary boolean operator $irOperator")
}
@@ -201,6 +253,8 @@ class OperatorExpressionGenerator(statementGenerator: StatementGenerator) : Stat
}
private fun generateIdentityOperator(expression: KtBinaryExpression, irOperator: IrStatementOrigin): IrExpression {
if (isDynamicBinaryOperator(expression)) return generateDynamicBinaryExpression(expression)
val irArgument0 = expression.left!!.genExpr()
val irArgument1 = expression.right!!.genExpr()
@@ -237,6 +291,8 @@ class OperatorExpressionGenerator(statementGenerator: StatementGenerator) : Stat
context.bindingContext[BindingContext.PRIMITIVE_NUMERIC_COMPARISON_INFO, ktExpression]
private fun generateEqualityOperator(expression: KtBinaryExpression, irOperator: IrStatementOrigin): IrExpression {
if (isDynamicBinaryOperator(expression)) return generateDynamicBinaryExpression(expression)
val comparisonInfo = getPrimitiveNumericComparisonInfo(expression)
val comparisonType = comparisonInfo?.comparisonType
@@ -356,11 +412,16 @@ class OperatorExpressionGenerator(statementGenerator: StatementGenerator) : Stat
return memberScope.findSingleFunction(Name.identifier("to$targetTypeName"))
}
private fun generateComparisonOperator(expression: KtBinaryExpression, origin: IrStatementOrigin): IrExpression {
val startOffset = expression.startOffsetSkippingComments
val endOffset = expression.endOffset
private fun generateComparisonOperator(ktExpression: KtBinaryExpression, origin: IrStatementOrigin): IrExpression {
if (isDynamicBinaryOperator(ktExpression)) return generateDynamicBinaryExpression(ktExpression)
val comparisonInfo = getPrimitiveNumericComparisonInfo(expression)
val startOffset = ktExpression.startOffsetSkippingComments
val endOffset = ktExpression.endOffset
val comparisonInfo = getPrimitiveNumericComparisonInfo(ktExpression)
val ktLeft = ktExpression.left ?: throw AssertionError("No LHS in ${ktExpression.text}")
val ktRight = ktExpression.right ?: throw AssertionError("No RHS in ${ktExpression.text}")
return if (comparisonInfo != null) {
IrBinaryPrimitiveImpl(
@@ -368,16 +429,19 @@ class OperatorExpressionGenerator(statementGenerator: StatementGenerator) : Stat
context.irBuiltIns.booleanType,
origin,
getComparisonOperatorSymbol(origin, comparisonInfo.comparisonType),
expression.left!!.generateAsPrimitiveNumericComparisonOperand(comparisonInfo.leftType, comparisonInfo.comparisonType),
expression.right!!.generateAsPrimitiveNumericComparisonOperand(comparisonInfo.rightType, comparisonInfo.comparisonType)
ktLeft.generateAsPrimitiveNumericComparisonOperand(comparisonInfo.leftType, comparisonInfo.comparisonType),
ktRight.generateAsPrimitiveNumericComparisonOperand(comparisonInfo.rightType, comparisonInfo.comparisonType)
)
} else {
val resolvedCall = getResolvedCall(ktExpression)
?: throw AssertionError("No resolved call for comparison operator ${ktExpression.text}")
IrBinaryPrimitiveImpl(
startOffset, endOffset,
context.irBuiltIns.booleanType,
origin,
getComparisonOperatorSymbol(origin, context.irBuiltIns.int),
generateCall(getResolvedCall(expression)!!, expression, origin),
generateCall(resolvedCall, ktExpression, origin),
IrConstImpl.int(startOffset, endOffset, context.irBuiltIns.intType, 0)
)
}
@@ -418,7 +482,10 @@ class OperatorExpressionGenerator(statementGenerator: StatementGenerator) : Stat
}
private fun generateBinaryOperatorAsCall(expression: KtBinaryExpression, origin: IrStatementOrigin?): IrExpression =
generateCall(getResolvedCall(expression)!!, expression, origin)
if (isDynamicBinaryOperator(expression))
generateDynamicBinaryExpression(expression)
else
generateCall(getResolvedCall(expression)!!, expression, origin)
private fun generatePrefixOperatorAsCall(expression: KtPrefixExpression, origin: IrStatementOrigin): IrExpression {
val resolvedCall = getResolvedCall(expression)!!
@@ -432,6 +499,8 @@ class OperatorExpressionGenerator(statementGenerator: StatementGenerator) : Stat
}
}
if (isDynamicUnaryOperator(expression)) return generateDynamicUnaryExpression(expression)
return generateCall(resolvedCall, expression, origin)
}
@@ -0,0 +1,4 @@
fun testEqeq(d: dynamic) = d == 3
fun testExclEq(d: dynamic) = d != 3
fun testEqeqeq(d: dynamic) = d === 3
fun testExclEqeq(d: dynamic) = d !== 3
@@ -0,0 +1,29 @@
FILE fqName:<root> fileName:/dynamicBinaryEqualityOperator.kt
FUN name:testEqeq visibility:public modality:FINAL <> (d:dynamic) returnType:kotlin.Boolean flags:
VALUE_PARAMETER name:d index:0 type:dynamic flags:
BLOCK_BODY
RETURN type=kotlin.Nothing from='testEqeq(dynamic): Boolean'
DYN_OP operator=EQEQ type=kotlin.Boolean
receiver: GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null
0: CONST Int type=kotlin.Int value=3
FUN name:testExclEq visibility:public modality:FINAL <> (d:dynamic) returnType:kotlin.Boolean flags:
VALUE_PARAMETER name:d index:0 type:dynamic flags:
BLOCK_BODY
RETURN type=kotlin.Nothing from='testExclEq(dynamic): Boolean'
DYN_OP operator=EXCLEQ type=kotlin.Boolean
receiver: GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null
0: CONST Int type=kotlin.Int value=3
FUN name:testEqeqeq visibility:public modality:FINAL <> (d:dynamic) returnType:kotlin.Boolean flags:
VALUE_PARAMETER name:d index:0 type:dynamic flags:
BLOCK_BODY
RETURN type=kotlin.Nothing from='testEqeqeq(dynamic): Boolean'
DYN_OP operator=EQEQEQ type=kotlin.Boolean
receiver: GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null
0: CONST Int type=kotlin.Int value=3
FUN name:testExclEqeq visibility:public modality:FINAL <> (d:dynamic) returnType:kotlin.Boolean flags:
VALUE_PARAMETER name:d index:0 type:dynamic flags:
BLOCK_BODY
RETURN type=kotlin.Nothing from='testExclEqeq(dynamic): Boolean'
DYN_OP operator=EXCLEQEQ type=kotlin.Boolean
receiver: GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null
0: CONST Int type=kotlin.Int value=3
@@ -0,0 +1,2 @@
fun testAndAnd(d: dynamic) = d && d
fun testOrOr(d: dynamic) = d || d
@@ -0,0 +1,15 @@
FILE fqName:<root> fileName:/dynamicBinaryLogicalOperator.kt
FUN name:testAndAnd visibility:public modality:FINAL <> (d:dynamic) returnType:kotlin.Boolean flags:
VALUE_PARAMETER name:d index:0 type:dynamic flags:
BLOCK_BODY
RETURN type=kotlin.Nothing from='testAndAnd(dynamic): Boolean'
DYN_OP operator=ANDAND type=kotlin.Boolean
receiver: GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null
0: GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null
FUN name:testOrOr visibility:public modality:FINAL <> (d:dynamic) returnType:kotlin.Boolean flags:
VALUE_PARAMETER name:d index:0 type:dynamic flags:
BLOCK_BODY
RETURN type=kotlin.Nothing from='testOrOr(dynamic): Boolean'
DYN_OP operator=OROR type=kotlin.Boolean
receiver: GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null
0: GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null
@@ -0,0 +1,5 @@
fun testBinaryPlus(d: dynamic) = d + 1
fun testBinaryMinus(d: dynamic) = d - 1
fun testMul(d: dynamic) = d * 2
fun testDiv(d: dynamic) = d / 2
fun testMod(d: dynamic) = d % 2
@@ -0,0 +1,36 @@
FILE fqName:<root> fileName:/dynamicBinaryOperator.kt
FUN name:testBinaryPlus visibility:public modality:FINAL <> (d:dynamic) returnType:dynamic flags:
VALUE_PARAMETER name:d index:0 type:dynamic flags:
BLOCK_BODY
RETURN type=kotlin.Nothing from='testBinaryPlus(dynamic): dynamic'
DYN_OP operator=BINARY_PLUS type=dynamic
receiver: GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null
0: CONST Int type=kotlin.Int value=1
FUN name:testBinaryMinus visibility:public modality:FINAL <> (d:dynamic) returnType:dynamic flags:
VALUE_PARAMETER name:d index:0 type:dynamic flags:
BLOCK_BODY
RETURN type=kotlin.Nothing from='testBinaryMinus(dynamic): dynamic'
DYN_OP operator=BINARY_MINUS type=dynamic
receiver: GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null
0: CONST Int type=kotlin.Int value=1
FUN name:testMul visibility:public modality:FINAL <> (d:dynamic) returnType:dynamic flags:
VALUE_PARAMETER name:d index:0 type:dynamic flags:
BLOCK_BODY
RETURN type=kotlin.Nothing from='testMul(dynamic): dynamic'
DYN_OP operator=MUL type=dynamic
receiver: GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null
0: CONST Int type=kotlin.Int value=2
FUN name:testDiv visibility:public modality:FINAL <> (d:dynamic) returnType:dynamic flags:
VALUE_PARAMETER name:d index:0 type:dynamic flags:
BLOCK_BODY
RETURN type=kotlin.Nothing from='testDiv(dynamic): dynamic'
DYN_OP operator=DIV type=dynamic
receiver: GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null
0: CONST Int type=kotlin.Int value=2
FUN name:testMod visibility:public modality:FINAL <> (d:dynamic) returnType:dynamic flags:
VALUE_PARAMETER name:d index:0 type:dynamic flags:
BLOCK_BODY
RETURN type=kotlin.Nothing from='testMod(dynamic): dynamic'
DYN_OP operator=MOD type=dynamic
receiver: GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null
0: CONST Int type=kotlin.Int value=2
@@ -0,0 +1,4 @@
fun testLess(d: dynamic) = d < 2
fun testLessOrEqual(d: dynamic) = d <= 2
fun testGreater(d: dynamic) = d > 2
fun testGreaterOrEqual(d: dynamic) = d >= 2
@@ -0,0 +1,29 @@
FILE fqName:<root> fileName:/dynamicBinaryRelationalOperator.kt
FUN name:testLess visibility:public modality:FINAL <> (d:dynamic) returnType:kotlin.Boolean flags:
VALUE_PARAMETER name:d index:0 type:dynamic flags:
BLOCK_BODY
RETURN type=kotlin.Nothing from='testLess(dynamic): Boolean'
DYN_OP operator=LT type=kotlin.Boolean
receiver: GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null
0: CONST Int type=kotlin.Int value=2
FUN name:testLessOrEqual visibility:public modality:FINAL <> (d:dynamic) returnType:kotlin.Boolean flags:
VALUE_PARAMETER name:d index:0 type:dynamic flags:
BLOCK_BODY
RETURN type=kotlin.Nothing from='testLessOrEqual(dynamic): Boolean'
DYN_OP operator=LE type=kotlin.Boolean
receiver: GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null
0: CONST Int type=kotlin.Int value=2
FUN name:testGreater visibility:public modality:FINAL <> (d:dynamic) returnType:kotlin.Boolean flags:
VALUE_PARAMETER name:d index:0 type:dynamic flags:
BLOCK_BODY
RETURN type=kotlin.Nothing from='testGreater(dynamic): Boolean'
DYN_OP operator=GT type=kotlin.Boolean
receiver: GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null
0: CONST Int type=kotlin.Int value=2
FUN name:testGreaterOrEqual visibility:public modality:FINAL <> (d:dynamic) returnType:kotlin.Boolean flags:
VALUE_PARAMETER name:d index:0 type:dynamic flags:
BLOCK_BODY
RETURN type=kotlin.Nothing from='testGreaterOrEqual(dynamic): Boolean'
DYN_OP operator=GE type=kotlin.Boolean
receiver: GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null
0: CONST Int type=kotlin.Int value=2
@@ -0,0 +1,3 @@
fun testUnaryMinus(d: dynamic) = -d
fun testUnaryPlus(d: dynamic) = +d
fun testExcl(d: dynamic) = !d
@@ -0,0 +1,19 @@
FILE fqName:<root> fileName:/dynamicUnaryOperator.kt
FUN name:testUnaryMinus visibility:public modality:FINAL <> (d:dynamic) returnType:dynamic flags:
VALUE_PARAMETER name:d index:0 type:dynamic flags:
BLOCK_BODY
RETURN type=kotlin.Nothing from='testUnaryMinus(dynamic): dynamic'
DYN_OP operator=UNARY_MINUS type=dynamic
receiver: GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null
FUN name:testUnaryPlus visibility:public modality:FINAL <> (d:dynamic) returnType:dynamic flags:
VALUE_PARAMETER name:d index:0 type:dynamic flags:
BLOCK_BODY
RETURN type=kotlin.Nothing from='testUnaryPlus(dynamic): dynamic'
DYN_OP operator=UNARY_PLUS type=dynamic
receiver: GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null
FUN name:testExcl visibility:public modality:FINAL <> (d:dynamic) returnType:dynamic flags:
VALUE_PARAMETER name:d index:0 type:dynamic flags:
BLOCK_BODY
RETURN type=kotlin.Nothing from='testExcl(dynamic): dynamic'
DYN_OP operator=EXCL type=dynamic
receiver: GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null
@@ -66,6 +66,26 @@ public class IrJsTextTestCaseGenerated extends AbstractIrJsTextTestCase {
runTest("compiler/testData/ir/irJsText/dynamic/dynamicArrayIncrementDecrement.kt");
}
@TestMetadata("dynamicBinaryEqualityOperator.kt")
public void testDynamicBinaryEqualityOperator() throws Exception {
runTest("compiler/testData/ir/irJsText/dynamic/dynamicBinaryEqualityOperator.kt");
}
@TestMetadata("dynamicBinaryLogicalOperator.kt")
public void testDynamicBinaryLogicalOperator() throws Exception {
runTest("compiler/testData/ir/irJsText/dynamic/dynamicBinaryLogicalOperator.kt");
}
@TestMetadata("dynamicBinaryOperator.kt")
public void testDynamicBinaryOperator() throws Exception {
runTest("compiler/testData/ir/irJsText/dynamic/dynamicBinaryOperator.kt");
}
@TestMetadata("dynamicBinaryRelationalOperator.kt")
public void testDynamicBinaryRelationalOperator() throws Exception {
runTest("compiler/testData/ir/irJsText/dynamic/dynamicBinaryRelationalOperator.kt");
}
@TestMetadata("dynamicCall.kt")
public void testDynamicCall() throws Exception {
runTest("compiler/testData/ir/irJsText/dynamic/dynamicCall.kt");
@@ -91,6 +111,11 @@ public class IrJsTextTestCaseGenerated extends AbstractIrJsTextTestCase {
runTest("compiler/testData/ir/irJsText/dynamic/dynamicMemberIncrementDecrement.kt");
}
@TestMetadata("dynamicUnaryOperator.kt")
public void testDynamicUnaryOperator() throws Exception {
runTest("compiler/testData/ir/irJsText/dynamic/dynamicUnaryOperator.kt");
}
@TestMetadata("dynamicWithImplicitCast.kt")
public void testDynamicWithImplicitCast() throws Exception {
runTest("compiler/testData/ir/irJsText/dynamic/dynamicWithImplicitCast.kt");