From bb1a12e28ebd841b3d9350f1569d199a8c341560 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Thu, 2 Apr 2020 22:18:06 +0200 Subject: [PATCH] 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. --- .../ir/FirBlackBoxCodegenTestGenerated.java | 10 +++++ .../jvm/lower/GenerateMultifileFacades.kt | 38 +++++++++++++------ ...cesToSameFunctionsFromDifferentPackages.kt | 36 ++++++++++++++++++ ...esToSamePropertiesFromDifferentPackages.kt | 37 ++++++++++++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 10 +++++ .../LightAnalysisModeTestGenerated.java | 10 +++++ .../ir/IrBlackBoxCodegenTestGenerated.java | 10 +++++ 7 files changed, 140 insertions(+), 11 deletions(-) create mode 100644 compiler/testData/codegen/box/multifileClasses/optimized/callableReferencesToSameFunctionsFromDifferentPackages.kt create mode 100644 compiler/testData/codegen/box/multifileClasses/optimized/callableReferencesToSamePropertiesFromDifferentPackages.kt diff --git a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java index 6344551cec8..1eb5ee43f17 100644 --- a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java @@ -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"); diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/GenerateMultifileFacades.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/GenerateMultifileFacades.kt index 7779b0f20f8..5d8b172a64f 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/GenerateMultifileFacades.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/GenerateMultifileFacades.kt @@ -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 + } } diff --git a/compiler/testData/codegen/box/multifileClasses/optimized/callableReferencesToSameFunctionsFromDifferentPackages.kt b/compiler/testData/codegen/box/multifileClasses/optimized/callableReferencesToSameFunctionsFromDifferentPackages.kt new file mode 100644 index 00000000000..027a3132794 --- /dev/null +++ b/compiler/testData/codegen/box/multifileClasses/optimized/callableReferencesToSameFunctionsFromDifferentPackages.kt @@ -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() {} diff --git a/compiler/testData/codegen/box/multifileClasses/optimized/callableReferencesToSamePropertiesFromDifferentPackages.kt b/compiler/testData/codegen/box/multifileClasses/optimized/callableReferencesToSamePropertiesFromDifferentPackages.kt new file mode 100644 index 00000000000..941b38e1d4a --- /dev/null +++ b/compiler/testData/codegen/box/multifileClasses/optimized/callableReferencesToSamePropertiesFromDifferentPackages.kt @@ -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() = "" diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 62f516a33e9..740d4762c7f 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -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"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index e8771bb6648..4b38d465199 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -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"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 5ed7f74d03e..0d648544701 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -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");