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:
Dmitry Petrov
2021-04-16 16:53:16 +03:00
committed by TeamCityServer
parent b1fb0ba9e1
commit 9a4a39e680
10 changed files with 164 additions and 19 deletions
@@ -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
@@ -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)
}
@@ -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 =
@@ -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.