From adc770b60422745245c57edc88057983fa02d879 Mon Sep 17 00:00:00 2001 From: Mikhail Bogdanov Date: Tue, 5 May 2020 17:30:56 +0200 Subject: [PATCH] Process default arguments in array convention calls #KT-16520 Fixed --- .../jetbrains/kotlin/codegen/StackValue.java | 65 +++++++++++++++---- .../ir/FirBlackBoxCodegenTestGenerated.java | 15 +++++ .../convention/incWithDefaults.kt | 34 ++++++++++ .../defaultArguments/convention/kt16520.kt | 17 +++++ .../convention/plusAssignWithDefaults.kt | 34 ++++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 15 +++++ .../LightAnalysisModeTestGenerated.java | 15 +++++ .../ir/IrBlackBoxCodegenTestGenerated.java | 15 +++++ .../IrJsCodegenBoxTestGenerated.java | 15 +++++ .../semantics/JsCodegenBoxTestGenerated.java | 15 +++++ 10 files changed, 226 insertions(+), 14 deletions(-) create mode 100644 compiler/testData/codegen/box/defaultArguments/convention/incWithDefaults.kt create mode 100644 compiler/testData/codegen/box/defaultArguments/convention/kt16520.kt create mode 100644 compiler/testData/codegen/box/defaultArguments/convention/plusAssignWithDefaults.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java index 601deaa2432..e1c94c4a99c 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java @@ -15,7 +15,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.builtins.PrimitiveType; -import org.jetbrains.kotlin.builtins.UnsignedTypes; import org.jetbrains.kotlin.codegen.binding.CodegenBinding; import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt; import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods; @@ -47,6 +46,7 @@ import org.jetbrains.org.objectweb.asm.Opcodes; import org.jetbrains.org.objectweb.asm.Type; import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; +import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; @@ -1526,29 +1526,66 @@ public abstract class StackValue { coerce(topOfStackType, topOfStackKotlinType, lastParameterType, lastParameterKotlinType, v); - getCallGenerator().putValueIfNeeded( + CallGenerator callGenerator = getCallGenerator(); + callGenerator.putValueIfNeeded( new JvmKotlinType(lastParameterType, lastParameterKotlinType), StackValue.onStack(lastParameterType, lastParameterKotlinType) ); - //Convention setter couldn't have default parameters, just getter can have it at last positions - //We should remove default parameters of getter from stack*/ - //Note that it works only for non-inline case CollectionElementReceiver collectionElementReceiver = (CollectionElementReceiver) receiver; + boolean callDefault = false; if (collectionElementReceiver.isGetter) { - List arguments = collectionElementReceiver.valueArguments; - List types = getter.getValueParameterTypes(); - for (int i = arguments.size() - 1; i >= 0; i--) { - ResolvedValueArgument argument = arguments.get(i); - if (argument instanceof DefaultValueArgument) { - Type defaultType = types.get(i); - AsmUtil.swap(v, lastParameterType, defaultType); - AsmUtil.pop(v, defaultType); + //Convention setter/getter could have default parameters at the end of parameter list (in case of setter before last parameter) + //We should remove default parameters of getter from stack if they don't match setter ones and regenerate mask for setter + //Note that it works only for non-inline cases + + //TODO: try to don't generate defaults at all in CollectionElementReceiver + + List getterArguments = new ArrayList(collectionElementReceiver.valueArguments); + List getterDefaults = CollectionsKt.takeLastWhile(getterArguments, + argument -> argument instanceof DefaultValueArgument); + + List setterArguments = resolvedSetCall.getValueArgumentsByIndex(); + List setterDefaults = CollectionsKt.takeLastWhile(CollectionsKt.dropLast(setterArguments, 1), + argument -> argument instanceof DefaultValueArgument); + + if (!getterDefaults.isEmpty() || !setterDefaults.isEmpty()) { + Local rhsValue = StackValue.local(codegen.myFrameMap.enterTemp(lastParameterType), lastParameterType); + rhsValue.store(StackValue.onStack(type), v); + + List types = getter.getValueParameterTypes(); + for (int i = collectionElementReceiver.valueArguments.size() - 1; i >= 0; i--) { + ResolvedValueArgument argument = collectionElementReceiver.valueArguments.get(i); + if (argument instanceof DefaultValueArgument) { + AsmUtil.pop(v, types.get(i)); + } } + + DefaultCallArgs defaultArgs = new DefaultCallArgs( + CodegenUtilKt.unwrapFrontendVersion(resolvedSetCall.getResultingDescriptor()).getValueParameters().size()); + if (!setterDefaults.isEmpty()) { + ArgumentGenerator setterArgumentGenerator = new CallBasedArgumentGenerator( + codegen, + callGenerator, + resolvedSetCall.getResultingDescriptor().getValueParameters(), setter.getValueParameterTypes() + ); + + int defaultIndex = CollectionsKt.getLastIndex(setterArguments) - 1/*rhs value*/ - setterDefaults.size(); + for (ResolvedValueArgument aDefault : setterDefaults) { + defaultArgs.mark(++defaultIndex); + setterArgumentGenerator.generateDefault(defaultIndex, (DefaultValueArgument)aDefault); + } + callDefault = true; + } + rhsValue.put(v); + codegen.myFrameMap.leaveTemp(lastParameterType); + defaultArgs.generateOnStackIfNeeded(callGenerator, false); } + } else { + callDefault = genDefaultMaskIfPresent(callGenerator); } - getCallGenerator().genCall(setter, resolvedSetCall, false, codegen); + callGenerator.genCall(setter, resolvedSetCall, callDefault, codegen); Type returnType = setter.getReturnType(); if (returnType != Type.VOID_TYPE) { pop(v, returnType); 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 f9af889adb7..69bac62a7c7 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 @@ -8846,6 +8846,16 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/defaultArguments/convention/incWithDefaultInGetter.kt"); } + @TestMetadata("incWithDefaults.kt") + public void testIncWithDefaults() throws Exception { + runTest("compiler/testData/codegen/box/defaultArguments/convention/incWithDefaults.kt"); + } + + @TestMetadata("kt16520.kt") + public void testKt16520() throws Exception { + runTest("compiler/testData/codegen/box/defaultArguments/convention/kt16520.kt"); + } + @TestMetadata("kt9140.kt") public void testKt9140() throws Exception { runTest("compiler/testData/codegen/box/defaultArguments/convention/kt9140.kt"); @@ -8855,6 +8865,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT public void testPlusAssignWithDefaultInGetter() throws Exception { runTest("compiler/testData/codegen/box/defaultArguments/convention/plusAssignWithDefaultInGetter.kt"); } + + @TestMetadata("plusAssignWithDefaults.kt") + public void testPlusAssignWithDefaults() throws Exception { + runTest("compiler/testData/codegen/box/defaultArguments/convention/plusAssignWithDefaults.kt"); + } } @TestMetadata("compiler/testData/codegen/box/defaultArguments/function") diff --git a/compiler/testData/codegen/box/defaultArguments/convention/incWithDefaults.kt b/compiler/testData/codegen/box/defaultArguments/convention/incWithDefaults.kt new file mode 100644 index 00000000000..5c119f6742b --- /dev/null +++ b/compiler/testData/codegen/box/defaultArguments/convention/incWithDefaults.kt @@ -0,0 +1,34 @@ +// IGNORE_BACKEND_FIR: JVM_IR +var inc: String = "" + +class X { + var result: String = "fail" + + operator fun get(name: String, type: Int = 100) = name + type + + operator fun set(name: String, defaultParam: String = "_default_", value: String) { + result = name + defaultParam + value; + } +} + +class Y { + var result: String = "fail" + + operator fun get(name: String, type: String = "_default2_", type2: String = "_default1_") = name + type + type2 + + operator fun set(name: String, defaultParam: String = "_default_in_setter_", value: String) { + result = name + defaultParam + value; + } +} + +fun box(): String { + var x = X() + x["index"] += "OK" + if (x.result != "index_default_index100OK") return "fail 1: ${x.result}" + + var y = Y() + y["index"] += "OK" + if (y.result != "index_default_in_setter_index_default2__default1_OK") return "fail 2: ${y.result}" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/defaultArguments/convention/kt16520.kt b/compiler/testData/codegen/box/defaultArguments/convention/kt16520.kt new file mode 100644 index 00000000000..59dd737fa75 --- /dev/null +++ b/compiler/testData/codegen/box/defaultArguments/convention/kt16520.kt @@ -0,0 +1,17 @@ +// IGNORE_BACKEND_FIR: JVM_IR +var result = "fail" + +class A { + operator fun set( + i1: Int, + i2: Int = 1, + v: String + ) { + result = "" + i1 + i2 + v + } +} + +fun box(): String { + A()[1] = "OK" + return if (result != "11OK") "fail: $result" else "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/defaultArguments/convention/plusAssignWithDefaults.kt b/compiler/testData/codegen/box/defaultArguments/convention/plusAssignWithDefaults.kt new file mode 100644 index 00000000000..112fd471af5 --- /dev/null +++ b/compiler/testData/codegen/box/defaultArguments/convention/plusAssignWithDefaults.kt @@ -0,0 +1,34 @@ +// IGNORE_BACKEND_FIR: JVM_IR +var inc: String = "" + +class X { + var result: String = "fail" + + operator fun get(name: String, type: Int = 100) = name + type + + operator fun set(name: String, defaultParam: String = "_default_", value: String) { + result = name + defaultParam + value; + } +} + +class Y { + var result: String = "fail" + + operator fun get(name: String, type: String = "_default_", type2: Int = 2) = name + type + type2 + + operator fun set(name: String, defaultParam: String = "_default_in_setter_", value: String) { + result = name + defaultParam + value; + } +} + +fun box(): String { + var x = X() + x["index"] += "OK" + if (x.result != "index_default_index100OK") return "fail 1: ${x.result}" + + var y = Y() + y["index"] += "OK" + if (y.result != "index_default_in_setter_index_default_2OK") return "fail 2: ${y.result}" + + return "OK" +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index ea50ad73169..47043fc02d3 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -10061,6 +10061,16 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/defaultArguments/convention/incWithDefaultInGetter.kt"); } + @TestMetadata("incWithDefaults.kt") + public void testIncWithDefaults() throws Exception { + runTest("compiler/testData/codegen/box/defaultArguments/convention/incWithDefaults.kt"); + } + + @TestMetadata("kt16520.kt") + public void testKt16520() throws Exception { + runTest("compiler/testData/codegen/box/defaultArguments/convention/kt16520.kt"); + } + @TestMetadata("kt9140.kt") public void testKt9140() throws Exception { runTest("compiler/testData/codegen/box/defaultArguments/convention/kt9140.kt"); @@ -10070,6 +10080,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { public void testPlusAssignWithDefaultInGetter() throws Exception { runTest("compiler/testData/codegen/box/defaultArguments/convention/plusAssignWithDefaultInGetter.kt"); } + + @TestMetadata("plusAssignWithDefaults.kt") + public void testPlusAssignWithDefaults() throws Exception { + runTest("compiler/testData/codegen/box/defaultArguments/convention/plusAssignWithDefaults.kt"); + } } @TestMetadata("compiler/testData/codegen/box/defaultArguments/function") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 137497de04c..20ea728019d 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -10061,6 +10061,16 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/defaultArguments/convention/incWithDefaultInGetter.kt"); } + @TestMetadata("incWithDefaults.kt") + public void testIncWithDefaults() throws Exception { + runTest("compiler/testData/codegen/box/defaultArguments/convention/incWithDefaults.kt"); + } + + @TestMetadata("kt16520.kt") + public void testKt16520() throws Exception { + runTest("compiler/testData/codegen/box/defaultArguments/convention/kt16520.kt"); + } + @TestMetadata("kt9140.kt") public void testKt9140() throws Exception { runTest("compiler/testData/codegen/box/defaultArguments/convention/kt9140.kt"); @@ -10070,6 +10080,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes public void testPlusAssignWithDefaultInGetter() throws Exception { runTest("compiler/testData/codegen/box/defaultArguments/convention/plusAssignWithDefaultInGetter.kt"); } + + @TestMetadata("plusAssignWithDefaults.kt") + public void testPlusAssignWithDefaults() throws Exception { + runTest("compiler/testData/codegen/box/defaultArguments/convention/plusAssignWithDefaults.kt"); + } } @TestMetadata("compiler/testData/codegen/box/defaultArguments/function") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 7e16d706efb..55524062751 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -8846,6 +8846,16 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/defaultArguments/convention/incWithDefaultInGetter.kt"); } + @TestMetadata("incWithDefaults.kt") + public void testIncWithDefaults() throws Exception { + runTest("compiler/testData/codegen/box/defaultArguments/convention/incWithDefaults.kt"); + } + + @TestMetadata("kt16520.kt") + public void testKt16520() throws Exception { + runTest("compiler/testData/codegen/box/defaultArguments/convention/kt16520.kt"); + } + @TestMetadata("kt9140.kt") public void testKt9140() throws Exception { runTest("compiler/testData/codegen/box/defaultArguments/convention/kt9140.kt"); @@ -8855,6 +8865,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes public void testPlusAssignWithDefaultInGetter() throws Exception { runTest("compiler/testData/codegen/box/defaultArguments/convention/plusAssignWithDefaultInGetter.kt"); } + + @TestMetadata("plusAssignWithDefaults.kt") + public void testPlusAssignWithDefaults() throws Exception { + runTest("compiler/testData/codegen/box/defaultArguments/convention/plusAssignWithDefaults.kt"); + } } @TestMetadata("compiler/testData/codegen/box/defaultArguments/function") 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 ab1ddf09c44..51def9310e1 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 @@ -7511,6 +7511,16 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/defaultArguments/convention/incWithDefaultInGetter.kt"); } + @TestMetadata("incWithDefaults.kt") + public void testIncWithDefaults() throws Exception { + runTest("compiler/testData/codegen/box/defaultArguments/convention/incWithDefaults.kt"); + } + + @TestMetadata("kt16520.kt") + public void testKt16520() throws Exception { + runTest("compiler/testData/codegen/box/defaultArguments/convention/kt16520.kt"); + } + @TestMetadata("kt9140.kt") public void testKt9140() throws Exception { runTest("compiler/testData/codegen/box/defaultArguments/convention/kt9140.kt"); @@ -7520,6 +7530,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { public void testPlusAssignWithDefaultInGetter() throws Exception { runTest("compiler/testData/codegen/box/defaultArguments/convention/plusAssignWithDefaultInGetter.kt"); } + + @TestMetadata("plusAssignWithDefaults.kt") + public void testPlusAssignWithDefaults() throws Exception { + runTest("compiler/testData/codegen/box/defaultArguments/convention/plusAssignWithDefaults.kt"); + } } @TestMetadata("compiler/testData/codegen/box/defaultArguments/function") 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 67c128a06c2..25e6368646c 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 @@ -7511,6 +7511,16 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/defaultArguments/convention/incWithDefaultInGetter.kt"); } + @TestMetadata("incWithDefaults.kt") + public void testIncWithDefaults() throws Exception { + runTest("compiler/testData/codegen/box/defaultArguments/convention/incWithDefaults.kt"); + } + + @TestMetadata("kt16520.kt") + public void testKt16520() throws Exception { + runTest("compiler/testData/codegen/box/defaultArguments/convention/kt16520.kt"); + } + @TestMetadata("kt9140.kt") public void testKt9140() throws Exception { runTest("compiler/testData/codegen/box/defaultArguments/convention/kt9140.kt"); @@ -7520,6 +7530,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { public void testPlusAssignWithDefaultInGetter() throws Exception { runTest("compiler/testData/codegen/box/defaultArguments/convention/plusAssignWithDefaultInGetter.kt"); } + + @TestMetadata("plusAssignWithDefaults.kt") + public void testPlusAssignWithDefaults() throws Exception { + runTest("compiler/testData/codegen/box/defaultArguments/convention/plusAssignWithDefaults.kt"); + } } @TestMetadata("compiler/testData/codegen/box/defaultArguments/function")