[IR generator] Better support for fields' default value in base classes
- Allows using those with the incoming IR implementation printer. - Moves the logic to common tree generator, so other trees can specify default values in base classes as well, if needed. ^KT-65773 In Progress
This commit is contained in:
committed by
Space Team
parent
288351d733
commit
4d9d1974ec
@@ -11,6 +11,7 @@ package org.jetbrains.kotlin.ir.declarations
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrSetValue
|
||||
import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
@@ -32,6 +33,14 @@ abstract class IrVariable : IrDeclarationBase(), IrValueDeclaration {
|
||||
|
||||
abstract var initializer: IrExpression?
|
||||
|
||||
/**
|
||||
* Variables are assignable by default. This means that they can be used in [IrSetValue].
|
||||
* Variables are assigned in the IR even though they are not 'var' in the input. Hence
|
||||
* the separate assignability flag.
|
||||
*/
|
||||
override val isAssignable: Boolean
|
||||
get() = true
|
||||
|
||||
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
|
||||
visitor.visitVariable(this, data)
|
||||
|
||||
|
||||
@@ -53,12 +53,6 @@ class IrVariableImpl(
|
||||
|
||||
override var initializer: IrExpression? = null
|
||||
|
||||
// Variables are assignable by default. This means that they can be used in IrSetValue.
|
||||
// Variables are assigned in the IR even though they are not 'var' in the input. Hence
|
||||
// the separate assignability flag.
|
||||
override val isAssignable: Boolean
|
||||
get() = true
|
||||
|
||||
override val factory: IrFactory
|
||||
get() = error("Create IrVariableImpl directly")
|
||||
}
|
||||
|
||||
@@ -587,6 +587,16 @@ object IrTree : AbstractTreeBuilder() {
|
||||
+field("isConst", boolean)
|
||||
+field("isLateinit", boolean)
|
||||
+field("initializer", expression, nullable = true)
|
||||
+field("isAssignable", boolean, mutable = false) {
|
||||
defaultValueInBase = "true"
|
||||
withGetter = true
|
||||
additionalImports.add(setValue)
|
||||
kDoc = """
|
||||
Variables are assignable by default. This means that they can be used in [${setValue.typeName}].
|
||||
Variables are assigned in the IR even though they are not 'var' in the input. Hence
|
||||
the separate assignability flag.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
val packageFragment: Element by element(Declaration) {
|
||||
ownsChildren = false
|
||||
@@ -608,8 +618,9 @@ object IrTree : AbstractTreeBuilder() {
|
||||
}
|
||||
+field("packageFqName", type<FqName>())
|
||||
+field("fqName", type<FqName>()) {
|
||||
baseGetter = "packageFqName"
|
||||
defaultValueInBase = "packageFqName"
|
||||
customSetter = "packageFqName = value"
|
||||
withGetter = true
|
||||
deprecation = Deprecated(
|
||||
"Please use `packageFqName` instead",
|
||||
ReplaceWith("packageFqName"),
|
||||
|
||||
+9
-11
@@ -12,8 +12,6 @@ sealed class Field(
|
||||
override val name: String,
|
||||
override var isMutable: Boolean,
|
||||
) : AbstractField<Field>(), AbstractFieldWithDefaultValue<Field> {
|
||||
var baseGetter: String? = null
|
||||
|
||||
sealed class UseFieldAsParameterInIrFactoryStrategy {
|
||||
|
||||
data object No : UseFieldAsParameterInIrFactoryStrategy()
|
||||
@@ -31,28 +29,26 @@ sealed class Field(
|
||||
UseFieldAsParameterInIrFactoryStrategy.Yes(null)
|
||||
}
|
||||
|
||||
override var withGetter: Boolean
|
||||
get() = baseGetter != null
|
||||
set(value) = error("Operation not supported")
|
||||
|
||||
override var defaultValueInImplementation: String? by ::baseGetter
|
||||
override var withGetter: Boolean = false
|
||||
|
||||
override var defaultValueInBase: String? = null
|
||||
override var defaultValueInImplementation: String? = null
|
||||
override var defaultValueInBuilder: String?
|
||||
get() = null
|
||||
set(_) = error("Builders are not supported")
|
||||
|
||||
override var customSetter: String? = null
|
||||
|
||||
override val origin: Field
|
||||
get() = this
|
||||
|
||||
override var customSetter: String? = null
|
||||
|
||||
override fun toString() = "$name: $typeRef"
|
||||
|
||||
override val isVolatile: Boolean
|
||||
get() = false
|
||||
|
||||
override val isFinal: Boolean
|
||||
get() = baseGetter != null
|
||||
override var isFinal: Boolean = false
|
||||
|
||||
override val isParameter: Boolean
|
||||
get() = false
|
||||
@@ -61,7 +57,9 @@ sealed class Field(
|
||||
|
||||
override fun updateFieldsInCopy(copy: Field) {
|
||||
super.updateFieldsInCopy(copy)
|
||||
copy.baseGetter = baseGetter
|
||||
copy.withGetter = withGetter
|
||||
copy.defaultValueInBase = defaultValueInBase
|
||||
copy.defaultValueInImplementation = defaultValueInImplementation
|
||||
copy.customUseInIrFactoryStrategy = customUseInIrFactoryStrategy
|
||||
copy.customSetter = customSetter
|
||||
}
|
||||
|
||||
+3
-2
@@ -52,14 +52,15 @@ abstract class AbstractElementPrinter<Element : AbstractElement<Element, Field,
|
||||
withIndent {
|
||||
for (field in filterFields(element)) {
|
||||
if (field.isParameter) continue
|
||||
if (!field.withGetter && field.defaultValueInImplementation == null && field.isFinal && field.fromParent) {
|
||||
if (!field.withGetter && field.defaultValueInImplementation == null && field.defaultValueInBase == null && field.isFinal && field.fromParent) {
|
||||
continue
|
||||
}
|
||||
if (separateFieldsWithBlankLine) println()
|
||||
fieldPrinter.printField(
|
||||
field,
|
||||
inImplementation = false,
|
||||
override = field.fromParent,
|
||||
modality = Modality.ABSTRACT.takeIf { !field.isFinal && !kind.isInterface },
|
||||
modality = Modality.ABSTRACT.takeIf { !field.isFinal && !kind.isInterface && field.defaultValueInBase == null },
|
||||
)
|
||||
}
|
||||
printAdditionalMethods(element)
|
||||
|
||||
+1
@@ -49,6 +49,7 @@ abstract class AbstractField<Field : AbstractField<Field>> {
|
||||
open val containsElement: Boolean
|
||||
get() = typeRef is ElementOrRef<*> || this is ListField && baseType is ElementOrRef<*>
|
||||
|
||||
open val defaultValueInBase: String? get() = null
|
||||
open val defaultValueInImplementation: String? get() = null
|
||||
|
||||
/**
|
||||
|
||||
+5
-4
@@ -8,8 +8,8 @@ package org.jetbrains.kotlin.generators.tree
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.generators.tree.printer.VariableKind
|
||||
import org.jetbrains.kotlin.generators.tree.printer.printBlock
|
||||
import org.jetbrains.kotlin.generators.tree.printer.printKDoc
|
||||
import org.jetbrains.kotlin.generators.tree.printer.printPropertyDeclaration
|
||||
import org.jetbrains.kotlin.generators.tree.printer.printKDoc
|
||||
import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly
|
||||
import org.jetbrains.kotlin.utils.SmartPrinter
|
||||
import org.jetbrains.kotlin.utils.withIndent
|
||||
@@ -33,12 +33,13 @@ abstract class AbstractFieldPrinter<Field : AbstractField<*>>(
|
||||
context(ImportCollector)
|
||||
fun printField(
|
||||
field: Field,
|
||||
inImplementation: Boolean,
|
||||
override: Boolean,
|
||||
inConstructor: Boolean = false,
|
||||
modality: Modality? = null,
|
||||
) {
|
||||
printer.run {
|
||||
val defaultValue = field.defaultValueInImplementation
|
||||
val defaultValue = if (inImplementation) field.defaultValueInImplementation else field.defaultValueInBase
|
||||
printPropertyDeclaration(
|
||||
name = field.name,
|
||||
type = actualTypeOfField(field),
|
||||
@@ -47,8 +48,8 @@ abstract class AbstractFieldPrinter<Field : AbstractField<*>>(
|
||||
visibility = field.visibility,
|
||||
modality = modality,
|
||||
override = override,
|
||||
isLateinit = field.isLateinit,
|
||||
isVolatile = field.isVolatile,
|
||||
isLateinit = (inImplementation || field.isFinal) && field.isLateinit,
|
||||
isVolatile = (inImplementation || field.isFinal) && field.isVolatile,
|
||||
optInAnnotation = field.optInAnnotation,
|
||||
printOptInWrapped = defaultValue != null,
|
||||
deprecation = field.deprecation,
|
||||
|
||||
+3
-2
@@ -68,11 +68,12 @@ abstract class AbstractImplementation<Implementation, Element, Field>(
|
||||
return allFields.firstOrNull { it.name == fieldName }
|
||||
}
|
||||
|
||||
private fun withDefault(field: Field) = !field.isFinal && (field.defaultValueInImplementation != null || field.isLateinit)
|
||||
private fun withDefault(field: Field) =
|
||||
!field.isFinal && (field.defaultValueInImplementation != null || field.defaultValueInBase != null || field.isLateinit)
|
||||
|
||||
val fieldsInConstructor by lazy { allFields.filterNot(::withDefault) }
|
||||
|
||||
val fieldsInBody by lazy { allFields.filter(::withDefault) }
|
||||
val fieldsInBody by lazy { allFields.filter(::withDefault).filter { it.defaultValueInBase == null } }
|
||||
|
||||
var requiresOptIn = false
|
||||
|
||||
|
||||
+14
-4
@@ -28,7 +28,8 @@ abstract class AbstractImplementationPrinter<Implementation, Element, Implementa
|
||||
protected abstract fun makeFieldPrinter(printer: SmartPrinter): AbstractFieldPrinter<ImplementationField>
|
||||
|
||||
context(ImportCollector)
|
||||
protected open fun SmartPrinter.printAdditionalMethods(implementation: Implementation) {}
|
||||
protected open fun SmartPrinter.printAdditionalMethods(implementation: Implementation) {
|
||||
}
|
||||
|
||||
context(ImportCollector)
|
||||
fun printImplementation(implementation: Implementation) {
|
||||
@@ -72,7 +73,7 @@ abstract class AbstractImplementationPrinter<Implementation, Element, Implementa
|
||||
print(field.name, ": ", field.typeRef.render())
|
||||
println(",")
|
||||
} else if (!field.isFinal) {
|
||||
fieldPrinter.printField(field, override = true, inConstructor = true)
|
||||
fieldPrinter.printField(field, inImplementation = true, override = true, inConstructor = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,11 +88,20 @@ abstract class AbstractImplementationPrinter<Implementation, Element, Implementa
|
||||
printBlock {
|
||||
if (isInterface || isAbstract) {
|
||||
implementation.allFields.forEach {
|
||||
fieldPrinter.printField(it, override = true, modality = Modality.ABSTRACT.takeIf { isAbstract })
|
||||
fieldPrinter.printField(
|
||||
it,
|
||||
inImplementation = true,
|
||||
override = true,
|
||||
modality = Modality.ABSTRACT.takeIf { isAbstract }
|
||||
)
|
||||
}
|
||||
} else {
|
||||
implementation.fieldsInBody.forEach {
|
||||
fieldPrinter.printField(it, override = true)
|
||||
fieldPrinter.printField(
|
||||
it,
|
||||
inImplementation = true,
|
||||
override = true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user