From b262d09a81bf20ffd71db18a0c24ac4f61fa151c Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Mon, 15 Feb 2021 15:49:14 +0300 Subject: [PATCH] JVM_IR KT-44627 fix bridge signature for parameter with primitive bound --- .../jvm/codegen/MethodSignatureMapper.kt | 4 ++- .../backend/jvm/lower/BridgeLowering.kt | 23 ++++++++++------ .../overrideWithPrimitiveUpperBound.kt | 5 ++++ .../overrideWithPrimitiveUpperBound.txt | 27 +++++++++++++++++++ .../overrideWithPrimitiveUpperBound2.kt | 5 ++++ .../overrideWithPrimitiveUpperBound2.txt | 26 ++++++++++++++++++ .../codegen/BytecodeListingTestGenerated.java | 10 +++++++ .../ir/IrBytecodeListingTestGenerated.java | 10 +++++++ 8 files changed, 101 insertions(+), 9 deletions(-) create mode 100644 compiler/testData/codegen/bytecodeListing/overrideWithPrimitiveUpperBound.kt create mode 100644 compiler/testData/codegen/bytecodeListing/overrideWithPrimitiveUpperBound.txt create mode 100644 compiler/testData/codegen/bytecodeListing/overrideWithPrimitiveUpperBound2.kt create mode 100644 compiler/testData/codegen/bytecodeListing/overrideWithPrimitiveUpperBound2.txt diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt index ab1e9090d9a..09fb473e718 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt @@ -198,7 +198,9 @@ class MethodSignatureMapper(private val context: JvmBackendContext) { // See also: KotlinTypeMapper.forceBoxedReturnType private fun forceBoxedReturnType(function: IrFunction): Boolean = - isBoxMethodForInlineClass(function) || forceFoxedReturnTypeOnOverride(function) || forceBoxedReturnTypeOnDefaultImplFun(function) || + isBoxMethodForInlineClass(function) || + forceFoxedReturnTypeOnOverride(function) || + forceBoxedReturnTypeOnDefaultImplFun(function) || function.isFromJava() && function.returnType.isInlined() private fun forceFoxedReturnTypeOnOverride(function: IrFunction) = diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt index 063805baf08..ccbb511e39d 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt @@ -428,17 +428,24 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass copyParametersWithErasure(this@addBridge, bridge.overridden) body = context.createIrBuilder(symbol, startOffset, endOffset).run { irExprBody(delegatingCall(this@apply, target)) } - // The generated bridge method overrides all of the symbols which were overridden by its overrides. - // This is technically wrong, but it's necessary to generate a method which maps to the same signature. - val inheritedOverrides = bridge.overriddenSymbols.flatMapTo(mutableSetOf()) { function -> - function.owner.safeAs()?.overriddenSymbols ?: emptyList() + if (!bridge.overridden.returnType.isTypeParameterWithPrimitiveUpperBound()) { + // The generated bridge method overrides all of the symbols which were overridden by its overrides. + // This is technically wrong, but it's necessary to generate a method which maps to the same signature. + // In case of 'fun foo(): T', where 'T' is a type parameter with primitive upper bound (e.g., 'T : Char'), + // 'foo' is mapped to 'foo()C', regardless of its overrides. + val inheritedOverrides = bridge.overriddenSymbols.flatMapTo(mutableSetOf()) { function -> + function.owner.safeAs()?.overriddenSymbols ?: emptyList() + } + val redundantOverrides = inheritedOverrides.flatMapTo(mutableSetOf()) { + it.owner.allOverridden().map { override -> override.symbol } + } + overriddenSymbols = inheritedOverrides.filter { it !in redundantOverrides } } - val redundantOverrides = inheritedOverrides.flatMapTo(mutableSetOf()) { - it.owner.allOverridden().map { override -> override.symbol } - } - overriddenSymbols = inheritedOverrides.filter { it !in redundantOverrides } } + private fun IrType.isTypeParameterWithPrimitiveUpperBound(): Boolean = + isTypeParameter() && eraseTypeParameters().isPrimitiveType() + private fun IrClass.addSpecialBridge(specialBridge: SpecialBridge, target: IrSimpleFunction): IrSimpleFunction = addFunction { startOffset = this@addSpecialBridge.startOffset diff --git a/compiler/testData/codegen/bytecodeListing/overrideWithPrimitiveUpperBound.kt b/compiler/testData/codegen/bytecodeListing/overrideWithPrimitiveUpperBound.kt new file mode 100644 index 00000000000..54d4e76009b --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/overrideWithPrimitiveUpperBound.kt @@ -0,0 +1,5 @@ +open class ATChar(open var x: T) + +open class BTChar(override var x: T) : ATChar(x) + +class CChar(override var x: Char) : BTChar('x') diff --git a/compiler/testData/codegen/bytecodeListing/overrideWithPrimitiveUpperBound.txt b/compiler/testData/codegen/bytecodeListing/overrideWithPrimitiveUpperBound.txt new file mode 100644 index 00000000000..18c03ddc333 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/overrideWithPrimitiveUpperBound.txt @@ -0,0 +1,27 @@ +@kotlin.Metadata +public class ATChar { + // source: 'overrideWithPrimitiveUpperBound.kt' + private field x: char + public method (p0: char): void + public method getX(): char + public method setX(p0: char): void +} + +@kotlin.Metadata +public class BTChar { + // source: 'overrideWithPrimitiveUpperBound.kt' + private field x: char + public method (p0: char): void + public method getX(): char + public method setX(p0: char): void +} + +@kotlin.Metadata +public final class CChar { + // source: 'overrideWithPrimitiveUpperBound.kt' + private field x: char + public method (p0: char): void + public synthetic bridge method getX(): char + public @org.jetbrains.annotations.NotNull method getX(): java.lang.Character + public method setX(p0: char): void +} diff --git a/compiler/testData/codegen/bytecodeListing/overrideWithPrimitiveUpperBound2.kt b/compiler/testData/codegen/bytecodeListing/overrideWithPrimitiveUpperBound2.kt new file mode 100644 index 00000000000..e381f4327f4 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/overrideWithPrimitiveUpperBound2.kt @@ -0,0 +1,5 @@ +open class ATAny(open val x: T) + +open class BTChar(override val x: T) : ATAny(x) + +class CChar(override val x: Char) : BTChar('x') diff --git a/compiler/testData/codegen/bytecodeListing/overrideWithPrimitiveUpperBound2.txt b/compiler/testData/codegen/bytecodeListing/overrideWithPrimitiveUpperBound2.txt new file mode 100644 index 00000000000..b1d72d7162e --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/overrideWithPrimitiveUpperBound2.txt @@ -0,0 +1,26 @@ +@kotlin.Metadata +public class ATAny { + // source: 'overrideWithPrimitiveUpperBound2.kt' + private final field x: java.lang.Object + public method (p0: java.lang.Object): void + public method getX(): java.lang.Object +} + +@kotlin.Metadata +public class BTChar { + // source: 'overrideWithPrimitiveUpperBound2.kt' + private final field x: char + public method (p0: char): void + public method getX(): char + public synthetic bridge method getX(): java.lang.Object +} + +@kotlin.Metadata +public final class CChar { + // source: 'overrideWithPrimitiveUpperBound2.kt' + private final field x: char + public method (p0: char): void + public synthetic bridge method getX(): char + public @org.jetbrains.annotations.NotNull method getX(): java.lang.Character + public synthetic bridge method getX(): java.lang.Object +} diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java index 40454e58f67..9bbc74d2da6 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java @@ -215,6 +215,16 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest { runTest("compiler/testData/codegen/bytecodeListing/noRemoveAtInReadOnly.kt"); } + @TestMetadata("overrideWithPrimitiveUpperBound.kt") + public void testOverrideWithPrimitiveUpperBound() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/overrideWithPrimitiveUpperBound.kt"); + } + + @TestMetadata("overrideWithPrimitiveUpperBound2.kt") + public void testOverrideWithPrimitiveUpperBound2() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/overrideWithPrimitiveUpperBound2.kt"); + } + @TestMetadata("privateCompanionFields.kt") public void testPrivateCompanionFields() throws Exception { runTest("compiler/testData/codegen/bytecodeListing/privateCompanionFields.kt"); diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java index 8e298304579..3c3bc80545c 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java @@ -215,6 +215,16 @@ public class IrBytecodeListingTestGenerated extends AbstractIrBytecodeListingTes runTest("compiler/testData/codegen/bytecodeListing/noRemoveAtInReadOnly.kt"); } + @TestMetadata("overrideWithPrimitiveUpperBound.kt") + public void testOverrideWithPrimitiveUpperBound() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/overrideWithPrimitiveUpperBound.kt"); + } + + @TestMetadata("overrideWithPrimitiveUpperBound2.kt") + public void testOverrideWithPrimitiveUpperBound2() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/overrideWithPrimitiveUpperBound2.kt"); + } + @TestMetadata("privateCompanionFields.kt") public void testPrivateCompanionFields() throws Exception { runTest("compiler/testData/codegen/bytecodeListing/privateCompanionFields.kt");