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 59d47f8f2bc..e94410b3df7 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 @@ -164,20 +164,18 @@ class DataClassMembersGenerator(declarationGenerator: DeclarationGenerator) : De .let { context.symbolTable.referenceFunction(it) } - private fun getHashCodeFunction(type: KotlinType): IrFunctionSymbol { + private fun getHashCodeFunction(type: KotlinType): FunctionDescriptor { val typeConstructorDescriptor = type.constructor.declarationDescriptor return when (typeConstructorDescriptor) { - is ClassDescriptor -> { - if (KotlinBuiltIns.isArrayOrPrimitiveArray(typeConstructorDescriptor)) { - context.irBuiltIns.dataClassArrayMemberHashCodeSymbol - } else { - val hashCodeDescriptor: CallableDescriptor = - typeConstructorDescriptor.findFirstFunction("hashCode") { it.valueParameters.isEmpty() } - context.symbolTable.referenceFunction(hashCodeDescriptor) - } - } + is ClassDescriptor -> + if (KotlinBuiltIns.isArrayOrPrimitiveArray(typeConstructorDescriptor)) + context.irBuiltIns.dataClassArrayMemberHashCodeSymbol.descriptor + else + type.memberScope.findFirstFunction("hashCode") { it.valueParameters.isEmpty() } + is TypeParameterDescriptor -> getHashCodeFunction(context.builtIns.anyType) // TODO + else -> throw AssertionError("Unexpected type: $type") } @@ -212,14 +210,17 @@ class DataClassMembersGenerator(declarationGenerator: DeclarationGenerator) : De } } - private fun MemberFunctionBuilder.getHashCodeOf(irValue: IrExpression): IrExpression = - irCall(getHashCodeFunction(irValue.type)).apply { + private fun MemberFunctionBuilder.getHashCodeOf(irValue: IrExpression): IrExpression { + val hashCodeFunctionDescriptor = getHashCodeFunction(irValue.type) + val hashCodeFunctionSymbol = declarationGenerator.context.symbolTable.referenceFunction(hashCodeFunctionDescriptor.original) + return irCall(hashCodeFunctionSymbol, hashCodeFunctionDescriptor).apply { if (descriptor.dispatchReceiverParameter != null) { dispatchReceiver = irValue } else { putValueArgument(0, irValue) } } + } override fun generateToStringMethod(function: FunctionDescriptor, properties: List) { buildMember(function, declaration) { diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/builders/ExpressionHelpers.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/builders/ExpressionHelpers.kt index 3661cf6d406..6672072d33d 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/builders/ExpressionHelpers.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/builders/ExpressionHelpers.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.ir.builders +import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.descriptors.VariableDescriptor import org.jetbrains.kotlin.ir.IrElement @@ -154,6 +155,13 @@ fun IrBuilderWithScope.irCall( fun IrBuilderWithScope.irCall(callee: IrFunctionSymbol): IrCall = irCall(callee, callee.descriptor.returnType!!) +fun IrBuilderWithScope.irCall( + calleeSymbol: IrFunctionSymbol, + calleeDescriptor: FunctionDescriptor, + typeArguments: Map? = null +): IrCall = + IrCallImpl(startOffset, endOffset, calleeDescriptor.returnType!!, calleeSymbol, calleeDescriptor, typeArguments) + fun IrBuilderWithScope.irCallOp(callee: IrFunctionSymbol, dispatchReceiver: IrExpression, argument: IrExpression): IrCall = irCall(callee, callee.descriptor.returnType!!).apply { this.dispatchReceiver = dispatchReceiver diff --git a/compiler/testData/ir/irText/classes/dataClassesGeneric.kt b/compiler/testData/ir/irText/classes/dataClassesGeneric.kt index 0ce8c4ed2c5..4e2693ec2d2 100644 --- a/compiler/testData/ir/irText/classes/dataClassesGeneric.kt +++ b/compiler/testData/ir/irText/classes/dataClassesGeneric.kt @@ -2,4 +2,6 @@ data class Test1(val x: T) data class Test2(val x: T) -data class Test3(val x: List) \ No newline at end of file +data class Test3(val x: List) + +data class Test4(val x: List) \ No newline at end of file diff --git a/compiler/testData/ir/irText/classes/dataClassesGeneric.txt b/compiler/testData/ir/irText/classes/dataClassesGeneric.txt index 3a7f45197de..e8dae654639 100644 --- a/compiler/testData/ir/irText/classes/dataClassesGeneric.txt +++ b/compiler/testData/ir/irText/classes/dataClassesGeneric.txt @@ -313,3 +313,100 @@ FILE fqName: fileName:/dataClassesGeneric.kt CONST Boolean type=kotlin.Boolean value=false RETURN type=kotlin.Nothing from='equals(Any?): Boolean' CONST Boolean type=kotlin.Boolean value=true + CLASS CLASS name:Test4 modality:FINAL visibility:public flags:data + $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:Test4 flags: + superClasses: + CLASS IR_EXTERNAL_DECLARATION_STUB CLASS name:Any modality:OPEN visibility:public flags: + CONSTRUCTOR visibility:public <> (x:kotlin.collections.List) returnType:Test4 flags:primary + VALUE_PARAMETER name:x index:0 type:kotlin.collections.List flags: + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'constructor Any()' + INSTANCE_INITIALIZER_CALL classDescriptor='Test4' + PROPERTY name:x type:kotlin.collections.List visibility:public modality:FINAL flags:val + FIELD PROPERTY_BACKING_FIELD name:x type:kotlin.collections.List visibility:public flags:final + EXPRESSION_BODY + GET_VAR 'value-parameter x: List' type=kotlin.collections.List origin=INITIALIZE_PROPERTY_FROM_PARAMETER + FUN DEFAULT_PROPERTY_ACCESSOR name: visibility:public modality:FINAL <> ($this:Test4) returnType:List flags: + correspondingProperty: PROPERTY name:x type:kotlin.collections.List visibility:public modality:FINAL flags:val + $this: VALUE_PARAMETER name: type:Test4 flags: + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): List' + GET_FIELD 'x: List' type=kotlin.collections.List origin=null + receiver: GET_VAR 'this@Test4: Test4' type=Test4 origin=null + FUN GENERATED_DATA_CLASS_MEMBER name:component1 visibility:public modality:FINAL <> ($this:Test4) returnType:List flags: + $this: VALUE_PARAMETER name: type:Test4 flags: + BLOCK_BODY + RETURN type=kotlin.Nothing from='component1(): List' + CALL '(): List' type=kotlin.collections.List origin=GET_PROPERTY + $this: GET_VAR 'this@Test4: Test4' type=Test4 origin=null + FUN GENERATED_DATA_CLASS_MEMBER name:copy visibility:public modality:FINAL <> ($this:Test4, x:kotlin.collections.List) returnType:Test4 flags: + $this: VALUE_PARAMETER name: type:Test4 flags: + VALUE_PARAMETER name:x index:0 type:kotlin.collections.List flags: + EXPRESSION_BODY + CALL '(): List' type=kotlin.collections.List origin=GET_PROPERTY + $this: GET_VAR 'this@Test4: Test4' type=Test4 origin=null + BLOCK_BODY + RETURN type=kotlin.Nothing from='copy(List = ...): Test4' + CALL 'constructor Test4(List)' type=Test4 origin=null + x: GET_VAR 'value-parameter x: List = ...' type=kotlin.collections.List origin=null + FUN GENERATED_DATA_CLASS_MEMBER name:toString visibility:public modality:OPEN <> ($this:Test4) returnType:String flags: + overridden: + FUN IR_EXTERNAL_DECLARATION_STUB name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:String flags: + $this: VALUE_PARAMETER name: type:Test4 flags: + BLOCK_BODY + RETURN type=kotlin.Nothing from='toString(): String' + STRING_CONCATENATION type=kotlin.String + CONST String type=kotlin.String value=Test4( + CONST String type=kotlin.String value=x= + CALL '(): List' type=kotlin.collections.List origin=GET_PROPERTY + $this: GET_VAR 'this@Test4: Test4' type=Test4 origin=null + CONST String type=kotlin.String value=) + FUN GENERATED_DATA_CLASS_MEMBER name:hashCode visibility:public modality:OPEN <> ($this:Test4) returnType:Int flags: + overridden: + FUN IR_EXTERNAL_DECLARATION_STUB name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:Int flags: + $this: VALUE_PARAMETER name: type:Test4 flags: + BLOCK_BODY + VAR IR_TEMPORARY_VARIABLE name:tmp0_result type:kotlin.Int flags:var + CONST Int type=kotlin.Int value=0 + SET_VAR 'tmp0_result: Int' type=kotlin.Unit origin=EQ + CALL 'hashCode(): Int' type=kotlin.Int origin=null + $this: CALL '(): List' type=kotlin.collections.List origin=GET_PROPERTY + $this: GET_VAR 'this@Test4: Test4' type=Test4 origin=null + RETURN type=kotlin.Nothing from='hashCode(): Int' + GET_VAR 'tmp0_result: Int' type=kotlin.Int origin=null + FUN GENERATED_DATA_CLASS_MEMBER name:equals visibility:public modality:OPEN <> ($this:Test4, other:kotlin.Any?) returnType:Boolean flags: + overridden: + FUN IR_EXTERNAL_DECLARATION_STUB name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:Boolean flags: + $this: VALUE_PARAMETER name: type:Test4 flags: + VALUE_PARAMETER name:other index:0 type:kotlin.Any? flags: + BLOCK_BODY + WHEN type=kotlin.Unit origin=null + BRANCH + if: CALL 'EQEQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EQEQEQ + arg0: GET_VAR 'this@Test4: Test4' type=Test4 origin=null + arg1: GET_VAR 'value-parameter other: Any?' type=kotlin.Any? origin=null + then: RETURN type=kotlin.Nothing from='equals(Any?): Boolean' + CONST Boolean type=kotlin.Boolean value=true + WHEN type=kotlin.Unit origin=null + BRANCH + if: TYPE_OP type=kotlin.Boolean origin=NOT_INSTANCEOF typeOperand=Test4 + typeOperand: CLASS CLASS name:Test4 modality:FINAL visibility:public flags:data + GET_VAR 'value-parameter other: Any?' type=kotlin.Any? origin=null + then: RETURN type=kotlin.Nothing from='equals(Any?): Boolean' + CONST Boolean type=kotlin.Boolean value=false + VAR IR_TEMPORARY_VARIABLE name:tmp0_other_with_cast type:Test4 flags:val + TYPE_OP type=Test4 origin=CAST typeOperand=Test4 + typeOperand: CLASS CLASS name:Test4 modality:FINAL visibility:public flags:data + GET_VAR 'value-parameter other: Any?' type=kotlin.Any? origin=null + WHEN type=kotlin.Unit origin=null + BRANCH + if: CALL 'NOT(Boolean): Boolean' type=kotlin.Boolean origin=EXCLEQ + arg0: CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EXCLEQ + arg0: CALL '(): List' type=kotlin.collections.List origin=GET_PROPERTY + $this: GET_VAR 'this@Test4: Test4' type=Test4 origin=null + arg1: CALL '(): List' type=kotlin.collections.List origin=GET_PROPERTY + $this: GET_VAR 'tmp0_other_with_cast: Test4' type=Test4 origin=null + then: RETURN type=kotlin.Nothing from='equals(Any?): Boolean' + CONST Boolean type=kotlin.Boolean value=false + RETURN type=kotlin.Nothing from='equals(Any?): Boolean' + CONST Boolean type=kotlin.Boolean value=true