Safely unfold callable reference instruction in interpreter
There was an assumption that if receiver exists then parameter will also exist. This is not true for references marked with `JvmStatic`. Later in `JvmStaticInObjectLowering` dispatch receiver may be dropped.
This commit is contained in:
+6
@@ -16889,6 +16889,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTest("compiler/testData/codegen/box/evaluate/plus.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("referenceNameFromStaticInDifferentModule.kt")
|
||||
public void testReferenceNameFromStaticInDifferentModule() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/evaluate/referenceNameFromStaticInDifferentModule.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("rem.kt")
|
||||
public void testRem() throws Exception {
|
||||
|
||||
+10
-17
@@ -416,28 +416,21 @@ private fun unfoldComposite(element: IrComposite, callStack: CallStack) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun unfoldFunctionReference(reference: IrFunctionReference, callStack: CallStack) {
|
||||
val function = reference.symbol.owner
|
||||
private fun unfoldCallableReference(reference: IrCallableReference<*>, callStack: CallStack) {
|
||||
callStack.pushSimpleInstruction(reference)
|
||||
reference.getArgumentsWithIr().forEach { (parameter, arg) ->
|
||||
callStack.pushSimpleInstruction(parameter)
|
||||
callStack.pushCompoundInstruction(arg)
|
||||
}
|
||||
}
|
||||
|
||||
reference.dispatchReceiver?.let { callStack.pushSimpleInstruction(function.dispatchReceiverParameter!!) }
|
||||
reference.extensionReceiver?.let { callStack.pushSimpleInstruction(function.extensionReceiverParameter!!) }
|
||||
|
||||
reference.extensionReceiver?.let { callStack.pushCompoundInstruction(it) }
|
||||
reference.dispatchReceiver?.let { callStack.pushCompoundInstruction(it) }
|
||||
private fun unfoldFunctionReference(reference: IrFunctionReference, callStack: CallStack) {
|
||||
unfoldCallableReference(reference, callStack)
|
||||
}
|
||||
|
||||
private fun unfoldPropertyReference(propertyReference: IrPropertyReference, callStack: CallStack) {
|
||||
callStack.pushSimpleInstruction(propertyReference)
|
||||
|
||||
val getter = propertyReference.getter?.owner
|
||||
if (getter != null) {
|
||||
propertyReference.dispatchReceiver?.let { callStack.pushSimpleInstruction(getter.dispatchReceiverParameter!!) }
|
||||
propertyReference.extensionReceiver?.let { callStack.pushSimpleInstruction(getter.extensionReceiverParameter!!) }
|
||||
|
||||
propertyReference.extensionReceiver?.let { callStack.pushCompoundInstruction(it) }
|
||||
propertyReference.dispatchReceiver?.let { callStack.pushCompoundInstruction(it) }
|
||||
}
|
||||
if (propertyReference.field != null) return callStack.pushSimpleInstruction(propertyReference)
|
||||
unfoldCallableReference(propertyReference, callStack)
|
||||
}
|
||||
|
||||
private fun unfoldClassReference(classReference: IrClassReference, callStack: CallStack) {
|
||||
|
||||
@@ -566,8 +566,8 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
|
||||
private fun interpretFunctionReference(reference: IrFunctionReference) {
|
||||
val irFunction = reference.symbol.owner
|
||||
|
||||
val dispatchReceiver = reference.dispatchReceiver?.let { callStack.popState() }
|
||||
val extensionReceiver = reference.extensionReceiver?.let { callStack.popState() }
|
||||
val dispatchReceiver = irFunction.getDispatchReceiver()?.let { reference.dispatchReceiver?.let { callStack.popState() } }
|
||||
val extensionReceiver = irFunction.getExtensionReceiver()?.let { reference.extensionReceiver?.let { callStack.popState() } }
|
||||
|
||||
val function = KFunctionState(
|
||||
reference,
|
||||
@@ -581,7 +581,11 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
|
||||
|
||||
private fun interpretPropertyReference(propertyReference: IrPropertyReference) {
|
||||
// it is impossible to get KProperty2 through ::, so only one receiver can be not null (or both null)
|
||||
val receiver = (propertyReference.dispatchReceiver ?: propertyReference.extensionReceiver)?.let { callStack.popState() }
|
||||
val getter = propertyReference.getter?.owner
|
||||
val dispatchReceiver = getter?.getDispatchReceiver()?.let { propertyReference.dispatchReceiver?.let { callStack.popState() } }
|
||||
val extensionReceiver = getter?.getExtensionReceiver()?.let { propertyReference.extensionReceiver?.let { callStack.popState() } }
|
||||
val receiver = dispatchReceiver ?: extensionReceiver
|
||||
|
||||
val propertyState = KPropertyState(propertyReference, receiver)
|
||||
|
||||
fun List<IrTypeParameter>.addToFields() {
|
||||
|
||||
@@ -108,12 +108,12 @@ fun IrMemberAccessExpression<*>.getArgumentsWithIr(): List<Pair<IrValueParameter
|
||||
else -> error(this)
|
||||
}
|
||||
|
||||
dispatchReceiver?.let {
|
||||
res += (irFunction.dispatchReceiverParameter!! to it)
|
||||
dispatchReceiver?.let { arg ->
|
||||
irFunction.dispatchReceiverParameter?.let { parameter -> res += (parameter to arg) }
|
||||
}
|
||||
|
||||
extensionReceiver?.let {
|
||||
res += (irFunction.extensionReceiverParameter!! to it)
|
||||
extensionReceiver?.let { arg ->
|
||||
irFunction.extensionReceiverParameter?.let { parameter -> res += (parameter to arg) }
|
||||
}
|
||||
|
||||
irFunction.valueParameters.forEachIndexed { index, it ->
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
// TARGET_BACKEND: JVM_IR
|
||||
// WITH_STDLIB
|
||||
|
||||
// MODULE: lib
|
||||
// FILE: lib.kt
|
||||
|
||||
object A {
|
||||
@JvmStatic
|
||||
val somePropertyFromObject: Int = 0
|
||||
|
||||
@JvmStatic
|
||||
fun someFunctionFromObject(str: String): String = str
|
||||
}
|
||||
|
||||
class B {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
val somePropertyFromCompanionObject: Int = 0
|
||||
|
||||
@JvmStatic
|
||||
fun someFunctionFromCompanionObject(str: String): String = str
|
||||
}
|
||||
}
|
||||
|
||||
// MODULE: main(lib)
|
||||
// FILE: main.kt
|
||||
|
||||
fun box(): String {
|
||||
// `name` call must be optimized with `ConstEvaluationLowering`
|
||||
if (A::somePropertyFromObject.name != "somePropertyFromObject") return "Fail 1"
|
||||
if (A::someFunctionFromObject.name != "someFunctionFromObject") return "Fail 2"
|
||||
if (B.Companion::somePropertyFromCompanionObject.name != "somePropertyFromCompanionObject") return "Fail 3"
|
||||
if (B.Companion::someFunctionFromCompanionObject.name != "someFunctionFromCompanionObject") return "Fail 4"
|
||||
return "OK"
|
||||
}
|
||||
+6
@@ -16889,6 +16889,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/evaluate/plus.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("referenceNameFromStaticInDifferentModule.kt")
|
||||
public void testReferenceNameFromStaticInDifferentModule() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/evaluate/referenceNameFromStaticInDifferentModule.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("rem.kt")
|
||||
public void testRem() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user