diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt index 8ccd1a56262..9c6e75d8e4b 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt @@ -141,7 +141,6 @@ private val jvmFilePhases = singletonReferencesPhase then callableReferencePhase then - functionNVarargInvokePhase then localDeclarationsPhase then singleAbstractMethodPhase then @@ -172,6 +171,7 @@ private val jvmFilePhases = objectClassPhase then makeInitializersPhase(JvmLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER, true) then collectionStubMethodLowering then + functionNVarargBridgePhase then bridgePhase then jvmStaticAnnotationPhase then staticDefaultFunctionPhase then diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt index d53b9833fb6..b5661f7672c 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt @@ -11,17 +11,13 @@ import org.jetbrains.kotlin.backend.common.ir.copyTo import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.irBlock -import org.jetbrains.kotlin.backend.common.lower.irIfThen import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.codegen.isInlineFunctionCall import org.jetbrains.kotlin.backend.jvm.codegen.isInlineIrExpression import org.jetbrains.kotlin.backend.jvm.ir.isInlineParameter -import org.jetbrains.kotlin.backend.jvm.localDeclarationsPhase -import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor import org.jetbrains.kotlin.codegen.PropertyReferenceCodegen -import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET @@ -32,7 +28,6 @@ import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter import org.jetbrains.kotlin.ir.builders.declarations.buildClass import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* -import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrClassReferenceImpl import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl @@ -66,52 +61,26 @@ internal class CallableReferenceLowering(private val context: JvmBackendContext) override fun lower(irFile: IrFile) = irFile.transformChildrenVoid(this) - // Change calls to big arity invoke functions to vararg calls. + // Mark function references appearing as inlined arguments to inline functions. override fun visitFunctionAccess(expression: IrFunctionAccessExpression): IrExpression { - markInlineFunctionReferences(expression) - expression.transformChildrenVoid(this) - - if (expression.valueArgumentsCount < FunctionInvokeDescriptor.BIG_ARITY || - !expression.symbol.owner.parentAsClass.defaultType.isFunctionOrKFunction()) - return expression - - return IrCallImpl( - expression.startOffset, expression.endOffset, - expression.type, functionNInvokeFun.symbol, functionNInvokeFun.descriptor, - 1, expression.origin - ).apply { - putTypeArgument(0, expression.type) - dispatchReceiver = expression.dispatchReceiver - extensionReceiver = expression.extensionReceiver - val vararg = IrVarargImpl( - UNDEFINED_OFFSET, UNDEFINED_OFFSET, - context.ir.symbols.array.typeWith(context.irBuiltIns.anyNType), - context.irBuiltIns.anyNType, - (0 until expression.valueArgumentsCount).map { expression.getValueArgument(it)!! } - ) - putValueArgument(0, vararg) - } - } - - private fun markInlineFunctionReferences(expression: IrFunctionAccessExpression) { val function = expression.symbol.owner - if (!function.isInlineFunctionCall(context)) - return + if (function.isInlineFunctionCall(context)) { + for (parameter in function.valueParameters) { + if (!parameter.isInlineParameter()) + continue - for (parameter in function.valueParameters) { - if (!parameter.isInlineParameter()) - continue + val valueArgument = expression.getValueArgument(parameter.index) ?: continue + if (!isInlineIrExpression(valueArgument)) + continue - val valueArgument = expression.getValueArgument(parameter.index) ?: continue - if (!isInlineIrExpression(valueArgument)) - continue - - if (valueArgument is IrFunctionReference) { - ignoredFunctionReferences.add(valueArgument) - } else if (valueArgument is IrBlock) { - ignoredFunctionReferences.addIfNotNull(valueArgument.statements.filterIsInstance().singleOrNull()) + if (valueArgument is IrFunctionReference) { + ignoredFunctionReferences.add(valueArgument) + } else if (valueArgument is IrBlock) { + ignoredFunctionReferences.addIfNotNull(valueArgument.statements.filterIsInstance().singleOrNull()) + } } } + return super.visitFunctionAccess(expression) } // Ignore function references handled in SAM conversion @@ -161,10 +130,6 @@ internal class CallableReferenceLowering(private val context: JvmBackendContext) // The type of the reference is KFunction private val parameterTypes = (irFunctionReference.type as IrSimpleType).arguments.map { (it as IrTypeProjection).type } private val argumentTypes = parameterTypes.dropLast(1) - private val returnType = parameterTypes.last() - - private val useVararg - get() = argumentTypes.size >= FunctionInvokeDescriptor.BIG_ARITY private val typeParameters = if (callee is IrConstructor) callee.parentAsClass.typeParameters + callee.typeParameters @@ -190,7 +155,10 @@ internal class CallableReferenceLowering(private val context: JvmBackendContext) fun build(): IrExpression { val constructor = createConstructor() val invokeMethod = createInvokeMethod() - createBridge(invokeMethod) + + val functionClass = context.ir.symbols.getJvmFunctionClass(argumentTypes.size) + functionReferenceClass.superTypes += functionClass.typeWith(parameterTypes) + invokeMethod.overriddenSymbols += functionClass.functions.single { it.owner.name.asString() == "invoke" } if (!isLambda) { createGetSignatureMethod(functionGetSignature) @@ -339,80 +307,6 @@ internal class CallableReferenceLowering(private val context: JvmBackendContext) } } - // Build a bridge to the monomorphic invoke method. This is more elaborate than the usual BridgeLowering, - // since we have special handling for functions with large arity (> 22 arguments). Large arity functions - // are translated to functions with a single vararg argument, which checks the number of arguments and types - // dynamically. - private fun createBridge(invoke: IrSimpleFunction) { - // Add supertypes - val actualFunctionClass = if (useVararg) - context.ir.symbols.functionN - else - context.ir.symbols.getJvmFunctionClass(argumentTypes.size) - - functionReferenceClass.superTypes += actualFunctionClass.typeWith(if (useVararg) listOf(returnType) else parameterTypes) - val superFunction = actualFunctionClass.owner.functions.find { it.name.asString() == "invoke" }!! - - // Only add a bridge method when necessary - if (context.state.typeMapper.mapAsmMethod(superFunction.descriptor) == - context.state.typeMapper.mapAsmMethod(invoke.descriptor) - ) { - invoke.overriddenSymbols += superFunction.symbol - return - } - - // Add the invoke bridge - functionReferenceClass.addFunction { - name = superFunction.name - returnType = context.irBuiltIns.anyNType - modality = Modality.FINAL - visibility = Visibilities.PUBLIC - origin = IrDeclarationOrigin.BRIDGE - }.apply { - overriddenSymbols += superFunction.symbol - dispatchReceiverParameter = parentAsClass.thisReceiver!!.copyTo(this) - if (useVararg) - valueParameters += superFunction.valueParameters[0].copyTo(this) - else - superFunction.valueParameters.forEach { valueParameters += it.copyTo(this, type = context.irBuiltIns.anyNType) } - - body = context.createIrBuilder(symbol).irBlockBody(startOffset, endOffset) { - // Check the number of arguments for large arity functions - if (useVararg) { - +irIfThen( - irNotEquals( - irCall(arraySizeProperty.getter!!).apply { - dispatchReceiver = irGet(valueParameters.single()) - }, - irInt(argumentTypes.size) - ), - irCall(context.irBuiltIns.illegalArgumentExceptionSymbol).apply { - putValueArgument(0, irString("Expected ${argumentTypes.size} arguments")) - } - ) - } - - +irReturn(irCall(invoke).apply { - dispatchReceiver = irGet(dispatchReceiverParameter!!) - - for (parameter in invoke.valueParameters) { - val index = parameter.index - - val argument = if (useVararg) { - val argArray = irGet(valueParameters.single()) - val argIndex = irInt(index) - irCallOp(arrayGetFun.symbol, context.irBuiltIns.anyNType, argArray, argIndex) - } else { - irGet(valueParameters[index]) - } - - putValueArgument(index, irImplicitCast(argument, argumentTypes[index])) - } - }) - } - } - } - private fun buildOverride(superFunction: IrSimpleFunction, newReturnType: IrType = superFunction.returnType): IrSimpleFunction = functionReferenceClass.addFunction { setSourceRange(irFunctionReference) @@ -497,14 +391,6 @@ internal class CallableReferenceLowering(private val context: JvmBackendContext) private fun IrClassSymbol.functionByName(name: String) = owner.functions.single { it.name.asString() == name } - private val arraySizeProperty by lazy { - context.irBuiltIns.arrayClass.owner.properties.single { it.name.toString() == "size" } - } - - private val arrayGetFun by lazy { - context.irBuiltIns.arrayClass.functionByName("get") - } - private val functionReferenceReceiverField = context.ir.symbols.functionReference.owner.declarations.single { it is IrField && it.name.toString() == "receiver" } as IrField diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionNVarargBridgeLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionNVarargBridgeLowering.kt new file mode 100644 index 00000000000..00b6edfb6c4 --- /dev/null +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionNVarargBridgeLowering.kt @@ -0,0 +1,180 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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.backend.jvm.lower + +import org.jetbrains.kotlin.backend.common.FileLoweringPass +import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext +import org.jetbrains.kotlin.backend.common.ir.copyTo +import org.jetbrains.kotlin.backend.common.lower.createIrBuilder +import org.jetbrains.kotlin.backend.common.lower.irIfThen +import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase +import org.jetbrains.kotlin.backend.jvm.JvmBackendContext +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor +import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.descriptors.Visibilities +import org.jetbrains.kotlin.ir.IrStatement +import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET +import org.jetbrains.kotlin.ir.builders.* +import org.jetbrains.kotlin.ir.builders.declarations.addFunction +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression +import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl +import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl +import org.jetbrains.kotlin.ir.types.* +import org.jetbrains.kotlin.ir.util.* +import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.utils.addToStdlib.safeAs + +internal val functionNVarargBridgePhase = makeIrFilePhase( + ::FunctionNVarargBridgeLowering, + name = "FunctionBridgePhase", + description = "Add bridges for invoke functions with a large number of arguments" +) + +// There are concrete function classes for functions with up to 22 arguments. Above that, we +// inherit from the generic FunctionN class which has a vararg invoke method. This phase +// adds a bridge method for such large arity functions, which checks the number of arguments +// dynamically. +private class FunctionNVarargBridgeLowering(val context: JvmBackendContext) : + FileLoweringPass, IrElementTransformerVoidWithContext() { + override fun lower(irFile: IrFile) = irFile.transformChildrenVoid(this) + + // Change calls to big arity invoke functions to vararg calls. + override fun visitFunctionAccess(expression: IrFunctionAccessExpression): IrExpression { + if (expression.valueArgumentsCount < FunctionInvokeDescriptor.BIG_ARITY || + !expression.symbol.owner.parentAsClass.defaultType.isFunctionOrKFunction() || + expression.symbol.owner.name.asString() != "invoke") + return super.visitFunctionAccess(expression) + + return IrCallImpl( + expression.startOffset, expression.endOffset, + expression.type, functionNInvokeFun, functionNInvokeFun.descriptor, + 1, expression.origin + ).apply { + putTypeArgument(0, expression.type) + dispatchReceiver = expression.dispatchReceiver + putValueArgument(0, IrVarargImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, + context.ir.symbols.array.typeWith(context.irBuiltIns.anyNType), + context.irBuiltIns.anyNType, + (0 until expression.valueArgumentsCount).map { expression.getValueArgument(it)!! } + )) + } + } + + override fun visitClassNew(declaration: IrClass): IrStatement { + val bigArityFunctionSuperTypes = declaration.superTypes.filterIsInstance().filter { + it.isFunctionType && it.arguments.size > FunctionInvokeDescriptor.BIG_ARITY + } + + if (bigArityFunctionSuperTypes.isEmpty()) + return super.visitClassNew(declaration) + declaration.transformChildrenVoid(this) + + // Note that we allow classes with multiple function supertypes, so long as only one + // of them has more than 22 arguments. + // TODO: Add a proper diagnostic message in the frontend + assert(bigArityFunctionSuperTypes.size == 1) { + "Class has multiple big-arity function super types: ${bigArityFunctionSuperTypes.joinToString { it.render() }}" + } + + // Fix super class + val superType = bigArityFunctionSuperTypes.single() + declaration.superTypes.remove(superType) + declaration.superTypes += context.ir.symbols.functionN.typeWith( + (superType.arguments.last() as IrTypeProjection).type + ) + + // Add vararg invoke bridge + val invokeFunction = declaration.functions.single { + it.name.asString() == "invoke" && it.valueParameters.size == superType.arguments.size - 1 + } + invokeFunction.overriddenSymbols.clear() + declaration.addBridge(invokeFunction, functionNInvokeFun.owner) + + return declaration + } + + private fun IrClass.addBridge(invoke: IrSimpleFunction, superFunction: IrSimpleFunction) = + addFunction { + name = superFunction.name + returnType = context.irBuiltIns.anyNType + modality = Modality.FINAL + visibility = Visibilities.PUBLIC + origin = IrDeclarationOrigin.BRIDGE + }.apply { + overriddenSymbols += superFunction.symbol + dispatchReceiverParameter = thisReceiver!!.copyTo(this) + valueParameters += superFunction.valueParameters.single().copyTo(this) + + body = context.createIrBuilder(symbol).irBlockBody(startOffset, endOffset) { + // Check the number of arguments + val argumentCount = invoke.valueParameters.size + +irIfThen( + irNotEquals( + irCall(arraySizePropertyGetter).apply { + dispatchReceiver = irGet(valueParameters.single()) + }, + irInt(argumentCount) + ), + irCall(context.irBuiltIns.illegalArgumentExceptionSymbol).apply { + putValueArgument(0, irString("Expected ${argumentCount} arguments")) + } + ) + + +irReturn(irCall(invoke).apply { + dispatchReceiver = irGet(dispatchReceiverParameter!!) + + for (parameter in invoke.valueParameters) { + val index = parameter.index + val argArray = irGet(valueParameters.single()) + val argument = irCallOp(arrayGetFun, context.irBuiltIns.anyNType, argArray, irInt(index)) + putValueArgument(index, irImplicitCast(argument, invoke.valueParameters[index].type)) + } + }) + } + } + + // Check if a type is an instance of kotlin.Function*, kotlin.jvm.functions.Function* + // or kotlin.reflect.KFunction*. Note that `IrType.isFunctionOrKFunction()` in IrTypeUtils + // does not check for the jvm specific kotlin.jvm.functions package and can't be used here. + private val IrType.isFunctionType: Boolean + get() { + val clazz = classOrNull?.owner ?: return false + val name = clazz.name.asString() + val fqName = clazz.parent.safeAs()?.fqName ?: return false + return when { + name.startsWith("Function") -> + fqName == KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME || fqName == FUNCTIONS_PACKAGE_FQ_NAME + name.startsWith("KFunction") -> + fqName == REFLECT_PACKAGE_FQ_NAME + else -> false + } + } + + private val functionNInvokeFun = + context.ir.symbols.functionN.functions.single { it.owner.name.toString() == "invoke" } + + private val arraySizePropertyGetter by lazy { + context.irBuiltIns.arrayClass.owner.properties.single { it.name.toString() == "size" }.getter!! + } + + private val arrayGetFun by lazy { + context.irBuiltIns.arrayClass.functions.single { it.owner.name.toString() == "get" } + } + + private val FUNCTIONS_PACKAGE_FQ_NAME = + KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME + .child(Name.identifier("jvm")) + .child(Name.identifier("functions")) + + private val REFLECT_PACKAGE_FQ_NAME = + KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME + .child(Name.identifier("reflect")) +} diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionNVarargInvokeLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionNVarargInvokeLowering.kt deleted file mode 100644 index 26291e5fc10..00000000000 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionNVarargInvokeLowering.kt +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. - * 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.backend.jvm.lower - -import org.jetbrains.kotlin.backend.common.ClassLoweringPass -import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor -import org.jetbrains.kotlin.backend.common.descriptors.WrappedValueParameterDescriptor -import org.jetbrains.kotlin.backend.common.ir.copyTo -import org.jetbrains.kotlin.backend.common.lower.createIrBuilder -import org.jetbrains.kotlin.backend.common.lower.irIfThen -import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase -import org.jetbrains.kotlin.backend.jvm.JvmBackendContext -import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin -import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor -import org.jetbrains.kotlin.descriptors.Modality -import org.jetbrains.kotlin.descriptors.Visibilities -import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET -import org.jetbrains.kotlin.ir.builders.* -import org.jetbrains.kotlin.ir.declarations.IrClass -import org.jetbrains.kotlin.ir.declarations.IrFunction -import org.jetbrains.kotlin.ir.declarations.IrProperty -import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction -import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl -import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl -import org.jetbrains.kotlin.ir.expressions.IrTypeOperator -import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl -import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl -import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl -import org.jetbrains.kotlin.ir.types.typeWith -import org.jetbrains.kotlin.ir.util.filterDeclarations -import org.jetbrains.kotlin.ir.util.findDeclaration -import org.jetbrains.kotlin.ir.util.isSubclassOf -import org.jetbrains.kotlin.name.Name - -internal val functionNVarargInvokePhase = makeIrFilePhase( - ::FunctionNVarargInvokeLowering, - name = "FunctionNVarargInvoke", - description = "Handle invoke functions with large number of arguments" -) - -private class FunctionNVarargInvokeLowering(var context: JvmBackendContext) : ClassLoweringPass { - - override fun lower(irClass: IrClass) { - val invokeFunctions = irClass.filterDeclarations { it.name.toString() == "invoke" } - if (invokeFunctions.isEmpty() || - invokeFunctions.any { it.valueParameters.size > 0 && it.valueParameters.last().varargElementType != null } || - invokeFunctions.all { it.valueParameters.size + (if (it.extensionReceiverParameter != null) 1 else 0) < FunctionInvokeDescriptor.Factory.BIG_ARITY } - ) { - // No need to add a new vararg invoke method - return - } - val functionInvokes = invokeFunctions.filter { irClass.isSubclassOf(context.ir.symbols.getFunction(it.valueParameters.size).owner) } - if (functionInvokes.isEmpty()) return - - irClass.declarations.add(generateVarargInvoke(irClass, functionInvokes)) - } - - private fun generateVarargInvoke(irClass: IrClass, invokesToDelegateTo: List): IrFunction { - val backendContext = context - val descriptor = WrappedSimpleFunctionDescriptor() - return IrFunctionImpl( - UNDEFINED_OFFSET, UNDEFINED_OFFSET, - origin = JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL, - symbol = IrSimpleFunctionSymbolImpl(descriptor), - name = Name.identifier("invoke"), - visibility = Visibilities.PUBLIC, - modality = Modality.OPEN, - returnType = context.irBuiltIns.anyNType, - isInline = false, - isExternal = false, - isTailrec = false, - isSuspend = false - ).apply { - descriptor.bind(this) - parent = irClass - dispatchReceiverParameter = irClass.thisReceiver?.copyTo(this) - val varargParameterDescriptor = WrappedValueParameterDescriptor() - val varargParam = IrValueParameterImpl( - UNDEFINED_OFFSET, UNDEFINED_OFFSET, - origin = JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL, - symbol = IrValueParameterSymbolImpl(varargParameterDescriptor), - name = Name.identifier("args"), - index = 0, - type = context.irBuiltIns.arrayClass.typeWith(context.irBuiltIns.anyNType), - varargElementType = context.irBuiltIns.anyNType, - isCrossinline = false, - isNoinline = false - ).apply { - varargParameterDescriptor.bind(this) - } - varargParam.parent = this - valueParameters.add(varargParam) - val irBuilder = context.createIrBuilder(symbol, UNDEFINED_OFFSET, UNDEFINED_OFFSET) - body = irBuilder.irBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) { - val arrayGetFun = - backendContext.irBuiltIns.arrayClass.owner.findDeclaration { it.name.toString() == "get" }!! - val arraySizeProperty = context.irBuiltIns.arrayClass.owner.findDeclaration { it.name.toString() == "size" }!! - val numberOfArguments = irTemporary(irCall(arraySizeProperty.getter!!).apply { - dispatchReceiver = irGet(varargParam) - }) - - for (target in invokesToDelegateTo) { - +irIfThen( - backendContext.irBuiltIns.unitType, - irEquals(irGet(numberOfArguments), irInt(target.valueParameters.size)), - irReturn( - IrTypeOperatorCallImpl( - UNDEFINED_OFFSET, UNDEFINED_OFFSET, - backendContext.irBuiltIns.anyNType, - IrTypeOperator.CAST, - target.returnType, - irCall(target).apply { - dispatchReceiver = irGet(dispatchReceiverParameter!!) - target.valueParameters.forEachIndexed { i, irValueParameter -> - val type = irValueParameter.type - putValueArgument( - i, - irBlock(resultType = type) { - val argValue = irTemporary( - irCallOp( - arrayGetFun.symbol, - context.irBuiltIns.anyNType, - irGet(varargParam), - irInt(i) - ) - ) - +irIfThen( - irNotIs(irGet(argValue), type), - irCall(context.irBuiltIns.illegalArgumentExceptionSymbol).apply { - putValueArgument(0, irString("Wrong type, expected $type")) - } - ) - +irGet(argValue) - } - ) - } - } - ) - ) - ) - } - - val throwMessage = invokesToDelegateTo.map { it.valueParameters.size.toString() }.joinToString( - prefix = "Expected ", - separator = " or ", - postfix = " arguments to invoke call" - ) - +irCall(context.irBuiltIns.illegalArgumentExceptionSymbol).apply { - putValueArgument(0, irString(throwMessage)) - } - } - } - } -} diff --git a/compiler/testData/codegen/box/coroutines/localCallableRef.kt b/compiler/testData/codegen/box/coroutines/localCallableRef.kt index 209e6eb2d20..dabab399a53 100644 --- a/compiler/testData/codegen/box/coroutines/localCallableRef.kt +++ b/compiler/testData/codegen/box/coroutines/localCallableRef.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // WITH_RUNTIME // WITH_COROUTINES diff --git a/compiler/testData/codegen/box/functions/bigArity/callFunViaVararg.kt b/compiler/testData/codegen/box/functions/bigArity/callFunViaVararg.kt index 6f562307ed3..e9b43bde121 100644 --- a/compiler/testData/codegen/box/functions/bigArity/callFunViaVararg.kt +++ b/compiler/testData/codegen/box/functions/bigArity/callFunViaVararg.kt @@ -1,6 +1,6 @@ // !LANGUAGE: +FunctionTypesWithBigArity // WITH_RUNTIME -// TARGET_BACKEND: JVM_IR +// TARGET_BACKEND: JVM // FILE: J.java // import kotlin.jvm.functions.Arity; @@ -20,7 +20,7 @@ public class J { throw new AssertionError("Bad return value from function"); } } catch (IllegalArgumentException e) { - if (i == 3 || i == 13 || i == 30 || i == 33) { + if (i == 30) { throw new AssertionError(String.format("Call with %d arguments is expected to succeed", i), e); } // OK @@ -35,7 +35,7 @@ public class J { "Incorrect exception (IllegalArgumentException expected): " + e.getClass().getName() + ", i = " + i, e ); } - if (i != 3 && i != 13 && i != 30 && i != 33) { + if (i != 30) { throw new AssertionError ("IllegalArgumentException expected, but nothing was thrown, i = " + i); } } @@ -47,9 +47,7 @@ public class J { class Fun : (Int, Int, Int) -> Int, (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) -> Int, (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, - Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) -> Int, - (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, - Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) -> Int { + Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) -> Int { override fun invoke(p00: Int, p01: Int, p02: Int): Int = 303 override fun invoke( @@ -62,13 +60,6 @@ class Fun : (Int, Int, Int) -> Int, p10: Int, p11: Int, p12: Int, p13: Int, p14: Int, p15: Int, p16: Int, p17: Int, p18: Int, p19: Int, p20: Int, p21: Int, p22: Int, p23: Int, p24: Int, p25: Int, p26: Int, p27: Int, p28: Int, p29: Int ): Int = 330 - - override fun invoke( - p00: Int, p01: Int, p02: Int, p03: Int, p04: Int, p05: Int, p06: Int, p07: Int, p08: Int, p09: Int, - p10: Int, p11: Int, p12: Int, p13: Int, p14: Int, p15: Int, p16: Int, p17: Int, p18: Int, p19: Int, - p20: Int, p21: Int, p22: Int, p23: Int, p24: Int, p25: Int, p26: Int, p27: Int, p28: Int, p29: Int, - p30: Int, p31: Int, p32: Int - ): Int = 333 } fun box(): String { diff --git a/compiler/testData/codegen/bytecodeText/directInvoke/inplaceClosure.kt b/compiler/testData/codegen/bytecodeText/directInvoke/inplaceClosure.kt index 86033d05e9d..3cbc1c163fc 100644 --- a/compiler/testData/codegen/bytecodeText/directInvoke/inplaceClosure.kt +++ b/compiler/testData/codegen/bytecodeText/directInvoke/inplaceClosure.kt @@ -1,3 +1,4 @@ +// IGNORE_BACKEND: JVM_IR fun test() { 1.(fun Int.() = 2)() } diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 8223243fefb..8c6df6b83a6 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -11345,6 +11345,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/functions/bigArity/callFromJava.kt"); } + @TestMetadata("callFunViaVararg.kt") + public void testCallFunViaVararg() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/callFunViaVararg.kt"); + } + @TestMetadata("callWithIncorrectNumberOfArguments.kt") public void testCallWithIncorrectNumberOfArguments() throws Exception { runTest("compiler/testData/codegen/box/functions/bigArity/callWithIncorrectNumberOfArguments.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 74376752ad6..abd0748aec1 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -11350,6 +11350,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/functions/bigArity/callFromJava.kt"); } + @TestMetadata("callFunViaVararg.kt") + public void testCallFunViaVararg() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/callFunViaVararg.kt"); + } + @TestMetadata("callWithIncorrectNumberOfArguments.kt") public void testCallWithIncorrectNumberOfArguments() throws Exception { runTest("compiler/testData/codegen/box/functions/bigArity/callWithIncorrectNumberOfArguments.kt");