Fix bridge methods generation when inline class types are used

This commit is contained in:
Mikhail Zarechenskiy
2018-06-19 15:58:31 +03:00
parent f326fd66be
commit fcacdc1fc5
10 changed files with 91 additions and 11 deletions
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.codegen.coroutines.SuspendFunctionGenerationStrategy
import org.jetbrains.kotlin.codegen.coroutines.SuspendInlineFunctionGenerationStrategy;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
import org.jetbrains.kotlin.codegen.state.TypeMapperUtilsKt;
import org.jetbrains.kotlin.config.JvmDefaultMode;
import org.jetbrains.kotlin.config.JvmTarget;
import org.jetbrains.kotlin.config.LanguageFeature;
@@ -615,7 +616,7 @@ public class FunctionCodegen {
KotlinTypeMapper typeMapper = parentCodegen.typeMapper;
if (BuiltinSpecialBridgesUtil.shouldHaveTypeSafeBarrier(functionDescriptor, typeMapper::mapAsmMethod)) {
generateTypeCheckBarrierIfNeeded(
new InstructionAdapter(mv), functionDescriptor, signature.getReturnType(), /* delegateParameterTypes = */null);
new InstructionAdapter(mv), functionDescriptor, signature.getReturnType(), null, typeMapper);
}
Label methodEnd;
@@ -1422,16 +1423,23 @@ public class FunctionCodegen {
Type[] argTypes = bridge.getArgumentTypes();
Type[] originalArgTypes = delegateTo.getArgumentTypes();
List<ParameterDescriptor> allKotlinParameters = new ArrayList<>(argTypes.length);
if (descriptor.getExtensionReceiverParameter() != null) allKotlinParameters.add(descriptor.getExtensionReceiverParameter());
allKotlinParameters.addAll(descriptor.getValueParameters());
boolean safeToUseKotlinTypes = allKotlinParameters.size() == argTypes.length;
InstructionAdapter iv = new InstructionAdapter(mv);
MemberCodegen.markLineNumberForDescriptor(owner.getThisDescriptor(), iv);
if (delegateTo.getArgumentTypes().length > 0 && isSpecialBridge) {
generateTypeCheckBarrierIfNeeded(iv, descriptor, bridge.getReturnType(), delegateTo.getArgumentTypes());
generateTypeCheckBarrierIfNeeded(iv, descriptor, bridge.getReturnType(), delegateTo.getArgumentTypes(), typeMapper);
}
iv.load(0, OBJECT_TYPE);
for (int i = 0, reg = 1; i < argTypes.length; i++) {
StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv);
KotlinType kotlinType = safeToUseKotlinTypes ? allKotlinParameters.get(i).getType() : null;
StackValue.local(reg, argTypes[i], kotlinType).put(originalArgTypes[i], kotlinType, iv);
//noinspection AssignmentToForLoopParameter
reg += argTypes[i].getSize();
}
@@ -1451,7 +1459,8 @@ public class FunctionCodegen {
}
}
StackValue.coerce(delegateTo.getReturnType(), bridge.getReturnType(), iv);
KotlinType returnType = descriptor.getReturnType();
StackValue.coerce(delegateTo.getReturnType(), returnType, bridge.getReturnType(), returnType, iv);
iv.areturn(bridge.getReturnType());
endVisit(mv, "bridge method", origin);
@@ -1461,7 +1470,8 @@ public class FunctionCodegen {
@NotNull InstructionAdapter iv,
@NotNull FunctionDescriptor descriptor,
@NotNull Type returnType,
@Nullable Type[] delegateParameterTypes
@Nullable Type[] delegateParameterTypes,
@NotNull KotlinTypeMapper typeMapper
) {
BuiltinMethodsWithSpecialGenericSignature.TypeSafeBarrierDescription typeSafeBarrierDescription =
BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(descriptor);
@@ -1489,7 +1499,13 @@ public class FunctionCodegen {
iv.ifnull(defaultBranch);
}
else {
CodegenUtilKt.generateIsCheck(iv, kotlinType, boxType(delegateParameterTypes[i]));
Type targetBoxedType;
if (InlineClassesUtilsKt.isInlineClassType(kotlinType)) {
targetBoxedType = typeMapper.mapTypeAsDeclaration(kotlinType);
} else {
targetBoxedType = boxType(delegateParameterTypes[i]);
}
CodegenUtilKt.generateIsCheck(iv, kotlinType, targetBoxedType);
iv.ifeq(defaultBranch);
}
}
@@ -0,0 +1,34 @@
// !LANGUAGE: +InlineClasses
// IGNORE_BACKEND: JS_IR
inline class InlinedComparable(val x: Int) : Comparable<InlinedComparable> {
override fun compareTo(other: InlinedComparable): Int {
return x.compareTo(other.x)
}
}
fun <T> generic(c: Comparable<T>, element: T) = c.compareTo(element)
interface Base<T> {
fun Base<T>.foo(a: Base<T>, b: T): Base<T>
}
inline class InlinedBase(val x: Int) : Base<InlinedBase> {
override fun Base<InlinedBase>.foo(a: Base<InlinedBase>, b: InlinedBase): Base<InlinedBase> {
return if (a is InlinedBase) InlinedBase(a.x + b.x) else this
}
fun double(): InlinedBase {
return this.foo(this, this) as InlinedBase
}
}
fun box(): String {
val a = InlinedComparable(42)
if (generic(a, a) != 0) return "Fail 1"
val b = InlinedBase(3)
if (b.double().x != 6) return "Fail 2"
return "OK"
}
@@ -13,6 +13,10 @@ inline class MyUIntArray(private val storage: IntArray) : Collection<MyUInt> {
override fun isEmpty(): Boolean = TODO()
}
fun <T> checkBoxed(c: Collection<T>, element: T): Boolean {
return c.contains(element) && c.containsAll(listOf(element))
}
fun box(): String {
val uints = MyUIntArray(intArrayOf(0, 1, 42))
@@ -21,5 +25,7 @@ fun box(): String {
val ints = listOf(MyUInt(1), MyUInt(0))
if (!uints.containsAll(ints)) return "Fail 2"
if (!checkBoxed(uints, MyUInt(0))) return "Fail 3"
return "OK"
}
@@ -8,7 +8,7 @@ inline class UIntArray(private val intArray: IntArray) {
inline class UIntIterator(private val intIterator: IntIterator) : Iterator<UInt> {
override fun next(): UInt {
return UInt(intIterator.next())
return UInt(intIterator.next()) // box inside bridge that returns java/lang/Object
}
override fun hasNext(): Boolean {
@@ -27,7 +27,7 @@ fun test() {
fun takeUInt(u: UInt) {}
// 0 INVOKESTATIC UInt\$Erased.box
// 1 INVOKESTATIC UInt\$Erased.box
// 0 INVOKEVIRTUAL UInt.unbox
// 0 INVOKEVIRTUAL UIntIterator.iterator
@@ -35,5 +35,4 @@ fun takeUInt(u: UInt) {}
// 0 intValue
// inside wrong bridge
// 1 valueOf
// 0 valueOf
@@ -11169,6 +11169,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/inlineClasses/boxUnboxOfInlineClassForCapturedVars.kt");
}
@TestMetadata("bridgesWhenInlineClassImplementsGenericInterface.kt")
public void testBridgesWhenInlineClassImplementsGenericInterface() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/bridgesWhenInlineClassImplementsGenericInterface.kt");
}
@TestMetadata("callComputablePropertyInsideInlineClass.kt")
public void testCallComputablePropertyInsideInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/callComputablePropertyInsideInlineClass.kt");
@@ -11169,6 +11169,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/inlineClasses/boxUnboxOfInlineClassForCapturedVars.kt");
}
@TestMetadata("bridgesWhenInlineClassImplementsGenericInterface.kt")
public void testBridgesWhenInlineClassImplementsGenericInterface() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/bridgesWhenInlineClassImplementsGenericInterface.kt");
}
@TestMetadata("callComputablePropertyInsideInlineClass.kt")
public void testCallComputablePropertyInsideInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/callComputablePropertyInsideInlineClass.kt");
@@ -11169,6 +11169,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/inlineClasses/boxUnboxOfInlineClassForCapturedVars.kt");
}
@TestMetadata("bridgesWhenInlineClassImplementsGenericInterface.kt")
public void testBridgesWhenInlineClassImplementsGenericInterface() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/bridgesWhenInlineClassImplementsGenericInterface.kt");
}
@TestMetadata("callComputablePropertyInsideInlineClass.kt")
public void testCallComputablePropertyInsideInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/callComputablePropertyInsideInlineClass.kt");
@@ -38,4 +38,4 @@ fun KotlinType.isNullableUnderlyingType(): Boolean {
val underlyingType = unsubstitutedUnderlyingType() ?: return false
return TypeUtils.isNullableType(underlyingType)
}
}
@@ -10834,6 +10834,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/inlineClasses/boxUnboxOfInlineClassForCapturedVars.kt");
}
@TestMetadata("bridgesWhenInlineClassImplementsGenericInterface.kt")
public void testBridgesWhenInlineClassImplementsGenericInterface() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/bridgesWhenInlineClassImplementsGenericInterface.kt");
}
@TestMetadata("callComputablePropertyInsideInlineClass.kt")
public void testCallComputablePropertyInsideInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/callComputablePropertyInsideInlineClass.kt");
@@ -9712,6 +9712,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/inlineClasses/boxUnboxOfInlineClassForCapturedVars.kt");
}
@TestMetadata("bridgesWhenInlineClassImplementsGenericInterface.kt")
public void testBridgesWhenInlineClassImplementsGenericInterface() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/bridgesWhenInlineClassImplementsGenericInterface.kt");
}
@TestMetadata("callComputablePropertyInsideInlineClass.kt")
public void testCallComputablePropertyInsideInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/callComputablePropertyInsideInlineClass.kt");