[tree generator] Add AbstractElement#subElements, drop semantic leaves

The notion of IR element class being 'semantically leaf' is rather hacky.
Instead, now we only distinguish whether an element has its
implementation class, which is what this notion was actually trying to
represent.

^KT-65773 In Progress
This commit is contained in:
Wojciech Litewka
2024-02-21 17:35:35 +01:00
committed by Space Team
parent 7e01fc5906
commit 6d5b07ebe9
13 changed files with 89 additions and 65 deletions
@@ -0,0 +1,19 @@
/*
* Copyright 2010-2023 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
import org.jetbrains.kotlin.ir.generator.config.AbstractIrTreeImplementationConfigurator
object ImplementationConfigurator : AbstractIrTreeImplementationConfigurator() {
override fun configure(): Unit = with(IrTree) {
impl(simpleFunction)
impl(property)
}
override fun configureAllImplementations() {
// Use configureFieldInAllImplementations to customize certain fields in all implementation classes
}
}
@@ -496,8 +496,6 @@ object IrTree : AbstractTreeBuilder() {
+listField("files", file, mutability = MutableList)
}
val property: Element by element(Declaration) {
isLeaf = true
parent(declarationBase)
parent(possiblyExternalDeclaration)
parent(overridableDeclaration.withArgs("S" to propertySymbolType))
@@ -552,8 +550,6 @@ object IrTree : AbstractTreeBuilder() {
+field("constructor", constructor, nullable = true, isChild = false) // K1
}
val simpleFunction: Element by element(Declaration) {
isLeaf = true
parent(function)
parent(overridableDeclaration.withArgs("S" to simpleFunctionSymbolType))
parent(attributeContainer)
@@ -6,7 +6,7 @@
package org.jetbrains.kotlin.ir.generator
import org.jetbrains.kotlin.generators.tree.printer.generateTree
import org.jetbrains.kotlin.ir.generator.model.markLeaves
import org.jetbrains.kotlin.ir.generator.model.Element
import org.jetbrains.kotlin.ir.generator.print.*
import org.jetbrains.kotlin.utils.bind
import java.io.File
@@ -15,6 +15,8 @@ const val BASE_PACKAGE = "org.jetbrains.kotlin.ir"
internal const val TREE_GENERATOR_README = "compiler/ir/ir.tree/tree-generator/ReadMe.md"
typealias Model = org.jetbrains.kotlin.generators.tree.Model<Element>
fun main(args: Array<String>) {
val generationPath = args.firstOrNull()?.let { File(it) }
?: File("compiler/ir/ir.tree/gen").canonicalFile
@@ -32,9 +34,7 @@ fun main(args: Array<String>) {
elementTransformerVoidType to ::TransformerVoidPrinter,
typeTransformerType to ::TypeTransformerPrinter.bind(model.rootElement),
),
afterConfiguration = {
markLeaves(model.elements)
},
ImplementationConfigurator,
enableBaseTransformerTypeDetection = false,
addFiles = { add(printFactory(generationPath, model)) }
)
@@ -0,0 +1,15 @@
/*
* Copyright 2010-2023 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.config
import org.jetbrains.kotlin.generators.tree.config.AbstractImplementationConfigurator
import org.jetbrains.kotlin.ir.generator.model.Element
import org.jetbrains.kotlin.ir.generator.model.Field
import org.jetbrains.kotlin.ir.generator.model.Implementation
abstract class AbstractIrTreeImplementationConfigurator : AbstractImplementationConfigurator<Implementation, Element, Field>() {
override fun createImplementation(element: Element, name: String?) = Implementation(element, name)
}
@@ -10,7 +10,7 @@ import org.jetbrains.kotlin.ir.generator.model.*
import org.jetbrains.kotlin.ir.generator.model.ElementOrRef
import org.jetbrains.kotlin.ir.generator.model.ElementRef
import org.jetbrains.kotlin.ir.generator.model.ListField
import org.jetbrains.kotlin.ir.generator.model.Model
import org.jetbrains.kotlin.ir.generator.Model
import org.jetbrains.kotlin.types.Variance
import kotlin.properties.PropertyDelegateProvider
import kotlin.properties.ReadOnlyProperty
@@ -17,7 +17,7 @@ class Element(
name: String,
override val propertyName: String,
category: Category,
) : AbstractElement<Element, Field, Nothing>(name) {
) : AbstractElement<Element, Field, Implementation>(name) {
enum class Category(private val packageDir: String, val defaultVisitorParam: String) {
Expression("expressions", "expression"),
@@ -78,17 +78,6 @@ class Element(
override val namePrefix: String
get() = "Ir"
/**
* Whether this element is semantically a leaf element in the hierarchy.
*
* This is set automatically by the [markLeaves] function for all true leaves, but can also be set manually to `true` if
* this element should be considered a leaf semantically.
*
* For example, we only generate [org.jetbrains.kotlin.ir.declarations.IrFactory] methods for leaf elements.
* If we want to generate a method for this element, but it has subclasses, it can be done by manually setting this property to `true`.
*/
var isLeaf = false
override var childrenOrderOverride: List<String>? = null
override var visitorParameterName = category.defaultVisitorParam
@@ -96,7 +85,7 @@ class Element(
var customHasAcceptMethod: Boolean? = null
override val hasAcceptMethod: Boolean
get() = customHasAcceptMethod ?: (isLeaf && parentInVisitor != null)
get() = customHasAcceptMethod ?: (implementations.isNotEmpty() && parentInVisitor != null)
override var hasTransformMethod = false
@@ -135,4 +124,4 @@ class Element(
}
typealias ElementRef = GenericElementRef<Element>
typealias ElementOrRef = GenericElementOrRef<Element>
typealias ElementOrRef = GenericElementOrRef<Element>
@@ -0,0 +1,14 @@
/*
* 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.model
import org.jetbrains.kotlin.generators.tree.AbstractImplementation
import org.jetbrains.kotlin.generators.tree.ImplementationKind
class Implementation(element: Element, name: String?) : AbstractImplementation<Implementation, Element, Field>(element, name) {
override val allFields
get() = element.allFields
}
@@ -1,24 +0,0 @@
/*
* Copyright 2010-2021 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.model
typealias Model = org.jetbrains.kotlin.generators.tree.Model<Element>
internal fun markLeaves(elements: List<Element>) {
val leaves = elements.toMutableSet()
for (el in elements) {
for (parent in el.elementParents) {
if (!parent.element.isLeaf) {
leaves.remove(parent.element)
}
}
}
for (el in leaves) {
el.isLeaf = true
}
}
@@ -15,7 +15,7 @@ import org.jetbrains.kotlin.ir.generator.TREE_GENERATOR_README
import org.jetbrains.kotlin.ir.generator.irFactoryType
import org.jetbrains.kotlin.ir.generator.model.Element
import org.jetbrains.kotlin.ir.generator.model.Field
import org.jetbrains.kotlin.ir.generator.model.Model
import org.jetbrains.kotlin.ir.generator.Model
import org.jetbrains.kotlin.ir.generator.stageControllerType
import org.jetbrains.kotlin.util.capitalizeDecapitalize.capitalizeAsciiOnly
import org.jetbrains.kotlin.utils.SmartPrinter
@@ -33,7 +33,7 @@ internal fun printFactory(generationPath: File, model: Model): GeneratedFile = p
withIndent {
println("val stageController: ", stageControllerType.render())
val factoryMethods = model.elements
.filter { it.isLeaf && it.generateIrFactoryMethod }
.filter { it.implementations.isNotEmpty() && it.generateIrFactoryMethod }
.sortedWith(compareBy({ it.packageName }, { it.name }))
.map(::FactoryMethod)
@@ -42,6 +42,11 @@ abstract class AbstractElement<Element, Field, Implementation>(
val isRootElement: Boolean
get() = elementParents.isEmpty()
/**
* A list of [Element]s which are direct subclasses of this element.
*/
lateinit var subElements: Set<Element>
var isSealed: Boolean = false
/**
@@ -69,18 +69,11 @@ abstract class AbstractImplementationConfigurator<Implementation, Element, Imple
}
private fun generateDefaultImplementations(elements: List<Element>) {
collectLeafsWithoutImplementation(elements).forEach {
impl(it)
}
}
private fun collectLeafsWithoutImplementation(elements: List<Element>): Set<Element> {
val leafs = elements.toMutableSet()
elements.forEach { element ->
leafs.removeAll(element.elementParents.map { it.element }.toSet())
}
leafs.removeAll(elementsWithImpl)
return leafs
elements
.filter { it.subElements.isEmpty() && it !in elementsWithImpl && !it.doesNotNeedImplementation }
.forEach {
impl(it)
}
}
/**
@@ -0,0 +1,20 @@
/*
* 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.generators.tree
internal fun <Element : AbstractElement<Element, *, *>> initializeSubElements(elements: List<Element>){
val elementSubclasses = elements.associateWith { mutableSetOf<Element>() }
for (element in elements) {
for (parent in element.elementParents) {
elementSubclasses.getValue(parent.element) += element
}
}
for ((element, subElements) in elementSubclasses) {
element.subElements = subElements
}
}
@@ -72,8 +72,6 @@ fun printGeneratedType(
* @param builderConfigurator The class for configuring the set of builders, see [Builder] and [AbstractBuilderConfigurator].
* @param createImplementationPrinter Provide the class that prints implementations of elements, see [AbstractImplementationPrinter].
* @param createBuilderPrinter Provide the class that prints the corresponding builder for each element class, see [AbstractBuilderPrinter].
* @param afterConfiguration The routine to run after all implementations and builders were fully configured,
* but before anything was printed to a file.
* @param enableBaseTransformerTypeDetection Whether to use a special algorithm for inferring return types of transformer methods for each
* element, see [detectBaseTransformerTypes].
* @param addFiles Arbitrary files to add to the set of generated files.
@@ -89,7 +87,6 @@ fun <Element, Implementation, ElementField, ImplementationField> generateTree(
builderConfigurator: AbstractBuilderConfigurator<Element, Implementation, ImplementationField, ElementField>? = null,
createImplementationPrinter: ((SmartPrinter) -> AbstractImplementationPrinter<Implementation, Element, ImplementationField>)? = null,
createBuilderPrinter: ((SmartPrinter) -> AbstractBuilderPrinter<Element, Implementation, ImplementationField, ElementField>)? = null,
afterConfiguration: () -> Unit = {},
enableBaseTransformerTypeDetection: Boolean = true,
addFiles: MutableList<GeneratedFile>.() -> Unit = {},
) where Element : AbstractElement<Element, ElementField, Implementation>,
@@ -100,13 +97,13 @@ fun <Element, Implementation, ElementField, ImplementationField> generateTree(
if (enableBaseTransformerTypeDetection) {
detectBaseTransformerTypes(model)
}
initializeSubElements(model.elements)
implementationConfigurator?.configureImplementations(model)
val implementations = model.elements.flatMap { it.implementations }
InterfaceAndAbstractClassConfigurator((model.elements + implementations))
.configureInterfacesAndAbstractClasses()
addPureAbstractElement(model.elements, pureAbstractElement)
builderConfigurator?.configureBuilders()
afterConfiguration()
val generatedFiles = mutableListOf<GeneratedFile>()
model.elements.mapTo(generatedFiles) { element ->