[IR generator] Get rid of the config model

In the IR generator, we had a so-called `ConfigModel` with classes like
`ElementConfig` and `FieldConfig` that we deal with during
tree configuration in `IrTree.kt`, and another kind of model called
just `Model` that included the `Element` and `Field` classes
correspondingly. Those were used for actual code generation.
After configuration, `ConfigModel` was transformed to `Model` and
then the code generation was performed using `Model`.

This architecture is overly complicated and results in massive code
duplication. Most `ElementConfig` and `FieldConfig` properties had
exactly the same counterparts in `Element` in `Field` classes.

So, if you wanted to add a new feature to the tree generator, you had to
add a property to both `ConfigModel` and `Model`.

Turns out we can do just fine with only one kind of model.
This commit is contained in:
Sergej Jaskiewicz
2023-11-02 19:26:43 +01:00
committed by Space Team
parent 37417f7919
commit 6ac4cd5973
7 changed files with 395 additions and 615 deletions
File diff suppressed because it is too large Load Diff
@@ -5,10 +5,11 @@
package org.jetbrains.kotlin.ir.generator
import org.jetbrains.kotlin.generators.tree.addPureAbstractElement
import org.jetbrains.kotlin.generators.util.GeneratorsFileUtil
import org.jetbrains.kotlin.generators.util.GeneratorsFileUtil.collectPreviouslyGeneratedFiles
import org.jetbrains.kotlin.generators.util.GeneratorsFileUtil.removeExtraFilesFromPreviousGeneration
import org.jetbrains.kotlin.ir.generator.model.config2model
import org.jetbrains.kotlin.ir.generator.model.*
import org.jetbrains.kotlin.ir.generator.print.*
import java.io.File
@@ -20,8 +21,13 @@ fun main(args: Array<String>) {
val generationPath = args.firstOrNull()?.let { File(it) }
?: File("compiler/ir/ir.tree/gen").canonicalFile
val config = IrTree.build()
val model = config2model(config)
val model = IrTree.build()
configureInterfacesAndAbstractClasses(model.elements)
addPureAbstractElement(model.elements, elementBaseType)
markLeaves(model.elements)
processFieldOverrides(model.elements)
addWalkableChildren(model.elements)
val previouslyGeneratedFiles = collectPreviouslyGeneratedFiles(generationPath)
val generatedFiles = sequence {
@@ -5,30 +5,47 @@
package org.jetbrains.kotlin.ir.generator.config
import org.jetbrains.kotlin.generators.tree.TypeRef
import org.jetbrains.kotlin.generators.tree.TypeRefWithNullability
import org.jetbrains.kotlin.generators.tree.TypeVariable
import org.jetbrains.kotlin.generators.tree.type
import org.jetbrains.kotlin.generators.tree.*
import org.jetbrains.kotlin.ir.generator.model.*
import org.jetbrains.kotlin.ir.generator.model.ElementRef
import org.jetbrains.kotlin.types.Variance
import kotlin.properties.PropertyDelegateProvider
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty
import org.jetbrains.kotlin.generators.tree.ElementOrRef as GenericElementOrRef
abstract class AbstractTreeBuilder {
private val configurationCallbacks = mutableListOf<() -> ElementConfig>()
private val configurationCallbacks = mutableListOf<() -> Element>()
abstract val rootElement: ElementConfig
abstract val rootElement: Element
fun element(category: ElementConfig.Category, name: String? = null, initializer: ElementConfig.() -> Unit = {}): ElementConfigDel {
val del = ElementConfigDel(category, name)
protected fun Field.skipInIrFactory() {
useInIrFactoryStrategy = Field.UseFieldAsParameterInIrFactoryStrategy.No
}
protected fun Field.useFieldInIrFactory(defaultValue: String? = null) {
useInIrFactoryStrategy = Field.UseFieldAsParameterInIrFactoryStrategy.Yes(defaultValue)
}
fun element(category: Element.Category, name: String? = null, initializer: Element.() -> Unit = {}): ElementDelegate {
val del = ElementDelegate(category, name)
configurationCallbacks.add {
del.element!!.apply { initializer() }
del.element!!.apply {
initializer()
if (elementParents.isEmpty() && this != rootElement) {
elementParents.add(ElementRef(rootElement))
}
}
}
return del
}
protected fun ElementConfig.parent(type: TypeRef) {
parents.add(type)
protected fun Element.parent(type: ClassRef<*>) {
otherParents.add(type)
}
protected fun Element.parent(type: ElementOrRef) {
elementParents.add(ElementRef(type.element, type.args, type.nullable))
}
protected fun param(name: String, vararg bounds: TypeRef, variance: Variance = Variance.INVARIANT): TypeVariable {
@@ -41,33 +58,48 @@ abstract class AbstractTreeBuilder {
nullable: Boolean = false,
mutable: Boolean = true,
isChild: Boolean = false,
initializer: SimpleFieldConfig.() -> Unit = {}
): SimpleFieldConfig {
initializer: SingleField.() -> Unit = {}
): SingleField {
checkChildType(isChild, type, name)
return SimpleFieldConfig(name, type, nullable, mutable, isChild).apply(initializer)
return SingleField(name, type?.copy(nullable) ?: InferredOverriddenType, mutable, isChild).apply(initializer)
}
protected fun listField(
name: String,
elementType: TypeRef?,
nullable: Boolean = false,
mutability: ListFieldConfig.Mutability = ListFieldConfig.Mutability.Immutable,
mutability: ListField.Mutability = ListField.Mutability.Immutable,
isChild: Boolean = false,
initializer: ListFieldConfig.() -> Unit = {}
): ListFieldConfig {
initializer: ListField.() -> Unit = {}
): ListField {
checkChildType(isChild, elementType, name)
return ListFieldConfig(name, elementType, nullable, mutability, isChild).apply(initializer)
val listType = when (mutability) {
ListField.Mutability.List -> StandardTypes.mutableList
ListField.Mutability.Array -> StandardTypes.array
else -> StandardTypes.list
}
return ListField(
name = name,
elementType = elementType ?: InferredOverriddenType,
listType = listType,
isNullable = nullable,
mutable = mutability == ListField.Mutability.Var,
isChild = isChild,
transformable = mutability != ListField.Mutability.Immutable,
).apply(initializer)
}
private fun checkChildType(isChild: Boolean, type: TypeRef?, name: String) {
if (isChild) {
require(type == null || type is ElementConfigOrRef) { "Field $name is a child field but has non-element type $type" }
require(type == null || type is GenericElementOrRef<*, *>) {
"Field $name is a child field but has non-element type $type"
}
}
}
fun build(): Config {
fun build(): Model {
val elements = configurationCallbacks.map { it() }
return Config(elements, rootElement)
return Model(elements, rootElement)
}
companion object {
@@ -77,20 +109,20 @@ abstract class AbstractTreeBuilder {
}
}
class ElementConfigDel(
private val category: ElementConfig.Category,
class ElementDelegate(
private val category: Element.Category,
private val name: String?
) : ReadOnlyProperty<AbstractTreeBuilder, ElementConfig>, PropertyDelegateProvider<AbstractTreeBuilder, ElementConfigDel> {
var element: ElementConfig? = null
) : ReadOnlyProperty<AbstractTreeBuilder, Element>, PropertyDelegateProvider<AbstractTreeBuilder, ElementDelegate> {
var element: Element? = null
private set
override fun getValue(thisRef: AbstractTreeBuilder, property: KProperty<*>): ElementConfig {
override fun getValue(thisRef: AbstractTreeBuilder, property: KProperty<*>): Element {
return element!!
}
override fun provideDelegate(thisRef: AbstractTreeBuilder, property: KProperty<*>): ElementConfigDel {
override fun provideDelegate(thisRef: AbstractTreeBuilder, property: KProperty<*>): ElementDelegate {
val path = thisRef.javaClass.name + "." + property.name
element = ElementConfig(path, name ?: property.name, category)
element = Element(name ?: property.name, path, category)
return this
}
}
@@ -1,185 +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.config
import org.jetbrains.kotlin.generators.tree.*
import org.jetbrains.kotlin.ir.generator.BASE_PACKAGE
import org.jetbrains.kotlin.ir.generator.model.Element
import org.jetbrains.kotlin.utils.SmartPrinter
class Config(
val elements: List<ElementConfig>,
val rootElement: ElementConfig,
)
class ElementConfig(
val propertyName: String,
val name: String,
val category: Category
) : ElementConfigOrRef {
val params = mutableListOf<TypeVariable>()
val parents = mutableListOf<TypeRef>()
val fields = mutableListOf<FieldConfig>()
val usedTypes = mutableListOf<Importable>()
var visitorName: String? = null
var visitorParent: ElementConfig? = null
var visitorParam: String? = null
var accept = false // By default, accept is generated only for leaves.
var transform = false
var transformByChildren = false
var transformerReturnType: ElementConfig? = null
var childrenOrderOverride: List<String>? = null
var ownsChildren = true // If false, acceptChildren/transformChildren will NOT be generated.
var generateIrFactoryMethod = category == Category.Declaration
val additionalIrFactoryMethodParameters = mutableListOf<FieldConfig>()
val fieldsToSkipInIrFactoryMethod = hashSetOf<String>()
/**
* Set this to `true` if the element should be a leaf semantically, but technically it's not.
*
* For example, we only generate [IrFactory] methods for leaf elements. If we want to generate a method for this element, but it has
* subclasses, it can be done by setting this property to `true`.
*/
var isForcedLeaf = false
var typeKind: TypeKind? = null
var generationCallback: (context(ImportCollector) SmartPrinter.() -> Unit)? = null
var kDoc: String? = null
override val element get() = this
override val args get() = emptyMap<NamedTypeParameterRef, TypeRef>()
override val nullable get() = false
override fun copy(args: Map<NamedTypeParameterRef, TypeRef>) = ElementConfigRef(this, args, false)
override fun copy(nullable: Boolean) = ElementConfigRef(this, args, nullable)
override fun substitute(map: TypeParameterSubstitutionMap): ElementConfig = this
operator fun TypeVariable.unaryPlus() = apply {
params.add(this)
}
operator fun FieldConfig.unaryPlus() = apply {
fields.add(this)
}
override fun toString() = element.name
override val packageName: String
get() = category.packageName
override val typeName: String
get() = Element.elementName2typeName(name)
context(ImportCollector)
override fun renderTo(appendable: Appendable) {
addImport(this)
appendable.append(typeName)
if (params.isNotEmpty()) {
params.joinTo(appendable, prefix = "<", postfix = ">") { it.name }
}
}
enum class Category(private val packageDir: String, val defaultVisitorParam: String) {
Expression("expressions", "expression"),
Declaration("declarations", "declaration"),
Other("", "element");
val packageName: String get() = BASE_PACKAGE + if (packageDir.isNotEmpty()) ".$packageDir" else ""
}
}
sealed interface ElementConfigOrRef : ParametrizedTypeRef<ElementConfigOrRef, NamedTypeParameterRef>, TypeRefWithNullability, Importable {
val element: ElementConfig
}
class ElementConfigRef(
override val element: ElementConfig,
override val args: Map<NamedTypeParameterRef, TypeRef>,
override val nullable: Boolean
) : ElementConfigOrRef {
override val packageName: String
get() = element.packageName
override val typeName: String
get() = element.typeName
override fun copy(args: Map<NamedTypeParameterRef, TypeRef>) = ElementConfigRef(element, args, nullable)
override fun copy(nullable: Boolean) = ElementConfigRef(element, args, nullable)
override fun toString() = element.name
context(ImportCollector)
override fun renderTo(appendable: Appendable) {
addImport(element)
appendable.append(element.typeName)
renderArgsTo(appendable)
renderNullabilityTo(appendable)
}
}
sealed class UseFieldAsParameterInIrFactoryStrategy {
data object No : UseFieldAsParameterInIrFactoryStrategy()
data class Yes(val defaultValue: String?) : UseFieldAsParameterInIrFactoryStrategy()
}
sealed class FieldConfig(
val name: String,
val isChild: Boolean,
) {
var baseDefaultValue: String? = null
var baseGetter: String? = null
var customSetter: String? = null
var optInAnnotation: ClassRef<*>? = null
var deprecation: Deprecated? = null
var visibility = Visibility.PUBLIC
internal var useFieldInIrFactoryStrategy: UseFieldAsParameterInIrFactoryStrategy =
if (isChild) UseFieldAsParameterInIrFactoryStrategy.No else UseFieldAsParameterInIrFactoryStrategy.Yes(null)
fun useFieldInIrFactory(defaultValue: String? = null) {
useFieldInIrFactoryStrategy = UseFieldAsParameterInIrFactoryStrategy.Yes(defaultValue)
}
fun skipInIrFactory() {
useFieldInIrFactoryStrategy = UseFieldAsParameterInIrFactoryStrategy.No
}
var kDoc: String? = null
override fun toString() = name
}
class SimpleFieldConfig(
name: String,
val type: TypeRefWithNullability?,
val nullable: Boolean,
val mutable: Boolean,
isChildElement: Boolean,
) : FieldConfig(name, isChildElement)
class ListFieldConfig(
name: String,
val elementType: TypeRef?,
val nullable: Boolean,
val mutability: Mutability,
isChildElement: Boolean,
) : FieldConfig(name, isChildElement) {
enum class Mutability {
Immutable,
Var,
List,
Array
}
}
@@ -6,23 +6,40 @@
package org.jetbrains.kotlin.ir.generator.model
import org.jetbrains.kotlin.generators.tree.*
import org.jetbrains.kotlin.ir.generator.config.ElementConfig
import org.jetbrains.kotlin.ir.generator.config.FieldConfig
import org.jetbrains.kotlin.ir.generator.BASE_PACKAGE
import org.jetbrains.kotlin.utils.SmartPrinter
import org.jetbrains.kotlin.utils.topologicalSort
import org.jetbrains.kotlin.generators.tree.ElementOrRef as GenericElementOrRef
import org.jetbrains.kotlin.generators.tree.ElementRef as GenericElementRef
class Element(
config: ElementConfig,
override val name: String,
override val packageName: String,
override val params: List<TypeVariable>,
override val fields: MutableSet<Field>,
val additionalFactoryMethodParameters: MutableList<Field>,
override val propertyName: String,
category: Category,
) : AbstractElement<Element, Field>() {
override var elementParents: List<ElementRef> = emptyList()
enum class Category(private val packageDir: String, val defaultVisitorParam: String) {
Expression("expressions", "expression"),
Declaration("declarations", "declaration"),
Other("", "element");
val packageName: String get() = BASE_PACKAGE + if (packageDir.isNotEmpty()) ".$packageDir" else ""
}
override val packageName: String = category.packageName
override val elementParents = mutableListOf<ElementRef>()
override var otherParents: MutableList<ClassRef<*>> = mutableListOf()
override val params = mutableListOf<TypeVariable>()
override val fields = mutableSetOf<Field>()
val additionalIrFactoryMethodParameters = mutableListOf<Field>()
var generateIrFactoryMethod = category == Category.Declaration
val fieldsToSkipInIrFactoryMethod = hashSetOf<String>()
override val allFields: List<Field>
get() = fields.toList()
@@ -38,26 +55,46 @@ class Element(
override var parentInVisitor: Element? = null
var transformerReturnType: Element? = null
override var kind: ImplementationKind? = when (config.typeKind) {
TypeKind.Class -> ImplementationKind.AbstractClass
TypeKind.Interface -> ImplementationKind.Interface
null -> null
}
var typeKind: TypeKind? = null
set(value) {
kind = when (value) {
TypeKind.Class -> ImplementationKind.AbstractClass
TypeKind.Interface -> ImplementationKind.Interface
null -> null
}
field = value
}
override var kind: ImplementationKind? = null
override val typeName
get() = elementName2typeName(name)
var isLeaf = config.isForcedLeaf
val childrenOrderOverride: List<String>? = config.childrenOrderOverride
/**
* 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
var childrenOrderOverride: List<String>? = null
override var walkableChildren: List<Field> = emptyList()
override val transformableChildren get() = walkableChildren.filter { it.transformable }
override val visitFunctionName = "visit" + (config.visitorName ?: name).replaceFirstChar(Char::uppercaseChar)
override val visitorParameterName = config.visitorParam ?: config.category.defaultVisitorParam
var visitorName: String? = null
override var hasAcceptMethod = config.accept
override val visitFunctionName: String
get() = "visit" + (visitorName ?: name).replaceFirstChar(Char::uppercaseChar)
override val hasTransformMethod = config.transform
override var visitorParameterName = category.defaultVisitorParam
override var hasAcceptMethod = false // By default, accept is generated only for leaves.
override var hasTransformMethod = false
override val hasAcceptChildrenMethod: Boolean
get() = ownsChildren && (isRootElement || walkableChildren.isNotEmpty())
@@ -65,17 +102,14 @@ class Element(
override val hasTransformChildrenMethod: Boolean
get() = ownsChildren && (isRootElement || transformableChildren.isNotEmpty())
val transformByChildren = config.transformByChildren
val ownsChildren = config.ownsChildren
val generateIrFactoryMethod = config.generateIrFactoryMethod
val fieldsToSkipInIrFactoryMethod = config.fieldsToSkipInIrFactoryMethod
var transformByChildren = false
var ownsChildren = true // If false, acceptChildren/transformChildren will NOT be generated.
val generationCallback = config.generationCallback
override val propertyName = config.propertyName
var generationCallback: (context(ImportCollector) SmartPrinter.() -> Unit)? = null
override val kDoc = config.kDoc
override var kDoc: String? = null
val usedTypes: List<Importable> = config.usedTypes
val usedTypes = mutableListOf<Importable>()
override fun toString() = name
@@ -105,38 +139,46 @@ class Element(
.distinctBy { it.name }
.asReversed()
}
operator fun TypeVariable.unaryPlus() = apply {
params.add(this)
}
operator fun Field.unaryPlus() = apply {
fields.add(this)
}
}
typealias ElementRef = GenericElementRef<Element, Field>
typealias ElementOrRef = GenericElementOrRef<Element, Field>
@Suppress("LeakingThis")
sealed class Field(
config: FieldConfig,
override val name: String,
override var isMutable: Boolean,
val isChild: Boolean,
) : AbstractField() {
abstract val baseDefaultValue: String?
abstract val baseGetter: String?
var baseDefaultValue: String? = null
var baseGetter: String? = null
abstract val transformable: Boolean
val useInIrFactoryStrategy = config.useFieldInIrFactoryStrategy
sealed class UseFieldAsParameterInIrFactoryStrategy {
init {
kDoc = config.kDoc
optInAnnotation = config.optInAnnotation
deprecation = config.deprecation
visibility = config.visibility
data object No : UseFieldAsParameterInIrFactoryStrategy()
data class Yes(val defaultValue: String?) : UseFieldAsParameterInIrFactoryStrategy()
}
var useInIrFactoryStrategy =
if (isChild) UseFieldAsParameterInIrFactoryStrategy.No else UseFieldAsParameterInIrFactoryStrategy.Yes(null)
override val withGetter: Boolean
get() = baseGetter != null
override val defaultValueInImplementation: String?
get() = baseGetter ?: baseDefaultValue
override val customSetter: String? = config.customSetter
override var customSetter: String? = null
override fun toString() = "$name: $typeRef"
@@ -154,29 +196,32 @@ sealed class Field(
}
class SingleField(
config: FieldConfig,
name: String,
override var typeRef: TypeRefWithNullability,
mutable: Boolean,
isChild: Boolean,
override val baseDefaultValue: String?,
override val baseGetter: String?,
) : Field(config, name, mutable, isChild) {
) : Field(name, mutable, isChild) {
override val transformable: Boolean
get() = isMutable
}
class ListField(
config: FieldConfig,
name: String,
var elementType: TypeRef,
private val isNullable: Boolean,
private val listType: ClassRef<PositionTypeParameterRef>,
mutable: Boolean,
isChild: Boolean,
override val transformable: Boolean,
override val baseDefaultValue: String?,
override val baseGetter: String?,
) : Field(config, name, mutable, isChild) {
) : Field(name, mutable, isChild) {
override val typeRef: TypeRefWithNullability
get() = listType.withArgs(elementType)
get() = listType.withArgs(elementType).copy(isNullable)
enum class Mutability {
Immutable,
Var,
List,
Array
}
}
@@ -6,14 +6,8 @@
package org.jetbrains.kotlin.ir.generator.model
import org.jetbrains.kotlin.generators.tree.*
import org.jetbrains.kotlin.ir.generator.config.*
import org.jetbrains.kotlin.ir.generator.elementBaseType
import org.jetbrains.kotlin.utils.addToStdlib.UnsafeCastFunction
import org.jetbrains.kotlin.utils.addToStdlib.castAll
import org.jetbrains.kotlin.utils.addToStdlib.partitionIsInstance
import org.jetbrains.kotlin.generators.tree.ElementRef as GenericElementRef
private object InferredOverriddenType : TypeRefWithNullability {
internal object InferredOverriddenType : TypeRefWithNullability {
context(ImportCollector)
override fun renderTo(appendable: Appendable) {
@@ -30,117 +24,7 @@ private object InferredOverriddenType : TypeRefWithNullability {
data class Model(val elements: List<Element>, val rootElement: Element)
fun config2model(config: Config): Model {
val ec2el = mutableMapOf<ElementConfig, Element>()
val elements = config.elements.map { ec ->
Element(
config = ec,
name = ec.name,
packageName = ec.category.packageName,
params = ec.params,
fields = ec.fields.mapTo(mutableSetOf(), ::transformFieldConfig),
additionalFactoryMethodParameters = ec.additionalIrFactoryMethodParameters.mapTo(mutableListOf(), ::transformFieldConfig)
).also {
ec2el[ec.element] = it
}
}
val rootElement = replaceElementRefs(config, ec2el)
configureInterfacesAndAbstractClasses(elements)
addPureAbstractElement(elements, elementBaseType)
markLeaves(elements)
processFieldOverrides(elements)
addWalkableChildren(elements)
return Model(elements, rootElement)
}
private fun transformFieldConfig(fc: FieldConfig): Field = when (fc) {
is SimpleFieldConfig -> SingleField(
fc,
fc.name,
fc.type?.copy(fc.nullable) ?: InferredOverriddenType,
fc.mutable,
fc.isChild,
fc.baseDefaultValue,
fc.baseGetter,
)
is ListFieldConfig -> {
val listType = when (fc.mutability) {
ListFieldConfig.Mutability.List -> StandardTypes.mutableList
ListFieldConfig.Mutability.Array -> StandardTypes.array
else -> StandardTypes.list
}
ListField(
fc,
fc.name,
fc.elementType ?: InferredOverriddenType,
listType.copy(fc.nullable),
fc.mutability == ListFieldConfig.Mutability.Var,
fc.isChild,
fc.mutability != ListFieldConfig.Mutability.Immutable,
fc.baseDefaultValue,
fc.baseGetter,
)
}
}
@OptIn(UnsafeCastFunction::class)
@Suppress("UNCHECKED_CAST")
private fun replaceElementRefs(config: Config, mapping: Map<ElementConfig, Element>): Element {
val visited = mutableMapOf<TypeRef, TypeRef>()
fun transform(type: TypeRef): TypeRef {
visited[type]?.let {
return it
}
return when (type) {
is ElementConfigOrRef -> {
val args = type.args.mapValues { transform(it.value) }
val el = mapping.getValue(type.element)
ElementRef(el, args, type.nullable)
}
is ClassRef<*> -> {
@Suppress("UNCHECKED_CAST") // this is the upper bound, compiler could know that, right?
type as ClassRef<TypeParameterRef>
val args = type.args.mapValues { transform(it.value) }
type.copy(args = args)
}
else -> type
}.also { visited[type] = it }
}
val rootEl = transform(config.rootElement) as GenericElementRef<Element, Field>
for (ec in config.elements) {
val el = mapping[ec.element]!!
val (elParents, otherParents) = ec.parents
.map { transform(it) }
.partitionIsInstance<TypeRef, ElementRef>()
el.elementParents = elParents.takeIf { it.isNotEmpty() || el == rootEl.element } ?: listOf(rootEl)
el.otherParents = otherParents.castAll<ClassRef<*>>().toMutableList()
el.parentInVisitor = (ec.visitorParent?.let(::transform) as GenericElementRef<Element, Field>?)?.element
el.transformerReturnType = (ec.transformerReturnType?.let(::transform) as GenericElementRef<Element, Field>?)?.element
for (field in el.fields) {
when (field) {
is SingleField -> {
field.typeRef = transform(field.typeRef) as TypeRefWithNullability
}
is ListField -> {
field.elementType = transform(field.elementType)
}
}
}
}
return rootEl.element
}
private fun markLeaves(elements: List<Element>) {
internal fun markLeaves(elements: List<Element>) {
val leaves = elements.toMutableSet()
for (el in elements) {
@@ -159,7 +43,7 @@ private fun markLeaves(elements: List<Element>) {
}
}
private fun processFieldOverrides(elements: List<Element>) {
internal fun processFieldOverrides(elements: List<Element>) {
for (element in iterateElementsParentFirst(elements)) {
for (field in element.fields) {
fun visitParents(visited: Element) {
@@ -193,7 +77,7 @@ private fun processFieldOverrides(elements: List<Element>) {
}
}
private fun addWalkableChildren(elements: List<Element>) {
internal fun addWalkableChildren(elements: List<Element>) {
for (element in elements) {
val walkableChildren = mutableMapOf<String, Field>()
@@ -12,9 +12,9 @@ import org.jetbrains.kotlin.generators.tree.printer.printFunctionDeclaration
import org.jetbrains.kotlin.generators.tree.printer.printGeneratedType
import org.jetbrains.kotlin.ir.generator.IrTree
import org.jetbrains.kotlin.ir.generator.TREE_GENERATOR_README
import org.jetbrains.kotlin.ir.generator.config.UseFieldAsParameterInIrFactoryStrategy
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.stageControllerType
import org.jetbrains.kotlin.util.capitalizeDecapitalize.capitalizeAsciiOnly
@@ -255,10 +255,10 @@ private class FactoryMethod(val element: Element) {
val name = "create" + element.name.capitalizeAsciiOnly()
val parameters = (element.allFieldsRecursively() + element.additionalFactoryMethodParameters)
val parameters = (element.allFieldsRecursively() + element.additionalIrFactoryMethodParameters)
.filterNot { it.name in element.fieldsToSkipInIrFactoryMethod }
.mapNotNull { field ->
(field.useInIrFactoryStrategy as? UseFieldAsParameterInIrFactoryStrategy.Yes)?.let {
(field.useInIrFactoryStrategy as? Field.UseFieldAsParameterInIrFactoryStrategy.Yes)?.let {
FunctionParameter(field.name, field.typeRef, it.defaultValue)
}
}