From fcacdc1fc57014d19a6659cef9283b723be99e23 Mon Sep 17 00:00:00 2001 From: Mikhail Zarechenskiy Date: Tue, 19 Jun 2018 15:58:31 +0300 Subject: [PATCH] Fix bridge methods generation when inline class types are used --- .../kotlin/codegen/FunctionCodegen.java | 28 +++++++++++---- ...enInlineClassImplementsGenericInterface.kt | 34 +++++++++++++++++++ .../inlineClassImplementsCollection.kt | 6 ++++ .../uIntArrayIteratorWithoutBoxing.kt | 7 ++-- .../ir/IrBlackBoxCodegenTestGenerated.java | 5 +++ .../codegen/BlackBoxCodegenTestGenerated.java | 5 +++ .../LightAnalysisModeTestGenerated.java | 5 +++ .../kotlin/resolve/inlineClassesUtils.kt | 2 +- .../IrJsCodegenBoxTestGenerated.java | 5 +++ .../semantics/JsCodegenBoxTestGenerated.java | 5 +++ 10 files changed, 91 insertions(+), 11 deletions(-) create mode 100644 compiler/testData/codegen/box/inlineClasses/bridgesWhenInlineClassImplementsGenericInterface.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java index 13077885a60..5b6d2e61df7 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java @@ -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 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); } } diff --git a/compiler/testData/codegen/box/inlineClasses/bridgesWhenInlineClassImplementsGenericInterface.kt b/compiler/testData/codegen/box/inlineClasses/bridgesWhenInlineClassImplementsGenericInterface.kt new file mode 100644 index 00000000000..9dd02c5de5c --- /dev/null +++ b/compiler/testData/codegen/box/inlineClasses/bridgesWhenInlineClassImplementsGenericInterface.kt @@ -0,0 +1,34 @@ +// !LANGUAGE: +InlineClasses +// IGNORE_BACKEND: JS_IR + +inline class InlinedComparable(val x: Int) : Comparable { + override fun compareTo(other: InlinedComparable): Int { + return x.compareTo(other.x) + } +} + +fun generic(c: Comparable, element: T) = c.compareTo(element) + +interface Base { + fun Base.foo(a: Base, b: T): Base +} + +inline class InlinedBase(val x: Int) : Base { + override fun Base.foo(a: Base, b: InlinedBase): Base { + 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" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/inlineClasses/inlineClassImplementsCollection.kt b/compiler/testData/codegen/box/inlineClasses/inlineClassImplementsCollection.kt index a9fc91d440f..73c34865878 100644 --- a/compiler/testData/codegen/box/inlineClasses/inlineClassImplementsCollection.kt +++ b/compiler/testData/codegen/box/inlineClasses/inlineClassImplementsCollection.kt @@ -13,6 +13,10 @@ inline class MyUIntArray(private val storage: IntArray) : Collection { override fun isEmpty(): Boolean = TODO() } +fun checkBoxed(c: Collection, 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" } \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/uIntArrayIteratorWithoutBoxing.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/uIntArrayIteratorWithoutBoxing.kt index 095fabca6c8..a165ea93685 100644 --- a/compiler/testData/codegen/bytecodeText/inlineClasses/uIntArrayIteratorWithoutBoxing.kt +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/uIntArrayIteratorWithoutBoxing.kt @@ -8,7 +8,7 @@ inline class UIntArray(private val intArray: IntArray) { inline class UIntIterator(private val intIterator: IntIterator) : Iterator { 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 \ No newline at end of file +// 0 valueOf \ No newline at end of file diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 3910ee87677..1f5aa762eb4 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -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"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index ec47030fe62..c34fdfcff85 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -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"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 85a05507344..085a3e23119 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -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"); diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/inlineClassesUtils.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/inlineClassesUtils.kt index b87821a23b5..2768bb95590 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/inlineClassesUtils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/inlineClassesUtils.kt @@ -38,4 +38,4 @@ fun KotlinType.isNullableUnderlyingType(): Boolean { val underlyingType = unsubstitutedUnderlyingType() ?: return false return TypeUtils.isNullableType(underlyingType) -} \ No newline at end of file +} diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java index b5fee2a570f..33544ab4e16 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java @@ -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"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index c3c8edcc591..b51681d9efb 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -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");