[IR] Final preparation to autogenerate IR declaration implementations

IR expressions are left out for now, because unlike declarations,
which are mostly created via IrFactory, expressions' constructors are
widely used, and it's hard to replicate the exact signatures of those
constructors with the tree generator.

Therefore, some other approach is expected to be taken when generating
them in the future.

^KT-65773 In Progress
This commit is contained in:
Wojciech Litewka
2024-02-21 16:40:11 +01:00
committed by Space Team
parent 451c51c849
commit 6cdddaacb0
13 changed files with 259 additions and 57 deletions
@@ -629,7 +629,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
override fun configureAllImplementations(model: Model) {
configureFieldInAllImplementations(
field = "controlFlowGraphReference",
fieldName = "controlFlowGraphReference",
implementationPredicate = { it.typeName != "FirAnonymousFunctionImpl" }
) {
defaultNull(it)
@@ -661,7 +661,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
"FirInaccessibleReceiverExpressionImpl"
)
configureFieldInAllImplementations(
field = "typeRef",
fieldName = "typeRef",
implementationPredicate = { it.typeName !in implementationWithConfigurableTypeRef },
fieldPredicate = { it.defaultValueInImplementation == null }
) {
@@ -670,7 +670,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
}
configureFieldInAllImplementations(
field = "lValueTypeRef",
fieldName = "lValueTypeRef",
implementationPredicate = { it.typeName in "FirVariableAssignmentImpl" },
fieldPredicate = { it.defaultValueInImplementation == null }
) {
@@ -27,6 +27,9 @@ private class ImplementationFieldPrinter(printer: SmartPrinter) : AbstractFieldP
override fun forceMutable(field: FieldWithDefault): Boolean = field.isMutable && field.isMutableOrEmptyIfList()
override fun actualTypeOfField(field: FieldWithDefault) = field.getMutableType()
override val wrapOptInAnnotations
get() = true
}
internal class ImplementationPrinter(
@@ -5,16 +5,139 @@
package org.jetbrains.kotlin.ir.generator
import org.jetbrains.kotlin.generators.tree.StandardTypes
import org.jetbrains.kotlin.ir.generator.config.AbstractIrTreeImplementationConfigurator
import org.jetbrains.kotlin.ir.generator.model.Element
import org.jetbrains.kotlin.ir.generator.model.ListField
object ImplementationConfigurator : AbstractIrTreeImplementationConfigurator() {
override fun configure(model: Model): Unit = with(IrTree) {
impl(simpleFunction)
impl(property)
impl(anonymousInitializer) {
implementation.doPrint = false
}
impl(simpleFunction) {
implementation.doPrint = false
}
impl(functionWithLateBinding) {
implementation.doPrint = false
}
impl(constructor) {
implementation.doPrint = false
}
impl(field) {
implementation.doPrint = false
}
impl(property) {
implementation.doPrint = false
}
impl(propertyWithLateBinding) {
implementation.doPrint = false
}
impl(localDelegatedProperty) {
implementation.doPrint = false
}
impl(typeParameter) {
implementation.doPrint = false
}
impl(valueParameter) {
implementation.doPrint = false
}
impl(variable) {
implementation.doPrint = false
}
impl(`class`) {
implementation.doPrint = false
}
impl(enumEntry) {
implementation.doPrint = false
}
impl(script) {
implementation.doPrint = false
}
impl(moduleFragment) {
implementation.doPrint = false
}
impl(errorDeclaration) {
implementation.doPrint = false
}
impl(externalPackageFragment) {
implementation.doPrint = false
}
impl(file) {
implementation.doPrint = false
}
impl(typeAlias) {
implementation.doPrint = false
}
}
override fun configureAllImplementations(model: Model) {
// Use configureFieldInAllImplementations to customize certain fields in all implementation classes
configureFieldInAllImplementations("parent") {
isLateinit("parent")
isMutable("parent")
}
configureFieldInAllImplementations("attributeOwnerId") {
default(it, "this")
}
configureFieldInAllImplementations("originalBeforeInline") {
defaultNull(it)
}
configureFieldInAllImplementations("metadata") {
defaultNull(it)
}
configureFieldInAllImplementations("annotations") {
defaultEmptyList(it)
}
configureFieldInAllImplementations("overriddenSymbols") {
defaultEmptyList(it)
}
configureFieldInAllImplementations("typeParameters") {
defaultEmptyList(it)
}
configureFieldInAllImplementations("statements") {
default(it, "ArrayList(2)")
}
configureFieldInAllImplementations("descriptor", { impl -> impl.allFields.any { it.name == "symbol" } }) {
default(it, "symbol.descriptor", withGetter = true)
}
configureFieldInAllImplementations(
fieldName = null,
fieldPredicate = { it is ListField && it.isChild && it.listType == StandardTypes.mutableList }
) {
default(it, "ArrayList()")
}
// Generation of implementation classes of IrExpression are left out for subsequent MR, as a part of KT-65773.
for (element in model.elements) {
if (element.category == Element.Category.Expression) {
for (implementation in element.implementations) {
implementation.doPrint = false
}
}
}
}
}
@@ -35,6 +35,7 @@ fun main(args: Array<String>) {
typeTransformerType to ::TypeTransformerPrinter.bind(model.rootElement),
),
ImplementationConfigurator,
createImplementationPrinter = ::ImplementationPrinter,
enableBaseTransformerTypeDetection = false,
addFiles = { add(printFactory(generationPath, model)) }
)
@@ -16,7 +16,7 @@ import org.jetbrains.kotlin.generators.tree.ElementRef as GenericElementRef
class Element(
name: String,
override val propertyName: String,
category: Category,
val category: Category,
) : AbstractElement<Element, Field, Implementation>(name) {
enum class Category(private val packageDir: String, val defaultVisitorParam: String) {
@@ -7,8 +7,19 @@ package org.jetbrains.kotlin.ir.generator.model
import org.jetbrains.kotlin.generators.tree.AbstractImplementation
import org.jetbrains.kotlin.generators.tree.ImplementationKind
import org.jetbrains.kotlin.generators.tree.ImportCollector
import org.jetbrains.kotlin.utils.SmartPrinter
class Implementation(element: Element, name: String?) : AbstractImplementation<Implementation, Element, Field>(element, name) {
override val allFields
get() = element.allFields
override val allFields: List<Field> = element.allFields.map { it.copy() }
override var kind: ImplementationKind? = ImplementationKind.FinalClass
var generationCallback: (context(ImportCollector) SmartPrinter.() -> Unit)? = null
override var doPrint = true
init {
isPublic = true
}
}
@@ -0,0 +1,49 @@
/*
* Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.ir.generator.print
import com.intellij.psi.util.PsiExpressionTrimRenderer.render
import org.jetbrains.kotlin.generators.tree.*
import org.jetbrains.kotlin.generators.tree.printer.printBlock
import org.jetbrains.kotlin.ir.generator.IrTree
import org.jetbrains.kotlin.ir.generator.IrTree.parent
import org.jetbrains.kotlin.ir.generator.irImplementationDetailType
import org.jetbrains.kotlin.ir.generator.model.*
import org.jetbrains.kotlin.utils.SmartPrinter
internal class ImplementationPrinter(printer: SmartPrinter) : AbstractImplementationPrinter<Implementation, Element, Field>(printer) {
override fun makeFieldPrinter(printer: SmartPrinter) = object : AbstractFieldPrinter<Field>(printer) {
override fun forceMutable(field: Field) = field.isMutable
}
override val pureAbstractElementType: ClassRef<*>
get() = org.jetbrains.kotlin.ir.generator.elementBaseType
override val implementationOptInAnnotation: ClassRef<*>
get() = irImplementationDetailType
override val separateFieldsWithBlankLine: Boolean
get() = true
context(ImportCollector)
override fun SmartPrinter.printAdditionalMethods(implementation: Implementation) {
implementation.generationCallback?.invoke(this@ImportCollector, this)
if (
implementation.element.traverseParentsUntil { it == IrTree.symbolOwner } &&
!implementation.element.let { it == IrTree.propertyWithLateBinding || it == IrTree.functionWithLateBinding }
) {
val symbolField = implementation["symbol"]
if (symbolField != null) {
println()
print("init")
printBlock {
println("${symbolField.name}.bind(this)")
}
}
}
}
}
@@ -30,6 +30,9 @@ abstract class AbstractFieldPrinter<Field : AbstractField<*>>(
*/
protected open fun actualTypeOfField(field: Field): TypeRefWithNullability = field.typeRef
protected open val wrapOptInAnnotations: Boolean
get() = false
context(ImportCollector)
fun printField(
field: Field,
@@ -51,9 +54,9 @@ abstract class AbstractFieldPrinter<Field : AbstractField<*>>(
isLateinit = (inImplementation || field.isFinal) && field.isLateinit,
isVolatile = (inImplementation || field.isFinal) && field.isVolatile,
optInAnnotation = field.optInAnnotation,
printOptInWrapped = defaultValue != null,
printOptInWrapped = wrapOptInAnnotations && defaultValue != null,
deprecation = field.deprecation,
kDoc = field.kDoc,
kDoc = field.kDoc.takeIf { !inImplementation },
initializer = defaultValue.takeUnless { field.withGetter }
)
println()
@@ -64,6 +64,10 @@ abstract class AbstractImplementation<Implementation, Element, Field>(
get() = true
var isPublic = false
var putImplementationOptInInConstructor = true
var constructorParameterOrderOverride: List<String>? = null
override fun get(fieldName: String): Field? {
return allFields.firstOrNull { it.name == fieldName }
}
@@ -92,4 +96,7 @@ abstract class AbstractImplementation<Implementation, Element, Field>(
}
var builder: LeafBuilder<Field, Element, Implementation>? = null
open val doPrint: Boolean
get() = true
}
@@ -25,11 +25,13 @@ abstract class AbstractImplementationPrinter<Implementation, Element, Implementa
protected abstract val pureAbstractElementType: ClassRef<*>
protected open val separateFieldsWithBlankLine: Boolean
get() = false
protected abstract fun makeFieldPrinter(printer: SmartPrinter): AbstractFieldPrinter<ImplementationField>
context(ImportCollector)
protected open fun SmartPrinter.printAdditionalMethods(implementation: Implementation) {
}
protected open fun SmartPrinter.printAdditionalMethods(implementation: Implementation) {}
context(ImportCollector)
fun printImplementation(implementation: Implementation) {
@@ -63,19 +65,21 @@ abstract class AbstractImplementationPrinter<Implementation, Element, Implementa
val fieldPrinter = makeFieldPrinter(this)
if (!isInterface && !isAbstract && implementation.fieldsInConstructor.isNotEmpty()) {
if (implementation.isPublic) {
if (implementation.isPublic && implementation.putImplementationOptInInConstructor) {
print(" @", implementationOptInAnnotation.render(), " constructor")
}
println("(")
withIndent {
implementation.fieldsInConstructor.forEachIndexed { _, field ->
if (field.isParameter) {
print(field.name, ": ", field.typeRef.render())
println(",")
} else if (!field.isFinal) {
fieldPrinter.printField(field, inImplementation = true, override = true, inConstructor = true)
implementation.fieldsInConstructor
.reorderFieldsIfNecessary(implementation.constructorParameterOrderOverride)
.forEachIndexed { _, field ->
if (field.isParameter) {
print(field.name, ": ", field.typeRef.render())
println(",")
} else if (!field.isFinal) {
fieldPrinter.printField(field, inImplementation = true, override = true, inConstructor = true)
}
}
}
}
print(")")
}
@@ -86,23 +90,18 @@ abstract class AbstractImplementationPrinter<Implementation, Element, Implementa
}
print(implementation.allParents.joinToString { "${it.render()}${it.kind.braces()}" })
printBlock {
if (isInterface || isAbstract) {
implementation.allFields.forEach {
fieldPrinter.printField(
it,
inImplementation = true,
override = true,
modality = Modality.ABSTRACT.takeIf { isAbstract }
)
}
} else {
implementation.fieldsInBody.forEach {
fieldPrinter.printField(
it,
inImplementation = true,
override = true
)
val fields = if (isInterface || isAbstract) implementation.allFields
else implementation.fieldsInBody
fields.forEachIndexed { index, field ->
if (index > 0 && separateFieldsWithBlankLine) {
println()
}
fieldPrinter.printField(
field,
inImplementation = true,
override = true,
modality = Modality.ABSTRACT.takeIf { isAbstract }
)
}
printAdditionalMethods(implementation)
@@ -80,14 +80,14 @@ abstract class AbstractImplementationConfigurator<Implementation, Element, Imple
* Allows to batch-apply [config] to certain fields in _all_ the implementations that satisfy the given
* [implementationPredicate].
*
* @param field The name of the field to configure across all `Impl` classes.
* @param fieldName The name of the field to configure across all `Impl` classes, or `null` if [config] should be applied to all fields.
* @param implementationPredicate Only implementations satisfying this predicate will be used in this configuration.
* @param fieldPredicate Only fields satisfying this predicate will be configured
* @param config The configuration block. Accepts the field name as an argument.
* See [ImplementationContext]'s documentation for description of its DSL methods.
*/
protected fun configureFieldInAllImplementations(
field: String,
fieldName: String?,
implementationPredicate: (Implementation) -> Boolean = { true },
fieldPredicate: (ImplementationField) -> Boolean = { true },
config: ImplementationContext.(field: String) -> Unit,
@@ -95,9 +95,17 @@ abstract class AbstractImplementationConfigurator<Implementation, Element, Imple
for (element in elementsWithImpl) {
for (implementation in element.implementations) {
if (!implementationPredicate(implementation)) continue
if (!implementation.allFields.any { it.name == field }) continue
if (!fieldPredicate(implementation.getField(field))) continue
ImplementationContext(implementation).config(field)
if (fieldName != null && !implementation.allFields.any { it.name == fieldName }) continue
val fields = if (fieldName != null) {
listOf(implementation.getField(fieldName))
} else {
implementation.allFields
}
for (field in fields.filter(fieldPredicate)) {
ImplementationContext(implementation).config(field.name)
}
}
}
}
@@ -83,9 +83,9 @@ fun <Element, Implementation, ElementField, ImplementationField> generateTree(
pureAbstractElement: ClassRef<*>,
createElementPrinter: (SmartPrinter) -> AbstractElementPrinter<Element, ElementField>,
createVisitorPrinters: List<Pair<ClassRef<*>, (SmartPrinter, ClassRef<*>) -> AbstractVisitorPrinter<Element, ElementField>>>,
implementationConfigurator: AbstractImplementationConfigurator<Implementation, Element, ImplementationField>? = null,
implementationConfigurator: AbstractImplementationConfigurator<Implementation, Element, ImplementationField>,
builderConfigurator: AbstractBuilderConfigurator<Element, Implementation, ImplementationField, ElementField>? = null,
createImplementationPrinter: ((SmartPrinter) -> AbstractImplementationPrinter<Implementation, Element, ImplementationField>)? = null,
createImplementationPrinter: (SmartPrinter) -> AbstractImplementationPrinter<Implementation, Element, ImplementationField>,
createBuilderPrinter: ((SmartPrinter) -> AbstractBuilderPrinter<Element, Implementation, ImplementationField, ElementField>)? = null,
enableBaseTransformerTypeDetection: Boolean = true,
addFiles: MutableList<GeneratedFile>.() -> Unit = {},
@@ -98,7 +98,7 @@ fun <Element, Implementation, ElementField, ImplementationField> generateTree(
detectBaseTransformerTypes(model)
}
initializeSubElements(model.elements)
implementationConfigurator?.configureImplementations(model)
implementationConfigurator.configureImplementations(model)
val implementations = model.elements.flatMap { it.implementations }
InterfaceAndAbstractClassConfigurator((model.elements + implementations))
.configureInterfacesAndAbstractClasses()
@@ -117,17 +117,15 @@ fun <Element, Implementation, ElementField, ImplementationField> generateTree(
}
}
if (createImplementationPrinter != null) {
implementations.mapTo(generatedFiles) { implementation ->
printGeneratedType(
generationPath,
treeGeneratorReadme,
implementation.packageName,
implementation.typeName,
fileSuppressions = listOf("DuplicatedCode", "unused"),
) {
createImplementationPrinter(this).printImplementation(implementation)
}
implementations.filter { it.doPrint }.mapTo(generatedFiles) { implementation ->
printGeneratedType(
generationPath,
treeGeneratorReadme,
implementation.packageName,
implementation.typeName,
fileSuppressions = listOf("DuplicatedCode", "unused"),
) {
createImplementationPrinter(this).printImplementation(implementation)
}
}
@@ -16,7 +16,7 @@ object ImplementationConfigurator : AbstractSwiftIrTreeImplementationConfigurato
override fun configureAllImplementations(model: Model) {
// Use configureFieldInAllImplementations to customize certain fields in all implementation classes
configureFieldInAllImplementations(
field = "parent",
fieldName = "parent",
) {
isMutable(it)
isLateinit(it)