IR: more consolidation of synthetic member generation for data class.
This commit is contained in:
committed by
Dmitriy Novozhilov
parent
7f02d57d88
commit
9f1ecadd65
+18
-5
@@ -120,11 +120,24 @@ internal class ClassMemberGenerator(
|
||||
irFunction.body = body
|
||||
}
|
||||
} else if (irFunction !is IrConstructor) {
|
||||
if (irFunction.origin == IrDeclarationOrigin.ENUM_CLASS_SPECIAL_MEMBER) {
|
||||
val kind = Fir2IrDeclarationStorage.ENUM_SYNTHETIC_NAMES.getValue(irFunction.name)
|
||||
irFunction.body = IrSyntheticBodyImpl(startOffset, endOffset, kind)
|
||||
} else {
|
||||
irFunction.body = firFunction?.body?.let { visitor.convertToIrBlockBody(it) }
|
||||
when {
|
||||
irFunction.origin == IrDeclarationOrigin.ENUM_CLASS_SPECIAL_MEMBER -> {
|
||||
val kind = Fir2IrDeclarationStorage.ENUM_SYNTHETIC_NAMES.getValue(irFunction.name)
|
||||
irFunction.body = IrSyntheticBodyImpl(startOffset, endOffset, kind)
|
||||
}
|
||||
irFunction.parent is IrClass && irFunction.parentAsClass.isData -> {
|
||||
when {
|
||||
DataClassMembersGenerator.isComponentN(irFunction) ->
|
||||
DataClassMembersGenerator(components).generateDataClassComponentBody(irFunction)
|
||||
DataClassMembersGenerator.isCopy(irFunction) ->
|
||||
DataClassMembersGenerator(components).generateDataClassCopyBody(irFunction)
|
||||
else ->
|
||||
irFunction.body = firFunction?.body?.let { visitor.convertToIrBlockBody(it) }
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
irFunction.body = firFunction?.body?.let { visitor.convertToIrBlockBody(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
if (irFunction !is IrConstructor || !irFunction.isPrimary) {
|
||||
|
||||
+64
-12
@@ -5,10 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.backend.generators
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.fir.backend.Fir2IrComponents
|
||||
import org.jetbrains.kotlin.fir.backend.declareThisReceiverParameter
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
@@ -20,8 +17,8 @@ import org.jetbrains.kotlin.ir.descriptors.WrappedSimpleFunctionDescriptor
|
||||
import org.jetbrains.kotlin.ir.descriptors.WrappedValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.util.DataClassMembersGenerator
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
class DataClassMembersGenerator(val components: Fir2IrComponents) {
|
||||
@@ -31,6 +28,15 @@ class DataClassMembersGenerator(val components: Fir2IrComponents) {
|
||||
fun generateDataClassMembers(irClass: IrClass): List<Name> =
|
||||
MyDataClassMethodsGenerator(irClass, IrDeclarationOrigin.GENERATED_DATA_CLASS_MEMBER).generate()
|
||||
|
||||
fun generateDataClassComponentBody(irFunction: IrFunction) =
|
||||
MyDataClassMethodsGenerator(irFunction.parentAsClass, IrDeclarationOrigin.GENERATED_DATA_CLASS_MEMBER)
|
||||
.generateComponentBody(irFunction)
|
||||
|
||||
fun generateDataClassCopyBody(irFunction: IrFunction) =
|
||||
MyDataClassMethodsGenerator(irFunction.parentAsClass, IrDeclarationOrigin.GENERATED_DATA_CLASS_MEMBER)
|
||||
.generateCopyBody(irFunction)
|
||||
|
||||
|
||||
private inner class MyDataClassMethodsGenerator(
|
||||
val irClass: IrClass,
|
||||
val origin: IrDeclarationOrigin
|
||||
@@ -51,6 +57,18 @@ class DataClassMembersGenerator(val components: Fir2IrComponents) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
override fun getBackingField(parameter: ValueParameterDescriptor?, irValueParameter: IrValueParameter?): IrField? =
|
||||
irValueParameter?.let {
|
||||
irClass.properties.single { irProperty ->
|
||||
irProperty.name == irValueParameter.name && irProperty.backingField?.type == irValueParameter.type
|
||||
}.backingField
|
||||
}
|
||||
|
||||
override fun transform(typeParameterDescriptor: TypeParameterDescriptor): IrType {
|
||||
// TODO
|
||||
return components.irBuiltIns.anyType
|
||||
}
|
||||
|
||||
override fun commitSubstituted(irMemberAccessExpression: IrMemberAccessExpression, descriptor: CallableDescriptor) {
|
||||
// TODO
|
||||
}
|
||||
@@ -72,34 +90,46 @@ class DataClassMembersGenerator(val components: Fir2IrComponents) {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
// TODO: consolidate componentN() and copy(...) too?
|
||||
|
||||
// TODO: generate equals, hashCode, and toString only if needed
|
||||
val equalsFunction = createSyntheticIrFunction(
|
||||
Name.identifier("equals"),
|
||||
components.irBuiltIns.booleanType,
|
||||
components.irBuiltIns.booleanType
|
||||
).apply {
|
||||
valueParameters = listOf(
|
||||
createSyntheticIrParameter(this, Name.identifier("other"), components.irBuiltIns.anyNType)
|
||||
)
|
||||
}
|
||||
irDataClassMembersGenerator.generateEqualsMethod(equalsFunction, properties)
|
||||
irClass.declarations.add(equalsFunction)
|
||||
|
||||
val hashCodeFunction = createSyntheticIrFunction(
|
||||
Name.identifier("hashCode"),
|
||||
components.irBuiltIns.intType,
|
||||
components.irBuiltIns.intType
|
||||
)
|
||||
irDataClassMembersGenerator.generateHashCodeMethod(hashCodeFunction, properties)
|
||||
irClass.declarations.add(hashCodeFunction)
|
||||
|
||||
val toStringFunction = createSyntheticIrFunction(
|
||||
Name.identifier("toString"),
|
||||
components.irBuiltIns.stringType,
|
||||
components.irBuiltIns.stringType
|
||||
)
|
||||
irDataClassMembersGenerator.generateToStringMethod(toStringFunction, properties)
|
||||
irClass.declarations.add(toStringFunction)
|
||||
|
||||
return listOf(equalsFunction.name, hashCodeFunction.name, toStringFunction.name)
|
||||
}
|
||||
|
||||
fun generateComponentBody(irFunction: IrFunction) {
|
||||
val index = getComponentIndex(irFunction)!!
|
||||
val valueParameter = irClass.primaryConstructor!!.valueParameters[index - 1]
|
||||
val backingField = irDataClassMembersGenerator.getBackingField(null, valueParameter)!!
|
||||
irDataClassMembersGenerator
|
||||
.generateComponentFunction(irFunction, backingField, valueParameter.startOffset, valueParameter.endOffset)
|
||||
}
|
||||
|
||||
fun generateCopyBody(irFunction: IrFunction) =
|
||||
irDataClassMembersGenerator.generateCopyFunction(irFunction, irClass.primaryConstructor!!.symbol)
|
||||
|
||||
private fun createSyntheticIrFunction(name: Name, returnType: IrType): IrFunction {
|
||||
val functionDescriptor = WrappedSimpleFunctionDescriptor()
|
||||
val thisReceiverDescriptor = WrappedValueParameterDescriptor()
|
||||
@@ -130,7 +160,7 @@ class DataClassMembersGenerator(val components: Fir2IrComponents) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun createSyntheticIrParameter(irFunction: IrFunction, name: Name, type: IrType): IrValueParameter {
|
||||
private fun createSyntheticIrParameter(irFunction: IrFunction, name: Name, type: IrType, index: Int = 0): IrValueParameter {
|
||||
val descriptor = WrappedValueParameterDescriptor()
|
||||
return components.symbolTable.declareValueParameter(
|
||||
UNDEFINED_OFFSET,
|
||||
@@ -145,7 +175,7 @@ class DataClassMembersGenerator(val components: Fir2IrComponents) {
|
||||
origin,
|
||||
symbol,
|
||||
name,
|
||||
0,
|
||||
index,
|
||||
type,
|
||||
null,
|
||||
isCrossinline = false,
|
||||
@@ -157,4 +187,26 @@ class DataClassMembersGenerator(val components: Fir2IrComponents) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val copyName = Name.identifier("copy")
|
||||
|
||||
fun isCopy(irFunction: IrFunction): Boolean =
|
||||
irFunction.name == copyName
|
||||
|
||||
fun isComponentN(irFunction: IrFunction): Boolean {
|
||||
if (irFunction.name.isSpecial) {
|
||||
return false
|
||||
}
|
||||
val name = irFunction.name.identifier
|
||||
if (!name.startsWith("component")) {
|
||||
return false
|
||||
}
|
||||
val n = getComponentIndex(irFunction)
|
||||
return n != null && n > 0
|
||||
}
|
||||
|
||||
fun getComponentIndex(irFunction: IrFunction): Int? =
|
||||
irFunction.name.identifier.substring("component".length).toIntOrNull()
|
||||
}
|
||||
}
|
||||
+3
-33
@@ -17,13 +17,11 @@ import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
|
||||
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.expressions.builder.*
|
||||
import org.jetbrains.kotlin.fir.expressions.impl.buildSingleExpressionBlock
|
||||
import org.jetbrains.kotlin.fir.references.FirReference
|
||||
import org.jetbrains.kotlin.fir.references.builder.*
|
||||
import org.jetbrains.kotlin.fir.symbols.CallableId
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildImplicitTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
|
||||
@@ -662,6 +660,7 @@ abstract class BaseFirBuilder<T>(val baseSession: FirSession, val context: Conte
|
||||
private fun generateComponentAccess(parameterSource: FirSourceElement?, firProperty: FirProperty) =
|
||||
buildQualifiedAccessExpression {
|
||||
source = parameterSource
|
||||
typeRef = firProperty.returnTypeRef
|
||||
dispatchReceiver = buildThisReceiverExpression {
|
||||
calleeReference = buildImplicitThisReference {
|
||||
boundSymbol = classBuilder.symbol
|
||||
@@ -682,7 +681,6 @@ abstract class BaseFirBuilder<T>(val baseSession: FirSession, val context: Conte
|
||||
val name = Name.identifier("component$componentIndex")
|
||||
componentIndex++
|
||||
val parameterSource = sourceNode?.toFirSourceElement()
|
||||
val target = FirFunctionTarget(labelName = null, isLambda = false)
|
||||
val componentFunction = buildSimpleFunction {
|
||||
source = parameterSource
|
||||
session = this@DataClassMembersGenerator.session
|
||||
@@ -692,14 +690,7 @@ abstract class BaseFirBuilder<T>(val baseSession: FirSession, val context: Conte
|
||||
status = FirDeclarationStatusImpl(Visibilities.PUBLIC, Modality.FINAL)
|
||||
symbol = FirNamedFunctionSymbol(CallableId(packageFqName, classFqName, name))
|
||||
|
||||
val returnExpression = buildReturnExpression {
|
||||
source = parameterSource
|
||||
result = generateComponentAccess(parameterSource, firProperty)
|
||||
this.target = target
|
||||
}
|
||||
body = buildSingleExpressionBlock(returnExpression)
|
||||
}.also {
|
||||
target.bind(it)
|
||||
// Refer to FIR backend ClassMemberGenerator for body generation.
|
||||
}
|
||||
classBuilder.addDeclaration(componentFunction)
|
||||
}
|
||||
@@ -708,7 +699,6 @@ abstract class BaseFirBuilder<T>(val baseSession: FirSession, val context: Conte
|
||||
private val copyName = Name.identifier("copy")
|
||||
|
||||
private fun generateCopyFunction() {
|
||||
val target = FirFunctionTarget(labelName = null, isLambda = false)
|
||||
classBuilder.addDeclaration(
|
||||
buildSimpleFunction {
|
||||
source = this@DataClassMembersGenerator.source.toFirSourceElement()
|
||||
@@ -732,27 +722,7 @@ abstract class BaseFirBuilder<T>(val baseSession: FirSession, val context: Conte
|
||||
isVararg = false
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Handle generic types.
|
||||
val initCallExpression = buildFunctionCall {
|
||||
argumentList = buildArgumentList {
|
||||
for ((ktParameter, firProperty) in zippedParameters) {
|
||||
val parameterSource = ktParameter?.toFirSourceElement()
|
||||
arguments += generateComponentAccess(parameterSource, firProperty)
|
||||
}
|
||||
}
|
||||
calleeReference = buildResolvedNamedReference {
|
||||
name = primaryConstructor.symbol.callableId.callableName
|
||||
resolvedSymbol = primaryConstructor.symbol
|
||||
}
|
||||
}
|
||||
val returnExpression = buildReturnExpression {
|
||||
result = initCallExpression
|
||||
this.target = target
|
||||
}
|
||||
body = buildSingleExpressionBlock(returnExpression)
|
||||
}.also {
|
||||
target.bind(it)
|
||||
// Refer to FIR backend ClassMemberGenerator for body generation.
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -25,9 +25,7 @@ FILE: annotated.kt
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final fun copy(): R|Two| {
|
||||
^copy R|/Two.Two|()
|
||||
}
|
||||
public final fun copy(): R|Two|
|
||||
|
||||
}
|
||||
public? final? fun bar(two: Two): R|kotlin/Unit| {
|
||||
|
||||
+4
-12
@@ -13,21 +13,13 @@ FILE: destructuring.kt
|
||||
public? final? val third: String = R|<local>/third|
|
||||
public? get(): String
|
||||
|
||||
public final fun component1(): Int {
|
||||
^component1 this@R|/Some|.R|/Some.first|
|
||||
}
|
||||
public final fun component1(): Int
|
||||
|
||||
public final fun component2(): Double {
|
||||
^component2 this@R|/Some|.R|/Some.second|
|
||||
}
|
||||
public final fun component2(): Double
|
||||
|
||||
public final fun component3(): String {
|
||||
^component3 this@R|/Some|.R|/Some.third|
|
||||
}
|
||||
public final fun component3(): String
|
||||
|
||||
public final fun copy(first: Int = this@R|/Some|.R|/Some.first|, second: Double = this@R|/Some|.R|/Some.second|, third: String = this@R|/Some|.R|/Some.third|): R|Some| {
|
||||
^copy R|/Some.Some|(this@R|/Some|.R|/Some.first|, this@R|/Some|.R|/Some.second|, this@R|/Some|.R|/Some.third|)
|
||||
}
|
||||
public final fun copy(first: Int = this@R|/Some|.R|/Some.first|, second: Double = this@R|/Some|.R|/Some.second|, third: String = this@R|/Some|.R|/Some.third|): R|Some|
|
||||
|
||||
}
|
||||
public? final? fun foo(some: Some): R|kotlin/Unit| {
|
||||
|
||||
@@ -48,17 +48,11 @@ FILE: for.kt
|
||||
public? final? val y: Int = R|<local>/y|
|
||||
public? get(): Int
|
||||
|
||||
public final fun component1(): Int {
|
||||
^component1 this@R|/Some|.R|/Some.x|
|
||||
}
|
||||
public final fun component1(): Int
|
||||
|
||||
public final fun component2(): Int {
|
||||
^component2 this@R|/Some|.R|/Some.y|
|
||||
}
|
||||
public final fun component2(): Int
|
||||
|
||||
public final fun copy(x: Int = this@R|/Some|.R|/Some.x|, y: Int = this@R|/Some|.R|/Some.y|): R|Some| {
|
||||
^copy R|/Some.Some|(this@R|/Some|.R|/Some.x|, this@R|/Some|.R|/Some.y|)
|
||||
}
|
||||
public final fun copy(x: Int = this@R|/Some|.R|/Some.x|, y: Int = this@R|/Some|.R|/Some.y|): R|Some|
|
||||
|
||||
}
|
||||
public? final? fun baz(set: Set<Some>): R|kotlin/Unit| {
|
||||
|
||||
@@ -10,17 +10,11 @@ FILE: lambda.kt
|
||||
public? final? val y: Int = R|<local>/y|
|
||||
public? get(): Int
|
||||
|
||||
public final fun component1(): Int {
|
||||
^component1 this@R|/Tuple|.R|/Tuple.x|
|
||||
}
|
||||
public final fun component1(): Int
|
||||
|
||||
public final fun component2(): Int {
|
||||
^component2 this@R|/Tuple|.R|/Tuple.y|
|
||||
}
|
||||
public final fun component2(): Int
|
||||
|
||||
public final fun copy(x: Int = this@R|/Tuple|.R|/Tuple.x|, y: Int = this@R|/Tuple|.R|/Tuple.y|): R|Tuple| {
|
||||
^copy R|/Tuple.Tuple|(this@R|/Tuple|.R|/Tuple.x|, this@R|/Tuple|.R|/Tuple.y|)
|
||||
}
|
||||
public final fun copy(x: Int = this@R|/Tuple|.R|/Tuple.x|, y: Int = this@R|/Tuple|.R|/Tuple.y|): R|Tuple|
|
||||
|
||||
}
|
||||
public? final? inline fun use(f: ( (Tuple) -> Int )): <implicit> {
|
||||
|
||||
Reference in New Issue
Block a user