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.serialization.deserialization.descriptors.DeserializedContainerSource
|
||||
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(
|
||||
components: Fir2IrComponents,
|
||||
@@ -90,7 +94,9 @@ class Fir2IrLazySimpleFunction(
|
||||
|
||||
override var dispatchReceiverParameter: IrValueParameter? by lazyVar {
|
||||
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)
|
||||
declareThisReceiverParameter(
|
||||
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.phaser.PhaseConfig
|
||||
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.intrinsics.IrIntrinsicMethods
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.BridgeLowering
|
||||
@@ -128,8 +127,6 @@ class JvmBackendContext(
|
||||
val suspendFunctionOriginalToView = mutableMapOf<IrFunction, IrFunction>()
|
||||
val fakeContinuation: IrExpression = createFakeContinuation(this)
|
||||
|
||||
val jvmStaticObjectFunctionToStaticFunctionMap = mutableMapOf<IrSimpleFunction, IrSimpleFunction>()
|
||||
|
||||
val staticDefaultStubs = mutableMapOf<IrSimpleFunctionSymbol, IrSimpleFunction>()
|
||||
|
||||
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.Name
|
||||
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.annotations.hasJvmFieldAnnotation
|
||||
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 =
|
||||
descriptor.hasJvmFieldAnnotation()
|
||||
|
||||
override fun isStaticFunction(descriptor: FunctionDescriptor): Boolean =
|
||||
DescriptorUtils.isNonCompanionObject(descriptor.containingDeclaration) &&
|
||||
(descriptor.hasJvmStaticAnnotation() ||
|
||||
descriptor is PropertyAccessorDescriptor && descriptor.correspondingProperty.hasJvmStaticAnnotation())
|
||||
|
||||
override val enhancedNullability: EnhancedNullability
|
||||
get() = JvmEnhancedNullability
|
||||
|
||||
|
||||
@@ -360,7 +360,7 @@ private val jvmFilePhases = listOf(
|
||||
initializersPhase,
|
||||
initializersCleanupPhase,
|
||||
functionNVarargBridgePhase,
|
||||
jvmStaticAnnotationPhase,
|
||||
jvmStaticInCompanionPhase,
|
||||
staticDefaultFunctionPhase,
|
||||
bridgePhase,
|
||||
syntheticAccessorPhase,
|
||||
@@ -392,6 +392,7 @@ val jvmPhases = NamedCompilerPhase(
|
||||
expectDeclarationsRemovingPhase then
|
||||
scriptsToClassesPhase then
|
||||
fileClassPhase then
|
||||
jvmStaticInObjectPhase then
|
||||
performByIrFile(lower = jvmFilePhases) then
|
||||
generateMultifileFacadesPhase 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.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addConstructor
|
||||
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.builders.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrClassReferenceImpl
|
||||
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.symbols.IrFunctionSymbol
|
||||
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
|
||||
// the function in question. Yet we still need to record it as the "receiver" in CallableReference in order for reflection
|
||||
// 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>
|
||||
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(
|
||||
superFunction: IrSimpleFunction,
|
||||
generator: JvmIrBuilder.() -> IrExpression
|
||||
@@ -494,7 +507,6 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
||||
irExprBody(generator())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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.irBlock
|
||||
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.jvm.JvmBackendContext
|
||||
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.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
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.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.expressions.IrCall
|
||||
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.impl.IrTypeOperatorCallImpl
|
||||
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.resolve.annotations.JVM_STATIC_ANNOTATION_FQ_NAME
|
||||
|
||||
internal val jvmStaticAnnotationPhase = makeIrFilePhase(
|
||||
::JvmStaticAnnotationLowering,
|
||||
name = "JvmStaticAnnotation",
|
||||
description = "Handle JvmStatic annotations"
|
||||
internal val jvmStaticInObjectPhase = makeIrModulePhase(
|
||||
::JvmStaticInObjectLowering,
|
||||
name = "JvmStaticInObject",
|
||||
description = "Make JvmStatic functions in non-companion objects static and replace all call sites in the module"
|
||||
)
|
||||
|
||||
/*
|
||||
* For @JvmStatic functions within companion objects of classes, we synthesize proxy static functions that redirect
|
||||
* to the actual implementation.
|
||||
* For @JvmStatic functions within static objects, we make the actual function static and modify all call sites.
|
||||
*/
|
||||
private class JvmStaticAnnotationLowering(val context: JvmBackendContext) : IrElementTransformerVoid(), FileLoweringPass {
|
||||
internal val jvmStaticInCompanionPhase = makeIrFilePhase(
|
||||
::JvmStaticInCompanionLowering,
|
||||
name = "JvmStaticInCompanion",
|
||||
description = "Synthesize static proxy functions for JvmStatic functions in companion objects"
|
||||
)
|
||||
|
||||
private class JvmStaticInObjectLowering(val context: JvmBackendContext) : IrElementTransformerVoid(), FileLoweringPass {
|
||||
override fun lower(irFile: IrFile) {
|
||||
CompanionObjectJvmStaticLowering(context).runOnFilePostfix(irFile)
|
||||
SingletonObjectJvmStaticLowering(context).runOnFilePostfix(irFile)
|
||||
irFile.transformChildrenVoid(MakeCallsStatic(context))
|
||||
}
|
||||
}
|
||||
|
||||
private class CompanionObjectJvmStaticLowering(val context: JvmBackendContext) : ClassLoweringPass {
|
||||
private class JvmStaticInCompanionLowering(val context: JvmBackendContext) : IrElementTransformerVoid(), ClassLoweringPass {
|
||||
override fun lower(irClass: IrClass) {
|
||||
val companion = irClass.declarations.find {
|
||||
it is IrClass && it.isCompanion
|
||||
} as? IrClass ?: return
|
||||
val companion = irClass.companionObject() ?: return
|
||||
|
||||
companion.declarations
|
||||
// In case of companion objects, proxy functions for '$default' methods for @JvmStatic functions with default parameters
|
||||
// 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 ->
|
||||
val jvmStaticFunction = declaration as IrSimpleFunction
|
||||
if (jvmStaticFunction.isExternal) {
|
||||
@@ -129,107 +129,46 @@ private class CompanionObjectJvmStaticLowering(val context: JvmBackendContext) :
|
||||
|
||||
private class SingletonObjectJvmStaticLowering(val context: JvmBackendContext) : ClassLoweringPass {
|
||||
override fun lower(irClass: IrClass) {
|
||||
if (!irClass.isObject || irClass.isCompanion) return
|
||||
if (!irClass.isNonCompanionObject) return
|
||||
|
||||
val jvmStaticFunctionsToReplace = irClass.declarations.filter {
|
||||
// dispatch receiver parameter is already null for synthetic property annotation methods
|
||||
isJvmStaticFunction(it) && it is IrSimpleFunction && it.dispatchReceiverParameter != null
|
||||
}
|
||||
jvmStaticFunctionsToReplace.forEach { function ->
|
||||
val replacement = createReplacement(context, function as IrSimpleFunction)
|
||||
// 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)
|
||||
for (function in irClass.simpleFunctions()) {
|
||||
if (function.isJvmStaticDeclaration()) {
|
||||
// dispatch receiver parameter is already null for synthetic property annotation methods
|
||||
function.dispatchReceiverParameter?.let { oldDispatchReceiverParameter ->
|
||||
function.dispatchReceiverParameter = null
|
||||
function.replaceThisByStaticReference(context.cachedDeclarations, irClass, oldDispatchReceiverParameter)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createReplacement(
|
||||
context: JvmBackendContext,
|
||||
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
|
||||
}
|
||||
internal fun IrDeclaration.isJvmStaticInObject(): Boolean =
|
||||
isJvmStaticDeclaration() && (parent as? IrClass)?.isNonCompanionObject == true
|
||||
|
||||
private class MakeCallsStatic(val context: JvmBackendContext) : IrElementTransformerVoid() {
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
if (expression.symbol.owner.isJvmStaticInSingleton() && expression.dispatchReceiver != null) {
|
||||
// Imported functions do not have their receiver parameter nulled by SingletonObjectJvmStaticLowering,
|
||||
// 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)
|
||||
}
|
||||
|
||||
override fun visitMemberAccess(expression: IrMemberAccessExpression<*>): IrExpression {
|
||||
val callee = expression.symbol.owner
|
||||
if (callee is IrDeclaration && callee.isJvmStaticInObject() && expression.dispatchReceiver != null) {
|
||||
return context.createIrBuilder(expression.symbol, expression.startOffset, expression.endOffset).irBlock(expression) {
|
||||
// OldReceiver has to be evaluated for its side effects.
|
||||
val oldReceiver = super.visitExpression(expression.dispatchReceiver!!)
|
||||
// `coerceToUnit()` is private in InsertImplicitCasts, have to reproduce it here
|
||||
val oldReceiverVoid = IrTypeOperatorCallImpl(
|
||||
+IrTypeOperatorCallImpl(
|
||||
oldReceiver.startOffset, oldReceiver.endOffset,
|
||||
context.irBuiltIns.unitType,
|
||||
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT,
|
||||
context.irBuiltIns.unitType,
|
||||
oldReceiver
|
||||
)
|
||||
|
||||
+super.visitExpression(oldReceiverVoid)
|
||||
+super.visitCall(
|
||||
irCall(expression, newFunction = newCallee).apply { dispatchReceiver = null }
|
||||
)
|
||||
expression.dispatchReceiver = null
|
||||
+super.visitMemberAccess(expression)
|
||||
}
|
||||
}
|
||||
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 =
|
||||
declaration is IrSimpleFunction &&
|
||||
(declaration.hasAnnotation(JVM_STATIC_ANNOTATION_FQ_NAME) ||
|
||||
declaration.correspondingPropertySymbol?.owner?.hasAnnotation(JVM_STATIC_ANNOTATION_FQ_NAME) == true) &&
|
||||
declaration.origin != JvmLoweredDeclarationOrigin.SYNTHETIC_METHOD_FOR_PROPERTY_ANNOTATIONS
|
||||
private fun IrDeclaration.isJvmStaticDeclaration(): Boolean =
|
||||
hasAnnotation(JVM_STATIC_ANNOTATION_FQ_NAME) ||
|
||||
(this as? IrSimpleFunction)?.correspondingPropertySymbol?.owner?.hasAnnotation(JVM_STATIC_ANNOTATION_FQ_NAME) == true
|
||||
|
||||
+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.IrSetFieldImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.util.filterOutAnnotations
|
||||
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.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
|
||||
|
||||
@@ -45,7 +42,7 @@ internal val remapObjectFieldAccesses = makeIrFilePhase(
|
||||
|
||||
private class MoveOrCopyCompanionObjectFieldsLowering(val context: JvmBackendContext) : ClassLoweringPass {
|
||||
override fun lower(irClass: IrClass) {
|
||||
if (irClass.isObject && !irClass.isCompanion) {
|
||||
if (irClass.isNonCompanionObject) {
|
||||
irClass.handle()
|
||||
} else {
|
||||
(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.expressions.*
|
||||
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.symbols.*
|
||||
import org.jetbrains.kotlin.ir.types.createType
|
||||
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
||||
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.load.java.JavaDescriptorVisibilities
|
||||
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 {
|
||||
+referenceClass
|
||||
+irCall(referenceClass.constructors.single()).apply {
|
||||
var index = 0
|
||||
expression.dispatchReceiver?.let { putValueArgument(index++, it) }
|
||||
expression.extensionReceiver?.let { putValueArgument(index++, it) }
|
||||
expression.getBoundReceiver()?.let { putValueArgument(0, it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -397,8 +397,7 @@ private class PropertyReferenceLowering(val context: JvmBackendContext) : IrElem
|
||||
}
|
||||
|
||||
private fun addConstructor(expression: IrCallableReference<*>, referenceClass: IrClass, superClass: IrClass) {
|
||||
// See propertyReferenceKindFor -- only one of them could ever be present.
|
||||
val hasBoundReceiver = expression.dispatchReceiver != null || expression.extensionReceiver != null
|
||||
val hasBoundReceiver = expression.getBoundReceiver() != null
|
||||
val numOfSuperArgs =
|
||||
(if (hasBoundReceiver) 1 else 0) + (if (useOptimizedSuperClass) 4 else 0)
|
||||
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,
|
||||
name = "StaticDefaultFunction",
|
||||
description = "Make function adapters for default arguments static",
|
||||
prerequisite = setOf(jvmStaticAnnotationPhase),
|
||||
prerequisite = setOf(jvmStaticInObjectPhase),
|
||||
)
|
||||
|
||||
private class StaticDefaultFunctionLowering(val context: JvmBackendContext) : IrElementTransformerVoid(), FileLoweringPass {
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.declarations.lazy
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
|
||||
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBody
|
||||
@@ -54,7 +54,7 @@ class IrLazyFunction(
|
||||
|
||||
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)
|
||||
|
||||
|
||||
+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 {
|
||||
typeTranslator.buildWithScope(this) {
|
||||
if (functionDispatchReceiver && stubGenerator.extensions.isStaticFunction(descriptor)) null
|
||||
else typeTranslator.buildWithScope(this) {
|
||||
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.isObject get() = kind == ClassKind.OBJECT
|
||||
val IrClass.isAnonymousObject get() = isClass && name == SpecialNames.NO_NAME_PROVIDED
|
||||
val IrClass.isNonCompanionObject: Boolean get() = isObject && !isCompanion
|
||||
val IrDeclarationWithName.fqNameWhenAvailable: FqName?
|
||||
get() = when (val parent = parent) {
|
||||
is IrDeclarationWithName -> parent.fqNameWhenAvailable?.child(name)
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.ir.util
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||
@@ -21,6 +22,8 @@ open class StubGeneratorExtensions {
|
||||
|
||||
open fun isPropertyWithPlatformField(descriptor: PropertyDescriptor): Boolean = false
|
||||
|
||||
open fun isStaticFunction(descriptor: FunctionDescriptor): Boolean = false
|
||||
|
||||
open val enhancedNullability: EnhancedNullability
|
||||
get() = EnhancedNullability
|
||||
|
||||
|
||||
Reference in New Issue
Block a user