diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/CallBasedArgumentGenerator.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/CallBasedArgumentGenerator.java index fd98bddc99b..33e4fbe421d 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/CallBasedArgumentGenerator.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/CallBasedArgumentGenerator.java @@ -64,7 +64,7 @@ public class CallBasedArgumentGenerator extends ArgumentGenerator { @Override protected void generateDefault(int i, @NotNull DefaultValueArgument argument) { - callGenerator.putValueIfNeeded(valueParameterTypes.get(i), createDefaulValue(valueParameterTypes.get(i)), ValueKind.DEFAULT_PARAMETER); + callGenerator.putValueIfNeeded(valueParameterTypes.get(i), createDefaulValue(valueParameterTypes.get(i)), ValueKind.DEFAULT_PARAMETER, i); } @Override @@ -73,7 +73,7 @@ public class CallBasedArgumentGenerator extends ArgumentGenerator { // Upper bound for type of vararg parameter should always have a form of 'Array', // while its lower bound may be Nothing-typed after approximation StackValue lazyVararg = codegen.genVarargs(argument, FlexibleTypesKt.upperIfFlexible(parameter.getType())); - callGenerator.putValueIfNeeded(valueParameterTypes.get(i), lazyVararg); + callGenerator.putValueIfNeeded(valueParameterTypes.get(i), lazyVararg, ValueKind.GENERAL_VARARG, 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 49cd0e8569a..50453f6e1bc 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/CallGenerator.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/CallGenerator.kt @@ -23,10 +23,11 @@ import org.jetbrains.org.objectweb.asm.Type enum class ValueKind { GENERAL, + GENERAL_VARARG, DEFAULT_PARAMETER, DEFAULT_MASK, METHOD_HANDLE_IN_DEFAULT, - CAPTURED + CAPTURED, } abstract class CallGenerator { @@ -68,7 +69,7 @@ abstract class CallGenerator { stackValue.put(stackValue.type, codegen.v) } - override fun putValueIfNeeded(parameterType: Type, value: StackValue, kind: ValueKind) { + override fun putValueIfNeeded(parameterType: Type, value: StackValue, kind: ValueKind, parameterIndex: Int) { value.put(value.type, codegen.v) } @@ -121,7 +122,8 @@ abstract class CallGenerator { abstract fun putValueIfNeeded( parameterType: Type, value: StackValue, - kind: ValueKind) + kind: ValueKind = ValueKind.GENERAL, + parameterIndex: Int = -1) abstract fun putCapturedValueOnStack( stackValue: StackValue, diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java index 1c64b85d7fe..8469a00f802 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java @@ -904,7 +904,7 @@ public class InlineCodegen extends CallGenerator { } else { StackValue value = codegen.gen(argumentExpression); - putValueIfNeeded(parameterType, value, valueParameterDescriptor.getIndex(), ValueKind.GENERAL); + putValueIfNeeded(parameterType, value, ValueKind.GENERAL, valueParameterDescriptor.getIndex()); } } @@ -923,16 +923,12 @@ public class InlineCodegen extends CallGenerator { } @Override - public void putValueIfNeeded(@NotNull Type parameterType, @NotNull StackValue value, @NotNull ValueKind kind) { - putValueIfNeeded(parameterType, value, -1, kind); - } - - private void putValueIfNeeded(@NotNull Type parameterType, @NotNull StackValue value, int index, @NotNull ValueKind kind) { + public void putValueIfNeeded(@NotNull Type parameterType, @NotNull StackValue value, @NotNull ValueKind kind, int parameterIndex) { if (processDefaultMaskOrMethodHandler(value, kind)) return; assert maskValues.isEmpty() : "Additional default call arguments should be last ones, but " + value; - putArgumentOrCapturedToLocalVal(parameterType, value, -1, index, kind); + putArgumentOrCapturedToLocalVal(parameterType, value, -1, parameterIndex, kind); } private boolean processDefaultMaskOrMethodHandler(@NotNull StackValue value, @NotNull ValueKind kind) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenForDefaultBody.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenForDefaultBody.kt index db4f362a8f2..dd4f9e09007 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenForDefaultBody.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenForDefaultBody.kt @@ -91,7 +91,7 @@ class InlineCodegenForDefaultBody( throw UnsupportedOperationException("Shouldn't be called") } - override fun putValueIfNeeded(parameterType: Type, value: StackValue, kind: ValueKind) { + override fun putValueIfNeeded(parameterType: Type, value: StackValue, kind: ValueKind, parameterIndex: Int) { //original method would be inlined directly into default impl body without any inline magic //so we no need to load variables on stack to further method call } diff --git a/compiler/testData/codegen/boxInline/argumentOrder/defaultParametersAndLastVararg.kt b/compiler/testData/codegen/boxInline/argumentOrder/defaultParametersAndLastVararg.kt new file mode 100644 index 00000000000..0cd491e95c6 --- /dev/null +++ b/compiler/testData/codegen/boxInline/argumentOrder/defaultParametersAndLastVararg.kt @@ -0,0 +1,54 @@ +// NO_CHECK_LAMBDA_INLINING +// FILE: 1.kt +// WITH_RUNTIME +package test + +open class A(val value: String) + +var invokeOrder = "" + +inline fun inlineFun( + receiver: String = { invokeOrder += " default receiver"; "DEFAULT" }(), + init: String, + vararg constraints: A +): String { + return constraints.map { it.value }.joinToString() + ", " + receiver + ", " + init +} + +// FILE: 2.kt +import test.* + + +var result = "" +fun box(): String { + + result = "" + invokeOrder = "" + result = inlineFun(constraints = { invokeOrder += "constraints";A("C") }(), + receiver = { invokeOrder += " receiver"; "R" }(), + init = { invokeOrder += " init"; "I" }()) + if (result != "C, R, I") return "fail 1: $result" + + //Change test after KT-17691 FIX + if (invokeOrder != " receiver initconstraints") return "fail 2: $invokeOrder" + + result = "" + invokeOrder = "" + result = inlineFun(init = { invokeOrder += "init"; "I" }(), + constraints = { invokeOrder += "constraints";A("C") }(), + receiver = { invokeOrder += " receiver"; "R" }() + ) + if (result != "C, R, I") return "fail 3: $result" + //Change test after KT-17691 FIX + if (invokeOrder != "init receiverconstraints") return "fail 4: $invokeOrder" + + result = "" + invokeOrder = "" + result = inlineFun(init = { invokeOrder += "init"; "I" }(), + constraints = { invokeOrder += " constraints";A("C") }()) + if (result != "C, DEFAULT, I") return "fail 5: $result" + if (invokeOrder != "init constraints default receiver") return "fail 6: $invokeOrder" + + return "OK" +} + diff --git a/compiler/testData/codegen/boxInline/argumentOrder/varargAndDefaultParameters.kt b/compiler/testData/codegen/boxInline/argumentOrder/varargAndDefaultParameters.kt new file mode 100644 index 00000000000..6bff7d61719 --- /dev/null +++ b/compiler/testData/codegen/boxInline/argumentOrder/varargAndDefaultParameters.kt @@ -0,0 +1,54 @@ +// NO_CHECK_LAMBDA_INLINING +// FILE: 1.kt +// WITH_RUNTIME +package test + +open class A(val value: String) + +var invokeOrder = "" + +inline fun inlineFun( + vararg constraints: A, + receiver: String = { invokeOrder += " default receiver"; "DEFAULT" }(), + init: String +): String { + return constraints.map { it.value }.joinToString() + ", " + receiver + ", " + init +} + +// FILE: 2.kt +import test.* + + +var result = "" +fun box(): String { + + result = "" + invokeOrder = "" + result = inlineFun(constraints = { invokeOrder += "constraints";A("C") }(), + receiver = { invokeOrder += " receiver"; "R" }(), + init = { invokeOrder += " init"; "I" }()) + if (result != "C, R, I") return "fail 1: $result" + + //Change test after KT-17691 FIX + if (invokeOrder != " receiver initconstraints") return "fail 2: $invokeOrder" + + result = "" + invokeOrder = "" + result = inlineFun(init = { invokeOrder += "init"; "I" }(), + constraints = { invokeOrder += "constraints";A("C") }(), + receiver = { invokeOrder += " receiver"; "R" }() + ) + if (result != "C, R, I") return "fail 3: $result" + //Change test after KT-17691 FIX + if (invokeOrder != "init receiverconstraints") return "fail 4: $invokeOrder" + + result = "" + invokeOrder = "" + result = inlineFun(init = { invokeOrder += "init"; "I" }(), + constraints = { invokeOrder += " constraints";A("C") }()) + if (result != "C, DEFAULT, I") return "fail 5: $result" + if (invokeOrder != "init constraints default receiver") return "fail 6: $invokeOrder" + + return "OK" +} + diff --git a/compiler/testData/codegen/boxInline/varargs/kt17653.kt b/compiler/testData/codegen/boxInline/varargs/kt17653.kt new file mode 100644 index 00000000000..c5b4c61339e --- /dev/null +++ b/compiler/testData/codegen/boxInline/varargs/kt17653.kt @@ -0,0 +1,18 @@ +// FILE: 1.kt + +package test + +inline fun inlineFun(vararg constraints: String, init: String.() -> String): String { + return "O".init() +} + +// FILE: 2.kt + +import test.* + +fun box(): String { + return inlineFun { + this + "K" + } +} + diff --git a/compiler/testData/codegen/boxInline/varargs/varargAndDefaultParameters.kt b/compiler/testData/codegen/boxInline/varargs/varargAndDefaultParameters.kt new file mode 100644 index 00000000000..4e4f5cbd8df --- /dev/null +++ b/compiler/testData/codegen/boxInline/varargs/varargAndDefaultParameters.kt @@ -0,0 +1,18 @@ +// FILE: 1.kt + +package test + +inline fun inlineFun(vararg constraints: String, receiver: String = "O", init: String.() -> String): String { + return receiver.init() +} + +// FILE: 2.kt + +import test.* + +fun box(): String { + return inlineFun { + this + "K" + } +} + diff --git a/compiler/testData/codegen/boxInline/varargs/varargAndDefaultParameters2.kt b/compiler/testData/codegen/boxInline/varargs/varargAndDefaultParameters2.kt new file mode 100644 index 00000000000..3dc7ee6f693 --- /dev/null +++ b/compiler/testData/codegen/boxInline/varargs/varargAndDefaultParameters2.kt @@ -0,0 +1,18 @@ +// FILE: 1.kt +// WITH_RUNTIME + +package test +inline fun inlineFun(vararg constraints: String, receiver: String = "K", init: String.() -> String): String { + return (constraints.joinToString() + receiver).init() +} + +// FILE: 2.kt + +import test.* + +fun box(): String { + return inlineFun("O") { + this + } +} + diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java index 232ed6b5295..f658ee90f3b 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java @@ -461,6 +461,12 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo doTest(fileName); } + @TestMetadata("defaultParametersAndLastVararg.kt") + public void testDefaultParametersAndLastVararg() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/argumentOrder/defaultParametersAndLastVararg.kt"); + doTest(fileName); + } + @TestMetadata("extension.kt") public void testExtension() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/argumentOrder/extension.kt"); @@ -496,6 +502,12 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/argumentOrder/simpleInClass.kt"); doTest(fileName); } + + @TestMetadata("varargAndDefaultParameters.kt") + public void testVarargAndDefaultParameters() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/argumentOrder/varargAndDefaultParameters.kt"); + doTest(fileName); + } } @TestMetadata("compiler/testData/codegen/boxInline/arrayConvention") @@ -2732,4 +2744,31 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo doTest(fileName); } } + + @TestMetadata("compiler/testData/codegen/boxInline/varargs") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Varargs extends AbstractBlackBoxInlineCodegenTest { + public void testAllFilesPresentInVarargs() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/varargs"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("kt17653.kt") + public void testKt17653() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/varargs/kt17653.kt"); + doTest(fileName); + } + + @TestMetadata("varargAndDefaultParameters.kt") + public void testVarargAndDefaultParameters() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/varargs/varargAndDefaultParameters.kt"); + doTest(fileName); + } + + @TestMetadata("varargAndDefaultParameters2.kt") + public void testVarargAndDefaultParameters2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/varargs/varargAndDefaultParameters2.kt"); + doTest(fileName); + } + } } diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java index 956548d90f5..769da40f02f 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java @@ -461,6 +461,12 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi doTest(fileName); } + @TestMetadata("defaultParametersAndLastVararg.kt") + public void testDefaultParametersAndLastVararg() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/argumentOrder/defaultParametersAndLastVararg.kt"); + doTest(fileName); + } + @TestMetadata("extension.kt") public void testExtension() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/argumentOrder/extension.kt"); @@ -496,6 +502,12 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/argumentOrder/simpleInClass.kt"); doTest(fileName); } + + @TestMetadata("varargAndDefaultParameters.kt") + public void testVarargAndDefaultParameters() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/argumentOrder/varargAndDefaultParameters.kt"); + doTest(fileName); + } } @TestMetadata("compiler/testData/codegen/boxInline/arrayConvention") @@ -2732,4 +2744,31 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi doTest(fileName); } } + + @TestMetadata("compiler/testData/codegen/boxInline/varargs") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Varargs extends AbstractCompileKotlinAgainstInlineKotlinTest { + public void testAllFilesPresentInVarargs() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/varargs"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("kt17653.kt") + public void testKt17653() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/varargs/kt17653.kt"); + doTest(fileName); + } + + @TestMetadata("varargAndDefaultParameters.kt") + public void testVarargAndDefaultParameters() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/varargs/varargAndDefaultParameters.kt"); + doTest(fileName); + } + + @TestMetadata("varargAndDefaultParameters2.kt") + public void testVarargAndDefaultParameters2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/varargs/varargAndDefaultParameters2.kt"); + doTest(fileName); + } + } }