FIR2IR: avoid descriptors computing hashCode
When synthesizing the hashCode function for data classes, descriptors were used, in partcular, memberScope for primitive classes. IrBasedDescriptors have no member scope, so we compute the hashCode function based on IR structures.
This commit is contained in:
+48
-3
@@ -31,11 +31,18 @@ import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
|||||||
import org.jetbrains.kotlin.ir.builders.IrGeneratorContextBase
|
import org.jetbrains.kotlin.ir.builders.IrGeneratorContextBase
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
|
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
|
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
import org.jetbrains.kotlin.ir.types.IrType
|
||||||
|
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||||
|
import org.jetbrains.kotlin.ir.types.classifierOrNull
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.ir.util.DataClassMembersGenerator
|
import org.jetbrains.kotlin.ir.util.DataClassMembersGenerator
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.representativeUpperBound
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A generator that generates synthetic members of data class as well as part of inline class.
|
* A generator that generates synthetic members of data class as well as part of inline class.
|
||||||
@@ -93,8 +100,47 @@ class DataClassMembersGenerator(val components: Fir2IrComponents) {
|
|||||||
return components.irBuiltIns.anyType
|
return components.irBuiltIns.anyType
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun commitSubstituted(irMemberAccessExpression: IrMemberAccessExpression<*>, descriptor: CallableDescriptor) {
|
inner class Fir2IrHashCodeFunctionInfo(override val symbol: IrSimpleFunctionSymbol) : HashCodeFunctionInfo {
|
||||||
// TODO
|
override fun commitSubstituted(irMemberAccessExpression: IrMemberAccessExpression<*>) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getHashCodeFunction(klass: IrClass): IrSimpleFunctionSymbol =
|
||||||
|
klass.functions.singleOrNull {
|
||||||
|
it.name.asString() == "hashCode" && it.valueParameters.isEmpty() && it.extensionReceiverParameter == null
|
||||||
|
}?.symbol
|
||||||
|
?: context.irBuiltIns.anyClass.functions.single { it.owner.name.asString() == "hashCode" }
|
||||||
|
|
||||||
|
|
||||||
|
val IrTypeParameter.erasedUpperBound: IrClass
|
||||||
|
get() {
|
||||||
|
// Pick the (necessarily unique) non-interface upper bound if it exists
|
||||||
|
for (type in superTypes) {
|
||||||
|
val irClass = type.classOrNull?.owner ?: continue
|
||||||
|
if (!irClass.isInterface && !irClass.isAnnotationClass) return irClass
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, choose either the first IrClass supertype or recurse.
|
||||||
|
// In the first case, all supertypes are interface types and the choice was arbitrary.
|
||||||
|
// In the second case, there is only a single supertype.
|
||||||
|
return when (val firstSuper = superTypes.first().classifierOrNull?.owner) {
|
||||||
|
is IrClass -> firstSuper
|
||||||
|
is IrTypeParameter -> firstSuper.erasedUpperBound
|
||||||
|
else -> error("unknown supertype kind $firstSuper")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun getHashCodeFunctionInfo(type: IrType): HashCodeFunctionInfo {
|
||||||
|
val classifier = type.classifierOrNull
|
||||||
|
val symbol = when {
|
||||||
|
classifier.isArrayOrPrimitiveArray -> context.irBuiltIns.dataClassArrayMemberHashCodeSymbol
|
||||||
|
classifier is IrClassSymbol -> getHashCodeFunction(classifier.owner)
|
||||||
|
classifier is IrTypeParameterSymbol -> getHashCodeFunction(classifier.owner.erasedUpperBound)
|
||||||
|
else -> error("Unknown classifier kind $classifier")
|
||||||
|
}
|
||||||
|
return Fir2IrHashCodeFunctionInfo(symbol)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,7 +177,6 @@ class DataClassMembersGenerator(val components: Fir2IrComponents) {
|
|||||||
val properties = irClass.declarations
|
val properties = irClass.declarations
|
||||||
.filterIsInstance<IrProperty>()
|
.filterIsInstance<IrProperty>()
|
||||||
.take(propertyParametersCount)
|
.take(propertyParametersCount)
|
||||||
.map { it.descriptor }
|
|
||||||
if (properties.isEmpty()) {
|
if (properties.isEmpty()) {
|
||||||
return emptyList()
|
return emptyList()
|
||||||
}
|
}
|
||||||
|
|||||||
+54
-3
@@ -17,15 +17,23 @@
|
|||||||
package org.jetbrains.kotlin.psi2ir.generators
|
package org.jetbrains.kotlin.psi2ir.generators
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.DataClassMethodGenerator
|
import org.jetbrains.kotlin.backend.common.DataClassMethodGenerator
|
||||||
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
|
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.IrType
|
||||||
|
import org.jetbrains.kotlin.ir.types.toKotlinType
|
||||||
import org.jetbrains.kotlin.ir.util.DataClassMembersGenerator
|
import org.jetbrains.kotlin.ir.util.DataClassMembersGenerator
|
||||||
import org.jetbrains.kotlin.ir.util.declareSimpleFunctionWithOverrides
|
import org.jetbrains.kotlin.ir.util.declareSimpleFunctionWithOverrides
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||||
import org.jetbrains.kotlin.psi.KtParameter
|
import org.jetbrains.kotlin.psi.KtParameter
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.representativeUpperBound
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A generator that generates synthetic members of data class as well as part of inline class.
|
* A generator that generates synthetic members of data class as well as part of inline class.
|
||||||
@@ -72,14 +80,57 @@ class DataClassMembersGenerator(
|
|||||||
override fun getProperty(parameter: ValueParameterDescriptor?, irValueParameter: IrValueParameter?): IrProperty? =
|
override fun getProperty(parameter: ValueParameterDescriptor?, irValueParameter: IrValueParameter?): IrProperty? =
|
||||||
parameter?.let {
|
parameter?.let {
|
||||||
val property = getOrFail(BindingContext.VALUE_PARAMETER_AS_PROPERTY, parameter)
|
val property = getOrFail(BindingContext.VALUE_PARAMETER_AS_PROPERTY, parameter)
|
||||||
return getProperty(property)
|
return getIrProperty(property)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun transform(typeParameterDescriptor: TypeParameterDescriptor): IrType =
|
override fun transform(typeParameterDescriptor: TypeParameterDescriptor): IrType =
|
||||||
typeParameterDescriptor.defaultType.toIrType()
|
typeParameterDescriptor.defaultType.toIrType()
|
||||||
|
|
||||||
override fun commitSubstituted(irMemberAccessExpression: IrMemberAccessExpression<*>, descriptor: CallableDescriptor) {
|
private fun MemberScope.findHashCodeFunctionOrNull() =
|
||||||
irMemberAccessExpression.commitSubstituted(descriptor)
|
getContributedFunctions(Name.identifier("hashCode"), NoLookupLocation.FROM_BACKEND)
|
||||||
|
.find { it.valueParameters.isEmpty() && it.extensionReceiverParameter == null }
|
||||||
|
|
||||||
|
private fun getHashCodeFunction(type: KotlinType): FunctionDescriptor =
|
||||||
|
type.memberScope.findHashCodeFunctionOrNull()
|
||||||
|
?: context.builtIns.any.unsubstitutedMemberScope.findHashCodeFunctionOrNull()!!
|
||||||
|
|
||||||
|
private fun getHashCodeFunction(
|
||||||
|
type: KotlinType,
|
||||||
|
symbolResolve: (FunctionDescriptor) -> IrSimpleFunctionSymbol
|
||||||
|
): IrSimpleFunctionSymbol =
|
||||||
|
when (val typeConstructorDescriptor = type.constructor.declarationDescriptor) {
|
||||||
|
is ClassDescriptor ->
|
||||||
|
if (KotlinBuiltIns.isArrayOrPrimitiveArray(typeConstructorDescriptor))
|
||||||
|
context.irBuiltIns.dataClassArrayMemberHashCodeSymbol
|
||||||
|
else
|
||||||
|
symbolResolve(getHashCodeFunction(type))
|
||||||
|
|
||||||
|
is TypeParameterDescriptor ->
|
||||||
|
getHashCodeFunction(typeConstructorDescriptor.representativeUpperBound, symbolResolve)
|
||||||
|
|
||||||
|
else ->
|
||||||
|
throw AssertionError("Unexpected type: $type")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inner class Psi2IrHashCodeFunctionInfo(
|
||||||
|
override val symbol: IrSimpleFunctionSymbol,
|
||||||
|
val substituted: CallableDescriptor
|
||||||
|
) : HashCodeFunctionInfo {
|
||||||
|
|
||||||
|
override fun commitSubstituted(irMemberAccessExpression: IrMemberAccessExpression<*>) {
|
||||||
|
irMemberAccessExpression.commitSubstituted(substituted)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getHashCodeFunctionInfo(type: IrType): HashCodeFunctionInfo {
|
||||||
|
var substituted: CallableDescriptor? = null
|
||||||
|
val symbol = getHashCodeFunction(type.toKotlinType()) { hashCodeDescriptor ->
|
||||||
|
substituted = hashCodeDescriptor
|
||||||
|
symbolTable.referenceSimpleFunction(hashCodeDescriptor.original)
|
||||||
|
}
|
||||||
|
return Psi2IrHashCodeFunctionInfo(symbol, substituted ?: symbol.descriptor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,30 +5,26 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.ir.util
|
package org.jetbrains.kotlin.ir.util
|
||||||
|
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
|
||||||
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
||||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
import org.jetbrains.kotlin.ir.builders.*
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
|
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
|
||||||
import org.jetbrains.kotlin.ir.descriptors.WrappedVariableDescriptor
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
|
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.mapTypeParameters
|
import org.jetbrains.kotlin.ir.expressions.mapTypeParameters
|
||||||
import org.jetbrains.kotlin.ir.expressions.mapValueParameters
|
import org.jetbrains.kotlin.ir.expressions.mapValueParameters
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
|
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
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.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
|
||||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||||
import org.jetbrains.kotlin.types.isNullable
|
|
||||||
import org.jetbrains.kotlin.types.typeUtil.representativeUpperBound
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A platform-, frontend-independent logic for generating synthetic members of data class: equals, hashCode, toString, componentN, and copy.
|
* A platform-, frontend-independent logic for generating synthetic members of data class: equals, hashCode, toString, componentN, and copy.
|
||||||
@@ -127,7 +123,7 @@ abstract class DataClassMembersGenerator(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun generateEqualsMethodBody(properties: List<PropertyDescriptor>) {
|
fun generateEqualsMethodBody(properties: List<IrProperty>) {
|
||||||
val irType = irClass.defaultType
|
val irType = irClass.defaultType
|
||||||
|
|
||||||
if (!irClass.isInline) {
|
if (!irClass.isInline) {
|
||||||
@@ -136,9 +132,8 @@ abstract class DataClassMembersGenerator(
|
|||||||
+irIfThenReturnFalse(irNotIs(irOther(), irType))
|
+irIfThenReturnFalse(irNotIs(irOther(), irType))
|
||||||
val otherWithCast = irTemporary(irAs(irOther(), irType), "other_with_cast")
|
val otherWithCast = irTemporary(irAs(irOther(), irType), "other_with_cast")
|
||||||
for (property in properties) {
|
for (property in properties) {
|
||||||
val irProperty = getProperty(property)
|
val arg1 = irGetProperty(irThis(), property)
|
||||||
val arg1 = irGetProperty(irThis(), irProperty)
|
val arg2 = irGetProperty(irGet(irType, otherWithCast.symbol), property)
|
||||||
val arg2 = irGetProperty(irGet(irType, otherWithCast.symbol), irProperty)
|
|
||||||
+irIfThenReturnFalse(irNotEquals(arg1, arg2))
|
+irIfThenReturnFalse(irNotEquals(arg1, arg2))
|
||||||
}
|
}
|
||||||
+irReturnTrue()
|
+irReturnTrue()
|
||||||
@@ -157,7 +152,7 @@ abstract class DataClassMembersGenerator(
|
|||||||
KotlinTypeChecker.DEFAULT.equalTypes(it.valueParameters[0].type, intType)
|
KotlinTypeChecker.DEFAULT.equalTypes(it.valueParameters[0].type, intType)
|
||||||
}.let { symbolTable.referenceSimpleFunction(it) }
|
}.let { symbolTable.referenceSimpleFunction(it) }
|
||||||
|
|
||||||
fun generateHashCodeMethodBody(properties: List<PropertyDescriptor>) {
|
fun generateHashCodeMethodBody(properties: List<IrProperty>) {
|
||||||
if (properties.isEmpty()) {
|
if (properties.isEmpty()) {
|
||||||
+irReturn(irInt(0))
|
+irReturn(irInt(0))
|
||||||
return
|
return
|
||||||
@@ -189,27 +184,23 @@ abstract class DataClassMembersGenerator(
|
|||||||
+irReturn(irGet(irResultVar))
|
+irReturn(irGet(irResultVar))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getHashCodeOfProperty(property: PropertyDescriptor): IrExpression {
|
private fun getHashCodeOfProperty(property: IrProperty): IrExpression {
|
||||||
val irProperty = getProperty(property)
|
|
||||||
return when {
|
return when {
|
||||||
property.type.isNullable() ->
|
property.backingField!!.type.isNullable() ->
|
||||||
irIfNull(
|
irIfNull(
|
||||||
context.irBuiltIns.intType,
|
context.irBuiltIns.intType,
|
||||||
irGetProperty(irThis(), irProperty),
|
irGetProperty(irThis(), property),
|
||||||
irInt(0),
|
irInt(0),
|
||||||
getHashCodeOf(property, irGetProperty(irThis(), irProperty))
|
getHashCodeOf(property, irGetProperty(irThis(), property))
|
||||||
)
|
)
|
||||||
else ->
|
else ->
|
||||||
getHashCodeOf(property, irGetProperty(irThis(), irProperty))
|
getHashCodeOf(property, irGetProperty(irThis(), property))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getHashCodeOf(property: PropertyDescriptor, irValue: IrExpression): IrExpression {
|
private fun getHashCodeOf(property: IrProperty, irValue: IrExpression): IrExpression {
|
||||||
var substituted: FunctionDescriptor? = null
|
val hashCodeFunctionInfo = getHashCodeFunctionInfo(property.backingField!!.type)
|
||||||
val hashCodeFunctionSymbol = getHashCodeFunction(property) {
|
val hashCodeFunctionSymbol = hashCodeFunctionInfo.symbol
|
||||||
substituted = it
|
|
||||||
symbolTable.referenceSimpleFunction(it.original)
|
|
||||||
}
|
|
||||||
|
|
||||||
val hasDispatchReceiver = hashCodeFunctionSymbol.descriptor.dispatchReceiverParameter != null
|
val hasDispatchReceiver = hashCodeFunctionSymbol.descriptor.dispatchReceiverParameter != null
|
||||||
return irCall(
|
return irCall(
|
||||||
@@ -223,26 +214,24 @@ abstract class DataClassMembersGenerator(
|
|||||||
} else {
|
} else {
|
||||||
putValueArgument(0, irValue)
|
putValueArgument(0, irValue)
|
||||||
}
|
}
|
||||||
commitSubstituted(this, substituted ?: hashCodeFunctionSymbol.descriptor)
|
hashCodeFunctionInfo.commitSubstituted(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun generateToStringMethodBody(properties: List<PropertyDescriptor>) {
|
fun generateToStringMethodBody(properties: List<IrProperty>) {
|
||||||
val irConcat = irConcat()
|
val irConcat = irConcat()
|
||||||
irConcat.addArgument(irString(irClass.descriptor.name.asString() + "("))
|
irConcat.addArgument(irString(irClass.name.asString() + "("))
|
||||||
var first = true
|
var first = true
|
||||||
for (property in properties) {
|
for (property in properties) {
|
||||||
if (!first) irConcat.addArgument(irString(", "))
|
if (!first) irConcat.addArgument(irString(", "))
|
||||||
|
|
||||||
irConcat.addArgument(irString(property.name.asString() + "="))
|
irConcat.addArgument(irString(property.name.asString() + "="))
|
||||||
|
|
||||||
val irPropertyValue = irGetProperty(irThis(), getProperty(property))
|
val irPropertyValue = irGetProperty(irThis(), property)
|
||||||
|
|
||||||
val typeConstructorDescriptor = property.type.constructor.declarationDescriptor
|
val classifier = property.backingField!!.type.classifierOrNull
|
||||||
val irPropertyStringValue =
|
val irPropertyStringValue =
|
||||||
if (typeConstructorDescriptor is ClassDescriptor &&
|
if (classifier.isArrayOrPrimitiveArray)
|
||||||
KotlinBuiltIns.isArrayOrPrimitiveArray(typeConstructorDescriptor)
|
|
||||||
)
|
|
||||||
irCall(context.irBuiltIns.dataClassArrayMemberToStringSymbol, context.irBuiltIns.stringType).apply {
|
irCall(context.irBuiltIns.dataClassArrayMemberToStringSymbol, context.irBuiltIns.stringType).apply {
|
||||||
putValueArgument(0, irPropertyValue)
|
putValueArgument(0, irPropertyValue)
|
||||||
}
|
}
|
||||||
@@ -257,10 +246,16 @@ abstract class DataClassMembersGenerator(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getProperty(property: PropertyDescriptor): IrProperty =
|
fun getIrProperty(property: PropertyDescriptor): IrProperty =
|
||||||
irPropertiesByDescriptor[property]
|
irPropertiesByDescriptor[property]
|
||||||
?: throw AssertionError("Class: ${irClass.descriptor}: unexpected property descriptor: $property")
|
?: throw AssertionError("Class: ${irClass.descriptor}: unexpected property descriptor: $property")
|
||||||
|
|
||||||
|
fun getBackingField(property: PropertyDescriptor): IrField =
|
||||||
|
getIrProperty(property).backingField!!
|
||||||
|
|
||||||
|
val IrClassifierSymbol?.isArrayOrPrimitiveArray: Boolean
|
||||||
|
get() = this == context.irBuiltIns.arrayClass || this in context.irBuiltIns.primitiveArrays
|
||||||
|
|
||||||
abstract fun declareSimpleFunction(startOffset: Int, endOffset: Int, functionDescriptor: FunctionDescriptor): IrFunction
|
abstract fun declareSimpleFunction(startOffset: Int, endOffset: Int, functionDescriptor: FunctionDescriptor): IrFunction
|
||||||
|
|
||||||
abstract fun generateSyntheticFunctionParameterDeclarations(irFunction: IrFunction)
|
abstract fun generateSyntheticFunctionParameterDeclarations(irFunction: IrFunction)
|
||||||
@@ -336,60 +331,33 @@ abstract class DataClassMembersGenerator(
|
|||||||
// Entry for psi2ir
|
// Entry for psi2ir
|
||||||
fun generateEqualsMethod(function: FunctionDescriptor, properties: List<PropertyDescriptor>) {
|
fun generateEqualsMethod(function: FunctionDescriptor, properties: List<PropertyDescriptor>) {
|
||||||
buildMember(function) {
|
buildMember(function) {
|
||||||
generateEqualsMethodBody(properties)
|
generateEqualsMethodBody(properties.map { getIrProperty(it) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Entry for fir2ir
|
// Entry for fir2ir
|
||||||
fun generateEqualsMethod(irFunction: IrFunction, properties: List<PropertyDescriptor>) {
|
fun generateEqualsMethod(irFunction: IrFunction, properties: List<IrProperty>) {
|
||||||
buildMember(irFunction) {
|
buildMember(irFunction) {
|
||||||
generateEqualsMethodBody(properties)
|
generateEqualsMethodBody(properties)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun MemberScope.findHashCodeFunctionOrNull() =
|
interface HashCodeFunctionInfo {
|
||||||
getContributedFunctions(Name.identifier("hashCode"), NoLookupLocation.FROM_BACKEND)
|
val symbol: IrSimpleFunctionSymbol
|
||||||
.find { it.valueParameters.isEmpty() }
|
fun commitSubstituted(irMemberAccessExpression: IrMemberAccessExpression<*>)
|
||||||
|
}
|
||||||
|
|
||||||
private fun getHashCodeFunction(type: KotlinType): FunctionDescriptor =
|
abstract fun getHashCodeFunctionInfo(type: IrType): HashCodeFunctionInfo
|
||||||
type.memberScope.findHashCodeFunctionOrNull()
|
|
||||||
?: context.builtIns.any.unsubstitutedMemberScope.findHashCodeFunctionOrNull()!!
|
|
||||||
|
|
||||||
private fun getHashCodeFunction(
|
|
||||||
type: KotlinType,
|
|
||||||
symbolResolve: (FunctionDescriptor) -> IrSimpleFunctionSymbol
|
|
||||||
): IrSimpleFunctionSymbol =
|
|
||||||
when (val typeConstructorDescriptor = type.constructor.declarationDescriptor) {
|
|
||||||
is ClassDescriptor ->
|
|
||||||
if (KotlinBuiltIns.isArrayOrPrimitiveArray(typeConstructorDescriptor))
|
|
||||||
context.irBuiltIns.dataClassArrayMemberHashCodeSymbol
|
|
||||||
else
|
|
||||||
symbolResolve(getHashCodeFunction(type))
|
|
||||||
|
|
||||||
is TypeParameterDescriptor ->
|
|
||||||
getHashCodeFunction(typeConstructorDescriptor.representativeUpperBound, symbolResolve)
|
|
||||||
|
|
||||||
else ->
|
|
||||||
throw AssertionError("Unexpected type: $type")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getHashCodeFunction(
|
|
||||||
property: PropertyDescriptor,
|
|
||||||
symbolResolve: (FunctionDescriptor) -> IrSimpleFunctionSymbol
|
|
||||||
): IrSimpleFunctionSymbol =
|
|
||||||
getHashCodeFunction(property.type, symbolResolve)
|
|
||||||
|
|
||||||
abstract fun commitSubstituted(irMemberAccessExpression: IrMemberAccessExpression<*>, descriptor: CallableDescriptor)
|
|
||||||
|
|
||||||
// Entry for psi2ir
|
// Entry for psi2ir
|
||||||
fun generateHashCodeMethod(function: FunctionDescriptor, properties: List<PropertyDescriptor>) {
|
fun generateHashCodeMethod(function: FunctionDescriptor, properties: List<PropertyDescriptor>) {
|
||||||
buildMember(function) {
|
buildMember(function) {
|
||||||
generateHashCodeMethodBody(properties)
|
generateHashCodeMethodBody(properties.map { getIrProperty(it) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Entry for fir2ir
|
// Entry for fir2ir
|
||||||
fun generateHashCodeMethod(irFunction: IrFunction, properties: List<PropertyDescriptor>) {
|
fun generateHashCodeMethod(irFunction: IrFunction, properties: List<IrProperty>) {
|
||||||
buildMember(irFunction) {
|
buildMember(irFunction) {
|
||||||
generateHashCodeMethodBody(properties)
|
generateHashCodeMethodBody(properties)
|
||||||
}
|
}
|
||||||
@@ -398,12 +366,12 @@ abstract class DataClassMembersGenerator(
|
|||||||
// Entry for psi2ir
|
// Entry for psi2ir
|
||||||
fun generateToStringMethod(function: FunctionDescriptor, properties: List<PropertyDescriptor>) {
|
fun generateToStringMethod(function: FunctionDescriptor, properties: List<PropertyDescriptor>) {
|
||||||
buildMember(function) {
|
buildMember(function) {
|
||||||
generateToStringMethodBody(properties)
|
generateToStringMethodBody(properties.map { getIrProperty(it) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Entry for fir2ir
|
// Entry for fir2ir
|
||||||
fun generateToStringMethod(irFunction: IrFunction, properties: List<PropertyDescriptor>) {
|
fun generateToStringMethod(irFunction: IrFunction, properties: List<IrProperty>) {
|
||||||
buildMember(irFunction) {
|
buildMember(irFunction) {
|
||||||
generateToStringMethodBody(properties)
|
generateToStringMethodBody(properties)
|
||||||
}
|
}
|
||||||
|
|||||||
-1
@@ -1,5 +1,4 @@
|
|||||||
// !LANGUAGE: +InlineClasses
|
// !LANGUAGE: +InlineClasses
|
||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
|
||||||
|
|
||||||
// FILE: Z.kt
|
// FILE: Z.kt
|
||||||
inline class Z(val value: Int)
|
inline class Z(val value: Int)
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ FILE fqName:<root> fileName:/inlineClassSyntheticMethods.kt
|
|||||||
$this: VALUE_PARAMETER GENERATED_INLINE_CLASS_MEMBER name:<this> type:<root>.IC<TT of <root>.IC>
|
$this: VALUE_PARAMETER GENERATED_INLINE_CLASS_MEMBER name:<this> type:<root>.IC<TT of <root>.IC>
|
||||||
BLOCK_BODY
|
BLOCK_BODY
|
||||||
RETURN type=kotlin.Nothing from='public open fun hashCode (): kotlin.Int declared in <root>.IC'
|
RETURN type=kotlin.Nothing from='public open fun hashCode (): kotlin.Int declared in <root>.IC'
|
||||||
CALL 'public open fun hashCode (): kotlin.Int declared in kotlin.Any' type=kotlin.Int origin=null
|
CALL 'public final fun hashCode (): kotlin.Int declared in <root>.C' type=kotlin.Int origin=null
|
||||||
$this: GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:c type:<root>.C<TT of <root>.IC> visibility:private [final]' type=<root>.C<TT of <root>.IC> origin=null
|
$this: GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:c type:<root>.C<TT of <root>.IC> visibility:private [final]' type=<root>.C<TT of <root>.IC> origin=null
|
||||||
receiver: GET_VAR '<this>: <root>.IC<TT of <root>.IC> declared in <root>.IC.hashCode' type=<root>.IC<TT of <root>.IC> origin=null
|
receiver: GET_VAR '<this>: <root>.IC<TT of <root>.IC> declared in <root>.IC.hashCode' type=<root>.IC<TT of <root>.IC> origin=null
|
||||||
FUN GENERATED_INLINE_CLASS_MEMBER name:toString visibility:public modality:OPEN <> ($this:<root>.IC<TT of <root>.IC>) returnType:kotlin.String
|
FUN GENERATED_INLINE_CLASS_MEMBER name:toString visibility:public modality:OPEN <> ($this:<root>.IC<TT of <root>.IC>) returnType:kotlin.String
|
||||||
|
|||||||
+1
-1
@@ -81,7 +81,7 @@ FILE fqName:<root> fileName:/lambdaInDataClassDefaultParameter.kt
|
|||||||
$this: VALUE_PARAMETER GENERATED_DATA_CLASS_MEMBER name:<this> type:<root>.A
|
$this: VALUE_PARAMETER GENERATED_DATA_CLASS_MEMBER name:<this> type:<root>.A
|
||||||
BLOCK_BODY
|
BLOCK_BODY
|
||||||
RETURN type=kotlin.Nothing from='public open fun hashCode (): kotlin.Int declared in <root>.A'
|
RETURN type=kotlin.Nothing from='public open fun hashCode (): kotlin.Int declared in <root>.A'
|
||||||
CALL 'public open fun hashCode (): kotlin.Int declared in kotlin.Any' type=kotlin.Int origin=null
|
CALL 'public open fun hashCode (): kotlin.Int [fake_override] declared in kotlin.Function2' type=kotlin.Int origin=null
|
||||||
$this: GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:runA type:@[ExtensionFunctionType] kotlin.Function2<<root>.A, kotlin.String, kotlin.Unit> visibility:private [final]' type=@[ExtensionFunctionType] kotlin.Function2<<root>.A, kotlin.String, kotlin.Unit> origin=null
|
$this: GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:runA type:@[ExtensionFunctionType] kotlin.Function2<<root>.A, kotlin.String, kotlin.Unit> visibility:private [final]' type=@[ExtensionFunctionType] kotlin.Function2<<root>.A, kotlin.String, kotlin.Unit> origin=null
|
||||||
receiver: GET_VAR '<this>: <root>.A declared in <root>.A.hashCode' type=<root>.A origin=null
|
receiver: GET_VAR '<this>: <root>.A declared in <root>.A.hashCode' type=<root>.A origin=null
|
||||||
FUN GENERATED_DATA_CLASS_MEMBER name:toString visibility:public modality:OPEN <> ($this:<root>.A) returnType:kotlin.String
|
FUN GENERATED_DATA_CLASS_MEMBER name:toString visibility:public modality:OPEN <> ($this:<root>.A) returnType:kotlin.String
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ FILE fqName:<root> fileName:/SignatureClash.kt
|
|||||||
$this: VALUE_PARAMETER GENERATED_DATA_CLASS_MEMBER name:<this> type:<root>.DataClass
|
$this: VALUE_PARAMETER GENERATED_DATA_CLASS_MEMBER name:<this> type:<root>.DataClass
|
||||||
BLOCK_BODY
|
BLOCK_BODY
|
||||||
RETURN type=kotlin.Nothing from='public open fun hashCode (): kotlin.Int declared in <root>.DataClass'
|
RETURN type=kotlin.Nothing from='public open fun hashCode (): kotlin.Int declared in <root>.DataClass'
|
||||||
CALL 'public open fun hashCode (): kotlin.Int declared in kotlin.Any' type=kotlin.Int origin=null
|
CALL 'public open fun hashCode (): kotlin.Int [fake_override] declared in <root>.Delegate' type=kotlin.Int origin=null
|
||||||
$this: GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:delegate type:<root>.Delegate visibility:private [final]' type=<root>.Delegate origin=null
|
$this: GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:delegate type:<root>.Delegate visibility:private [final]' type=<root>.Delegate origin=null
|
||||||
receiver: GET_VAR '<this>: <root>.DataClass declared in <root>.DataClass.hashCode' type=<root>.DataClass origin=null
|
receiver: GET_VAR '<this>: <root>.DataClass declared in <root>.DataClass.hashCode' type=<root>.DataClass origin=null
|
||||||
FUN GENERATED_DATA_CLASS_MEMBER name:toString visibility:public modality:OPEN <> ($this:<root>.DataClass) returnType:kotlin.String
|
FUN GENERATED_DATA_CLASS_MEMBER name:toString visibility:public modality:OPEN <> ($this:<root>.DataClass) returnType:kotlin.String
|
||||||
|
|||||||
Reference in New Issue
Block a user