Skip to content

Commit

Permalink
JVM IR: Box inline classes in covariant overrides (KT-30419)
Browse files Browse the repository at this point in the history
  • Loading branch information
Steven Schäfer authored and dnpetrov committed Apr 16, 2020
1 parent 5252423 commit 7479149
Show file tree
Hide file tree
Showing 18 changed files with 21 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -182,19 +182,17 @@ 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 =
function.parent.let { it is IrClass && it.isInline } &&
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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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()
}
}
Expand Down Expand Up @@ -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 =
Expand Down Expand Up @@ -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()) }
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR

inline class X(val x: Any)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR

inline class X(val x: Any)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR

inline class X(val x: Any?)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR

inline class X(val x: Any?)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// WITH_RUNTIME
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR

fun f1(): () -> Result<String> {
return {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// WITH_RUNTIME
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR

fun f1() = lazy {
runCatching {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR

inline class X(val x: Any)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR

inline class X(val x: Any?)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR

inline class X(val x: Any)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR

interface IFoo {
fun foo(): String
Expand Down
Original file line number Diff line number Diff line change
@@ -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>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR

inline class X(val x: Any)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR

inline class ResultOrClosed(val x: Any?)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR

interface IQ {
fun ok(): String
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR

interface IQ {
fun ok(): String
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND_FIR: JVM_IR

inline class R(val x: Any)

fun useR(r: R) {
Expand Down

0 comments on commit 7479149

Please sign in to comment.