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:
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
+16
@@ -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"
|
||||
}
|
||||
+9
@@ -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*/
|
||||
}
|
||||
+19
@@ -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"
|
||||
}
|
||||
+12
@@ -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*/
|
||||
}
|
||||
}
|
||||
+16
@@ -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"
|
||||
}
|
||||
+9
@@ -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
|
||||
}
|
||||
+19
@@ -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"
|
||||
}
|
||||
+13
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
+45
@@ -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)
|
||||
|
||||
+45
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user