[FIR/IR generator] Use TypeRef for working with types in fields

- Don't inherit `AbstractField` from `Importable`, because it really
  is not
- Remove the `arguments` and `nullable` properties from `AbstractField`.
  Both properties can be derived from the field's `typeRef`.
- Make `AbstractField`'s `typeRef` property of type
  `TypeRefWithNullability` instead of just `TypeRef`, because fields
  can always be nullable.
This commit is contained in:
Sergej Jaskiewicz
2023-10-17 22:04:14 +02:00
committed by Space Team
parent f30bf0e7e2
commit de4e39906c
22 changed files with 210 additions and 192 deletions
@@ -445,7 +445,7 @@ object BuilderConfigurator : AbstractBuilderConfigurator<FirTreeBuilder>(FirTree
configureFieldInAllLeafBuilders(
field = "attributes",
fieldPredicate = { it.type == declarationAttributesType.type }
fieldPredicate = { it.typeRef == declarationAttributesType }
) {
default(it, "${declarationAttributesType.type}()")
}
@@ -16,8 +16,12 @@ import org.jetbrains.kotlin.fir.tree.generator.FirTreeBuilder.typeParameter
import org.jetbrains.kotlin.fir.tree.generator.FirTreeBuilder.typeParameterRef
import org.jetbrains.kotlin.fir.tree.generator.FirTreeBuilder.typeProjection
import org.jetbrains.kotlin.fir.tree.generator.FirTreeBuilder.typeRef
import org.jetbrains.kotlin.fir.tree.generator.context.AbstractFieldConfigurator
import org.jetbrains.kotlin.fir.tree.generator.context.type
import org.jetbrains.kotlin.fir.tree.generator.model.*
import org.jetbrains.kotlin.generators.tree.TypeRefWithVariance
import org.jetbrains.kotlin.generators.tree.withArgs
import org.jetbrains.kotlin.types.Variance
object FieldSets {
val calleeReference by lazy { field("calleeReference", reference, withReplace = true) }
@@ -45,12 +49,17 @@ object FieldSets {
).withTransform(needTransformInOtherChildren = true)
}
fun symbolWithPackage(packageName: String, symbolClassName: String, argument: String? = null): Field {
return field("symbol", type(packageName, symbolClassName), argument)
}
fun AbstractFieldConfigurator<*>.ConfigureContext.symbolWithPackageWithArgument(packageName: String, symbolClassName: String) =
field("symbol", type(packageName, symbolClassName).withArgs(TypeRefWithVariance(Variance.OUT_VARIANCE, element)))
fun symbol(symbolClassName: String, argument: String? = null): Field =
symbolWithPackage("fir.symbols.impl", symbolClassName, argument)
fun symbolWithPackage(packageName: String, symbolClassName: String): Field =
field("symbol", type(packageName, symbolClassName))
fun AbstractFieldConfigurator<*>.ConfigureContext.symbolWithArgument(symbolClassName: String): Field =
symbolWithPackageWithArgument("fir.symbols.impl", symbolClassName)
fun symbol(symbolClassName: String): Field =
symbolWithPackage("fir.symbols.impl", symbolClassName)
fun body(nullable: Boolean = false, withReplace: Boolean = false) =
field("body", block, nullable, withReplace = withReplace)
@@ -23,7 +23,8 @@ import org.jetbrains.kotlin.fir.tree.generator.FieldSets.smartcastStability
import org.jetbrains.kotlin.fir.tree.generator.FieldSets.status
import org.jetbrains.kotlin.fir.tree.generator.FieldSets.superTypeRefs
import org.jetbrains.kotlin.fir.tree.generator.FieldSets.symbol
import org.jetbrains.kotlin.fir.tree.generator.FieldSets.symbolWithPackage
import org.jetbrains.kotlin.fir.tree.generator.FieldSets.symbolWithArgument
import org.jetbrains.kotlin.fir.tree.generator.FieldSets.symbolWithPackageWithArgument
import org.jetbrains.kotlin.fir.tree.generator.FieldSets.typeArguments
import org.jetbrains.kotlin.fir.tree.generator.FieldSets.typeParameterRefs
import org.jetbrains.kotlin.fir.tree.generator.FieldSets.typeParameters
@@ -35,6 +36,7 @@ import org.jetbrains.kotlin.fir.tree.generator.context.type
import org.jetbrains.kotlin.fir.tree.generator.model.*
import org.jetbrains.kotlin.generators.tree.StandardTypes
import org.jetbrains.kotlin.generators.tree.TypeRef
import org.jetbrains.kotlin.generators.tree.withArgs
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuilder) {
@@ -91,11 +93,11 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
}
fileAnnotationsContainer.configure {
+field("containingFileSymbol", type("fir.symbols.impl", "FirFileSymbol"), argument = null)
+field("containingFileSymbol", type("fir.symbols.impl", "FirFileSymbol"))
}
declaration.configure {
+symbolWithPackage("fir.symbols", "FirBasedSymbol", "out FirDeclaration")
+symbolWithPackageWithArgument("fir.symbols", "FirBasedSymbol")
+field("moduleData", firModuleDataType)
+field("origin", declarationOriginType)
+field("attributes", declarationAttributesType)
@@ -106,7 +108,7 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
+field("returnTypeRef", typeRef, withReplace = true).withTransform()
+field("receiverParameter", receiverParameter, nullable = true, withReplace = true).withTransform()
+field("deprecationsProvider", deprecationsProviderType).withReplace().apply { isMutable = true }
+symbol("FirCallableSymbol", "out FirCallableDeclaration")
+symbolWithArgument("FirCallableSymbol")
+field("containerSource", type<DeserializedContainerSource>(), nullable = true)
+field("dispatchReceiverType", coneSimpleKotlinTypeType, nullable = true)
@@ -115,7 +117,7 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
}
function.configure {
+symbol("FirFunctionSymbol", "out FirFunction")
+symbolWithArgument("FirFunctionSymbol")
+fieldList(valueParameter, withReplace = true).withTransform()
+body(nullable = true, withReplace = true).withTransform()
}
@@ -162,7 +164,7 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
jump.configure {
val e = withArg("E", targetElement)
+field("target", jumpTargetType to listOf(e))
+field("target", jumpTargetType.withArgs(e))
}
loopJump.configure {
@@ -227,7 +229,7 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
constExpression.configure {
val t = withArg("T")
+field("kind", constKindType to listOf(t), withReplace = true)
+field("kind", constKindType.withArgs(t), withReplace = true)
+field("value", t)
}
@@ -278,12 +280,12 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
}
classLikeDeclaration.configure {
+symbol("FirClassLikeSymbol", "out FirClassLikeDeclaration")
+symbolWithArgument("FirClassLikeSymbol")
+field("deprecationsProvider", deprecationsProviderType).withReplace().apply { isMutable = true }
}
klass.configure {
+symbol("FirClassSymbol", "out FirClass")
+symbolWithArgument("FirClassSymbol")
+classKind
+superTypeRefs(withReplace = true).withTransform()
+declarations.withTransform()
@@ -338,7 +340,7 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
typeParameter.configure {
+name
+symbol("FirTypeParameterSymbol")
+field("containingDeclarationSymbol", firBasedSymbolType to listOf(TypeRef.Star)).apply {
+field("containingDeclarationSymbol", firBasedSymbolType.withArgs(TypeRef.Star)).apply {
withBindThis = false
}
+field(varianceType)
@@ -427,7 +429,7 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
valueParameter.configure {
+symbol("FirValueParameterSymbol")
+field("defaultValue", expression, nullable = true, withReplace = true)
+field("containingFunctionSymbol", functionSymbolType, "*").apply {
+field("containingFunctionSymbol", functionSymbolType.withArgs(TypeRef.Star)).apply {
withBindThis = false
}
generateBooleanFields("crossinline", "noinline", "vararg")
@@ -440,7 +442,7 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
variable.configure {
+name
+symbol("FirVariableSymbol", "out FirVariable")
+symbolWithArgument("FirVariableSymbol")
+initializer.withTransform().withReplace()
+field("delegate", expression, nullable = true, withReplace = true).withTransform()
generateBooleanFields("var", "val")
@@ -548,7 +550,7 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
}
annotationArgumentMapping.configure {
+field("mapping", StandardTypes.map to listOf(nameType, expression))
+field("mapping", StandardTypes.map.withArgs(nameType, expression))
}
augmentedArraySetCall.configure {
@@ -571,7 +573,7 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
smartCastExpression.configure {
+field("originalExpression", expression, withReplace = true).withTransform()
+field("typesFromSmartCast", StandardTypes.collection to listOf(coneKotlinTypeType))
+field("typesFromSmartCast", StandardTypes.collection.withArgs(coneKotlinTypeType))
+field("smartcastType", typeRef)
+field("smartcastTypeWithoutNullableNothing", typeRef, nullable = true)
+booleanField("isStable")
@@ -667,11 +669,11 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
}
namedReferenceWithCandidateBase.configure {
+field("candidateSymbol", firBasedSymbolType, "*")
+field("candidateSymbol", firBasedSymbolType.withArgs(TypeRef.Star))
}
resolvedNamedReference.configure {
+field("resolvedSymbol", firBasedSymbolType, "*")
+field("resolvedSymbol", firBasedSymbolType.withArgs(TypeRef.Star))
}
resolvedCallableReference.configure {
@@ -694,7 +696,7 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
thisReference.configure {
+stringField("labelName", nullable = true)
+field("boundSymbol", firBasedSymbolType, "*", nullable = true, withReplace = true)
+field("boundSymbol", firBasedSymbolType.withArgs(TypeRef.Star), nullable = true, withReplace = true)
+intField("contextReceiverNumber", withReplace = true)
+booleanField("isImplicit")
+field("diagnostic", coneDiagnosticType, nullable = true, withReplace = true)
@@ -20,6 +20,8 @@ import org.jetbrains.kotlin.fir.types.ConeErrorType
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.ConeSimpleKotlinType
import org.jetbrains.kotlin.generators.tree.TypeKind
import org.jetbrains.kotlin.generators.tree.TypeRef
import org.jetbrains.kotlin.generators.tree.withArgs
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
@@ -52,9 +54,12 @@ val coneSimpleKotlinTypeType = type<ConeSimpleKotlinType>()
val coneClassLikeTypeType = type<ConeClassLikeType>()
val standardClassIdsType = type<StandardClassIds>()
val whenRefType = generatedType("", "FirExpressionRef<FirWhenExpression>")
val referenceToSimpleExpressionType = generatedType("", "FirExpressionRef<FirExpression>")
val safeCallCheckedSubjectReferenceType = generatedType("", "FirExpressionRef<FirCheckedSafeCallSubject>")
val whenRefType = generatedType("", "FirExpressionRef")
.withArgs(FirTreeBuilder.whenExpression)
val referenceToSimpleExpressionType = generatedType("", "FirExpressionRef")
.withArgs(FirTreeBuilder.expression)
val safeCallCheckedSubjectReferenceType = generatedType("", "FirExpressionRef")
.withArgs(FirTreeBuilder.checkedSafeCallSubject)
val firModuleDataType = type("fir", "FirModuleData")
val firImplicitTypeWithoutSourceType = generatedType("types.impl", "FirImplicitTypeRefImplWithoutSource")
@@ -75,7 +80,7 @@ val firBasedSymbolType = type("fir.symbols", "FirBasedSymbol")
val functionSymbolType = type("fir.symbols.impl", "FirFunctionSymbol")
val backingFieldSymbolType = type("fir.symbols.impl", "FirBackingFieldSymbol")
val delegateFieldSymbolType = type("fir.symbols.impl", "FirDelegateFieldSymbol")
val classLikeSymbolType = type("fir.symbols.impl", "FirClassLikeSymbol<*>")
val classLikeSymbolType = type("fir.symbols.impl", "FirClassLikeSymbol").withArgs(TypeRef.Star)
val regularClassSymbolType = type("fir.symbols.impl", "FirRegularClassSymbol")
val typeParameterSymbolType = type("fir.symbols.impl", "FirTypeParameterSymbol")
val emptyArgumentListType = type("fir.expressions", "FirEmptyArgumentList")
@@ -104,7 +104,7 @@ class Element(override val name: String, kind: Kind) : AbstractElement<Element,
existingField.needTransformInOtherChildren = existingField.needTransformInOtherChildren || parentField.needTransformInOtherChildren
existingField.withReplace = parentField.withReplace || existingField.withReplace
existingField.parentHasSeparateTransform = parentField.needsSeparateTransform
if (parentField.type != existingField.type && parentField.withReplace) {
if (parentField.typeRef.copy(nullable = false) != existingField.typeRef.copy(nullable = false) && parentField.withReplace) {
existingField.overridenTypes += parentField.typeRef
overridenFields[existingField, parentField] = false
} else {
@@ -126,15 +126,9 @@ class Element(override val name: String, kind: Kind) : AbstractElement<Element,
val parent = parentRef.element
val fields = parent.allFields.map { field ->
val copy = (field as? SimpleField)?.let { simpleField ->
// FIXME: Replace with parentRef.args[simpleField.typeRef]
parentRef.args[NamedTypeParameterRef(simpleField.type)]?.let {
simpleField.replaceType(it)
}
simpleField.replaceType(simpleField.typeRef.substitute(parentRef.args) as TypeRefWithNullability)
} ?: field.copy()
copy.apply {
arguments.replaceAll {
parentRef.args[it] ?: it
}
fromParent = true
}
}
@@ -5,26 +5,16 @@
package org.jetbrains.kotlin.fir.tree.generator.model
import org.jetbrains.kotlin.generators.tree.NamedTypeParameterRef
import org.jetbrains.kotlin.generators.tree.StandardTypes
import org.jetbrains.kotlin.generators.tree.TypeRef
import org.jetbrains.kotlin.generators.tree.typeWithArguments
import org.jetbrains.kotlin.generators.tree.*
// ----------- Simple field -----------
fun field(name: String, type: TypeRef, nullable: Boolean = false, withReplace: Boolean = false): Field {
return SimpleField(name, type.typeWithArguments, type.packageName, nullable, withReplace)
fun field(name: String, type: TypeRefWithNullability, nullable: Boolean = false, withReplace: Boolean = false): Field {
return SimpleField(name, type.copy(nullable), withReplace)
}
fun field(name: String, typeWithArgs: Pair<TypeRef, List<TypeRef>>, nullable: Boolean = false, withReplace: Boolean = false): Field {
val (type, args) = typeWithArgs
return SimpleField(name, type.typeWithArguments, type.packageName, nullable, withReplace).apply {
arguments += args
}
}
fun field(type: TypeRef, nullable: Boolean = false, withReplace: Boolean = false): Field {
return SimpleField(type.type.replaceFirstChar(Char::lowercaseChar), type.typeWithArguments, type.packageName, nullable, withReplace)
fun field(type: TypeRefWithNullability, nullable: Boolean = false, withReplace: Boolean = false): Field {
return SimpleField(type.type.replaceFirstChar(Char::lowercaseChar), type.copy(nullable), withReplace)
}
fun booleanField(name: String, withReplace: Boolean = false): Field {
@@ -41,20 +31,12 @@ fun intField(name: String, withReplace: Boolean = false): Field {
// ----------- Fir field -----------
fun field(name: String, type: TypeRef, argument: String? = null, nullable: Boolean = false, withReplace: Boolean = false): Field {
return if (argument == null) {
field(name, type, nullable, withReplace)
} else {
field(name, type to listOf(NamedTypeParameterRef(argument)), nullable, withReplace)
}
}
fun field(name: String, element: ElementOrRef, nullable: Boolean = false, withReplace: Boolean = false): Field {
return FirField(name, element, nullable, withReplace)
return FirField(name, element.copy(nullable), withReplace)
}
fun field(element: Element, nullable: Boolean = false, withReplace: Boolean = false): Field {
return FirField(element.name.replaceFirstChar(Char::lowercaseChar), element, nullable, withReplace)
return FirField(element.name.replaceFirstChar(Char::lowercaseChar), element.copy(nullable), withReplace)
}
// ----------- Field list -----------
@@ -91,4 +73,4 @@ fun Field.withTransform(needTransformInOtherChildren: Boolean = false): Field =
fun Field.withReplace(): Field = copy().apply {
withReplace = true
}
}
@@ -29,7 +29,7 @@ sealed class Field : AbstractField() {
open var isMutableInInterface: Boolean = false
open val fromDelegate: Boolean get() = false
open val overridenTypes: MutableSet<TypeRef> = mutableSetOf()
open val overridenTypes: MutableSet<TypeRefWithNullability> = mutableSetOf()
open var useNullableForReplace: Boolean = false
open var notNull: Boolean = false
@@ -45,16 +45,12 @@ sealed class Field : AbstractField() {
abstract override var isMutable: Boolean
override fun getTypeWithArguments(notNull: Boolean): String = type + generics + if (nullable && !notNull) "?" else ""
fun copy(): Field = internalCopy().also {
updateFieldsInCopy(it)
}
protected fun updateFieldsInCopy(copy: Field) {
if (copy !is FieldWithDefault) {
copy.arguments.clear()
copy.arguments.addAll(arguments)
copy.needsSeparateTransform = needsSeparateTransform
copy.needTransformInOtherChildren = needTransformInOtherChildren
copy.useInBaseTransformerDetection = useInBaseTransformerDetection
@@ -77,13 +73,11 @@ sealed class Field : AbstractField() {
class FieldWithDefault(val origin: Field) : Field() {
override val name: String get() = origin.name
override val type: String get() = origin.type
override val typeRef: TypeRefWithNullability get() = origin.typeRef
override var isVolatile: Boolean = origin.isVolatile
override val nullable: Boolean get() = origin.nullable
override var withReplace: Boolean
get() = origin.withReplace
set(_) {}
override val packageName: String? get() = origin.packageName
override val isFirType: Boolean get() = origin.isFirType
override var needsSeparateTransform: Boolean
get() = origin.needsSeparateTransform
@@ -93,12 +87,6 @@ class FieldWithDefault(val origin: Field) : Field() {
get() = origin.needTransformInOtherChildren
set(_) {}
override val arguments: MutableList<TypeRef>
get() = origin.arguments
override val fullQualifiedName: String?
get() = origin.fullQualifiedName
override var isFinal: Boolean
get() = origin.isFinal
set(_) {}
@@ -128,7 +116,7 @@ class FieldWithDefault(val origin: Field) : Field() {
override var customSetter: String? = null
override var fromDelegate: Boolean = false
var needAcceptAndTransform: Boolean = true
override val overridenTypes: MutableSet<TypeRef>
override val overridenTypes: MutableSet<TypeRefWithNullability>
get() = origin.overridenTypes
override val arbitraryImportables: MutableList<Importable>
@@ -151,9 +139,7 @@ class FieldWithDefault(val origin: Field) : Field() {
class SimpleField(
override val name: String,
override val type: String,
override val packageName: String?,
override val nullable: Boolean,
override val typeRef: TypeRefWithNullability,
override var withReplace: Boolean,
override var isVolatile: Boolean = false,
override var isFinal: Boolean = false,
@@ -167,9 +153,7 @@ class SimpleField(
override fun internalCopy(): Field {
return SimpleField(
name = name,
type = type,
packageName = packageName,
nullable = nullable,
typeRef = typeRef,
withReplace = withReplace,
isVolatile = isVolatile,
isFinal = isFinal,
@@ -180,11 +164,9 @@ class SimpleField(
}
}
fun replaceType(newType: TypeRef) = SimpleField(
fun replaceType(newType: TypeRefWithNullability) = SimpleField(
name = name,
type = newType.type,
packageName = newType.packageName,
nullable = nullable,
typeRef = newType,
withReplace = withReplace,
isVolatile = isVolatile,
isFinal = isFinal,
@@ -198,18 +180,14 @@ class SimpleField(
class FirField(
override val name: String,
val element: ElementOrRef,
override val nullable: Boolean,
val element: ElementRef,
override var withReplace: Boolean,
) : Field() {
init {
arguments += element.args.values
}
override val type: String get() = element.type
override val typeRef: TypeRefWithNullability
get() = element
override var isVolatile: Boolean = false
override var isFinal: Boolean = false
override val packageName: String? get() = element.packageName
override val isFirType: Boolean = true
override var isMutable: Boolean = true
@@ -217,14 +195,10 @@ class FirField(
override var isLateinit: Boolean = false
override var isParameter: Boolean = false
override fun getTypeWithArguments(notNull: Boolean): String =
element.getTypeWithArguments(notNull) + if (nullable && !notNull) "?" else ""
override fun internalCopy(): Field {
return FirField(
name,
element,
nullable,
withReplace
).apply {
withBindThis = this@FirField.withBindThis
@@ -241,12 +215,8 @@ class FieldList(
useMutableOrEmpty: Boolean = false
) : Field() {
override var defaultValueInImplementation: String? = null
override val packageName: String? get() = baseType.packageName
override val fullQualifiedName: String? get() = baseType.fullQualifiedName
override val type: String = "List<${baseType.typeWithArguments}>"
override val nullable: Boolean
get() = false
override val typeRef: ClassRef<PositionTypeParameterRef>
get() = StandardTypes.list.withArgs(baseType)
override var isVolatile: Boolean = false
override var isFinal: Boolean = false
@@ -7,6 +7,8 @@ package org.jetbrains.kotlin.fir.tree.generator.printer
import org.jetbrains.kotlin.fir.tree.generator.declarationAttributesType
import org.jetbrains.kotlin.fir.tree.generator.model.*
import org.jetbrains.kotlin.generators.tree.StandardTypes
import org.jetbrains.kotlin.generators.tree.TypeRefWithNullability
import org.jetbrains.kotlin.generators.tree.printer.GeneratedFile
import org.jetbrains.kotlin.generators.tree.printer.printGeneratedType
import org.jetbrains.kotlin.generators.tree.typeWithArguments
@@ -129,7 +131,8 @@ private fun FieldWithDefault.needBackingField(fieldIsUseless: Boolean) =
defaultValueInBuilder == null
}
private fun FieldWithDefault.needNotNullDelegate(fieldIsUseless: Boolean) = needBackingField(fieldIsUseless) && (type == "Boolean" || type == "Int")
private fun FieldWithDefault.needNotNullDelegate(fieldIsUseless: Boolean) =
needBackingField(fieldIsUseless) && (typeRef == StandardTypes.boolean || typeRef == StandardTypes.int)
private fun SmartPrinter.printFieldInBuilder(field: FieldWithDefault, builder: Builder, fieldIsUseless: Boolean): Pair<Boolean, Boolean> {
@@ -139,7 +142,7 @@ private fun SmartPrinter.printFieldInBuilder(field: FieldWithDefault, builder: B
return true to false
}
val name = field.name
val type = field.getTypeWithArguments(field.notNull)
val type = field.typeRef.getTypeWithArguments(field.notNull)
val defaultValue = if (fieldIsUseless)
field.defaultValueInImplementation.also { requireNotNull(it) }
else
@@ -168,7 +171,7 @@ private fun SmartPrinter.printFieldInBuilder(field: FieldWithDefault, builder: B
false
}
field.needNotNullDelegate(fieldIsUseless) -> {
println(" by kotlin.properties.Delegates.notNull<${field.type}>()")
println(" by kotlin.properties.Delegates.notNull<${field.typeRef.type}>()")
hasRequiredFields = true
true
}
@@ -206,7 +209,7 @@ private fun SmartPrinter.printDeprecationOnUselessFieldIfNeeded(field: Field, bu
private fun SmartPrinter.printFieldListInBuilder(field: FieldList, builder: Builder, fieldIsUseless: Boolean) {
printDeprecationOnUselessFieldIfNeeded(field, builder, fieldIsUseless)
printModifiers(builder, field, fieldIsUseless)
print("val ${field.name}: ${field.getMutableType(forBuilder = true)}")
print("val ${field.name}: ${field.getMutableType(forBuilder = true).typeWithArguments}")
if (builder is LeafBuilder) {
print(" = mutableListOf()")
}
@@ -301,7 +304,7 @@ private fun SmartPrinter.printDslBuildCopyFunction(
when {
field.invisibleField -> {}
field.origin is FieldList -> println("copyBuilder.${field.name}.addAll(original.${field.name})")
field.type == declarationAttributesType.type -> println("copyBuilder.${field.name} = original.${field.name}.copy()")
field.typeRef == declarationAttributesType -> println("copyBuilder.${field.name} = original.${field.name}.copy()")
field.notNull -> println("original.${field.name}?.let { copyBuilder.${field.name} = it }")
else -> println("copyBuilder.${field.name} = original.${field.name}")
}
@@ -82,7 +82,7 @@ fun SmartPrinter.printElement(element: Element) {
}
}
fun Field.replaceDeclaration(override: Boolean, overridenType: TypeRef? = null, forceNullable: Boolean = false) {
fun Field.replaceDeclaration(override: Boolean, overridenType: TypeRefWithNullability? = null, forceNullable: Boolean = false) {
println()
if (name == "source") {
println("@FirImplementationDetail")
@@ -6,11 +6,18 @@
package org.jetbrains.kotlin.fir.tree.generator.printer
import org.jetbrains.kotlin.fir.tree.generator.model.Field
import org.jetbrains.kotlin.generators.tree.typeWithArguments
import org.jetbrains.kotlin.utils.SmartPrinter
import org.jetbrains.kotlin.utils.withIndent
fun SmartPrinter.printField(field: Field, isImplementation: Boolean, override: Boolean, inConstructor: Boolean = false, notNull: Boolean = false, modifiers: SmartPrinter.() -> Unit = {}) {
fun SmartPrinter.printField(
field: Field,
isImplementation: Boolean,
override: Boolean,
inConstructor: Boolean = false,
modifiers: SmartPrinter.() -> Unit = {},
) {
if (!field.isVal && field.isVolatile) {
println("@Volatile")
}
@@ -32,8 +39,8 @@ fun SmartPrinter.printField(field: Field, isImplementation: Boolean, override: B
} else {
print("val")
}
val type = if (isImplementation) field.getMutableType(notNull = notNull) else field.getTypeWithArguments(notNull = notNull)
print(" ${field.name}: $type")
val type = if (isImplementation) field.getMutableType() else field.typeRef
print(" ${field.name}: ${type.typeWithArguments}")
if (inConstructor) print(",")
println()
}
@@ -52,7 +59,7 @@ fun SmartPrinter.printFieldWithDefaultInImplementation(field: Field) {
} else {
print("var")
}
print(" ${field.name}: ${field.getMutableType()}")
print(" ${field.name}: ${field.getMutableType().typeWithArguments}")
if (field.withGetter) {
println()
pushIndent()
@@ -79,9 +79,11 @@ fun SmartPrinter.printImplementation(implementation: Implementation) {
withIndent {
fieldsWithoutDefault.forEachIndexed { _, field ->
if (field.isParameter) {
println("${field.name}: ${field.typeWithArguments},")
print("${field.name}: ${field.typeRef.typeWithArguments}")
if (field.nullable) print("?")
println(",")
} else if (!field.isFinal) {
printField(field, isImplementation = true, override = true, inConstructor = true, notNull = field.notNull)
printField(field, isImplementation = true, override = true, inConstructor = true)
}
}
}
@@ -99,7 +101,7 @@ fun SmartPrinter.printImplementation(implementation: Implementation) {
allFields.forEach {
abstract()
printField(it, isImplementation = true, override = true, notNull = it.notNull)
printField(it, isImplementation = true, override = true)
}
} else {
fieldsWithDefault.forEach {
@@ -112,7 +114,7 @@ fun SmartPrinter.printImplementation(implementation: Implementation) {
val bindingCalls = element.allFields.filter {
it.withBindThis && it.type.contains("Symbol") && it !is FieldList && it.name != "companionObjectSymbol"
it.withBindThis && it.typeRef.type.contains("Symbol") && it !is FieldList && it.name != "companionObjectSymbol"
}.takeIf {
it.isNotEmpty() && !isInterface && !isAbstract &&
!element.type.contains("Reference")
@@ -322,7 +324,7 @@ fun SmartPrinter.printImplementation(implementation: Implementation) {
fun generateReplace(
field: Field,
overridenType: TypeRef? = null,
overridenType: TypeRefWithNullability? = null,
forceNullable: Boolean = false,
body: () -> Unit,
) {
@@ -375,7 +377,7 @@ fun SmartPrinter.printImplementation(implementation: Implementation) {
for (overridenType in field.overridenTypes) {
generateReplace(field, overridenType) {
println("require($newValue is ${field.typeWithArguments})")
println("require($newValue is ${field.typeRef.typeWithArguments})")
println("replace$capitalizedFieldName($newValue)")
}
}
@@ -30,8 +30,9 @@ fun Builder.collectImports(): List<String> {
usedTypes.mapNotNullTo(this) { it.fullQualifiedName }
for (field in allFields) {
if (field.invisibleField) continue
field.fullQualifiedName?.let(this::add)
field.arguments.mapNotNullTo(this) { it.fullQualifiedName }
// TODO: Use recursive import collection for TypeRefs
field.typeRef.fullQualifiedName?.let(this::add)
(field.typeRef as? ParametrizedTypeRef<*, *>)?.args?.values?.mapNotNullTo(this) { it.fullQualifiedName }
}
add(materializedElement?.fullQualifiedName ?: throw IllegalStateException(type))
@@ -72,9 +73,9 @@ fun Element.collectImports(): List<String> {
}
private fun Element.collectImportsInternal(base: List<String>, kind: ImportKind): List<String> {
val fqns = base + allFields.mapNotNull { it.fullQualifiedName } +
val fqns = base + allFields.mapNotNull { it.typeRef.fullQualifiedName } +
allFields.flatMap { it.overridenTypes.mapNotNull { it.fullQualifiedName } + it.arbitraryImportables.mapNotNull { it.fullQualifiedName } } +
allFields.flatMap { it.arguments.mapNotNull { it.fullQualifiedName } } +
allFields.flatMap { (it.typeRef as? ParametrizedTypeRef<*, *>)?.args?.values?.mapNotNull { it.fullQualifiedName } ?: emptyList() } + // TODO: Use recursive import collection for TypeRefs
params.flatMap { it.bounds.mapNotNull { it.fullQualifiedName } }
val result = fqns.filterRedundantImports(packageName, kind).toMutableList()
@@ -122,23 +123,21 @@ fun transformFunctionDeclaration(transformName: String, returnType: String): Str
return "fun <D> transform$transformName(transformer: FirTransformer<D>, data: D): $returnType"
}
fun Field.replaceFunctionDeclaration(overridenType: TypeRef? = null, forceNullable: Boolean = false): String {
fun Field.replaceFunctionDeclaration(overridenType: TypeRefWithNullability? = null, forceNullable: Boolean = false): String {
val capName = name.replaceFirstChar(Char::uppercaseChar)
val type = overridenType?.typeWithArguments ?: typeWithArguments
val typeWithNullable = if (forceNullable && !type.endsWith("?")) "$type?" else type
return "fun replace$capName(new$capName: $typeWithNullable)"
val type = overridenType ?: typeRef
val typeWithNullable = if (forceNullable) type.copy(nullable = true) else type
return "fun replace$capName(new$capName: ${typeWithNullable.typeWithArguments})"
}
fun Field.getMutableType(forBuilder: Boolean = false, notNull: Boolean = false): String = when (this) {
fun Field.getMutableType(forBuilder: Boolean = false): TypeRef = when (this) {
is FieldList -> when {
isMutableOrEmpty && !forBuilder -> "MutableOrEmpty$typeWithArguments"
isMutable -> "Mutable$typeWithArguments"
else -> typeWithArguments
}
is FieldWithDefault -> if (isMutable) origin.getMutableType(notNull) else getTypeWithArguments(notNull)
else -> getTypeWithArguments(notNull)
isMutableOrEmpty && !forBuilder -> type(BASE_PACKAGE, "MutableOrEmptyList", kind = TypeKind.Class)
isMutable -> StandardTypes.mutableList
else -> StandardTypes.list
}.withArgs(baseType).copy(nullable)
is FieldWithDefault -> if (isMutable) origin.getMutableType() else typeRef
else -> typeRef
}
fun Field.call(): String = if (nullable) "?." else "."
@@ -147,8 +146,3 @@ val Element.safeDecapitalizedName: String get() = if (name == "Class") "klass" e
val ImplementationWithArg.generics: String
get() = argument?.let { "<${it.type}>" } ?: ""
val Field.generics: String
get() = arguments.takeIf { it.isNotEmpty() }
?.let { it.joinToString(", ", "<", ">") { it.typeWithArguments } }
?: ""
@@ -17,13 +17,13 @@ import org.jetbrains.kotlin.generators.tree.ElementOrRef as GenericElementOrRef
* a type of [Field], except when that [Field] is explicitly opted out of it via [Field.useInBaseTransformerDetection].
*/
fun detectBaseTransformerTypes(builder: AbstractFirTreeBuilder) {
val usedAsFieldType = hashSetOf<GenericElementOrRef<*, *>>()
val usedAsFieldType = hashSetOf<Element>()
for (element in builder.elements) {
for (field in element.allFirFields) {
if (!field.useInBaseTransformerDetection) continue
val fieldElement = when (field) {
is FirField -> field.element
is FieldList -> field.baseType as GenericElementOrRef<*, *>
is FirField -> field.element.element
is FieldList -> (field.baseType as GenericElementOrRef<*, *>).element as Element
else -> error("Invalid field type: $field")
}
if (fieldElement == AbstractFirTreeBuilder.baseFirElement) continue
@@ -33,7 +33,7 @@ import org.jetbrains.kotlin.types.Variance
// 2) parents
// 3) fields
object IrTree : AbstractTreeBuilder() {
private fun symbol(type: TypeRef, mutable: Boolean = false): SimpleFieldConfig =
private fun symbol(type: TypeRefWithNullability, mutable: Boolean = false): SimpleFieldConfig =
field("symbol", type, mutable = mutable)
private fun descriptor(typeName: String, nullable: Boolean = false): SimpleFieldConfig =
@@ -6,6 +6,7 @@
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.types.Variance
@@ -36,7 +37,7 @@ abstract class AbstractTreeBuilder {
protected fun field(
name: String,
type: TypeRef?,
type: TypeRefWithNullability?,
nullable: Boolean = false,
mutable: Boolean = true,
isChild: Boolean = false,
@@ -62,6 +62,8 @@ class ElementConfig(
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)
}
@@ -78,8 +80,6 @@ class ElementConfig(
override val type: String
get() = Element.elementName2typeName(name)
override fun getTypeWithArguments(notNull: Boolean): String = type
enum class Category(private val packageDir: String, val defaultVisitorParam: String) {
Expression("expressions", "expression"),
Declaration("declarations", "declaration"),
@@ -108,8 +108,6 @@ class ElementConfigRef(
override val packageName: String
get() = element.packageName
override fun getTypeWithArguments(notNull: Boolean): String = type + generics
}
sealed class UseFieldAsParameterInIrFactoryStrategy {
@@ -152,7 +150,7 @@ sealed class FieldConfig(
class SimpleFieldConfig(
name: String,
val type: TypeRef?,
val type: TypeRefWithNullability?,
val nullable: Boolean,
val mutable: Boolean,
isChildElement: Boolean,
@@ -116,7 +116,6 @@ typealias ElementOrRef = GenericElementOrRef<Element, Field>
sealed class Field(
config: FieldConfig,
override val name: String,
override val nullable: Boolean,
override var isMutable: Boolean,
val isChild: Boolean,
) : AbstractField() {
@@ -145,25 +144,17 @@ sealed class Field(
override val isParameter: Boolean
get() = false
override val type: String
get() = typeRef.type
override val packageName: String?
get() = typeRef.packageName
override fun getTypeWithArguments(notNull: Boolean): String = typeRef.getTypeWithArguments(notNull)
}
class SingleField(
config: FieldConfig,
name: String,
override var typeRef: TypeRef,
nullable: Boolean,
override var typeRef: TypeRefWithNullability,
mutable: Boolean,
isChild: Boolean,
override val baseDefaultValue: CodeBlock?,
override val baseGetter: CodeBlock?,
) : Field(config, name, nullable, mutable, isChild) {
) : Field(config, name, mutable, isChild) {
override val transformable: Boolean
get() = isMutable
}
@@ -173,13 +164,12 @@ class ListField(
name: String,
var elementType: TypeRef,
private val listType: ClassRef<PositionTypeParameterRef>,
nullable: Boolean,
mutable: Boolean,
isChild: Boolean,
override val transformable: Boolean,
override val baseDefaultValue: CodeBlock?,
override val baseGetter: CodeBlock?,
) : Field(config, name, nullable, mutable, isChild) {
override val typeRef: TypeRef
) : Field(config, name, mutable, isChild) {
override val typeRef: TypeRefWithNullability
get() = listType.withArgs(elementType)
}
@@ -13,7 +13,7 @@ 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 : TypeRef {
private object InferredOverriddenType : TypeRefWithNullability {
override val type: String
get() = error("not supported")
override val packageName: String?
@@ -22,6 +22,13 @@ private object InferredOverriddenType : TypeRef {
override fun getTypeWithArguments(notNull: Boolean): String {
error("not supported")
}
override fun substitute(map: TypeParameterSubstitutionMap) = this
override val nullable: Boolean
get() = false
override fun copy(nullable: Boolean) = this
}
data class Model(val elements: List<Element>, val rootElement: Element)
@@ -57,8 +64,7 @@ private fun transformFieldConfig(fc: FieldConfig): Field = when (fc) {
is SimpleFieldConfig -> SingleField(
fc,
fc.name,
fc.type ?: InferredOverriddenType,
fc.nullable,
fc.type?.copy(fc.nullable) ?: InferredOverriddenType,
fc.mutable,
fc.isChild,
fc.baseDefaultValue,
@@ -74,8 +80,7 @@ private fun transformFieldConfig(fc: FieldConfig): Field = when (fc) {
fc,
fc.name,
fc.elementType ?: InferredOverriddenType,
listType,
fc.nullable,
listType.copy(fc.nullable),
fc.mutability == ListFieldConfig.Mutability.Var,
fc.isChild,
fc.mutability != ListFieldConfig.Mutability.Immutable,
@@ -127,7 +132,7 @@ private fun replaceElementRefs(config: Config, mapping: Map<ElementConfig, Eleme
for (field in el.fields) {
when (field) {
is SingleField -> {
field.typeRef = transform(field.typeRef)
field.typeRef = transform(field.typeRef) as TypeRefWithNullability
}
is ListField -> {
field.elementType = transform(field.elementType)
@@ -186,7 +191,8 @@ private fun processFieldOverrides(elements: List<Element>) {
type.takeUnless { it is InferredOverriddenType } ?: overriddenType
when (field) {
is SingleField -> {
field.typeRef = transformInferredType(field.typeRef, (overriddenField as SingleField).typeRef)
field.typeRef =
transformInferredType(field.typeRef, (overriddenField as SingleField).typeRef) as TypeRefWithNullability
}
is ListField -> {
field.elementType = transformInferredType(field.elementType, (overriddenField as ListField).elementType)
@@ -235,7 +235,6 @@ fun printElements(generationPath: File, model: Model) = sequence {
val elRef = child.typeRef as GenericElementRef<Element, Field>
if (!elRef.element.hasTransformMethod) {
append(" as %T")
if (child.nullable) append("?")
args.add(elRef.toPoet())
}
}
@@ -55,4 +55,7 @@ abstract class AbstractElement<Element, Field> : ElementOrRef<Element, Field>, F
@Suppress("UNCHECKED_CAST")
final override fun copy(args: Map<NamedTypeParameterRef, TypeRef>) =
ElementRef(this as Element, args, nullable)
@Suppress("UNCHECKED_CAST")
override fun substitute(map: TypeParameterSubstitutionMap): Element = this as Element
}
@@ -5,16 +5,14 @@
package org.jetbrains.kotlin.generators.tree
abstract class AbstractField : Importable {
abstract class AbstractField {
abstract val name: String
open val typeRef: TypeRef
get() = type(packageName!!, type).withArgs(*arguments.toTypedArray()).copy(nullable = nullable)
abstract val typeRef: TypeRefWithNullability
open val arguments = mutableListOf<TypeRef>()
abstract val nullable: Boolean
val nullable: Boolean
get() = typeRef.nullable
abstract val isVolatile: Boolean
@@ -49,4 +47,4 @@ abstract class AbstractField : Importable {
override fun hashCode(): Int {
return name.hashCode()
}
}
}
@@ -11,6 +11,13 @@ import java.util.*
import kotlin.reflect.KClass
interface TypeRef : Importable {
/**
* Constructs a new [TypeRef] by recursively replacing referenced [TypeParameterRef]s with other types according to the provided
* substitution map.
*/
fun substitute(map: TypeParameterSubstitutionMap): TypeRef
object Star : TypeRef {
override val type: String
get() = "*"
@@ -20,6 +27,8 @@ interface TypeRef : Importable {
override fun getTypeWithArguments(notNull: Boolean): String = type
override fun substitute(map: TypeParameterSubstitutionMap) = this
override fun toString(): String = type
}
}
@@ -65,8 +74,6 @@ class ClassRef<P : TypeParameterRef> private constructor(
override val fullQualifiedName: String
get() = canonicalName
override fun getTypeWithArguments(notNull: Boolean): String = type + generics
/**
* The enclosing classes, outermost first, followed by the simple name. This is `["Map", "Entry"]`
* for `Map.Entry`.
@@ -77,12 +84,44 @@ class ClassRef<P : TypeParameterRef> private constructor(
override fun copy(nullable: Boolean) = ClassRef(kind, names, args, nullable)
override fun toString() = canonicalName
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is ClassRef<*>) return false
return kind == other.kind && args == other.args && nullable == other.nullable && names == other.names
}
override fun hashCode(): Int = Objects.hash(kind, args, nullable, names)
}
/**
* Used for specifying a type argument with use-site variance, e.g. `FirClassSymbol<out FirClass>`.
*/
data class TypeRefWithVariance<out T : TypeRef>(val variance: Variance, val typeRef: T) : TypeRef {
override val type: String
get() = buildString {
if (variance != Variance.INVARIANT) {
append(variance)
append(" ")
}
append(typeRef.typeWithArguments)
}
override val packageName: String?
get() = null
override fun getTypeWithArguments(notNull: Boolean): String = type
override fun substitute(map: TypeParameterSubstitutionMap): TypeRefWithVariance<*> =
TypeRefWithVariance(variance, typeRef.substitute(map))
}
interface ElementOrRef<Element, Field> : ParametrizedTypeRef<ElementOrRef<Element, Field>, NamedTypeParameterRef>, ClassOrElementRef
where Element : AbstractElement<Element, Field>,
Field : AbstractField {
val element: Element
override fun copy(nullable: Boolean): ElementRef<Element, Field>
}
data class ElementRef<Element : AbstractElement<Element, Field>, Field : AbstractField>(
@@ -98,10 +137,6 @@ data class ElementRef<Element : AbstractElement<Element, Field>, Field : Abstrac
override val packageName: String?
get() = element.packageName
override fun getTypeWithArguments(notNull: Boolean): String {
return element.type + generics
}
override fun toString() = buildString {
append(element.name)
append("<")
@@ -114,10 +149,13 @@ data class ElementRef<Element : AbstractElement<Element, Field>, Field : Abstrac
}
sealed interface TypeParameterRef : TypeRef
sealed interface TypeParameterRef : TypeRef, TypeRefWithNullability {
override fun substitute(map: TypeParameterSubstitutionMap): TypeRef = map[this] ?: this
}
data class PositionTypeParameterRef(
val index: Int,
override val nullable: Boolean = false,
) : TypeParameterRef {
override fun toString() = index.toString()
@@ -128,10 +166,13 @@ data class PositionTypeParameterRef(
get() = null
override fun getTypeWithArguments(notNull: Boolean): String = type
override fun copy(nullable: Boolean) = PositionTypeParameterRef(index, nullable)
}
open class NamedTypeParameterRef(
val name: String,
override val nullable: Boolean = false,
) : TypeParameterRef {
override fun equals(other: Any?): Boolean {
return other is NamedTypeParameterRef && other.name == name
@@ -150,6 +191,8 @@ open class NamedTypeParameterRef(
get() = null
override fun getTypeWithArguments(notNull: Boolean) = name
final override fun copy(nullable: Boolean) = NamedTypeParameterRef(name, nullable)
}
interface TypeRefWithNullability : TypeRef {
@@ -158,20 +201,29 @@ interface TypeRefWithNullability : TypeRef {
fun copy(nullable: Boolean): TypeRefWithNullability
}
interface ParametrizedTypeRef<Self, P : TypeParameterRef> : TypeRef {
interface ParametrizedTypeRef<Self : ParametrizedTypeRef<Self, P>, P : TypeParameterRef> : TypeRef {
val args: Map<P, TypeRef>
fun copy(args: Map<P, TypeRef>): Self
override fun substitute(map: TypeParameterSubstitutionMap): Self =
copy(args.mapValues { it.value.substitute(map) })
override fun getTypeWithArguments(notNull: Boolean): String = type + generics + (if (nullable) "?" else "")
}
typealias TypeParameterSubstitutionMap = Map<out TypeParameterRef, TypeRef>
val ParametrizedTypeRef<*, *>.generics: String
get() = if (args.isEmpty()) "" else args.values.joinToString(prefix = "<", postfix = ">") { it.typeWithArguments }
fun <T> ParametrizedTypeRef<T, NamedTypeParameterRef>.withArgs(vararg args: Pair<String, TypeRef>) =
copy(args.associate { (k, v) -> NamedTypeParameterRef(k) to v })
fun <Self : ParametrizedTypeRef<Self, NamedTypeParameterRef>> ParametrizedTypeRef<Self, NamedTypeParameterRef>.withArgs(
vararg args: Pair<String, TypeRef>
) = copy(args.associate { (k, v) -> NamedTypeParameterRef(k) to v })
fun <T> ParametrizedTypeRef<T, PositionTypeParameterRef>.withArgs(vararg args: TypeRef) =
copy(args.withIndex().associate { (i, t) -> PositionTypeParameterRef(i) to t })
fun <Self : ParametrizedTypeRef<Self, PositionTypeParameterRef>> ParametrizedTypeRef<Self, PositionTypeParameterRef>.withArgs(
vararg args: TypeRef
) = copy(args.withIndex().associate { (i, t) -> PositionTypeParameterRef(i) to t })
class TypeVariable(
@@ -211,3 +263,6 @@ fun ClassOrElementRef.inheritanceClauseParenthesis(): String = when (this) {
TypeKind.Interface -> ""
}
}
val TypeRef.nullable: Boolean
get() = (this as? TypeRefWithNullability)?.nullable ?: false