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