JVM IR: support -Xmultifile-parts-inherit mode
This commit is contained in:
+82
-19
@@ -17,15 +17,15 @@ import org.jetbrains.kotlin.backend.common.phaser.namedIrModulePhase
|
|||||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||||
import org.jetbrains.kotlin.backend.jvm.codegen.fileParent
|
import org.jetbrains.kotlin.backend.jvm.codegen.fileParent
|
||||||
|
import org.jetbrains.kotlin.config.JvmAnalysisFlags
|
||||||
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
import org.jetbrains.kotlin.descriptors.impl.EmptyPackageFragmentDescriptor
|
import org.jetbrains.kotlin.descriptors.impl.EmptyPackageFragmentDescriptor
|
||||||
import org.jetbrains.kotlin.ir.*
|
import org.jetbrains.kotlin.ir.*
|
||||||
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
|
import org.jetbrains.kotlin.ir.builders.declarations.addConstructor
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.buildClass
|
import org.jetbrains.kotlin.ir.builders.declarations.buildClass
|
||||||
import org.jetbrains.kotlin.ir.builders.irBlockBody
|
|
||||||
import org.jetbrains.kotlin.ir.builders.irCall
|
|
||||||
import org.jetbrains.kotlin.ir.builders.irGet
|
|
||||||
import org.jetbrains.kotlin.ir.builders.irReturn
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
|
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl
|
import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl
|
||||||
@@ -35,12 +35,15 @@ import org.jetbrains.kotlin.ir.expressions.IrGetField
|
|||||||
import org.jetbrains.kotlin.ir.expressions.copyTypeArgumentsFrom
|
import org.jetbrains.kotlin.ir.expressions.copyTypeArgumentsFrom
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl
|
||||||
|
import org.jetbrains.kotlin.ir.types.typeWith
|
||||||
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
|
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
|
||||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||||
|
import org.jetbrains.kotlin.ir.util.primaryConstructor
|
||||||
import org.jetbrains.kotlin.ir.util.transformFlat
|
import org.jetbrains.kotlin.ir.util.transformFlat
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
|
import org.jetbrains.kotlin.load.java.JavaVisibilities
|
||||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||||
|
|
||||||
internal val generateMultifileFacadesPhase = namedIrModulePhase(
|
internal val generateMultifileFacadesPhase = namedIrModulePhase(
|
||||||
@@ -57,7 +60,12 @@ internal val generateMultifileFacadesPhase = namedIrModulePhase(
|
|||||||
val movedFields = mutableMapOf<IrField, IrField>()
|
val movedFields = mutableMapOf<IrField, IrField>()
|
||||||
val functionDelegates = mutableMapOf<IrFunction, IrFunction>()
|
val functionDelegates = mutableMapOf<IrFunction, IrFunction>()
|
||||||
|
|
||||||
input.files.addAll(generateMultifileFacades(input.descriptor, context, movedFields, functionDelegates))
|
// In -Xmultifile-parts-inherit mode, instead of generating "bridge" methods in the facade which call into parts,
|
||||||
|
// we construct an inheritance chain such that all part members are present as fake overrides in the facade.
|
||||||
|
val shouldGeneratePartHierarchy = context.state.languageVersionSettings.getFlag(JvmAnalysisFlags.inheritMultifileParts)
|
||||||
|
input.files.addAll(
|
||||||
|
generateMultifileFacades(input.descriptor, context, shouldGeneratePartHierarchy, movedFields, functionDelegates)
|
||||||
|
)
|
||||||
|
|
||||||
UpdateFieldCallSites(movedFields).lower(input)
|
UpdateFieldCallSites(movedFields).lower(input)
|
||||||
UpdateFunctionCallSites(functionDelegates).lower(input)
|
UpdateFunctionCallSites(functionDelegates).lower(input)
|
||||||
@@ -94,6 +102,7 @@ internal class MultifileFacadeFileEntry(
|
|||||||
private fun generateMultifileFacades(
|
private fun generateMultifileFacades(
|
||||||
module: ModuleDescriptor,
|
module: ModuleDescriptor,
|
||||||
context: JvmBackendContext,
|
context: JvmBackendContext,
|
||||||
|
shouldGeneratePartHierarchy: Boolean,
|
||||||
movedFields: MutableMap<IrField, IrField>,
|
movedFields: MutableMap<IrField, IrField>,
|
||||||
functionDelegates: MutableMap<IrFunction, IrFunction>
|
functionDelegates: MutableMap<IrFunction, IrFunction>
|
||||||
): List<IrFile> =
|
): List<IrFile> =
|
||||||
@@ -111,6 +120,10 @@ private fun generateMultifileFacades(
|
|||||||
val fileEntry = MultifileFacadeFileEntry(jvmClassName, partClasses.map(IrClass::fileParent))
|
val fileEntry = MultifileFacadeFileEntry(jvmClassName, partClasses.map(IrClass::fileParent))
|
||||||
val file = IrFileImpl(fileEntry, EmptyPackageFragmentDescriptor(module, kotlinPackageFqName))
|
val file = IrFileImpl(fileEntry, EmptyPackageFragmentDescriptor(module, kotlinPackageFqName))
|
||||||
|
|
||||||
|
context.log {
|
||||||
|
"Multifile facade $jvmClassName:\n ${partClasses.joinToString("\n ") { it.fqNameWhenAvailable!!.asString() }}\n"
|
||||||
|
}
|
||||||
|
|
||||||
val facadeClass = buildClass {
|
val facadeClass = buildClass {
|
||||||
name = jvmClassName.fqNameForTopLevelClassMaybeWithDollars.shortName()
|
name = jvmClassName.fqNameForTopLevelClassMaybeWithDollars.shortName()
|
||||||
}.apply {
|
}.apply {
|
||||||
@@ -119,6 +132,19 @@ private fun generateMultifileFacades(
|
|||||||
if (jvmClassName.packageFqName != kotlinPackageFqName) {
|
if (jvmClassName.packageFqName != kotlinPackageFqName) {
|
||||||
context.classNameOverride[this] = jvmClassName
|
context.classNameOverride[this] = jvmClassName
|
||||||
}
|
}
|
||||||
|
if (shouldGeneratePartHierarchy) {
|
||||||
|
val superClass = modifyMultifilePartsForHierarchy(context, partClasses)
|
||||||
|
superTypes.add(superClass.typeWith())
|
||||||
|
|
||||||
|
addConstructor {
|
||||||
|
visibility = Visibilities.PRIVATE
|
||||||
|
isPrimary = true
|
||||||
|
}.also { constructor ->
|
||||||
|
constructor.body = context.createIrBuilder(constructor.symbol).irBlockBody {
|
||||||
|
+irDelegatingConstructorCall(superClass.primaryConstructor!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
file.declarations.add(facadeClass)
|
file.declarations.add(facadeClass)
|
||||||
|
|
||||||
@@ -128,8 +154,8 @@ private fun generateMultifileFacades(
|
|||||||
moveFieldsOfConstProperties(partClass, facadeClass, movedFields)
|
moveFieldsOfConstProperties(partClass, facadeClass, movedFields)
|
||||||
|
|
||||||
for (member in partClass.declarations) {
|
for (member in partClass.declarations) {
|
||||||
if (member is IrFunction) {
|
if (member is IrSimpleFunction) {
|
||||||
val newMember = member.createMultifileDelegateIfNeeded(context, facadeClass)
|
val newMember = member.createMultifileDelegateIfNeeded(context, facadeClass, shouldGeneratePartHierarchy)
|
||||||
if (newMember != null) {
|
if (newMember != null) {
|
||||||
functionDelegates[member] = newMember
|
functionDelegates[member] = newMember
|
||||||
}
|
}
|
||||||
@@ -140,6 +166,31 @@ private fun generateMultifileFacades(
|
|||||||
file
|
file
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Changes supertypes of multifile part classes so that they inherit from each other, and returns the last part class.
|
||||||
|
// The multifile facade should inherit from that part class.
|
||||||
|
private fun modifyMultifilePartsForHierarchy(context: JvmBackendContext, unsortedParts: List<IrClass>): IrClass {
|
||||||
|
val parts = unsortedParts.sortedBy(IrClass::name)
|
||||||
|
val superClasses = listOf(context.irBuiltIns.anyClass.owner) + parts.subList(0, parts.size - 1)
|
||||||
|
|
||||||
|
for ((klass, superClass) in parts.zip(superClasses)) {
|
||||||
|
klass.modality = Modality.OPEN
|
||||||
|
klass.visibility = JavaVisibilities.PACKAGE_VISIBILITY
|
||||||
|
|
||||||
|
klass.superTypes.clear()
|
||||||
|
klass.superTypes.add(superClass.typeWith())
|
||||||
|
|
||||||
|
klass.addConstructor {
|
||||||
|
isPrimary = true
|
||||||
|
}.also { constructor ->
|
||||||
|
constructor.body = context.createIrBuilder(constructor.symbol).irBlockBody {
|
||||||
|
+irDelegatingConstructorCall(superClass.primaryConstructor!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return parts.last()
|
||||||
|
}
|
||||||
|
|
||||||
private fun moveFieldsOfConstProperties(partClass: IrClass, facadeClass: IrClass, movedFields: MutableMap<IrField, IrField>) {
|
private fun moveFieldsOfConstProperties(partClass: IrClass, facadeClass: IrClass, movedFields: MutableMap<IrField, IrField>) {
|
||||||
partClass.declarations.transformFlat { member ->
|
partClass.declarations.transformFlat { member ->
|
||||||
if (member is IrField && member.shouldMoveToFacade()) {
|
if (member is IrField && member.shouldMoveToFacade()) {
|
||||||
@@ -158,7 +209,11 @@ private fun IrField.shouldMoveToFacade(): Boolean {
|
|||||||
return property != null && property.isConst && !Visibilities.isPrivate(visibility)
|
return property != null && property.isConst && !Visibilities.isPrivate(visibility)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun IrFunction.createMultifileDelegateIfNeeded(context: JvmBackendContext, facadeClass: IrClass): IrFunction? {
|
private fun IrSimpleFunction.createMultifileDelegateIfNeeded(
|
||||||
|
context: JvmBackendContext,
|
||||||
|
facadeClass: IrClass,
|
||||||
|
shouldGeneratePartHierarchy: Boolean
|
||||||
|
): IrSimpleFunction? {
|
||||||
if (Visibilities.isPrivate(visibility) ||
|
if (Visibilities.isPrivate(visibility) ||
|
||||||
name == StaticInitializersLowering.clinitName ||
|
name == StaticInitializersLowering.clinitName ||
|
||||||
origin == JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR
|
origin == JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR
|
||||||
@@ -166,18 +221,26 @@ private fun IrFunction.createMultifileDelegateIfNeeded(context: JvmBackendContex
|
|||||||
|
|
||||||
// TODO: perform copy of the signature only, without body
|
// TODO: perform copy of the signature only, without body
|
||||||
val function = deepCopyWithSymbols(facadeClass)
|
val function = deepCopyWithSymbols(facadeClass)
|
||||||
function.body = context.createIrBuilder(function.symbol).irBlockBody {
|
|
||||||
+irReturn(irCall(this@createMultifileDelegateIfNeeded).also { call ->
|
if (shouldGeneratePartHierarchy) {
|
||||||
call.passTypeArgumentsFrom(function)
|
function.body = null
|
||||||
function.extensionReceiverParameter?.let { parameter ->
|
function.origin = IrDeclarationOrigin.FAKE_OVERRIDE
|
||||||
call.extensionReceiver = irGet(parameter)
|
function.overriddenSymbols.clear()
|
||||||
}
|
function.overriddenSymbols.add(symbol)
|
||||||
for (parameter in function.valueParameters) {
|
} else {
|
||||||
call.putValueArgument(parameter.index, irGet(parameter))
|
function.body = context.createIrBuilder(function.symbol).irBlockBody {
|
||||||
}
|
+irReturn(irCall(this@createMultifileDelegateIfNeeded).also { call ->
|
||||||
})
|
call.passTypeArgumentsFrom(function)
|
||||||
|
function.extensionReceiverParameter?.let { parameter ->
|
||||||
|
call.extensionReceiver = irGet(parameter)
|
||||||
|
}
|
||||||
|
for (parameter in function.valueParameters) {
|
||||||
|
call.putValueArgument(parameter.index, irGet(parameter))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function.origin = JvmLoweredDeclarationOrigin.MULTIFILE_BRIDGE
|
||||||
}
|
}
|
||||||
function.origin = JvmLoweredDeclarationOrigin.MULTIFILE_BRIDGE
|
|
||||||
|
|
||||||
facadeClass.declarations.add(function)
|
facadeClass.declarations.add(function)
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ interface IrClass :
|
|||||||
override var visibility: Visibility
|
override var visibility: Visibility
|
||||||
|
|
||||||
val kind: ClassKind
|
val kind: ClassKind
|
||||||
val modality: Modality
|
var modality: Modality
|
||||||
val isCompanion: Boolean
|
val isCompanion: Boolean
|
||||||
val isInner: Boolean
|
val isInner: Boolean
|
||||||
val isData: Boolean
|
val isData: Boolean
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ class IrClassImpl(
|
|||||||
override val name: Name,
|
override val name: Name,
|
||||||
override val kind: ClassKind,
|
override val kind: ClassKind,
|
||||||
override var visibility: Visibility,
|
override var visibility: Visibility,
|
||||||
override val modality: Modality,
|
override var modality: Modality,
|
||||||
override val isCompanion: Boolean,
|
override val isCompanion: Boolean,
|
||||||
override val isInner: Boolean,
|
override val isInner: Boolean,
|
||||||
override val isData: Boolean,
|
override val isData: Boolean,
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ class IrLazyClass(
|
|||||||
override val name: Name,
|
override val name: Name,
|
||||||
override val kind: ClassKind,
|
override val kind: ClassKind,
|
||||||
override var visibility: Visibility,
|
override var visibility: Visibility,
|
||||||
override val modality: Modality,
|
override var modality: Modality,
|
||||||
override val isCompanion: Boolean,
|
override val isCompanion: Boolean,
|
||||||
override val isInner: Boolean,
|
override val isInner: Boolean,
|
||||||
override val isData: Boolean,
|
override val isData: Boolean,
|
||||||
|
|||||||
Vendored
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// !INHERIT_MULTIFILE_PARTS
|
// !INHERIT_MULTIFILE_PARTS
|
||||||
// FILE: bar.kt
|
// FILE: bar.kt
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user