JVM IR: Box inline classes in covariant overrides (KT-30419)

This commit is contained in:
Steven Schäfer
2020-04-08 16:09:05 +02:00
committed by Dmitry Petrov
parent 52524235f7
commit 74791495d7
18 changed files with 21 additions and 28 deletions
@@ -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)
@@ -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,5 +1,4 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR
inline class X(val x: Any)
@@ -1,5 +1,4 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR
inline class X(val x: Any?)
@@ -1,5 +1,4 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR
inline class X(val x: Any?)
@@ -1,6 +1,5 @@
// WITH_RUNTIME
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR
fun f1(): () -> Result<String> {
return {
@@ -1,6 +1,5 @@
// WITH_RUNTIME
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR
fun f1() = lazy {
runCatching {
@@ -1,5 +1,4 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR
inline class X(val x: Any)
@@ -1,5 +1,4 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR
inline class X(val x: Any?)
@@ -1,5 +1,4 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR
inline class X(val x: Any)
@@ -1,5 +1,4 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR
interface IFoo {
fun foo(): String
@@ -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,5 +1,4 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR
inline class X(val x: Any)
@@ -1,5 +1,4 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR
inline class ResultOrClosed(val x: Any?)
@@ -1,5 +1,4 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR
interface IQ {
fun ok(): String
@@ -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) {