diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/Ir.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/Ir.kt index 062abfd899d..be72c1604b7 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/Ir.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/Ir.kt @@ -169,6 +169,8 @@ abstract class Symbols(val context: T, private val abstract val coroutineSuspendedGetter: IrSimpleFunctionSymbol + fun getFunction(parameterCount: Int) = symbolTable.referenceClass(context.builtIns.getFunction(parameterCount)) + val functionReference = calc { symbolTable.referenceClass(context.getInternalClass("FunctionReference")) } fun getFunction(name: Name, receiverType: KotlinType, vararg argTypes: KotlinType) = 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 086e77a15a3..b39bd15b8cf 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 @@ -57,6 +57,7 @@ class JvmLower(val context: JvmBackendContext) { true ).runOnFilePostfix(irFile) CallableReferenceLowering(context).lower(irFile) + FunctionNVarargInvokeLowering(context).runOnFilePostfix(irFile) InnerClassesLowering(context).runOnFilePostfix(irFile) InnerClassConstructorCallsLowering(context).runOnFilePostfix(irFile) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrIllegalArgumentException.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrIllegalArgumentException.kt new file mode 100644 index 00000000000..1e4c9ffb536 --- /dev/null +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrIllegalArgumentException.kt @@ -0,0 +1,50 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.backend.jvm.intrinsics + +import org.jetbrains.kotlin.backend.jvm.JvmBackendContext +import org.jetbrains.kotlin.backend.jvm.codegen.BlockInfo +import org.jetbrains.kotlin.backend.jvm.codegen.ExpressionCodegen +import org.jetbrains.kotlin.codegen.StackValue +import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression +import org.jetbrains.kotlin.resolve.jvm.AsmTypes.JAVA_STRING_TYPE +import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature +import org.jetbrains.org.objectweb.asm.Type +import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter + +class IrIllegalArgumentException : IntrinsicMethod() { + val exceptionTypeDescriptor = Type.getInternalName(IllegalArgumentException::class.java) + + override fun toCallable( + expression: IrMemberAccessExpression, + signature: JvmMethodSignature, + context: JvmBackendContext + ): IrIntrinsicFunction { + return object : IrIntrinsicFunction(expression, signature, context, listOf(JAVA_STRING_TYPE)) { + override fun genInvokeInstruction(v: InstructionAdapter) { + v.invokespecial(exceptionTypeDescriptor, "", Type.getMethodDescriptor(Type.VOID_TYPE, JAVA_STRING_TYPE), false) + v.athrow() + } + + override fun invoke(v: InstructionAdapter, codegen: ExpressionCodegen, data: BlockInfo): StackValue { + v.anew(Type.getType(exceptionTypeDescriptor)) + v.dup() + return super.invoke(v, codegen, data) + } + } + } +} \ No newline at end of file diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrIntrinsicMethods.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrIntrinsicMethods.kt index 94617175994..a8da97b4695 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrIntrinsicMethods.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrIntrinsicMethods.kt @@ -52,6 +52,7 @@ class IrIntrinsicMethods(irBuiltIns: IrBuiltIns) { irMapping[irBuiltIns.enumValueOf] = IrEnumValueOf() irMapping[irBuiltIns.noWhenBranchMatchedException] = IrNoWhenBranchMatchedException() + irMapping[irBuiltIns.illegalArgumentException] = IrIllegalArgumentException() irMapping[irBuiltIns.throwNpe] = ThrowNPE() } 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 016b33fa330..bbf8db8ad15 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 @@ -37,20 +37,14 @@ import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.impl.* import org.jetbrains.kotlin.ir.expressions.* -import org.jetbrains.kotlin.ir.expressions.impl.IrClassReferenceImpl -import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl -import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl -import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl +import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl -import org.jetbrains.kotlin.ir.types.IrSimpleType -import org.jetbrains.kotlin.ir.types.IrType +import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection -import org.jetbrains.kotlin.ir.types.toIrType -import org.jetbrains.kotlin.ir.types.toKotlinType import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.load.java.JavaVisibilities @@ -99,8 +93,41 @@ class CallableReferenceLowering(val context: JvmBackendContext) : FileLoweringPa } } + val argumentsCount = expression.valueArgumentsCount + // Change calls to FunctionN with large N to varargs calls. + val newCall = if (argumentsCount > MAX_ARGCOUNT_WITHOUT_VARARG && + descriptor.containingDeclaration in listOf( + context.builtIns.getFunction(argumentsCount), + context.reflectionTypes.getKFunction(argumentsCount) + ) + ) { + val vararg = IrVarargImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, + context.ir.symbols.array.typeWith(), + context.ir.symbols.any.typeWith(), + (0 until argumentsCount).map { i -> expression.getValueArgument(i)!! } + ) + val invokeFunDescriptor = context.getClass(FqName("kotlin.jvm.functions.FunctionN")) + .getFunction("invoke", listOf(expression.type.toKotlinType())) + val invokeFunSymbol = context.ir.symbols.externalSymbolTable.referenceSimpleFunction(invokeFunDescriptor) + + IrCallImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, + expression.type, + invokeFunSymbol, invokeFunDescriptor, + 1, + expression.origin, + expression.superQualifier?.let { context.ir.symbols.externalSymbolTable.referenceClass(it) } + ).apply { + putTypeArgument(0, expression.type) + dispatchReceiver = expression.dispatchReceiver + extensionReceiver = expression.extensionReceiver + putValueArgument(0, vararg) + } + } else expression + //TODO: clean - return super.visitCall(expression) + return super.visitCall(newCall) } override fun visitFunctionReference(expression: IrFunctionReference): IrExpression { @@ -155,6 +182,8 @@ class CallableReferenceLowering(val context: JvmBackendContext) : FileLoweringPa private val functionReferenceOrLambda = if (isLambda) context.ir.symbols.lambdaClass else context.ir.symbols.functionReference + var useVararg: Boolean = false + fun build(): BuiltFunctionReference { val startOffset = irFunctionReference.startOffset val endOffset = irFunctionReference.endOffset @@ -165,9 +194,17 @@ class CallableReferenceLowering(val context: JvmBackendContext) : FileLoweringPa ) val numberOfParameters = unboundFunctionParameters.size - val functionClassDescriptor = context.getClass(FqName("kotlin.jvm.functions.Function$numberOfParameters")) + useVararg = (numberOfParameters > MAX_ARGCOUNT_WITHOUT_VARARG) + + val functionClassDescriptor = if (useVararg) + context.getClass(FqName("kotlin.jvm.functions.FunctionN")) + else + context.getClass(FqName("kotlin.jvm.functions.Function$numberOfParameters")) val functionParameterTypes = unboundFunctionParameters.map { it.type } - val functionClassTypeParameters = functionParameterTypes + returnType + val functionClassTypeParameters = if (useVararg) + listOf(returnType) + else + functionParameterTypes + returnType superTypes += functionClassDescriptor.defaultType.replace(functionClassTypeParameters) var suspendFunctionClassDescriptor: ClassDescriptor? = null @@ -197,7 +234,17 @@ class CallableReferenceLowering(val context: JvmBackendContext) : FileLoweringPa endOffset = endOffset, origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, descriptor = functionReferenceClassDescriptor - ) + ).apply { + createParameterDeclarations() + val typeTranslator = TypeTranslator(context.ir.symbols.externalSymbolTable, context.state.languageVersionSettings, + enterTableScope=true) + val constantValueGenerator = ConstantValueGenerator(context.state.module, context.ir.symbols.externalSymbolTable) + typeTranslator.constantValueGenerator = constantValueGenerator + constantValueGenerator.typeTranslator = typeTranslator + functionReferenceClassDescriptor.typeConstructor.supertypes.mapTo(this.superTypes) { + typeTranslator.translateType(it) + } + } val contributedDescriptors = mutableListOf() val constructorBuilder = createConstructorBuilder() @@ -205,8 +252,6 @@ class CallableReferenceLowering(val context: JvmBackendContext) : FileLoweringPa SimpleMemberScope(contributedDescriptors), setOf(constructorBuilder.symbol.descriptor), null ) - functionReferenceClass.createParameterDeclarations() - functionReferenceThis = functionReferenceClass.thisReceiver!!.symbol val invokeFunctionDescriptor = functionClassDescriptor.getFunction("invoke", functionClassTypeParameters) @@ -219,7 +264,6 @@ class CallableReferenceLowering(val context: JvmBackendContext) : FileLoweringPa invokeMethodBuilder.initialize() functionReferenceClass.declarations.add(invokeMethodBuilder.ir) - if (!isLambda) { val getSignatureBuilder = createGetSignatureMethodBuilder(functionReferenceOrLambda.owner.descriptor.getFunction("getSignature", emptyList())) @@ -245,7 +289,6 @@ class CallableReferenceLowering(val context: JvmBackendContext) : FileLoweringPa ).filterNotNull() ) - getSignatureBuilder.initialize() functionReferenceClass.declarations.add(getSignatureBuilder.ir) @@ -391,31 +434,74 @@ class CallableReferenceLowering(val context: JvmBackendContext) : FileLoweringPa createParameterDeclarations() body = irBuilder.irBlockBody(startOffset, endOffset) { + val arrayGetFun = context.irBuiltIns.arrayClass.owner + .declarations.find { + (it as? IrSimpleFunction)?.name?.toString() == "get" + }!! as IrSimpleFunction + + if (useVararg) { + val varargParam = valueParameters.single() + val arraySizeProperty = context.irBuiltIns.arrayClass.owner.declarations.find { + (it as? IrProperty)?.name?.toString() == "size" + } as IrProperty + +irIfThen( + irNotEquals( + irCall(arraySizeProperty.getter!!).apply { + dispatchReceiver = irGet(varargParam) + }, + irInt(unboundFunctionParameters.size) + ), + irCall(context.irBuiltIns.illegalArgumentExceptionFun).apply { + putValueArgument(0, irString("Expected ${unboundFunctionParameters.size} arguments")) + } + ) + } +irReturn( irCall(irFunctionReference.symbol).apply { var unboundIndex = 0 val unboundArgsSet = unboundFunctionParameters.toSet() - functionParameters.forEach { - val argument = - if (!unboundArgsSet.contains(it)) - // Bound parameter - read from field. - irGetField(irGet(functionReferenceThis.owner), argumentToPropertiesMap[it]!!.owner) - else { - if (ourSymbol.descriptor.isSuspend && unboundIndex == valueParameters.size) + + functionParameters.forEach { parameter -> + val argument = when { + !unboundArgsSet.contains(parameter) -> + // Bound parameter - read from field. + irGetField(irGet(functionReferenceThis.owner), argumentToPropertiesMap[parameter]!!.owner) + ourSymbol.descriptor.isSuspend && unboundIndex == valueParameters.size -> // For suspend functions the last argument is continuation and it is implicit. - TODO() + TODO() // irCall(getContinuationSymbol, // listOf(ourSymbol.descriptor.returnType!!)) - else - irGet(valueParameters[unboundIndex++]) + useVararg -> { + val type = parameter.type.toIrType()!! + val varargParam = valueParameters.single() + irBlock(resultType = type) { + val argValue = irTemporary( + irCall(arrayGetFun).apply { + dispatchReceiver = irGet(varargParam) + putValueArgument(0, irInt(unboundIndex++)) + } + ) + +irIfThen( + irNotIs(irGet(argValue), type), + irCall(context.irBuiltIns.illegalArgumentExceptionFun).apply { + putValueArgument(0, irString("Wrong type, expected $type")) + } + ) + +irGet(argValue) + } } - when (it) { + else -> { + irGet(valueParameters[unboundIndex++]) + } + } + when (parameter) { functionDescriptor.dispatchReceiverParameter -> dispatchReceiver = argument functionDescriptor.extensionReceiverParameter -> extensionReceiver = argument - else -> putValueArgument((it as ValueParameterDescriptor).index, argument) + else -> putValueArgument((parameter as ValueParameterDescriptor).index, argument) } } - assert(unboundIndex == valueParameters.size) { "Not all arguments of are used" } + + if (!useVararg) assert(unboundIndex == valueParameters.size) { "Not all arguments of are used" } } ) } @@ -703,6 +789,10 @@ class CallableReferenceLowering(val context: JvmBackendContext) : FileLoweringPa Name.identifier("$${name.substring(1, name.length - 1)}") } else this } + + companion object { + const val MAX_ARGCOUNT_WITHOUT_VARARG = 22 + } } // Copied from K/Native IrUtils2.kt 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 new file mode 100644 index 00000000000..d0208771687 --- /dev/null +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionNVarargInvokeLowering.kt @@ -0,0 +1,144 @@ +/* + * Copyright 2010-2018 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.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.lower.createIrBuilder +import org.jetbrains.kotlin.backend.common.lower.irIfThen +import org.jetbrains.kotlin.backend.jvm.JvmBackendContext +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.* +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.classifierOrFail +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 + +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) <= CallableReferenceLowering.MAX_ARGCOUNT_WITHOUT_VARARG } + ) { + // 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 = CallableReferenceLowering.DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, + symbol = IrSimpleFunctionSymbolImpl(descriptor), + name = Name.identifier("invoke"), + visibility = Visibilities.PUBLIC, + modality = Modality.OPEN, + isInline = false, + isExternal = false, + isTailrec = false, + isSuspend = false + ).apply { + descriptor.bind(this) + returnType = context.irBuiltIns.anyNType + dispatchReceiverParameter = irClass.thisReceiver + val varargParameterDescriptor = WrappedValueParameterDescriptor() + val varargParam = IrValueParameterImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, + origin = CallableReferenceLowering.DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, + symbol = IrValueParameterSymbolImpl(varargParameterDescriptor), + name = Name.identifier("args"), + index = 0, + type = context.irBuiltIns.arrayClass.typeWith(), + varargElementType = context.irBuiltIns.anyClass.typeWith(), + isCrossinline = false, + isNoinline = false + ).apply { + varargParameterDescriptor.bind(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, + target.returnType.classifierOrFail, + irCall(target).apply { + dispatchReceiver = irGet(irClass.thisReceiver!!) + 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.illegalArgumentExceptionFun).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.illegalArgumentExceptionFun.symbol).apply { + putValueArgument(0, irString(throwMessage)) + } + } + } + } +} diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrBuiltIns.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrBuiltIns.kt index bd4e2ff096d..ead0770c06f 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrBuiltIns.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrBuiltIns.kt @@ -124,6 +124,8 @@ class IrBuiltIns( val stringType = string.toIrType() val stringClass = builtIns.string.toIrSymbol() + val arrayClass = builtIns.array.toIrSymbol() + val throwableType = builtIns.throwable.defaultType.toIrType() val throwableClass = builtIns.throwable.toIrSymbol() @@ -152,6 +154,7 @@ class IrBuiltIns( val throwIseFun = defineOperator("THROW_ISE", nothing, listOf()) val booleanNotFun = defineOperator("NOT", bool, listOf(bool)) val noWhenBranchMatchedExceptionFun = defineOperator("noWhenBranchMatchedException", nothing, listOf()) + val illegalArgumentExceptionFun = defineOperator("illegalArgumentException", nothing, listOf(string)) val eqeqeq = eqeqeqFun.descriptor val eqeq = eqeqFun.descriptor @@ -159,6 +162,7 @@ class IrBuiltIns( val throwCce = throwCceFun.descriptor val booleanNot = booleanNotFun.descriptor val noWhenBranchMatchedException = noWhenBranchMatchedExceptionFun.descriptor + val illegalArgumentException = illegalArgumentExceptionFun.descriptor val eqeqeqSymbol = eqeqeqFun.symbol val eqeqSymbol = eqeqFun.symbol @@ -167,6 +171,7 @@ class IrBuiltIns( val throwIseSymbol = throwIseFun.symbol val booleanNotSymbol = booleanNotFun.symbol val noWhenBranchMatchedExceptionSymbol = noWhenBranchMatchedExceptionFun.symbol + val illegalArgumentExceptionSymbol = illegalArgumentExceptionFun.symbol val enumValueOfFun = createEnumValueOfFun() val enumValueOf = enumValueOfFun.descriptor diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt index d6bccf96a23..fb3a577cdbc 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt @@ -266,6 +266,26 @@ val IrClass.defaultType: IrType val IrSimpleFunction.isReal: Boolean get() = descriptor.kind.isReal +fun IrClass.isImmediateSubClassOf(ancestor: IrClass) = ancestor.symbol in superTypes.mapNotNull { + (it as? IrSimpleType)?.classifier +} + +fun IrClass.isSubclassOf(ancestor: IrClass): Boolean { + + val alreadyVisited = mutableSetOf() + + fun IrClass.hasAncestorInSuperTypes(): Boolean = when { + this === ancestor -> true + this in alreadyVisited -> false + else -> { + alreadyVisited.add(this) + superTypes.mapNotNull { ((it as? IrSimpleType)?.classifier as? IrClassSymbol)?.owner }.any { it.hasAncestorInSuperTypes() } + } + } + + return this.hasAncestorInSuperTypes() +} + // This implementation is from kotlin-native // TODO: use this implementation instead of any other fun IrSimpleFunction.resolveFakeOverride(): IrSimpleFunction? { @@ -339,6 +359,12 @@ fun IrDeclaration.isEffectivelyExternal(): Boolean { fun IrDeclaration.isDynamic() = this is IrFunction && dispatchReceiverParameter?.type is IrDynamicType +inline fun IrDeclarationContainer.findDeclaration(predicate: (T) -> Boolean): T? = + declarations.find { it is T && predicate(it) } as? T + +inline fun IrDeclarationContainer.filterDeclarations(predicate: (T) -> Boolean): List = + declarations.filter { it is T && predicate(it) } as List + fun IrValueParameter.copy(newDescriptor: ParameterDescriptor): IrValueParameter { assert(this.descriptor.type == newDescriptor.type) diff --git a/compiler/testData/codegen/box/functions/bigArity/callFromJava.kt b/compiler/testData/codegen/box/functions/bigArity/callFromJava.kt index 2717a3d5e86..6849e865c86 100644 --- a/compiler/testData/codegen/box/functions/bigArity/callFromJava.kt +++ b/compiler/testData/codegen/box/functions/bigArity/callFromJava.kt @@ -1,7 +1,6 @@ // !LANGUAGE: +FunctionTypesWithBigArity // WITH_RUNTIME // TARGET_BACKEND: JVM -// IGNORE_BACKEND: JVM_IR // FILE: J.java import kotlin.jvm.functions.FunctionN; diff --git a/compiler/testData/codegen/box/functions/bigArity/callFunViaVararg.kt b/compiler/testData/codegen/box/functions/bigArity/callFunViaVararg.kt new file mode 100644 index 00000000000..b78cf01ec82 --- /dev/null +++ b/compiler/testData/codegen/box/functions/bigArity/callFunViaVararg.kt @@ -0,0 +1,77 @@ +// !LANGUAGE: +FunctionTypesWithBigArity +// WITH_RUNTIME +// TARGET_BACKEND: JVM_IR +// FILE: J.java + +// import kotlin.jvm.functions.Arity; +import kotlin.jvm.functions.FunctionN; +import kotlin.Unit; +import java.util.Arrays; + +public class J { + // TODO: uncomment arity as soon as Arity is introduced + public static void test(/* @Arity(30) */ FunctionN f) { + Object o = new Integer(0); + for (int i = 0; i < 42; i++) { + Object[] args = new Object[i]; + Arrays.fill(args, o); + try { + if (f.invoke(args).intValue() != 300 + i) { + throw new AssertionError("Bad return value from function"); + } + } catch (IllegalArgumentException e) { + if (i == 3 || i == 13 || i == 30 || i == 33) { + throw new AssertionError(String.format("Call with %d arguments is expected to succeed", i), e); + } + // OK + + if (!e.getMessage().contains("30")) { + throw new AssertionError("Exception must specify the expected number of arguments: " + e.getMessage(), e); + } + + continue; + } catch (Throwable e) { + throw new AssertionError( + "Incorrect exception (IllegalArgumentException expected): " + e.getClass().getName() + ", i = " + i, e + ); + } + if (i != 3 && i != 13 && i != 30 && i != 33) { + throw new AssertionError ("IllegalArgumentException expected, but nothing was thrown, i = " + i); + } + } + } +} + +// FILE: K.kt + +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 { + override fun invoke(p00: Int, p01: Int, p02: Int): Int = 303 + + 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 + ): Int = 313 + + 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 + ): 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 { + J.test(Fun() as kotlin.jvm.functions.FunctionN) + return "OK" +} diff --git a/compiler/testData/codegen/box/functions/bigArity/callWithIncorrectNumberOfArguments.kt b/compiler/testData/codegen/box/functions/bigArity/callWithIncorrectNumberOfArguments.kt index 9eb845d8a6c..712d3deafde 100644 --- a/compiler/testData/codegen/box/functions/bigArity/callWithIncorrectNumberOfArguments.kt +++ b/compiler/testData/codegen/box/functions/bigArity/callWithIncorrectNumberOfArguments.kt @@ -1,7 +1,6 @@ // !LANGUAGE: +FunctionTypesWithBigArity // WITH_RUNTIME // TARGET_BACKEND: JVM -// IGNORE_BACKEND: JVM_IR // FILE: J.java // import kotlin.jvm.functions.Arity; diff --git a/compiler/testData/codegen/box/functions/bigArity/function255.kt b/compiler/testData/codegen/box/functions/bigArity/function255.kt index a36e4f88dd4..39c6066e8db 100644 --- a/compiler/testData/codegen/box/functions/bigArity/function255.kt +++ b/compiler/testData/codegen/box/functions/bigArity/function255.kt @@ -1,6 +1,5 @@ // !LANGUAGE: +FunctionTypesWithBigArity // IGNORE_BACKEND: JS_IR -// IGNORE_BACKEND: JVM_IR class A(val value: Int) { // for (i in 1..254) { print("p${"%03d".format(i)}: A, "); if (i % 10 == 0) println() }; println() diff --git a/compiler/testData/codegen/box/functions/bigArity/invokeCallableReference.kt b/compiler/testData/codegen/box/functions/bigArity/invokeCallableReference.kt index df604171b70..c9509a07ba5 100644 --- a/compiler/testData/codegen/box/functions/bigArity/invokeCallableReference.kt +++ b/compiler/testData/codegen/box/functions/bigArity/invokeCallableReference.kt @@ -1,5 +1,4 @@ // !LANGUAGE: +FunctionTypesWithBigArity -// IGNORE_BACKEND: JVM_IR class A diff --git a/compiler/testData/codegen/box/functions/bigArity/invokeLambda.kt b/compiler/testData/codegen/box/functions/bigArity/invokeLambda.kt index 2ea0367ad0b..afb24c958db 100644 --- a/compiler/testData/codegen/box/functions/bigArity/invokeLambda.kt +++ b/compiler/testData/codegen/box/functions/bigArity/invokeLambda.kt @@ -1,5 +1,4 @@ // !LANGUAGE: +FunctionTypesWithBigArity -// IGNORE_BACKEND: JVM_IR class A(val value: Int) diff --git a/compiler/testData/codegen/box/functions/bigArity/invokeMemberCallableReference.kt b/compiler/testData/codegen/box/functions/bigArity/invokeMemberCallableReference.kt new file mode 100644 index 00000000000..743865b5b4d --- /dev/null +++ b/compiler/testData/codegen/box/functions/bigArity/invokeMemberCallableReference.kt @@ -0,0 +1,17 @@ +// !LANGUAGE: +FunctionTypesWithBigArity + +class A { + fun foo( + p00: A, p01: A, p02: A, p03: A, p04: A, p05: A, p06: A, p07: A, p08: A, p09: A, + p10: A, p11: A, p12: A, p13: A, p14: A, p15: A, p16: A, p17: A, p18: A, p19: A, + p20: A, p21: A, p22: A, p23: A, p24: A, p25: A, p26: A, p27: A, p28: A, p29: A + ): String { + return "OK" + } +} + +fun box(): String { + val a = A() + val ref = a::foo + return ref(a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a) +} diff --git a/compiler/testData/codegen/box/functions/bigArity/javaLambda.kt b/compiler/testData/codegen/box/functions/bigArity/javaLambda.kt index a96cdae2644..255bac4fb20 100644 --- a/compiler/testData/codegen/box/functions/bigArity/javaLambda.kt +++ b/compiler/testData/codegen/box/functions/bigArity/javaLambda.kt @@ -1,7 +1,6 @@ // !LANGUAGE: +FunctionTypesWithBigArity // WITH_RUNTIME // TARGET_BACKEND: JVM -// IGNORE_BACKEND: JVM_IR // FILE: J.java // import kotlin.jvm.functions.Arity; diff --git a/compiler/testData/codegen/box/functions/bigArity/noBigFunctionTypes.kt b/compiler/testData/codegen/box/functions/bigArity/noBigFunctionTypes.kt index c839bfa4d40..1dd13185e96 100644 --- a/compiler/testData/codegen/box/functions/bigArity/noBigFunctionTypes.kt +++ b/compiler/testData/codegen/box/functions/bigArity/noBigFunctionTypes.kt @@ -1,9 +1,8 @@ // !LANGUAGE: -FunctionTypesWithBigArity -// IGNORE_BACKEND: JVM_IR // This test does not make sense for JVM because a diagnostic is reported when function types with big arity are not available // (see diagnostics/tests/sourceCompatibility/noBigFunctionTypes.kt) -// IGNORE_BACKEND: JVM +// IGNORE_BACKEND: JVM, JVM_IR class A diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index cfdedbd1ca1..70d8e29253d 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -10729,6 +10729,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/functions/bigArity/invokeLambda.kt"); } + @TestMetadata("invokeMemberCallableReference.kt") + public void testInvokeMemberCallableReference() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/invokeMemberCallableReference.kt"); + } + @TestMetadata("javaLambda.kt") public void testJavaLambda() throws Exception { runTest("compiler/testData/codegen/box/functions/bigArity/javaLambda.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 6acf53f10d9..4a74cde35b3 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -10734,6 +10734,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/functions/bigArity/invokeLambda.kt"); } + @TestMetadata("invokeMemberCallableReference.kt") + public void testInvokeMemberCallableReference() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/invokeMemberCallableReference.kt"); + } + @TestMetadata("javaLambda.kt") public void testJavaLambda() throws Exception { runTest("compiler/testData/codegen/box/functions/bigArity/javaLambda.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 04d247b5c87..e1099a24583 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -10704,6 +10704,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes 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"); @@ -10729,6 +10734,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/functions/bigArity/invokeLambda.kt"); } + @TestMetadata("invokeMemberCallableReference.kt") + public void testInvokeMemberCallableReference() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/invokeMemberCallableReference.kt"); + } + @TestMetadata("javaLambda.kt") public void testJavaLambda() throws Exception { runTest("compiler/testData/codegen/box/functions/bigArity/javaLambda.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java index e6cfb73d411..6f6d6f3da7e 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java @@ -9279,6 +9279,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/functions/bigArity/invokeLambda.kt"); } + @TestMetadata("invokeMemberCallableReference.kt") + public void testInvokeMemberCallableReference() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/invokeMemberCallableReference.kt"); + } + @TestMetadata("noBigFunctionTypes.kt") public void testNoBigFunctionTypes() throws Exception { runTest("compiler/testData/codegen/box/functions/bigArity/noBigFunctionTypes.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 70bea159e63..7d23d3f448e 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -10344,6 +10344,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/functions/bigArity/invokeLambda.kt"); } + @TestMetadata("invokeMemberCallableReference.kt") + public void testInvokeMemberCallableReference() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/invokeMemberCallableReference.kt"); + } + @TestMetadata("noBigFunctionTypes.kt") public void testNoBigFunctionTypes() throws Exception { runTest("compiler/testData/codegen/box/functions/bigArity/noBigFunctionTypes.kt");