JVM IR: fail when SyntheticAccessorLowering adds accessor to other files

This would help for example in debugging the issue fixed in the previous
commit.

The only problem by now where this lowering tried to add accessors to
foreign files was reproduced for interfaces inheriting from Cloneable.
There, we generate a DefaultImpls bridge that calls protected method
`clone` from java.lang.Cloneable.DefaultImpls. This makes no sense, but
the old backend behaves the same. Instead of generating accessor for it
in JVM IR, we now see all DefaultImpls bridges as public as a
workaround. (The fact that assertion no longer fails here is checked
e.g. by box/reflection/mapping/methodsFromObject.kt.)
This commit is contained in:
Alexander Udalov
2020-01-03 11:43:59 +01:00
parent 957b100cd1
commit d6ed93b2b8
3 changed files with 24 additions and 16 deletions
@@ -11,9 +11,9 @@ import org.jetbrains.kotlin.backend.common.deepCopyWithVariables
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.Scope
import org.jetbrains.kotlin.ir.declarations.*
@@ -514,6 +514,7 @@ fun createStaticFunctionWithReceivers(
dispatchReceiverType: IrType? = oldFunction.dispatchReceiverParameter?.type,
origin: IrDeclarationOrigin = oldFunction.origin,
modality: Modality = Modality.FINAL,
visibility: Visibility = oldFunction.visibility,
copyMetadata: Boolean = true
): IrSimpleFunction {
val descriptor = (oldFunction.descriptor as? DescriptorWithContainerSource)?.let {
@@ -524,7 +525,7 @@ fun createStaticFunctionWithReceivers(
origin,
IrSimpleFunctionSymbolImpl(descriptor),
name,
oldFunction.visibility,
visibility,
modality,
oldFunction.returnType,
isInline = oldFunction.isInline,
@@ -210,7 +210,12 @@ class JvmDeclarationFactory(
else -> JvmLoweredDeclarationOrigin.DEFAULT_IMPLS_BRIDGE
},
// Old backend doesn't generate ACC_FINAL on DefaultImpls methods.
modality = Modality.OPEN
modality = Modality.OPEN,
// Interface functions are always public, with one exception: clone in Cloneable, which is protected. However, Cloneable
// has no DefaultImpls, so this merely replicates the incorrect behavior of the old backend. We should rather not generate
// a bridge to clone when interface inherits from Cloneable at all. Below, we force everything, including those bridges,
// to be public so that we won't try to generate synthetic accessor for them.
visibility = Visibilities.PUBLIC
).also { it.copyAttributes(interfaceFun) }
}
}
@@ -39,13 +39,21 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrElementTransformerVoidWithContext(), FileLoweringPass {
private val pendingTransformations = mutableListOf<Function0<Unit>>()
private val pendingAccessorsToAdd = mutableListOf<IrFunction>()
private val inlineLambdaToCallSite = mutableMapOf<IrFunction, IrDeclaration?>()
override fun lower(irFile: IrFile) {
inlineLambdaToCallSite.putAll(IrInlineReferenceLocator.scan(context, irFile).lambdaToCallSite)
irFile.transformChildrenVoid(this)
pendingTransformations.forEach { it() }
for (accessor in pendingAccessorsToAdd) {
assert(accessor.file == irFile) {
"SyntheticAccessorLowering should not attempt to modify other files!\n" +
"While lowering this file: ${irFile.render()}\n" +
"Trying to add this accessor: ${accessor.render()}"
}
(accessor.parent as IrDeclarationContainer).declarations.add(accessor)
}
}
private val functionMap = mutableMapOf<IrFunctionSymbol, IrFunctionSymbol>()
@@ -68,11 +76,7 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle
!expression.symbol.isAccessible(withSuper, thisSymbol) ->
functionMap.getOrPut(expression.symbol) {
when (val symbol = expression.symbol) {
is IrConstructorSymbol -> symbol.owner.makeConstructorAccessor().also { accessor ->
pendingTransformations.add {
(accessor.parent as IrDeclarationContainer).declarations.add(accessor)
}
}.symbol
is IrConstructorSymbol -> symbol.owner.makeConstructorAccessor().also(pendingAccessorsToAdd::add).symbol
is IrSimpleFunctionSymbol -> symbol.owner.makeSimpleFunctionAccessor(expression as IrCall).symbol
else -> error("Unknown subclass of IrFunctionSymbol")
}
@@ -101,9 +105,7 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle
override fun visitConstructor(declaration: IrConstructor): IrStatement {
if (declaration.isOrShouldBeHidden) {
pendingTransformations.add {
declaration.parentAsClass.declarations.add(handleHiddenConstructor(declaration))
}
pendingAccessorsToAdd.add(handleHiddenConstructor(declaration))
declaration.visibility = Visibilities.PRIVATE
}
@@ -241,7 +243,7 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle
isSuspend = source.isSuspend // synthetic accessors of suspend functions are handled in codegen
}.also { accessor ->
accessor.parent = parent
pendingTransformations.add { (accessor.parent as IrDeclarationContainer).declarations.add(accessor) }
pendingAccessorsToAdd.add(accessor)
accessor.copyTypeParametersFrom(source, JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR)
accessor.copyValueParametersToStatic(source, JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR, dispatchReceiverType)
@@ -273,7 +275,7 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle
returnType = fieldSymbol.owner.type
}.also { accessor ->
accessor.parent = fieldSymbol.owner.accessorParent()
pendingTransformations.add { (accessor.parent as IrDeclarationContainer).declarations.add(accessor) }
pendingAccessorsToAdd.add(accessor)
if (!fieldSymbol.owner.isStatic) {
accessor.addValueParameter(
@@ -309,7 +311,7 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle
returnType = context.irBuiltIns.unitType
}.also { accessor ->
accessor.parent = fieldSymbol.owner.accessorParent()
pendingTransformations.add { (accessor.parent as IrDeclarationContainer).declarations.add(accessor) }
pendingAccessorsToAdd.add(accessor)
if (!fieldSymbol.owner.isStatic) {
accessor.addValueParameter(