[IR generator] Simplify computation of walkable children

Don't require to specify them explicitly via `isChild` in IR generator,
instead test the field type whether it is an element.
This commit is contained in:
Sergej Jaskiewicz
2023-11-16 19:01:36 +01:00
committed by Space Team
parent ad4e97154f
commit 5f04bc8a27
7 changed files with 152 additions and 161 deletions
@@ -105,6 +105,7 @@ object IrTree : AbstractTreeBuilder() {
+descriptor("DeclarationDescriptor")
+field("origin", type(Packages.declarations, "IrDeclarationOrigin"))
+field("parent", declarationParent) {
needAcceptAndTransform = false
skipInIrFactory()
}
+factory
@@ -237,7 +238,7 @@ object IrTree : AbstractTreeBuilder() {
TODO: consider dropping [$name] if it isn't used by any known plugin.
""".trimIndent()
}
+field("defaultValue", expressionBody, nullable = true, isChild = true)
+field("defaultValue", expressionBody, nullable = true)
}
val `class`: Element by element(Declaration) {
parent(declarationBase)
@@ -285,7 +286,7 @@ object IrTree : AbstractTreeBuilder() {
+listField("superTypes", irTypeType, mutability = Var) {
skipInIrFactory()
}
+field("thisReceiver", valueParameter, nullable = true, isChild = true)
+field("thisReceiver", valueParameter, nullable = true)
+field(
"valueClassRepresentation",
type<ValueClassRepresentation<*>>().withArgs(type(Packages.types, "IrSimpleType")),
@@ -316,10 +317,12 @@ object IrTree : AbstractTreeBuilder() {
""".trimIndent()
+field("attributeOwnerId", attributeContainer) {
needAcceptAndTransform = false
skipInIrFactory()
}
// null <=> this element wasn't inlined
+field("originalBeforeInline", attributeContainer, nullable = true) {
needAcceptAndTransform = false
skipInIrFactory()
}
}
@@ -331,14 +334,14 @@ object IrTree : AbstractTreeBuilder() {
+field("isStatic", boolean) {
useFieldInIrFactory(defaultValue = "false")
}
+field("body", blockBody, isChild = true)
+field("body", blockBody)
}
val declarationContainer: Element by element(Declaration) {
ownsChildren = false
parent(declarationParent)
+listField("declarations", declaration, mutability = MutableList, isChild = true) {
+listField("declarations", declaration, mutability = MutableList) {
kDoc = """
Accessing list of declaration may trigger lazy declaration list computation for lazy class,
which requires computation of fake-overrides for this class. So it's unsafe to access it
@@ -354,7 +357,7 @@ object IrTree : AbstractTreeBuilder() {
parent(declaration)
parent(declarationParent)
+listField("typeParameters", typeParameter, mutability = Var, isChild = true)
+listField("typeParameters", typeParameter, mutability = Var)
}
val typeParameter: Element by element(Declaration) {
needTransformMethod()
@@ -394,14 +397,14 @@ object IrTree : AbstractTreeBuilder() {
+field("isInline", boolean)
+field("isExpect", boolean)
+field("returnType", irTypeType)
+field("dispatchReceiverParameter", valueParameter, nullable = true, isChild = true)
+field("extensionReceiverParameter", valueParameter, nullable = true, isChild = true)
+listField("valueParameters", valueParameter, mutability = Var, isChild = true)
+field("dispatchReceiverParameter", valueParameter, nullable = true)
+field("extensionReceiverParameter", valueParameter, nullable = true)
+listField("valueParameters", valueParameter, mutability = Var)
// The first `contextReceiverParametersCount` value parameters are context receivers.
+field("contextReceiverParametersCount", int) {
skipInIrFactory()
}
+field("body", body, nullable = true, isChild = true)
+field("body", body, nullable = true)
}
val constructor: Element by element(Declaration) {
parent(function)
@@ -416,8 +419,8 @@ object IrTree : AbstractTreeBuilder() {
+descriptor("ClassDescriptor")
+symbol(enumEntrySymbolType)
+field("initializerExpression", expressionBody, nullable = true, isChild = true)
+field("correspondingClass", `class`, nullable = true, isChild = true)
+field("initializerExpression", expressionBody, nullable = true)
+field("correspondingClass", `class`, nullable = true)
}
val errorDeclaration: Element by element(Declaration) {
parent(declarationBase)
@@ -453,7 +456,7 @@ object IrTree : AbstractTreeBuilder() {
+field("type", irTypeType)
+field("isFinal", boolean)
+field("isStatic", boolean)
+field("initializer", expressionBody, nullable = true, isChild = true)
+field("initializer", expressionBody, nullable = true)
+field("correspondingPropertySymbol", propertySymbolType, nullable = true) {
skipInIrFactory()
}
@@ -468,9 +471,9 @@ object IrTree : AbstractTreeBuilder() {
+symbol(localDelegatedPropertySymbolType)
+field("type", irTypeType)
+field("isVar", boolean)
+field("delegate", variable, isChild = true)
+field("getter", simpleFunction, isChild = true)
+field("setter", simpleFunction, nullable = true, isChild = true)
+field("delegate", variable)
+field("getter", simpleFunction)
+field("setter", simpleFunction, nullable = true)
}
val moduleFragment: Element by element(Declaration) {
needTransformMethod()
@@ -482,7 +485,7 @@ object IrTree : AbstractTreeBuilder() {
}
+field("name", type<Name>(), mutable = false)
+field("irBuiltins", type(Packages.tree, "IrBuiltIns"), mutable = false)
+listField("files", file, mutability = MutableList, isChild = true)
+listField("files", file, mutability = MutableList)
usedTypes += ArbitraryImportable(Packages.tree, "UNDEFINED_OFFSET")
+field("startOffset", int, mutable = false) {
baseGetter = "UNDEFINED_OFFSET"
@@ -511,9 +514,9 @@ object IrTree : AbstractTreeBuilder() {
useFieldInIrFactory(defaultValue = "false")
}
+isFakeOverrideField()
+field("backingField", field, nullable = true, isChild = true)
+field("getter", simpleFunction, nullable = true, isChild = true)
+field("setter", simpleFunction, nullable = true, isChild = true)
+field("backingField", field, nullable = true)
+field("getter", simpleFunction, nullable = true)
+field("setter", simpleFunction, nullable = true)
}
private fun isFakeOverrideField() = field("isFakeOverride", boolean) {
@@ -534,18 +537,20 @@ object IrTree : AbstractTreeBuilder() {
+symbol(scriptSymbolType)
// NOTE: is the result of the FE conversion, because there script interpreted as a class and has receiver
// TODO: consider removing from here and handle appropriately in the lowering
+field("thisReceiver", valueParameter, isChild = true, nullable = true) // K1
+field("thisReceiver", valueParameter, nullable = true) // K1
+field("baseClass", irTypeType, nullable = true) // K1
+listField("explicitCallParameters", variable, mutability = Var, isChild = true)
+listField("implicitReceiversParameters", valueParameter, mutability = Var, isChild = true)
+listField("explicitCallParameters", variable, mutability = Var)
+listField("implicitReceiversParameters", valueParameter, mutability = Var)
+listField("providedProperties", propertySymbolType, mutability = Var)
+listField("providedPropertiesParameters", valueParameter, mutability = Var, isChild = true)
+listField("providedPropertiesParameters", valueParameter, mutability = Var)
+field("resultProperty", propertySymbolType, nullable = true)
+field("earlierScriptsParameter", valueParameter, nullable = true, isChild = true)
+field("earlierScriptsParameter", valueParameter, nullable = true)
+listField("importedScripts", scriptSymbolType, mutability = Var, nullable = true)
+listField("earlierScripts", scriptSymbolType, mutability = Var, nullable = true)
+field("targetClass", classSymbolType, nullable = true)
+field("constructor", constructor, nullable = true) // K1
+field("constructor", constructor, nullable = true) { // K1
needAcceptAndTransform = false
}
}
val simpleFunction: Element by element(Declaration) {
isLeaf = true
@@ -586,7 +591,7 @@ object IrTree : AbstractTreeBuilder() {
+field("isVar", boolean)
+field("isConst", boolean)
+field("isLateinit", boolean)
+field("initializer", expression, nullable = true, isChild = true)
+field("initializer", expression, nullable = true)
}
val packageFragment: Element by element(Declaration) {
ownsChildren = false
@@ -636,7 +641,9 @@ object IrTree : AbstractTreeBuilder() {
parent(metadataSourceOwner)
+symbol(fileSymbolType)
+field("module", moduleFragment)
+field("module", moduleFragment) {
needAcceptAndTransform = false
}
+field("fileEntry", type(Packages.tree, "IrFileEntry"))
}
@@ -649,10 +656,12 @@ object IrTree : AbstractTreeBuilder() {
parent(attributeContainer)
+field("attributeOwnerId", attributeContainer) {
needAcceptAndTransform = false
baseDefaultValue = "this"
skipInIrFactory()
}
+field("originalBeforeInline", attributeContainer, nullable = true) {
needAcceptAndTransform = false
baseDefaultValue = "null"
skipInIrFactory()
}
@@ -661,7 +670,7 @@ object IrTree : AbstractTreeBuilder() {
val statementContainer: Element by element(Expression) {
ownsChildren = false
+listField("statements", statement, mutability = MutableList, isChild = true)
+listField("statements", statement, mutability = MutableList)
}
val body: Element by element(Expression) {
needTransformMethod()
@@ -677,7 +686,7 @@ object IrTree : AbstractTreeBuilder() {
parent(body)
+factory
+field("expression", expression, isChild = true) {
+field("expression", expression) {
useFieldInIrFactory()
}
}
@@ -703,15 +712,15 @@ object IrTree : AbstractTreeBuilder() {
parent(declarationReference)
+field("dispatchReceiver", expression, nullable = true, isChild = true) {
+field("dispatchReceiver", expression, nullable = true) {
baseDefaultValue = "null"
}
+field("extensionReceiver", expression, nullable = true, isChild = true) {
+field("extensionReceiver", expression, nullable = true) {
baseDefaultValue = "null"
}
+symbol(s)
+field("origin", statementOriginType, nullable = true)
+listField("valueArguments", expression.copy(nullable = true), mutability = Array, isChild = true) {
+listField("valueArguments", expression.copy(nullable = true), mutability = Array) {
visibility = Visibility.PROTECTED
}
+listField("typeArguments", irTypeType.copy(nullable = true), mutability = Array) {
@@ -831,7 +840,7 @@ object IrTree : AbstractTreeBuilder() {
parent(statementContainer)
+field("origin", statementOriginType, nullable = true)
+listField("statements", statement, mutability = MutableList, isChild = true) {
+listField("statements", statement, mutability = MutableList) {
baseDefaultValue = "ArrayList(2)"
}
}
@@ -870,7 +879,9 @@ object IrTree : AbstractTreeBuilder() {
parent(expression)
+field("loop", loop)
+field("loop", loop) {
needAcceptAndTransform = false
}
+field("label", string, nullable = true) {
baseDefaultValue = "null"
}
@@ -959,19 +970,19 @@ object IrTree : AbstractTreeBuilder() {
val constantPrimitive: Element by element(Expression) {
parent(constantValue)
+field("value", const.withArgs("T" to TypeRef.Star), isChild = true)
+field("value", const.withArgs("T" to TypeRef.Star))
}
val constantObject: Element by element(Expression) {
parent(constantValue)
+field("constructor", constructorSymbolType)
+listField("valueArguments", constantValue, mutability = MutableList, isChild = true)
+listField("valueArguments", constantValue, mutability = MutableList)
+listField("typeArguments", irTypeType, mutability = MutableList)
}
val constantArray: Element by element(Expression) {
parent(constantValue)
+listField("elements", constantValue, mutability = MutableList, isChild = true)
+listField("elements", constantValue, mutability = MutableList)
}
val delegatingConstructorCall: Element by element(Expression) {
parent(functionAccessExpression)
@@ -985,14 +996,14 @@ object IrTree : AbstractTreeBuilder() {
parent(dynamicExpression)
+field("operator", type(Packages.exprs, "IrDynamicOperator"))
+field("receiver", expression, isChild = true)
+listField("arguments", expression, mutability = MutableList, isChild = true)
+field("receiver", expression)
+listField("arguments", expression, mutability = MutableList)
}
val dynamicMemberExpression: Element by element(Expression) {
parent(dynamicExpression)
+field("memberName", string)
+field("receiver", expression, isChild = true)
+field("receiver", expression)
}
val enumConstructorCall: Element by element(Expression) {
parent(functionAccessExpression)
@@ -1009,8 +1020,8 @@ object IrTree : AbstractTreeBuilder() {
val errorCallExpression: Element by element(Expression) {
parent(errorExpression)
+field("explicitReceiver", expression, nullable = true, isChild = true)
+listField("arguments", expression, mutability = MutableList, isChild = true)
+field("explicitReceiver", expression, nullable = true)
+listField("arguments", expression, mutability = MutableList)
}
val fieldAccessExpression: Element by element(Expression) {
nameInVisitorMethod = "FieldAccess"
@@ -1020,7 +1031,7 @@ object IrTree : AbstractTreeBuilder() {
+symbol(fieldSymbolType, mutable = true)
+field("superQualifierSymbol", classSymbolType, nullable = true)
+field("receiver", expression, nullable = true, isChild = true) {
+field("receiver", expression, nullable = true) {
baseDefaultValue = "null"
}
+field("origin", statementOriginType, nullable = true)
@@ -1031,7 +1042,7 @@ object IrTree : AbstractTreeBuilder() {
val setField: Element by element(Expression) {
parent(fieldAccessExpression)
+field("value", expression, isChild = true)
+field("value", expression)
}
val functionExpression: Element by element(Expression) {
transformerReturnType = rootElement
@@ -1039,12 +1050,12 @@ object IrTree : AbstractTreeBuilder() {
parent(expression)
+field("origin", statementOriginType)
+field("function", simpleFunction, isChild = true)
+field("function", simpleFunction)
}
val getClass: Element by element(Expression) {
parent(expression)
+field("argument", expression, isChild = true)
+field("argument", expression)
}
val instanceInitializerCall: Element by element(Expression) {
parent(expression)
@@ -1058,10 +1069,10 @@ object IrTree : AbstractTreeBuilder() {
parent(expression)
+field("origin", statementOriginType, nullable = true)
+field("body", expression, nullable = true, isChild = true) {
+field("body", expression, nullable = true) {
baseDefaultValue = "null"
}
+field("condition", expression, isChild = true)
+field("condition", expression)
+field("label", string, nullable = true) {
baseDefaultValue = "null"
}
@@ -1080,48 +1091,48 @@ object IrTree : AbstractTreeBuilder() {
val `return`: Element by element(Expression) {
parent(expression)
+field("value", expression, isChild = true)
+field("value", expression)
+field("returnTargetSymbol", returnTargetSymbolType)
}
val stringConcatenation: Element by element(Expression) {
parent(expression)
+listField("arguments", expression, mutability = MutableList, isChild = true)
+listField("arguments", expression, mutability = MutableList)
}
val suspensionPoint: Element by element(Expression) {
parent(expression)
+field("suspensionPointIdParameter", variable, isChild = true)
+field("result", expression, isChild = true)
+field("resumeResult", expression, isChild = true)
+field("suspensionPointIdParameter", variable)
+field("result", expression)
+field("resumeResult", expression)
}
val suspendableExpression: Element by element(Expression) {
parent(expression)
+field("suspensionPointId", expression, isChild = true)
+field("result", expression, isChild = true)
+field("suspensionPointId", expression)
+field("result", expression)
}
val `throw`: Element by element(Expression) {
parent(expression)
+field("value", expression, isChild = true)
+field("value", expression)
}
val `try`: Element by element(Expression) {
visitorParameterName = "aTry"
parent(expression)
+field("tryResult", expression, isChild = true)
+listField("catches", catch, mutability = MutableList, isChild = true)
+field("finallyExpression", expression, nullable = true, isChild = true)
+field("tryResult", expression)
+listField("catches", catch, mutability = MutableList)
+field("finallyExpression", expression, nullable = true)
}
val catch: Element by element(Expression) {
visitorParameterName = "aCatch"
needTransformMethod()
transformByChildren = true
+field("catchParameter", variable, isChild = true)
+field("result", expression, isChild = true)
+field("catchParameter", variable)
+field("result", expression)
}
val typeOperatorCall: Element by element(Expression) {
nameInVisitorMethod = "TypeOperator"
@@ -1129,7 +1140,7 @@ object IrTree : AbstractTreeBuilder() {
parent(expression)
+field("operator", type(Packages.exprs, "IrTypeOperator"))
+field("argument", expression, isChild = true)
+field("argument", expression)
+field("typeOperand", irTypeType)
}
val valueAccessExpression: Element by element(Expression) {
@@ -1146,14 +1157,14 @@ object IrTree : AbstractTreeBuilder() {
val setValue: Element by element(Expression) {
parent(valueAccessExpression)
+field("value", expression, isChild = true)
+field("value", expression)
}
val varargElement: Element by element(Expression)
val vararg: Element by element(Expression) {
parent(expression)
+field("varargElementType", irTypeType)
+listField("elements", varargElement, mutability = MutableList, isChild = true)
+listField("elements", varargElement, mutability = MutableList)
}
val spreadElement: Element by element(Expression) {
visitorParameterName = "spread"
@@ -1162,13 +1173,13 @@ object IrTree : AbstractTreeBuilder() {
parent(varargElement)
+field("expression", expression, isChild = true)
+field("expression", expression)
}
val `when`: Element by element(Expression) {
parent(expression)
+field("origin", statementOriginType, nullable = true)
+listField("branches", branch, mutability = MutableList, isChild = true)
+listField("branches", branch, mutability = MutableList)
}
val branch: Element by element(Expression) {
visitorParameterName = "branch"
@@ -1176,8 +1187,8 @@ object IrTree : AbstractTreeBuilder() {
needTransformMethod()
transformByChildren = true
+field("condition", expression, isChild = true)
+field("result", expression, isChild = true)
+field("condition", expression)
+field("result", expression)
}
val elseBranch: Element by element(Expression) {
visitorParameterName = "branch"
@@ -10,7 +10,6 @@ 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.addWalkableChildren
import org.jetbrains.kotlin.ir.generator.model.markLeaves
import org.jetbrains.kotlin.ir.generator.print.*
import java.io.File
@@ -28,7 +27,6 @@ fun main(args: Array<String>) {
InterfaceAndAbstractClassConfigurator(model.elements).configureInterfacesAndAbstractClasses()
addPureAbstractElement(model.elements, elementBaseType)
markLeaves(model.elements)
addWalkableChildren(model.elements)
val previouslyGeneratedFiles = collectPreviouslyGeneratedFiles(generationPath)
val generatedFiles = sequence {
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.ir.generator.config
import org.jetbrains.kotlin.generators.tree.*
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
@@ -14,7 +15,6 @@ 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<() -> Element>()
@@ -22,11 +22,11 @@ abstract class AbstractTreeBuilder {
abstract val rootElement: Element
protected fun Field.skipInIrFactory() {
useInIrFactoryStrategy = Field.UseFieldAsParameterInIrFactoryStrategy.No
customUseInIrFactoryStrategy = Field.UseFieldAsParameterInIrFactoryStrategy.No
}
protected fun Field.useFieldInIrFactory(defaultValue: String? = null) {
useInIrFactoryStrategy = Field.UseFieldAsParameterInIrFactoryStrategy.Yes(defaultValue)
customUseInIrFactoryStrategy = Field.UseFieldAsParameterInIrFactoryStrategy.Yes(defaultValue)
}
fun element(category: Element.Category, name: String? = null, initializer: Element.() -> Unit = {}): ElementDelegate {
@@ -75,22 +75,18 @@ abstract class AbstractTreeBuilder {
type: TypeRefWithNullability,
nullable: Boolean = false,
mutable: Boolean = true,
isChild: Boolean = false,
initializer: SingleField.() -> Unit = {}
): SingleField {
checkChildType(isChild, type, name)
return SingleField(name, type.copy(nullable), mutable, isChild).apply(initializer)
return SingleField(name, type.copy(nullable), mutable).apply(initializer)
}
protected fun listField(
name: String,
elementType: TypeRef,
baseType: TypeRef,
nullable: Boolean = false,
mutability: ListField.Mutability,
isChild: Boolean = false,
initializer: ListField.() -> Unit = {}
): ListField {
checkChildType(isChild, elementType, name)
val listType = when (mutability) {
ListField.Mutability.MutableList -> StandardTypes.mutableList
ListField.Mutability.Array -> StandardTypes.array
@@ -98,22 +94,13 @@ abstract class AbstractTreeBuilder {
}
return ListField(
name = name,
baseType = elementType,
baseType = baseType,
listType = listType,
isNullable = nullable,
mutable = mutability == ListField.Mutability.Var,
isChild = isChild,
).apply(initializer)
}
private fun checkChildType(isChild: Boolean, type: TypeRef?, name: String) {
if (isChild) {
require(type == null || type is GenericElementOrRef<*, *>) {
"Field $name is a child field but has non-element type $type"
}
}
}
fun build(): Model {
val elements = configurationCallbacks.map { it() }
return Model(elements, rootElement)
@@ -11,7 +11,6 @@ import org.jetbrains.kotlin.ir.generator.BASE_PACKAGE
import org.jetbrains.kotlin.ir.generator.IrTree
import org.jetbrains.kotlin.ir.generator.elementBaseType
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
@@ -90,8 +89,7 @@ class Element(
*/
var isLeaf = false
var childrenOrderOverride: List<String>? = null
override var walkableChildren: List<Field> = emptyList()
override var childrenOrderOverride: List<String>? = null
override var visitorParameterName = category.defaultVisitorParam
@@ -104,10 +102,19 @@ class Element(
override var hasTransformMethod = false
override val hasAcceptChildrenMethod: Boolean
get() = ownsChildren && (isRootElement || walkableChildren.isNotEmpty())
get() = hasAcceptOrTransformChildrenMethod(Element::walkableChildren)
override val hasTransformChildrenMethod: Boolean
get() = ownsChildren && (isRootElement || transformableChildren.isNotEmpty())
get() = hasAcceptOrTransformChildrenMethod(Element::transformableChildren)
private fun hasAcceptOrTransformChildrenMethod(walkableOrTransformableChildren: Element.() -> List<Field>): Boolean {
if (!ownsChildren) return false
if (!isRootElement && walkableOrTransformableChildren().isEmpty()) return false
val atLeastOneParentHasAcceptOrTransformChildrenMethod = traverseParentsUntil { parent ->
parent != this && parent.hasAcceptOrTransformChildrenMethod(walkableOrTransformableChildren) && !parent.isRootElement
}
return !atLeastOneParentHasAcceptOrTransformChildrenMethod
}
var transformByChildren = false
var ownsChildren = true // If false, acceptChildren/transformChildren will NOT be generated.
@@ -135,7 +142,6 @@ typealias ElementOrRef = GenericElementOrRef<Element, Field>
sealed class Field(
override val name: String,
override var isMutable: Boolean,
val isChild: Boolean,
) : AbstractField<Field>() {
var baseDefaultValue: String? = null
var baseGetter: String? = null
@@ -147,8 +153,15 @@ sealed class Field(
data class Yes(val defaultValue: String?) : UseFieldAsParameterInIrFactoryStrategy()
}
var useInIrFactoryStrategy =
if (isChild) UseFieldAsParameterInIrFactoryStrategy.No else UseFieldAsParameterInIrFactoryStrategy.Yes(null)
var customUseInIrFactoryStrategy: UseFieldAsParameterInIrFactoryStrategy? = null
val useInIrFactoryStrategy: UseFieldAsParameterInIrFactoryStrategy
get() = customUseInIrFactoryStrategy
?: if (needAcceptAndTransform && containsElement) {
UseFieldAsParameterInIrFactoryStrategy.No
} else {
UseFieldAsParameterInIrFactoryStrategy.Yes(null)
}
override val withGetter: Boolean
get() = baseGetter != null
@@ -175,12 +188,13 @@ sealed class Field(
override fun copy() = internalCopy().also(::updateFieldsInCopy)
protected fun updateFieldsInCopy(copy: Field) {
copy.needAcceptAndTransform = needAcceptAndTransform
copy.useInBaseTransformerDetection = useInBaseTransformerDetection
copy.isMutable = isMutable
copy.optInAnnotation = optInAnnotation
copy.baseDefaultValue = baseDefaultValue
copy.baseGetter = baseGetter
copy.useInIrFactoryStrategy = useInIrFactoryStrategy
copy.customUseInIrFactoryStrategy = customUseInIrFactoryStrategy
copy.fromParent = fromParent
copy.customSetter = customSetter
copy.visibility = visibility
@@ -195,13 +209,12 @@ class SingleField(
name: String,
override var typeRef: TypeRefWithNullability,
mutable: Boolean,
isChild: Boolean,
) : Field(name, mutable, isChild) {
) : Field(name, mutable) {
override fun replaceType(newType: TypeRefWithNullability) =
SingleField(name, newType, isMutable, isChild).also(::updateFieldsInCopy)
SingleField(name, newType, isMutable).also(::updateFieldsInCopy)
override fun internalCopy() = SingleField(name, typeRef, isMutable, isChild)
override fun internalCopy() = SingleField(name, typeRef, isMutable)
}
class ListField(
@@ -210,15 +223,14 @@ class ListField(
private val isNullable: Boolean,
override val listType: ClassRef<PositionTypeParameterRef>,
mutable: Boolean,
isChild: Boolean,
) : Field(name, mutable, isChild), AbstractListField {
) : Field(name, mutable), AbstractListField {
override val typeRef: ClassRef<PositionTypeParameterRef>
get() = listType.withArgs(baseType).copy(isNullable)
override fun replaceType(newType: TypeRefWithNullability) = copy()
override fun internalCopy() = ListField(name, baseType, isNullable, listType, isMutable, isChild)
override fun internalCopy() = ListField(name, baseType, isNullable, listType, isMutable)
enum class Mutability {
Var,
@@ -5,8 +5,6 @@
package org.jetbrains.kotlin.ir.generator.model
import org.jetbrains.kotlin.generators.tree.*
typealias Model = org.jetbrains.kotlin.generators.tree.Model<Element>
internal fun markLeaves(elements: List<Element>) {
@@ -24,53 +22,3 @@ internal fun markLeaves(elements: List<Element>) {
el.isLeaf = true
}
}
internal fun addWalkableChildren(elements: List<Element>) {
for (element in elements) {
val walkableChildren = mutableMapOf<String, Field>()
fun visitParents(visited: Element) {
for (parent in visited.elementParents) {
if (!parent.element.ownsChildren) {
for (field in parent.element.fields) {
if (field.isChild) {
walkableChildren[field.name] = field
}
}
visitParents(parent.element)
}
}
}
visitParents(element)
element.fields.filter { it.isChild }.associateByTo(walkableChildren) { it.name }
element.walkableChildren = reorderIfNecessary(walkableChildren.values.toList(), element.childrenOrderOverride)
}
}
private fun reorderIfNecessary(fields: List<Field>, order: List<String>?): List<Field> =
if (order == null) fields else fields.sortedBy {
val position = order.indexOf(it.name)
if (position < 0) order.size else position
}
private fun iterateElementsParentFirst(elements: List<Element>) = sequence {
val pending = elements.sortedBy { it.elementParents.size }.toMutableSet()
pendingLoop@ while (pending.isNotEmpty()) {
val iter = pending.iterator()
while (iter.hasNext()) {
val element = iter.next()
if (element.elementParents.none { it.element in pending }) {
yield(element)
iter.remove()
continue@pendingLoop
}
}
error("Cannot find next element to process")
}
}
@@ -26,11 +26,19 @@ interface FieldContainer<out Field : AbstractField<*>> {
val hasTransformChildrenMethod: Boolean
get() = false
/**
* Allows to override the order in which the specified children will be visited in `acceptChildren`/`transformChildren` methods.
*/
val childrenOrderOverride: List<String>?
get() = null
/**
* The fields on which to run the visitor in generated `acceptChildren` methods.
*/
val walkableChildren: List<Field>
get() = allFields.filter { it.containsElement && !it.withGetter && it.needAcceptAndTransform }
get() = allFields
.filter { it.containsElement && !it.withGetter && it.needAcceptAndTransform }
.reorderFieldsIfNecessary(childrenOrderOverride)
/**
* The fields on which to run the transformer in generated `transformChildren` methods.
@@ -5,9 +5,26 @@
package org.jetbrains.kotlin.generators.tree
/**
* Runs [block] on this element and all its parents recursively.
*/
fun <Element : AbstractElement<Element, *>> Element.traverseParents(block: (Element) -> Unit) {
block(this)
elementParents.forEach { it.element.traverseParents(block) }
traverseParentsUntil { block(it); false }
}
/**
* Runs [block] on this element and all its parents recursively.
*
* If [block] returns `true` at any point, aborts iteration and returns `true`.
*
* If [block] always returns `false`, visits all the parents and returns `false`.
*/
fun <Element : AbstractElement<Element, *>> Element.traverseParentsUntil(block: (Element) -> Boolean): Boolean {
if (block(this)) return true
for (parent in elementParents) {
if (parent.element.traverseParentsUntil(block)) return true
}
return false
}
/**
@@ -46,4 +63,14 @@ operator fun <K, V, U> MutableMap<K, MutableMap<V, U>>.set(k1: K, k2: V, value:
operator fun <K, V, U> Map<K, Map<V, U>>.get(k1: K, k2: V): U {
return getValue(k1).getValue(k2)
}
}
internal fun <Field : AbstractField<*>> List<Field>.reorderFieldsIfNecessary(order: List<String>?): List<Field> =
if (order == null) {
this
} else {
sortedBy {
val position = order.indexOf(it.name)
if (position < 0) order.size else position
}
}