diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmInlineClassLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmInlineClassLowering.kt index 963a47b903d..e0ce78c1090 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmInlineClassLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmInlineClassLowering.kt @@ -14,10 +14,8 @@ import org.jetbrains.kotlin.backend.common.lower.irBlockBody import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin +import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.* import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.inlineClassFieldName -import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.isInlineClassFieldGetter -import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.isPrimaryInlineClassConstructor -import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.unboxInlineClass import org.jetbrains.kotlin.config.ApiVersion import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.ir.IrStatement @@ -136,18 +134,25 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F if (function.overriddenSymbols.isEmpty() || replacement.dispatchReceiverParameter != null) return listOf(replacement) - // Update the overridden symbols to point to their inline class replacements - function.overriddenSymbols = replacement.overriddenSymbols - - // Replace the function body with a wrapper - if (!function.isFakeOverride || !function.parentAsClass.isInline) { - createBridgeBody(function, replacement) + // If the original function has value parameters which need mangling we still need to replace + // it with a mangled version. + val bridgeFunction = if (!function.isFakeOverride && function.fullValueParameterList.any { it.type.requiresMangling }) { + context.inlineClassReplacements.createMethodReplacement(function) } else { - // Fake overrides redirect from the replacement to the original function, which is in turn replaced during interfacePhase. - createBridgeBody(replacement, function) + // Update the overridden symbols to point to their inline class replacements + function.overriddenSymbols = replacement.overriddenSymbols + function } - return listOf(replacement, function) + // Replace the function body with a wrapper + if (!bridgeFunction.isFakeOverride || !bridgeFunction.parentAsClass.isInline) { + createBridgeBody(bridgeFunction, replacement) + } else { + // Fake overrides redirect from the replacement to the original function, which is in turn replaced during interfacePhase. + createBridgeBody(replacement, bridgeFunction) + } + + return listOf(replacement, bridgeFunction) } // Secondary constructors for boxed types get translated to static functions returning diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/inlineclasses/InlineClassAbi.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/inlineclasses/InlineClassAbi.kt index ec532213f4c..86aaf46f954 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/inlineclasses/InlineClassAbi.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/inlineclasses/InlineClassAbi.kt @@ -97,13 +97,13 @@ object InlineClassAbi { } } -private val IrType.requiresMangling: Boolean +internal val IrType.requiresMangling: Boolean get() { val irClass = erasedUpperBound return irClass.isInline && irClass.fqNameWhenAvailable != DescriptorUtils.RESULT_FQ_NAME } -private val IrFunction.fullValueParameterList: List +internal val IrFunction.fullValueParameterList: List get() = listOfNotNull(extensionReceiverParameter) + valueParameters internal val IrFunction.hasMangledParameters: Boolean diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/inlineclasses/MemoizedInlineClassReplacements.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/inlineclasses/MemoizedInlineClassReplacements.kt index ffa1156d589..83ffabfb737 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/inlineclasses/MemoizedInlineClassReplacements.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/inlineclasses/MemoizedInlineClassReplacements.kt @@ -124,7 +124,7 @@ class MemoizedInlineClassReplacements { } } - private fun createMethodReplacement(function: IrFunction): IrSimpleFunction = + internal fun createMethodReplacement(function: IrFunction): IrSimpleFunction = buildReplacement(function, function.origin) { require(function.dispatchReceiverParameter != null && function is IrSimpleFunction) val newValueParameters = ArrayList() diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/mangledInlineClassInterfaceImplementation.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/mangledInlineClassInterfaceImplementation.kt new file mode 100644 index 00000000000..d0048aeb678 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/mangledInlineClassInterfaceImplementation.kt @@ -0,0 +1,18 @@ +// !LANGUAGE: +InlineClasses + +interface A { + fun foo(a: T): String +} + +inline class Foo(val x: Long) : A { + override fun foo(a: Foo): String = if (x != a.x) "OK" else "FAIL" +} + +fun box(): String { + return Foo(0L).foo(Foo(1L)) +} + +// 1 public foo-GWb7d6U\(J\)Ljava/lang/String; +// 1 public synthetic bridge foo\(Ljava/lang/Object;\)Ljava/lang/String; +// 1 public static foo-GWb7d6U\(JJ\)Ljava/lang/String; +// 0 foo\(J diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index d4a88a8b4ed..9ac1b20b9bf 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -2810,6 +2810,11 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/inlineClasses/isCheckForInlineClass.kt"); } + @TestMetadata("mangledInlineClassInterfaceImplementation.kt") + public void testMangledInlineClassInterfaceImplementation() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/inlineClasses/mangledInlineClassInterfaceImplementation.kt"); + } + @TestMetadata("noActualCallsOfInlineFunctionsOfInlineClass.kt") public void testNoActualCallsOfInlineFunctionsOfInlineClass() throws Exception { runTest("compiler/testData/codegen/bytecodeText/inlineClasses/noActualCallsOfInlineFunctionsOfInlineClass.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java index ac5786a7efb..3d51e16fee5 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java @@ -2855,6 +2855,11 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/inlineClasses/isCheckForInlineClass.kt"); } + @TestMetadata("mangledInlineClassInterfaceImplementation.kt") + public void testMangledInlineClassInterfaceImplementation() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/inlineClasses/mangledInlineClassInterfaceImplementation.kt"); + } + @TestMetadata("noActualCallsOfInlineFunctionsOfInlineClass.kt") public void testNoActualCallsOfInlineFunctionsOfInlineClass() throws Exception { runTest("compiler/testData/codegen/bytecodeText/inlineClasses/noActualCallsOfInlineFunctionsOfInlineClass.kt");