Process default arguments in array convention calls

#KT-16520 Fixed
This commit is contained in:
Mikhail Bogdanov
2020-05-05 17:30:56 +02:00
parent 3134832396
commit adc770b604
10 changed files with 226 additions and 14 deletions
@@ -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<ResolvedValueArgument> arguments = collectionElementReceiver.valueArguments;
List<Type> 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<ResolvedValueArgument> getterArguments = new ArrayList(collectionElementReceiver.valueArguments);
List<ResolvedValueArgument> getterDefaults = CollectionsKt.takeLastWhile(getterArguments,
argument -> argument instanceof DefaultValueArgument);
List<ResolvedValueArgument> setterArguments = resolvedSetCall.getValueArgumentsByIndex();
List<ResolvedValueArgument> 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<Type> 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);
@@ -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")
@@ -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"
}
@@ -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"
}
@@ -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"
}
@@ -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")
@@ -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")
@@ -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")
@@ -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")
@@ -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")