JVM IR: Box inline classes in covariant overrides (KT-30419)
This commit is contained in:
committed by
Dmitry Petrov
parent
52524235f7
commit
74791495d7
+4
-6
@@ -182,8 +182,8 @@ class MethodSignatureMapper(private val context: JvmBackendContext) {
|
||||
private fun forceBoxedReturnType(function: IrFunction): Boolean {
|
||||
if (isBoxMethodForInlineClass(function)) return true
|
||||
|
||||
return isJvmPrimitive(function.returnType) &&
|
||||
function is IrSimpleFunction && function.allOverridden().any { !isJvmPrimitive(it.returnType) }
|
||||
return isJvmPrimitiveOrInlineClass(function.returnType) &&
|
||||
function is IrSimpleFunction && function.allOverridden().any { !isJvmPrimitiveOrInlineClass(it.returnType) }
|
||||
}
|
||||
|
||||
private fun isBoxMethodForInlineClass(function: IrFunction): Boolean =
|
||||
@@ -191,10 +191,8 @@ class MethodSignatureMapper(private val context: JvmBackendContext) {
|
||||
function.origin == JvmLoweredDeclarationOrigin.SYNTHETIC_INLINE_CLASS_MEMBER &&
|
||||
function.name.asString() == "box-impl"
|
||||
|
||||
private fun isJvmPrimitive(type: IrType): Boolean {
|
||||
if (type.isPrimitiveType()) return true
|
||||
return type.getClass()?.isInline == true && AsmUtil.isPrimitive(typeMapper.mapType(type))
|
||||
}
|
||||
private fun isJvmPrimitiveOrInlineClass(type: IrType): Boolean =
|
||||
type.isPrimitiveType() || type.getClass()?.isInline == true
|
||||
|
||||
fun mapSignatureSkipGeneric(function: IrFunction): JvmMethodSignature =
|
||||
mapSignature(function, true)
|
||||
|
||||
+17
-4
@@ -15,7 +15,9 @@ import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.eraseTypeParameters
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.isJvmAbstract
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.unboxInlineClass
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
@@ -31,6 +33,7 @@ import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import org.jetbrains.kotlin.utils.getOrPutNullable
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.Method
|
||||
@@ -172,8 +175,10 @@ private class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass,
|
||||
createBridges(declaration, member)
|
||||
|
||||
// For lambda classes, we move overrides from the `invoke` function to its bridge. This will allow us to avoid boxing
|
||||
// the return type of `invoke` in codegen for lambdas with primitive return type.
|
||||
if (member.name == OperatorNameConventions.INVOKE && declaration.origin == JvmLoweredDeclarationOrigin.LAMBDA_IMPL) {
|
||||
// the return type of `invoke` in codegen for lambdas with primitive return type. This does not apply to lambdas returning
|
||||
// inline class types erasing to Any, which we need to box.
|
||||
if (member.name == OperatorNameConventions.INVOKE && declaration.origin == JvmLoweredDeclarationOrigin.LAMBDA_IMPL
|
||||
&& !member.returnType.isInlineClassErasingToAny) {
|
||||
member.overriddenSymbols = listOf()
|
||||
}
|
||||
}
|
||||
@@ -354,10 +359,15 @@ private class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass,
|
||||
copyParametersWithErasure(this@addBridge, bridge.overridden)
|
||||
body = context.createIrBuilder(symbol).run { irExprBody(delegatingCall(this@apply, target)) }
|
||||
|
||||
val redundantOverrides = bridge.overriddenSymbols.flatMapTo(mutableSetOf()) {
|
||||
// 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<IrSimpleFunction>()?.overriddenSymbols ?: emptyList()
|
||||
}
|
||||
val redundantOverrides = inheritedOverrides.flatMapTo(mutableSetOf()) {
|
||||
it.owner.allOverridden().map { override -> override.symbol }.asIterable()
|
||||
}
|
||||
overriddenSymbols = bridge.overriddenSymbols.filter { it !in redundantOverrides }
|
||||
overriddenSymbols = inheritedOverrides.filter { it !in redundantOverrides }
|
||||
}
|
||||
|
||||
private fun IrClass.addSpecialBridge(specialBridge: SpecialBridge, target: IrSimpleFunction): IrSimpleFunction =
|
||||
@@ -492,3 +502,6 @@ private fun IrSimpleFunction.resolvesToClass(): Boolean {
|
||||
|
||||
private fun IrSimpleFunction.overriddenFromClass(): IrSimpleFunction? =
|
||||
overriddenSymbols.singleOrNull { !it.owner.parentAsClass.isJvmInterface }?.owner
|
||||
|
||||
private val IrType.isInlineClassErasingToAny: Boolean
|
||||
get() = unboxInlineClass().let { unboxed -> unboxed != this && (unboxed.isAny() || unboxed.isNullableAny()) }
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
|
||||
inline class X(val x: Any)
|
||||
|
||||
|
||||
-1
@@ -1,5 +1,4 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
|
||||
inline class X(val x: Any)
|
||||
|
||||
|
||||
-1
@@ -1,5 +1,4 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
|
||||
inline class X(val x: Any?)
|
||||
|
||||
|
||||
-1
@@ -1,5 +1,4 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
|
||||
inline class X(val x: Any?)
|
||||
|
||||
|
||||
-1
@@ -1,6 +1,5 @@
|
||||
// WITH_RUNTIME
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
|
||||
fun f1(): () -> Result<String> {
|
||||
return {
|
||||
|
||||
-1
@@ -1,6 +1,5 @@
|
||||
// WITH_RUNTIME
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
|
||||
fun f1() = lazy {
|
||||
runCatching {
|
||||
|
||||
-1
@@ -1,5 +1,4 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
|
||||
inline class X(val x: Any)
|
||||
|
||||
|
||||
-1
@@ -1,5 +1,4 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
|
||||
inline class X(val x: Any?)
|
||||
|
||||
|
||||
compiler/testData/codegen/box/inlineClasses/boxReturnValueOnOverride/covariantOverrideErasedToAny.kt
Vendored
-1
@@ -1,5 +1,4 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
|
||||
inline class X(val x: Any)
|
||||
|
||||
|
||||
-1
@@ -1,5 +1,4 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
|
||||
interface IFoo {
|
||||
fun foo(): String
|
||||
|
||||
-1
@@ -1,7 +1,6 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// WITH_RUNTIME
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
|
||||
interface IFooList {
|
||||
fun foo(): List<String>
|
||||
|
||||
-1
@@ -1,5 +1,4 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
|
||||
inline class X(val x: Any)
|
||||
|
||||
|
||||
-1
@@ -1,5 +1,4 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
|
||||
inline class ResultOrClosed(val x: Any?)
|
||||
|
||||
|
||||
Vendored
-1
@@ -1,5 +1,4 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
|
||||
interface IQ {
|
||||
fun ok(): String
|
||||
|
||||
Vendored
-1
@@ -1,5 +1,4 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
|
||||
interface IQ {
|
||||
fun ok(): String
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
|
||||
inline class R(val x: Any)
|
||||
|
||||
fun useR(r: R) {
|
||||
|
||||
Reference in New Issue
Block a user