From 5cefd4e443a098d3d2f661de7422699590b67527 Mon Sep 17 00:00:00 2001 From: Kristoffer Andersen Date: Thu, 19 Sep 2019 09:38:26 +0200 Subject: [PATCH] JVM IR: Implement -Xjvm-default=enable --- .../backend/jvm/lower/InterfaceDelegationLowering.kt | 11 +++++++---- .../kotlin/backend/jvm/lower/InterfaceLowering.kt | 9 ++++++--- .../kotlin/ir/declarations/impl/IrFunctionImpl.kt | 1 + .../writeFlags/jvm8/defaults/defaultMethod.kt | 1 - 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceDelegationLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceDelegationLowering.kt index 4b7921178b3..8fe274dccd7 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceDelegationLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceDelegationLowering.kt @@ -78,7 +78,7 @@ private class InterfaceDelegationLowering(val context: JvmBackendContext) : IrEl for (function in actualClass.functions.toList()) { // Copy the list, because we are adding new declarations from the loop if (function.origin !== IrDeclarationOrigin.FAKE_OVERRIDE) continue - // In classes, only generate interface delegation for functions immediately inherited from am interface. + // In classes, only generate interface delegation for functions immediately inherited from an interface. // (Otherwise, delegation will be present in the parent class) if (!isDefaultImplsGeneration && function.overriddenSymbols.any { @@ -92,7 +92,9 @@ private class InterfaceDelegationLowering(val context: JvmBackendContext) : IrEl val implementation = function.resolveFakeOverride() ?: continue if (!implementation.hasInterfaceParent() || Visibilities.isPrivate(implementation.visibility) || - implementation.isDefinitelyNotDefaultImplsMethod() || implementation.isMethodOfAny() + implementation.isDefinitelyNotDefaultImplsMethod() || + implementation.isMethodOfAny() || + (!context.state.jvmDefaultMode.isCompatibility && implementation.hasJvmDefault()) ) { continue } @@ -205,8 +207,9 @@ private class InterfaceSuperCallsLowering(val context: JvmBackendContext) : IrEl if (expression.superQualifierSymbol?.owner?.isInterface != true) { return super.visitCall(expression) } + val superCallee = (expression.symbol.owner as IrSimpleFunction).resolveFakeOverride()!! - if (superCallee.isDefinitelyNotDefaultImplsMethod()) return super.visitCall(expression) + if (superCallee.isDefinitelyNotDefaultImplsMethod() || superCallee.hasJvmDefault()) return super.visitCall(expression) val redirectTarget = context.declarationFactory.getDefaultImplsFunction(superCallee) val newCall = irCall(expression, redirectTarget, receiversAsArguments = true) @@ -222,7 +225,7 @@ internal val interfaceDefaultCallsPhase = makeIrFilePhase( ) private class InterfaceDefaultCallsLowering(val context: JvmBackendContext) : IrElementTransformerVoid(), FileLoweringPass { - + // TODO If there are no default _implementations_ we can avoid generating defaultImpls class entirely by moving default arg dispatchers to the interface class override fun lower(irFile: IrFile) { irFile.transformChildrenVoid(this) } 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 803f8a2bcbd..48de8e6f727 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 @@ -45,6 +45,7 @@ private class InterfaceLowering(val context: JvmBackendContext) : IrElementTrans if (!irClass.isInterface) return val defaultImplsIrClass = context.declarationFactory.getDefaultImplsClass(irClass) + //TODO: Don't add DefaultImpls if it's empty. Just like the old backend...? irClass.declarations.add(defaultImplsIrClass) val members = defaultImplsIrClass.declarations @@ -52,8 +53,11 @@ private class InterfaceLowering(val context: JvmBackendContext) : IrElementTrans if (function !is IrSimpleFunction) continue if (function.modality != Modality.ABSTRACT && function.origin != IrDeclarationOrigin.FAKE_OVERRIDE) { + + if(function.hasJvmDefault() && !context.state.jvmDefaultMode.isCompatibility && !mustMoveToDefaultImpls(function)) continue + val element = context.declarationFactory.getDefaultImplsFunction(function).also { - if (shouldRemoveFunction(function)) + if (mustMoveToDefaultImpls(function)) removedFunctions[function.symbol] = it.symbol } members.add(element) @@ -64,7 +68,6 @@ private class InterfaceLowering(val context: JvmBackendContext) : IrElementTrans if (function.hasJvmDefault() && function.origin != JvmLoweredDeclarationOrigin.SYNTHETIC_METHOD_FOR_PROPERTY_ANNOTATIONS ) { - // TODO: don't touch function and only generate element / DefaultImpls when needed. function.body = IrExpressionBodyImpl(callDefaultImpls(element, function)) } else { function.body = null @@ -98,7 +101,7 @@ private class InterfaceLowering(val context: JvmBackendContext) : IrElementTrans } } - private fun shouldRemoveFunction(function: IrFunction): Boolean = + private fun mustMoveToDefaultImpls(function: IrFunction): Boolean = Visibilities.isPrivate(function.visibility) && function.name != clinitName || function.origin == IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER || function.origin == JvmLoweredDeclarationOrigin.SYNTHETIC_METHOD_FOR_PROPERTY_ANNOTATIONS diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/impl/IrFunctionImpl.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/impl/IrFunctionImpl.kt index 626a9a8d473..a4c52ae6097 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/impl/IrFunctionImpl.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/impl/IrFunctionImpl.kt @@ -16,6 +16,7 @@ import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl import org.jetbrains.kotlin.ir.types.IrType +import org.jetbrains.kotlin.ir.util.name import org.jetbrains.kotlin.ir.visitors.IrElementVisitor import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.utils.SmartList diff --git a/compiler/testData/writeFlags/jvm8/defaults/defaultMethod.kt b/compiler/testData/writeFlags/jvm8/defaults/defaultMethod.kt index bed85333f57..0552a70ca80 100644 --- a/compiler/testData/writeFlags/jvm8/defaults/defaultMethod.kt +++ b/compiler/testData/writeFlags/jvm8/defaults/defaultMethod.kt @@ -1,5 +1,4 @@ // !JVM_DEFAULT_MODE: enable -// IGNORE_BACKEND: JVM_IR // JVM_TARGET: 1.8 // WITH_RUNTIME