diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index c17b29ecfef..fc1713aff92 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -20958,6 +20958,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT public void testPrivateTopLevelFun() throws Exception { runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/withAccessor/privateTopLevelFun.kt"); } + + @Test + @TestMetadata("protectedSuperclassCompanionObjectMember.kt") + public void testProtectedSuperclassCompanionObjectMember() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/withAccessor/protectedSuperclassCompanionObjectMember.kt"); + } } } @@ -39772,6 +39778,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/syntheticAccessors/protectedFromLambda.kt"); } + @Test + @TestMetadata("protectedSuperclassCompanionObjectMember.kt") + public void testProtectedSuperclassCompanionObjectMember() throws Exception { + runTest("compiler/testData/codegen/box/syntheticAccessors/protectedSuperclassCompanionObjectMember.kt"); + } + @Test @TestMetadata("superCallFromMultipleSubclasses.kt") public void testSuperCallFromMultipleSubclasses() throws Exception { diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmCachedDeclarations.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmCachedDeclarations.kt index b92dc70d16b..d3dae034822 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmCachedDeclarations.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmCachedDeclarations.kt @@ -179,7 +179,20 @@ class JvmCachedDeclarations( modality = if (isInterface) Modality.OPEN else target.modality // Since we already mangle the name above we need to reset internal visibilities to public in order // to avoid mangling the same name twice. - visibility = if (target.visibility == DescriptorVisibilities.INTERNAL) DescriptorVisibilities.PUBLIC else target.visibility + visibility = when (target.visibility) { + DescriptorVisibilities.INTERNAL -> + DescriptorVisibilities.PUBLIC + DescriptorVisibilities.PROTECTED -> { + // Required to properly create accessors to protected static companion object member + // when this member is referenced in subclass. + if (isStatic) + JavaDescriptorVisibilities.PROTECTED_STATIC_VISIBILITY + else + DescriptorVisibilities.PROTECTED + } + else -> + target.visibility + } isSuspend = target.isSuspend }.apply proxy@{ parent = this@makeProxy diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmStaticAnnotationLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmStaticAnnotationLowering.kt index ef795544dbf..a9f94286a61 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmStaticAnnotationLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmStaticAnnotationLowering.kt @@ -5,35 +5,27 @@ package org.jetbrains.kotlin.backend.jvm.lower -import org.jetbrains.kotlin.backend.common.ClassLoweringPass import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.ir.* import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase import org.jetbrains.kotlin.backend.common.phaser.makeIrModulePhase -import org.jetbrains.kotlin.backend.common.runOnFilePostfix import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.codegen.isEffectivelyInlineOnly import org.jetbrains.kotlin.backend.jvm.codegen.isInlineFunctionCall import org.jetbrains.kotlin.backend.jvm.ir.replaceThisByStaticReference import org.jetbrains.kotlin.descriptors.DescriptorVisibilities -import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.builders.* -import org.jetbrains.kotlin.ir.builders.declarations.addFunction -import org.jetbrains.kotlin.ir.builders.declarations.buildFun import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns -import org.jetbrains.kotlin.ir.expressions.IrCall -import org.jetbrains.kotlin.ir.expressions.IrExpression -import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression -import org.jetbrains.kotlin.ir.expressions.IrTypeOperator +import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid -import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.annotations.JVM_STATIC_ANNOTATION_FQ_NAME internal val jvmStaticInObjectPhase = makeIrModulePhase( @@ -145,10 +137,37 @@ private class CompanionObjectJvmStaticTransformer(val context: JvmBackendContext override fun visitCall(expression: IrCall): IrExpression { expression.transformChildrenVoid(this) val callee = expression.symbol.owner - if (callee.isJvmStaticInCompanion() && callee.visibility == DescriptorVisibilities.PROTECTED && !callee.isInlineFunctionCall(context)) { - val (staticProxy, _) = context.cachedDeclarations.getStaticAndCompanionDeclaration(callee) - return expression.makeStatic(context, staticProxy) + return when { + shouldReplaceWithStaticCall(callee) -> { + val (staticProxy, _) = context.cachedDeclarations.getStaticAndCompanionDeclaration(callee) + expression.makeStatic(context, staticProxy) + } + callee.symbol == context.ir.symbols.indyLambdaMetafactoryIntrinsic -> { + val implFunRef = expression.getValueArgument(1) as? IrFunctionReference + ?: throw AssertionError("'implMethodReference' is expected to be 'IrFunctionReference': ${expression.dump()}") + val implFun = implFunRef.symbol.owner + if (implFunRef.dispatchReceiver != null && implFun is IrSimpleFunction && shouldReplaceWithStaticCall(implFun)) { + val (staticProxy, _) = context.cachedDeclarations.getStaticAndCompanionDeclaration(implFun) + expression.putValueArgument( + 1, + IrFunctionReferenceImpl( + implFunRef.startOffset, implFunRef.endOffset, implFunRef.type, + staticProxy.symbol, + staticProxy.typeParameters.size, + staticProxy.valueParameters.size, + implFunRef.reflectionTarget, implFunRef.origin + ) + ) + } + expression + } + else -> + expression } - return expression } + + private fun shouldReplaceWithStaticCall(callee: IrSimpleFunction) = + callee.isJvmStaticInCompanion() && + callee.visibility == DescriptorVisibilities.PROTECTED && + !callee.isInlineFunctionCall(context) } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SyntheticAccessorLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SyntheticAccessorLowering.kt index 3bbd0ed9a24..beea8d27af5 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SyntheticAccessorLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SyntheticAccessorLowering.kt @@ -332,7 +332,9 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle classes.flatMap { it.declarations.filter(IrDeclaration::isAnonymousObject).filterIsInstance() } val candidates = objectsInScope + companions + classes candidates.lastOrNull { parent is IrClass && it.isSubclassOf(parent) } ?: classes.last() - } else parent + } else { + parent + } private fun IrConstructor.makeConstructorAccessor( originForConstructorAccessor: IrDeclarationOrigin = diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/indy/LambdaMetafactoryArguments.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/indy/LambdaMetafactoryArguments.kt index 45d4e60ba5a..df0dda61df1 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/indy/LambdaMetafactoryArguments.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/indy/LambdaMetafactoryArguments.kt @@ -21,7 +21,6 @@ import org.jetbrains.kotlin.ir.builders.declarations.buildClass import org.jetbrains.kotlin.ir.builders.declarations.buildValueParameter import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.IrFunctionReference -import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl import org.jetbrains.kotlin.ir.overrides.buildFakeOverrideMember import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl @@ -56,7 +55,7 @@ internal class LambdaMetafactoryArgumentsBuilder( // Can't use JDK LambdaMetafactory for function references by default (because of 'equals'). // TODO special mode that would generate indy everywhere? - if (reference.origin != IrStatementOrigin.LAMBDA && !samClass.isFromJava()) + if (!reference.origin.isLambda && !samClass.isFromJava()) return null val samMethod = samClass.getSingleAbstractMethod() @@ -83,7 +82,7 @@ internal class LambdaMetafactoryArgumentsBuilder( // JDK LambdaMetafactory doesn't copy annotations from implementation method to an instance method in a // corresponding synthetic class, which doesn't look like a binary compatible change. // TODO relaxed mode? - if (implFun.annotations.isNotEmpty()) + if (reference.origin.isLambda && implFun.annotations.isNotEmpty()) return null // Don't use JDK LambdaMetafactory for big arity lambdas. diff --git a/compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/withAccessor/protectedSuperclassCompanionObjectMember.kt b/compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/withAccessor/protectedSuperclassCompanionObjectMember.kt new file mode 100644 index 00000000000..a599eb141f2 --- /dev/null +++ b/compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/withAccessor/protectedSuperclassCompanionObjectMember.kt @@ -0,0 +1,36 @@ +// TARGET_BACKEND: JVM +// IGNORE_LIGHT_ANALYSIS +// IGNORE_BACKEND: JVM +// JVM_TARGET: 1.8 +// SAM_CONVERSIONS: INDY +// WITH_RUNTIME +// FULL_JDK + +// CHECK_BYTECODE_TEXT +// 1 java/lang/invoke/LambdaMetafactory + +// FILE: test.kt +import c2.* + +fun box(): String = + C2().supplier().get() + +// FILE: C1.kt +package c1 + +open class C1 { + companion object { + @JvmStatic + protected fun test(): String = "OK" + } +} + +// FILE: C2.kt +package c2 + +import c1.* +import java.util.function.Supplier + +class C2 : C1() { + fun supplier() = Supplier(::test) +} diff --git a/compiler/testData/codegen/box/syntheticAccessors/protectedSuperclassCompanionObjectMember.kt b/compiler/testData/codegen/box/syntheticAccessors/protectedSuperclassCompanionObjectMember.kt new file mode 100644 index 00000000000..a5f9ebcbad5 --- /dev/null +++ b/compiler/testData/codegen/box/syntheticAccessors/protectedSuperclassCompanionObjectMember.kt @@ -0,0 +1,30 @@ +// TARGET_BACKEND: JVM +// WITH_RUNTIME +// IGNORE_LIGHT_ANALYSIS +// IGNORE_BACKEND: JVM + +// FILE: test.kt +import c2.* + +fun box(): String = + C2().b()() + +// FILE: C1.kt +package c1 + +open class C1 { + companion object { + @JvmStatic + protected fun test(string: String): String = + string + } +} + +// FILE: C2.kt +package c2 + +import c1.* + +class C2 : C1() { + fun b() = { test("OK") } +} \ No newline at end of file diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index ec0e4bfeca5..f7a659ff848 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -20934,6 +20934,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { public void testPrivateTopLevelFun() throws Exception { runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/withAccessor/privateTopLevelFun.kt"); } + + @Test + @TestMetadata("protectedSuperclassCompanionObjectMember.kt") + public void testProtectedSuperclassCompanionObjectMember() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/withAccessor/protectedSuperclassCompanionObjectMember.kt"); + } } } @@ -39748,6 +39754,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/syntheticAccessors/protectedFromLambda.kt"); } + @Test + @TestMetadata("protectedSuperclassCompanionObjectMember.kt") + public void testProtectedSuperclassCompanionObjectMember() throws Exception { + runTest("compiler/testData/codegen/box/syntheticAccessors/protectedSuperclassCompanionObjectMember.kt"); + } + @Test @TestMetadata("superCallFromMultipleSubclasses.kt") public void testSuperCallFromMultipleSubclasses() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index 1d66285cf6e..58cd85ecd1b 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -20958,6 +20958,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes public void testPrivateTopLevelFun() throws Exception { runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/withAccessor/privateTopLevelFun.kt"); } + + @Test + @TestMetadata("protectedSuperclassCompanionObjectMember.kt") + public void testProtectedSuperclassCompanionObjectMember() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/withAccessor/protectedSuperclassCompanionObjectMember.kt"); + } } } @@ -39772,6 +39778,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/syntheticAccessors/protectedFromLambda.kt"); } + @Test + @TestMetadata("protectedSuperclassCompanionObjectMember.kt") + public void testProtectedSuperclassCompanionObjectMember() throws Exception { + runTest("compiler/testData/codegen/box/syntheticAccessors/protectedSuperclassCompanionObjectMember.kt"); + } + @Test @TestMetadata("superCallFromMultipleSubclasses.kt") public void testSuperCallFromMultipleSubclasses() throws Exception { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index ce5acb0d68a..6feae2ec201 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -17482,6 +17482,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) public static class WithAccessor extends AbstractLightAnalysisModeTest { + @TestMetadata("protectedSuperclassCompanionObjectMember.kt") + public void ignoreProtectedSuperclassCompanionObjectMember() throws Exception { + runTest("compiler/testData/codegen/box/invokedynamic/sam/functionRefToJavaInterface/withAccessor/protectedSuperclassCompanionObjectMember.kt"); + } + private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); } @@ -31765,6 +31770,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) public static class SyntheticAccessors extends AbstractLightAnalysisModeTest { + @TestMetadata("protectedSuperclassCompanionObjectMember.kt") + public void ignoreProtectedSuperclassCompanionObjectMember() throws Exception { + runTest("compiler/testData/codegen/box/syntheticAccessors/protectedSuperclassCompanionObjectMember.kt"); + } + private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); }