JVM IR: Handle external static declarations in companion objects
This commit is contained in:
committed by
Alexander Udalov
parent
48db96b66d
commit
058b229544
+52
-60
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -7,7 +7,10 @@ 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.FileLoweringPass
|
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||||
import org.jetbrains.kotlin.backend.common.ir.*
|
import org.jetbrains.kotlin.backend.common.ir.copyParameterDeclarationsFrom
|
||||||
|
import org.jetbrains.kotlin.backend.common.ir.copyTo
|
||||||
|
import org.jetbrains.kotlin.backend.common.ir.copyTypeParametersFrom
|
||||||
|
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.lower.irBlock
|
import org.jetbrains.kotlin.backend.common.lower.irBlock
|
||||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||||
@@ -17,21 +20,21 @@ import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
|||||||
import org.jetbrains.kotlin.backend.jvm.ir.isInCurrentModule
|
import org.jetbrains.kotlin.backend.jvm.ir.isInCurrentModule
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.replaceThisByStaticReference
|
import org.jetbrains.kotlin.backend.jvm.ir.replaceThisByStaticReference
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
import org.jetbrains.kotlin.ir.builders.declarations.addFunction
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFunWithDescriptorForInlining
|
import org.jetbrains.kotlin.ir.builders.declarations.buildFunWithDescriptorForInlining
|
||||||
|
import org.jetbrains.kotlin.ir.builders.irCall
|
||||||
|
import org.jetbrains.kotlin.ir.builders.irExprBody
|
||||||
|
import org.jetbrains.kotlin.ir.builders.irGet
|
||||||
|
import org.jetbrains.kotlin.ir.builders.irGetField
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrBody
|
|
||||||
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
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrTypeOperator
|
import org.jetbrains.kotlin.ir.expressions.IrTypeOperator
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
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
|
||||||
import org.jetbrains.kotlin.name.Name
|
|
||||||
import org.jetbrains.kotlin.resolve.annotations.JVM_STATIC_ANNOTATION_FQ_NAME
|
import org.jetbrains.kotlin.resolve.annotations.JVM_STATIC_ANNOTATION_FQ_NAME
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
|
||||||
|
|
||||||
internal val jvmStaticAnnotationPhase = makeIrFilePhase(
|
internal val jvmStaticAnnotationPhase = makeIrFilePhase(
|
||||||
::JvmStaticAnnotationLowering,
|
::JvmStaticAnnotationLowering,
|
||||||
@@ -60,70 +63,59 @@ private class CompanionObjectJvmStaticLowering(val context: JvmBackendContext) :
|
|||||||
|
|
||||||
companion?.declarations?.filter(::isJvmStaticFunction)?.forEach { declaration ->
|
companion?.declarations?.filter(::isJvmStaticFunction)?.forEach { declaration ->
|
||||||
val jvmStaticFunction = declaration as IrSimpleFunction
|
val jvmStaticFunction = declaration as IrSimpleFunction
|
||||||
val proxy = createProxy(jvmStaticFunction, irClass, companion)
|
if (jvmStaticFunction.isExternal) {
|
||||||
irClass.addMember(proxy)
|
// We move external functions to the enclosing class and potentially add accessors there.
|
||||||
|
// The JVM backend also adds accessors in the companion object, but these are superfluous.
|
||||||
|
val staticExternal = irClass.addFunction {
|
||||||
|
updateFrom(jvmStaticFunction)
|
||||||
|
name = jvmStaticFunction.name
|
||||||
|
returnType = jvmStaticFunction.returnType
|
||||||
|
}.apply {
|
||||||
|
copyTypeParametersFrom(jvmStaticFunction)
|
||||||
|
extensionReceiverParameter = jvmStaticFunction.extensionReceiverParameter?.copyTo(this)
|
||||||
|
valueParameters = jvmStaticFunction.valueParameters.map { it.copyTo(this) }
|
||||||
|
annotations = jvmStaticFunction.annotations.map { it.deepCopyWithSymbols() }
|
||||||
|
}
|
||||||
|
companion.declarations.remove(jvmStaticFunction)
|
||||||
|
companion.addProxy(staticExternal, companion, isStatic = false)
|
||||||
|
} else {
|
||||||
|
irClass.addProxy(jvmStaticFunction, companion)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createProxy(target: IrSimpleFunction, irClass: IrClass, companion: IrClass): IrSimpleFunction {
|
private fun IrClass.addProxy(target: IrSimpleFunction, companion: IrClass, isStatic: Boolean = true) =
|
||||||
return buildFun {
|
addFunction {
|
||||||
updateFrom(target)
|
|
||||||
returnType = target.returnType
|
returnType = target.returnType
|
||||||
origin = JvmLoweredDeclarationOrigin.JVM_STATIC_WRAPPER
|
origin = JvmLoweredDeclarationOrigin.JVM_STATIC_WRAPPER
|
||||||
name = target.name
|
name = target.name
|
||||||
modality = if (irClass.isInterface) Modality.OPEN else target.modality
|
modality = if (isInterface) Modality.OPEN else target.modality
|
||||||
isInline = false
|
visibility = target.visibility
|
||||||
isExternal = false
|
isSuspend = target.isSuspend
|
||||||
isTailrec = false
|
|
||||||
isExpect = false
|
|
||||||
}.apply {
|
}.apply {
|
||||||
parent = irClass
|
|
||||||
copyTypeParametersFrom(target)
|
copyTypeParametersFrom(target)
|
||||||
target.extensionReceiverParameter?.let { extensionReceiverParameter = it.copyTo(this) }
|
if (!isStatic) {
|
||||||
|
dispatchReceiverParameter = thisReceiver?.copyTo(this, type = defaultType)
|
||||||
|
}
|
||||||
|
extensionReceiverParameter = target.extensionReceiverParameter?.copyTo(this)
|
||||||
valueParameters = target.valueParameters.map { it.copyTo(this) }
|
valueParameters = target.valueParameters.map { it.copyTo(this) }
|
||||||
|
|
||||||
annotations = target.annotations.map { it.deepCopyWithSymbols() }
|
annotations = target.annotations.map { it.deepCopyWithSymbols() }
|
||||||
|
|
||||||
body = createProxyBody(target, this, companion)
|
val proxy = this
|
||||||
|
val companionInstanceField = context.declarationFactory.getFieldForObjectInstance(companion)
|
||||||
|
body = context.createIrBuilder(symbol).run {
|
||||||
|
irExprBody(irCall(target).apply {
|
||||||
|
passTypeArgumentsFrom(proxy)
|
||||||
|
if (target.dispatchReceiverParameter != null) {
|
||||||
|
dispatchReceiver = irGetField(null, companionInstanceField)
|
||||||
|
}
|
||||||
|
extensionReceiverParameter?.let { extensionReceiver = irGet(it) }
|
||||||
|
for ((i, valueParameter) in valueParameters.withIndex()) {
|
||||||
|
putValueArgument(i, irGet(valueParameter))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private fun createProxyBody(target: IrFunction, proxy: IrFunction, companion: IrClass): IrBody {
|
|
||||||
val companionInstanceField = context.declarationFactory.getFieldForObjectInstance(companion)
|
|
||||||
val companionInstanceFieldSymbol = companionInstanceField.symbol
|
|
||||||
val call = IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, target.returnType, target.symbol)
|
|
||||||
|
|
||||||
call.passTypeArgumentsFrom(proxy)
|
|
||||||
|
|
||||||
target.dispatchReceiverParameter?.let { _ ->
|
|
||||||
call.dispatchReceiver = IrGetFieldImpl(
|
|
||||||
UNDEFINED_OFFSET,
|
|
||||||
UNDEFINED_OFFSET,
|
|
||||||
companionInstanceFieldSymbol,
|
|
||||||
companion.defaultType
|
|
||||||
)
|
|
||||||
}
|
|
||||||
proxy.extensionReceiverParameter?.let { extensionReceiver ->
|
|
||||||
call.extensionReceiver = IrGetValueImpl(
|
|
||||||
UNDEFINED_OFFSET,
|
|
||||||
UNDEFINED_OFFSET,
|
|
||||||
extensionReceiver.symbol
|
|
||||||
)
|
|
||||||
}
|
|
||||||
proxy.valueParameters.mapIndexed { i, valueParameter ->
|
|
||||||
call.putValueArgument(
|
|
||||||
i,
|
|
||||||
IrGetValueImpl(
|
|
||||||
UNDEFINED_OFFSET,
|
|
||||||
UNDEFINED_OFFSET,
|
|
||||||
valueParameter.symbol
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return IrExpressionBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, call)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SingletonObjectJvmStaticLowering(
|
private class SingletonObjectJvmStaticLowering(
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
// IGNORE_BACKEND_FIR: JVM_IR
|
||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
|
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
// IGNORE_BACKEND_FIR: JVM_IR
|
||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
|
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|||||||
Reference in New Issue
Block a user