KT-4107 Data objects
This commit is contained in:
+2
-5
@@ -14,17 +14,13 @@ import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addFunction
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||
import org.jetbrains.kotlin.ir.types.getClass
|
||||
import org.jetbrains.kotlin.ir.types.isArray
|
||||
import org.jetbrains.kotlin.ir.util.DataClassMembersGenerator
|
||||
import org.jetbrains.kotlin.ir.util.SYNTHETIC_OFFSET
|
||||
import org.jetbrains.kotlin.ir.util.functions
|
||||
import org.jetbrains.kotlin.ir.util.isPrimitiveArray
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
|
||||
class MethodsFromAnyGeneratorForLowerings(val context: BackendContext, val irClass: IrClass, val origin: IrDeclarationOrigin) {
|
||||
private fun IrClass.addSyntheticFunction(name: String, returnType: IrType) =
|
||||
@@ -74,6 +70,7 @@ open class LoweringDataClassMemberGenerator(
|
||||
IrGeneratorContextBase(backendContext.irBuiltIns),
|
||||
backendContext.ir.symbols.externalSymbolTable,
|
||||
irClass,
|
||||
irClass.kotlinFqName,
|
||||
origin,
|
||||
forbidDirectFieldAccess
|
||||
) {
|
||||
|
||||
@@ -353,6 +353,7 @@ private val jvmFilePhases = listOf(
|
||||
|
||||
enumClassPhase,
|
||||
objectClassPhase,
|
||||
readResolveForDataObjectsPhase,
|
||||
staticInitializersPhase,
|
||||
initializersPhase,
|
||||
initializersCleanupPhase,
|
||||
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.jvm.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.ir.addDispatchReceiver
|
||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||
import org.jetbrains.kotlin.ir.builders.irExprBody
|
||||
import org.jetbrains.kotlin.ir.builders.irGetField
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
import org.jetbrains.kotlin.ir.util.fields
|
||||
import org.jetbrains.kotlin.ir.util.getAllSuperclasses
|
||||
import org.jetbrains.kotlin.ir.util.hasEqualFqName
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
internal val readResolveForDataObjectsPhase = makeIrFilePhase(
|
||||
::ReadResolveForDataObjectsLowering,
|
||||
name = "ReadResolveForDataObjectsLowering",
|
||||
description = "Generate readResolve for serializable data objects"
|
||||
)
|
||||
|
||||
private class ReadResolveForDataObjectsLowering(val context: JvmBackendContext) : ClassLoweringPass {
|
||||
override fun lower(irClass: IrClass) {
|
||||
if (!context.state.languageVersionSettings.supportsFeature(LanguageFeature.DataObjects)) return
|
||||
|
||||
if (!irClass.isData || irClass.kind != ClassKind.OBJECT || !irClass.isSerializable()) return
|
||||
|
||||
context.irFactory.buildFun {
|
||||
name = Name.identifier("readResolve")
|
||||
modality = Modality.FINAL
|
||||
origin = IrDeclarationOrigin.GENERATED_DATA_CLASS_MEMBER
|
||||
returnType = context.irBuiltIns.anyType
|
||||
visibility = DescriptorVisibilities.PRIVATE
|
||||
}.apply {
|
||||
addDispatchReceiver { type = irClass.defaultType }
|
||||
parent = irClass
|
||||
body = context.createJvmIrBuilder(symbol).run {
|
||||
val instanceField = irClass.fields.single { it.name.asString() == JvmAbi.INSTANCE_FIELD }
|
||||
irExprBody(irGetField(null, instanceField))
|
||||
}
|
||||
irClass.declarations.add(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val SERIALIZABLE_FQ_NAME = FqName("java.io.Serializable")
|
||||
|
||||
private fun IrClass.isSerializable(): Boolean =
|
||||
getAllSuperclasses().any { it.hasEqualFqName(SERIALIZABLE_FQ_NAME) }
|
||||
+3
-2
@@ -74,8 +74,9 @@ class DataClassMembersGenerator(
|
||||
val origin: IrDeclarationOrigin
|
||||
) : DataClassMethodGenerator(ktClassOrObject, declarationGenerator.context.bindingContext) {
|
||||
|
||||
private val irDataClassMembersGenerator =
|
||||
object : DataClassMembersGenerator(context, context.symbolTable, irClass, origin, generateBodies = generateBodies) {
|
||||
private val irDataClassMembersGenerator = object : DataClassMembersGenerator(
|
||||
context, context.symbolTable, irClass, ktClassOrObject.fqName, origin, generateBodies = generateBodies
|
||||
) {
|
||||
override fun declareSimpleFunction(startOffset: Int, endOffset: Int, functionDescriptor: FunctionDescriptor): IrFunction =
|
||||
declareSimpleFunction(startOffset, endOffset, origin, functionDescriptor)
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrNull
|
||||
import org.jetbrains.kotlin.ir.types.isNullable
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
/**
|
||||
@@ -32,6 +33,7 @@ abstract class DataClassMembersGenerator(
|
||||
val context: IrGeneratorContext,
|
||||
val symbolTable: ReferenceSymbolTable,
|
||||
val irClass: IrClass,
|
||||
val fqName: FqName?,
|
||||
val origin: IrDeclarationOrigin,
|
||||
val forbidDirectFieldAccess: Boolean = false,
|
||||
val generateBodies: Boolean = false
|
||||
@@ -139,9 +141,9 @@ abstract class DataClassMembersGenerator(
|
||||
+irReturnTrue()
|
||||
}
|
||||
|
||||
fun generateHashCodeMethodBody(properties: List<IrProperty>) {
|
||||
fun generateHashCodeMethodBody(properties: List<IrProperty>, constHashCode: Int) {
|
||||
if (properties.isEmpty()) {
|
||||
+irReturn(irInt(0))
|
||||
+irReturn(irInt(constHashCode))
|
||||
return
|
||||
} else if (properties.size == 1) {
|
||||
+irReturn(getHashCodeOfProperty(properties[0]))
|
||||
@@ -186,6 +188,10 @@ abstract class DataClassMembersGenerator(
|
||||
}
|
||||
|
||||
fun generateToStringMethodBody(properties: List<IrProperty>) {
|
||||
if (properties.isEmpty() && irClass.kind == ClassKind.OBJECT) {
|
||||
+irReturn(irString(irClass.name.asString()))
|
||||
return
|
||||
}
|
||||
val irConcat = irConcat()
|
||||
irConcat.addArgument(irString(irClass.classNameForToString() + "("))
|
||||
var first = true
|
||||
@@ -259,6 +265,7 @@ abstract class DataClassMembersGenerator(
|
||||
) {
|
||||
MemberFunctionBuilder(startOffset, endOffset, declareSimpleFunction(startOffset, endOffset, function)).addToClass { irFunction ->
|
||||
irFunction.buildWithScope {
|
||||
irFunction.parent = irClass
|
||||
generateSyntheticFunctionParameterDeclarations(irFunction)
|
||||
body(irFunction)
|
||||
}
|
||||
@@ -344,14 +351,20 @@ abstract class DataClassMembersGenerator(
|
||||
// Entry for psi2ir
|
||||
fun generateHashCodeMethod(function: FunctionDescriptor, properties: List<PropertyDescriptor>) {
|
||||
buildMember(function) {
|
||||
generateHashCodeMethodBody(properties.map { getIrProperty(it) })
|
||||
generateHashCodeMethodBody(
|
||||
properties.map { getIrProperty(it) },
|
||||
if (irClass.kind == ClassKind.OBJECT && irClass.isData) fqName.hashCode() else 0
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Entry for fir2ir
|
||||
fun generateHashCodeMethod(irFunction: IrFunction, properties: List<IrProperty>) {
|
||||
buildMember(irFunction) {
|
||||
generateHashCodeMethodBody(properties)
|
||||
generateHashCodeMethodBody(
|
||||
properties,
|
||||
if (irClass.kind == ClassKind.OBJECT && irClass.isData) fqName.hashCode() else 0
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user