[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") +descriptor("DeclarationDescriptor")
+field("origin", type(Packages.declarations, "IrDeclarationOrigin")) +field("origin", type(Packages.declarations, "IrDeclarationOrigin"))
+field("parent", declarationParent) { +field("parent", declarationParent) {
needAcceptAndTransform = false
skipInIrFactory() skipInIrFactory()
} }
+factory +factory
@@ -237,7 +238,7 @@ object IrTree : AbstractTreeBuilder() {
TODO: consider dropping [$name] if it isn't used by any known plugin. TODO: consider dropping [$name] if it isn't used by any known plugin.
""".trimIndent() """.trimIndent()
} }
+field("defaultValue", expressionBody, nullable = true, isChild = true) +field("defaultValue", expressionBody, nullable = true)
} }
val `class`: Element by element(Declaration) { val `class`: Element by element(Declaration) {
parent(declarationBase) parent(declarationBase)
@@ -285,7 +286,7 @@ object IrTree : AbstractTreeBuilder() {
+listField("superTypes", irTypeType, mutability = Var) { +listField("superTypes", irTypeType, mutability = Var) {
skipInIrFactory() skipInIrFactory()
} }
+field("thisReceiver", valueParameter, nullable = true, isChild = true) +field("thisReceiver", valueParameter, nullable = true)
+field( +field(
"valueClassRepresentation", "valueClassRepresentation",
type<ValueClassRepresentation<*>>().withArgs(type(Packages.types, "IrSimpleType")), type<ValueClassRepresentation<*>>().withArgs(type(Packages.types, "IrSimpleType")),
@@ -316,10 +317,12 @@ object IrTree : AbstractTreeBuilder() {
""".trimIndent() """.trimIndent()
+field("attributeOwnerId", attributeContainer) { +field("attributeOwnerId", attributeContainer) {
needAcceptAndTransform = false
skipInIrFactory() skipInIrFactory()
} }
// null <=> this element wasn't inlined // null <=> this element wasn't inlined
+field("originalBeforeInline", attributeContainer, nullable = true) { +field("originalBeforeInline", attributeContainer, nullable = true) {
needAcceptAndTransform = false
skipInIrFactory() skipInIrFactory()
} }
} }
@@ -331,14 +334,14 @@ object IrTree : AbstractTreeBuilder() {
+field("isStatic", boolean) { +field("isStatic", boolean) {
useFieldInIrFactory(defaultValue = "false") useFieldInIrFactory(defaultValue = "false")
} }
+field("body", blockBody, isChild = true) +field("body", blockBody)
} }
val declarationContainer: Element by element(Declaration) { val declarationContainer: Element by element(Declaration) {
ownsChildren = false ownsChildren = false
parent(declarationParent) parent(declarationParent)
+listField("declarations", declaration, mutability = MutableList, isChild = true) { +listField("declarations", declaration, mutability = MutableList) {
kDoc = """ kDoc = """
Accessing list of declaration may trigger lazy declaration list computation for lazy class, 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 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(declaration)
parent(declarationParent) parent(declarationParent)
+listField("typeParameters", typeParameter, mutability = Var, isChild = true) +listField("typeParameters", typeParameter, mutability = Var)
} }
val typeParameter: Element by element(Declaration) { val typeParameter: Element by element(Declaration) {
needTransformMethod() needTransformMethod()
@@ -394,14 +397,14 @@ object IrTree : AbstractTreeBuilder() {
+field("isInline", boolean) +field("isInline", boolean)
+field("isExpect", boolean) +field("isExpect", boolean)
+field("returnType", irTypeType) +field("returnType", irTypeType)
+field("dispatchReceiverParameter", valueParameter, nullable = true, isChild = true) +field("dispatchReceiverParameter", valueParameter, nullable = true)
+field("extensionReceiverParameter", valueParameter, nullable = true, isChild = true) +field("extensionReceiverParameter", valueParameter, nullable = true)
+listField("valueParameters", valueParameter, mutability = Var, isChild = true) +listField("valueParameters", valueParameter, mutability = Var)
// The first `contextReceiverParametersCount` value parameters are context receivers. // The first `contextReceiverParametersCount` value parameters are context receivers.
+field("contextReceiverParametersCount", int) { +field("contextReceiverParametersCount", int) {
skipInIrFactory() skipInIrFactory()
} }
+field("body", body, nullable = true, isChild = true) +field("body", body, nullable = true)
} }
val constructor: Element by element(Declaration) { val constructor: Element by element(Declaration) {
parent(function) parent(function)
@@ -416,8 +419,8 @@ object IrTree : AbstractTreeBuilder() {
+descriptor("ClassDescriptor") +descriptor("ClassDescriptor")
+symbol(enumEntrySymbolType) +symbol(enumEntrySymbolType)
+field("initializerExpression", expressionBody, nullable = true, isChild = true) +field("initializerExpression", expressionBody, nullable = true)
+field("correspondingClass", `class`, nullable = true, isChild = true) +field("correspondingClass", `class`, nullable = true)
} }
val errorDeclaration: Element by element(Declaration) { val errorDeclaration: Element by element(Declaration) {
parent(declarationBase) parent(declarationBase)
@@ -453,7 +456,7 @@ object IrTree : AbstractTreeBuilder() {
+field("type", irTypeType) +field("type", irTypeType)
+field("isFinal", boolean) +field("isFinal", boolean)
+field("isStatic", boolean) +field("isStatic", boolean)
+field("initializer", expressionBody, nullable = true, isChild = true) +field("initializer", expressionBody, nullable = true)
+field("correspondingPropertySymbol", propertySymbolType, nullable = true) { +field("correspondingPropertySymbol", propertySymbolType, nullable = true) {
skipInIrFactory() skipInIrFactory()
} }
@@ -468,9 +471,9 @@ object IrTree : AbstractTreeBuilder() {
+symbol(localDelegatedPropertySymbolType) +symbol(localDelegatedPropertySymbolType)
+field("type", irTypeType) +field("type", irTypeType)
+field("isVar", boolean) +field("isVar", boolean)
+field("delegate", variable, isChild = true) +field("delegate", variable)
+field("getter", simpleFunction, isChild = true) +field("getter", simpleFunction)
+field("setter", simpleFunction, nullable = true, isChild = true) +field("setter", simpleFunction, nullable = true)
} }
val moduleFragment: Element by element(Declaration) { val moduleFragment: Element by element(Declaration) {
needTransformMethod() needTransformMethod()
@@ -482,7 +485,7 @@ object IrTree : AbstractTreeBuilder() {
} }
+field("name", type<Name>(), mutable = false) +field("name", type<Name>(), mutable = false)
+field("irBuiltins", type(Packages.tree, "IrBuiltIns"), 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") usedTypes += ArbitraryImportable(Packages.tree, "UNDEFINED_OFFSET")
+field("startOffset", int, mutable = false) { +field("startOffset", int, mutable = false) {
baseGetter = "UNDEFINED_OFFSET" baseGetter = "UNDEFINED_OFFSET"
@@ -511,9 +514,9 @@ object IrTree : AbstractTreeBuilder() {
useFieldInIrFactory(defaultValue = "false") useFieldInIrFactory(defaultValue = "false")
} }
+isFakeOverrideField() +isFakeOverrideField()
+field("backingField", field, nullable = true, isChild = true) +field("backingField", field, nullable = true)
+field("getter", simpleFunction, nullable = true, isChild = true) +field("getter", simpleFunction, nullable = true)
+field("setter", simpleFunction, nullable = true, isChild = true) +field("setter", simpleFunction, nullable = true)
} }
private fun isFakeOverrideField() = field("isFakeOverride", boolean) { private fun isFakeOverrideField() = field("isFakeOverride", boolean) {
@@ -534,18 +537,20 @@ object IrTree : AbstractTreeBuilder() {
+symbol(scriptSymbolType) +symbol(scriptSymbolType)
// NOTE: is the result of the FE conversion, because there script interpreted as a class and has receiver // 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 // 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 +field("baseClass", irTypeType, nullable = true) // K1
+listField("explicitCallParameters", variable, mutability = Var, isChild = true) +listField("explicitCallParameters", variable, mutability = Var)
+listField("implicitReceiversParameters", valueParameter, mutability = Var, isChild = true) +listField("implicitReceiversParameters", valueParameter, mutability = Var)
+listField("providedProperties", propertySymbolType, 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("resultProperty", propertySymbolType, nullable = true)
+field("earlierScriptsParameter", valueParameter, nullable = true, isChild = true) +field("earlierScriptsParameter", valueParameter, nullable = true)
+listField("importedScripts", scriptSymbolType, mutability = Var, nullable = true) +listField("importedScripts", scriptSymbolType, mutability = Var, nullable = true)
+listField("earlierScripts", scriptSymbolType, mutability = Var, nullable = true) +listField("earlierScripts", scriptSymbolType, mutability = Var, nullable = true)
+field("targetClass", classSymbolType, 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) { val simpleFunction: Element by element(Declaration) {
isLeaf = true isLeaf = true
@@ -586,7 +591,7 @@ object IrTree : AbstractTreeBuilder() {
+field("isVar", boolean) +field("isVar", boolean)
+field("isConst", boolean) +field("isConst", boolean)
+field("isLateinit", boolean) +field("isLateinit", boolean)
+field("initializer", expression, nullable = true, isChild = true) +field("initializer", expression, nullable = true)
} }
val packageFragment: Element by element(Declaration) { val packageFragment: Element by element(Declaration) {
ownsChildren = false ownsChildren = false
@@ -636,7 +641,9 @@ object IrTree : AbstractTreeBuilder() {
parent(metadataSourceOwner) parent(metadataSourceOwner)
+symbol(fileSymbolType) +symbol(fileSymbolType)
+field("module", moduleFragment) +field("module", moduleFragment) {
needAcceptAndTransform = false
}
+field("fileEntry", type(Packages.tree, "IrFileEntry")) +field("fileEntry", type(Packages.tree, "IrFileEntry"))
} }
@@ -649,10 +656,12 @@ object IrTree : AbstractTreeBuilder() {
parent(attributeContainer) parent(attributeContainer)
+field("attributeOwnerId", attributeContainer) { +field("attributeOwnerId", attributeContainer) {
needAcceptAndTransform = false
baseDefaultValue = "this" baseDefaultValue = "this"
skipInIrFactory() skipInIrFactory()
} }
+field("originalBeforeInline", attributeContainer, nullable = true) { +field("originalBeforeInline", attributeContainer, nullable = true) {
needAcceptAndTransform = false
baseDefaultValue = "null" baseDefaultValue = "null"
skipInIrFactory() skipInIrFactory()
} }
@@ -661,7 +670,7 @@ object IrTree : AbstractTreeBuilder() {
val statementContainer: Element by element(Expression) { val statementContainer: Element by element(Expression) {
ownsChildren = false ownsChildren = false
+listField("statements", statement, mutability = MutableList, isChild = true) +listField("statements", statement, mutability = MutableList)
} }
val body: Element by element(Expression) { val body: Element by element(Expression) {
needTransformMethod() needTransformMethod()
@@ -677,7 +686,7 @@ object IrTree : AbstractTreeBuilder() {
parent(body) parent(body)
+factory +factory
+field("expression", expression, isChild = true) { +field("expression", expression) {
useFieldInIrFactory() useFieldInIrFactory()
} }
} }
@@ -703,15 +712,15 @@ object IrTree : AbstractTreeBuilder() {
parent(declarationReference) parent(declarationReference)
+field("dispatchReceiver", expression, nullable = true, isChild = true) { +field("dispatchReceiver", expression, nullable = true) {
baseDefaultValue = "null" baseDefaultValue = "null"
} }
+field("extensionReceiver", expression, nullable = true, isChild = true) { +field("extensionReceiver", expression, nullable = true) {
baseDefaultValue = "null" baseDefaultValue = "null"
} }
+symbol(s) +symbol(s)
+field("origin", statementOriginType, nullable = true) +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 visibility = Visibility.PROTECTED
} }
+listField("typeArguments", irTypeType.copy(nullable = true), mutability = Array) { +listField("typeArguments", irTypeType.copy(nullable = true), mutability = Array) {
@@ -831,7 +840,7 @@ object IrTree : AbstractTreeBuilder() {
parent(statementContainer) parent(statementContainer)
+field("origin", statementOriginType, nullable = true) +field("origin", statementOriginType, nullable = true)
+listField("statements", statement, mutability = MutableList, isChild = true) { +listField("statements", statement, mutability = MutableList) {
baseDefaultValue = "ArrayList(2)" baseDefaultValue = "ArrayList(2)"
} }
} }
@@ -870,7 +879,9 @@ object IrTree : AbstractTreeBuilder() {
parent(expression) parent(expression)
+field("loop", loop) +field("loop", loop) {
needAcceptAndTransform = false
}
+field("label", string, nullable = true) { +field("label", string, nullable = true) {
baseDefaultValue = "null" baseDefaultValue = "null"
} }
@@ -959,19 +970,19 @@ object IrTree : AbstractTreeBuilder() {
val constantPrimitive: Element by element(Expression) { val constantPrimitive: Element by element(Expression) {
parent(constantValue) 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) { val constantObject: Element by element(Expression) {
parent(constantValue) parent(constantValue)
+field("constructor", constructorSymbolType) +field("constructor", constructorSymbolType)
+listField("valueArguments", constantValue, mutability = MutableList, isChild = true) +listField("valueArguments", constantValue, mutability = MutableList)
+listField("typeArguments", irTypeType, mutability = MutableList) +listField("typeArguments", irTypeType, mutability = MutableList)
} }
val constantArray: Element by element(Expression) { val constantArray: Element by element(Expression) {
parent(constantValue) parent(constantValue)
+listField("elements", constantValue, mutability = MutableList, isChild = true) +listField("elements", constantValue, mutability = MutableList)
} }
val delegatingConstructorCall: Element by element(Expression) { val delegatingConstructorCall: Element by element(Expression) {
parent(functionAccessExpression) parent(functionAccessExpression)
@@ -985,14 +996,14 @@ object IrTree : AbstractTreeBuilder() {
parent(dynamicExpression) parent(dynamicExpression)
+field("operator", type(Packages.exprs, "IrDynamicOperator")) +field("operator", type(Packages.exprs, "IrDynamicOperator"))
+field("receiver", expression, isChild = true) +field("receiver", expression)
+listField("arguments", expression, mutability = MutableList, isChild = true) +listField("arguments", expression, mutability = MutableList)
} }
val dynamicMemberExpression: Element by element(Expression) { val dynamicMemberExpression: Element by element(Expression) {
parent(dynamicExpression) parent(dynamicExpression)
+field("memberName", string) +field("memberName", string)
+field("receiver", expression, isChild = true) +field("receiver", expression)
} }
val enumConstructorCall: Element by element(Expression) { val enumConstructorCall: Element by element(Expression) {
parent(functionAccessExpression) parent(functionAccessExpression)
@@ -1009,8 +1020,8 @@ object IrTree : AbstractTreeBuilder() {
val errorCallExpression: Element by element(Expression) { val errorCallExpression: Element by element(Expression) {
parent(errorExpression) parent(errorExpression)
+field("explicitReceiver", expression, nullable = true, isChild = true) +field("explicitReceiver", expression, nullable = true)
+listField("arguments", expression, mutability = MutableList, isChild = true) +listField("arguments", expression, mutability = MutableList)
} }
val fieldAccessExpression: Element by element(Expression) { val fieldAccessExpression: Element by element(Expression) {
nameInVisitorMethod = "FieldAccess" nameInVisitorMethod = "FieldAccess"
@@ -1020,7 +1031,7 @@ object IrTree : AbstractTreeBuilder() {
+symbol(fieldSymbolType, mutable = true) +symbol(fieldSymbolType, mutable = true)
+field("superQualifierSymbol", classSymbolType, nullable = true) +field("superQualifierSymbol", classSymbolType, nullable = true)
+field("receiver", expression, nullable = true, isChild = true) { +field("receiver", expression, nullable = true) {
baseDefaultValue = "null" baseDefaultValue = "null"
} }
+field("origin", statementOriginType, nullable = true) +field("origin", statementOriginType, nullable = true)
@@ -1031,7 +1042,7 @@ object IrTree : AbstractTreeBuilder() {
val setField: Element by element(Expression) { val setField: Element by element(Expression) {
parent(fieldAccessExpression) parent(fieldAccessExpression)
+field("value", expression, isChild = true) +field("value", expression)
} }
val functionExpression: Element by element(Expression) { val functionExpression: Element by element(Expression) {
transformerReturnType = rootElement transformerReturnType = rootElement
@@ -1039,12 +1050,12 @@ object IrTree : AbstractTreeBuilder() {
parent(expression) parent(expression)
+field("origin", statementOriginType) +field("origin", statementOriginType)
+field("function", simpleFunction, isChild = true) +field("function", simpleFunction)
} }
val getClass: Element by element(Expression) { val getClass: Element by element(Expression) {
parent(expression) parent(expression)
+field("argument", expression, isChild = true) +field("argument", expression)
} }
val instanceInitializerCall: Element by element(Expression) { val instanceInitializerCall: Element by element(Expression) {
parent(expression) parent(expression)
@@ -1058,10 +1069,10 @@ object IrTree : AbstractTreeBuilder() {
parent(expression) parent(expression)
+field("origin", statementOriginType, nullable = true) +field("origin", statementOriginType, nullable = true)
+field("body", expression, nullable = true, isChild = true) { +field("body", expression, nullable = true) {
baseDefaultValue = "null" baseDefaultValue = "null"
} }
+field("condition", expression, isChild = true) +field("condition", expression)
+field("label", string, nullable = true) { +field("label", string, nullable = true) {
baseDefaultValue = "null" baseDefaultValue = "null"
} }
@@ -1080,48 +1091,48 @@ object IrTree : AbstractTreeBuilder() {
val `return`: Element by element(Expression) { val `return`: Element by element(Expression) {
parent(expression) parent(expression)
+field("value", expression, isChild = true) +field("value", expression)
+field("returnTargetSymbol", returnTargetSymbolType) +field("returnTargetSymbol", returnTargetSymbolType)
} }
val stringConcatenation: Element by element(Expression) { val stringConcatenation: Element by element(Expression) {
parent(expression) parent(expression)
+listField("arguments", expression, mutability = MutableList, isChild = true) +listField("arguments", expression, mutability = MutableList)
} }
val suspensionPoint: Element by element(Expression) { val suspensionPoint: Element by element(Expression) {
parent(expression) parent(expression)
+field("suspensionPointIdParameter", variable, isChild = true) +field("suspensionPointIdParameter", variable)
+field("result", expression, isChild = true) +field("result", expression)
+field("resumeResult", expression, isChild = true) +field("resumeResult", expression)
} }
val suspendableExpression: Element by element(Expression) { val suspendableExpression: Element by element(Expression) {
parent(expression) parent(expression)
+field("suspensionPointId", expression, isChild = true) +field("suspensionPointId", expression)
+field("result", expression, isChild = true) +field("result", expression)
} }
val `throw`: Element by element(Expression) { val `throw`: Element by element(Expression) {
parent(expression) parent(expression)
+field("value", expression, isChild = true) +field("value", expression)
} }
val `try`: Element by element(Expression) { val `try`: Element by element(Expression) {
visitorParameterName = "aTry" visitorParameterName = "aTry"
parent(expression) parent(expression)
+field("tryResult", expression, isChild = true) +field("tryResult", expression)
+listField("catches", catch, mutability = MutableList, isChild = true) +listField("catches", catch, mutability = MutableList)
+field("finallyExpression", expression, nullable = true, isChild = true) +field("finallyExpression", expression, nullable = true)
} }
val catch: Element by element(Expression) { val catch: Element by element(Expression) {
visitorParameterName = "aCatch" visitorParameterName = "aCatch"
needTransformMethod() needTransformMethod()
transformByChildren = true transformByChildren = true
+field("catchParameter", variable, isChild = true) +field("catchParameter", variable)
+field("result", expression, isChild = true) +field("result", expression)
} }
val typeOperatorCall: Element by element(Expression) { val typeOperatorCall: Element by element(Expression) {
nameInVisitorMethod = "TypeOperator" nameInVisitorMethod = "TypeOperator"
@@ -1129,7 +1140,7 @@ object IrTree : AbstractTreeBuilder() {
parent(expression) parent(expression)
+field("operator", type(Packages.exprs, "IrTypeOperator")) +field("operator", type(Packages.exprs, "IrTypeOperator"))
+field("argument", expression, isChild = true) +field("argument", expression)
+field("typeOperand", irTypeType) +field("typeOperand", irTypeType)
} }
val valueAccessExpression: Element by element(Expression) { val valueAccessExpression: Element by element(Expression) {
@@ -1146,14 +1157,14 @@ object IrTree : AbstractTreeBuilder() {
val setValue: Element by element(Expression) { val setValue: Element by element(Expression) {
parent(valueAccessExpression) parent(valueAccessExpression)
+field("value", expression, isChild = true) +field("value", expression)
} }
val varargElement: Element by element(Expression) val varargElement: Element by element(Expression)
val vararg: Element by element(Expression) { val vararg: Element by element(Expression) {
parent(expression) parent(expression)
+field("varargElementType", irTypeType) +field("varargElementType", irTypeType)
+listField("elements", varargElement, mutability = MutableList, isChild = true) +listField("elements", varargElement, mutability = MutableList)
} }
val spreadElement: Element by element(Expression) { val spreadElement: Element by element(Expression) {
visitorParameterName = "spread" visitorParameterName = "spread"
@@ -1162,13 +1173,13 @@ object IrTree : AbstractTreeBuilder() {
parent(varargElement) parent(varargElement)
+field("expression", expression, isChild = true) +field("expression", expression)
} }
val `when`: Element by element(Expression) { val `when`: Element by element(Expression) {
parent(expression) parent(expression)
+field("origin", statementOriginType, nullable = true) +field("origin", statementOriginType, nullable = true)
+listField("branches", branch, mutability = MutableList, isChild = true) +listField("branches", branch, mutability = MutableList)
} }
val branch: Element by element(Expression) { val branch: Element by element(Expression) {
visitorParameterName = "branch" visitorParameterName = "branch"
@@ -1176,8 +1187,8 @@ object IrTree : AbstractTreeBuilder() {
needTransformMethod() needTransformMethod()
transformByChildren = true transformByChildren = true
+field("condition", expression, isChild = true) +field("condition", expression)
+field("result", expression, isChild = true) +field("result", expression)
} }
val elseBranch: Element by element(Expression) { val elseBranch: Element by element(Expression) {
visitorParameterName = "branch" 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
import org.jetbrains.kotlin.generators.util.GeneratorsFileUtil.collectPreviouslyGeneratedFiles import org.jetbrains.kotlin.generators.util.GeneratorsFileUtil.collectPreviouslyGeneratedFiles
import org.jetbrains.kotlin.generators.util.GeneratorsFileUtil.removeExtraFilesFromPreviousGeneration 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.model.markLeaves
import org.jetbrains.kotlin.ir.generator.print.* import org.jetbrains.kotlin.ir.generator.print.*
import java.io.File import java.io.File
@@ -28,7 +27,6 @@ fun main(args: Array<String>) {
InterfaceAndAbstractClassConfigurator(model.elements).configureInterfacesAndAbstractClasses() InterfaceAndAbstractClassConfigurator(model.elements).configureInterfacesAndAbstractClasses()
addPureAbstractElement(model.elements, elementBaseType) addPureAbstractElement(model.elements, elementBaseType)
markLeaves(model.elements) markLeaves(model.elements)
addWalkableChildren(model.elements)
val previouslyGeneratedFiles = collectPreviouslyGeneratedFiles(generationPath) val previouslyGeneratedFiles = collectPreviouslyGeneratedFiles(generationPath)
val generatedFiles = sequence { val generatedFiles = sequence {
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.ir.generator.config
import org.jetbrains.kotlin.generators.tree.* import org.jetbrains.kotlin.generators.tree.*
import org.jetbrains.kotlin.ir.generator.model.* 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.ElementRef
import org.jetbrains.kotlin.ir.generator.model.ListField import org.jetbrains.kotlin.ir.generator.model.ListField
import org.jetbrains.kotlin.ir.generator.model.Model 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.PropertyDelegateProvider
import kotlin.properties.ReadOnlyProperty import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty import kotlin.reflect.KProperty
import org.jetbrains.kotlin.generators.tree.ElementOrRef as GenericElementOrRef
abstract class AbstractTreeBuilder { abstract class AbstractTreeBuilder {
private val configurationCallbacks = mutableListOf<() -> Element>() private val configurationCallbacks = mutableListOf<() -> Element>()
@@ -22,11 +22,11 @@ abstract class AbstractTreeBuilder {
abstract val rootElement: Element abstract val rootElement: Element
protected fun Field.skipInIrFactory() { protected fun Field.skipInIrFactory() {
useInIrFactoryStrategy = Field.UseFieldAsParameterInIrFactoryStrategy.No customUseInIrFactoryStrategy = Field.UseFieldAsParameterInIrFactoryStrategy.No
} }
protected fun Field.useFieldInIrFactory(defaultValue: String? = null) { 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 { fun element(category: Element.Category, name: String? = null, initializer: Element.() -> Unit = {}): ElementDelegate {
@@ -75,22 +75,18 @@ abstract class AbstractTreeBuilder {
type: TypeRefWithNullability, type: TypeRefWithNullability,
nullable: Boolean = false, nullable: Boolean = false,
mutable: Boolean = true, mutable: Boolean = true,
isChild: Boolean = false,
initializer: SingleField.() -> Unit = {} initializer: SingleField.() -> Unit = {}
): SingleField { ): SingleField {
checkChildType(isChild, type, name) return SingleField(name, type.copy(nullable), mutable).apply(initializer)
return SingleField(name, type.copy(nullable), mutable, isChild).apply(initializer)
} }
protected fun listField( protected fun listField(
name: String, name: String,
elementType: TypeRef, baseType: TypeRef,
nullable: Boolean = false, nullable: Boolean = false,
mutability: ListField.Mutability, mutability: ListField.Mutability,
isChild: Boolean = false,
initializer: ListField.() -> Unit = {} initializer: ListField.() -> Unit = {}
): ListField { ): ListField {
checkChildType(isChild, elementType, name)
val listType = when (mutability) { val listType = when (mutability) {
ListField.Mutability.MutableList -> StandardTypes.mutableList ListField.Mutability.MutableList -> StandardTypes.mutableList
ListField.Mutability.Array -> StandardTypes.array ListField.Mutability.Array -> StandardTypes.array
@@ -98,22 +94,13 @@ abstract class AbstractTreeBuilder {
} }
return ListField( return ListField(
name = name, name = name,
baseType = elementType, baseType = baseType,
listType = listType, listType = listType,
isNullable = nullable, isNullable = nullable,
mutable = mutability == ListField.Mutability.Var, mutable = mutability == ListField.Mutability.Var,
isChild = isChild,
).apply(initializer) ).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 { fun build(): Model {
val elements = configurationCallbacks.map { it() } val elements = configurationCallbacks.map { it() }
return Model(elements, rootElement) 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.IrTree
import org.jetbrains.kotlin.ir.generator.elementBaseType import org.jetbrains.kotlin.ir.generator.elementBaseType
import org.jetbrains.kotlin.utils.SmartPrinter 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.ElementOrRef as GenericElementOrRef
import org.jetbrains.kotlin.generators.tree.ElementRef as GenericElementRef import org.jetbrains.kotlin.generators.tree.ElementRef as GenericElementRef
@@ -90,8 +89,7 @@ class Element(
*/ */
var isLeaf = false var isLeaf = false
var childrenOrderOverride: List<String>? = null override var childrenOrderOverride: List<String>? = null
override var walkableChildren: List<Field> = emptyList()
override var visitorParameterName = category.defaultVisitorParam override var visitorParameterName = category.defaultVisitorParam
@@ -104,10 +102,19 @@ class Element(
override var hasTransformMethod = false override var hasTransformMethod = false
override val hasAcceptChildrenMethod: Boolean override val hasAcceptChildrenMethod: Boolean
get() = ownsChildren && (isRootElement || walkableChildren.isNotEmpty()) get() = hasAcceptOrTransformChildrenMethod(Element::walkableChildren)
override val hasTransformChildrenMethod: Boolean 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 transformByChildren = false
var ownsChildren = true // If false, acceptChildren/transformChildren will NOT be generated. var ownsChildren = true // If false, acceptChildren/transformChildren will NOT be generated.
@@ -135,7 +142,6 @@ typealias ElementOrRef = GenericElementOrRef<Element, Field>
sealed class Field( sealed class Field(
override val name: String, override val name: String,
override var isMutable: Boolean, override var isMutable: Boolean,
val isChild: Boolean,
) : AbstractField<Field>() { ) : AbstractField<Field>() {
var baseDefaultValue: String? = null var baseDefaultValue: String? = null
var baseGetter: String? = null var baseGetter: String? = null
@@ -147,8 +153,15 @@ sealed class Field(
data class Yes(val defaultValue: String?) : UseFieldAsParameterInIrFactoryStrategy() data class Yes(val defaultValue: String?) : UseFieldAsParameterInIrFactoryStrategy()
} }
var useInIrFactoryStrategy = var customUseInIrFactoryStrategy: UseFieldAsParameterInIrFactoryStrategy? = null
if (isChild) UseFieldAsParameterInIrFactoryStrategy.No else UseFieldAsParameterInIrFactoryStrategy.Yes(null)
val useInIrFactoryStrategy: UseFieldAsParameterInIrFactoryStrategy
get() = customUseInIrFactoryStrategy
?: if (needAcceptAndTransform && containsElement) {
UseFieldAsParameterInIrFactoryStrategy.No
} else {
UseFieldAsParameterInIrFactoryStrategy.Yes(null)
}
override val withGetter: Boolean override val withGetter: Boolean
get() = baseGetter != null get() = baseGetter != null
@@ -175,12 +188,13 @@ sealed class Field(
override fun copy() = internalCopy().also(::updateFieldsInCopy) override fun copy() = internalCopy().also(::updateFieldsInCopy)
protected fun updateFieldsInCopy(copy: Field) { protected fun updateFieldsInCopy(copy: Field) {
copy.needAcceptAndTransform = needAcceptAndTransform
copy.useInBaseTransformerDetection = useInBaseTransformerDetection copy.useInBaseTransformerDetection = useInBaseTransformerDetection
copy.isMutable = isMutable copy.isMutable = isMutable
copy.optInAnnotation = optInAnnotation copy.optInAnnotation = optInAnnotation
copy.baseDefaultValue = baseDefaultValue copy.baseDefaultValue = baseDefaultValue
copy.baseGetter = baseGetter copy.baseGetter = baseGetter
copy.useInIrFactoryStrategy = useInIrFactoryStrategy copy.customUseInIrFactoryStrategy = customUseInIrFactoryStrategy
copy.fromParent = fromParent copy.fromParent = fromParent
copy.customSetter = customSetter copy.customSetter = customSetter
copy.visibility = visibility copy.visibility = visibility
@@ -195,13 +209,12 @@ class SingleField(
name: String, name: String,
override var typeRef: TypeRefWithNullability, override var typeRef: TypeRefWithNullability,
mutable: Boolean, mutable: Boolean,
isChild: Boolean, ) : Field(name, mutable) {
) : Field(name, mutable, isChild) {
override fun replaceType(newType: TypeRefWithNullability) = 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( class ListField(
@@ -210,15 +223,14 @@ class ListField(
private val isNullable: Boolean, private val isNullable: Boolean,
override val listType: ClassRef<PositionTypeParameterRef>, override val listType: ClassRef<PositionTypeParameterRef>,
mutable: Boolean, mutable: Boolean,
isChild: Boolean, ) : Field(name, mutable), AbstractListField {
) : Field(name, mutable, isChild), AbstractListField {
override val typeRef: ClassRef<PositionTypeParameterRef> override val typeRef: ClassRef<PositionTypeParameterRef>
get() = listType.withArgs(baseType).copy(isNullable) get() = listType.withArgs(baseType).copy(isNullable)
override fun replaceType(newType: TypeRefWithNullability) = copy() 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 { enum class Mutability {
Var, Var,
@@ -5,8 +5,6 @@
package org.jetbrains.kotlin.ir.generator.model package org.jetbrains.kotlin.ir.generator.model
import org.jetbrains.kotlin.generators.tree.*
typealias Model = org.jetbrains.kotlin.generators.tree.Model<Element> typealias Model = org.jetbrains.kotlin.generators.tree.Model<Element>
internal fun markLeaves(elements: List<Element>) { internal fun markLeaves(elements: List<Element>) {
@@ -24,53 +22,3 @@ internal fun markLeaves(elements: List<Element>) {
el.isLeaf = true 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 val hasTransformChildrenMethod: Boolean
get() = false 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. * The fields on which to run the visitor in generated `acceptChildren` methods.
*/ */
val walkableChildren: List<Field> 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. * The fields on which to run the transformer in generated `transformChildren` methods.
@@ -5,9 +5,26 @@
package org.jetbrains.kotlin.generators.tree 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) { fun <Element : AbstractElement<Element, *>> Element.traverseParents(block: (Element) -> Unit) {
block(this) traverseParentsUntil { block(it); false }
elementParents.forEach { it.element.traverseParents(block) } }
/**
* 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 { operator fun <K, V, U> Map<K, Map<V, U>>.get(k1: K, k2: V): U {
return getValue(k1).getValue(k2) 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
}
}