From 71179326237d7ae5b7f00a568ba186e27a5dd31a Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Wed, 11 Nov 2020 15:25:03 +0100 Subject: [PATCH] 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. --- .../fir/lazy/Fir2IrLazySimpleFunction.kt | 8 +- .../kotlin/backend/jvm/JvmBackendContext.kt | 3 - .../backend/jvm/JvmGeneratorExtensions.kt | 7 + .../jetbrains/kotlin/backend/jvm/JvmLower.kt | 3 +- .../jvm/lower/FunctionReferenceLowering.kt | 24 ++- .../jvm/lower/JvmStaticAnnotationLowering.kt | 143 +++++------------- .../MoveCompanionObjectFieldsLowering.kt | 7 +- .../jvm/lower/PropertyReferenceLowering.kt | 18 ++- .../lower/StaticDefaultFunctionLowering.kt | 2 +- .../ir/declarations/lazy/IrLazyFunction.kt | 4 +- .../declarations/lazy/IrLazyFunctionBase.kt | 8 +- .../org/jetbrains/kotlin/ir/util/IrUtils.kt | 1 + .../kotlin/ir/util/StubGeneratorExtensions.kt | 3 + 13 files changed, 103 insertions(+), 128 deletions(-) diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazySimpleFunction.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazySimpleFunction.kt index a19aff88a2d..9378ae7aabd 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazySimpleFunction.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazySimpleFunction.kt @@ -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, diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt index 712701eabee..10c4e2dde5a 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt @@ -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() val fakeContinuation: IrExpression = createFakeContinuation(this) - val jvmStaticObjectFunctionToStaticFunctionMap = mutableMapOf() - val staticDefaultStubs = mutableMapOf() val inlineClassReplacements = MemoizedInlineClassReplacements(state.functionsWithInlineClassReturnTypesMangled, irFactory, this) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmGeneratorExtensions.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmGeneratorExtensions.kt index a2efe1faecf..ad6c5fcbc2e 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmGeneratorExtensions.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmGeneratorExtensions.kt @@ -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 diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt index abf036f5e9b..312247d2af8 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt @@ -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 diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionReferenceLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionReferenceLowering.kt index 6d0dbba4d4b..f955b4e0137 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionReferenceLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionReferenceLowering.kt @@ -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? = irFunctionReference.getArgumentsWithIr().singleOrNull() + private val boundReceiver: Pair? = + if (callee.isJvmStaticInObject()) createFakeBoundReceiverForJvmStaticInObject() + else irFunctionReference.getArgumentsWithIr().singleOrNull() // The type of the reference is KFunction 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 { + // 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 { diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmStaticAnnotationLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmStaticAnnotationLowering.kt index f57e6de91e2..607ca0a75d3 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmStaticAnnotationLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmStaticAnnotationLowering.kt @@ -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 diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/MoveCompanionObjectFieldsLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/MoveCompanionObjectFieldsLowering.kt index 285e9939662..9c143d7364c 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/MoveCompanionObjectFieldsLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/MoveCompanionObjectFieldsLowering.kt @@ -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() diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/PropertyReferenceLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/PropertyReferenceLowering.kt index 33538836587..899f330d48e 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/PropertyReferenceLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/PropertyReferenceLowering.kt @@ -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 + } } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/StaticDefaultFunctionLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/StaticDefaultFunctionLowering.kt index d8547246650..226593cf858 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/StaticDefaultFunctionLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/StaticDefaultFunctionLowering.kt @@ -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 { diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/IrLazyFunction.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/IrLazyFunction.kt index f3c6f51d930..20d7be42be4 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/IrLazyFunction.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/IrLazyFunction.kt @@ -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) diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/IrLazyFunctionBase.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/IrLazyFunctionBase.kt index 694af6664b0..598d528f8d9 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/IrLazyFunctionBase.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/IrLazyFunctionBase.kt @@ -34,9 +34,13 @@ interface IrLazyFunctionBase : IrLazyDeclarationBase, IrTypeParametersContainer } } - fun createReceiverParameter(parameter: ReceiverParameterDescriptor?): ReadWriteProperty = + fun createReceiverParameter( + parameter: ReceiverParameterDescriptor?, + functionDispatchReceiver: Boolean = false, + ): ReadWriteProperty = lazyVar { - typeTranslator.buildWithScope(this) { + if (functionDispatchReceiver && stubGenerator.extensions.isStaticFunction(descriptor)) null + else typeTranslator.buildWithScope(this) { parameter?.generateReceiverParameterStub()?.also { it.parent = this@IrLazyFunctionBase } } } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt index 2529dc3df0e..2f8ba09729c 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt @@ -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) diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/StubGeneratorExtensions.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/StubGeneratorExtensions.kt index 886a7ea6dcd..8e30cdbf1be 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/StubGeneratorExtensions.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/StubGeneratorExtensions.kt @@ -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