Support inline classes working with collection elements (get/set)

This commit is contained in:
Mikhail Zarechenskiy
2018-02-07 15:39:21 +03:00
parent 8015295059
commit 059f1e9eed
9 changed files with 104 additions and 6 deletions
@@ -4050,9 +4050,11 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
List<KtExpression> indices = expression.getIndexExpressions();
FunctionDescriptor operationDescriptor = (FunctionDescriptor) bindingContext.get(REFERENCE_TARGET, expression);
assert operationDescriptor != null;
boolean isInlineClassType = type != null && InlineClassesUtilsKt.isInlineClassType(type);
if (arrayType.getSort() == Type.ARRAY &&
indices.size() == 1 &&
isInt(operationDescriptor.getValueParameters().get(0).getType())) {
isInt(operationDescriptor.getValueParameters().get(0).getType()) &&
!isInlineClassType) {
assert type != null;
Type elementType;
if (KotlinBuiltIns.isArray(type)) {
@@ -4084,7 +4086,12 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
);
Type elementType = isGetter ? callableMethod.getReturnType() : ArrayUtil.getLastElement(argumentTypes);
return StackValue.collectionElement(collectionElementReceiver, elementType, resolvedGetCall, resolvedSetCall, this);
KotlinType elementKotlinType = isGetter ?
operationDescriptor.getReturnType() :
CollectionsKt.last(operationDescriptor.getValueParameters()).getType();
return StackValue.collectionElement(
collectionElementReceiver, elementType, elementKotlinType, resolvedGetCall, resolvedSetCall, this
);
}
}
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.codegen;
import com.intellij.psi.tree.IElementType;
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;
@@ -282,11 +283,12 @@ public abstract class StackValue {
public static StackValue collectionElement(
CollectionElementReceiver collectionElementReceiver,
Type type,
KotlinType kotlinType,
ResolvedCall<FunctionDescriptor> getter,
ResolvedCall<FunctionDescriptor> setter,
ExpressionCodegen codegen
) {
return new CollectionElement(collectionElementReceiver, type, getter, setter, codegen);
return new CollectionElement(collectionElementReceiver, type, kotlinType, getter, setter, codegen);
}
@NotNull
@@ -1167,11 +1169,12 @@ public abstract class StackValue {
public CollectionElement(
@NotNull CollectionElementReceiver collectionElementReceiver,
@NotNull Type type,
@Nullable KotlinType kotlinType,
@Nullable ResolvedCall<FunctionDescriptor> resolvedGetCall,
@Nullable ResolvedCall<FunctionDescriptor> resolvedSetCall,
@NotNull ExpressionCodegen codegen
) {
super(type, null, false, false, collectionElementReceiver, true);
super(type, kotlinType, false, false, collectionElementReceiver, true);
this.resolvedGetCall = resolvedGetCall;
this.resolvedSetCall = resolvedSetCall;
this.setter = resolvedSetCall == null ? null :
@@ -1246,13 +1249,16 @@ public abstract class StackValue {
}
@Override
public void storeSelector(@NotNull Type topOfStackType, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v) {
public void storeSelector(@NotNull Type topOfStackType, @Nullable KotlinType topOfStackKotlinType, @NotNull InstructionAdapter v) {
if (setter == null) {
throw new UnsupportedOperationException("no setter specified");
}
Type lastParameterType = ArraysKt.last(setter.getParameterTypes());
coerce(topOfStackType, lastParameterType, v);
KotlinType lastParameterKotlinType =
CollectionsKt.last(resolvedSetCall.getResultingDescriptor().getValueParameters()).getType();
coerce(topOfStackType, topOfStackKotlinType, lastParameterType, lastParameterKotlinType, v);
getCallGenerator().putValueIfNeeded(lastParameterType, StackValue.onStack(lastParameterType));
@@ -0,0 +1,32 @@
// !LANGUAGE: +InlineClasses
inline class UInt(private val value: Int) {
fun asInt() = value
}
inline class UIntArray(private val intArray: IntArray) {
operator fun get(index: Int): UInt = UInt(intArray[index])
operator fun set(index: Int, value: UInt) {
intArray[index] = value.asInt()
}
}
fun UIntArray.swap(i: Int, j: Int) {
this[j] = this[i].also { this[i] = this[j] }
}
fun uIntArrayOf(vararg elements: Int) = UIntArray(intArrayOf(*elements))
fun box(): String {
val a = uIntArrayOf(1, 2, 3, 4)
a.swap(0, 3)
a.swap(1, 2)
if (a[0].asInt() != 4) return "fail"
if (a[1].asInt() != 3) return "fail"
if (a[2].asInt() != 2) return "fail"
if (a[3].asInt() != 1) return "fail"
return "OK"
}
@@ -0,0 +1,23 @@
// !LANGUAGE: +InlineClasses
inline class UInt(private val value: Int) {
fun asInt() = value
}
inline class UIntArray(private val intArray: IntArray) {
operator fun get(index: Int): UInt = UInt(intArray[index])
operator fun set(index: Int, value: UInt) {
intArray[index] = value.asInt()
}
}
fun UIntArray.swap(i: Int, j: Int) {
this[j] = this[i].also { this[i] = this[j] }
}
// 2 INVOKEVIRTUAL UInt.unbox
// 1 INVOKESTATIC UInt\$Erased.box
// 0 intValue
// 0 valueOf
@@ -10389,6 +10389,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
}
@TestMetadata("boxUnboxInlineClassesWithOperatorsGetSet.kt")
public void testBoxUnboxInlineClassesWithOperatorsGetSet() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/boxUnboxInlineClassesWithOperatorsGetSet.kt");
doTest(fileName);
}
@TestMetadata("boxUnboxOfInlineClassForCapturedVars.kt")
public void testBoxUnboxOfInlineClassForCapturedVars() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/boxUnboxOfInlineClassForCapturedVars.kt");
@@ -10389,6 +10389,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
}
@TestMetadata("boxUnboxInlineClassesWithOperatorsGetSet.kt")
public void testBoxUnboxInlineClassesWithOperatorsGetSet() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/boxUnboxInlineClassesWithOperatorsGetSet.kt");
doTest(fileName);
}
@TestMetadata("boxUnboxOfInlineClassForCapturedVars.kt")
public void testBoxUnboxOfInlineClassForCapturedVars() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/boxUnboxOfInlineClassForCapturedVars.kt");
@@ -1968,6 +1968,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
doTest(fileName);
}
@TestMetadata("uIntArraySwapBoxing.kt")
public void testUIntArraySwapBoxing() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inlineClasses/uIntArraySwapBoxing.kt");
doTest(fileName);
}
@TestMetadata("unboxInlineClassAfterElvis.kt")
public void testUnboxInlineClassAfterElvis() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inlineClasses/unboxInlineClassAfterElvis.kt");
@@ -10389,6 +10389,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
}
@TestMetadata("boxUnboxInlineClassesWithOperatorsGetSet.kt")
public void testBoxUnboxInlineClassesWithOperatorsGetSet() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/boxUnboxInlineClassesWithOperatorsGetSet.kt");
doTest(fileName);
}
@TestMetadata("boxUnboxOfInlineClassForCapturedVars.kt")
public void testBoxUnboxOfInlineClassForCapturedVars() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/boxUnboxOfInlineClassForCapturedVars.kt");
@@ -11373,6 +11373,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
}
@TestMetadata("boxUnboxInlineClassesWithOperatorsGetSet.kt")
public void testBoxUnboxInlineClassesWithOperatorsGetSet() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/boxUnboxInlineClassesWithOperatorsGetSet.kt");
doTest(fileName);
}
@TestMetadata("boxUnboxOfInlineClassForCapturedVars.kt")
public void testBoxUnboxOfInlineClassForCapturedVars() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/boxUnboxOfInlineClassForCapturedVars.kt");