From 076272f7ca51e85653b02cdf2855cb95e73c421f Mon Sep 17 00:00:00 2001 From: Georgy Bronnikov Date: Mon, 7 Dec 2020 23:09:44 +0300 Subject: [PATCH] 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. --- .../generators/DataClassMembersGenerator.kt | 51 +++++++- .../generators/DataClassMembersGenerator.kt | 57 ++++++++- .../ir/util/DataClassMembersGenerator.kt | 110 +++++++----------- .../inlineClassInGeneratedToString.kt | 1 - .../inlineClassSyntheticMethods.fir.txt | 2 +- .../lambdaInDataClassDefaultParameter.fir.txt | 2 +- .../irText/firProblems/SignatureClash.fir.txt | 2 +- 7 files changed, 144 insertions(+), 81 deletions(-) diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/DataClassMembersGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/DataClassMembersGenerator.kt index c928347c9f6..105b6b54a2c 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/DataClassMembersGenerator.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/DataClassMembersGenerator.kt @@ -31,11 +31,18 @@ import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.builders.IrGeneratorContextBase import org.jetbrains.kotlin.ir.declarations.* 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.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.DataClassMembersGenerator 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. @@ -93,8 +100,47 @@ class DataClassMembersGenerator(val components: Fir2IrComponents) { return components.irBuiltIns.anyType } - override fun commitSubstituted(irMemberAccessExpression: IrMemberAccessExpression<*>, descriptor: CallableDescriptor) { - // TODO + inner class Fir2IrHashCodeFunctionInfo(override val symbol: IrSimpleFunctionSymbol) : HashCodeFunctionInfo { + 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 .filterIsInstance() .take(propertyParametersCount) - .map { it.descriptor } if (properties.isEmpty()) { return emptyList() } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DataClassMembersGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DataClassMembersGenerator.kt index 0c9f09e84bb..8adfb284602 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DataClassMembersGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DataClassMembersGenerator.kt @@ -17,15 +17,23 @@ package org.jetbrains.kotlin.psi2ir.generators import org.jetbrains.kotlin.backend.common.DataClassMethodGenerator +import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.ir.declarations.* 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.toKotlinType import org.jetbrains.kotlin.ir.util.DataClassMembersGenerator import org.jetbrains.kotlin.ir.util.declareSimpleFunctionWithOverrides +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtParameter 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. @@ -72,14 +80,57 @@ class DataClassMembersGenerator( override fun getProperty(parameter: ValueParameterDescriptor?, irValueParameter: IrValueParameter?): IrProperty? = parameter?.let { val property = getOrFail(BindingContext.VALUE_PARAMETER_AS_PROPERTY, parameter) - return getProperty(property) + return getIrProperty(property) } override fun transform(typeParameterDescriptor: TypeParameterDescriptor): IrType = typeParameterDescriptor.defaultType.toIrType() - override fun commitSubstituted(irMemberAccessExpression: IrMemberAccessExpression<*>, descriptor: CallableDescriptor) { - irMemberAccessExpression.commitSubstituted(descriptor) + private fun MemberScope.findHashCodeFunctionOrNull() = + 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) } } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DataClassMembersGenerator.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DataClassMembersGenerator.kt index b1cf4821498..07e0b362587 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DataClassMembersGenerator.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DataClassMembersGenerator.kt @@ -5,30 +5,26 @@ package org.jetbrains.kotlin.ir.util -import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.declarations.* 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.IrMemberAccessExpression import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.expressions.mapTypeParameters 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.IrSimpleFunctionSymbol 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.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.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. @@ -127,7 +123,7 @@ abstract class DataClassMembersGenerator( ) } - fun generateEqualsMethodBody(properties: List) { + fun generateEqualsMethodBody(properties: List) { val irType = irClass.defaultType if (!irClass.isInline) { @@ -136,9 +132,8 @@ abstract class DataClassMembersGenerator( +irIfThenReturnFalse(irNotIs(irOther(), irType)) val otherWithCast = irTemporary(irAs(irOther(), irType), "other_with_cast") for (property in properties) { - val irProperty = getProperty(property) - val arg1 = irGetProperty(irThis(), irProperty) - val arg2 = irGetProperty(irGet(irType, otherWithCast.symbol), irProperty) + val arg1 = irGetProperty(irThis(), property) + val arg2 = irGetProperty(irGet(irType, otherWithCast.symbol), property) +irIfThenReturnFalse(irNotEquals(arg1, arg2)) } +irReturnTrue() @@ -157,7 +152,7 @@ abstract class DataClassMembersGenerator( KotlinTypeChecker.DEFAULT.equalTypes(it.valueParameters[0].type, intType) }.let { symbolTable.referenceSimpleFunction(it) } - fun generateHashCodeMethodBody(properties: List) { + fun generateHashCodeMethodBody(properties: List) { if (properties.isEmpty()) { +irReturn(irInt(0)) return @@ -189,27 +184,23 @@ abstract class DataClassMembersGenerator( +irReturn(irGet(irResultVar)) } - private fun getHashCodeOfProperty(property: PropertyDescriptor): IrExpression { - val irProperty = getProperty(property) + private fun getHashCodeOfProperty(property: IrProperty): IrExpression { return when { - property.type.isNullable() -> + property.backingField!!.type.isNullable() -> irIfNull( context.irBuiltIns.intType, - irGetProperty(irThis(), irProperty), + irGetProperty(irThis(), property), irInt(0), - getHashCodeOf(property, irGetProperty(irThis(), irProperty)) + getHashCodeOf(property, irGetProperty(irThis(), property)) ) else -> - getHashCodeOf(property, irGetProperty(irThis(), irProperty)) + getHashCodeOf(property, irGetProperty(irThis(), property)) } } - private fun getHashCodeOf(property: PropertyDescriptor, irValue: IrExpression): IrExpression { - var substituted: FunctionDescriptor? = null - val hashCodeFunctionSymbol = getHashCodeFunction(property) { - substituted = it - symbolTable.referenceSimpleFunction(it.original) - } + private fun getHashCodeOf(property: IrProperty, irValue: IrExpression): IrExpression { + val hashCodeFunctionInfo = getHashCodeFunctionInfo(property.backingField!!.type) + val hashCodeFunctionSymbol = hashCodeFunctionInfo.symbol val hasDispatchReceiver = hashCodeFunctionSymbol.descriptor.dispatchReceiverParameter != null return irCall( @@ -223,26 +214,24 @@ abstract class DataClassMembersGenerator( } else { putValueArgument(0, irValue) } - commitSubstituted(this, substituted ?: hashCodeFunctionSymbol.descriptor) + hashCodeFunctionInfo.commitSubstituted(this) } } - fun generateToStringMethodBody(properties: List) { + fun generateToStringMethodBody(properties: List) { val irConcat = irConcat() - irConcat.addArgument(irString(irClass.descriptor.name.asString() + "(")) + irConcat.addArgument(irString(irClass.name.asString() + "(")) var first = true for (property in properties) { if (!first) irConcat.addArgument(irString(", ")) 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 = - if (typeConstructorDescriptor is ClassDescriptor && - KotlinBuiltIns.isArrayOrPrimitiveArray(typeConstructorDescriptor) - ) + if (classifier.isArrayOrPrimitiveArray) irCall(context.irBuiltIns.dataClassArrayMemberToStringSymbol, context.irBuiltIns.stringType).apply { putValueArgument(0, irPropertyValue) } @@ -257,10 +246,16 @@ abstract class DataClassMembersGenerator( } } - fun getProperty(property: PropertyDescriptor): IrProperty = + fun getIrProperty(property: PropertyDescriptor): IrProperty = irPropertiesByDescriptor[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 generateSyntheticFunctionParameterDeclarations(irFunction: IrFunction) @@ -336,60 +331,33 @@ abstract class DataClassMembersGenerator( // Entry for psi2ir fun generateEqualsMethod(function: FunctionDescriptor, properties: List) { buildMember(function) { - generateEqualsMethodBody(properties) + generateEqualsMethodBody(properties.map { getIrProperty(it) }) } } // Entry for fir2ir - fun generateEqualsMethod(irFunction: IrFunction, properties: List) { + fun generateEqualsMethod(irFunction: IrFunction, properties: List) { buildMember(irFunction) { generateEqualsMethodBody(properties) } } - private fun MemberScope.findHashCodeFunctionOrNull() = - getContributedFunctions(Name.identifier("hashCode"), NoLookupLocation.FROM_BACKEND) - .find { it.valueParameters.isEmpty() } + interface HashCodeFunctionInfo { + val symbol: IrSimpleFunctionSymbol + fun commitSubstituted(irMemberAccessExpression: IrMemberAccessExpression<*>) + } - 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") - } - - private fun getHashCodeFunction( - property: PropertyDescriptor, - symbolResolve: (FunctionDescriptor) -> IrSimpleFunctionSymbol - ): IrSimpleFunctionSymbol = - getHashCodeFunction(property.type, symbolResolve) - - abstract fun commitSubstituted(irMemberAccessExpression: IrMemberAccessExpression<*>, descriptor: CallableDescriptor) + abstract fun getHashCodeFunctionInfo(type: IrType): HashCodeFunctionInfo // Entry for psi2ir fun generateHashCodeMethod(function: FunctionDescriptor, properties: List) { buildMember(function) { - generateHashCodeMethodBody(properties) + generateHashCodeMethodBody(properties.map { getIrProperty(it) }) } } // Entry for fir2ir - fun generateHashCodeMethod(irFunction: IrFunction, properties: List) { + fun generateHashCodeMethod(irFunction: IrFunction, properties: List) { buildMember(irFunction) { generateHashCodeMethodBody(properties) } @@ -398,12 +366,12 @@ abstract class DataClassMembersGenerator( // Entry for psi2ir fun generateToStringMethod(function: FunctionDescriptor, properties: List) { buildMember(function) { - generateToStringMethodBody(properties) + generateToStringMethodBody(properties.map { getIrProperty(it) }) } } // Entry for fir2ir - fun generateToStringMethod(irFunction: IrFunction, properties: List) { + fun generateToStringMethod(irFunction: IrFunction, properties: List) { buildMember(irFunction) { generateToStringMethodBody(properties) } diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/inlineClassInGeneratedToString.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/inlineClassInGeneratedToString.kt index 28c6fa70476..e1a7fab3496 100644 --- a/compiler/testData/codegen/bytecodeText/inlineClasses/inlineClassInGeneratedToString.kt +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/inlineClassInGeneratedToString.kt @@ -1,5 +1,4 @@ // !LANGUAGE: +InlineClasses -// IGNORE_BACKEND_FIR: JVM_IR // FILE: Z.kt inline class Z(val value: Int) diff --git a/compiler/testData/ir/irText/classes/inlineClassSyntheticMethods.fir.txt b/compiler/testData/ir/irText/classes/inlineClassSyntheticMethods.fir.txt index 35b49f52d51..dac9b0059cd 100644 --- a/compiler/testData/ir/irText/classes/inlineClassSyntheticMethods.fir.txt +++ b/compiler/testData/ir/irText/classes/inlineClassSyntheticMethods.fir.txt @@ -95,7 +95,7 @@ FILE fqName: fileName:/inlineClassSyntheticMethods.kt $this: VALUE_PARAMETER GENERATED_INLINE_CLASS_MEMBER name: type:.IC.IC> BLOCK_BODY RETURN type=kotlin.Nothing from='public open fun hashCode (): kotlin.Int declared in .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 .C' type=kotlin.Int origin=null $this: GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:c type:.C.IC> visibility:private [final]' type=.C.IC> origin=null receiver: GET_VAR ': .IC.IC> declared in .IC.hashCode' type=.IC.IC> origin=null FUN GENERATED_INLINE_CLASS_MEMBER name:toString visibility:public modality:OPEN <> ($this:.IC.IC>) returnType:kotlin.String diff --git a/compiler/testData/ir/irText/classes/lambdaInDataClassDefaultParameter.fir.txt b/compiler/testData/ir/irText/classes/lambdaInDataClassDefaultParameter.fir.txt index 921be13b44b..41833762667 100644 --- a/compiler/testData/ir/irText/classes/lambdaInDataClassDefaultParameter.fir.txt +++ b/compiler/testData/ir/irText/classes/lambdaInDataClassDefaultParameter.fir.txt @@ -81,7 +81,7 @@ FILE fqName: fileName:/lambdaInDataClassDefaultParameter.kt $this: VALUE_PARAMETER GENERATED_DATA_CLASS_MEMBER name: type:.A BLOCK_BODY RETURN type=kotlin.Nothing from='public open fun hashCode (): kotlin.Int declared in .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<.A, kotlin.String, kotlin.Unit> visibility:private [final]' type=@[ExtensionFunctionType] kotlin.Function2<.A, kotlin.String, kotlin.Unit> origin=null receiver: GET_VAR ': .A declared in .A.hashCode' type=.A origin=null FUN GENERATED_DATA_CLASS_MEMBER name:toString visibility:public modality:OPEN <> ($this:.A) returnType:kotlin.String diff --git a/compiler/testData/ir/irText/firProblems/SignatureClash.fir.txt b/compiler/testData/ir/irText/firProblems/SignatureClash.fir.txt index b034dcca96b..c2fbb9ed3f7 100644 --- a/compiler/testData/ir/irText/firProblems/SignatureClash.fir.txt +++ b/compiler/testData/ir/irText/firProblems/SignatureClash.fir.txt @@ -169,7 +169,7 @@ FILE fqName: fileName:/SignatureClash.kt $this: VALUE_PARAMETER GENERATED_DATA_CLASS_MEMBER name: type:.DataClass BLOCK_BODY RETURN type=kotlin.Nothing from='public open fun hashCode (): kotlin.Int declared in .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 .Delegate' type=kotlin.Int origin=null $this: GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:delegate type:.Delegate visibility:private [final]' type=.Delegate origin=null receiver: GET_VAR ': .DataClass declared in .DataClass.hashCode' type=.DataClass origin=null FUN GENERATED_DATA_CLASS_MEMBER name:toString visibility:public modality:OPEN <> ($this:.DataClass) returnType:kotlin.String