[JVM_IR] Deal with lowering ordering issues for JvmStatic function references.
Do not destructively update the @JvmStatic function, instead create a copy on first access, and replace the original with the copy in the jvm static lowering. This ensures that the original function is seen in other lowerings independently of file lowering order.
This commit is contained in:
committed by
Alexander Udalov
parent
3d2f5f4bc1
commit
7b4e0b2f5d
Generated
+5
@@ -17779,6 +17779,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTest("compiler/testData/codegen/box/jvmStatic/funAccess.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("functionReference.kt")
|
||||
public void testFunctionReference() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvmStatic/functionReference.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("importStaticMemberFromObject.kt")
|
||||
public void testImportStaticMemberFromObject() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvmStatic/importStaticMemberFromObject.kt");
|
||||
|
||||
@@ -129,6 +129,8 @@ 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)
|
||||
|
||||
+47
-19
@@ -17,8 +17,8 @@ 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.Modality
|
||||
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
|
||||
@@ -127,36 +127,62 @@ 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) {
|
||||
if (!irClass.isObject || irClass.isCompanion) return
|
||||
|
||||
irClass.declarations.filter(::isJvmStaticFunction).forEach {
|
||||
val jvmStaticFunction = it as IrSimpleFunction
|
||||
val jvmStaticFunctionsToReplace = irClass.declarations.filter {
|
||||
// dispatch receiver parameter is already null for synthetic property annotation methods
|
||||
jvmStaticFunction.dispatchReceiverParameter?.let { oldDispatchReceiverParameter ->
|
||||
jvmStaticFunction.dispatchReceiverParameter = null
|
||||
jvmStaticFunction.body = jvmStaticFunction.body?.replaceThisByStaticReference(
|
||||
context.cachedDeclarations,
|
||||
irClass,
|
||||
oldDispatchReceiverParameter
|
||||
)
|
||||
}
|
||||
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)?.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(
|
||||
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
|
||||
}
|
||||
|
||||
private class MakeCallsStatic(
|
||||
val context: JvmBackendContext
|
||||
) : IrElementTransformerVoid() {
|
||||
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,
|
||||
@@ -165,7 +191,9 @@ private class MakeCallsStatic(
|
||||
val callee = expression.symbol.owner
|
||||
val newCallee = if (!callee.isInCurrentModule()) {
|
||||
callee.copyRemovingDispatchReceiver() // TODO: cache these
|
||||
} else callee
|
||||
} else {
|
||||
createReplacement(context, callee)
|
||||
}
|
||||
|
||||
return context.createIrBuilder(expression.symbol, expression.startOffset, expression.endOffset).irBlock(expression) {
|
||||
// OldReceiver has to be evaluated for its side effects.
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
|
||||
// WITH_RUNTIME
|
||||
// FILE: u1.kt
|
||||
|
||||
object O {
|
||||
@JvmStatic
|
||||
fun foo() = "OK"
|
||||
}
|
||||
|
||||
// FILE: u2.kt
|
||||
|
||||
fun box() = (O::foo)()
|
||||
+5
@@ -19179,6 +19179,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/jvmStatic/funAccess.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("functionReference.kt")
|
||||
public void testFunctionReference() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvmStatic/functionReference.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("importStaticMemberFromObject.kt")
|
||||
public void testImportStaticMemberFromObject() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvmStatic/importStaticMemberFromObject.kt");
|
||||
|
||||
+5
@@ -19179,6 +19179,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/jvmStatic/funAccess.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("functionReference.kt")
|
||||
public void testFunctionReference() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvmStatic/functionReference.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("importStaticMemberFromObject.kt")
|
||||
public void testImportStaticMemberFromObject() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvmStatic/importStaticMemberFromObject.kt");
|
||||
|
||||
+5
@@ -17779,6 +17779,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/jvmStatic/funAccess.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("functionReference.kt")
|
||||
public void testFunctionReference() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvmStatic/functionReference.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("importStaticMemberFromObject.kt")
|
||||
public void testImportStaticMemberFromObject() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/jvmStatic/importStaticMemberFromObject.kt");
|
||||
|
||||
Reference in New Issue
Block a user