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");
|
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
|
@Test
|
||||||
@TestMetadata("rem.kt")
|
@TestMetadata("rem.kt")
|
||||||
public void testRem() throws Exception {
|
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) {
|
private fun unfoldCallableReference(reference: IrCallableReference<*>, callStack: CallStack) {
|
||||||
val function = reference.symbol.owner
|
|
||||||
callStack.pushSimpleInstruction(reference)
|
callStack.pushSimpleInstruction(reference)
|
||||||
|
reference.getArgumentsWithIr().forEach { (parameter, arg) ->
|
||||||
|
callStack.pushSimpleInstruction(parameter)
|
||||||
|
callStack.pushCompoundInstruction(arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
reference.dispatchReceiver?.let { callStack.pushSimpleInstruction(function.dispatchReceiverParameter!!) }
|
private fun unfoldFunctionReference(reference: IrFunctionReference, callStack: CallStack) {
|
||||||
reference.extensionReceiver?.let { callStack.pushSimpleInstruction(function.extensionReceiverParameter!!) }
|
unfoldCallableReference(reference, callStack)
|
||||||
|
|
||||||
reference.extensionReceiver?.let { callStack.pushCompoundInstruction(it) }
|
|
||||||
reference.dispatchReceiver?.let { callStack.pushCompoundInstruction(it) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun unfoldPropertyReference(propertyReference: IrPropertyReference, callStack: CallStack) {
|
private fun unfoldPropertyReference(propertyReference: IrPropertyReference, callStack: CallStack) {
|
||||||
callStack.pushSimpleInstruction(propertyReference)
|
if (propertyReference.field != null) return callStack.pushSimpleInstruction(propertyReference)
|
||||||
|
unfoldCallableReference(propertyReference, callStack)
|
||||||
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) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun unfoldClassReference(classReference: IrClassReference, callStack: CallStack) {
|
private fun unfoldClassReference(classReference: IrClassReference, callStack: CallStack) {
|
||||||
|
|||||||
@@ -566,8 +566,8 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
|
|||||||
private fun interpretFunctionReference(reference: IrFunctionReference) {
|
private fun interpretFunctionReference(reference: IrFunctionReference) {
|
||||||
val irFunction = reference.symbol.owner
|
val irFunction = reference.symbol.owner
|
||||||
|
|
||||||
val dispatchReceiver = reference.dispatchReceiver?.let { callStack.popState() }
|
val dispatchReceiver = irFunction.getDispatchReceiver()?.let { reference.dispatchReceiver?.let { callStack.popState() } }
|
||||||
val extensionReceiver = reference.extensionReceiver?.let { callStack.popState() }
|
val extensionReceiver = irFunction.getExtensionReceiver()?.let { reference.extensionReceiver?.let { callStack.popState() } }
|
||||||
|
|
||||||
val function = KFunctionState(
|
val function = KFunctionState(
|
||||||
reference,
|
reference,
|
||||||
@@ -581,7 +581,11 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
|
|||||||
|
|
||||||
private fun interpretPropertyReference(propertyReference: IrPropertyReference) {
|
private fun interpretPropertyReference(propertyReference: IrPropertyReference) {
|
||||||
// it is impossible to get KProperty2 through ::, so only one receiver can be not null (or both null)
|
// 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)
|
val propertyState = KPropertyState(propertyReference, receiver)
|
||||||
|
|
||||||
fun List<IrTypeParameter>.addToFields() {
|
fun List<IrTypeParameter>.addToFields() {
|
||||||
|
|||||||
@@ -108,12 +108,12 @@ fun IrMemberAccessExpression<*>.getArgumentsWithIr(): List<Pair<IrValueParameter
|
|||||||
else -> error(this)
|
else -> error(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatchReceiver?.let {
|
dispatchReceiver?.let { arg ->
|
||||||
res += (irFunction.dispatchReceiverParameter!! to it)
|
irFunction.dispatchReceiverParameter?.let { parameter -> res += (parameter to arg) }
|
||||||
}
|
}
|
||||||
|
|
||||||
extensionReceiver?.let {
|
extensionReceiver?.let { arg ->
|
||||||
res += (irFunction.extensionReceiverParameter!! to it)
|
irFunction.extensionReceiverParameter?.let { parameter -> res += (parameter to arg) }
|
||||||
}
|
}
|
||||||
|
|
||||||
irFunction.valueParameters.forEachIndexed { index, it ->
|
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");
|
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
|
@Test
|
||||||
@TestMetadata("rem.kt")
|
@TestMetadata("rem.kt")
|
||||||
public void testRem() throws Exception {
|
public void testRem() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user