[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.descriptors.VariableDescriptor
|
||||||
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
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.symbols.IrVariableSymbol
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||||
@@ -32,6 +33,14 @@ abstract class IrVariable : IrDeclarationBase(), IrValueDeclaration {
|
|||||||
|
|
||||||
abstract var initializer: IrExpression?
|
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 =
|
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
|
||||||
visitor.visitVariable(this, data)
|
visitor.visitVariable(this, data)
|
||||||
|
|
||||||
|
|||||||
@@ -53,12 +53,6 @@ class IrVariableImpl(
|
|||||||
|
|
||||||
override var initializer: IrExpression? = null
|
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
|
override val factory: IrFactory
|
||||||
get() = error("Create IrVariableImpl directly")
|
get() = error("Create IrVariableImpl directly")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -587,6 +587,16 @@ object IrTree : AbstractTreeBuilder() {
|
|||||||
+field("isConst", boolean)
|
+field("isConst", boolean)
|
||||||
+field("isLateinit", boolean)
|
+field("isLateinit", boolean)
|
||||||
+field("initializer", expression, nullable = true)
|
+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) {
|
val packageFragment: Element by element(Declaration) {
|
||||||
ownsChildren = false
|
ownsChildren = false
|
||||||
@@ -608,8 +618,9 @@ object IrTree : AbstractTreeBuilder() {
|
|||||||
}
|
}
|
||||||
+field("packageFqName", type<FqName>())
|
+field("packageFqName", type<FqName>())
|
||||||
+field("fqName", type<FqName>()) {
|
+field("fqName", type<FqName>()) {
|
||||||
baseGetter = "packageFqName"
|
defaultValueInBase = "packageFqName"
|
||||||
customSetter = "packageFqName = value"
|
customSetter = "packageFqName = value"
|
||||||
|
withGetter = true
|
||||||
deprecation = Deprecated(
|
deprecation = Deprecated(
|
||||||
"Please use `packageFqName` instead",
|
"Please use `packageFqName` instead",
|
||||||
ReplaceWith("packageFqName"),
|
ReplaceWith("packageFqName"),
|
||||||
|
|||||||
+9
-11
@@ -12,8 +12,6 @@ sealed class Field(
|
|||||||
override val name: String,
|
override val name: String,
|
||||||
override var isMutable: Boolean,
|
override var isMutable: Boolean,
|
||||||
) : AbstractField<Field>(), AbstractFieldWithDefaultValue<Field> {
|
) : AbstractField<Field>(), AbstractFieldWithDefaultValue<Field> {
|
||||||
var baseGetter: String? = null
|
|
||||||
|
|
||||||
sealed class UseFieldAsParameterInIrFactoryStrategy {
|
sealed class UseFieldAsParameterInIrFactoryStrategy {
|
||||||
|
|
||||||
data object No : UseFieldAsParameterInIrFactoryStrategy()
|
data object No : UseFieldAsParameterInIrFactoryStrategy()
|
||||||
@@ -31,28 +29,26 @@ sealed class Field(
|
|||||||
UseFieldAsParameterInIrFactoryStrategy.Yes(null)
|
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?
|
override var defaultValueInBuilder: String?
|
||||||
get() = null
|
get() = null
|
||||||
set(_) = error("Builders are not supported")
|
set(_) = error("Builders are not supported")
|
||||||
|
|
||||||
|
override var customSetter: String? = null
|
||||||
|
|
||||||
override val origin: Field
|
override val origin: Field
|
||||||
get() = this
|
get() = this
|
||||||
|
|
||||||
override var customSetter: String? = null
|
|
||||||
|
|
||||||
override fun toString() = "$name: $typeRef"
|
override fun toString() = "$name: $typeRef"
|
||||||
|
|
||||||
override val isVolatile: Boolean
|
override val isVolatile: Boolean
|
||||||
get() = false
|
get() = false
|
||||||
|
|
||||||
override val isFinal: Boolean
|
override var isFinal: Boolean = false
|
||||||
get() = baseGetter != null
|
|
||||||
|
|
||||||
override val isParameter: Boolean
|
override val isParameter: Boolean
|
||||||
get() = false
|
get() = false
|
||||||
@@ -61,7 +57,9 @@ sealed class Field(
|
|||||||
|
|
||||||
override fun updateFieldsInCopy(copy: Field) {
|
override fun updateFieldsInCopy(copy: Field) {
|
||||||
super.updateFieldsInCopy(copy)
|
super.updateFieldsInCopy(copy)
|
||||||
copy.baseGetter = baseGetter
|
copy.withGetter = withGetter
|
||||||
|
copy.defaultValueInBase = defaultValueInBase
|
||||||
|
copy.defaultValueInImplementation = defaultValueInImplementation
|
||||||
copy.customUseInIrFactoryStrategy = customUseInIrFactoryStrategy
|
copy.customUseInIrFactoryStrategy = customUseInIrFactoryStrategy
|
||||||
copy.customSetter = customSetter
|
copy.customSetter = customSetter
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-2
@@ -52,14 +52,15 @@ abstract class AbstractElementPrinter<Element : AbstractElement<Element, Field,
|
|||||||
withIndent {
|
withIndent {
|
||||||
for (field in filterFields(element)) {
|
for (field in filterFields(element)) {
|
||||||
if (field.isParameter) continue
|
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
|
continue
|
||||||
}
|
}
|
||||||
if (separateFieldsWithBlankLine) println()
|
if (separateFieldsWithBlankLine) println()
|
||||||
fieldPrinter.printField(
|
fieldPrinter.printField(
|
||||||
field,
|
field,
|
||||||
|
inImplementation = false,
|
||||||
override = field.fromParent,
|
override = field.fromParent,
|
||||||
modality = Modality.ABSTRACT.takeIf { !field.isFinal && !kind.isInterface },
|
modality = Modality.ABSTRACT.takeIf { !field.isFinal && !kind.isInterface && field.defaultValueInBase == null },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
printAdditionalMethods(element)
|
printAdditionalMethods(element)
|
||||||
|
|||||||
+1
@@ -49,6 +49,7 @@ abstract class AbstractField<Field : AbstractField<Field>> {
|
|||||||
open val containsElement: Boolean
|
open val containsElement: Boolean
|
||||||
get() = typeRef is ElementOrRef<*> || this is ListField && baseType is ElementOrRef<*>
|
get() = typeRef is ElementOrRef<*> || this is ListField && baseType is ElementOrRef<*>
|
||||||
|
|
||||||
|
open val defaultValueInBase: String? get() = null
|
||||||
open val defaultValueInImplementation: 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.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.generators.tree.printer.VariableKind
|
import org.jetbrains.kotlin.generators.tree.printer.VariableKind
|
||||||
import org.jetbrains.kotlin.generators.tree.printer.printBlock
|
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.printPropertyDeclaration
|
||||||
|
import org.jetbrains.kotlin.generators.tree.printer.printKDoc
|
||||||
import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly
|
import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly
|
||||||
import org.jetbrains.kotlin.utils.SmartPrinter
|
import org.jetbrains.kotlin.utils.SmartPrinter
|
||||||
import org.jetbrains.kotlin.utils.withIndent
|
import org.jetbrains.kotlin.utils.withIndent
|
||||||
@@ -33,12 +33,13 @@ abstract class AbstractFieldPrinter<Field : AbstractField<*>>(
|
|||||||
context(ImportCollector)
|
context(ImportCollector)
|
||||||
fun printField(
|
fun printField(
|
||||||
field: Field,
|
field: Field,
|
||||||
|
inImplementation: Boolean,
|
||||||
override: Boolean,
|
override: Boolean,
|
||||||
inConstructor: Boolean = false,
|
inConstructor: Boolean = false,
|
||||||
modality: Modality? = null,
|
modality: Modality? = null,
|
||||||
) {
|
) {
|
||||||
printer.run {
|
printer.run {
|
||||||
val defaultValue = field.defaultValueInImplementation
|
val defaultValue = if (inImplementation) field.defaultValueInImplementation else field.defaultValueInBase
|
||||||
printPropertyDeclaration(
|
printPropertyDeclaration(
|
||||||
name = field.name,
|
name = field.name,
|
||||||
type = actualTypeOfField(field),
|
type = actualTypeOfField(field),
|
||||||
@@ -47,8 +48,8 @@ abstract class AbstractFieldPrinter<Field : AbstractField<*>>(
|
|||||||
visibility = field.visibility,
|
visibility = field.visibility,
|
||||||
modality = modality,
|
modality = modality,
|
||||||
override = override,
|
override = override,
|
||||||
isLateinit = field.isLateinit,
|
isLateinit = (inImplementation || field.isFinal) && field.isLateinit,
|
||||||
isVolatile = field.isVolatile,
|
isVolatile = (inImplementation || field.isFinal) && field.isVolatile,
|
||||||
optInAnnotation = field.optInAnnotation,
|
optInAnnotation = field.optInAnnotation,
|
||||||
printOptInWrapped = defaultValue != null,
|
printOptInWrapped = defaultValue != null,
|
||||||
deprecation = field.deprecation,
|
deprecation = field.deprecation,
|
||||||
|
|||||||
+3
-2
@@ -68,11 +68,12 @@ abstract class AbstractImplementation<Implementation, Element, Field>(
|
|||||||
return allFields.firstOrNull { it.name == fieldName }
|
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 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
|
var requiresOptIn = false
|
||||||
|
|
||||||
|
|||||||
+14
-4
@@ -28,7 +28,8 @@ abstract class AbstractImplementationPrinter<Implementation, Element, Implementa
|
|||||||
protected abstract fun makeFieldPrinter(printer: SmartPrinter): AbstractFieldPrinter<ImplementationField>
|
protected abstract fun makeFieldPrinter(printer: SmartPrinter): AbstractFieldPrinter<ImplementationField>
|
||||||
|
|
||||||
context(ImportCollector)
|
context(ImportCollector)
|
||||||
protected open fun SmartPrinter.printAdditionalMethods(implementation: Implementation) {}
|
protected open fun SmartPrinter.printAdditionalMethods(implementation: Implementation) {
|
||||||
|
}
|
||||||
|
|
||||||
context(ImportCollector)
|
context(ImportCollector)
|
||||||
fun printImplementation(implementation: Implementation) {
|
fun printImplementation(implementation: Implementation) {
|
||||||
@@ -72,7 +73,7 @@ abstract class AbstractImplementationPrinter<Implementation, Element, Implementa
|
|||||||
print(field.name, ": ", field.typeRef.render())
|
print(field.name, ": ", field.typeRef.render())
|
||||||
println(",")
|
println(",")
|
||||||
} else if (!field.isFinal) {
|
} 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 {
|
printBlock {
|
||||||
if (isInterface || isAbstract) {
|
if (isInterface || isAbstract) {
|
||||||
implementation.allFields.forEach {
|
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 {
|
} else {
|
||||||
implementation.fieldsInBody.forEach {
|
implementation.fieldsInBody.forEach {
|
||||||
fieldPrinter.printField(it, override = true)
|
fieldPrinter.printField(
|
||||||
|
it,
|
||||||
|
inImplementation = true,
|
||||||
|
override = true
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user