Supported inline of array convention simple cases; Fix for KT-9211: M13 an extension function that is inline, and for get(v) causes an exception when called using brackets

#KT-9211 Fixed
This commit is contained in:
Michael Bogdanov
2016-01-18 14:59:43 +03:00
parent 84dbdf2ccb
commit 23480a5698
17 changed files with 303 additions and 15 deletions
@@ -2443,7 +2443,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
}
@NotNull
private CallGenerator getOrCreateCallGenerator(@NotNull ResolvedCall<?> resolvedCall) {
CallGenerator getOrCreateCallGenerator(@NotNull ResolvedCall<?> resolvedCall) {
Map<TypeParameterDescriptor, KotlinType> typeArguments = resolvedCall.getTypeArguments();
TypeParameterMappings mappings = new TypeParameterMappings();
for (Map.Entry<TypeParameterDescriptor, KotlinType> entry : typeArguments.entrySet()) {
@@ -3476,10 +3476,6 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
ResolvedCall<FunctionDescriptor> resolvedCall = isGetter ? resolvedGetCall : resolvedSetCall;
assert resolvedCall != null : "couldn't find resolved call: " + expression.getText();
ArgumentGenerator argumentGenerator = new CallBasedArgumentGenerator(
this, defaultCallGenerator, resolvedCall.getResultingDescriptor().getValueParameters(), callable.getValueParameterTypes()
);
List<ResolvedValueArgument> valueArguments = resolvedCall.getValueArgumentsByIndex();
assert valueArguments != null : "Failed to arrange value arguments by index: " + operationDescriptor;
@@ -3490,7 +3486,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
}
return new StackValue.CollectionElementReceiver(
callable, receiver, resolvedGetCall, resolvedSetCall, isGetter, this, argumentGenerator, valueArguments
callable, receiver, resolvedGetCall, resolvedSetCall, isGetter, this, valueArguments
);
}
@@ -47,7 +47,7 @@ public class FrameMap {
myVarSizes.remove(descriptor);
int oldIndex = myVarIndex.remove(descriptor);
if (oldIndex != myMaxIndex) {
throw new IllegalStateException("descriptor can be left only if it is last");
throw new IllegalStateException("Descriptor can be left only if it is last: " + descriptor);
}
return oldIndex;
}
@@ -17,8 +17,9 @@
package org.jetbrains.kotlin.codegen;
import com.intellij.psi.tree.IElementType;
import kotlin.collections.ArraysKt;
import kotlin.Unit;
import kotlin.collections.ArraysKt;
import kotlin.collections.CollectionsKt;
import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
@@ -768,13 +769,14 @@ public abstract class StackValue {
private final Callable callable;
private final boolean isGetter;
private final ExpressionCodegen codegen;
private final ArgumentGenerator argumentGenerator;
private final List<ResolvedValueArgument> valueArguments;
private final FrameMap frame;
private final StackValue receiver;
private final ResolvedCall<FunctionDescriptor> resolvedGetCall;
private final ResolvedCall<FunctionDescriptor> resolvedSetCall;
private DefaultCallMask mask;
private CallGenerator callGenerator;
boolean isComplexOperationWithDup;
public CollectionElementReceiver(
@NotNull Callable callable,
@@ -783,7 +785,6 @@ public abstract class StackValue {
ResolvedCall<FunctionDescriptor> resolvedSetCall,
boolean isGetter,
@NotNull ExpressionCodegen codegen,
ArgumentGenerator argumentGenerator,
List<ResolvedValueArgument> valueArguments
) {
super(OBJECT_TYPE);
@@ -793,7 +794,6 @@ public abstract class StackValue {
this.receiver = receiver;
this.resolvedGetCall = resolvedGetCall;
this.resolvedSetCall = resolvedSetCall;
this.argumentGenerator = argumentGenerator;
this.valueArguments = valueArguments;
this.codegen = codegen;
this.frame = codegen.myFrameMap;
@@ -803,8 +803,25 @@ public abstract class StackValue {
public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
ResolvedCall<?> call = isGetter ? resolvedGetCall : resolvedSetCall;
StackValue newReceiver = StackValue.receiver(call, receiver, codegen, callable);
ArgumentGenerator generator = createArgumentGenerator();
newReceiver.put(newReceiver.type, v);
mask = argumentGenerator.generate(valueArguments, valueArguments);
callGenerator.putHiddenParams();
mask = generator.generate(valueArguments, valueArguments);
}
private ArgumentGenerator createArgumentGenerator() {
assert callGenerator == null :
"'putSelector' and 'createArgumentGenerator' methods should be called once for CollectionElementReceiver: " + callable;
ResolvedCall<FunctionDescriptor> resolvedCall = isGetter ? resolvedGetCall : resolvedSetCall;
assert resolvedCall != null : "Resolved call should be non-null: " + callable;
callGenerator =
!isComplexOperationWithDup ? codegen.getOrCreateCallGenerator(resolvedCall) : codegen.defaultCallGenerator;
return new CallBasedArgumentGenerator(
codegen,
callGenerator,
resolvedCall.getResultingDescriptor().getValueParameters(), callable.getValueParameterTypes()
);
}
@Override
@@ -932,7 +949,7 @@ public abstract class StackValue {
if (getter == null) {
throw new UnsupportedOperationException("no getter specified");
}
CallGenerator callGenerator = codegen.defaultCallGenerator;
CallGenerator callGenerator = getCallGenerator();
callGenerator.genCall(getter, resolvedGetCall, genDefaultMaskIfPresent(callGenerator), codegen);
coerceTo(type, v);
}
@@ -942,6 +959,14 @@ public abstract class StackValue {
return mask.generateOnStackIfNeeded(callGenerator);
}
private CallGenerator getCallGenerator() {
CallGenerator generator = ((CollectionElementReceiver) receiver).callGenerator;
assert generator != null :
"CollectionElementReceiver should be putted on stack before CollectionElement:" +
" getCall = " + resolvedGetCall + ", setCall = " + resolvedSetCall;
return generator;
}
@Override
public int receiverSize() {
if (isStandardStack(codegen.typeMapper, resolvedGetCall, 1) && isStandardStack(codegen.typeMapper, resolvedSetCall, 2)) {
@@ -991,8 +1016,13 @@ public abstract class StackValue {
Type lastParameterType = ArraysKt.last(setter.getParameterTypes());
coerce(topOfStackType, lastParameterType, v);
//*Convention setter couldn't have default parameters, just getter can have it at last positions
getCallGenerator().afterParameterPut(lastParameterType, StackValue.onStack(lastParameterType),
CollectionsKt.getLastIndex(setter.getValueParameterTypes()));
//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;
if (collectionElementReceiver.isGetter) {
List<ResolvedValueArgument> arguments = collectionElementReceiver.valueArguments;
@@ -1007,7 +1037,7 @@ public abstract class StackValue {
}
}
codegen.defaultCallGenerator.genCall(setter, resolvedSetCall, false, codegen);
getCallGenerator().genCall(setter, resolvedSetCall, false, codegen);
Type returnType = setter.getReturnType();
if (returnType != Type.VOID_TYPE) {
pop(v, returnType);
@@ -1529,6 +1559,11 @@ public abstract class StackValue {
super(value.type, value.receiver.canHaveSideEffects());
this.originalValueWithReceiver = value;
this.isReadOperations = isReadOperations;
if (value instanceof CollectionElement) {
if (value.receiver instanceof CollectionElementReceiver) {
((CollectionElementReceiver) value.receiver).isComplexOperationWithDup = true;
}
}
}
@Override
@@ -0,0 +1,15 @@
import test.*
fun box(): String {
val z = 1;
val p = z[2, 3]
if (p != 6) return "fail 1: $p"
z[2, 3] = p
if (res != 12) return "fail 2: $res"
return "OK"
}
@@ -0,0 +1,9 @@
package test
var res = 1
inline operator fun Int.get(z: Int, p: Int) = this + z + p
inline operator fun Int.set(z: Int, p: Int, l: Int) {
res = this + z + p + l
}
@@ -0,0 +1,17 @@
import test.*
fun box(): String {
with(A()) {
val z = 1;
val p = z[2, 3]
if (p != 6) return "fail 1: $p"
z[2, 3] = p
if (res != 12) return "fail 2: $res"
}
return "OK"
}
@@ -0,0 +1,13 @@
package test
var res = 1
class A {
inline operator fun Int.get(z: Int, p: Int) = this + z + p
inline operator fun Int.set(z: Int, p: Int, l: Int) {
res = this + z + p + l
}
}
@@ -0,0 +1,16 @@
import test.*
fun box(): String {
val z = 1;
val p = z[2, { 3 }]
if (p != 106) return "fail 1: $p"
val captured = 3;
z[2, { captured } ] = p
if (res != 112) return "fail 2: $res"
return "OK"
}
@@ -0,0 +1,9 @@
package test
var res = 1
inline operator fun Int.get(z: Int, p: () -> Int, defaultt: Int = 100) = this + z + p() + defaultt
inline operator fun Int.set(z: Int, p: () -> Int, l: Int/*, x : Int = 1000*/) {
res = this + z + p() + l /*+ x*/
}
@@ -0,0 +1,19 @@
import test.*
fun box(): String {
val z = 1;
with(A()) {
val p = z[2, { 3 }]
if (p != 106) return "fail 1: $p"
val captured = 3;
z[2, { captured }] = p
if (res != 112) return "fail 2: $res"
}
return "OK"
}
@@ -0,0 +1,12 @@
package test
var res = 1
class A {
inline operator fun Int.get(z: Int, p: () -> Int, defaultt: Int = 100) = this + z + p() + defaultt
inline operator fun Int.set(z: Int, p: () -> Int, l: Int/*, x : Int = 1000*/) {
res = this + z + p() + l /*+ x*/
}
}
@@ -0,0 +1,16 @@
import test.*
fun box(): String {
val z = 1;
val p = z[2, { 3 }]
if (p != 6) return "fail 1: $p"
val captured = 3;
z[2, { captured } ] = p
if (res != 12) return "fail 2: $res"
return "OK"
}
@@ -0,0 +1,9 @@
package test
var res = 1
inline operator fun Int.get(z: Int, p: () -> Int) = this + z + p()
inline operator fun Int.set(z: Int, p: () -> Int, l: Int) {
res = this + z + p() + l
}
@@ -0,0 +1,19 @@
import test.*
fun box(): String {
val z = 1;
with(A()) {
val p = z[2, { 3 }]
if (p != 6) return "fail 1: $p"
val captured = 3;
z[2, { captured }] = p
if (res != 12) return "fail 2: $res"
}
return "OK"
}
@@ -0,0 +1,13 @@
package test
var res = 1
class A {
inline operator fun Int.get(z: Int, p: () -> Int) = this + z + p()
inline operator fun Int.set(z: Int, p: () -> Int, l: Int) {
res = this + z + p() + l
}
}
@@ -386,6 +386,51 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
}
}
@TestMetadata("compiler/testData/codegen/boxInline/arrayConvention")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class ArrayConvention extends AbstractBlackBoxInlineCodegenTest {
public void testAllFilesPresentInArrayConvention() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/arrayConvention"), Pattern.compile("^(.+)\\.1.kt$"), true);
}
@TestMetadata("simpleAccess.1.kt")
public void testSimpleAccess() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/arrayConvention/simpleAccess.1.kt");
doTestMultiFileWithInlineCheck(fileName);
}
@TestMetadata("simpleAccessInClass.1.kt")
public void testSimpleAccessInClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/arrayConvention/simpleAccessInClass.1.kt");
doTestMultiFileWithInlineCheck(fileName);
}
@TestMetadata("simpleAccessWithDefault.1.kt")
public void testSimpleAccessWithDefault() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/arrayConvention/simpleAccessWithDefault.1.kt");
doTestMultiFileWithInlineCheck(fileName);
}
@TestMetadata("simpleAccessWithDefaultInClass.1.kt")
public void testSimpleAccessWithDefaultInClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/arrayConvention/simpleAccessWithDefaultInClass.1.kt");
doTestMultiFileWithInlineCheck(fileName);
}
@TestMetadata("simpleAccessWithLambda.1.kt")
public void testSimpleAccessWithLambda() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/arrayConvention/simpleAccessWithLambda.1.kt");
doTestMultiFileWithInlineCheck(fileName);
}
@TestMetadata("simpleAccessWithLambdaInClass.1.kt")
public void testSimpleAccessWithLambdaInClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/arrayConvention/simpleAccessWithLambdaInClass.1.kt");
doTestMultiFileWithInlineCheck(fileName);
}
}
@TestMetadata("compiler/testData/codegen/boxInline/builders")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -386,6 +386,51 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
}
}
@TestMetadata("compiler/testData/codegen/boxInline/arrayConvention")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class ArrayConvention extends AbstractCompileKotlinAgainstInlineKotlinTest {
public void testAllFilesPresentInArrayConvention() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/arrayConvention"), Pattern.compile("^(.+)\\.1.kt$"), true);
}
@TestMetadata("simpleAccess.1.kt")
public void testSimpleAccess() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/arrayConvention/simpleAccess.1.kt");
doBoxTestWithInlineCheck(fileName);
}
@TestMetadata("simpleAccessInClass.1.kt")
public void testSimpleAccessInClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/arrayConvention/simpleAccessInClass.1.kt");
doBoxTestWithInlineCheck(fileName);
}
@TestMetadata("simpleAccessWithDefault.1.kt")
public void testSimpleAccessWithDefault() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/arrayConvention/simpleAccessWithDefault.1.kt");
doBoxTestWithInlineCheck(fileName);
}
@TestMetadata("simpleAccessWithDefaultInClass.1.kt")
public void testSimpleAccessWithDefaultInClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/arrayConvention/simpleAccessWithDefaultInClass.1.kt");
doBoxTestWithInlineCheck(fileName);
}
@TestMetadata("simpleAccessWithLambda.1.kt")
public void testSimpleAccessWithLambda() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/arrayConvention/simpleAccessWithLambda.1.kt");
doBoxTestWithInlineCheck(fileName);
}
@TestMetadata("simpleAccessWithLambdaInClass.1.kt")
public void testSimpleAccessWithLambdaInClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/arrayConvention/simpleAccessWithLambdaInClass.1.kt");
doBoxTestWithInlineCheck(fileName);
}
}
@TestMetadata("compiler/testData/codegen/boxInline/builders")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)