From e11c90f26c610048231e2f9de0b7e19ca24ab98a Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Fri, 31 Jul 2020 10:59:21 +0300 Subject: [PATCH] JVM_IR: KT-40293 Box return type for DefaultImpls methods if required --- .../backend/jvm/JvmCachedDeclarations.kt | 6 ++++++ .../jvm/codegen/MethodSignatureMapper.kt | 18 ++++++++++++++---- .../backend/jvm/lower/InterfaceLowering.kt | 8 ++++---- .../specialization/primitiveAndAny.kt | 1 - .../specialization/primitiveAndNullable.kt | 1 - 5 files changed, 24 insertions(+), 10 deletions(-) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmCachedDeclarations.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmCachedDeclarations.kt index f373a37b307..5e57c9133e9 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmCachedDeclarations.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmCachedDeclarations.kt @@ -43,6 +43,7 @@ class JvmCachedDeclarations( private val defaultImplsMethods = HashMap() private val defaultImplsClasses = HashMap() private val defaultImplsRedirections = HashMap() + private val defaultImplsOriginalMethods = HashMap() fun getFieldForEnumEntry(enumEntry: IrEnumEntry): IrField = singletonFieldDeclarations.getOrPut(enumEntry) { @@ -176,10 +177,15 @@ class JvmCachedDeclarations( it.annotations += irCall(this@JvmCachedDeclarations.context.ir.symbols.javaLangDeprecatedConstructor) } } + + defaultImplsOriginalMethods[it] = interfaceFun } } } + fun getOriginalFunctionForDefaultImpl(defaultImplFun: IrSimpleFunction) = + defaultImplsOriginalMethods[defaultImplFun] + fun getDefaultImplsClass(interfaceClass: IrClass): IrClass = defaultImplsClasses.getOrPut(interfaceClass) { context.irFactory.buildClass { 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 c677df424f9..eba567c20c1 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 @@ -171,10 +171,20 @@ class MethodSignatureMapper(private val context: JvmBackendContext) { private fun hasVoidReturnType(function: IrFunction): Boolean = function is IrConstructor || (function.returnType.isUnit() && !function.isGetter) - // Copied from KotlinTypeMapper.forceBoxedReturnType. - private fun forceBoxedReturnType(function: IrFunction): Boolean = isBoxMethodForInlineClass(function) || - function is IrSimpleFunction && function.returnType.isPrimitiveType() && - function.allOverridden().any { !it.returnType.isPrimitiveType() } + // See also: KotlinTypeMapper.forceBoxedReturnType + private fun forceBoxedReturnType(function: IrFunction): Boolean = + isBoxMethodForInlineClass(function) || forceFoxedReturnTypeOnOverride(function) || forceBoxedReturnTypeOnDefaultImplFun(function) + + private fun forceFoxedReturnTypeOnOverride(function: IrFunction) = + function is IrSimpleFunction && + function.returnType.isPrimitiveType() && + function.allOverridden().any { !it.returnType.isPrimitiveType() } + + private fun forceBoxedReturnTypeOnDefaultImplFun(function: IrFunction): Boolean { + if (function !is IrSimpleFunction) return false + val originalFun = context.cachedDeclarations.getOriginalFunctionForDefaultImpl(function) ?: return false + return forceFoxedReturnTypeOnOverride(originalFun) + } private fun isBoxMethodForInlineClass(function: IrFunction): Boolean = function.parent.let { it is IrClass && it.isInline } && diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceLowering.kt index 81dbf782dc7..4281e66d038 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceLowering.kt @@ -64,13 +64,13 @@ internal class InterfaceLowering(val context: JvmBackendContext) : IrElementTran val jvmDefaultMode = context.state.jvmDefaultMode val isCompatibilityMode = jvmDefaultMode.isCompatibility && !irClass.hasJvmDefaultNoCompatibilityAnnotation() // There are 6 cases for functions on interfaces: - loop@ for (function in irClass.functions) { + for (function in irClass.functions) { when { /** * 1) They are plain abstract interface functions, in which case we leave them: */ function.modality == Modality.ABSTRACT -> - continue@loop + continue /** * 2) They inherit a default implementation from an interface this interface extends: @@ -99,13 +99,13 @@ internal class InterfaceLowering(val context: JvmBackendContext) : IrElementTran // (KT-36188) where there could be multiple implementations. (resolveFakeOverride() only returns the implementation if // there's only one.) if (function.name.asString().endsWith("\$default")) { - continue@loop + continue } val implementation = function.resolveFakeOverride() ?: error("No single implementation found for: ${function.render()}") when { Visibilities.isPrivate(implementation.visibility) || implementation.isMethodOfAny() -> - continue@loop + continue !function.isDefinitelyNotDefaultImplsMethod(jvmDefaultMode, implementation) -> { val defaultImpl = createDefaultImpl(function) val superImpl = firstSuperMethodFromKotlin(function, implementation) diff --git a/compiler/testData/codegen/bytecodeListing/jvm8/defaults/allCompatibility/specialization/primitiveAndAny.kt b/compiler/testData/codegen/bytecodeListing/jvm8/defaults/allCompatibility/specialization/primitiveAndAny.kt index 0198aacbe9e..21d12dc0422 100644 --- a/compiler/testData/codegen/bytecodeListing/jvm8/defaults/allCompatibility/specialization/primitiveAndAny.kt +++ b/compiler/testData/codegen/bytecodeListing/jvm8/defaults/allCompatibility/specialization/primitiveAndAny.kt @@ -1,7 +1,6 @@ // !JVM_DEFAULT_MODE: all-compatibility // JVM_TARGET: 1.8 // WITH_RUNTIME -// IGNORE_BACKEND: JVM_IR interface Base { fun test(): Int? = 0 diff --git a/compiler/testData/codegen/bytecodeListing/jvm8/defaults/allCompatibility/specialization/primitiveAndNullable.kt b/compiler/testData/codegen/bytecodeListing/jvm8/defaults/allCompatibility/specialization/primitiveAndNullable.kt index 6193e630dcb..910710fb9ac 100644 --- a/compiler/testData/codegen/bytecodeListing/jvm8/defaults/allCompatibility/specialization/primitiveAndNullable.kt +++ b/compiler/testData/codegen/bytecodeListing/jvm8/defaults/allCompatibility/specialization/primitiveAndNullable.kt @@ -1,7 +1,6 @@ // !JVM_DEFAULT_MODE: all-compatibility // JVM_TARGET: 1.8 // WITH_RUNTIME -// IGNORE_BACKEND: JVM_IR interface Base { fun test(): Int? = 0 }