From 34a64d9171d3f8993b6c92f216191de8a7430c8b Mon Sep 17 00:00:00 2001 From: Mathias Quintero Date: Sat, 14 Mar 2020 10:33:41 +0100 Subject: [PATCH] Making var arg kParameters default to empty array no argument given fixes KT-29969 --- .../ir/FirBlackBoxCodegenTestGenerated.java | 10 ++++++++ .../box/reflection/callBy/emptyVarArg.kt | 19 ++++++++++++++ .../createAnnotation/callByWithEmptyVarArg.kt | 25 +++++++++++++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 10 ++++++++ .../LightAnalysisModeTestGenerated.java | 10 ++++++++ .../ir/IrBlackBoxCodegenTestGenerated.java | 10 ++++++++ .../reflect/jvm/internal/KCallableImpl.kt | 14 +++++++++++ .../IrJsCodegenBoxTestGenerated.java | 10 ++++++++ .../semantics/JsCodegenBoxTestGenerated.java | 10 ++++++++ 9 files changed, 118 insertions(+) create mode 100644 compiler/testData/codegen/box/reflection/callBy/emptyVarArg.kt create mode 100644 compiler/testData/codegen/box/reflection/createAnnotation/callByWithEmptyVarArg.kt diff --git a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java index 5f678fb817d..0bf102bd801 100644 --- a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java @@ -22728,6 +22728,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/reflection/callBy/defaultInSuperInterface.kt"); } + @TestMetadata("emptyVarArg.kt") + public void testEmptyVarArg() throws Exception { + runTest("compiler/testData/codegen/box/reflection/callBy/emptyVarArg.kt"); + } + @TestMetadata("extensionFunction.kt") public void testExtensionFunction() throws Exception { runTest("compiler/testData/codegen/box/reflection/callBy/extensionFunction.kt"); @@ -23035,6 +23040,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/reflection/createAnnotation/callByKotlin.kt"); } + @TestMetadata("callByWithEmptyVarArg.kt") + public void testCallByWithEmptyVarArg() throws Exception { + runTest("compiler/testData/codegen/box/reflection/createAnnotation/callByWithEmptyVarArg.kt"); + } + @TestMetadata("callJava.kt") public void testCallJava() throws Exception { runTest("compiler/testData/codegen/box/reflection/createAnnotation/callJava.kt"); diff --git a/compiler/testData/codegen/box/reflection/callBy/emptyVarArg.kt b/compiler/testData/codegen/box/reflection/callBy/emptyVarArg.kt new file mode 100644 index 00000000000..5132b3783d4 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/callBy/emptyVarArg.kt @@ -0,0 +1,19 @@ +// IGNORE_BACKEND_FIR: JVM_IR +// IGNORE_BACKEND: JS_IR +// IGNORE_BACKEND: JS, NATIVE + +// WITH_REFLECT + +import kotlin.test.assertEquals + +fun join(vararg strings: String) = strings.toList().joinToString("") + +fun sum(vararg bytes: Byte) = bytes.toList().fold(0) { acc, el -> acc + el } + +fun box(): String { + val j = ::join + val s = ::sum + assertEquals("", j.callBy(emptyMap())) + assertEquals(0, s.callBy(emptyMap())) + return "OK" +} diff --git a/compiler/testData/codegen/box/reflection/createAnnotation/callByWithEmptyVarArg.kt b/compiler/testData/codegen/box/reflection/createAnnotation/callByWithEmptyVarArg.kt new file mode 100644 index 00000000000..362533bddf5 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/createAnnotation/callByWithEmptyVarArg.kt @@ -0,0 +1,25 @@ +// IGNORE_BACKEND_FIR: JVM_IR +// IGNORE_BACKEND: JS_IR +// IGNORE_BACKEND: JS, NATIVE + +// WITH_REFLECT + +import kotlin.reflect.* +import kotlin.reflect.full.* +import kotlin.test.assert + +annotation class Foo(vararg val strings: String) + +annotation class Bar(vararg val bytes: Byte) + +fun box(): String { + val fooConstructor = Foo::class.primaryConstructor!! + val foo = fooConstructor.callBy(emptyMap()) + assert(foo.strings.isEmpty()) + + val barConstructor = Bar::class.primaryConstructor!! + val bar = barConstructor.callBy(emptyMap()) + assert(bar.bytes.isEmpty()) + + return "OK" +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 29fa39ad775..3a4d1a6d2b2 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -24289,6 +24289,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/reflection/callBy/defaultInSuperInterface.kt"); } + @TestMetadata("emptyVarArg.kt") + public void testEmptyVarArg() throws Exception { + runTest("compiler/testData/codegen/box/reflection/callBy/emptyVarArg.kt"); + } + @TestMetadata("extensionFunction.kt") public void testExtensionFunction() throws Exception { runTest("compiler/testData/codegen/box/reflection/callBy/extensionFunction.kt"); @@ -24596,6 +24601,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/reflection/createAnnotation/callByKotlin.kt"); } + @TestMetadata("callByWithEmptyVarArg.kt") + public void testCallByWithEmptyVarArg() throws Exception { + runTest("compiler/testData/codegen/box/reflection/createAnnotation/callByWithEmptyVarArg.kt"); + } + @TestMetadata("callJava.kt") public void testCallJava() throws Exception { runTest("compiler/testData/codegen/box/reflection/createAnnotation/callJava.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index f523893fa34..6356dfcc9ab 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -23106,6 +23106,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/reflection/callBy/defaultInSuperInterface.kt"); } + @TestMetadata("emptyVarArg.kt") + public void testEmptyVarArg() throws Exception { + runTest("compiler/testData/codegen/box/reflection/callBy/emptyVarArg.kt"); + } + @TestMetadata("extensionFunction.kt") public void testExtensionFunction() throws Exception { runTest("compiler/testData/codegen/box/reflection/callBy/extensionFunction.kt"); @@ -23413,6 +23418,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/reflection/createAnnotation/callByKotlin.kt"); } + @TestMetadata("callByWithEmptyVarArg.kt") + public void testCallByWithEmptyVarArg() throws Exception { + runTest("compiler/testData/codegen/box/reflection/createAnnotation/callByWithEmptyVarArg.kt"); + } + @TestMetadata("callJava.kt") public void testCallJava() throws Exception { runTest("compiler/testData/codegen/box/reflection/createAnnotation/callJava.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 6da1d889624..5d74ba2c2e8 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -22728,6 +22728,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/reflection/callBy/defaultInSuperInterface.kt"); } + @TestMetadata("emptyVarArg.kt") + public void testEmptyVarArg() throws Exception { + runTest("compiler/testData/codegen/box/reflection/callBy/emptyVarArg.kt"); + } + @TestMetadata("extensionFunction.kt") public void testExtensionFunction() throws Exception { runTest("compiler/testData/codegen/box/reflection/callBy/extensionFunction.kt"); @@ -23035,6 +23040,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/reflection/createAnnotation/callByKotlin.kt"); } + @TestMetadata("callByWithEmptyVarArg.kt") + public void testCallByWithEmptyVarArg() throws Exception { + runTest("compiler/testData/codegen/box/reflection/createAnnotation/callByWithEmptyVarArg.kt"); + } + @TestMetadata("callJava.kt") public void testCallJava() throws Exception { runTest("compiler/testData/codegen/box/reflection/createAnnotation/callJava.kt"); diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt index 3359e46a96e..dc6d90e4d90 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor +import java.lang.reflect.Array as ReflectArray import java.lang.reflect.ParameterizedType import java.lang.reflect.Type import java.lang.reflect.WildcardType @@ -17,6 +18,7 @@ import kotlin.coroutines.Continuation import kotlin.reflect.* import kotlin.reflect.jvm.internal.calls.Caller import kotlin.reflect.jvm.javaType +import kotlin.reflect.jvm.jvmErasure internal abstract class KCallableImpl : KCallable { abstract val descriptor: CallableMemberDescriptor @@ -134,6 +136,9 @@ internal abstract class KCallableImpl : KCallable { mask = mask or (1 shl (index % Integer.SIZE)) anyOptional = true } + parameter.isVararg -> { + arguments.add(defaultEmptyArray(parameter.type)) + } else -> { throw IllegalArgumentException("No argument provided for a required parameter: $parameter") } @@ -174,6 +179,7 @@ internal abstract class KCallableImpl : KCallable { args[parameter] ?: throw IllegalArgumentException("Annotation argument value cannot be null ($parameter)") } parameter.isOptional -> null + parameter.isVararg -> defaultEmptyArray(parameter.type) else -> throw IllegalArgumentException("No argument provided for a required parameter: $parameter") } } @@ -202,6 +208,14 @@ internal abstract class KCallableImpl : KCallable { } } else null + private fun defaultEmptyArray(type: KType): Any = + type.jvmErasure.java.run { + if (isArray) ReflectArray.newInstance(componentType, 0) + else throw KotlinReflectionInternalError( + "Cannot instantiate the default empty array of type $simpleName, because it is not an array type" + ) + } + private fun extractContinuationArgument(): Type? { if ((descriptor as? FunctionDescriptor)?.isSuspend == true) { // kotlin.coroutines.Continuation diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java index 88c809cca2e..be488eaf2be 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java @@ -19299,6 +19299,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/reflection/callBy/defaultInSuperInterface.kt"); } + @TestMetadata("emptyVarArg.kt") + public void testEmptyVarArg() throws Exception { + runTest("compiler/testData/codegen/box/reflection/callBy/emptyVarArg.kt"); + } + @TestMetadata("extensionFunction.kt") public void testExtensionFunction() throws Exception { runTest("compiler/testData/codegen/box/reflection/callBy/extensionFunction.kt"); @@ -19496,6 +19501,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/reflection/createAnnotation/arrayOfKClasses.kt"); } + @TestMetadata("callByWithEmptyVarArg.kt") + public void testCallByWithEmptyVarArg() throws Exception { + runTest("compiler/testData/codegen/box/reflection/createAnnotation/callByWithEmptyVarArg.kt"); + } + @TestMetadata("enumKClassAnnotation.kt") public void testEnumKClassAnnotation() throws Exception { runTest("compiler/testData/codegen/box/reflection/createAnnotation/enumKClassAnnotation.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 5d908dfca14..2417b924968 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 @@ -19359,6 +19359,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/reflection/callBy/defaultInSuperInterface.kt"); } + @TestMetadata("emptyVarArg.kt") + public void testEmptyVarArg() throws Exception { + runTest("compiler/testData/codegen/box/reflection/callBy/emptyVarArg.kt"); + } + @TestMetadata("extensionFunction.kt") public void testExtensionFunction() throws Exception { runTest("compiler/testData/codegen/box/reflection/callBy/extensionFunction.kt"); @@ -19556,6 +19561,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/reflection/createAnnotation/arrayOfKClasses.kt"); } + @TestMetadata("callByWithEmptyVarArg.kt") + public void testCallByWithEmptyVarArg() throws Exception { + runTest("compiler/testData/codegen/box/reflection/createAnnotation/callByWithEmptyVarArg.kt"); + } + @TestMetadata("enumKClassAnnotation.kt") public void testEnumKClassAnnotation() throws Exception { runTest("compiler/testData/codegen/box/reflection/createAnnotation/enumKClassAnnotation.kt");