diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java index 4f29a54c326..8a1ed1c8fda 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java @@ -719,14 +719,24 @@ public class AsmUtil { KotlinType type = parameter.getType(); if (isNullableType(type) || InlineClassesUtilsKt.isNullableUnderlyingType(type)) return; - int index = frameMap.getIndex(parameter); Type asmType = typeMapper.mapType(type); if (asmType.getSort() == Type.OBJECT || asmType.getSort() == Type.ARRAY) { - v.load(index, asmType); + StackValue value; + if (JvmCodegenUtil.isDeclarationOfBigArityFunctionInvoke(parameter.getContainingDeclaration())) { + int index = getIndexOfParameterInVarargInvokeArray(parameter); + value = StackValue.arrayElement( + OBJECT_TYPE, null, StackValue.local(1, getArrayType(OBJECT_TYPE)), StackValue.constant(index) + ); + } + else { + int index = frameMap.getIndex(parameter); + value = StackValue.local(index, asmType); + } + value.put(asmType, v); v.visitLdcInsn(name); - String checkMethod = "checkParameterIsNotNull"; - v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, checkMethod, - "(Ljava/lang/Object;Ljava/lang/String;)V", false); + v.invokestatic( + IntrinsicMethods.INTRINSICS_CLASS_NAME, "checkParameterIsNotNull", "(Ljava/lang/Object;Ljava/lang/String;)V", false + ); } } @@ -756,6 +766,28 @@ public class AsmUtil { }; } + private static int getIndexOfParameterInVarargInvokeArray(@NotNull ParameterDescriptor parameter) { + if (parameter instanceof ReceiverParameterDescriptor) return 0; + + DeclarationDescriptor container = parameter.getContainingDeclaration(); + assert parameter instanceof ValueParameterDescriptor : "Non-extension-receiver parameter must be a value parameter: " + parameter; + int extensionShift = ((CallableDescriptor) container).getExtensionReceiverParameter() == null ? 0 : 1; + + return extensionShift + ((ValueParameterDescriptor) parameter).getIndex(); + } + + // At the beginning of the vararg invoke of a function with big arity N, generates an assert that the vararg parameter has N elements + public static void generateVarargInvokeArityAssert(InstructionAdapter v, int functionArity) { + Label start = new Label(); + v.load(1, getArrayType(OBJECT_TYPE)); + v.arraylength(); + v.iconst(functionArity); + v.ificmpeq(start); + v.visitLdcInsn("Vararg argument must contain " + functionArity + " elements."); + v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "throwIllegalArgument", "(Ljava/lang/String;)V", false); + v.visitLabel(start); + } + public static void pushDefaultValueOnStack(@NotNull Type type, @NotNull InstructionAdapter v) { if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) { v.aconst(null); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/CallBasedArgumentGenerator.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/CallBasedArgumentGenerator.java index 539d3440dda..1d53853c8bf 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/CallBasedArgumentGenerator.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/CallBasedArgumentGenerator.java @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.codegen; import org.jetbrains.annotations.NotNull; +import org.jetbrains.kotlin.descriptors.CallableDescriptor; import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor; import org.jetbrains.kotlin.psi.KtExpression; import org.jetbrains.kotlin.psi.ValueArgument; @@ -18,12 +19,14 @@ import org.jetbrains.org.objectweb.asm.Type; import java.util.List; import static org.jetbrains.kotlin.codegen.StackValue.createDefaultValue; +import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE; public class CallBasedArgumentGenerator extends ArgumentGenerator { private final ExpressionCodegen codegen; private final CallGenerator callGenerator; private final List valueParameters; private final List valueParameterTypes; + private final boolean isVarargInvoke; public CallBasedArgumentGenerator( @NotNull ExpressionCodegen codegen, @@ -36,19 +39,23 @@ public class CallBasedArgumentGenerator extends ArgumentGenerator { this.valueParameters = valueParameters; this.valueParameterTypes = valueParameterTypes; - assert valueParameters.size() == valueParameterTypes.size() : - "Value parameters and their types mismatch in sizes: " + valueParameters.size() + " != " + valueParameterTypes.size(); + CallableDescriptor container = valueParameters.isEmpty() ? null : valueParameters.get(0).getContainingDeclaration(); + this.isVarargInvoke = JvmCodegenUtil.isDeclarationOfBigArityFunctionInvoke(container); + + if (!isVarargInvoke) { + assert valueParameters.size() == valueParameterTypes.size() : + "Value parameters and their types mismatch in sizes: " + valueParameters.size() + " != " + valueParameterTypes.size(); + } } @Override protected void generateExpression(int i, @NotNull ExpressionValueArgument argument) { ValueParameterDescriptor parameter = valueParameters.get(i); - Type type = valueParameterTypes.get(i); ValueArgument valueArgument = argument.getValueArgument(); assert valueArgument != null; KtExpression argumentExpression = valueArgument.getArgumentExpression(); assert argumentExpression != null : valueArgument.asElement().getText(); - callGenerator.genValueAndPut(parameter, argumentExpression, type, i); + callGenerator.genValueAndPut(parameter, argumentExpression, isVarargInvoke ? OBJECT_TYPE : valueParameterTypes.get(i), i); } @Override diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/CallGenerator.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/CallGenerator.kt index 08796ff1a88..d5a41ccfd05 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/CallGenerator.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/CallGenerator.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.codegen import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE import org.jetbrains.org.objectweb.asm.Type enum class ValueKind { @@ -46,12 +47,30 @@ interface CallGenerator { } override fun genValueAndPut( - valueParameterDescriptor: ValueParameterDescriptor, - argumentExpression: KtExpression, - parameterType: Type, - parameterIndex: Int) { + valueParameterDescriptor: ValueParameterDescriptor, + argumentExpression: KtExpression, + parameterType: Type, + parameterIndex: Int + ) { + val container = valueParameterDescriptor.containingDeclaration + val isVarargInvoke = JvmCodegenUtil.isDeclarationOfBigArityFunctionInvoke(container) + + val v = codegen.v + if (isVarargInvoke) { + if (parameterIndex == 0) { + v.iconst(container.valueParameters.size) + v.newarray(OBJECT_TYPE) + } + v.dup() + v.iconst(parameterIndex) + } + val value = codegen.gen(argumentExpression) - value.put(parameterType, valueParameterDescriptor.original.type, codegen.v) + value.put(parameterType, valueParameterDescriptor.original.type, v) + + if (isVarargInvoke) { + v.astore(OBJECT_TYPE) + } } override fun putCapturedValueOnStack( diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java index edc63d0126f..a9dab231ad8 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java @@ -199,7 +199,8 @@ public class ClosureCodegen extends MemberCodegen { typeMapper.mapAsmMethod(erasedInterfaceFunction), erasedInterfaceFunction.getReturnType(), typeMapper.mapAsmMethod(funDescriptor), - funDescriptor.getReturnType() + funDescriptor.getReturnType(), + JvmCodegenUtil.isDeclarationOfBigArityFunctionInvoke(erasedInterfaceFunction) ); //TODO: rewrite cause ugly hack @@ -270,7 +271,8 @@ public class ClosureCodegen extends MemberCodegen { @NotNull Method bridge, @Nullable KotlinType bridgeReturnType, @NotNull Method delegate, - @Nullable KotlinType delegateReturnType + @Nullable KotlinType delegateReturnType, + boolean isVarargInvoke ) { if (bridge.equals(delegate)) return; @@ -285,9 +287,14 @@ public class ClosureCodegen extends MemberCodegen { InstructionAdapter iv = new InstructionAdapter(mv); MemberCodegen.markLineNumberForDescriptor(DescriptorUtils.getParentOfType(funDescriptor, ClassDescriptor.class), iv); - iv.load(0, asmType); - Type[] myParameterTypes = bridge.getArgumentTypes(); + if (isVarargInvoke) { + assert myParameterTypes.length == 1 && myParameterTypes[0].equals(AsmUtil.getArrayType(OBJECT_TYPE)) : + "Vararg invoke must have one parameter of type [Ljava/lang/Object;: " + bridge; + generateVarargInvokeArityAssert(iv, delegate.getArgumentTypes().length); + } + + iv.load(0, asmType); List calleeParameters = CollectionsKt.plus( CollectionsKt.listOfNotNull(funDescriptor.getExtensionReceiverParameter()), @@ -296,11 +303,20 @@ public class ClosureCodegen extends MemberCodegen { int slot = 1; for (int i = 0; i < calleeParameters.size(); i++) { - Type type = myParameterTypes[i]; ParameterDescriptor calleeParameter = calleeParameters.get(i); KotlinType parameterType = calleeParameter.getType(); - StackValue.local(slot, type, parameterType).put(typeMapper.mapType(calleeParameter), parameterType, iv); - slot += type.getSize(); + StackValue value; + if (isVarargInvoke) { + value = StackValue.arrayElement( + OBJECT_TYPE, null, StackValue.local(1, myParameterTypes[0], parameterType), StackValue.constant(i) + ); + } + else { + Type type = myParameterTypes[i]; + value = StackValue.local(slot, type, parameterType); + slot += type.getSize(); + } + value.put(typeMapper.mapType(calleeParameter), parameterType, iv); } iv.invokevirtual(asmType.getInternalName(), delegate.getName(), delegate.getDescriptor(), false); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java index 710193f1471..34f943058d2 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java @@ -1417,17 +1417,29 @@ public class FunctionCodegen { if (!state.getClassBuilderMode().generateBodies) return; mv.visitCode(); + InstructionAdapter iv = new InstructionAdapter(mv); Type[] argTypes = bridge.getArgumentTypes(); Type[] originalArgTypes = delegateTo.getArgumentTypes(); - List allKotlinParameters = new ArrayList<>(argTypes.length); + List allKotlinParameters = new ArrayList<>(originalArgTypes.length); if (descriptor.getExtensionReceiverParameter() != null) allKotlinParameters.add(descriptor.getExtensionReceiverParameter()); allKotlinParameters.addAll(descriptor.getValueParameters()); - boolean safeToUseKotlinTypes = allKotlinParameters.size() == argTypes.length; + boolean safeToUseKotlinTypes = allKotlinParameters.size() == originalArgTypes.length; + + boolean isVarargInvoke = JvmCodegenUtil.isOverrideOfBigArityFunctionInvoke(descriptor); + if (isVarargInvoke) { + assert argTypes.length == 1 && argTypes[0].equals(AsmUtil.getArrayType(OBJECT_TYPE)) : + "Vararg invoke must have one parameter of type [Ljava/lang/Object;: " + bridge; + AsmUtil.generateVarargInvokeArityAssert(iv, originalArgTypes.length); + } + else { + assert argTypes.length == originalArgTypes.length : + "Number of parameters of the bridge and delegate must be the same.\n" + + "Descriptor: " + descriptor + "\nBridge: " + bridge + "\nDelegate: " + delegateTo; + } - InstructionAdapter iv = new InstructionAdapter(mv); MemberCodegen.markLineNumberForDescriptor(owner.getThisDescriptor(), iv); if (delegateTo.getArgumentTypes().length > 0 && isSpecialBridge) { @@ -1435,11 +1447,18 @@ public class FunctionCodegen { } iv.load(0, OBJECT_TYPE); - for (int i = 0, reg = 1; i < argTypes.length; i++) { + for (int i = 0, reg = 1; i < originalArgTypes.length; i++) { KotlinType kotlinType = safeToUseKotlinTypes ? allKotlinParameters.get(i).getType() : null; - StackValue.local(reg, argTypes[i], kotlinType).put(originalArgTypes[i], kotlinType, iv); - //noinspection AssignmentToForLoopParameter - reg += argTypes[i].getSize(); + StackValue value; + if (isVarargInvoke) { + value = StackValue.arrayElement(OBJECT_TYPE, null, StackValue.local(1, argTypes[0]), StackValue.constant(i)); + } + else { + value = StackValue.local(reg, argTypes[i], kotlinType); + //noinspection AssignmentToForLoopParameter + reg += argTypes[i].getSize(); + } + value.put(originalArgTypes[i], kotlinType, iv); } if (isStubDeclarationWithDelegationToSuper) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java index e1dc5028461..4ed072098f5 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java @@ -11,6 +11,7 @@ import kotlin.collections.CollectionsKt; import kotlin.text.StringsKt; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor; import org.jetbrains.kotlin.codegen.binding.CalculatedClosure; import org.jetbrains.kotlin.codegen.context.CodegenContext; import org.jetbrains.kotlin.codegen.context.FacadePartWithSourceFile; @@ -38,6 +39,7 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue; import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver; import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor; import org.jetbrains.kotlin.types.KotlinType; +import org.jetbrains.kotlin.util.OperatorNameConventions; import java.io.File; @@ -348,4 +350,17 @@ public class JvmCodegenUtil { kind != OwnerKind.DEFAULT_IMPLS && !Boolean.FALSE.equals(bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, descriptor)); } + + public static boolean isDeclarationOfBigArityFunctionInvoke(@Nullable DeclarationDescriptor descriptor) { + return descriptor instanceof FunctionInvokeDescriptor && ((FunctionInvokeDescriptor) descriptor).hasBigArity(); + } + + public static boolean isOverrideOfBigArityFunctionInvoke(@Nullable DeclarationDescriptor descriptor) { + return descriptor instanceof FunctionDescriptor && + descriptor.getName().equals(OperatorNameConventions.INVOKE) && + CollectionsKt.any( + DescriptorUtils.getAllOverriddenDeclarations((FunctionDescriptor) descriptor), + JvmCodegenUtil::isDeclarationOfBigArityFunctionInvoke + ); + } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt index e358843fc98..abff742af45 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt @@ -43,7 +43,6 @@ import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter import org.jetbrains.org.objectweb.asm.commons.Method - abstract class AbstractCoroutineCodegen( outerExpressionCodegen: ExpressionCodegen, element: KtElement, @@ -228,7 +227,7 @@ class CoroutineCodegenForLambda private constructor( val bridgeParameters = (1 until delegate.argumentTypes.size).map { AsmTypes.OBJECT_TYPE } + delegate.argumentTypes.last() val bridge = Method(delegate.name, delegate.returnType, bridgeParameters.toTypedArray()) - generateBridge(bridge, createCoroutineDescriptor.returnType, delegate, createCoroutineDescriptor.returnType) + generateBridge(bridge, createCoroutineDescriptor.returnType, delegate, createCoroutineDescriptor.returnType, false) } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java index d4400f288ca..e3256b746c9 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java @@ -66,6 +66,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.stream.Stream; import static org.jetbrains.kotlin.codegen.AsmUtil.isStaticMethod; import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.*; @@ -1172,7 +1173,16 @@ public class KotlinTypeMapper { skipGenericSignature); } - return mapSignatureWithCustomParameters(f, kind, f.getValueParameters(), skipGenericSignature, hasSpecialBridge); + if (isDeclarationOfBigArityFunctionInvoke(f)) { + KotlinBuiltIns builtIns = DescriptorUtilsKt.getBuiltIns(f); + KotlinType arrayOfNullableAny = builtIns.getArrayType(Variance.INVARIANT, builtIns.getNullableAnyType()); + return mapSignatureWithCustomParameters(f, kind, Stream.of(arrayOfNullableAny), false, false); + } + + return mapSignatureWithCustomParameters( + f, kind, f.getValueParameters().stream().map(ValueParameterDescriptor::getType), + skipGenericSignature, hasSpecialBridge + ); } @NotNull @@ -1182,14 +1192,17 @@ public class KotlinTypeMapper { @NotNull List valueParameters, boolean skipGenericSignature ) { - return mapSignatureWithCustomParameters(f, kind, valueParameters, skipGenericSignature, false); + return mapSignatureWithCustomParameters( + f, kind, valueParameters.stream().map(ValueParameterDescriptor::getType), + skipGenericSignature, false + ); } @NotNull private JvmMethodGenericSignature mapSignatureWithCustomParameters( @NotNull FunctionDescriptor f, @NotNull OwnerKind kind, - @NotNull List valueParameters, + @NotNull Stream valueParameterTypes, boolean skipGenericSignature, boolean hasSpecialBridge ) { @@ -1203,9 +1216,7 @@ public class KotlinTypeMapper { sw.writeParametersStart(); writeAdditionalConstructorParameters((ClassConstructorDescriptor) f, sw); - for (ValueParameterDescriptor parameter : valueParameters) { - writeParameter(sw, parameter.getType(), f); - } + valueParameterTypes.forEach(type -> writeParameter(sw, type, f)); if (f instanceof AccessorForConstructorDescriptor) { writeParameter(sw, JvmMethodParameterKind.CONSTRUCTOR_MARKER, DEFAULT_CONSTRUCTOR_MARKER); @@ -1242,14 +1253,10 @@ public class KotlinTypeMapper { writeParameter(sw, JvmMethodParameterKind.RECEIVER, receiverParameter.getType(), f); } - for (ValueParameterDescriptor parameter : valueParameters) { + valueParameterTypes.forEach(type -> { boolean forceBoxing = MethodSignatureMappingKt.forceSingleValueParameterBoxing(f); - writeParameter( - sw, - forceBoxing ? TypeUtils.makeNullable(parameter.getType()) : parameter.getType(), - f - ); - } + writeParameter(sw, forceBoxing ? TypeUtils.makeNullable(type) : type, f); + }); sw.writeReturnType(); mapReturnType(f, sw); diff --git a/compiler/testData/codegen/box/functions/bigArity/callWithIncorrectNumberOfArguments.kt b/compiler/testData/codegen/box/functions/bigArity/callWithIncorrectNumberOfArguments.kt new file mode 100644 index 00000000000..d882b078576 --- /dev/null +++ b/compiler/testData/codegen/box/functions/bigArity/callWithIncorrectNumberOfArguments.kt @@ -0,0 +1,66 @@ +// WITH_RUNTIME +// TARGET_BACKEND: JVM +// 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 Object(); + for (int i = 0; i < 42; i++) { + if (i == 30) continue; + + Object[] args = new Object[i]; + Arrays.fill(args, o); + try { + f.invoke(args); + } catch (IllegalArgumentException 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 + ); + } + throw new AssertionError("IllegalArgumentException expected, but nothing was thrown, i = " + i); + } + } +} + +// FILE: K.kt + +fun foo( + p00: Any?, p01: Any?, p02: Any?, p03: Any?, p04: Any?, p05: Any?, p06: Any?, p07: Any?, p08: Any?, p09: Any?, + p10: Any?, p11: Any?, p12: Any?, p13: Any?, p14: Any?, p15: Any?, p16: Any?, p17: Any?, p18: Any?, p19: Any?, + p20: Any?, p21: Any?, p22: Any?, p23: Any?, p24: Any?, p25: Any?, p26: Any?, p27: Any?, p28: Any?, p29: Any? +) {} + +class Fun : (Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, + Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?) -> Unit { + override fun invoke( + p00: Any?, p01: Any?, p02: Any?, p03: Any?, p04: Any?, p05: Any?, p06: Any?, p07: Any?, p08: Any?, p09: Any?, + p10: Any?, p11: Any?, p12: Any?, p13: Any?, p14: Any?, p15: Any?, p16: Any?, p17: Any?, p18: Any?, p19: Any?, + p20: Any?, p21: Any?, p22: Any?, p23: Any?, p24: Any?, p25: Any?, p26: Any?, p27: Any?, p28: Any?, p29: Any? + ) {} +} + +fun box(): String { + val lambda: Function30< + Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, + Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, + Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, + Unit> = { _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ -> } + J.test(lambda as kotlin.jvm.functions.FunctionN) + J.test(::foo as kotlin.jvm.functions.FunctionN) + J.test(Fun() as kotlin.jvm.functions.FunctionN) + return "OK" +} diff --git a/compiler/testData/codegen/box/functions/bigArity/function255.kt b/compiler/testData/codegen/box/functions/bigArity/function255.kt new file mode 100644 index 00000000000..2e064b0b24c --- /dev/null +++ b/compiler/testData/codegen/box/functions/bigArity/function255.kt @@ -0,0 +1,120 @@ +// IGNORE_BACKEND: JS_IR + +class A(val value: Int) { + // for (i in 1..254) { print("p${"%03d".format(i)}: A, "); if (i % 10 == 0) println() }; println() + + fun lmao( + p001: A, p002: A, p003: A, p004: A, p005: A, p006: A, p007: A, p008: A, p009: A, p010: A, + p011: A, p012: A, p013: A, p014: A, p015: A, p016: A, p017: A, p018: A, p019: A, p020: A, + p021: A, p022: A, p023: A, p024: A, p025: A, p026: A, p027: A, p028: A, p029: A, p030: A, + p031: A, p032: A, p033: A, p034: A, p035: A, p036: A, p037: A, p038: A, p039: A, p040: A, + p041: A, p042: A, p043: A, p044: A, p045: A, p046: A, p047: A, p048: A, p049: A, p050: A, + p051: A, p052: A, p053: A, p054: A, p055: A, p056: A, p057: A, p058: A, p059: A, p060: A, + p061: A, p062: A, p063: A, p064: A, p065: A, p066: A, p067: A, p068: A, p069: A, p070: A, + p071: A, p072: A, p073: A, p074: A, p075: A, p076: A, p077: A, p078: A, p079: A, p080: A, + p081: A, p082: A, p083: A, p084: A, p085: A, p086: A, p087: A, p088: A, p089: A, p090: A, + p091: A, p092: A, p093: A, p094: A, p095: A, p096: A, p097: A, p098: A, p099: A, p100: A, + p101: A, p102: A, p103: A, p104: A, p105: A, p106: A, p107: A, p108: A, p109: A, p110: A, + p111: A, p112: A, p113: A, p114: A, p115: A, p116: A, p117: A, p118: A, p119: A, p120: A, + p121: A, p122: A, p123: A, p124: A, p125: A, p126: A, p127: A, p128: A, p129: A, p130: A, + p131: A, p132: A, p133: A, p134: A, p135: A, p136: A, p137: A, p138: A, p139: A, p140: A, + p141: A, p142: A, p143: A, p144: A, p145: A, p146: A, p147: A, p148: A, p149: A, p150: A, + p151: A, p152: A, p153: A, p154: A, p155: A, p156: A, p157: A, p158: A, p159: A, p160: A, + p161: A, p162: A, p163: A, p164: A, p165: A, p166: A, p167: A, p168: A, p169: A, p170: A, + p171: A, p172: A, p173: A, p174: A, p175: A, p176: A, p177: A, p178: A, p179: A, p180: A, + p181: A, p182: A, p183: A, p184: A, p185: A, p186: A, p187: A, p188: A, p189: A, p190: A, + p191: A, p192: A, p193: A, p194: A, p195: A, p196: A, p197: A, p198: A, p199: A, p200: A, + p201: A, p202: A, p203: A, p204: A, p205: A, p206: A, p207: A, p208: A, p209: A, p210: A, + p211: A, p212: A, p213: A, p214: A, p215: A, p216: A, p217: A, p218: A, p219: A, p220: A, + p221: A, p222: A, p223: A, p224: A, p225: A, p226: A, p227: A, p228: A, p229: A, p230: A, + p231: A, p232: A, p233: A, p234: A, p235: A, p236: A, p237: A, p238: A, p239: A, p240: A, + p241: A, p242: A, p243: A, p244: A, p245: A, p246: A, p247: A, p248: A, p249: A, p250: A, + p251: A, p252: A, p253: A, p254: A + ) { + check(this, 0) + + // for (i in 1..254) { print("check(p${"%03d".format(i)}, $i)"); if (i % 6 == 0) println() else print("; ") }; println() + + check(p001, 1); check(p002, 2); check(p003, 3); check(p004, 4); check(p005, 5); check(p006, 6) + check(p007, 7); check(p008, 8); check(p009, 9); check(p010, 10); check(p011, 11); check(p012, 12) + check(p013, 13); check(p014, 14); check(p015, 15); check(p016, 16); check(p017, 17); check(p018, 18) + check(p019, 19); check(p020, 20); check(p021, 21); check(p022, 22); check(p023, 23); check(p024, 24) + check(p025, 25); check(p026, 26); check(p027, 27); check(p028, 28); check(p029, 29); check(p030, 30) + check(p031, 31); check(p032, 32); check(p033, 33); check(p034, 34); check(p035, 35); check(p036, 36) + check(p037, 37); check(p038, 38); check(p039, 39); check(p040, 40); check(p041, 41); check(p042, 42) + check(p043, 43); check(p044, 44); check(p045, 45); check(p046, 46); check(p047, 47); check(p048, 48) + check(p049, 49); check(p050, 50); check(p051, 51); check(p052, 52); check(p053, 53); check(p054, 54) + check(p055, 55); check(p056, 56); check(p057, 57); check(p058, 58); check(p059, 59); check(p060, 60) + check(p061, 61); check(p062, 62); check(p063, 63); check(p064, 64); check(p065, 65); check(p066, 66) + check(p067, 67); check(p068, 68); check(p069, 69); check(p070, 70); check(p071, 71); check(p072, 72) + check(p073, 73); check(p074, 74); check(p075, 75); check(p076, 76); check(p077, 77); check(p078, 78) + check(p079, 79); check(p080, 80); check(p081, 81); check(p082, 82); check(p083, 83); check(p084, 84) + check(p085, 85); check(p086, 86); check(p087, 87); check(p088, 88); check(p089, 89); check(p090, 90) + check(p091, 91); check(p092, 92); check(p093, 93); check(p094, 94); check(p095, 95); check(p096, 96) + check(p097, 97); check(p098, 98); check(p099, 99); check(p100, 100); check(p101, 101); check(p102, 102) + check(p103, 103); check(p104, 104); check(p105, 105); check(p106, 106); check(p107, 107); check(p108, 108) + check(p109, 109); check(p110, 110); check(p111, 111); check(p112, 112); check(p113, 113); check(p114, 114) + check(p115, 115); check(p116, 116); check(p117, 117); check(p118, 118); check(p119, 119); check(p120, 120) + check(p121, 121); check(p122, 122); check(p123, 123); check(p124, 124); check(p125, 125); check(p126, 126) + check(p127, 127); check(p128, 128); check(p129, 129); check(p130, 130); check(p131, 131); check(p132, 132) + check(p133, 133); check(p134, 134); check(p135, 135); check(p136, 136); check(p137, 137); check(p138, 138) + check(p139, 139); check(p140, 140); check(p141, 141); check(p142, 142); check(p143, 143); check(p144, 144) + check(p145, 145); check(p146, 146); check(p147, 147); check(p148, 148); check(p149, 149); check(p150, 150) + check(p151, 151); check(p152, 152); check(p153, 153); check(p154, 154); check(p155, 155); check(p156, 156) + check(p157, 157); check(p158, 158); check(p159, 159); check(p160, 160); check(p161, 161); check(p162, 162) + check(p163, 163); check(p164, 164); check(p165, 165); check(p166, 166); check(p167, 167); check(p168, 168) + check(p169, 169); check(p170, 170); check(p171, 171); check(p172, 172); check(p173, 173); check(p174, 174) + check(p175, 175); check(p176, 176); check(p177, 177); check(p178, 178); check(p179, 179); check(p180, 180) + check(p181, 181); check(p182, 182); check(p183, 183); check(p184, 184); check(p185, 185); check(p186, 186) + check(p187, 187); check(p188, 188); check(p189, 189); check(p190, 190); check(p191, 191); check(p192, 192) + check(p193, 193); check(p194, 194); check(p195, 195); check(p196, 196); check(p197, 197); check(p198, 198) + check(p199, 199); check(p200, 200); check(p201, 201); check(p202, 202); check(p203, 203); check(p204, 204) + check(p205, 205); check(p206, 206); check(p207, 207); check(p208, 208); check(p209, 209); check(p210, 210) + check(p211, 211); check(p212, 212); check(p213, 213); check(p214, 214); check(p215, 215); check(p216, 216) + check(p217, 217); check(p218, 218); check(p219, 219); check(p220, 220); check(p221, 221); check(p222, 222) + check(p223, 223); check(p224, 224); check(p225, 225); check(p226, 226); check(p227, 227); check(p228, 228) + check(p229, 229); check(p230, 230); check(p231, 231); check(p232, 232); check(p233, 233); check(p234, 234) + check(p235, 235); check(p236, 236); check(p237, 237); check(p238, 238); check(p239, 239); check(p240, 240) + check(p241, 241); check(p242, 242); check(p243, 243); check(p244, 244); check(p245, 245); check(p246, 246) + check(p247, 247); check(p248, 248); check(p249, 249); check(p250, 250); check(p251, 251); check(p252, 252) + check(p253, 253); check(p254, 254) + } + + private fun check(a: A, value: Int) { + if (a.value != value) { + throw AssertionError("Expected $value, actual ${a.value}") + } + } +} + +fun box(): String { + val ref = A(0)::lmao + + // for (i in 1..254) { print("A($i), "); if (i % 12 == 0) println() }; println() + ref( + A(1), A(2), A(3), A(4), A(5), A(6), A(7), A(8), A(9), A(10), A(11), A(12), + A(13), A(14), A(15), A(16), A(17), A(18), A(19), A(20), A(21), A(22), A(23), A(24), + A(25), A(26), A(27), A(28), A(29), A(30), A(31), A(32), A(33), A(34), A(35), A(36), + A(37), A(38), A(39), A(40), A(41), A(42), A(43), A(44), A(45), A(46), A(47), A(48), + A(49), A(50), A(51), A(52), A(53), A(54), A(55), A(56), A(57), A(58), A(59), A(60), + A(61), A(62), A(63), A(64), A(65), A(66), A(67), A(68), A(69), A(70), A(71), A(72), + A(73), A(74), A(75), A(76), A(77), A(78), A(79), A(80), A(81), A(82), A(83), A(84), + A(85), A(86), A(87), A(88), A(89), A(90), A(91), A(92), A(93), A(94), A(95), A(96), + A(97), A(98), A(99), A(100), A(101), A(102), A(103), A(104), A(105), A(106), A(107), A(108), + A(109), A(110), A(111), A(112), A(113), A(114), A(115), A(116), A(117), A(118), A(119), A(120), + A(121), A(122), A(123), A(124), A(125), A(126), A(127), A(128), A(129), A(130), A(131), A(132), + A(133), A(134), A(135), A(136), A(137), A(138), A(139), A(140), A(141), A(142), A(143), A(144), + A(145), A(146), A(147), A(148), A(149), A(150), A(151), A(152), A(153), A(154), A(155), A(156), + A(157), A(158), A(159), A(160), A(161), A(162), A(163), A(164), A(165), A(166), A(167), A(168), + A(169), A(170), A(171), A(172), A(173), A(174), A(175), A(176), A(177), A(178), A(179), A(180), + A(181), A(182), A(183), A(184), A(185), A(186), A(187), A(188), A(189), A(190), A(191), A(192), + A(193), A(194), A(195), A(196), A(197), A(198), A(199), A(200), A(201), A(202), A(203), A(204), + A(205), A(206), A(207), A(208), A(209), A(210), A(211), A(212), A(213), A(214), A(215), A(216), + A(217), A(218), A(219), A(220), A(221), A(222), A(223), A(224), A(225), A(226), A(227), A(228), + A(229), A(230), A(231), A(232), A(233), A(234), A(235), A(236), A(237), A(238), A(239), A(240), + A(241), A(242), A(243), A(244), A(245), A(246), A(247), A(248), A(249), A(250), A(251), A(252), + A(253), A(254) + ) + + return "OK" +} diff --git a/compiler/testData/codegen/box/functions/bigArity/instanceOfCallableReference.kt b/compiler/testData/codegen/box/functions/bigArity/instanceOfCallableReference.kt new file mode 100644 index 00000000000..4208ef4d759 --- /dev/null +++ b/compiler/testData/codegen/box/functions/bigArity/instanceOfCallableReference.kt @@ -0,0 +1,20 @@ +// IGNORE_BACKEND: JS_IR, JS + +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 +) { +} + +fun box(): String { + val ref = ::foo + if (ref is Function0<*>) return "Fail 0" + if (ref is Function1<*, *>) return "Fail 1" + if (ref !is Function30<*, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *>) return "Fail 30" + if (ref is Function31<*, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *>) return "Fail 31" + + return "OK" +} diff --git a/compiler/testData/codegen/box/functions/bigArity/invokeCallableReference.kt b/compiler/testData/codegen/box/functions/bigArity/invokeCallableReference.kt new file mode 100644 index 00000000000..14378b51686 --- /dev/null +++ b/compiler/testData/codegen/box/functions/bigArity/invokeCallableReference.kt @@ -0,0 +1,16 @@ +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 ref = ::foo + + val a = A() + 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/invokeLambda.kt b/compiler/testData/codegen/box/functions/bigArity/invokeLambda.kt new file mode 100644 index 00000000000..8e016138c83 --- /dev/null +++ b/compiler/testData/codegen/box/functions/bigArity/invokeLambda.kt @@ -0,0 +1,52 @@ +class A(val value: Int) + +private fun check(actual: A, expected: Int) { + if (expected != actual.value) { + throw AssertionError("Expected $expected, actual ${actual.value}") + } +} + +fun box(): String { + val l = { + 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 -> + check(p00, 0) + check(p01, 1) + check(p02, 2) + check(p03, 3) + check(p04, 4) + check(p05, 5) + check(p06, 6) + check(p07, 7) + check(p08, 8) + check(p09, 9) + check(p10, 10) + check(p11, 11) + check(p12, 12) + check(p13, 13) + check(p14, 14) + check(p15, 15) + check(p16, 16) + check(p17, 17) + check(p18, 18) + check(p19, 19) + check(p20, 20) + check(p21, 21) + check(p22, 22) + check(p23, 23) + check(p24, 24) + check(p25, 25) + check(p26, 26) + check(p27, 27) + check(p28, 28) + check(p29, 29) + "OK" + } + + return l( + A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7), A(8), A(9), + A(10), A(11), A(12), A(13), A(14), A(15), A(16), A(17), A(18), A(19), + A(20), A(21), A(22), A(23), A(24), A(25), A(26), A(27), A(28), A(29) + ) +} diff --git a/compiler/testData/codegen/box/functions/bigArity/javaLambda.kt b/compiler/testData/codegen/box/functions/bigArity/javaLambda.kt new file mode 100644 index 00000000000..c44b2449dfc --- /dev/null +++ b/compiler/testData/codegen/box/functions/bigArity/javaLambda.kt @@ -0,0 +1,58 @@ +// WITH_RUNTIME +// TARGET_BACKEND: JVM +// FILE: J.java + +// import kotlin.jvm.functions.Arity; +import kotlin.jvm.functions.FunctionN; + +public class J { + // TODO: uncomment arity as soon as Arity is introduced + // @Arity(30) + public static final FunctionN FIELD = new FunctionN() { + @Override + public String invoke(Object... args) { + return "OK"; + } + + @Override + public int getArity() { + return 30; + } + }; + + // TODO: uncomment arity as soon as Arity is introduced + // @Arity(30) + public static FunctionN getViaMethod() { + return FIELD; + } +} + +// FILE: K.kt + +class A + +fun call(f: (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) -> String): String { + val a = A() + return f(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) +} + +fun box(): String { + val f = J.FIELD as Function30< + Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, + Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, + Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, + String> + if (f !is Function30<*, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *>) return "Fail field 30" + if (f is Function31<*, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *>) return "Fail field 31" + if (call(f) != "OK") return "Fail field call" + + val m = J.getViaMethod() as Function30< + Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, + Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, + Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, + String> + if (m !is Function30<*, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *>) return "Fail method 30" + if (m is Function31<*, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *>) return "Fail method 31" + + return call(m) +} diff --git a/compiler/testData/codegen/box/functions/bigArity/subclass.kt b/compiler/testData/codegen/box/functions/bigArity/subclass.kt new file mode 100644 index 00000000000..31ca50c3e02 --- /dev/null +++ b/compiler/testData/codegen/box/functions/bigArity/subclass.kt @@ -0,0 +1,22 @@ +// Implementing function interface is prohibited in JavaScript +// IGNORE_BACKEND: JS_IR, JS + +class A(val value: String) + +class Fun : (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, A, A, A, A, A, A, A, A, A, A, A, A) -> String { + override fun invoke( + p1: A, p2: A, p3: A, p4: A, p5: A, p6: A, p7: A, p8: A, p9: 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, + p30: A, p31: A, p32: A, p33: A, p34: A, p35: A, p36: A, p37: A, p38: A, p39: A, + p40: A, p41: A, p42: A + ): String { + return p21.value + p32.value + } +} + +fun box(): String { + val a = A("") + val f = Fun() + return f(a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, A("O"), a, a, a, a, a, a, a, a, a, a, A("K"), a, a, a, a, a, a, a, a, a, a) +} diff --git a/compiler/testData/codegen/box/javaInterop/notNullAssertions/functionWithBigArity.kt b/compiler/testData/codegen/box/javaInterop/notNullAssertions/functionWithBigArity.kt new file mode 100644 index 00000000000..ca7a4971aed --- /dev/null +++ b/compiler/testData/codegen/box/javaInterop/notNullAssertions/functionWithBigArity.kt @@ -0,0 +1,55 @@ +// TARGET_BACKEND: JVM +// WITH_RUNTIME +// FILE: Test.java + +// import kotlin.jvm.functions.Arity; +import kotlin.jvm.functions.FunctionN; +import java.util.Arrays; + +public class Test { + public static final int N = 30; + + // TODO: uncomment arity as soon as Arity is introduced + public static void test(/* @Arity(N) */ FunctionN f) { + Object[] args = new Object[N]; + Object o = new Object(); + Arrays.fill(args, o); + for (int i = 0; i < N; i++) { + args[i] = null; + try { + f.invoke(args); + } catch (IllegalArgumentException e) { + // OK + continue; + } catch (Throwable e) { + throw new AssertionError( + "Incorrect exception (IllegalArgumentException expected): " + e.getClass().getName() + ", parameter index = " + i, + e + ); + } finally { + args[i] = o; + } + throw new AssertionError("IllegalArgumentException expected, but nothing was thrown, parameter index = " + i); + } + } +} + +// FILE: box.kt + +fun f( + p01: Any, p02: Any, p03: Any, p04: Any, p05: Any, p06: Any, p07: Any, p08: Any, p09: Any, p10: Any, + p11: Any, p12: Any, p13: Any, p14: Any, p15: Any, p16: Any, p17: Any, p18: Any, p19: Any, p20: Any, + p21: Any, p22: Any, p23: Any, p24: Any, p25: Any, p26: Any, p27: Any, p28: Any, p29: Any, p30: Any +): Any = Any() + +fun Any.g( + p02: Any, p03: Any, p04: Any, p05: Any, p06: Any, p07: Any, p08: Any, p09: Any, p10: Any, + p11: Any, p12: Any, p13: Any, p14: Any, p15: Any, p16: Any, p17: Any, p18: Any, p19: Any, p20: Any, + p21: Any, p22: Any, p23: Any, p24: Any, p25: Any, p26: Any, p27: Any, p28: Any, p29: Any, p30: Any +): Any = Any() + +fun box(): String { + Test.test(::f as kotlin.jvm.functions.FunctionN) + Test.test(Any::g as kotlin.jvm.functions.FunctionN) + return "OK" +} diff --git a/compiler/testData/codegen/box/reflection/call/bigArity.kt b/compiler/testData/codegen/box/reflection/call/bigArity.kt new file mode 100644 index 00000000000..cd275bd789e --- /dev/null +++ b/compiler/testData/codegen/box/reflection/call/bigArity.kt @@ -0,0 +1,22 @@ +// IGNORE_BACKEND: JS_IR, JS, NATIVE +// WITH_REFLECT + +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: String + ): String { + return p29 + } +} + +fun box(): String { + val a = A() + val o = A::foo.call(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, "O") + + val foo = A::class.members.single { it.name == "foo" } + val k = foo.call(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, "K") + + return o + k +} diff --git a/compiler/testData/codegen/box/reflection/parameters/bigArity.kt b/compiler/testData/codegen/box/reflection/parameters/bigArity.kt new file mode 100644 index 00000000000..a80ccd55e9a --- /dev/null +++ b/compiler/testData/codegen/box/reflection/parameters/bigArity.kt @@ -0,0 +1,21 @@ +// IGNORE_BACKEND: JS_IR, JS, NATIVE +// WITH_REFLECT + +import kotlin.test.assertEquals + +class A + +data class BigDataClass( + val p00: A, val p01: A, val p02: A, val p03: A, val p04: A, val p05: A, val p06: A, val p07: A, val p08: A, val p09: A, + val p10: A, val p11: A, val p12: A, val p13: A, val p14: A, val p15: A, val p16: A, val p17: A, val p18: A, val p19: A, + val p20: A, val p21: A, val p22: A, val p23: A, val p24: A, val p25: A, val p26: A, val p27: A, val p28: A, val p29: A +) + +fun box(): String { + assertEquals( + "[null, p00, p01, p02, p03, p04, p05, p06, p07, p08, p09, p10, p11, p12, p13, p14, " + + "p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29]", + BigDataClass::copy.parameters.map { it.name }.toString() + ) + return "OK" +} diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index e5879444c5c..e06c195cf26 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -10275,6 +10275,54 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/functions/recursiveIncrementCall.kt"); } + @TestMetadata("compiler/testData/codegen/box/functions/bigArity") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class BigArity extends AbstractIrBlackBoxCodegenTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); + } + + public void testAllFilesPresentInBigArity() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/functions/bigArity"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); + } + + @TestMetadata("callWithIncorrectNumberOfArguments.kt") + public void testCallWithIncorrectNumberOfArguments() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/callWithIncorrectNumberOfArguments.kt"); + } + + @TestMetadata("function255.kt") + public void testFunction255() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/function255.kt"); + } + + @TestMetadata("instanceOfCallableReference.kt") + public void testInstanceOfCallableReference() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/instanceOfCallableReference.kt"); + } + + @TestMetadata("invokeCallableReference.kt") + public void testInvokeCallableReference() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/invokeCallableReference.kt"); + } + + @TestMetadata("invokeLambda.kt") + public void testInvokeLambda() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/invokeLambda.kt"); + } + + @TestMetadata("javaLambda.kt") + public void testJavaLambda() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/javaLambda.kt"); + } + + @TestMetadata("subclass.kt") + public void testSubclass() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/subclass.kt"); + } + } + @TestMetadata("compiler/testData/codegen/box/functions/functionExpression") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) @@ -11687,6 +11735,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/extensionReceiverParameter.kt"); } + @TestMetadata("functionWithBigArity.kt") + public void testFunctionWithBigArity() throws Exception { + runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/functionWithBigArity.kt"); + } + @TestMetadata("incWithNullabilityAssertionOnExtensionReceiverInPrivateOperator_lv11.kt") public void testIncWithNullabilityAssertionOnExtensionReceiverInPrivateOperator_lv11() throws Exception { runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/incWithNullabilityAssertionOnExtensionReceiverInPrivateOperator_lv11.kt"); @@ -16649,6 +16702,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/call"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true); } + @TestMetadata("bigArity.kt") + public void testBigArity() throws Exception { + runTest("compiler/testData/codegen/box/reflection/call/bigArity.kt"); + } + @TestMetadata("callInstanceJavaMethod.kt") public void testCallInstanceJavaMethod() throws Exception { runTest("compiler/testData/codegen/box/reflection/call/callInstanceJavaMethod.kt"); @@ -18085,6 +18143,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/parameters"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true); } + @TestMetadata("bigArity.kt") + public void testBigArity() throws Exception { + runTest("compiler/testData/codegen/box/reflection/parameters/bigArity.kt"); + } + @TestMetadata("boundInnerClassConstructor.kt") public void testBoundInnerClassConstructor() throws Exception { runTest("compiler/testData/codegen/box/reflection/parameters/boundInnerClassConstructor.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index ad1ab179b8e..16f182ab1ed 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -10275,6 +10275,54 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/functions/recursiveIncrementCall.kt"); } + @TestMetadata("compiler/testData/codegen/box/functions/bigArity") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class BigArity extends AbstractBlackBoxCodegenTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); + } + + public void testAllFilesPresentInBigArity() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/functions/bigArity"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); + } + + @TestMetadata("callWithIncorrectNumberOfArguments.kt") + public void testCallWithIncorrectNumberOfArguments() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/callWithIncorrectNumberOfArguments.kt"); + } + + @TestMetadata("function255.kt") + public void testFunction255() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/function255.kt"); + } + + @TestMetadata("instanceOfCallableReference.kt") + public void testInstanceOfCallableReference() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/instanceOfCallableReference.kt"); + } + + @TestMetadata("invokeCallableReference.kt") + public void testInvokeCallableReference() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/invokeCallableReference.kt"); + } + + @TestMetadata("invokeLambda.kt") + public void testInvokeLambda() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/invokeLambda.kt"); + } + + @TestMetadata("javaLambda.kt") + public void testJavaLambda() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/javaLambda.kt"); + } + + @TestMetadata("subclass.kt") + public void testSubclass() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/subclass.kt"); + } + } + @TestMetadata("compiler/testData/codegen/box/functions/functionExpression") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) @@ -11687,6 +11735,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/extensionReceiverParameter.kt"); } + @TestMetadata("functionWithBigArity.kt") + public void testFunctionWithBigArity() throws Exception { + runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/functionWithBigArity.kt"); + } + @TestMetadata("incWithNullabilityAssertionOnExtensionReceiverInPrivateOperator_lv11.kt") public void testIncWithNullabilityAssertionOnExtensionReceiverInPrivateOperator_lv11() throws Exception { runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/incWithNullabilityAssertionOnExtensionReceiverInPrivateOperator_lv11.kt"); @@ -16649,6 +16702,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/call"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); } + @TestMetadata("bigArity.kt") + public void testBigArity() throws Exception { + runTest("compiler/testData/codegen/box/reflection/call/bigArity.kt"); + } + @TestMetadata("callInstanceJavaMethod.kt") public void testCallInstanceJavaMethod() throws Exception { runTest("compiler/testData/codegen/box/reflection/call/callInstanceJavaMethod.kt"); @@ -18085,6 +18143,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/parameters"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); } + @TestMetadata("bigArity.kt") + public void testBigArity() throws Exception { + runTest("compiler/testData/codegen/box/reflection/parameters/bigArity.kt"); + } + @TestMetadata("boundInnerClassConstructor.kt") public void testBoundInnerClassConstructor() throws Exception { runTest("compiler/testData/codegen/box/reflection/parameters/boundInnerClassConstructor.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 02b013f13c6..ac7be3b9a24 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -10275,6 +10275,54 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/functions/recursiveIncrementCall.kt"); } + @TestMetadata("compiler/testData/codegen/box/functions/bigArity") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class BigArity extends AbstractLightAnalysisModeTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); + } + + public void testAllFilesPresentInBigArity() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/functions/bigArity"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); + } + + @TestMetadata("callWithIncorrectNumberOfArguments.kt") + public void testCallWithIncorrectNumberOfArguments() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/callWithIncorrectNumberOfArguments.kt"); + } + + @TestMetadata("function255.kt") + public void testFunction255() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/function255.kt"); + } + + @TestMetadata("instanceOfCallableReference.kt") + public void testInstanceOfCallableReference() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/instanceOfCallableReference.kt"); + } + + @TestMetadata("invokeCallableReference.kt") + public void testInvokeCallableReference() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/invokeCallableReference.kt"); + } + + @TestMetadata("invokeLambda.kt") + public void testInvokeLambda() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/invokeLambda.kt"); + } + + @TestMetadata("javaLambda.kt") + public void testJavaLambda() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/javaLambda.kt"); + } + + @TestMetadata("subclass.kt") + public void testSubclass() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/subclass.kt"); + } + } + @TestMetadata("compiler/testData/codegen/box/functions/functionExpression") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) @@ -11687,6 +11735,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/extensionReceiverParameter.kt"); } + @TestMetadata("functionWithBigArity.kt") + public void testFunctionWithBigArity() throws Exception { + runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/functionWithBigArity.kt"); + } + @TestMetadata("incWithNullabilityAssertionOnExtensionReceiverInPrivateOperator_lv11.kt") public void testIncWithNullabilityAssertionOnExtensionReceiverInPrivateOperator_lv11() throws Exception { runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/incWithNullabilityAssertionOnExtensionReceiverInPrivateOperator_lv11.kt"); @@ -16649,6 +16702,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/call"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); } + @TestMetadata("bigArity.kt") + public void testBigArity() throws Exception { + runTest("compiler/testData/codegen/box/reflection/call/bigArity.kt"); + } + @TestMetadata("callInstanceJavaMethod.kt") public void testCallInstanceJavaMethod() throws Exception { runTest("compiler/testData/codegen/box/reflection/call/callInstanceJavaMethod.kt"); @@ -18085,6 +18143,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/parameters"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); } + @TestMetadata("bigArity.kt") + public void testBigArity() throws Exception { + runTest("compiler/testData/codegen/box/reflection/parameters/bigArity.kt"); + } + @TestMetadata("boundInnerClassConstructor.kt") public void testBoundInnerClassConstructor() throws Exception { runTest("compiler/testData/codegen/box/reflection/parameters/boundInnerClassConstructor.kt"); diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/builtins/jvm/JavaToKotlinClassMap.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/builtins/jvm/JavaToKotlinClassMap.kt index b11a26f90d3..07f6b5582e6 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/builtins/jvm/JavaToKotlinClassMap.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/builtins/jvm/JavaToKotlinClassMap.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns.FQ_NAMES import org.jetbrains.kotlin.builtins.PlatformToKotlinClassMap import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor +import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.name.* import org.jetbrains.kotlin.resolve.DescriptorUtils @@ -21,6 +22,14 @@ import org.jetbrains.kotlin.types.TypeUtils import java.util.* object JavaToKotlinClassMap : PlatformToKotlinClassMap { + private val NUMBERED_FUNCTION_PREFIX = + FunctionClassDescriptor.Kind.Function.packageFqName.toString() + "." + FunctionClassDescriptor.Kind.Function.classNamePrefix + private val NUMBERED_K_FUNCTION_PREFIX = + FunctionClassDescriptor.Kind.KFunction.packageFqName.toString() + "." + FunctionClassDescriptor.Kind.KFunction.classNamePrefix + + private val FUNCTION_N_CLASS_ID = ClassId.topLevel(FqName("kotlin.jvm.functions.FunctionN")) + private val FUNCTION_N_FQ_NAME = FUNCTION_N_CLASS_ID.asSingleFqName() + private val K_FUNCTION_CLASS_ID = ClassId.topLevel(FqName("kotlin.reflect.KFunction")) private val javaToKotlin = HashMap() private val kotlinToJava = HashMap() @@ -82,17 +91,14 @@ object JavaToKotlinClassMap : PlatformToKotlinClassMap { ) } - // TODO: support also functions with >= 23 parameters - val kFunction = FunctionClassDescriptor.Kind.KFunction - val kFun = kFunction.packageFqName.toString() + "." + kFunction.classNamePrefix - for (i in 0..22) { - add(ClassId.topLevel(FqName("kotlin.jvm.functions.Function" + i)), KotlinBuiltIns.getFunctionClassId(i)) - addKotlinToJava(FqName(kFun + i), ClassId.topLevel(FqName(kFun))) + for (i in 0 until FunctionInvokeDescriptor.BIG_ARITY) { + add(ClassId.topLevel(FqName("kotlin.jvm.functions.Function$i")), KotlinBuiltIns.getFunctionClassId(i)) + addKotlinToJava(FqName(NUMBERED_K_FUNCTION_PREFIX + i), K_FUNCTION_CLASS_ID) } - for (i in 0 until 22) { + for (i in 0 until FunctionInvokeDescriptor.BIG_ARITY - 1) { val kSuspendFunction = FunctionClassDescriptor.Kind.KSuspendFunction val kSuspendFun = kSuspendFunction.packageFqName.toString() + "." + kSuspendFunction.classNamePrefix - addKotlinToJava(FqName(kSuspendFun + i), ClassId.topLevel(FqName(kFun))) + addKotlinToJava(FqName(kSuspendFun + i), K_FUNCTION_CLASS_ID) } addKotlinToJava(FQ_NAMES.nothing.toSafe(), classId(Void::class.java)) @@ -107,13 +113,16 @@ object JavaToKotlinClassMap : PlatformToKotlinClassMap { * java.util.Map.Entry -> kotlin.Map.Entry * java.lang.Void -> null * kotlin.jvm.functions.Function3 -> kotlin.Function3 + * kotlin.jvm.functions.FunctionN -> null // Without a type annotation like @Arity(n), it's impossible to find out arity */ fun mapJavaToKotlin(fqName: FqName): ClassId? { return javaToKotlin[fqName.toUnsafe()] } - fun mapJavaToKotlin(fqName: FqName, builtIns: KotlinBuiltIns): ClassDescriptor? { - val kotlinClassId = mapJavaToKotlin(fqName) + fun mapJavaToKotlin(fqName: FqName, builtIns: KotlinBuiltIns, functionTypeArity: Int? = null): ClassDescriptor? { + val kotlinClassId = + if (functionTypeArity != null && fqName == FUNCTION_N_FQ_NAME) KotlinBuiltIns.getFunctionClassId(functionTypeArity) + else mapJavaToKotlin(fqName) return if (kotlinClassId != null) builtIns.getBuiltInClassByFqName(kotlinClassId.asSingleFqName()) else null } @@ -125,10 +134,23 @@ object JavaToKotlinClassMap : PlatformToKotlinClassMap { * kotlin.Nothing -> java.lang.Void * kotlin.IntArray -> null * kotlin.Function3 -> kotlin.jvm.functions.Function3 + * kotlin.Function42 -> kotlin.jvm.functions.FunctionN * kotlin.reflect.KFunction3 -> kotlin.reflect.KFunction + * kotlin.reflect.KFunction42 -> kotlin.reflect.KFunction */ - fun mapKotlinToJava(kotlinFqName: FqNameUnsafe): ClassId? { - return kotlinToJava[kotlinFqName] + fun mapKotlinToJava(kotlinFqName: FqNameUnsafe): ClassId? = when { + isKotlinFunctionWithBigArity(kotlinFqName, NUMBERED_FUNCTION_PREFIX) -> FUNCTION_N_CLASS_ID + isKotlinFunctionWithBigArity(kotlinFqName, NUMBERED_K_FUNCTION_PREFIX) -> K_FUNCTION_CLASS_ID + else -> kotlinToJava[kotlinFqName] + } + + private fun isKotlinFunctionWithBigArity(kotlinFqName: FqNameUnsafe, prefix: String): Boolean { + val arityString = kotlinFqName.asString().substringAfter(prefix, "") + if (arityString.isNotEmpty() && !arityString.startsWith('0')) { + val arity = arityString.toIntOrNull() + return arity != null && arity >= FunctionInvokeDescriptor.BIG_ARITY + } + return false } private fun addMapping(platformMutabilityMapping: PlatformMutabilityMapping) { diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/functions/FunctionInvokeDescriptor.kt b/core/descriptors/src/org/jetbrains/kotlin/builtins/functions/FunctionInvokeDescriptor.kt index ca490c18fd7..1f2d3491d0e 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/functions/FunctionInvokeDescriptor.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/functions/FunctionInvokeDescriptor.kt @@ -46,6 +46,18 @@ class FunctionInvokeDescriptor private constructor( this.setHasStableParameterNames(false) } + /** + * Returns true if this `invoke` has so much parameters that it makes sense to wrap them into array and make this function have a single + * `vararg Any?` parameter in the binaries, on platforms where function types are represented as separate classes (JVM, Native). + * + * For example, on JVM there are 23 function classes with the fixed number of parameters (`Function0` ... `Function22`), and another + * class representing the function with big arity, with a variable number of parameters (`FunctionN`). Whenever `invoke` of a function + * type with big arity is called, the JVM back-end wraps all arguments into an array and passes it to `FunctionN.invoke`. + */ + @get:JvmName("hasBigArity") + val hasBigArity: Boolean + get() = valueParameters.size >= BIG_ARITY + override fun doSubstitute(configuration: CopyConfiguration): FunctionDescriptor? { val substituted = super.doSubstitute(configuration) as FunctionInvokeDescriptor? ?: return null if (substituted.valueParameters.none { it.type.extractParameterNameFromFunctionTypeArgument() != null }) return substituted @@ -96,6 +108,9 @@ class FunctionInvokeDescriptor private constructor( } companion object Factory { + /** @see hasBigArity */ + const val BIG_ARITY = 23 + fun create(functionClass: FunctionClassDescriptor, isSuspend: Boolean): FunctionInvokeDescriptor { val typeParameters = functionClass.declaredTypeParameters 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 75bfaf6d5b2..1bfc25204be 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 @@ -8935,6 +8935,44 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/functions/recursiveIncrementCall.kt"); } + @TestMetadata("compiler/testData/codegen/box/functions/bigArity") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class BigArity extends AbstractIrJsCodegenBoxTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath); + } + + public void testAllFilesPresentInBigArity() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/functions/bigArity"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS_IR, true); + } + + @TestMetadata("function255.kt") + public void testFunction255() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/function255.kt"); + } + + @TestMetadata("instanceOfCallableReference.kt") + public void testInstanceOfCallableReference() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/instanceOfCallableReference.kt"); + } + + @TestMetadata("invokeCallableReference.kt") + public void testInvokeCallableReference() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/invokeCallableReference.kt"); + } + + @TestMetadata("invokeLambda.kt") + public void testInvokeLambda() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/invokeLambda.kt"); + } + + @TestMetadata("subclass.kt") + public void testSubclass() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/subclass.kt"); + } + } + @TestMetadata("compiler/testData/codegen/box/functions/functionExpression") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) @@ -14944,6 +14982,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/call"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS_IR, true); } + @TestMetadata("bigArity.kt") + public void testBigArity() throws Exception { + runTest("compiler/testData/codegen/box/reflection/call/bigArity.kt"); + } + @TestMetadata("callInstanceJavaMethod.kt") public void testCallInstanceJavaMethod() throws Exception { runTest("compiler/testData/codegen/box/reflection/call/callInstanceJavaMethod.kt"); @@ -16365,6 +16408,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/parameters"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS_IR, true); } + @TestMetadata("bigArity.kt") + public void testBigArity() throws Exception { + runTest("compiler/testData/codegen/box/reflection/parameters/bigArity.kt"); + } + @TestMetadata("boundInnerClassConstructor.kt") public void testBoundInnerClassConstructor() throws Exception { runTest("compiler/testData/codegen/box/reflection/parameters/boundInnerClassConstructor.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 e29f42d5c8b..588c3fa6704 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 @@ -9930,6 +9930,44 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/functions/recursiveIncrementCall.kt"); } + @TestMetadata("compiler/testData/codegen/box/functions/bigArity") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class BigArity extends AbstractJsCodegenBoxTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath); + } + + public void testAllFilesPresentInBigArity() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/functions/bigArity"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true); + } + + @TestMetadata("function255.kt") + public void testFunction255() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/function255.kt"); + } + + @TestMetadata("instanceOfCallableReference.kt") + public void testInstanceOfCallableReference() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/instanceOfCallableReference.kt"); + } + + @TestMetadata("invokeCallableReference.kt") + public void testInvokeCallableReference() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/invokeCallableReference.kt"); + } + + @TestMetadata("invokeLambda.kt") + public void testInvokeLambda() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/invokeLambda.kt"); + } + + @TestMetadata("subclass.kt") + public void testSubclass() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/subclass.kt"); + } + } + @TestMetadata("compiler/testData/codegen/box/functions/functionExpression") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) @@ -15939,6 +15977,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/call"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true); } + @TestMetadata("bigArity.kt") + public void testBigArity() throws Exception { + runTest("compiler/testData/codegen/box/reflection/call/bigArity.kt"); + } + @TestMetadata("callInstanceJavaMethod.kt") public void testCallInstanceJavaMethod() throws Exception { runTest("compiler/testData/codegen/box/reflection/call/callInstanceJavaMethod.kt"); @@ -17360,6 +17403,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/parameters"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true); } + @TestMetadata("bigArity.kt") + public void testBigArity() throws Exception { + runTest("compiler/testData/codegen/box/reflection/parameters/bigArity.kt"); + } + @TestMetadata("boundInnerClassConstructor.kt") public void testBoundInnerClassConstructor() throws Exception { runTest("compiler/testData/codegen/box/reflection/parameters/boundInnerClassConstructor.kt");