JVM_IR: use correct dispatch receiver type in more references

#KT-46902 Fixed
This commit is contained in:
pyos
2021-05-26 10:45:16 +02:00
committed by max-kammerer
parent 16dbafced1
commit d37ceb47be
17 changed files with 69 additions and 59 deletions
@@ -2542,6 +2542,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/callableReference/kt44483.kt");
}
@Test
@TestMetadata("kt46902.kt")
public void testKt46902() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt46902.kt");
}
@Test
@TestMetadata("nested.kt")
public void testNested() throws Exception {
@@ -23,7 +23,6 @@ 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.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.IrTypeProjection
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
@@ -125,43 +124,10 @@ private class InlineCallableReferenceToLambdaTransformer(
}
}
private class BoundReceiver(
val receiverParameter: IrValueParameter,
val receiverValue: IrExpression,
val receiverType: IrType
)
private fun IrCallableReference<*>.getBoundReceiver(): BoundReceiver? {
val irFunction = when (this) {
is IrFunctionReference ->
this.symbol.owner
is IrPropertyReference ->
this.getter!!.owner
else ->
throw AssertionError("Unexpected callable reference: ${this.render()}")
}
this.dispatchReceiver?.let { dispatchReceiver ->
val dispatchReceiverParameter = irFunction.dispatchReceiverParameter
?: throw AssertionError("Referenced declaration '${this.symbol.owner.render()}' has no dispatch receiver: ${this.dump()}")
// NB in case of fake override of Base::foo in Child::foo, dispatch receiver type is Base,
// but we in fact need Child (because of accessor generation).
return BoundReceiver(dispatchReceiverParameter, dispatchReceiver, irFunction.parentAsClass.defaultType)
}
this.extensionReceiver?.let { extensionReceiver ->
val extensionReceiverParameter = irFunction.extensionReceiverParameter
?: throw AssertionError("Referenced declaration '${this.symbol.owner.render()}' has no extension receiver: ${this.dump()}")
return BoundReceiver(extensionReceiverParameter, extensionReceiver, extensionReceiverParameter.type)
}
return null
}
private fun expandInlineFunctionReferenceToLambda(expression: IrCallableReference<*>, referencedFunction: IrFunction): IrExpression {
val irBuilder = context.createJvmIrBuilder(currentScope!!.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset)
return irBuilder.irBlock(expression, IrStatementOrigin.LAMBDA) {
val boundReceiver = expression.getBoundReceiver()
val (receiverParameter, receiverValue) = expression.getArgumentsWithIr().singleOrNull() ?: (null to null)
val argumentTypes = (expression.type as IrSimpleType).arguments.dropLast(1).map { (it as IrTypeProjection).type }
val function = context.irFactory.buildFun {
@@ -173,8 +139,8 @@ private class InlineCallableReferenceToLambdaTransformer(
isSuspend = referencedFunction.isSuspend
}.apply {
parent = currentDeclarationParent!!
if (boundReceiver != null) {
addExtensionReceiver(boundReceiver.receiverType)
if (receiverValue != null) {
addExtensionReceiver(receiverValue.type)
}
for ((index, argumentType) in argumentTypes.withIndex()) {
addValueParameter {
@@ -196,7 +162,7 @@ private class InlineCallableReferenceToLambdaTransformer(
var unboundIndex = 0
for (parameter in referencedFunction.explicitParameters) {
when {
boundReceiver?.receiverParameter == parameter ->
receiverParameter == parameter ->
irGet(extensionReceiverParameter!!)
parameter.isVararg && unboundIndex < argumentTypes.size && parameter.type == valueParameters[unboundIndex].type ->
irGet(valueParameters[unboundIndex++])
@@ -225,7 +191,7 @@ private class InlineCallableReferenceToLambdaTransformer(
origin = IrStatementOrigin.LAMBDA
).apply {
copyAttributes(expression)
extensionReceiver = boundReceiver?.receiverValue
extensionReceiver = receiverValue
}
}
}
@@ -354,15 +354,7 @@ private class PropertyReferenceLowering(val context: JvmBackendContext) : IrElem
val receiverFromField = boundReceiver?.let { irImplicitCast(irGetField(irGet(arguments[0]), backingField), it.type) }
call.copyTypeArgumentsFrom(expression)
call.dispatchReceiver = call.symbol.owner.dispatchReceiverParameter?.let {
receiverFromField ?: irImplicitCast(
irGet(arguments[1]),
// In `C::x`, the receiver must be cast to `C` in order to put accessors for protected
// properties in the correct class (box/syntheticAccessors/accessorForProtectedPropertyReference.kt).
// However, if `x` is a property of C's superclass, the type of `dispatchReceiverParameter` is not `C`.
// Since the receiver is not bound, the type of the property must be `KProperty1<C, ReturnType>` or
// `KProperty2<C, ExtensionReceiver, ReturnType>`.
((expression.type as IrSimpleType).arguments.first() as IrTypeProjection).type
)
receiverFromField ?: irImplicitCast(irGet(arguments[1]), expression.receiverType)
}
call.extensionReceiver = call.symbol.owner.extensionReceiverParameter?.let {
if (call.symbol.owner.dispatchReceiverParameter == null)
@@ -393,9 +385,9 @@ private class PropertyReferenceLowering(val context: JvmBackendContext) : IrElem
field.isStatic ->
null
expression.dispatchReceiver != null ->
irImplicitCast(irGetField(irGet(arguments[0]), backingField), field.parentAsClass.defaultType)
irImplicitCast(irGetField(irGet(arguments[0]), backingField), expression.receiverType)
else ->
irImplicitCast(irGet(arguments[1]), field.parentAsClass.defaultType)
irImplicitCast(irGet(arguments[1]), expression.receiverType)
}
referenceClass.addOverride(get!!) { arguments ->
@@ -449,6 +441,12 @@ private class PropertyReferenceLowering(val context: JvmBackendContext) : IrElem
}
}
// In `value::x`, using `value`'s type is fine; but in `C::x`, the type of the receiver has to be `C`.
// This is *not* the type of `x`'s dispatch receiver if `x` is declared in a superclass of `C`, so we
// extract `C` from the reference's type, which is either `KProperty1<C, R>` or `KProperty2<C, Extension, R>`.
private val IrCallableReference<*>.receiverType
get() = dispatchReceiver?.type ?: ((type as IrSimpleType).arguments.first() as IrTypeProjection).type
private fun IrCallableReference<*>.getBoundReceiver(): IrExpression? {
val callee = symbol.owner
return if (callee is IrDeclaration && callee.isJvmStaticInObject()) {
@@ -0,0 +1,12 @@
class A {
inner class C(val m: String) {
fun test(): String {
m.f(::C)
return m
}
}
}
inline fun String.f(g: (String) -> A.C): A.C = g(this)
fun box(): String = A().C("OK").test()
@@ -1,7 +1,5 @@
// TARGET_BACKEND: JVM
// WITH_RUNTIME
// IGNORE_BACKEND_FIR: JVM_IR
// ^ ::jpf is incorrectly represented as a reference to Base::jpf (should be: reference to fake override in Derived)
// FILE: kt46578_delegated.kt
import p.*
@@ -1,7 +1,5 @@
// TARGET_BACKEND: JVM
// WITH_RUNTIME
// IGNORE_BACKEND_FIR: JVM_IR
// ^ ::jpf is incorrectly represented as a reference to Base::jpf (should be: reference to fake override in Derived)
// FILE: kt46578_propertyRef.kt
import p.*
@@ -1,5 +1,4 @@
// TARGET_BACKEND: JVM
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME
// FILE: a.kt
@@ -1,5 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// FILE: a.kt
package a
@@ -1,5 +1,4 @@
// IGNORE_BACKEND: WASM
// IGNORE_BACKEND_FIR: JVM_IR
// FILE: a.kt
package a
@@ -1,5 +1,4 @@
// TARGET_BACKEND: JVM
// IGNORE_BACKEND_FIR: JVM_IR
// FILE: a/Base.java
package a;
@@ -2542,6 +2542,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/callableReference/kt44483.kt");
}
@Test
@TestMetadata("kt46902.kt")
public void testKt46902() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt46902.kt");
}
@Test
@TestMetadata("nested.kt")
public void testNested() throws Exception {
@@ -2542,6 +2542,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/callableReference/kt44483.kt");
}
@Test
@TestMetadata("kt46902.kt")
public void testKt46902() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt46902.kt");
}
@Test
@TestMetadata("nested.kt")
public void testNested() throws Exception {
@@ -2230,6 +2230,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/callableReference/kt44483.kt");
}
@TestMetadata("kt46902.kt")
public void testKt46902() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt46902.kt");
}
@TestMetadata("nested.kt")
public void testNested() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/nested.kt");
@@ -1510,6 +1510,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
runTest("compiler/testData/codegen/box/callableReference/kt44483.kt");
}
@TestMetadata("kt46902.kt")
public void testKt46902() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt46902.kt");
}
@TestMetadata("nested.kt")
public void testNested() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/nested.kt");
@@ -1510,6 +1510,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/callableReference/kt44483.kt");
}
@TestMetadata("kt46902.kt")
public void testKt46902() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt46902.kt");
}
@TestMetadata("nested.kt")
public void testNested() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/nested.kt");
@@ -1510,6 +1510,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/callableReference/kt44483.kt");
}
@TestMetadata("kt46902.kt")
public void testKt46902() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt46902.kt");
}
@TestMetadata("nested.kt")
public void testNested() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/nested.kt");
@@ -1290,6 +1290,11 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest
runTest("compiler/testData/codegen/box/callableReference/kt37604.kt");
}
@TestMetadata("kt46902.kt")
public void testKt46902() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt46902.kt");
}
@TestMetadata("nested.kt")
public void testNested() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/nested.kt");