JVM_IR KT-45998 fix protected companion object member accessors
Also, make sure it works with indy-based SAM conversions.
This commit is contained in:
committed by
TeamCityServer
parent
b1fb0ba9e1
commit
9a4a39e680
+12
@@ -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 {
|
||||
|
||||
+14
-1
@@ -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
|
||||
|
||||
+33
-14
@@ -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)
|
||||
}
|
||||
|
||||
+3
-1
@@ -332,7 +332,9 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle
|
||||
classes.flatMap { it.declarations.filter(IrDeclaration::isAnonymousObject).filterIsInstance<IrClass>() }
|
||||
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 =
|
||||
|
||||
+2
-3
@@ -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.
|
||||
|
||||
+36
@@ -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<String>(::test)
|
||||
}
|
||||
Vendored
+30
@@ -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") }
|
||||
}
|
||||
+12
@@ -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 {
|
||||
|
||||
+12
@@ -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 {
|
||||
|
||||
+10
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user