JVM IR: Do not generate DefaultImpls if it's empty. This revealed that InterfaceDelegationLowering was relying on the presence of DefaultImpls even when empty. Hence, simply dropping it from InterfaceLowering was not trivial. Moved default delegation in DefaultImpls to SuperType.DefaultImpls to InterfaceLowering. Clean up logic considerably, and document inter-phase dependencies.
This commit is contained in:
committed by
max-kammerer
parent
cc6252098f
commit
9d1d6a7b1f
@@ -144,6 +144,13 @@ private val defaultArgumentInjectorPhase = makeIrFilePhase(
|
|||||||
prerequisite = setOf(defaultArgumentStubPhase, callableReferencePhase)
|
prerequisite = setOf(defaultArgumentStubPhase, callableReferencePhase)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private val interfacePhase = makeIrFilePhase(
|
||||||
|
::InterfaceLowering,
|
||||||
|
name = "Interface",
|
||||||
|
description = "Move default implementations of interface members to DefaultImpls class",
|
||||||
|
prerequisite = setOf(defaultArgumentInjectorPhase)
|
||||||
|
)
|
||||||
|
|
||||||
private val innerClassesPhase = makeIrFilePhase(
|
private val innerClassesPhase = makeIrFilePhase(
|
||||||
::InnerClassesLowering,
|
::InnerClassesLowering,
|
||||||
name = "InnerClasses",
|
name = "InnerClasses",
|
||||||
@@ -158,6 +165,13 @@ private val returnableBlocksPhase = makeIrFilePhase(
|
|||||||
prerequisite = setOf(arrayConstructorPhase, assertionPhase)
|
prerequisite = setOf(arrayConstructorPhase, assertionPhase)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private val syntheticAccessorPhase = makeIrFilePhase(
|
||||||
|
::SyntheticAccessorLowering,
|
||||||
|
name = "SyntheticAccessor",
|
||||||
|
description = "Introduce synthetic accessors",
|
||||||
|
prerequisite = setOf(objectClassPhase, staticDefaultFunctionPhase, interfacePhase)
|
||||||
|
)
|
||||||
|
|
||||||
@Suppress("Reformat")
|
@Suppress("Reformat")
|
||||||
private val jvmFilePhases =
|
private val jvmFilePhases =
|
||||||
typeAliasAnnotationMethodsPhase then
|
typeAliasAnnotationMethodsPhase then
|
||||||
|
|||||||
+52
-68
@@ -13,7 +13,6 @@ import org.jetbrains.kotlin.backend.common.ir.passTypeArgumentsFrom
|
|||||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
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.codegen.isJvmInterface
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.hasJvmDefault
|
import org.jetbrains.kotlin.backend.jvm.ir.hasJvmDefault
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
@@ -39,7 +38,6 @@ import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
|
|||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.ir.visitors.*
|
import org.jetbrains.kotlin.ir.visitors.*
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
import java.util.function.UnaryOperator
|
|
||||||
|
|
||||||
internal val interfaceDelegationPhase = makeIrFilePhase(
|
internal val interfaceDelegationPhase = makeIrFilePhase(
|
||||||
::InterfaceDelegationLowering,
|
::InterfaceDelegationLowering,
|
||||||
@@ -68,95 +66,80 @@ private class InterfaceDelegationLowering(val context: JvmBackendContext) : IrEl
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun generateInterfaceMethods(irClass: IrClass) {
|
private fun generateInterfaceMethods(irClass: IrClass) {
|
||||||
val (actualClass, isDefaultImplsGeneration) = if (irClass.origin == JvmLoweredDeclarationOrigin.DEFAULT_IMPLS) {
|
|
||||||
Pair(irClass.parent as IrClass, true)
|
|
||||||
} else {
|
|
||||||
Pair(irClass, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
val toRemove = mutableListOf<IrSimpleFunction>()
|
val toRemove = mutableListOf<IrSimpleFunction>()
|
||||||
for (function in actualClass.functions.toList()) { // Copy the list, because we are adding new declarations from the loop
|
for (function in irClass.functions.toList()) { // Copy the list, because we are adding new declarations from the loop
|
||||||
if (function.origin !== IrDeclarationOrigin.FAKE_OVERRIDE) continue
|
if (function.origin !== IrDeclarationOrigin.FAKE_OVERRIDE) continue
|
||||||
|
|
||||||
// In classes, only generate interface delegation for functions immediately inherited from an interface.
|
// Only generate interface delegation for functions immediately inherited from an interface.
|
||||||
// (Otherwise, delegation will be present in the parent class)
|
// (Otherwise, delegation will be present in the parent class)
|
||||||
if (!isDefaultImplsGeneration &&
|
if (function.overriddenSymbols.any { !it.owner.parentAsClass.isInterface && it.owner.modality != Modality.ABSTRACT }) {
|
||||||
function.overriddenSymbols.any {
|
|
||||||
(!it.owner.parentAsClass.isInterface || it.owner.hasJvmDefault()) &&
|
|
||||||
it.owner.modality != Modality.ABSTRACT
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
val implementation = function.resolveFakeOverride() ?: continue
|
val implementation = function.resolveFakeOverride() ?: continue
|
||||||
if (!implementation.hasInterfaceParent() ||
|
|
||||||
Visibilities.isPrivate(implementation.visibility) ||
|
if (!implementation.hasInterfaceParent()
|
||||||
implementation.isDefinitelyNotDefaultImplsMethod() ||
|
|| Visibilities.isPrivate(implementation.visibility)
|
||||||
implementation.isMethodOfAny() ||
|
|| implementation.isDefinitelyNotDefaultImplsMethod()
|
||||||
(!context.state.jvmDefaultMode.isCompatibility && implementation.hasJvmDefault())
|
|| implementation.isMethodOfAny()
|
||||||
|
|| (!context.state.jvmDefaultMode.isCompatibility && implementation.hasJvmDefault())
|
||||||
) {
|
) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
val delegation = generateDelegationToDefaultImpl(irClass, implementation, function, isDefaultImplsGeneration)
|
toRemove.add(function)
|
||||||
if (!isDefaultImplsGeneration) {
|
|
||||||
toRemove.add(function)
|
val delegation = generateDelegationToDefaultImpl(irClass, implementation, function)
|
||||||
replacementMap[function.symbol] = delegation.symbol
|
irClass.declarations.add(delegation)
|
||||||
}
|
replacementMap[function.symbol] = delegation.symbol
|
||||||
}
|
}
|
||||||
irClass.declarations.removeAll(toRemove)
|
irClass.declarations.removeAll(toRemove)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateDelegationToDefaultImpl(
|
private fun generateDelegationToDefaultImpl(
|
||||||
irClass: IrClass,
|
irClass: IrClass,
|
||||||
interfaceFun: IrSimpleFunction,
|
interfaceImplementation: IrSimpleFunction,
|
||||||
inheritedFun: IrSimpleFunction,
|
classOverride: IrSimpleFunction
|
||||||
isDefaultImplsGeneration: Boolean
|
|
||||||
): IrSimpleFunction {
|
): IrSimpleFunction {
|
||||||
val defaultImplFun = context.declarationFactory.getDefaultImplsFunction(interfaceFun)
|
val inheritedProperty = classOverride.correspondingPropertySymbol?.owner
|
||||||
|
val descriptor = DescriptorsToIrRemapper.remapDeclaredSimpleFunction(classOverride.descriptor)
|
||||||
|
|
||||||
val irFunction =
|
val irFunction =
|
||||||
if (!isDefaultImplsGeneration) {
|
IrFunctionImpl(
|
||||||
val inheritedProperty = inheritedFun.correspondingPropertySymbol?.owner
|
UNDEFINED_OFFSET,
|
||||||
val descriptor = DescriptorsToIrRemapper.remapDeclaredSimpleFunction(inheritedFun.descriptor)
|
UNDEFINED_OFFSET,
|
||||||
IrFunctionImpl(
|
IrDeclarationOrigin.DEFINED,
|
||||||
UNDEFINED_OFFSET,
|
IrSimpleFunctionSymbolImpl(descriptor),
|
||||||
UNDEFINED_OFFSET,
|
classOverride.name,
|
||||||
IrDeclarationOrigin.DEFINED,
|
Visibilities.PUBLIC,
|
||||||
IrSimpleFunctionSymbolImpl(descriptor),
|
classOverride.modality,
|
||||||
inheritedFun.name,
|
classOverride.returnType,
|
||||||
Visibilities.PUBLIC,
|
isInline = classOverride.isInline,
|
||||||
inheritedFun.modality,
|
isExternal = false,
|
||||||
inheritedFun.returnType,
|
isTailrec = false,
|
||||||
isInline = inheritedFun.isInline,
|
isSuspend = classOverride.isSuspend
|
||||||
isExternal = false,
|
).apply {
|
||||||
isTailrec = false,
|
descriptor.bind(this)
|
||||||
isSuspend = inheritedFun.isSuspend
|
parent = irClass
|
||||||
).apply {
|
overriddenSymbols.addAll(classOverride.overriddenSymbols)
|
||||||
descriptor.bind(this)
|
copyParameterDeclarationsFrom(classOverride)
|
||||||
parent = irClass
|
annotations.addAll(classOverride.annotations)
|
||||||
overriddenSymbols.addAll(inheritedFun.overriddenSymbols)
|
|
||||||
copyParameterDeclarationsFrom(inheritedFun)
|
|
||||||
annotations.addAll(inheritedFun.annotations)
|
|
||||||
|
|
||||||
if (inheritedProperty != null) {
|
if (inheritedProperty != null) {
|
||||||
val propertyDescriptor = DescriptorsToIrRemapper.remapDeclaredProperty(inheritedProperty.descriptor)
|
val propertyDescriptor = DescriptorsToIrRemapper.remapDeclaredProperty(inheritedProperty.descriptor)
|
||||||
IrPropertyImpl(
|
IrPropertyImpl(
|
||||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrDeclarationOrigin.DEFINED, IrPropertySymbolImpl(propertyDescriptor),
|
UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrDeclarationOrigin.DEFINED, IrPropertySymbolImpl(propertyDescriptor),
|
||||||
inheritedProperty.name, Visibilities.PUBLIC, inheritedProperty.modality, inheritedProperty.isVar,
|
inheritedProperty.name, Visibilities.PUBLIC, inheritedProperty.modality, inheritedProperty.isVar,
|
||||||
inheritedProperty.isConst, inheritedProperty.isLateinit, inheritedProperty.isDelegated, isExternal = false
|
inheritedProperty.isConst, inheritedProperty.isLateinit, inheritedProperty.isDelegated, isExternal = false
|
||||||
).apply {
|
).apply {
|
||||||
propertyDescriptor.bind(this)
|
propertyDescriptor.bind(this)
|
||||||
parent = irClass
|
parent = irClass
|
||||||
correspondingPropertySymbol = symbol
|
correspondingPropertySymbol = symbol
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else context.declarationFactory.getDefaultImplsFunction(inheritedFun)
|
}
|
||||||
|
|
||||||
irClass.declarations.add(irFunction)
|
|
||||||
|
|
||||||
|
val defaultImplFun = context.declarationFactory.getDefaultImplsFunction(interfaceImplementation)
|
||||||
context.createIrBuilder(irFunction.symbol, UNDEFINED_OFFSET, UNDEFINED_OFFSET).apply {
|
context.createIrBuilder(irFunction.symbol, UNDEFINED_OFFSET, UNDEFINED_OFFSET).apply {
|
||||||
irFunction.body = irBlockBody {
|
irFunction.body = irBlockBody {
|
||||||
+irReturn(
|
+irReturn(
|
||||||
@@ -182,7 +165,7 @@ private class InterfaceDelegationLowering(val context: JvmBackendContext) : IrEl
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitSimpleFunction(declaration: IrSimpleFunction) {
|
override fun visitSimpleFunction(declaration: IrSimpleFunction) {
|
||||||
declaration.overriddenSymbols.replaceAll(UnaryOperator { symbol -> replacementMap[symbol] ?: symbol })
|
declaration.overriddenSymbols.replaceAll { symbol -> replacementMap[symbol] ?: symbol }
|
||||||
super.visitSimpleFunction(declaration)
|
super.visitSimpleFunction(declaration)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -234,7 +217,8 @@ private class InterfaceDefaultCallsLowering(val context: JvmBackendContext) : Ir
|
|||||||
val callee = expression.symbol.owner
|
val callee = expression.symbol.owner
|
||||||
|
|
||||||
if (callee.parent.safeAs<IrClass>()?.isInterface != true ||
|
if (callee.parent.safeAs<IrClass>()?.isInterface != true ||
|
||||||
callee.origin != IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER
|
callee.origin != IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER ||
|
||||||
|
(callee.hasJvmDefault() && !context.state.jvmDefaultMode.isCompatibility)
|
||||||
) {
|
) {
|
||||||
return super.visitCall(expression)
|
return super.visitCall(expression)
|
||||||
}
|
}
|
||||||
|
|||||||
+99
-41
@@ -7,14 +7,17 @@ package org.jetbrains.kotlin.backend.jvm.lower
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
||||||
import org.jetbrains.kotlin.backend.common.ir.copyBodyToStatic
|
import org.jetbrains.kotlin.backend.common.ir.copyBodyToStatic
|
||||||
|
import org.jetbrains.kotlin.backend.common.ir.isMethodOfAny
|
||||||
import org.jetbrains.kotlin.backend.common.ir.passTypeArgumentsFrom
|
import org.jetbrains.kotlin.backend.common.ir.passTypeArgumentsFrom
|
||||||
import org.jetbrains.kotlin.backend.common.lower.InitializersLowering.Companion.clinitName
|
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
|
||||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.hasJvmDefault
|
import org.jetbrains.kotlin.backend.jvm.ir.hasJvmDefault
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
|
import org.jetbrains.kotlin.ir.builders.irBlockBody
|
||||||
|
import org.jetbrains.kotlin.ir.builders.irReturn
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
@@ -23,62 +26,95 @@ import org.jetbrains.kotlin.ir.expressions.IrReturn
|
|||||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrLocalDelegatedPropertySymbol
|
import org.jetbrains.kotlin.ir.symbols.IrLocalDelegatedPropertySymbol
|
||||||
import org.jetbrains.kotlin.ir.util.copyTypeAndValueArgumentsFrom
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.ir.util.irCall
|
|
||||||
import org.jetbrains.kotlin.ir.util.isInterface
|
|
||||||
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
|
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
|
|
||||||
internal val interfacePhase = makeIrFilePhase(
|
/**
|
||||||
::InterfaceLowering,
|
* This phase moves interface members with default implementations to the
|
||||||
name = "Interface",
|
* associated companion DefaultImpls with bridges, as appropriate. It then
|
||||||
description = "Move default implementations of interface members to DefaultImpls class"
|
* performs a traversal of any other code in this interface and redirects calls
|
||||||
)
|
* to the interface to the companion, if functions were moved completely.
|
||||||
|
*/
|
||||||
|
internal class InterfaceLowering(val context: JvmBackendContext) : IrElementTransformerVoid(), ClassLoweringPass {
|
||||||
|
|
||||||
private class InterfaceLowering(val context: JvmBackendContext) : IrElementTransformerVoid(), ClassLoweringPass {
|
private val removedFunctions = hashMapOf<IrFunctionSymbol, IrFunctionSymbol>()
|
||||||
|
|
||||||
val state = context.state
|
|
||||||
val removedFunctions = hashMapOf<IrFunctionSymbol, IrFunctionSymbol>()
|
|
||||||
|
|
||||||
override fun lower(irClass: IrClass) {
|
override fun lower(irClass: IrClass) {
|
||||||
if (!irClass.isInterface) return
|
if (!irClass.isInterface) return
|
||||||
|
|
||||||
val defaultImplsIrClass = context.declarationFactory.getDefaultImplsClass(irClass)
|
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
|
val members = defaultImplsIrClass.declarations
|
||||||
|
|
||||||
for (function in irClass.declarations) {
|
// There are 6 cases for functions on interfaces:
|
||||||
if (function !is IrSimpleFunction) continue
|
loop@ 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
|
||||||
|
|
||||||
if (function.modality != Modality.ABSTRACT && function.origin != IrDeclarationOrigin.FAKE_OVERRIDE) {
|
/**
|
||||||
|
* 2) They inherit a default implementation from an interface this interface
|
||||||
|
* extends: create a bridge from companion to companion, if necessary:
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* interface A { fun foo() = 0 }
|
||||||
|
* interface B : A { }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* yields
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* interface A { fun foo(); class DefaultImpls { fun foo() = 0 } } // !! by Case 4 !!
|
||||||
|
* interface B : A { class DefaultImpls { fun foo() = A.DefaultImpls.foo() } }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
function.origin == IrDeclarationOrigin.FAKE_OVERRIDE -> {
|
||||||
|
val implementation = function.resolveFakeOverride()!!
|
||||||
|
|
||||||
if(function.hasJvmDefault() && !context.state.jvmDefaultMode.isCompatibility && !mustMoveToDefaultImpls(function)) continue
|
if (!Visibilities.isPrivate(implementation.visibility)
|
||||||
|
&& !implementation.isMethodOfAny()
|
||||||
val element = context.declarationFactory.getDefaultImplsFunction(function).also {
|
&& (!implementation.hasJvmDefault() || context.state.jvmDefaultMode.isCompatibility)
|
||||||
if (mustMoveToDefaultImpls(function))
|
) {
|
||||||
removedFunctions[function.symbol] = it.symbol
|
delegateInheritedDefaultImplementationToDefaultImpls(function, implementation, defaultImplsIrClass)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
members.add(element)
|
|
||||||
|
|
||||||
copyBodyToStatic(function, element)
|
/**
|
||||||
element.body = element.body?.patchDeclarationParents(element)
|
* 3) Private methods, default parameter dispatchers (without @JvmDefault)
|
||||||
|
* and $annotation methods are always moved without bridges
|
||||||
|
*/
|
||||||
|
Visibilities.isPrivate(function.visibility)
|
||||||
|
|| (function.origin == IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER && !function.hasJvmDefault())
|
||||||
|
|| function.origin == JvmLoweredDeclarationOrigin.SYNTHETIC_METHOD_FOR_PROPERTY_ANNOTATIONS -> {
|
||||||
|
val defaultImpl = createDefaultImpl(function, members)
|
||||||
|
removedFunctions[function.symbol] = defaultImpl.symbol
|
||||||
|
}
|
||||||
|
|
||||||
if (function.hasJvmDefault() &&
|
/**
|
||||||
function.origin != JvmLoweredDeclarationOrigin.SYNTHETIC_METHOD_FOR_PROPERTY_ANNOTATIONS
|
* 4) _Without_ @JvmDefault, the default implementation is moved to DefaultImpls and
|
||||||
) {
|
* an abstract stub is left.
|
||||||
function.body = IrExpressionBodyImpl(callDefaultImpls(element, function))
|
*/
|
||||||
} else {
|
!function.hasJvmDefault() -> {
|
||||||
|
createDefaultImpl(function, members)
|
||||||
function.body = null
|
function.body = null
|
||||||
//TODO reset modality to abstract
|
//TODO reset modality to abstract
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 5) _With_ @JvmDefault, we move and bridge if in compatibility mode, ...
|
||||||
|
*/
|
||||||
|
context.state.jvmDefaultMode.isCompatibility -> {
|
||||||
|
val defaultImpl = createDefaultImpl(function, members)
|
||||||
|
function.body = IrExpressionBodyImpl(createDelegatingCall(defaultImpl, function))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6) ... otherwise we simply leave the default function implementation on the interface.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update IrElements (e.g., IrCalls) to point to the new functions.
|
|
||||||
irClass.transformChildrenVoid(this)
|
|
||||||
|
|
||||||
irClass.declarations.removeAll {
|
irClass.declarations.removeAll {
|
||||||
it is IrFunction && removedFunctions.containsKey(it.symbol)
|
it is IrFunction && removedFunctions.containsKey(it.symbol)
|
||||||
}
|
}
|
||||||
@@ -99,14 +135,20 @@ private class InterfaceLowering(val context: JvmBackendContext) : IrElementTrans
|
|||||||
delegatedPropertyArray.parent = defaultImplsIrClass
|
delegatedPropertyArray.parent = defaultImplsIrClass
|
||||||
delegatedPropertyArray.initializer?.patchDeclarationParents(defaultImplsIrClass)
|
delegatedPropertyArray.initializer?.patchDeclarationParents(defaultImplsIrClass)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (defaultImplsIrClass.declarations.isNotEmpty()) irClass.declarations.add(defaultImplsIrClass)
|
||||||
|
// Update IrElements (e.g., IrCalls) to point to the new functions.
|
||||||
|
irClass.transformChildrenVoid(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun mustMoveToDefaultImpls(function: IrFunction): Boolean =
|
private fun createDefaultImpl(function: IrSimpleFunction, members: MutableList<IrDeclaration>): IrSimpleFunction =
|
||||||
Visibilities.isPrivate(function.visibility) && function.name != clinitName ||
|
context.declarationFactory.getDefaultImplsFunction(function).also {
|
||||||
function.origin == IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER ||
|
it.body = function.body?.patchDeclarationParents(it)
|
||||||
function.origin == JvmLoweredDeclarationOrigin.SYNTHETIC_METHOD_FOR_PROPERTY_ANNOTATIONS
|
copyBodyToStatic(function, it)
|
||||||
|
members.add(it)
|
||||||
|
}
|
||||||
|
|
||||||
private fun callDefaultImpls(defaultImpls: IrFunction, interfaceMethod: IrFunction): IrCall {
|
private fun createDelegatingCall(defaultImpls: IrFunction, interfaceMethod: IrFunction): IrCall {
|
||||||
val startOffset = interfaceMethod.startOffset
|
val startOffset = interfaceMethod.startOffset
|
||||||
val endOffset = interfaceMethod.endOffset
|
val endOffset = interfaceMethod.endOffset
|
||||||
|
|
||||||
@@ -126,6 +168,22 @@ private class InterfaceLowering(val context: JvmBackendContext) : IrElementTrans
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun delegateInheritedDefaultImplementationToDefaultImpls(
|
||||||
|
fakeOverride: IrSimpleFunction,
|
||||||
|
implementation: IrSimpleFunction,
|
||||||
|
defaultImpls: IrClass
|
||||||
|
) {
|
||||||
|
val defaultImplFun = context.declarationFactory.getDefaultImplsFunction(implementation)
|
||||||
|
val irFunction = context.declarationFactory.getDefaultImplsFunction(fakeOverride)
|
||||||
|
|
||||||
|
defaultImpls.declarations.add(irFunction)
|
||||||
|
context.createIrBuilder(irFunction.symbol, UNDEFINED_OFFSET, UNDEFINED_OFFSET).apply {
|
||||||
|
irFunction.body = irBlockBody {
|
||||||
|
+irReturn(createDelegatingCall(defaultImplFun, irFunction))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun visitReturn(expression: IrReturn): IrExpression {
|
override fun visitReturn(expression: IrReturn): IrExpression {
|
||||||
val newFunction = removedFunctions[expression.returnTargetSymbol]?.owner
|
val newFunction = removedFunctions[expression.returnTargetSymbol]?.owner
|
||||||
return super.visitReturn(
|
return super.visitReturn(
|
||||||
|
|||||||
+1
-8
@@ -36,14 +36,7 @@ import org.jetbrains.kotlin.load.java.JavaVisibilities
|
|||||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
internal val syntheticAccessorPhase = makeIrFilePhase(
|
internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrElementTransformerVoidWithContext(), FileLoweringPass {
|
||||||
::SyntheticAccessorLowering,
|
|
||||||
name = "SyntheticAccessor",
|
|
||||||
description = "Introduce synthetic accessors",
|
|
||||||
prerequisite = setOf(objectClassPhase, staticDefaultFunctionPhase)
|
|
||||||
)
|
|
||||||
|
|
||||||
private class SyntheticAccessorLowering(val context: JvmBackendContext) : IrElementTransformerVoidWithContext(), FileLoweringPass {
|
|
||||||
private val pendingTransformations = mutableListOf<Function0<Unit>>()
|
private val pendingTransformations = mutableListOf<Function0<Unit>>()
|
||||||
private val inlineLambdaToCallSite = mutableMapOf<IrFunction, IrDeclaration?>()
|
private val inlineLambdaToCallSite = mutableMapOf<IrFunction, IrDeclaration?>()
|
||||||
|
|
||||||
|
|||||||
@@ -11,12 +11,10 @@ import org.jetbrains.kotlin.descriptors.Visibility
|
|||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrBody
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol
|
import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
|
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
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.ir.visitors.IrElementVisitor
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.utils.SmartList
|
import org.jetbrains.kotlin.utils.SmartList
|
||||||
|
|||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
// !JVM_DEFAULT_MODE: compatibility
|
||||||
|
// JVM_TARGET: 1.8
|
||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
interface A {
|
||||||
|
@JvmDefault
|
||||||
|
fun foo(x: Int = 0): Int {
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TESTED_OBJECT_KIND: innerClass
|
||||||
|
// TESTED_OBJECTS: A, DefaultImpls
|
||||||
|
// FLAGS: ACC_FINAL, ACC_STATIC, ACC_PUBLIC
|
||||||
|
|
||||||
|
// TESTED_OBJECT_KIND: function
|
||||||
|
// TESTED_OBJECTS: A, foo$default
|
||||||
|
// FLAGS: ACC_PUBLIC, ACC_SYNTHETIC, ACC_STATIC
|
||||||
|
|
||||||
|
// TESTED_OBJECT_KIND: function
|
||||||
|
// TESTED_OBJECTS: A$DefaultImpls, foo$default
|
||||||
|
// FLAGS: ACC_PUBLIC, ACC_SYNTHETIC, ACC_STATIC
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
// !JVM_DEFAULT_MODE: enable
|
||||||
|
// JVM_TARGET: 1.8
|
||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
interface Test {
|
||||||
|
@JvmDefault
|
||||||
|
fun foo(): String {
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmDefault
|
||||||
|
fun bar(x: String = "OK"): String {
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TESTED_OBJECT_KIND: innerClass
|
||||||
|
// TESTED_OBJECTS: Test, DefaultImpls
|
||||||
|
// ABSENT: TRUE
|
||||||
+10
@@ -756,6 +756,11 @@ public class WriteFlagsTestGenerated extends AbstractWriteFlagsTest {
|
|||||||
runTest("compiler/testData/writeFlags/jvm8/defaults/defaultProperty.kt");
|
runTest("compiler/testData/writeFlags/jvm8/defaults/defaultProperty.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("onlyJvmDefaultsOnInterface.kt")
|
||||||
|
public void testOnlyJvmDefaultsOnInterface() throws Exception {
|
||||||
|
runTest("compiler/testData/writeFlags/jvm8/defaults/onlyJvmDefaultsOnInterface.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("propertyAnnotation.kt")
|
@TestMetadata("propertyAnnotation.kt")
|
||||||
public void testPropertyAnnotation() throws Exception {
|
public void testPropertyAnnotation() throws Exception {
|
||||||
runTest("compiler/testData/writeFlags/jvm8/defaults/propertyAnnotation.kt");
|
runTest("compiler/testData/writeFlags/jvm8/defaults/propertyAnnotation.kt");
|
||||||
@@ -773,6 +778,11 @@ public class WriteFlagsTestGenerated extends AbstractWriteFlagsTest {
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/writeFlags/jvm8/defaults/compatibility"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/writeFlags/jvm8/defaults/compatibility"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("defaultImplementations.kt")
|
||||||
|
public void testDefaultImplementations() throws Exception {
|
||||||
|
runTest("compiler/testData/writeFlags/jvm8/defaults/compatibility/defaultImplementations.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("propertyAccessors.kt")
|
@TestMetadata("propertyAccessors.kt")
|
||||||
public void testPropertyAccessors() throws Exception {
|
public void testPropertyAccessors() throws Exception {
|
||||||
runTest("compiler/testData/writeFlags/jvm8/defaults/compatibility/propertyAccessors.kt");
|
runTest("compiler/testData/writeFlags/jvm8/defaults/compatibility/propertyAccessors.kt");
|
||||||
|
|||||||
+10
@@ -756,6 +756,11 @@ public class IrWriteFlagsTestGenerated extends AbstractIrWriteFlagsTest {
|
|||||||
runTest("compiler/testData/writeFlags/jvm8/defaults/defaultProperty.kt");
|
runTest("compiler/testData/writeFlags/jvm8/defaults/defaultProperty.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("onlyJvmDefaultsOnInterface.kt")
|
||||||
|
public void testOnlyJvmDefaultsOnInterface() throws Exception {
|
||||||
|
runTest("compiler/testData/writeFlags/jvm8/defaults/onlyJvmDefaultsOnInterface.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("propertyAnnotation.kt")
|
@TestMetadata("propertyAnnotation.kt")
|
||||||
public void testPropertyAnnotation() throws Exception {
|
public void testPropertyAnnotation() throws Exception {
|
||||||
runTest("compiler/testData/writeFlags/jvm8/defaults/propertyAnnotation.kt");
|
runTest("compiler/testData/writeFlags/jvm8/defaults/propertyAnnotation.kt");
|
||||||
@@ -773,6 +778,11 @@ public class IrWriteFlagsTestGenerated extends AbstractIrWriteFlagsTest {
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/writeFlags/jvm8/defaults/compatibility"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/writeFlags/jvm8/defaults/compatibility"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("defaultImplementations.kt")
|
||||||
|
public void testDefaultImplementations() throws Exception {
|
||||||
|
runTest("compiler/testData/writeFlags/jvm8/defaults/compatibility/defaultImplementations.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("propertyAccessors.kt")
|
@TestMetadata("propertyAccessors.kt")
|
||||||
public void testPropertyAccessors() throws Exception {
|
public void testPropertyAccessors() throws Exception {
|
||||||
runTest("compiler/testData/writeFlags/jvm8/defaults/compatibility/propertyAccessors.kt");
|
runTest("compiler/testData/writeFlags/jvm8/defaults/compatibility/propertyAccessors.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user