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 1e02aa46e72..241b8312f5e 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 @@ -42192,6 +42192,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/syntheticAccessors/kt48331.kt"); } + @Test + @TestMetadata("kt48954.kt") + public void testKt48954() throws Exception { + runTest("compiler/testData/codegen/box/syntheticAccessors/kt48954.kt"); + } + @Test @TestMetadata("kt9717.kt") public void testKt9717() throws Exception { diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/indy/LambdaMetafactoryArguments.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/indy/LambdaMetafactoryArguments.kt index b395b2f5b35..4cc85f04336 100644 --- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/indy/LambdaMetafactoryArguments.kt +++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/indy/LambdaMetafactoryArguments.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.backend.common.lower.VariableRemapper import org.jetbrains.kotlin.backend.common.lower.parents import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound +import org.jetbrains.kotlin.backend.jvm.ir.findSuperDeclaration import org.jetbrains.kotlin.backend.jvm.ir.getSingleAbstractMethod import org.jetbrains.kotlin.backend.jvm.ir.isCompiledToJvmDefault import org.jetbrains.kotlin.backend.jvm.lower.findInterfaceImplementation @@ -26,6 +27,7 @@ import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid +import org.jetbrains.kotlin.load.java.JavaDescriptorVisibilities import org.jetbrains.kotlin.load.java.JvmAnnotationNames import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name @@ -78,6 +80,7 @@ internal class LambdaMetafactoryArgumentsBuilder( // TODO in cases where LambdaMetafactory is unusable directly due to problems with the implementation function, // we can still avoid generating an entire class by converting the function reference into a lambda first; // see `InlineCallableReferenceToLambdaPhase` + val implFun = reference.symbol.owner // Don't generate references to intrinsic functions as invokedynamic (no such method exists at run-time). @@ -97,6 +100,18 @@ internal class LambdaMetafactoryArgumentsBuilder( return null } + // It's possible to reference through a child class a method declared in a package-private base Java class. + // In this case the corresponding method might be inaccessible in the context where it's referenced (see KT-48954). + // For now, just prohibit referencing methods from package-private Java classes through indy (without precise accessibility check). + // TODO wrap into lambda? + if (implFun is IrSimpleFunction) { + val baseFun = findSuperDeclaration(implFun, false, context.state.jvmDefaultMode) + val baseFunClass = baseFun.parent as? IrClass + if (baseFunClass != null && baseFunClass.visibility == JavaDescriptorVisibilities.PACKAGE_VISIBILITY) { + return null + } + } + val implFunParent = implFun.parent if (implFunParent is IrClass && implFunParent.origin == IrDeclarationOrigin.JVM_MULTIFILE_CLASS) { // LambdaMetafactory treats multifile class part members as non-accessible, diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt index 08eed1a3330..34da3f298d2 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt @@ -428,29 +428,8 @@ class MethodSignatureMapper(private val context: JvmBackendContext) { fun mapCalleeToAsmMethod(function: IrSimpleFunction, isSuperCall: Boolean = false): Method = mapAsmMethod(findSuperDeclaration(function, isSuperCall)) - // Copied from KotlinTypeMapper.findSuperDeclaration. - internal fun findSuperDeclaration(function: IrSimpleFunction, isSuperCall: Boolean): IrSimpleFunction { - var current = function - while (current.isFakeOverride) { - // TODO: probably isJvmInterface instead of isInterface, here and in KotlinTypeMapper - val classCallable = current.overriddenSymbols.firstOrNull { !it.owner.parentAsClass.isInterface }?.owner - if (classCallable != null) { - current = classCallable - continue - } - if (isSuperCall && !current.parentAsClass.isInterface && - current.resolveFakeOverride()?.run { - isMethodOfAny() || !isCompiledToJvmDefault(context.state.jvmDefaultMode) - } == true - ) { - return current - } - - current = current.overriddenSymbols.firstOrNull()?.owner - ?: error("Fake override should have at least one overridden descriptor: ${current.render()}") - } - return current - } + private fun findSuperDeclaration(function: IrSimpleFunction, isSuperCall: Boolean): IrSimpleFunction = + findSuperDeclaration(function, isSuperCall, context.state.jvmDefaultMode) private fun getJvmMethodNameIfSpecial(irFunction: IrSimpleFunction): String? { if (irFunction.origin == JvmLoweredDeclarationOrigin.STATIC_INLINE_CLASS_REPLACEMENT) { diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/JvmInvokeDynamic.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/JvmInvokeDynamic.kt index af015770114..bde528bef7d 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/JvmInvokeDynamic.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/JvmInvokeDynamic.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.backend.jvm.intrinsics import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.codegen.* +import org.jetbrains.kotlin.backend.jvm.ir.findSuperDeclaration import org.jetbrains.kotlin.ir.builders.declarations.buildClass import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrConstructor @@ -106,7 +107,7 @@ object JvmInvokeDynamic : IntrinsicMethod() { is IrSimpleFunction -> { // Note that if the given function is a fake override, we emit a method handle with explicit super class. // This has the same binary compatibility guarantees as in Java. - codegen.methodSignatureMapper.findSuperDeclaration(irFun0, false) + findSuperDeclaration(irFun0, false, codegen.state.jvmDefaultMode) } else -> throw java.lang.AssertionError("Simple function or constructor expected: ${irFun0.render()}") diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/JvmIrUtils.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/JvmIrUtils.kt index 26eeda9924d..83d8ba681b7 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/JvmIrUtils.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/JvmIrUtils.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.backend.jvm.ir import org.jetbrains.kotlin.backend.common.ir.ir2string +import org.jetbrains.kotlin.backend.common.ir.isMethodOfAny import org.jetbrains.kotlin.backend.common.lower.at import org.jetbrains.kotlin.backend.common.lower.irNot import org.jetbrains.kotlin.backend.jvm.CachedFieldsForObjectInstances @@ -395,3 +396,26 @@ fun IrDeclarationParent.getCallableReferenceOwnerKClassType(context: JvmBackendC fun IrDeclaration.getCallableReferenceTopLevelFlag(): Int = if (parent.let { it is IrClass && it.isFileClass }) 1 else 0 + +// Based on KotlinTypeMapper.findSuperDeclaration. +fun findSuperDeclaration(function: IrSimpleFunction, isSuperCall: Boolean, jvmDefaultMode: JvmDefaultMode): IrSimpleFunction { + var current = function + while (current.isFakeOverride) { + // TODO: probably isJvmInterface instead of isInterface, here and in KotlinTypeMapper + val classCallable = current.overriddenSymbols.firstOrNull { !it.owner.parentAsClass.isInterface }?.owner + if (classCallable != null) { + current = classCallable + continue + } + if (isSuperCall && !current.parentAsClass.isInterface) { + val overridden = current.resolveFakeOverride() + if (overridden != null && (overridden.isMethodOfAny() || !overridden.isCompiledToJvmDefault(jvmDefaultMode))) { + return current + } + } + + current = current.overriddenSymbols.firstOrNull()?.owner + ?: error("Fake override should have at least one overridden descriptor: ${current.render()}") + } + return current +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/syntheticAccessors/kt48954.kt b/compiler/testData/codegen/box/syntheticAccessors/kt48954.kt new file mode 100644 index 00000000000..9d6c153087c --- /dev/null +++ b/compiler/testData/codegen/box/syntheticAccessors/kt48954.kt @@ -0,0 +1,41 @@ +// TARGET_BACKEND: JVM +// FULL_JDK +// JVM_TARGET: 1.8 + +// FILE: kt48954.kt +import lib.* +import app.* + +fun box(): String { + val foo = Foo() + Service(foo::bar).test() + return foo.p +} + +// FILE: app/Service.kt +package app + +import java.util.function.Consumer + +class Service(private val consumer: Consumer) { + fun test() { + consumer.accept("OK") + } +} + +// FILE: lib/PackagePrivateBase.java +package lib; + +class PackagePrivateBase { + public String p; + + public void bar(String param) { + this.p = param; + } +} + +// FILE: lib/Foo.java +package lib; + +public class Foo extends PackagePrivateBase { +} 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 daaeb8c953f..c2295a54c89 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 @@ -42036,6 +42036,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/syntheticAccessors/kt48331.kt"); } + @Test + @TestMetadata("kt48954.kt") + public void testKt48954() throws Exception { + runTest("compiler/testData/codegen/box/syntheticAccessors/kt48954.kt"); + } + @Test @TestMetadata("kt9717.kt") public void testKt9717() 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 cd4e106fdb8..32f83d6f880 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 @@ -42192,6 +42192,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/syntheticAccessors/kt48331.kt"); } + @Test + @TestMetadata("kt48954.kt") + public void testKt48954() throws Exception { + runTest("compiler/testData/codegen/box/syntheticAccessors/kt48954.kt"); + } + @Test @TestMetadata("kt9717.kt") public void testKt9717() 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 7cd5958d8b9..00dd430c3ee 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -33839,6 +33839,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/syntheticAccessors/kt48331.kt"); } + @TestMetadata("kt48954.kt") + public void testKt48954() throws Exception { + runTest("compiler/testData/codegen/box/syntheticAccessors/kt48954.kt"); + } + @TestMetadata("kt9717.kt") public void testKt9717() throws Exception { runTest("compiler/testData/codegen/box/syntheticAccessors/kt9717.kt");