From cf29dce4c2932962e04de981a418eafb6b1de249 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Tue, 12 Feb 2019 10:03:46 +0300 Subject: [PATCH] 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. --- .../generators/ArgumentsGenerationUtils.kt | 9 +- .../kotlin/psi2ir/generators/CallGenerator.kt | 31 +----- .../kotlin/psi2ir/generators/DynamicCalls.kt | 57 ++++++++++ .../generators/OperatorExpressionGenerator.kt | 103 +++++++++++++++--- .../dynamic/dynamicBinaryEqualityOperator.kt | 4 + .../dynamic/dynamicBinaryEqualityOperator.txt | 29 +++++ .../dynamic/dynamicBinaryLogicalOperator.kt | 2 + .../dynamic/dynamicBinaryLogicalOperator.txt | 15 +++ .../irJsText/dynamic/dynamicBinaryOperator.kt | 5 + .../dynamic/dynamicBinaryOperator.txt | 36 ++++++ .../dynamicBinaryRelationalOperator.kt | 4 + .../dynamicBinaryRelationalOperator.txt | 29 +++++ .../irJsText/dynamic/dynamicUnaryOperator.kt | 3 + .../irJsText/dynamic/dynamicUnaryOperator.txt | 19 ++++ .../kotlin/ir/IrJsTextTestCaseGenerated.java | 25 +++++ 15 files changed, 326 insertions(+), 45 deletions(-) create mode 100644 compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DynamicCalls.kt create mode 100644 compiler/testData/ir/irJsText/dynamic/dynamicBinaryEqualityOperator.kt create mode 100644 compiler/testData/ir/irJsText/dynamic/dynamicBinaryEqualityOperator.txt create mode 100644 compiler/testData/ir/irJsText/dynamic/dynamicBinaryLogicalOperator.kt create mode 100644 compiler/testData/ir/irJsText/dynamic/dynamicBinaryLogicalOperator.txt create mode 100644 compiler/testData/ir/irJsText/dynamic/dynamicBinaryOperator.kt create mode 100644 compiler/testData/ir/irJsText/dynamic/dynamicBinaryOperator.txt create mode 100644 compiler/testData/ir/irJsText/dynamic/dynamicBinaryRelationalOperator.kt create mode 100644 compiler/testData/ir/irJsText/dynamic/dynamicBinaryRelationalOperator.txt create mode 100644 compiler/testData/ir/irJsText/dynamic/dynamicUnaryOperator.kt create mode 100644 compiler/testData/ir/irJsText/dynamic/dynamicUnaryOperator.txt diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ArgumentsGenerationUtils.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ArgumentsGenerationUtils.kt index 448b0112ea9..ab418920595 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ArgumentsGenerationUtils.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ArgumentsGenerationUtils.kt @@ -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 -> diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt index b8e9bf02c9c..80ab0acf25f 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt @@ -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 diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DynamicCalls.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DynamicCalls.kt new file mode 100644 index 00000000000..9c918dd7cf4 --- /dev/null +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DynamicCalls.kt @@ -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") + } +} \ No newline at end of file diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/OperatorExpressionGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/OperatorExpressionGenerator.kt index d77def6d51a..2ce2dcab678 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/OperatorExpressionGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/OperatorExpressionGenerator.kt @@ -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) } diff --git a/compiler/testData/ir/irJsText/dynamic/dynamicBinaryEqualityOperator.kt b/compiler/testData/ir/irJsText/dynamic/dynamicBinaryEqualityOperator.kt new file mode 100644 index 00000000000..51f0399c277 --- /dev/null +++ b/compiler/testData/ir/irJsText/dynamic/dynamicBinaryEqualityOperator.kt @@ -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 diff --git a/compiler/testData/ir/irJsText/dynamic/dynamicBinaryEqualityOperator.txt b/compiler/testData/ir/irJsText/dynamic/dynamicBinaryEqualityOperator.txt new file mode 100644 index 00000000000..42dd24e330e --- /dev/null +++ b/compiler/testData/ir/irJsText/dynamic/dynamicBinaryEqualityOperator.txt @@ -0,0 +1,29 @@ +FILE fqName: 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 diff --git a/compiler/testData/ir/irJsText/dynamic/dynamicBinaryLogicalOperator.kt b/compiler/testData/ir/irJsText/dynamic/dynamicBinaryLogicalOperator.kt new file mode 100644 index 00000000000..48409698c97 --- /dev/null +++ b/compiler/testData/ir/irJsText/dynamic/dynamicBinaryLogicalOperator.kt @@ -0,0 +1,2 @@ +fun testAndAnd(d: dynamic) = d && d +fun testOrOr(d: dynamic) = d || d diff --git a/compiler/testData/ir/irJsText/dynamic/dynamicBinaryLogicalOperator.txt b/compiler/testData/ir/irJsText/dynamic/dynamicBinaryLogicalOperator.txt new file mode 100644 index 00000000000..7d933b396ed --- /dev/null +++ b/compiler/testData/ir/irJsText/dynamic/dynamicBinaryLogicalOperator.txt @@ -0,0 +1,15 @@ +FILE fqName: 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 diff --git a/compiler/testData/ir/irJsText/dynamic/dynamicBinaryOperator.kt b/compiler/testData/ir/irJsText/dynamic/dynamicBinaryOperator.kt new file mode 100644 index 00000000000..7b8e1ae89fa --- /dev/null +++ b/compiler/testData/ir/irJsText/dynamic/dynamicBinaryOperator.kt @@ -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 diff --git a/compiler/testData/ir/irJsText/dynamic/dynamicBinaryOperator.txt b/compiler/testData/ir/irJsText/dynamic/dynamicBinaryOperator.txt new file mode 100644 index 00000000000..5c8983eaf33 --- /dev/null +++ b/compiler/testData/ir/irJsText/dynamic/dynamicBinaryOperator.txt @@ -0,0 +1,36 @@ +FILE fqName: 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 diff --git a/compiler/testData/ir/irJsText/dynamic/dynamicBinaryRelationalOperator.kt b/compiler/testData/ir/irJsText/dynamic/dynamicBinaryRelationalOperator.kt new file mode 100644 index 00000000000..2827598766b --- /dev/null +++ b/compiler/testData/ir/irJsText/dynamic/dynamicBinaryRelationalOperator.kt @@ -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 \ No newline at end of file diff --git a/compiler/testData/ir/irJsText/dynamic/dynamicBinaryRelationalOperator.txt b/compiler/testData/ir/irJsText/dynamic/dynamicBinaryRelationalOperator.txt new file mode 100644 index 00000000000..4f9a5542bf1 --- /dev/null +++ b/compiler/testData/ir/irJsText/dynamic/dynamicBinaryRelationalOperator.txt @@ -0,0 +1,29 @@ +FILE fqName: 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 diff --git a/compiler/testData/ir/irJsText/dynamic/dynamicUnaryOperator.kt b/compiler/testData/ir/irJsText/dynamic/dynamicUnaryOperator.kt new file mode 100644 index 00000000000..9d4240a1f01 --- /dev/null +++ b/compiler/testData/ir/irJsText/dynamic/dynamicUnaryOperator.kt @@ -0,0 +1,3 @@ +fun testUnaryMinus(d: dynamic) = -d +fun testUnaryPlus(d: dynamic) = +d +fun testExcl(d: dynamic) = !d \ No newline at end of file diff --git a/compiler/testData/ir/irJsText/dynamic/dynamicUnaryOperator.txt b/compiler/testData/ir/irJsText/dynamic/dynamicUnaryOperator.txt new file mode 100644 index 00000000000..a1a276bea6a --- /dev/null +++ b/compiler/testData/ir/irJsText/dynamic/dynamicUnaryOperator.txt @@ -0,0 +1,19 @@ +FILE fqName: 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 diff --git a/compiler/tests/org/jetbrains/kotlin/ir/IrJsTextTestCaseGenerated.java b/compiler/tests/org/jetbrains/kotlin/ir/IrJsTextTestCaseGenerated.java index 5b1ab3342b5..0cc6feb56a6 100644 --- a/compiler/tests/org/jetbrains/kotlin/ir/IrJsTextTestCaseGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/ir/IrJsTextTestCaseGenerated.java @@ -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");