JVM IR: handle JvmStatic in object as module phase
This allows to get rid of the situation where a JvmStatic function in object can be seen in different states in different lowerings: unlowered with a dispatch receiver parameter, declaration is lowered but calls are not, and both declaration and calls are lowered. Now it works like this: 1) JvmStatic functions in objects coming from dependencies are always loaded as lowered, without the extra dispatch receiver parameter. In psi2ir this is done via JVM-specific extension; in fir2ir it's done in place (but probably should be extracted to extension too). 2) Functions from sources are created as unlowered by both psi2ir and fir2ir, and are lowered in a module-wide phase at the beginning of JvmLower. 3) Calls to all JvmStatic functions from objects (from sources and dependencies) are lowered in the same phase at the beginning of JvmLower. This ensures that all lowerings after the module-wide phase `jvmStaticInObjectPhase`, which include all per-file phases, see all JvmStatic functions in objects without the additional dispatch receiver parameter, and calls do not have dispatch receiver either. The only issue with this approach is that function/property reference representation in reflection needs to have that dispatch receiver parameter, and that is achieved via a hack in those lowerings, which seems not too out of place anyway, given that they're handled specially in kotlin-reflect as well.
This commit is contained in:
@@ -21,6 +21,10 @@ import org.jetbrains.kotlin.ir.types.IrType
|
|||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
|
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
|
||||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
|
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
|
||||||
|
import org.jetbrains.kotlin.ir.util.hasAnnotation
|
||||||
|
import org.jetbrains.kotlin.ir.util.isNonCompanionObject
|
||||||
|
import org.jetbrains.kotlin.ir.util.isObject
|
||||||
|
import org.jetbrains.kotlin.resolve.annotations.JVM_STATIC_ANNOTATION_FQ_NAME
|
||||||
|
|
||||||
class Fir2IrLazySimpleFunction(
|
class Fir2IrLazySimpleFunction(
|
||||||
components: Fir2IrComponents,
|
components: Fir2IrComponents,
|
||||||
@@ -90,7 +94,9 @@ class Fir2IrLazySimpleFunction(
|
|||||||
|
|
||||||
override var dispatchReceiverParameter: IrValueParameter? by lazyVar {
|
override var dispatchReceiverParameter: IrValueParameter? by lazyVar {
|
||||||
val containingClass = parent as? IrClass
|
val containingClass = parent as? IrClass
|
||||||
if (!fir.isStatic && containingClass != null) {
|
if (containingClass != null && !fir.isStatic &&
|
||||||
|
!(containingClass.isNonCompanionObject && hasAnnotation(JVM_STATIC_ANNOTATION_FQ_NAME))
|
||||||
|
) {
|
||||||
declarationStorage.enterScope(this)
|
declarationStorage.enterScope(this)
|
||||||
declareThisReceiverParameter(
|
declareThisReceiverParameter(
|
||||||
symbolTable,
|
symbolTable,
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.backend.common.ir.Ir
|
|||||||
import org.jetbrains.kotlin.backend.common.lower.irThrow
|
import org.jetbrains.kotlin.backend.common.lower.irThrow
|
||||||
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
|
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
|
||||||
import org.jetbrains.kotlin.backend.jvm.codegen.*
|
import org.jetbrains.kotlin.backend.jvm.codegen.*
|
||||||
import org.jetbrains.kotlin.backend.jvm.codegen.createFakeContinuation
|
|
||||||
import org.jetbrains.kotlin.backend.jvm.descriptors.JvmSharedVariablesManager
|
import org.jetbrains.kotlin.backend.jvm.descriptors.JvmSharedVariablesManager
|
||||||
import org.jetbrains.kotlin.backend.jvm.intrinsics.IrIntrinsicMethods
|
import org.jetbrains.kotlin.backend.jvm.intrinsics.IrIntrinsicMethods
|
||||||
import org.jetbrains.kotlin.backend.jvm.lower.BridgeLowering
|
import org.jetbrains.kotlin.backend.jvm.lower.BridgeLowering
|
||||||
@@ -128,8 +127,6 @@ class JvmBackendContext(
|
|||||||
val suspendFunctionOriginalToView = mutableMapOf<IrFunction, IrFunction>()
|
val suspendFunctionOriginalToView = mutableMapOf<IrFunction, IrFunction>()
|
||||||
val fakeContinuation: IrExpression = createFakeContinuation(this)
|
val fakeContinuation: IrExpression = createFakeContinuation(this)
|
||||||
|
|
||||||
val jvmStaticObjectFunctionToStaticFunctionMap = mutableMapOf<IrSimpleFunction, IrSimpleFunction>()
|
|
||||||
|
|
||||||
val staticDefaultStubs = mutableMapOf<IrSimpleFunctionSymbol, IrSimpleFunction>()
|
val staticDefaultStubs = mutableMapOf<IrSimpleFunctionSymbol, IrSimpleFunction>()
|
||||||
|
|
||||||
val inlineClassReplacements = MemoizedInlineClassReplacements(state.functionsWithInlineClassReturnTypesMangled, irFactory, this)
|
val inlineClassReplacements = MemoizedInlineClassReplacements(state.functionsWithInlineClassReturnTypesMangled, irFactory, this)
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ import org.jetbrains.kotlin.load.kotlin.JvmPackagePartSource
|
|||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi2ir.generators.GeneratorExtensions
|
import org.jetbrains.kotlin.psi2ir.generators.GeneratorExtensions
|
||||||
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
|
import org.jetbrains.kotlin.resolve.annotations.hasJvmStaticAnnotation
|
||||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||||
import org.jetbrains.kotlin.resolve.jvm.annotations.hasJvmFieldAnnotation
|
import org.jetbrains.kotlin.resolve.jvm.annotations.hasJvmFieldAnnotation
|
||||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||||
@@ -79,6 +81,11 @@ class JvmGeneratorExtensions(private val generateFacades: Boolean = true) : Gene
|
|||||||
override fun isPropertyWithPlatformField(descriptor: PropertyDescriptor): Boolean =
|
override fun isPropertyWithPlatformField(descriptor: PropertyDescriptor): Boolean =
|
||||||
descriptor.hasJvmFieldAnnotation()
|
descriptor.hasJvmFieldAnnotation()
|
||||||
|
|
||||||
|
override fun isStaticFunction(descriptor: FunctionDescriptor): Boolean =
|
||||||
|
DescriptorUtils.isNonCompanionObject(descriptor.containingDeclaration) &&
|
||||||
|
(descriptor.hasJvmStaticAnnotation() ||
|
||||||
|
descriptor is PropertyAccessorDescriptor && descriptor.correspondingProperty.hasJvmStaticAnnotation())
|
||||||
|
|
||||||
override val enhancedNullability: EnhancedNullability
|
override val enhancedNullability: EnhancedNullability
|
||||||
get() = JvmEnhancedNullability
|
get() = JvmEnhancedNullability
|
||||||
|
|
||||||
|
|||||||
@@ -360,7 +360,7 @@ private val jvmFilePhases = listOf(
|
|||||||
initializersPhase,
|
initializersPhase,
|
||||||
initializersCleanupPhase,
|
initializersCleanupPhase,
|
||||||
functionNVarargBridgePhase,
|
functionNVarargBridgePhase,
|
||||||
jvmStaticAnnotationPhase,
|
jvmStaticInCompanionPhase,
|
||||||
staticDefaultFunctionPhase,
|
staticDefaultFunctionPhase,
|
||||||
bridgePhase,
|
bridgePhase,
|
||||||
syntheticAccessorPhase,
|
syntheticAccessorPhase,
|
||||||
@@ -392,6 +392,7 @@ val jvmPhases = NamedCompilerPhase(
|
|||||||
expectDeclarationsRemovingPhase then
|
expectDeclarationsRemovingPhase then
|
||||||
scriptsToClassesPhase then
|
scriptsToClassesPhase then
|
||||||
fileClassPhase then
|
fileClassPhase then
|
||||||
|
jvmStaticInObjectPhase then
|
||||||
performByIrFile(lower = jvmFilePhases) then
|
performByIrFile(lower = jvmFilePhases) then
|
||||||
generateMultifileFacadesPhase then
|
generateMultifileFacadesPhase then
|
||||||
resolveInlineCallsPhase then
|
resolveInlineCallsPhase then
|
||||||
|
|||||||
+18
-6
@@ -18,14 +18,12 @@ import org.jetbrains.kotlin.descriptors.Modality
|
|||||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
import org.jetbrains.kotlin.ir.builders.*
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.addConstructor
|
import org.jetbrains.kotlin.ir.builders.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.addFunction
|
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.buildClass
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrClassReferenceImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrClassReferenceImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrGetObjectValueImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
@@ -111,7 +109,9 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
|||||||
// However, when we bind a value of an inline class type as a receiver, the receiver will turn into an argument of
|
// However, when we bind a value of an inline class type as a receiver, the receiver will turn into an argument of
|
||||||
// the function in question. Yet we still need to record it as the "receiver" in CallableReference in order for reflection
|
// the function in question. Yet we still need to record it as the "receiver" in CallableReference in order for reflection
|
||||||
// to work correctly.
|
// to work correctly.
|
||||||
private val boundReceiver: Pair<IrValueParameter, IrExpression>? = irFunctionReference.getArgumentsWithIr().singleOrNull()
|
private val boundReceiver: Pair<IrValueParameter, IrExpression>? =
|
||||||
|
if (callee.isJvmStaticInObject()) createFakeBoundReceiverForJvmStaticInObject()
|
||||||
|
else irFunctionReference.getArgumentsWithIr().singleOrNull()
|
||||||
|
|
||||||
// The type of the reference is KFunction<in A1, ..., in An, out R>
|
// The type of the reference is KFunction<in A1, ..., in An, out R>
|
||||||
private val parameterTypes = (irFunctionReference.type as IrSimpleType).arguments.map { (it as IrTypeProjection).type }
|
private val parameterTypes = (irFunctionReference.type as IrSimpleType).arguments.map { (it as IrTypeProjection).type }
|
||||||
@@ -485,6 +485,19 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun createFakeBoundReceiverForJvmStaticInObject(): Pair<IrValueParameter, IrGetObjectValueImpl> {
|
||||||
|
// JvmStatic functions in objects are special in that they are generated as static methods in the bytecode, and JVM IR lowers
|
||||||
|
// both declarations and call sites early on in jvmStaticInObjectPhase because it's easier that way in subsequent lowerings.
|
||||||
|
// However from the point of view of Kotlin language (and thus reflection), these functions still take the dispatch receiver
|
||||||
|
// parameter of the object type. So we pretend here that a JvmStatic function in object has an additional dispatch receiver
|
||||||
|
// parameter, so that the correct function reference object will be created and reflective calls will work at runtime.
|
||||||
|
val objectClass = callee.parentAsClass
|
||||||
|
return buildValueParameter(callee) {
|
||||||
|
name = Name.identifier("\$this")
|
||||||
|
type = objectClass.typeWith()
|
||||||
|
} to IrGetObjectValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, objectClass.typeWith(), objectClass.symbol)
|
||||||
|
}
|
||||||
|
|
||||||
private fun createLegacyMethodOverride(
|
private fun createLegacyMethodOverride(
|
||||||
superFunction: IrSimpleFunction,
|
superFunction: IrSimpleFunction,
|
||||||
generator: JvmIrBuilder.() -> IrExpression
|
generator: JvmIrBuilder.() -> IrExpression
|
||||||
@@ -494,7 +507,6 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
|||||||
irExprBody(generator())
|
irExprBody(generator())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
+41
-102
@@ -11,23 +11,21 @@ import org.jetbrains.kotlin.backend.common.ir.*
|
|||||||
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
|
||||||
|
import org.jetbrains.kotlin.backend.common.phaser.makeIrModulePhase
|
||||||
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
|
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
|
||||||
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.copyCorrespondingPropertyFrom
|
|
||||||
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.DescriptorVisibilities
|
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.addFunction
|
import org.jetbrains.kotlin.ir.builders.declarations.addFunction
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
|
||||||
import org.jetbrains.kotlin.ir.builders.irCall
|
import org.jetbrains.kotlin.ir.builders.irCall
|
||||||
import org.jetbrains.kotlin.ir.builders.irExprBody
|
import org.jetbrains.kotlin.ir.builders.irExprBody
|
||||||
import org.jetbrains.kotlin.ir.builders.irGet
|
import org.jetbrains.kotlin.ir.builders.irGet
|
||||||
import org.jetbrains.kotlin.ir.builders.irGetField
|
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.IrCall
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrTypeOperator
|
import org.jetbrains.kotlin.ir.expressions.IrTypeOperator
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
@@ -36,35 +34,37 @@ import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
|||||||
import org.jetbrains.kotlin.name.Name
|
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
|
||||||
|
|
||||||
internal val jvmStaticAnnotationPhase = makeIrFilePhase(
|
internal val jvmStaticInObjectPhase = makeIrModulePhase(
|
||||||
::JvmStaticAnnotationLowering,
|
::JvmStaticInObjectLowering,
|
||||||
name = "JvmStaticAnnotation",
|
name = "JvmStaticInObject",
|
||||||
description = "Handle JvmStatic annotations"
|
description = "Make JvmStatic functions in non-companion objects static and replace all call sites in the module"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
internal val jvmStaticInCompanionPhase = makeIrFilePhase(
|
||||||
* For @JvmStatic functions within companion objects of classes, we synthesize proxy static functions that redirect
|
::JvmStaticInCompanionLowering,
|
||||||
* to the actual implementation.
|
name = "JvmStaticInCompanion",
|
||||||
* For @JvmStatic functions within static objects, we make the actual function static and modify all call sites.
|
description = "Synthesize static proxy functions for JvmStatic functions in companion objects"
|
||||||
*/
|
)
|
||||||
private class JvmStaticAnnotationLowering(val context: JvmBackendContext) : IrElementTransformerVoid(), FileLoweringPass {
|
|
||||||
|
private class JvmStaticInObjectLowering(val context: JvmBackendContext) : IrElementTransformerVoid(), FileLoweringPass {
|
||||||
override fun lower(irFile: IrFile) {
|
override fun lower(irFile: IrFile) {
|
||||||
CompanionObjectJvmStaticLowering(context).runOnFilePostfix(irFile)
|
|
||||||
SingletonObjectJvmStaticLowering(context).runOnFilePostfix(irFile)
|
SingletonObjectJvmStaticLowering(context).runOnFilePostfix(irFile)
|
||||||
irFile.transformChildrenVoid(MakeCallsStatic(context))
|
irFile.transformChildrenVoid(MakeCallsStatic(context))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class CompanionObjectJvmStaticLowering(val context: JvmBackendContext) : ClassLoweringPass {
|
private class JvmStaticInCompanionLowering(val context: JvmBackendContext) : IrElementTransformerVoid(), ClassLoweringPass {
|
||||||
override fun lower(irClass: IrClass) {
|
override fun lower(irClass: IrClass) {
|
||||||
val companion = irClass.declarations.find {
|
val companion = irClass.companionObject() ?: return
|
||||||
it is IrClass && it.isCompanion
|
|
||||||
} as? IrClass ?: return
|
|
||||||
|
|
||||||
companion.declarations
|
companion.declarations
|
||||||
// In case of companion objects, proxy functions for '$default' methods for @JvmStatic functions with default parameters
|
// In case of companion objects, proxy functions for '$default' methods for @JvmStatic functions with default parameters
|
||||||
// are not created in the host class.
|
// are not created in the host class.
|
||||||
.filter { isJvmStaticFunction(it) && it.origin != IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER }
|
.filter {
|
||||||
|
it.isJvmStaticDeclaration() &&
|
||||||
|
it.origin != IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER &&
|
||||||
|
it.origin != JvmLoweredDeclarationOrigin.SYNTHETIC_METHOD_FOR_PROPERTY_ANNOTATIONS
|
||||||
|
}
|
||||||
.forEach { declaration ->
|
.forEach { declaration ->
|
||||||
val jvmStaticFunction = declaration as IrSimpleFunction
|
val jvmStaticFunction = declaration as IrSimpleFunction
|
||||||
if (jvmStaticFunction.isExternal) {
|
if (jvmStaticFunction.isExternal) {
|
||||||
@@ -129,107 +129,46 @@ private class CompanionObjectJvmStaticLowering(val context: JvmBackendContext) :
|
|||||||
|
|
||||||
private class SingletonObjectJvmStaticLowering(val context: JvmBackendContext) : ClassLoweringPass {
|
private class SingletonObjectJvmStaticLowering(val context: JvmBackendContext) : ClassLoweringPass {
|
||||||
override fun lower(irClass: IrClass) {
|
override fun lower(irClass: IrClass) {
|
||||||
if (!irClass.isObject || irClass.isCompanion) return
|
if (!irClass.isNonCompanionObject) return
|
||||||
|
|
||||||
val jvmStaticFunctionsToReplace = irClass.declarations.filter {
|
for (function in irClass.simpleFunctions()) {
|
||||||
// dispatch receiver parameter is already null for synthetic property annotation methods
|
if (function.isJvmStaticDeclaration()) {
|
||||||
isJvmStaticFunction(it) && it is IrSimpleFunction && it.dispatchReceiverParameter != null
|
// dispatch receiver parameter is already null for synthetic property annotation methods
|
||||||
}
|
function.dispatchReceiverParameter?.let { oldDispatchReceiverParameter ->
|
||||||
jvmStaticFunctionsToReplace.forEach { function ->
|
function.dispatchReceiverParameter = null
|
||||||
val replacement = createReplacement(context, function as IrSimpleFunction)
|
function.replaceThisByStaticReference(context.cachedDeclarations, irClass, oldDispatchReceiverParameter)
|
||||||
// Set dispatch receiver parameter for body move operation.
|
}
|
||||||
replacement.dispatchReceiverParameter = function.dispatchReceiverParameter
|
}
|
||||||
replacement.body = function.moveBodyTo(replacement)
|
|
||||||
replacement.replaceThisByStaticReference(context.cachedDeclarations, irClass, function.dispatchReceiverParameter!!)
|
|
||||||
// Clear dispatch receiver parameter again after body move operation.
|
|
||||||
replacement.dispatchReceiverParameter = null
|
|
||||||
irClass.declarations.remove(function)
|
|
||||||
irClass.declarations.add(replacement)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createReplacement(
|
internal fun IrDeclaration.isJvmStaticInObject(): Boolean =
|
||||||
context: JvmBackendContext,
|
isJvmStaticDeclaration() && (parent as? IrClass)?.isNonCompanionObject == true
|
||||||
jvmStaticFunction: IrSimpleFunction
|
|
||||||
): IrSimpleFunction =
|
|
||||||
context.jvmStaticObjectFunctionToStaticFunctionMap.getOrPut(jvmStaticFunction) {
|
|
||||||
val irClass = jvmStaticFunction.parentAsClass
|
|
||||||
val newFunction = context.irFactory.buildFun {
|
|
||||||
updateFrom(jvmStaticFunction)
|
|
||||||
name = jvmStaticFunction.name
|
|
||||||
returnType = jvmStaticFunction.returnType
|
|
||||||
}.apply {
|
|
||||||
parent = irClass
|
|
||||||
copyTypeParametersFrom(jvmStaticFunction)
|
|
||||||
copyAnnotationsFrom(jvmStaticFunction)
|
|
||||||
extensionReceiverParameter = jvmStaticFunction.extensionReceiverParameter?.copyTo(this)
|
|
||||||
valueParameters = jvmStaticFunction.valueParameters.map { it.copyTo(this) }
|
|
||||||
copyAttributes(jvmStaticFunction)
|
|
||||||
copyCorrespondingPropertyFrom(jvmStaticFunction)
|
|
||||||
metadata = jvmStaticFunction.metadata
|
|
||||||
}
|
|
||||||
context.jvmStaticObjectFunctionToStaticFunctionMap[jvmStaticFunction] = newFunction
|
|
||||||
newFunction
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private fun IrFunction.isJvmStaticInSingleton(): Boolean {
|
|
||||||
val parentClass = parent as? IrClass ?: return false
|
|
||||||
return isJvmStaticFunction(this) && parentClass.isObject && !parentClass.isCompanion
|
|
||||||
}
|
|
||||||
|
|
||||||
private class MakeCallsStatic(val context: JvmBackendContext) : IrElementTransformerVoid() {
|
private class MakeCallsStatic(val context: JvmBackendContext) : IrElementTransformerVoid() {
|
||||||
override fun visitCall(expression: IrCall): IrExpression {
|
override fun visitMemberAccess(expression: IrMemberAccessExpression<*>): IrExpression {
|
||||||
if (expression.symbol.owner.isJvmStaticInSingleton() && expression.dispatchReceiver != null) {
|
val callee = expression.symbol.owner
|
||||||
// Imported functions do not have their receiver parameter nulled by SingletonObjectJvmStaticLowering,
|
if (callee is IrDeclaration && callee.isJvmStaticInObject() && expression.dispatchReceiver != null) {
|
||||||
// so we have to do it here.
|
|
||||||
// TODO: would be better handled by lowering imported declarations.
|
|
||||||
val callee = expression.symbol.owner
|
|
||||||
val newCallee = if (!callee.isInCurrentModule()) {
|
|
||||||
callee.copyRemovingDispatchReceiver() // TODO: cache these
|
|
||||||
} else {
|
|
||||||
createReplacement(context, callee)
|
|
||||||
}
|
|
||||||
|
|
||||||
return context.createIrBuilder(expression.symbol, expression.startOffset, expression.endOffset).irBlock(expression) {
|
return context.createIrBuilder(expression.symbol, expression.startOffset, expression.endOffset).irBlock(expression) {
|
||||||
// OldReceiver has to be evaluated for its side effects.
|
// OldReceiver has to be evaluated for its side effects.
|
||||||
val oldReceiver = super.visitExpression(expression.dispatchReceiver!!)
|
val oldReceiver = super.visitExpression(expression.dispatchReceiver!!)
|
||||||
// `coerceToUnit()` is private in InsertImplicitCasts, have to reproduce it here
|
// `coerceToUnit()` is private in InsertImplicitCasts, have to reproduce it here
|
||||||
val oldReceiverVoid = IrTypeOperatorCallImpl(
|
+IrTypeOperatorCallImpl(
|
||||||
oldReceiver.startOffset, oldReceiver.endOffset,
|
oldReceiver.startOffset, oldReceiver.endOffset,
|
||||||
context.irBuiltIns.unitType,
|
context.irBuiltIns.unitType,
|
||||||
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT,
|
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT,
|
||||||
context.irBuiltIns.unitType,
|
context.irBuiltIns.unitType,
|
||||||
oldReceiver
|
oldReceiver
|
||||||
)
|
)
|
||||||
|
expression.dispatchReceiver = null
|
||||||
+super.visitExpression(oldReceiverVoid)
|
+super.visitMemberAccess(expression)
|
||||||
+super.visitCall(
|
|
||||||
irCall(expression, newFunction = newCallee).apply { dispatchReceiver = null }
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return super.visitCall(expression)
|
return super.visitMemberAccess(expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun IrSimpleFunction.copyRemovingDispatchReceiver(): IrSimpleFunction =
|
|
||||||
factory.buildFun {
|
|
||||||
updateFrom(this@copyRemovingDispatchReceiver)
|
|
||||||
name = this@copyRemovingDispatchReceiver.name
|
|
||||||
returnType = this@copyRemovingDispatchReceiver.returnType
|
|
||||||
}.also {
|
|
||||||
it.parent = parent
|
|
||||||
it.copyCorrespondingPropertyFrom(this)
|
|
||||||
it.annotations += annotations
|
|
||||||
it.copyParameterDeclarationsFrom(this)
|
|
||||||
it.dispatchReceiverParameter = null
|
|
||||||
it.copyAttributes(this)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isJvmStaticFunction(declaration: IrDeclaration): Boolean =
|
private fun IrDeclaration.isJvmStaticDeclaration(): Boolean =
|
||||||
declaration is IrSimpleFunction &&
|
hasAnnotation(JVM_STATIC_ANNOTATION_FQ_NAME) ||
|
||||||
(declaration.hasAnnotation(JVM_STATIC_ANNOTATION_FQ_NAME) ||
|
(this as? IrSimpleFunction)?.correspondingPropertySymbol?.owner?.hasAnnotation(JVM_STATIC_ANNOTATION_FQ_NAME) == true
|
||||||
declaration.correspondingPropertySymbol?.owner?.hasAnnotation(JVM_STATIC_ANNOTATION_FQ_NAME) == true) &&
|
|
||||||
declaration.origin != JvmLoweredDeclarationOrigin.SYNTHETIC_METHOD_FOR_PROPERTY_ANNOTATIONS
|
|
||||||
|
|||||||
+2
-5
@@ -23,10 +23,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl
|
|||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl
|
import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl
|
||||||
import org.jetbrains.kotlin.ir.util.filterOutAnnotations
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.ir.util.isObject
|
|
||||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
|
||||||
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.resolve.deprecation.DeprecationResolver
|
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
|
||||||
|
|
||||||
@@ -45,7 +42,7 @@ internal val remapObjectFieldAccesses = makeIrFilePhase(
|
|||||||
|
|
||||||
private class MoveOrCopyCompanionObjectFieldsLowering(val context: JvmBackendContext) : ClassLoweringPass {
|
private class MoveOrCopyCompanionObjectFieldsLowering(val context: JvmBackendContext) : ClassLoweringPass {
|
||||||
override fun lower(irClass: IrClass) {
|
override fun lower(irClass: IrClass) {
|
||||||
if (irClass.isObject && !irClass.isCompanion) {
|
if (irClass.isNonCompanionObject) {
|
||||||
irClass.handle()
|
irClass.handle()
|
||||||
} else {
|
} else {
|
||||||
(irClass.declarations.singleOrNull { it is IrClass && it.isCompanion } as IrClass?)?.handle()
|
(irClass.declarations.singleOrNull { it is IrClass && it.isCompanion } as IrClass?)?.handle()
|
||||||
|
|||||||
+13
-5
@@ -31,11 +31,13 @@ import org.jetbrains.kotlin.ir.builders.declarations.*
|
|||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrGetObjectValueImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
|
||||||
import org.jetbrains.kotlin.ir.symbols.*
|
import org.jetbrains.kotlin.ir.symbols.*
|
||||||
import org.jetbrains.kotlin.ir.types.createType
|
import org.jetbrains.kotlin.ir.types.createType
|
||||||
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
||||||
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
|
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
|
||||||
|
import org.jetbrains.kotlin.ir.types.typeWith
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.load.java.JavaDescriptorVisibilities
|
import org.jetbrains.kotlin.load.java.JavaDescriptorVisibilities
|
||||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||||
@@ -301,9 +303,7 @@ private class PropertyReferenceLowering(val context: JvmBackendContext) : IrElem
|
|||||||
return context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset).irBlock {
|
return context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset).irBlock {
|
||||||
+referenceClass
|
+referenceClass
|
||||||
+irCall(referenceClass.constructors.single()).apply {
|
+irCall(referenceClass.constructors.single()).apply {
|
||||||
var index = 0
|
expression.getBoundReceiver()?.let { putValueArgument(0, it) }
|
||||||
expression.dispatchReceiver?.let { putValueArgument(index++, it) }
|
|
||||||
expression.extensionReceiver?.let { putValueArgument(index++, it) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -397,8 +397,7 @@ private class PropertyReferenceLowering(val context: JvmBackendContext) : IrElem
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun addConstructor(expression: IrCallableReference<*>, referenceClass: IrClass, superClass: IrClass) {
|
private fun addConstructor(expression: IrCallableReference<*>, referenceClass: IrClass, superClass: IrClass) {
|
||||||
// See propertyReferenceKindFor -- only one of them could ever be present.
|
val hasBoundReceiver = expression.getBoundReceiver() != null
|
||||||
val hasBoundReceiver = expression.dispatchReceiver != null || expression.extensionReceiver != null
|
|
||||||
val numOfSuperArgs =
|
val numOfSuperArgs =
|
||||||
(if (hasBoundReceiver) 1 else 0) + (if (useOptimizedSuperClass) 4 else 0)
|
(if (hasBoundReceiver) 1 else 0) + (if (useOptimizedSuperClass) 4 else 0)
|
||||||
val superConstructor = superClass.constructors.single { it.valueParameters.size == numOfSuperArgs }
|
val superConstructor = superClass.constructors.single { it.valueParameters.size == numOfSuperArgs }
|
||||||
@@ -434,4 +433,13 @@ private class PropertyReferenceLowering(val context: JvmBackendContext) : IrElem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun IrCallableReference<*>.getBoundReceiver(): IrExpression? {
|
||||||
|
val callee = symbol.owner
|
||||||
|
return if (callee is IrDeclaration && callee.isJvmStaticInObject()) {
|
||||||
|
// See FunctionReferenceLowering.FunctionReferenceBuilder.createFakeBoundReceiverForJvmStaticInObject.
|
||||||
|
val objectClass = callee.parentAsClass
|
||||||
|
IrGetObjectValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, objectClass.typeWith(), objectClass.symbol)
|
||||||
|
} else dispatchReceiver ?: extensionReceiver
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -36,7 +36,7 @@ internal val staticDefaultFunctionPhase = makeIrFilePhase(
|
|||||||
::StaticDefaultFunctionLowering,
|
::StaticDefaultFunctionLowering,
|
||||||
name = "StaticDefaultFunction",
|
name = "StaticDefaultFunction",
|
||||||
description = "Make function adapters for default arguments static",
|
description = "Make function adapters for default arguments static",
|
||||||
prerequisite = setOf(jvmStaticAnnotationPhase),
|
prerequisite = setOf(jvmStaticInObjectPhase),
|
||||||
)
|
)
|
||||||
|
|
||||||
private class StaticDefaultFunctionLowering(val context: JvmBackendContext) : IrElementTransformerVoid(), FileLoweringPass {
|
private class StaticDefaultFunctionLowering(val context: JvmBackendContext) : IrElementTransformerVoid(), FileLoweringPass {
|
||||||
|
|||||||
@@ -5,9 +5,9 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.ir.declarations.lazy
|
package org.jetbrains.kotlin.ir.declarations.lazy
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
|
|
||||||
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
||||||
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.IrBody
|
||||||
@@ -54,7 +54,7 @@ class IrLazyFunction(
|
|||||||
|
|
||||||
override val initialSignatureFunction: IrFunction? by createInitialSignatureFunction()
|
override val initialSignatureFunction: IrFunction? by createInitialSignatureFunction()
|
||||||
|
|
||||||
override var dispatchReceiverParameter: IrValueParameter? by createReceiverParameter(descriptor.dispatchReceiverParameter)
|
override var dispatchReceiverParameter: IrValueParameter? by createReceiverParameter(descriptor.dispatchReceiverParameter, true)
|
||||||
|
|
||||||
override var extensionReceiverParameter: IrValueParameter? by createReceiverParameter(descriptor.extensionReceiverParameter)
|
override var extensionReceiverParameter: IrValueParameter? by createReceiverParameter(descriptor.extensionReceiverParameter)
|
||||||
|
|
||||||
|
|||||||
+6
-2
@@ -34,9 +34,13 @@ interface IrLazyFunctionBase : IrLazyDeclarationBase, IrTypeParametersContainer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createReceiverParameter(parameter: ReceiverParameterDescriptor?): ReadWriteProperty<Any?, IrValueParameter?> =
|
fun createReceiverParameter(
|
||||||
|
parameter: ReceiverParameterDescriptor?,
|
||||||
|
functionDispatchReceiver: Boolean = false,
|
||||||
|
): ReadWriteProperty<Any?, IrValueParameter?> =
|
||||||
lazyVar {
|
lazyVar {
|
||||||
typeTranslator.buildWithScope(this) {
|
if (functionDispatchReceiver && stubGenerator.extensions.isStaticFunction(descriptor)) null
|
||||||
|
else typeTranslator.buildWithScope(this) {
|
||||||
parameter?.generateReceiverParameterStub()?.also { it.parent = this@IrLazyFunctionBase }
|
parameter?.generateReceiverParameterStub()?.also { it.parent = this@IrLazyFunctionBase }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -259,6 +259,7 @@ val IrClass.isInterface get() = kind == ClassKind.INTERFACE
|
|||||||
val IrClass.isClass get() = kind == ClassKind.CLASS
|
val IrClass.isClass get() = kind == ClassKind.CLASS
|
||||||
val IrClass.isObject get() = kind == ClassKind.OBJECT
|
val IrClass.isObject get() = kind == ClassKind.OBJECT
|
||||||
val IrClass.isAnonymousObject get() = isClass && name == SpecialNames.NO_NAME_PROVIDED
|
val IrClass.isAnonymousObject get() = isClass && name == SpecialNames.NO_NAME_PROVIDED
|
||||||
|
val IrClass.isNonCompanionObject: Boolean get() = isObject && !isCompanion
|
||||||
val IrDeclarationWithName.fqNameWhenAvailable: FqName?
|
val IrDeclarationWithName.fqNameWhenAvailable: FqName?
|
||||||
get() = when (val parent = parent) {
|
get() = when (val parent = parent) {
|
||||||
is IrDeclarationWithName -> parent.fqNameWhenAvailable?.child(name)
|
is IrDeclarationWithName -> parent.fqNameWhenAvailable?.child(name)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.ir.util
|
package org.jetbrains.kotlin.ir.util
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||||
@@ -21,6 +22,8 @@ open class StubGeneratorExtensions {
|
|||||||
|
|
||||||
open fun isPropertyWithPlatformField(descriptor: PropertyDescriptor): Boolean = false
|
open fun isPropertyWithPlatformField(descriptor: PropertyDescriptor): Boolean = false
|
||||||
|
|
||||||
|
open fun isStaticFunction(descriptor: FunctionDescriptor): Boolean = false
|
||||||
|
|
||||||
open val enhancedNullability: EnhancedNullability
|
open val enhancedNullability: EnhancedNullability
|
||||||
get() = EnhancedNullability
|
get() = EnhancedNullability
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user