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..fae0085f964 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 @@ -280,7 +280,7 @@ fun Generator.getSuperQualifier(resolvedCall: ResolvedCall<*>): ClassDescriptor? return getOrFail(BindingContext.REFERENCE_TARGET, superCallExpression.instanceReference) as ClassDescriptor } -fun StatementGenerator.pregenerateCall(resolvedCall: ResolvedCall<*>): CallBuilder { +fun StatementGenerator.pregenerateCall(resolvedCall: ResolvedCall<*>, isVariableAsFunctionCall: Boolean = false): CallBuilder { if (resolvedCall.isExtensionInvokeCall()) { return pregenerateExtensionInvokeCall(resolvedCall) } 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 8588300bf9d..f5f3b23c4c7 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 @@ -21,10 +21,14 @@ import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.* +import org.jetbrains.kotlin.ir.types.IrDynamicType 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.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.* @@ -36,6 +40,7 @@ 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) { @@ -183,12 +188,7 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator } else { call.callReceiver.adjustForCallee(getMethodDescriptor).call { dispatchReceiverValue, extensionReceiverValue -> if (descriptor.isDynamic()) { - val dispatchReceiver = dispatchReceiverValue?.load() - ?: throw AssertionError("Dynamic member reference $descriptor should have a dispatch receiver") - - if (extensionReceiverValue != null) { - throw AssertionError("Dynamic member reference $descriptor should have no extension receiver") - } + val dispatchReceiver = getDynamicExpressionReceiver(dispatchReceiverValue, extensionReceiverValue, descriptor) IrDynamicMemberExpressionImpl( startOffset, endOffset, @@ -216,6 +216,33 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator } } + private fun getDynamicExpressionReceiver( + dispatchReceiverValue: IntermediateValue?, + extensionReceiverValue: IntermediateValue?, + referencedDescriptor: DeclarationDescriptor + ): IrExpression { + val dispatchReceiver = dispatchReceiverValue?.load() + ?: throw AssertionError("Dynamic member reference $referencedDescriptor should have a dispatch receiver") + if (dispatchReceiver.type !is IrDynamicType) { + throw AssertionError( + "Dynamic member reference $referencedDescriptor should have a receiver of dynamic type: ${dispatchReceiver.render()}" + ) + } + + if (extensionReceiverValue != null) { + throw AssertionError("Dynamic member reference $referencedDescriptor should have no extension receiver") + } + + return dispatchReceiver + } + + private fun ResolvedCall<*>.isImplicitInvokeOnDynamic(): Boolean { + if (resultingDescriptor.name != OperatorNameConventions.INVOKE) return false + val callExression = call.callElement as? KtCallExpression ?: return true + val calleeExpression = callExression.calleeExpression as? KtSimpleNameExpression ?: return true + return calleeExpression.getReferencedName() != OperatorNameConventions.INVOKE.asString() + } + private fun generateFunctionCall( functionDescriptor: FunctionDescriptor, startOffset: Int, @@ -225,21 +252,48 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator ): IrExpression = call.callReceiver.call { dispatchReceiverValue, extensionReceiverValue -> val returnType = functionDescriptor.returnType!! - val functionSymbol = context.symbolTable.referenceFunction(functionDescriptor.original) - val superQualifierSymbol = call.superQualifier?.let { context.symbolTable.referenceClass(it) } - val irCall = IrCallImpl( - startOffset, endOffset, - returnType.toIrType(), - functionSymbol, - functionDescriptor, - origin, - superQualifierSymbol - ).apply { - putTypeArguments(call.typeArguments) { it.toIrType() } - this.dispatchReceiver = dispatchReceiverValue?.load() - this.extensionReceiver = extensionReceiverValue?.load() + val irType = returnType.toIrType() + + if (functionDescriptor.isDynamic()) { + IrDynamicOperatorExpressionImpl( + startOffset, endOffset, + irType, + IrDynamicOperator.INVOKE + ).apply { + val dispatchReceiver = getDynamicExpressionReceiver(dispatchReceiverValue, extensionReceiverValue, functionDescriptor) + + receiver = + if (call.original.isImplicitInvokeOnDynamic()) + dispatchReceiver + else + IrDynamicMemberExpressionImpl( + startOffset, endOffset, // TODO obtain more exact start/end offsets for explicit receiver expression + dispatchReceiver.type, + functionDescriptor.name.asString(), + dispatchReceiver + ) + + arguments.addAll(call.getValueArgumentsInParameterOrder().mapIndexed { index: Int, arg: IrExpression? -> + arg ?: throw AssertionError("No argument in dynamic call $functionDescriptor at position $index") + }) + } + } else { + val functionSymbol = context.symbolTable.referenceFunction(functionDescriptor.original) + val superQualifierSymbol = call.superQualifier?.let { context.symbolTable.referenceClass(it) } + val irCall = IrCallImpl( + startOffset, endOffset, + irType, + functionSymbol, + functionDescriptor, + origin, + superQualifierSymbol + ).apply { + putTypeArguments(call.typeArguments) { it.toIrType() } + this.dispatchReceiver = dispatchReceiverValue?.load() + this.extensionReceiver = extensionReceiverValue?.load() + } + addParametersToCall(startOffset, endOffset, call, irCall, returnType) } - addParametersToCall(startOffset, endOffset, call, irCall, returnType) } private fun addParametersToCall( diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt index 7b2aa1ad6bc..f8835252d16 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt @@ -329,7 +329,7 @@ class StatementGenerator( val resolvedCall = getResolvedCall(expression) ?: return ErrorExpressionGenerator(this).generateErrorCall(expression) if (resolvedCall is VariableAsFunctionResolvedCall) { - val functionCall = pregenerateCall(resolvedCall.functionCall) + val functionCall = pregenerateCall(resolvedCall.functionCall, isVariableAsFunctionCall = true) return CallGenerator(this).generateCall(expression, functionCall, IrStatementOrigin.INVOKE) } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrDynamicExpression.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrDynamicExpression.kt index e6d7d8a6ac8..609619bf49f 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrDynamicExpression.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrDynamicExpression.kt @@ -10,12 +10,23 @@ interface IrDynamicExpression : IrExpression interface IrDynamicOperatorExpression : IrDynamicExpression { val operator: IrDynamicOperator - val valueArgumentsCount: Int - fun getValueArgument(index: Int): IrExpression? - fun putValueArgument(index: Int, valueArgument: IrExpression?) - fun removeValueArgument(index: Int) + var receiver: IrExpression + + val arguments: MutableList } +var IrDynamicOperatorExpression.left: IrExpression + get() = receiver + set(value) { + receiver = value + } + +var IrDynamicOperatorExpression.right: IrExpression + get() = arguments[0] + set(value) { + arguments[0] = value + } + interface IrDynamicMemberExpression : IrDynamicExpression { val memberName: String var receiver: IrExpression diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/impl/IrDynamicOperatorExpressionImpl.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/impl/IrDynamicOperatorExpressionImpl.kt index efa18655244..da7d2d9b78e 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/impl/IrDynamicOperatorExpressionImpl.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/impl/IrDynamicOperatorExpressionImpl.kt @@ -16,45 +16,27 @@ class IrDynamicOperatorExpressionImpl( startOffset: Int, endOffset: Int, type: IrType, - override val operator: IrDynamicOperator, - override val valueArgumentsCount: Int + override val operator: IrDynamicOperator ) : IrExpressionBase(startOffset, endOffset, type), IrDynamicOperatorExpression { - private val valueArguments = arrayOfNulls(valueArgumentsCount) - - override fun getValueArgument(index: Int): IrExpression? { - if (index >= valueArgumentsCount) { - throw AssertionError("$this: No such value argument slot: $index") - } - return valueArguments[index] - } - - override fun putValueArgument(index: Int, valueArgument: IrExpression?) { - if (index >= valueArgumentsCount) { - throw AssertionError("$this: No such value argument slot: $index") - } - valueArguments[index] = valueArgument - } - - override fun removeValueArgument(index: Int) { - putValueArgument(index, null) - } + override lateinit var receiver: IrExpression + override val arguments: MutableList = ArrayList() override fun accept(visitor: IrElementVisitor, data: D): R = visitor.visitDynamicOperatorExpression(this, data) override fun acceptChildren(visitor: IrElementVisitor, data: D) { - for (valueArgument in valueArguments) { - valueArgument?.accept(visitor, data) + for (valueArgument in arguments) { + valueArgument.accept(visitor, data) } } override fun transformChildren(transformer: IrElementTransformer, data: D) { - for (i in 0 until valueArgumentsCount) { - valueArguments[i] = valueArguments[i]?.transform(transformer, data) + for (i in arguments.indices) { + arguments[i] = arguments[i].transform(transformer, data) } } } \ No newline at end of file diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTree.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTree.kt index da228d77222..74059862e71 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTree.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTree.kt @@ -652,12 +652,10 @@ open class DeepCopyIrTree : IrElementTransformerVoid() { IrDynamicOperatorExpressionImpl( expression.startOffset, expression.endOffset, expression.type, - expression.operator, - expression.valueArgumentsCount + expression.operator ).apply { - for (i in 0 until expression.valueArgumentsCount) { - putValueArgument(i, expression.getValueArgument(i)?.transform()) - } + receiver = expression.receiver.transform() + expression.arguments.mapTo(arguments) { it.transform() } } override fun visitDynamicMemberExpression(expression: IrDynamicMemberExpression): IrDynamicMemberExpression = diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTreeWithSymbols.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTreeWithSymbols.kt index e05d8aeb58a..3f239aa98fd 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTreeWithSymbols.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTreeWithSymbols.kt @@ -716,12 +716,10 @@ open class DeepCopyIrTreeWithSymbols( IrDynamicOperatorExpressionImpl( expression.startOffset, expression.endOffset, expression.type.remapType(), - expression.operator, - expression.valueArgumentsCount + expression.operator ).apply { - for (i in 0 until expression.valueArgumentsCount) { - putValueArgument(i, expression.getValueArgument(i)?.transform()) - } + receiver = expression.receiver.transform() + expression.arguments.mapTo(arguments) { it.transform() } } override fun visitDynamicMemberExpression(expression: IrDynamicMemberExpression): IrDynamicMemberExpression = diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DumpIrTree.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DumpIrTree.kt index 7dd84590761..5051f14c1e1 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DumpIrTree.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DumpIrTree.kt @@ -258,6 +258,15 @@ class DumpIrTreeVisitor(out: Appendable) : IrElementVisitor { } } + override fun visitDynamicOperatorExpression(expression: IrDynamicOperatorExpression, data: String) { + expression.dumpLabeledElementWith(data) { + expression.receiver.accept(this, "receiver") + for ((i, arg) in expression.arguments.withIndex()) { + arg.accept(this, i.toString()) + } + } + } + private inline fun IrElement.dumpLabeledElementWith(label: String, body: () -> Unit) { printer.println(accept(elementRenderer, null).withLabel(label)) indented(body) diff --git a/compiler/testData/ir/irJsText/dynamic/dynamicCall.kt b/compiler/testData/ir/irJsText/dynamic/dynamicCall.kt new file mode 100644 index 00000000000..7a42237ea11 --- /dev/null +++ b/compiler/testData/ir/irJsText/dynamic/dynamicCall.kt @@ -0,0 +1,7 @@ +fun test1(d: dynamic) = d.member(1, 2, 3) + +fun test2(d: dynamic) = d?.member(1, 2, 3) + +// Named arguments in dynamic calls are ignored by JS back-end. +// If this becomes a compilation error, simply remove this particular test case. +fun test3(d: dynamic) = d.member(a = 1, b = 2, c = 3) \ No newline at end of file diff --git a/compiler/testData/ir/irJsText/dynamic/dynamicCall.txt b/compiler/testData/ir/irJsText/dynamic/dynamicCall.txt new file mode 100644 index 00000000000..2c1dc0b3d7c --- /dev/null +++ b/compiler/testData/ir/irJsText/dynamic/dynamicCall.txt @@ -0,0 +1,42 @@ +FILE fqName: fileName:/dynamicCall.kt + FUN name:test1 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='test1(dynamic): dynamic' + DYN_OP operator=INVOKE type=dynamic + receiver: DYN_MEMBER memberName='member' type=dynamic + GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null + 0: CONST Int type=kotlin.Int value=1 + 1: CONST Int type=kotlin.Int value=2 + 2: CONST Int type=kotlin.Int value=3 + FUN name:test2 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='test2(dynamic): dynamic' + BLOCK type=dynamic origin=SAFE_CALL + VAR IR_TEMPORARY_VARIABLE name:tmp0_safe_receiver type:dynamic flags:val + GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null + WHEN type=dynamic origin=null + BRANCH + if: CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EQEQ + arg0: GET_VAR 'tmp0_safe_receiver: dynamic' type=dynamic origin=null + arg1: CONST Null type=kotlin.Nothing? value=null + then: CONST Null type=kotlin.Nothing? value=null + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: DYN_OP operator=INVOKE type=dynamic + receiver: DYN_MEMBER memberName='member' type=dynamic + GET_VAR 'tmp0_safe_receiver: dynamic' type=dynamic origin=null + 0: CONST Int type=kotlin.Int value=1 + 1: CONST Int type=kotlin.Int value=2 + 2: CONST Int type=kotlin.Int value=3 + FUN name:test3 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='test3(dynamic): dynamic' + DYN_OP operator=INVOKE type=dynamic + receiver: DYN_MEMBER memberName='member' type=dynamic + GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null + 0: CONST Int type=kotlin.Int value=1 + 1: CONST Int type=kotlin.Int value=2 + 2: CONST Int type=kotlin.Int value=3 diff --git a/compiler/testData/ir/irJsText/dynamic/invokeOperator.kt b/compiler/testData/ir/irJsText/dynamic/invokeOperator.kt index 7288711798f..cde4c76f6a3 100644 --- a/compiler/testData/ir/irJsText/dynamic/invokeOperator.kt +++ b/compiler/testData/ir/irJsText/dynamic/invokeOperator.kt @@ -1,9 +1,9 @@ fun invoke() {} fun test1(a: dynamic) = a(1) -fun test1a(a: dynamic) = a.invoke(1) -fun test2(a: dynamic, b: dynamic) = a(b) -fun test2a(a: dynamic, b: dynamic) = a.invoke(b) -fun test2b(a: dynamic, b: dynamic) = a(b)(b) -fun test2c(a: dynamic, b: dynamic) = a(b).invoke(b) -fun test3(a: dynamic) = invoke() \ No newline at end of file +fun test2(a: dynamic) = a.invoke(1) +fun test3(a: dynamic, b: dynamic) = a(b) +fun test4(a: dynamic, b: dynamic) = a.invoke(b) +fun test5(a: dynamic, b: dynamic) = a(b)(b) +fun test6(a: dynamic, b: dynamic) = a(b).invoke(b) +fun test7(a: dynamic) = invoke() \ No newline at end of file diff --git a/compiler/testData/ir/irJsText/dynamic/invokeOperator.txt b/compiler/testData/ir/irJsText/dynamic/invokeOperator.txt index c46f74fc70c..7beb9533034 100644 --- a/compiler/testData/ir/irJsText/dynamic/invokeOperator.txt +++ b/compiler/testData/ir/irJsText/dynamic/invokeOperator.txt @@ -5,54 +5,57 @@ FILE fqName: fileName:/invokeOperator.kt VALUE_PARAMETER name:a index:0 type:dynamic flags: BLOCK_BODY RETURN type=kotlin.Nothing from='test1(dynamic): dynamic' - CALL 'invoke(dynamic): dynamic' type=dynamic origin=INVOKE - $this: GET_VAR 'value-parameter a: dynamic' type=dynamic origin=VARIABLE_AS_FUNCTION - p0: CONST Int type=kotlin.Int value=1 - FUN name:test1a visibility:public modality:FINAL <> (a:dynamic) returnType:dynamic flags: + DYN_OP operator=INVOKE type=dynamic + receiver: GET_VAR 'value-parameter a: dynamic' type=dynamic origin=VARIABLE_AS_FUNCTION + 0: CONST Int type=kotlin.Int value=1 + FUN name:test2 visibility:public modality:FINAL <> (a:dynamic) returnType:dynamic flags: VALUE_PARAMETER name:a index:0 type:dynamic flags: BLOCK_BODY - RETURN type=kotlin.Nothing from='test1a(dynamic): dynamic' - CALL 'invoke(dynamic): dynamic' type=dynamic origin=null - $this: GET_VAR 'value-parameter a: dynamic' type=dynamic origin=null - p0: CONST Int type=kotlin.Int value=1 - FUN name:test2 visibility:public modality:FINAL <> (a:dynamic, b:dynamic) returnType:dynamic flags: + RETURN type=kotlin.Nothing from='test2(dynamic): dynamic' + DYN_OP operator=INVOKE type=dynamic + receiver: DYN_MEMBER memberName='invoke' type=dynamic + GET_VAR 'value-parameter a: dynamic' type=dynamic origin=null + 0: CONST Int type=kotlin.Int value=1 + FUN name:test3 visibility:public modality:FINAL <> (a:dynamic, b:dynamic) returnType:dynamic flags: VALUE_PARAMETER name:a index:0 type:dynamic flags: VALUE_PARAMETER name:b index:1 type:dynamic flags: BLOCK_BODY - RETURN type=kotlin.Nothing from='test2(dynamic, dynamic): dynamic' - CALL 'invoke(dynamic): dynamic' type=dynamic origin=INVOKE - $this: GET_VAR 'value-parameter a: dynamic' type=dynamic origin=VARIABLE_AS_FUNCTION - p0: GET_VAR 'value-parameter b: dynamic' type=dynamic origin=null - FUN name:test2a visibility:public modality:FINAL <> (a:dynamic, b:dynamic) returnType:dynamic flags: + RETURN type=kotlin.Nothing from='test3(dynamic, dynamic): dynamic' + DYN_OP operator=INVOKE type=dynamic + receiver: GET_VAR 'value-parameter a: dynamic' type=dynamic origin=VARIABLE_AS_FUNCTION + 0: GET_VAR 'value-parameter b: dynamic' type=dynamic origin=null + FUN name:test4 visibility:public modality:FINAL <> (a:dynamic, b:dynamic) returnType:dynamic flags: VALUE_PARAMETER name:a index:0 type:dynamic flags: VALUE_PARAMETER name:b index:1 type:dynamic flags: BLOCK_BODY - RETURN type=kotlin.Nothing from='test2a(dynamic, dynamic): dynamic' - CALL 'invoke(dynamic): dynamic' type=dynamic origin=null - $this: GET_VAR 'value-parameter a: dynamic' type=dynamic origin=null - p0: GET_VAR 'value-parameter b: dynamic' type=dynamic origin=null - FUN name:test2b visibility:public modality:FINAL <> (a:dynamic, b:dynamic) returnType:dynamic flags: + RETURN type=kotlin.Nothing from='test4(dynamic, dynamic): dynamic' + DYN_OP operator=INVOKE type=dynamic + receiver: DYN_MEMBER memberName='invoke' type=dynamic + GET_VAR 'value-parameter a: dynamic' type=dynamic origin=null + 0: GET_VAR 'value-parameter b: dynamic' type=dynamic origin=null + FUN name:test5 visibility:public modality:FINAL <> (a:dynamic, b:dynamic) returnType:dynamic flags: VALUE_PARAMETER name:a index:0 type:dynamic flags: VALUE_PARAMETER name:b index:1 type:dynamic flags: BLOCK_BODY - RETURN type=kotlin.Nothing from='test2b(dynamic, dynamic): dynamic' - CALL 'invoke(dynamic): dynamic' type=dynamic origin=INVOKE - $this: CALL 'invoke(dynamic): dynamic' type=dynamic origin=INVOKE - $this: GET_VAR 'value-parameter a: dynamic' type=dynamic origin=VARIABLE_AS_FUNCTION - p0: GET_VAR 'value-parameter b: dynamic' type=dynamic origin=null - p0: GET_VAR 'value-parameter b: dynamic' type=dynamic origin=null - FUN name:test2c visibility:public modality:FINAL <> (a:dynamic, b:dynamic) returnType:dynamic flags: + RETURN type=kotlin.Nothing from='test5(dynamic, dynamic): dynamic' + DYN_OP operator=INVOKE type=dynamic + receiver: DYN_OP operator=INVOKE type=dynamic + receiver: GET_VAR 'value-parameter a: dynamic' type=dynamic origin=VARIABLE_AS_FUNCTION + 0: GET_VAR 'value-parameter b: dynamic' type=dynamic origin=null + 0: GET_VAR 'value-parameter b: dynamic' type=dynamic origin=null + FUN name:test6 visibility:public modality:FINAL <> (a:dynamic, b:dynamic) returnType:dynamic flags: VALUE_PARAMETER name:a index:0 type:dynamic flags: VALUE_PARAMETER name:b index:1 type:dynamic flags: BLOCK_BODY - RETURN type=kotlin.Nothing from='test2c(dynamic, dynamic): dynamic' - CALL 'invoke(dynamic): dynamic' type=dynamic origin=null - $this: CALL 'invoke(dynamic): dynamic' type=dynamic origin=INVOKE - $this: GET_VAR 'value-parameter a: dynamic' type=dynamic origin=VARIABLE_AS_FUNCTION - p0: GET_VAR 'value-parameter b: dynamic' type=dynamic origin=null - p0: GET_VAR 'value-parameter b: dynamic' type=dynamic origin=null - FUN name:test3 visibility:public modality:FINAL <> (a:dynamic) returnType:kotlin.Unit flags: + RETURN type=kotlin.Nothing from='test6(dynamic, dynamic): dynamic' + DYN_OP operator=INVOKE type=dynamic + receiver: DYN_MEMBER memberName='invoke' type=dynamic + DYN_OP operator=INVOKE type=dynamic + receiver: GET_VAR 'value-parameter a: dynamic' type=dynamic origin=VARIABLE_AS_FUNCTION + 0: GET_VAR 'value-parameter b: dynamic' type=dynamic origin=null + 0: GET_VAR 'value-parameter b: dynamic' type=dynamic origin=null + FUN name:test7 visibility:public modality:FINAL <> (a:dynamic) returnType:kotlin.Unit flags: VALUE_PARAMETER name:a index:0 type:dynamic flags: BLOCK_BODY - RETURN type=kotlin.Nothing from='test3(dynamic): Unit' + RETURN type=kotlin.Nothing from='test7(dynamic): Unit' CALL 'invoke(): Unit' type=kotlin.Unit origin=null diff --git a/compiler/tests/org/jetbrains/kotlin/ir/IrJsTextTestCaseGenerated.java b/compiler/tests/org/jetbrains/kotlin/ir/IrJsTextTestCaseGenerated.java index afa9b5b13f3..b585633606d 100644 --- a/compiler/tests/org/jetbrains/kotlin/ir/IrJsTextTestCaseGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/ir/IrJsTextTestCaseGenerated.java @@ -41,6 +41,11 @@ public class IrJsTextTestCaseGenerated extends AbstractIrJsTextTestCase { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/ir/irJsText/dynamic"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); } + @TestMetadata("dynamicCall.kt") + public void testDynamicCall() throws Exception { + runTest("compiler/testData/ir/irJsText/dynamic/dynamicCall.kt"); + } + @TestMetadata("dynamicMemberAccess.kt") public void testDynamicMemberAccess() throws Exception { runTest("compiler/testData/ir/irJsText/dynamic/dynamicMemberAccess.kt");