JVM IR: use correct owner for callable references in optimized multifile classes

The owner should always be the facade class, because the part class is
package-private and will be inaccessible from other package.

Note that in the old backend, function references already do have the
facade as the owner correctly, but property references don't, this is
reported as KT-37972.
This commit is contained in:
Alexander Udalov
2020-04-02 22:18:06 +02:00
parent 78467792d5
commit bb1a12e28e
7 changed files with 140 additions and 11 deletions

View File

@@ -16444,6 +16444,16 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/multifileClasses/optimized/callableRefToPrivateConstVal.kt");
}
@TestMetadata("callableReferencesToSameFunctionsFromDifferentPackages.kt")
public void testCallableReferencesToSameFunctionsFromDifferentPackages() throws Exception {
runTest("compiler/testData/codegen/box/multifileClasses/optimized/callableReferencesToSameFunctionsFromDifferentPackages.kt");
}
@TestMetadata("callableReferencesToSamePropertiesFromDifferentPackages.kt")
public void testCallableReferencesToSamePropertiesFromDifferentPackages() throws Exception {
runTest("compiler/testData/codegen/box/multifileClasses/optimized/callableReferencesToSamePropertiesFromDifferentPackages.kt");
}
@TestMetadata("calls.kt")
public void testCalls() throws Exception {
runTest("compiler/testData/codegen/box/multifileClasses/optimized/calls.kt");

View File

@@ -64,7 +64,7 @@ internal val generateMultifileFacadesPhase = namedIrModulePhase(
)
UpdateFunctionCallSites(functionDelegates).lower(input)
UpdateConstantFacadePropertyReferences(context).lower(input)
UpdateConstantFacadePropertyReferences(context, shouldGeneratePartHierarchy).lower(input)
context.multifileFacadesToAdd.clear()
@@ -280,17 +280,12 @@ private class UpdateFunctionCallSites(
}
}
private class UpdateConstantFacadePropertyReferences(private val context: JvmBackendContext) : ClassLoweringPass {
private class UpdateConstantFacadePropertyReferences(
private val context: JvmBackendContext,
private val shouldGeneratePartHierarchy: Boolean
) : ClassLoweringPass {
override fun lower(irClass: IrClass) {
// Find property reference classes for properties whose fields were moved to the facade class.
if (irClass.origin != JvmLoweredDeclarationOrigin.GENERATED_PROPERTY_REFERENCE)
return
val property = (irClass.attributeOwnerId as? IrPropertyReference)?.getter?.owner?.correspondingPropertySymbol?.owner
?: return
val facadeClass = context.multifileFacadeClassForPart[property.parentAsClass.attributeOwnerId]
?: return
if (property.backingField?.shouldMoveToFacade() != true)
return
val facadeClass = getReplacementFacadeClassOrNull(irClass) ?: return
// Replace the class reference in the body of the property reference class (in getOwner) to refer to the facade class instead.
irClass.transformChildrenVoid(object : IrElementTransformerVoid() {
@@ -301,4 +296,25 @@ private class UpdateConstantFacadePropertyReferences(private val context: JvmBac
)
})
}
// We should replace references to facade classes in the following cases:
// - if -Xmultifile-parts-inherit is enabled, always replace all references;
// - otherwise, replace references in classes for properties whose fields were moved to the facade class.
private fun getReplacementFacadeClassOrNull(irClass: IrClass): IrClass? {
if (irClass.origin != JvmLoweredDeclarationOrigin.GENERATED_PROPERTY_REFERENCE &&
irClass.origin != JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL
) return null
val declaration = when (val callableReference = irClass.attributeOwnerId) {
is IrPropertyReference -> callableReference.getter?.owner?.correspondingPropertySymbol?.owner
is IrFunctionReference -> callableReference.symbol.owner
else -> null
} ?: return null
val parent = declaration.parent as? IrClass ?: return null
val facadeClass = context.multifileFacadeClassForPart[parent.attributeOwnerId]
return if (shouldGeneratePartHierarchy ||
(declaration is IrProperty && declaration.backingField?.shouldMoveToFacade() == true)
) facadeClass else null
}
}

View File

@@ -0,0 +1,36 @@
// TARGET_BACKEND: JVM
// IGNORE_LIGHT_ANALYSIS
// WITH_RUNTIME
// !INHERIT_MULTIFILE_PARTS
// FILE: box.kt
import a.funRefA
import b.funRefB
fun box(): String {
if (funRefA != funRefB) return "Fail: funRefA != funRefB"
return "OK"
}
// FILE: a.kt
package a
import test.function
val funRefA = ::function
// FILE: b.kt
package b
import test.function
val funRefB = ::function
// FILE: part.kt
@file:[JvmName("MultifileClass") JvmMultifileClass]
package test
fun function() {}

View File

@@ -0,0 +1,37 @@
// TARGET_BACKEND: JVM
// TODO: KT-37972 IllegalAccessError on initializing property reference for a property declared in JvmMultifileClass with -Xmultifile-parts-inherit
// IGNORE_BACKEND: JVM
// WITH_RUNTIME
// !INHERIT_MULTIFILE_PARTS
// FILE: box.kt
import a.propRefA
import b.propRefB
fun box(): String {
if (propRefA != propRefB) return "Fail: propRefA != propRefB"
return "OK"
}
// FILE: a.kt
package a
import test.property
val propRefA = ::property
// FILE: b.kt
package b
import test.property
val propRefB = ::property
// FILE: part.kt
@file:[JvmName("MultifileClass") JvmMultifileClass]
package test
val property: String get() = ""

View File

@@ -17634,6 +17634,16 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/multifileClasses/optimized/callableRefToPrivateConstVal.kt");
}
@TestMetadata("callableReferencesToSameFunctionsFromDifferentPackages.kt")
public void testCallableReferencesToSameFunctionsFromDifferentPackages() throws Exception {
runTest("compiler/testData/codegen/box/multifileClasses/optimized/callableReferencesToSameFunctionsFromDifferentPackages.kt");
}
@TestMetadata("callableReferencesToSamePropertiesFromDifferentPackages.kt")
public void testCallableReferencesToSamePropertiesFromDifferentPackages() throws Exception {
runTest("compiler/testData/codegen/box/multifileClasses/optimized/callableReferencesToSamePropertiesFromDifferentPackages.kt");
}
@TestMetadata("calls.kt")
public void testCalls() throws Exception {
runTest("compiler/testData/codegen/box/multifileClasses/optimized/calls.kt");

View File

@@ -17634,6 +17634,16 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/multifileClasses/optimized/callableRefToPrivateConstVal.kt");
}
@TestMetadata("callableReferencesToSameFunctionsFromDifferentPackages.kt")
public void testCallableReferencesToSameFunctionsFromDifferentPackages() throws Exception {
runTest("compiler/testData/codegen/box/multifileClasses/optimized/callableReferencesToSameFunctionsFromDifferentPackages.kt");
}
@TestMetadata("callableReferencesToSamePropertiesFromDifferentPackages.kt")
public void testCallableReferencesToSamePropertiesFromDifferentPackages() throws Exception {
runTest("compiler/testData/codegen/box/multifileClasses/optimized/callableReferencesToSamePropertiesFromDifferentPackages.kt");
}
@TestMetadata("calls.kt")
public void testCalls() throws Exception {
runTest("compiler/testData/codegen/box/multifileClasses/optimized/calls.kt");

View File

@@ -16444,6 +16444,16 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/multifileClasses/optimized/callableRefToPrivateConstVal.kt");
}
@TestMetadata("callableReferencesToSameFunctionsFromDifferentPackages.kt")
public void testCallableReferencesToSameFunctionsFromDifferentPackages() throws Exception {
runTest("compiler/testData/codegen/box/multifileClasses/optimized/callableReferencesToSameFunctionsFromDifferentPackages.kt");
}
@TestMetadata("callableReferencesToSamePropertiesFromDifferentPackages.kt")
public void testCallableReferencesToSamePropertiesFromDifferentPackages() throws Exception {
runTest("compiler/testData/codegen/box/multifileClasses/optimized/callableReferencesToSamePropertiesFromDifferentPackages.kt");
}
@TestMetadata("calls.kt")
public void testCalls() throws Exception {
runTest("compiler/testData/codegen/box/multifileClasses/optimized/calls.kt");