JVM_IR: KT-40293 Box return type for DefaultImpls methods if required

This commit is contained in:
Dmitry Petrov
2020-07-31 10:59:21 +03:00
parent 034d5a948c
commit e11c90f26c
5 changed files with 24 additions and 10 deletions
@@ -43,6 +43,7 @@ class JvmCachedDeclarations(
private val defaultImplsMethods = HashMap<IrSimpleFunction, IrSimpleFunction>() private val defaultImplsMethods = HashMap<IrSimpleFunction, IrSimpleFunction>()
private val defaultImplsClasses = HashMap<IrClass, IrClass>() private val defaultImplsClasses = HashMap<IrClass, IrClass>()
private val defaultImplsRedirections = HashMap<IrSimpleFunction, IrSimpleFunction>() private val defaultImplsRedirections = HashMap<IrSimpleFunction, IrSimpleFunction>()
private val defaultImplsOriginalMethods = HashMap<IrSimpleFunction, IrSimpleFunction>()
fun getFieldForEnumEntry(enumEntry: IrEnumEntry): IrField = fun getFieldForEnumEntry(enumEntry: IrEnumEntry): IrField =
singletonFieldDeclarations.getOrPut(enumEntry) { singletonFieldDeclarations.getOrPut(enumEntry) {
@@ -176,10 +177,15 @@ class JvmCachedDeclarations(
it.annotations += irCall(this@JvmCachedDeclarations.context.ir.symbols.javaLangDeprecatedConstructor) it.annotations += irCall(this@JvmCachedDeclarations.context.ir.symbols.javaLangDeprecatedConstructor)
} }
} }
defaultImplsOriginalMethods[it] = interfaceFun
} }
} }
} }
fun getOriginalFunctionForDefaultImpl(defaultImplFun: IrSimpleFunction) =
defaultImplsOriginalMethods[defaultImplFun]
fun getDefaultImplsClass(interfaceClass: IrClass): IrClass = fun getDefaultImplsClass(interfaceClass: IrClass): IrClass =
defaultImplsClasses.getOrPut(interfaceClass) { defaultImplsClasses.getOrPut(interfaceClass) {
context.irFactory.buildClass { context.irFactory.buildClass {
@@ -171,10 +171,20 @@ class MethodSignatureMapper(private val context: JvmBackendContext) {
private fun hasVoidReturnType(function: IrFunction): Boolean = private fun hasVoidReturnType(function: IrFunction): Boolean =
function is IrConstructor || (function.returnType.isUnit() && !function.isGetter) function is IrConstructor || (function.returnType.isUnit() && !function.isGetter)
// Copied from KotlinTypeMapper.forceBoxedReturnType. // See also: KotlinTypeMapper.forceBoxedReturnType
private fun forceBoxedReturnType(function: IrFunction): Boolean = isBoxMethodForInlineClass(function) || private fun forceBoxedReturnType(function: IrFunction): Boolean =
function is IrSimpleFunction && function.returnType.isPrimitiveType() && isBoxMethodForInlineClass(function) || forceFoxedReturnTypeOnOverride(function) || forceBoxedReturnTypeOnDefaultImplFun(function)
function.allOverridden().any { !it.returnType.isPrimitiveType() }
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 = private fun isBoxMethodForInlineClass(function: IrFunction): Boolean =
function.parent.let { it is IrClass && it.isInline } && function.parent.let { it is IrClass && it.isInline } &&
@@ -64,13 +64,13 @@ internal class InterfaceLowering(val context: JvmBackendContext) : IrElementTran
val jvmDefaultMode = context.state.jvmDefaultMode val jvmDefaultMode = context.state.jvmDefaultMode
val isCompatibilityMode = jvmDefaultMode.isCompatibility && !irClass.hasJvmDefaultNoCompatibilityAnnotation() val isCompatibilityMode = jvmDefaultMode.isCompatibility && !irClass.hasJvmDefaultNoCompatibilityAnnotation()
// There are 6 cases for functions on interfaces: // There are 6 cases for functions on interfaces:
loop@ for (function in irClass.functions) { for (function in irClass.functions) {
when { when {
/** /**
* 1) They are plain abstract interface functions, in which case we leave them: * 1) They are plain abstract interface functions, in which case we leave them:
*/ */
function.modality == Modality.ABSTRACT -> function.modality == Modality.ABSTRACT ->
continue@loop continue
/** /**
* 2) They inherit a default implementation from an interface this interface extends: * 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 // (KT-36188) where there could be multiple implementations. (resolveFakeOverride() only returns the implementation if
// there's only one.) // there's only one.)
if (function.name.asString().endsWith("\$default")) { if (function.name.asString().endsWith("\$default")) {
continue@loop continue
} }
val implementation = function.resolveFakeOverride() ?: error("No single implementation found for: ${function.render()}") val implementation = function.resolveFakeOverride() ?: error("No single implementation found for: ${function.render()}")
when { when {
Visibilities.isPrivate(implementation.visibility) || implementation.isMethodOfAny() -> Visibilities.isPrivate(implementation.visibility) || implementation.isMethodOfAny() ->
continue@loop continue
!function.isDefinitelyNotDefaultImplsMethod(jvmDefaultMode, implementation) -> { !function.isDefinitelyNotDefaultImplsMethod(jvmDefaultMode, implementation) -> {
val defaultImpl = createDefaultImpl(function) val defaultImpl = createDefaultImpl(function)
val superImpl = firstSuperMethodFromKotlin(function, implementation) val superImpl = firstSuperMethodFromKotlin(function, implementation)
@@ -1,7 +1,6 @@
// !JVM_DEFAULT_MODE: all-compatibility // !JVM_DEFAULT_MODE: all-compatibility
// JVM_TARGET: 1.8 // JVM_TARGET: 1.8
// WITH_RUNTIME // WITH_RUNTIME
// IGNORE_BACKEND: JVM_IR
interface Base { interface Base {
fun test(): Int? = 0 fun test(): Int? = 0
@@ -1,7 +1,6 @@
// !JVM_DEFAULT_MODE: all-compatibility // !JVM_DEFAULT_MODE: all-compatibility
// JVM_TARGET: 1.8 // JVM_TARGET: 1.8
// WITH_RUNTIME // WITH_RUNTIME
// IGNORE_BACKEND: JVM_IR
interface Base { interface Base {
fun test(): Int? = 0 fun test(): Int? = 0
} }