From c3c09aa95a58580022bb6853edfd34703b41bcf6 Mon Sep 17 00:00:00 2001 From: Pavel Mikhailovskii Date: Tue, 28 Jun 2022 09:51:57 +0200 Subject: [PATCH] KT-4107 Data objects --- .../diagnostics/KtFirDataClassConverters.kt | 6 + .../api/fir/diagnostics/KtFirDiagnostics.kt | 4 + .../fir/diagnostics/KtFirDiagnosticsImpl.kt | 5 + ...CompilerTestFE10TestdataTestGenerated.java | 40 +++++- .../common/DataClassMethodGenerator.kt | 7 +- .../common/FunctionsFromAnyGenerator.kt | 8 +- .../FunctionsFromAnyGeneratorImpl.java | 132 ++++++++++-------- ...irOldFrontendDiagnosticsTestGenerated.java | 40 +++++- ...DiagnosticsWithLightTreeTestGenerated.java | 40 +++++- .../diagnostics/FirDiagnosticsList.kt | 2 + .../fir/analysis/diagnostics/FirErrors.kt | 1 + .../checkers/CommonDeclarationCheckers.kt | 1 + .../FirDataObjectContentChecker.kt | 38 +++++ .../declaration/FirModifierChecker.kt | 8 +- .../diagnostics/FirErrorsDefaultMessages.kt | 3 +- .../generators/DataClassMembersGenerator.kt | 4 +- .../FirBlackBoxCodegenTestGenerated.java | 40 ++++++ .../kotlin/fir/builder/BaseFirBuilder.kt | 8 +- .../jetbrains/kotlin/diagnostics/Errors.java | 1 + .../rendering/DefaultErrorMessages.java | 1 + .../resolve/PlatformConfiguratorBase.kt | 1 + .../checkers/DataClassDeclarationChecker.kt | 3 +- .../checkers/DataObjectContentChecker.kt | 38 +++++ .../lazy/descriptors/LazyClassMemberScope.kt | 2 +- .../MethodsFromAnyGeneratorForLowerings.kt | 7 +- .../jetbrains/kotlin/backend/jvm/JvmLower.kt | 1 + .../ReadResolveForDataObjectsLowering.kt | 63 +++++++++ .../generators/DataClassMembersGenerator.kt | 5 +- .../ir/util/DataClassMembersGenerator.kt | 21 ++- .../src/org/jetbrains/kotlin/psi/KtClass.kt | 1 - .../jetbrains/kotlin/psi/KtClassOrObject.kt | 2 + .../kotlin/resolve/ModifierCheckerHelpers.kt | 8 +- .../codegen/box/dataObjects/equals.kt | 15 ++ .../codegen/box/dataObjects/hashCode.kt | 19 +++ .../box/dataObjects/multipleInstances.kt | 18 +++ .../codegen/box/dataObjects/serialization.kt | 19 +++ .../codegen/box/dataObjects/serialization.txt | 28 ++++ .../codegen/box/dataObjects/toString.kt | 52 +++++++ .../tests/dataClasses/companionDataObject.kt | 6 + .../tests/dataClasses/companionDataObject.txt | 16 +++ .../tests/dataClasses/dataObject.kt | 2 - .../tests/dataClasses/dataObject.txt | 13 -- .../dataClasses/dataObjectDisabled.fir.kt | 2 + .../tests/dataClasses/dataObjectDisabled.kt | 2 + .../tests/dataClasses/dataObjectDisabled.txt | 9 ++ .../tests/dataClasses/dataObjectEnabled.kt | 3 + .../tests/dataClasses/dataObjectEnabled.txt | 9 ++ .../tests/dataClasses/dataObjectLiteral.kt | 10 ++ .../tests/dataClasses/dataObjectLiteral.txt | 18 +++ .../diagnostics/tests/dataClasses/strange.kt | 6 +- .../diagnostics/tests/dataClasses/strange.txt | 6 +- .../dataObjects/overrideEqualsAndHashCode.kt | 44 ++++++ .../dataObjects/overrideEqualsAndHashCode.txt | 40 ++++++ .../dataObjects/customReadResolve.kt | 16 +++ .../dataObjects/customReadResolve.txt | 26 ++++ .../parameters/dataClassMembers.fir.kt.txt | 1 + .../test/runners/DiagnosticTestGenerated.java | 40 +++++- ...gnosticsTestWithJvmIrBackendGenerated.java | 16 +++ ...nosticsTestWithOldJvmBackendGenerated.java | 10 ++ .../codegen/BlackBoxCodegenTestGenerated.java | 28 ++++ .../IrBlackBoxCodegenTestGenerated.java | 40 ++++++ .../LightAnalysisModeTestGenerated.java | 28 ++++ .../kotlin/config/LanguageVersionSettings.kt | 1 + .../descriptors/annotations/KotlinTarget.kt | 5 +- .../js/test/JsCodegenBoxTestGenerated.java | 28 ++++ .../test/ir/IrJsCodegenBoxTestGenerated.java | 28 ++++ .../IrCodegenBoxWasmTestGenerated.java | 28 ++++ .../JsEqualsHashcodeToStringGenerator.java | 20 ++- .../NativeCodegenBoxTestGenerated.java | 30 ++++ .../testData/converter/nestedClasses2.kt | 2 +- .../testData/converter/nestedClasses2.txt | 33 +++++ .../testData/converter/nestedClasses2_ir.txt | 16 +++ .../converter/nestedClassesNonRootPackage.kt | 2 +- .../converter/nestedClassesNonRootPackage.txt | 29 ++++ .../nestedClassesNonRootPackage_ir.txt | 12 ++ 75 files changed, 1183 insertions(+), 134 deletions(-) create mode 100644 compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDataObjectContentChecker.kt create mode 100644 compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/DataObjectContentChecker.kt create mode 100644 compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/ReadResolveForDataObjectsLowering.kt create mode 100644 compiler/testData/codegen/box/dataObjects/equals.kt create mode 100644 compiler/testData/codegen/box/dataObjects/hashCode.kt create mode 100644 compiler/testData/codegen/box/dataObjects/multipleInstances.kt create mode 100644 compiler/testData/codegen/box/dataObjects/serialization.kt create mode 100644 compiler/testData/codegen/box/dataObjects/serialization.txt create mode 100644 compiler/testData/codegen/box/dataObjects/toString.kt create mode 100644 compiler/testData/diagnostics/tests/dataClasses/companionDataObject.kt create mode 100644 compiler/testData/diagnostics/tests/dataClasses/companionDataObject.txt delete mode 100644 compiler/testData/diagnostics/tests/dataClasses/dataObject.kt delete mode 100644 compiler/testData/diagnostics/tests/dataClasses/dataObject.txt create mode 100644 compiler/testData/diagnostics/tests/dataClasses/dataObjectDisabled.fir.kt create mode 100644 compiler/testData/diagnostics/tests/dataClasses/dataObjectDisabled.kt create mode 100644 compiler/testData/diagnostics/tests/dataClasses/dataObjectDisabled.txt create mode 100644 compiler/testData/diagnostics/tests/dataClasses/dataObjectEnabled.kt create mode 100644 compiler/testData/diagnostics/tests/dataClasses/dataObjectEnabled.txt create mode 100644 compiler/testData/diagnostics/tests/dataClasses/dataObjectLiteral.kt create mode 100644 compiler/testData/diagnostics/tests/dataClasses/dataObjectLiteral.txt create mode 100644 compiler/testData/diagnostics/tests/dataObjects/overrideEqualsAndHashCode.kt create mode 100644 compiler/testData/diagnostics/tests/dataObjects/overrideEqualsAndHashCode.txt create mode 100644 compiler/testData/diagnostics/testsWithJvmBackend/dataObjects/customReadResolve.kt create mode 100644 compiler/testData/diagnostics/testsWithJvmBackend/dataObjects/customReadResolve.txt diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt index 5c9569831ec..43a879a8d23 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -2438,6 +2438,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.DATA_OBJECT_CUSTOM_EQUALS_OR_HASH_CODE) { firDiagnostic -> + DataObjectCustomEqualsOrHashCodeImpl( + firDiagnostic as KtPsiDiagnostic, + token, + ) + } add(FirErrors.FUN_INTERFACE_CONSTRUCTOR_REFERENCE) { firDiagnostic -> FunInterfaceConstructorReferenceImpl( firDiagnostic as KtPsiDiagnostic, diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt index ce18175d8d6..012ba5808c7 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt @@ -1729,6 +1729,10 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = TailRecursionInTryIsNotSupported::class } + abstract class DataObjectCustomEqualsOrHashCode : KtFirDiagnostic() { + override val diagnosticClass get() = DataObjectCustomEqualsOrHashCode::class + } + abstract class FunInterfaceConstructorReference : KtFirDiagnostic() { override val diagnosticClass get() = FunInterfaceConstructorReference::class } diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index 8a3e8c146ad..788c9759384 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -2073,6 +2073,11 @@ internal class TailRecursionInTryIsNotSupportedImpl( override val token: KtLifetimeToken, ) : KtFirDiagnostic.TailRecursionInTryIsNotSupported(), KtAbstractFirDiagnostic +internal class DataObjectCustomEqualsOrHashCodeImpl( + override val firDiagnostic: KtPsiDiagnostic, + override val token: KtLifetimeToken, +) : KtFirDiagnostic.DataObjectCustomEqualsOrHashCode(), KtAbstractFirDiagnostic + internal class FunInterfaceConstructorReferenceImpl( override val firDiagnostic: KtPsiDiagnostic, override val token: KtLifetimeToken, diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java index 49a09dee1a1..d2f5011f492 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java @@ -6956,6 +6956,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/dataClasses"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); } + @Test + @TestMetadata("companionDataObject.kt") + public void testCompanionDataObject() throws Exception { + runTest("compiler/testData/diagnostics/tests/dataClasses/companionDataObject.kt"); + } + @Test @TestMetadata("componentNamedComponent1.kt") public void testComponentNamedComponent1() throws Exception { @@ -7029,9 +7035,21 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag } @Test - @TestMetadata("dataObject.kt") - public void testDataObject() throws Exception { - runTest("compiler/testData/diagnostics/tests/dataClasses/dataObject.kt"); + @TestMetadata("dataObjectDisabled.kt") + public void testDataObjectDisabled() throws Exception { + runTest("compiler/testData/diagnostics/tests/dataClasses/dataObjectDisabled.kt"); + } + + @Test + @TestMetadata("dataObjectEnabled.kt") + public void testDataObjectEnabled() throws Exception { + runTest("compiler/testData/diagnostics/tests/dataClasses/dataObjectEnabled.kt"); + } + + @Test + @TestMetadata("dataObjectLiteral.kt") + public void testDataObjectLiteral() throws Exception { + runTest("compiler/testData/diagnostics/tests/dataClasses/dataObjectLiteral.kt"); } @Test @@ -7655,6 +7673,22 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag } } + @Nested + @TestMetadata("compiler/testData/diagnostics/tests/dataObjects") + @TestDataPath("$PROJECT_ROOT") + public class DataObjects { + @Test + public void testAllFilesPresentInDataObjects() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/dataObjects"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); + } + + @Test + @TestMetadata("overrideEqualsAndHashCode.kt") + public void testOverrideEqualsAndHashCode() throws Exception { + runTest("compiler/testData/diagnostics/tests/dataObjects/overrideEqualsAndHashCode.kt"); + } + } + @Nested @TestMetadata("compiler/testData/diagnostics/tests/declarationChecks") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/DataClassMethodGenerator.kt b/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/DataClassMethodGenerator.kt index 1eec7561701..a22905ce459 100644 --- a/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/DataClassMethodGenerator.kt +++ b/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/DataClassMethodGenerator.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.backend.common import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.psi.KtClassOrObject +import org.jetbrains.kotlin.psi.KtObjectDeclaration import org.jetbrains.kotlin.psi.KtParameter import org.jetbrains.kotlin.resolve.BindingContext @@ -33,8 +34,10 @@ abstract class DataClassMethodGenerator( ) : FunctionsFromAnyGenerator(declaration, bindingContext) { override fun generate() { - generateComponentFunctionsForDataClasses() - generateCopyFunctionForDataClasses(primaryConstructorParameters) + if (declaration !is KtObjectDeclaration) { + generateComponentFunctionsForDataClasses() + generateCopyFunctionForDataClasses(primaryConstructorParameters) + } super.generate() } diff --git a/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/FunctionsFromAnyGenerator.kt b/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/FunctionsFromAnyGenerator.kt index 577314e4fb1..67f0498dde0 100644 --- a/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/FunctionsFromAnyGenerator.kt +++ b/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/FunctionsFromAnyGenerator.kt @@ -21,11 +21,9 @@ abstract class FunctionsFromAnyGenerator(protected val declaration: KtClassOrObj open fun generate() { val properties = primaryConstructorProperties - if (properties.isNotEmpty()) { - generateToStringIfNeeded(properties) - generateHashCodeIfNeeded(properties) - generateEqualsIfNeeded(properties) - } + generateToStringIfNeeded(properties) + generateHashCodeIfNeeded(properties) + generateEqualsIfNeeded(properties) } protected abstract fun generateToStringMethod(function: FunctionDescriptor, properties: List) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionsFromAnyGeneratorImpl.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionsFromAnyGeneratorImpl.java index dd86b2fb30e..a8a9d450e7d 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionsFromAnyGeneratorImpl.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionsFromAnyGeneratorImpl.java @@ -17,8 +17,10 @@ import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper; import org.jetbrains.kotlin.descriptors.ClassDescriptor; import org.jetbrains.kotlin.descriptors.FunctionDescriptor; import org.jetbrains.kotlin.descriptors.PropertyDescriptor; +import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.psi.KtClassOrObject; import org.jetbrains.kotlin.resolve.BindingContext; +import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.resolve.InlineClassesUtilsKt; import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt; import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin; @@ -103,42 +105,46 @@ public class FunctionsFromAnyGeneratorImpl extends FunctionsFromAnyGenerator { mv.visitCode(); - StringConcatGenerator generator = StringConcatGenerator.Companion.create(generationState, iv); - generator.genStringBuilderConstructorIfNeded(); - boolean first = true; + if (properties.isEmpty()) { + iv.aconst(classDescriptor.getName().asString()); + } else { + StringConcatGenerator generator = StringConcatGenerator.Companion.create(generationState, iv); + generator.genStringBuilderConstructorIfNeded(); + boolean first = true; - for (PropertyDescriptor propertyDescriptor : properties) { - if (first) { - generator.addStringConstant(classDescriptor.getName() + "(" + propertyDescriptor.getName().asString() + "="); - first = false; - } - else { - generator.addStringConstant(", " + propertyDescriptor.getName().asString() + "="); - } - - JvmKotlinType type = genOrLoadOnStack(iv, context, propertyDescriptor, 0); - Type asmType = type.getType(); - KotlinType kotlinType = type.getKotlinType(); - - if (asmType.getSort() == Type.ARRAY) { - Type elementType = correctElementType(asmType); - if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) { - iv.invokestatic("java/util/Arrays", "toString", "([Ljava/lang/Object;)Ljava/lang/String;", false); - asmType = JAVA_STRING_TYPE; - kotlinType = DescriptorUtilsKt.getBuiltIns(function).getStringType(); + for (PropertyDescriptor propertyDescriptor : properties) { + if (first) { + generator.addStringConstant(classDescriptor.getName() + "(" + propertyDescriptor.getName().asString() + "="); + first = false; } - else if (elementType.getSort() != Type.CHAR) { - iv.invokestatic("java/util/Arrays", "toString", "(" + asmType.getDescriptor() + ")Ljava/lang/String;", false); - asmType = JAVA_STRING_TYPE; - kotlinType = DescriptorUtilsKt.getBuiltIns(function).getStringType(); + else { + generator.addStringConstant(", " + propertyDescriptor.getName().asString() + "="); } + + JvmKotlinType type = genOrLoadOnStack(iv, context, propertyDescriptor, 0); + Type asmType = type.getType(); + KotlinType kotlinType = type.getKotlinType(); + + if (asmType.getSort() == Type.ARRAY) { + Type elementType = correctElementType(asmType); + if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) { + iv.invokestatic("java/util/Arrays", "toString", "([Ljava/lang/Object;)Ljava/lang/String;", false); + asmType = JAVA_STRING_TYPE; + kotlinType = DescriptorUtilsKt.getBuiltIns(function).getStringType(); + } + else if (elementType.getSort() != Type.CHAR) { + iv.invokestatic("java/util/Arrays", "toString", "(" + asmType.getDescriptor() + ")Ljava/lang/String;", false); + asmType = JAVA_STRING_TYPE; + kotlinType = DescriptorUtilsKt.getBuiltIns(function).getStringType(); + } + } + genInvokeAppendMethod(generator, asmType, kotlinType, typeMapper, StackValue.onStack(asmType)); } - genInvokeAppendMethod(generator, asmType, kotlinType, typeMapper, StackValue.onStack(asmType)); + + generator.addStringConstant(")"); + + generator.genToString(); } - - generator.addStringConstant(")"); - - generator.genToString(); iv.areturn(JAVA_STRING_TYPE); FunctionCodegen.endVisit(mv, toStringMethodName, getDeclaration()); @@ -175,41 +181,45 @@ public class FunctionsFromAnyGeneratorImpl extends FunctionsFromAnyGenerator { InstructionAdapter iv = new InstructionAdapter(mv); mv.visitCode(); - boolean first = true; - for (PropertyDescriptor propertyDescriptor : properties) { - if (!first) { - iv.iconst(31); - iv.mul(Type.INT_TYPE); - } + if (properties.isEmpty()) { + iv.iconst(DescriptorUtils.getFqNameSafe(classDescriptor).asString().hashCode()); + } else { + boolean first = true; + for (PropertyDescriptor propertyDescriptor : properties) { + if (!first) { + iv.iconst(31); + iv.mul(Type.INT_TYPE); + } - JvmKotlinType propertyType = genOrLoadOnStack(iv, context, propertyDescriptor, 0); - KotlinType kotlinType = propertyDescriptor.getReturnType(); - Type asmType = typeMapper.mapType(kotlinType); - StackValue.coerce(propertyType.getType(), propertyType.getKotlinType(), asmType, kotlinType, iv); + JvmKotlinType propertyType = genOrLoadOnStack(iv, context, propertyDescriptor, 0); + KotlinType kotlinType = propertyDescriptor.getReturnType(); + Type asmType = typeMapper.mapType(kotlinType); + StackValue.coerce(propertyType.getType(), propertyType.getKotlinType(), asmType, kotlinType, iv); - Label ifNull = null; - if (!isPrimitive(asmType)) { - ifNull = new Label(); - iv.dup(); - iv.ifnull(ifNull); - } + Label ifNull = null; + if (!isPrimitive(asmType)) { + ifNull = new Label(); + iv.dup(); + iv.ifnull(ifNull); + } - genHashCode(mv, iv, asmType, generationState.getTarget()); + genHashCode(mv, iv, asmType, generationState.getTarget()); - if (ifNull != null) { - Label end = new Label(); - iv.goTo(end); - iv.mark(ifNull); - iv.pop(); - iv.iconst(0); - iv.mark(end); - } + if (ifNull != null) { + Label end = new Label(); + iv.goTo(end); + iv.mark(ifNull); + iv.pop(); + iv.iconst(0); + iv.mark(end); + } - if (first) { - first = false; - } - else { - iv.add(Type.INT_TYPE); + if (first) { + first = false; + } + else { + iv.add(Type.INT_TYPE); + } } } diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java index 1afd739b340..f90e2d1c1a8 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java @@ -6956,6 +6956,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/dataClasses"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); } + @Test + @TestMetadata("companionDataObject.kt") + public void testCompanionDataObject() throws Exception { + runTest("compiler/testData/diagnostics/tests/dataClasses/companionDataObject.kt"); + } + @Test @TestMetadata("componentNamedComponent1.kt") public void testComponentNamedComponent1() throws Exception { @@ -7029,9 +7035,21 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti } @Test - @TestMetadata("dataObject.kt") - public void testDataObject() throws Exception { - runTest("compiler/testData/diagnostics/tests/dataClasses/dataObject.kt"); + @TestMetadata("dataObjectDisabled.kt") + public void testDataObjectDisabled() throws Exception { + runTest("compiler/testData/diagnostics/tests/dataClasses/dataObjectDisabled.kt"); + } + + @Test + @TestMetadata("dataObjectEnabled.kt") + public void testDataObjectEnabled() throws Exception { + runTest("compiler/testData/diagnostics/tests/dataClasses/dataObjectEnabled.kt"); + } + + @Test + @TestMetadata("dataObjectLiteral.kt") + public void testDataObjectLiteral() throws Exception { + runTest("compiler/testData/diagnostics/tests/dataClasses/dataObjectLiteral.kt"); } @Test @@ -7655,6 +7673,22 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti } } + @Nested + @TestMetadata("compiler/testData/diagnostics/tests/dataObjects") + @TestDataPath("$PROJECT_ROOT") + public class DataObjects { + @Test + public void testAllFilesPresentInDataObjects() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/dataObjects"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); + } + + @Test + @TestMetadata("overrideEqualsAndHashCode.kt") + public void testOverrideEqualsAndHashCode() throws Exception { + runTest("compiler/testData/diagnostics/tests/dataObjects/overrideEqualsAndHashCode.kt"); + } + } + @Nested @TestMetadata("compiler/testData/diagnostics/tests/declarationChecks") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java index 600cb953f82..2839427dff0 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java @@ -6956,6 +6956,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/dataClasses"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); } + @Test + @TestMetadata("companionDataObject.kt") + public void testCompanionDataObject() throws Exception { + runTest("compiler/testData/diagnostics/tests/dataClasses/companionDataObject.kt"); + } + @Test @TestMetadata("componentNamedComponent1.kt") public void testComponentNamedComponent1() throws Exception { @@ -7029,9 +7035,21 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac } @Test - @TestMetadata("dataObject.kt") - public void testDataObject() throws Exception { - runTest("compiler/testData/diagnostics/tests/dataClasses/dataObject.kt"); + @TestMetadata("dataObjectDisabled.kt") + public void testDataObjectDisabled() throws Exception { + runTest("compiler/testData/diagnostics/tests/dataClasses/dataObjectDisabled.kt"); + } + + @Test + @TestMetadata("dataObjectEnabled.kt") + public void testDataObjectEnabled() throws Exception { + runTest("compiler/testData/diagnostics/tests/dataClasses/dataObjectEnabled.kt"); + } + + @Test + @TestMetadata("dataObjectLiteral.kt") + public void testDataObjectLiteral() throws Exception { + runTest("compiler/testData/diagnostics/tests/dataClasses/dataObjectLiteral.kt"); } @Test @@ -7655,6 +7673,22 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac } } + @Nested + @TestMetadata("compiler/testData/diagnostics/tests/dataObjects") + @TestDataPath("$PROJECT_ROOT") + public class DataObjects { + @Test + public void testAllFilesPresentInDataObjects() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/dataObjects"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); + } + + @Test + @TestMetadata("overrideEqualsAndHashCode.kt") + public void testOverrideEqualsAndHashCode() throws Exception { + runTest("compiler/testData/diagnostics/tests/dataObjects/overrideEqualsAndHashCode.kt"); + } + } + @Nested @TestMetadata("compiler/testData/diagnostics/tests/declarationChecks") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt index a4425908b2f..59bd1a5a281 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt @@ -16,6 +16,7 @@ import org.jetbrains.kotlin.descriptors.EffectiveVisibility import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.diagnostics.WhenMissingCase import org.jetbrains.kotlin.diagnostics.deprecationError2 +import org.jetbrains.kotlin.diagnostics.error0 import org.jetbrains.kotlin.fir.FirModuleData import org.jetbrains.kotlin.fir.PrivateForInline import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.* @@ -901,6 +902,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { val TAILREC_ON_VIRTUAL_MEMBER_ERROR by error(PositioningStrategy.TAILREC_MODIFIER) val NON_TAIL_RECURSIVE_CALL by warning(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) val TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED by warning(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) + val DATA_OBJECT_CUSTOM_EQUALS_OR_HASH_CODE by error(PositioningStrategy.OVERRIDE_MODIFIER) } val FUN_INTERFACES by object : DiagnosticGroup("Fun interfaces") { diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index a221de19837..db0c832a1e3 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -483,6 +483,7 @@ object FirErrors { val TAILREC_ON_VIRTUAL_MEMBER_ERROR by error0(SourceElementPositioningStrategies.TAILREC_MODIFIER) val NON_TAIL_RECURSIVE_CALL by warning0(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED) val TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED by warning0(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED) + val DATA_OBJECT_CUSTOM_EQUALS_OR_HASH_CODE by error0(SourceElementPositioningStrategies.OVERRIDE_MODIFIER) // Fun interfaces val FUN_INTERFACE_CONSTRUCTOR_REFERENCE by error0(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt index 561e5f3e98f..5344e262373 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt @@ -54,6 +54,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() { FirTailrecFunctionChecker, FirTopLevelFunctionsChecker, FirMemberFunctionsChecker, + FirDataObjectContentChecker, ) override val propertyCheckers: Set diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDataObjectContentChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDataObjectContentChecker.kt new file mode 100644 index 00000000000..13e23c268c3 --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDataObjectContentChecker.kt @@ -0,0 +1,38 @@ +/* + * 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.fir.analysis.checkers.declaration + +import org.jetbrains.kotlin.KtFakeSourceElementKind +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.diagnostics.reportOn +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.checkers.hasModifier +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors +import org.jetbrains.kotlin.fir.declarations.FirClass +import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction +import org.jetbrains.kotlin.fir.types.isNullableAny +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.util.OperatorNameConventions + +object FirDataObjectContentChecker : FirSimpleFunctionChecker() { + override fun check(declaration: FirSimpleFunction, context: CheckerContext, reporter: DiagnosticReporter) { + if (!declaration.hasModifier(KtTokens.OVERRIDE_KEYWORD)) return + val source = declaration.source + if (source == null || source.kind is KtFakeSourceElementKind) return + + val containingClass = context.containingDeclarations.lastOrNull() as? FirClass ?: return + if (containingClass.classKind != ClassKind.OBJECT || !containingClass.hasModifier(KtTokens.DATA_KEYWORD)) return + + if ( + (declaration.name == OperatorNameConventions.HASH_CODE && declaration.valueParameters.isEmpty()) || + (declaration.name == OperatorNameConventions.EQUALS && + declaration.valueParameters.singleOrNull()?.returnTypeRef?.isNullableAny == true) + ) { + reporter.reportOn(source, FirErrors.DATA_OBJECT_CUSTOM_EQUALS_OR_HASH_CODE, context) + } + } +} diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirModifierChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirModifierChecker.kt index 6336f08cb88..e0b4850710b 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirModifierChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirModifierChecker.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration import org.jetbrains.kotlin.KtFakeSourceElementKind import org.jetbrains.kotlin.KtSourceElement +import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget.Companion.classActualTargets import org.jetbrains.kotlin.fir.analysis.checkers.FirModifier @@ -27,6 +28,7 @@ import org.jetbrains.kotlin.fir.declarations.utils.isLocal import org.jetbrains.kotlin.fir.languageVersionSettings import org.jetbrains.kotlin.lexer.KtModifierKeywordToken import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.lexer.KtTokens.DATA_KEYWORD import org.jetbrains.kotlin.resolve.* object FirModifierChecker : FirBasicDeclarationChecker() { @@ -182,7 +184,11 @@ object FirModifierChecker : FirBasicDeclarationChecker() { } val set = map[modifierToken] ?: emptySet() val checkResult = if (factory == FirErrors.WRONG_MODIFIER_TARGET) { - actualTargets.none { it in set } + actualTargets.none { it in set } || + // TODO: Implement some generic feature-checking mechanism + (modifierToken == DATA_KEYWORD + && actualTargets.contains(KotlinTarget.STANDALONE_OBJECT) + && !context.languageVersionSettings.supportsFeature(LanguageFeature.DataObjects)) } else { actualTargets.any { it in set } } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt index 5d63b7ce211..c07319a2e6c 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt @@ -136,6 +136,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DATA_CLASS_NOT_PR import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DATA_CLASS_OVERRIDE_CONFLICT import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DATA_CLASS_VARARG_PARAMETER import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DATA_CLASS_WITHOUT_PARAMETERS +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DATA_OBJECT_CUSTOM_EQUALS_OR_HASH_CODE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DECLARATION_CANT_BE_INLINED import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DELEGATED_PROPERTY_INSIDE_VALUE_CLASS @@ -579,7 +580,6 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_MODIFIER_TA import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_NUMBER_OF_TYPE_ARGUMENTS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_SETTER_PARAMETER_TYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_SETTER_RETURN_TYPE -import org.jetbrains.kotlin.psi.KtReferenceExpression @Suppress("unused") object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() { @@ -1456,6 +1456,7 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() { map.put(TAILREC_ON_VIRTUAL_MEMBER_ERROR, "Tailrec is not allowed on open members") map.put(NON_TAIL_RECURSIVE_CALL, "Recursive call is not a tail call") map.put(TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED, "Tail recursion optimization inside try/catch/finally is not supported") + map.put(DATA_OBJECT_CUSTOM_EQUALS_OR_HASH_CODE, "Data object cannot have a custom implementation of 'equals' or 'hashCode'") // Fun interfaces map.put(FUN_INTERFACE_CONSTRUCTOR_REFERENCE, "Functional/SAM interface constructor references are prohibited") 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 2c368212650..bdd019c264b 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 @@ -87,6 +87,7 @@ class DataClassMembersGenerator(val components: Fir2IrComponents) : Fir2IrCompon IrGeneratorContextBase(components.irBuiltIns), components.symbolTable, irClass, + irClass.kotlinFqName, origin ) { override fun declareSimpleFunction(startOffset: Int, endOffset: Int, functionDescriptor: FunctionDescriptor): IrFunction { @@ -183,9 +184,6 @@ class DataClassMembersGenerator(val components: Fir2IrComponents) : Fir2IrCompon fun generate(klass: FirClass): List { val propertyParametersCount = irClass.primaryConstructor?.explicitParameters?.size ?: 0 val properties = irClass.properties.filter { it.backingField != null }.take(propertyParametersCount).toList() - if (properties.isEmpty()) { - return emptyList() - } val result = mutableListOf() diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index e4f5d577be0..c4738d93d9f 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -13648,6 +13648,46 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT } } + @Nested + @TestMetadata("compiler/testData/codegen/box/dataObjects") + @TestDataPath("$PROJECT_ROOT") + public class DataObjects { + @Test + public void testAllFilesPresentInDataObjects() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/dataObjects"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); + } + + @Test + @TestMetadata("equals.kt") + public void testEquals() throws Exception { + runTest("compiler/testData/codegen/box/dataObjects/equals.kt"); + } + + @Test + @TestMetadata("hashCode.kt") + public void testHashCode() throws Exception { + runTest("compiler/testData/codegen/box/dataObjects/hashCode.kt"); + } + + @Test + @TestMetadata("multipleInstances.kt") + public void testMultipleInstances() throws Exception { + runTest("compiler/testData/codegen/box/dataObjects/multipleInstances.kt"); + } + + @Test + @TestMetadata("serialization.kt") + public void testSerialization() throws Exception { + runTest("compiler/testData/codegen/box/dataObjects/serialization.kt"); + } + + @Test + @TestMetadata("toString.kt") + public void testToString() throws Exception { + runTest("compiler/testData/codegen/box/dataObjects/toString.kt"); + } + } + @Nested @TestMetadata("compiler/testData/codegen/box/deadCodeElimination") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/BaseFirBuilder.kt b/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/BaseFirBuilder.kt index ce0846b9c14..bf2e6bc3a1c 100644 --- a/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/BaseFirBuilder.kt +++ b/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/BaseFirBuilder.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.builder import com.intellij.psi.tree.IElementType import org.jetbrains.kotlin.* import org.jetbrains.kotlin.KtNodeTypes.* +import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.fir.* @@ -38,6 +39,7 @@ import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.parsing.* +import org.jetbrains.kotlin.psi.KtObjectDeclaration import org.jetbrains.kotlin.psi.KtPsiUtil import org.jetbrains.kotlin.types.ConstantValueKind import org.jetbrains.kotlin.util.OperatorNameConventions @@ -1078,8 +1080,10 @@ abstract class BaseFirBuilder(val baseSession: FirSession, val context: Conte private val createParameterTypeRefWithSourceKind: (FirProperty, KtFakeSourceElementKind) -> FirTypeRef, ) { fun generate() { - generateComponentFunctions() - generateCopyFunction() + if (classBuilder.classKind != ClassKind.OBJECT) { + generateComponentFunctions() + generateCopyFunction() + } // Refer to (IR utils or FIR backend) DataClassMembersGenerator for generating equals, hashCode, and toString } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 50499fd0c96..8700376e570 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -737,6 +737,7 @@ public interface Errors { DiagnosticFactory0 DATA_CLASS_WITHOUT_PARAMETERS = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 DATA_CLASS_VARARG_PARAMETER = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 DATA_CLASS_NOT_PROPERTY_PARAMETER = DiagnosticFactory0.create(ERROR); + DiagnosticFactory0 DATA_OBJECT_CUSTOM_EQUALS_OR_HASH_CODE = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 CATCH_PARAMETER_WITH_DEFAULT_VALUE = DiagnosticFactory0.create(ERROR); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index 42472a0e461..364ee636a6f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -1058,6 +1058,7 @@ public class DefaultErrorMessages { MAP.put(DATA_CLASS_WITHOUT_PARAMETERS, "Data class must have at least one primary constructor parameter"); MAP.put(DATA_CLASS_VARARG_PARAMETER, "Primary constructor vararg parameters are forbidden for data classes"); MAP.put(DATA_CLASS_NOT_PROPERTY_PARAMETER, "Data class primary constructor must only have property (val / var) parameters"); + MAP.put(DATA_OBJECT_CUSTOM_EQUALS_OR_HASH_CODE, "Data object cannot have a custom implementation of 'equals' or 'hashCode'"); MAP.put(CATCH_PARAMETER_WITH_DEFAULT_VALUE, "Catch clause parameter may not have a default value"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt index ace2226013f..c9476042265 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt @@ -52,6 +52,7 @@ private val DEFAULT_DECLARATION_CHECKERS = listOf( ValueParameterUsageInDefaultArgumentChecker, CyclicAnnotationsChecker, UnsupportedUntilRangeDeclarationChecker, + DataObjectContentChecker, ) private val DEFAULT_CALL_CHECKERS = listOf( diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/DataClassDeclarationChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/DataClassDeclarationChecker.kt index 7821464f182..fe66ec8247b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/DataClassDeclarationChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/DataClassDeclarationChecker.kt @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.resolve.checkers import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.psi.KtClassOrObject @@ -27,7 +28,7 @@ class DataClassDeclarationChecker : DeclarationChecker { if (descriptor !is ClassDescriptor) return if (declaration !is KtClassOrObject) return - if (descriptor.isData) { + if (descriptor.isData && descriptor.kind == ClassKind.CLASS) { if (descriptor.unsubstitutedPrimaryConstructor == null && descriptor.constructors.isNotEmpty()) { declaration.nameIdentifier?.let { context.trace.report(Errors.PRIMARY_CONSTRUCTOR_REQUIRED_FOR_DATA_CLASS.on(it)) } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/DataObjectContentChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/DataObjectContentChecker.kt new file mode 100644 index 00000000000..66270fbad8a --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/DataObjectContentChecker.kt @@ -0,0 +1,38 @@ +/* + * 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.resolve.checkers + +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.util.OperatorNameConventions + +object DataObjectContentChecker : DeclarationChecker { + override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) { + if (descriptor !is FunctionDescriptor) return + if (descriptor.name != OperatorNameConventions.EQUALS && descriptor.name != OperatorNameConventions.HASH_CODE) return + + val container = descriptor.containingDeclaration + if (container !is ClassDescriptor) return + if (!container.isData || container.kind != ClassKind.OBJECT) return + + if (DescriptorUtils.getAllOverriddenDescriptors(descriptor).any(::isDeclaredInAny)) { + val target = declaration.modifierList?.getModifier(KtTokens.OVERRIDE_KEYWORD) ?: declaration + context.trace.report(Errors.DATA_OBJECT_CUSTOM_EQUALS_OR_HASH_CODE.on(target)) + } + } + + private fun isDeclaredInAny(descriptor: FunctionDescriptor): Boolean { + val container = descriptor.containingDeclaration + return container is ClassDescriptor && KotlinBuiltIns.isAny(container) + } +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassMemberScope.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassMemberScope.kt index 1062505010b..e015771731d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassMemberScope.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassMemberScope.kt @@ -482,7 +482,7 @@ open class LazyClassMemberScope( } private fun addDataClassMethods(result: MutableCollection, location: LookupLocation) { - if (!thisDescriptor.isData) return + if (!thisDescriptor.isData || thisDescriptor.kind != ClassKind.CLASS) return if (getPrimaryConstructor() == null) return diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/MethodsFromAnyGeneratorForLowerings.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/MethodsFromAnyGeneratorForLowerings.kt index 839ed894be0..a7839758af2 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/MethodsFromAnyGeneratorForLowerings.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/MethodsFromAnyGeneratorForLowerings.kt @@ -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 ) { diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt index 23cb79c3e19..8356fed4b8f 100644 --- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt +++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt @@ -353,6 +353,7 @@ private val jvmFilePhases = listOf( enumClassPhase, objectClassPhase, + readResolveForDataObjectsPhase, staticInitializersPhase, initializersPhase, initializersCleanupPhase, diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/ReadResolveForDataObjectsLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/ReadResolveForDataObjectsLowering.kt new file mode 100644 index 00000000000..8827f877475 --- /dev/null +++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/ReadResolveForDataObjectsLowering.kt @@ -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) } 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 facbe96a783..813c51665ab 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 @@ -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) 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 8f07c29c852..c071eb2180d 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 @@ -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) { + fun generateHashCodeMethodBody(properties: List, 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) { + 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) { 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) { buildMember(irFunction) { - generateHashCodeMethodBody(properties) + generateHashCodeMethodBody( + properties, + if (irClass.kind == ClassKind.OBJECT && irClass.isData) fqName.hashCode() else 0 + ) } } diff --git a/compiler/psi/src/org/jetbrains/kotlin/psi/KtClass.kt b/compiler/psi/src/org/jetbrains/kotlin/psi/KtClass.kt index 9c88e1c59df..f26366f0603 100644 --- a/compiler/psi/src/org/jetbrains/kotlin/psi/KtClass.kt +++ b/compiler/psi/src/org/jetbrains/kotlin/psi/KtClass.kt @@ -29,7 +29,6 @@ open class KtClass : KtClassOrObject { _stub?.isInterface() ?: (findChildByType(KtTokens.INTERFACE_KEYWORD) != null) fun isEnum(): Boolean = hasModifier(KtTokens.ENUM_KEYWORD) - fun isData(): Boolean = hasModifier(KtTokens.DATA_KEYWORD) fun isSealed(): Boolean = hasModifier(KtTokens.SEALED_KEYWORD) fun isInner(): Boolean = hasModifier(KtTokens.INNER_KEYWORD) fun isInline(): Boolean = hasModifier(KtTokens.INLINE_KEYWORD) diff --git a/compiler/psi/src/org/jetbrains/kotlin/psi/KtClassOrObject.kt b/compiler/psi/src/org/jetbrains/kotlin/psi/KtClassOrObject.kt index bbabbac5722..3cac8da612a 100644 --- a/compiler/psi/src/org/jetbrains/kotlin/psi/KtClassOrObject.kt +++ b/compiler/psi/src/org/jetbrains/kotlin/psi/KtClassOrObject.kt @@ -100,6 +100,8 @@ abstract class KtClassOrObject : override fun isLocal(): Boolean = stub?.isLocal() ?: KtPsiUtil.isLocal(this) + fun isData(): Boolean = hasModifier(KtTokens.DATA_KEYWORD) + override fun getDeclarations(): List = getBody()?.declarations.orEmpty() override fun getPresentation(): ItemPresentation? = ItemPresentationProviders.getItemPresentation(this) diff --git a/compiler/psi/src/org/jetbrains/kotlin/resolve/ModifierCheckerHelpers.kt b/compiler/psi/src/org/jetbrains/kotlin/resolve/ModifierCheckerHelpers.kt index 9215c557061..13ef31f428c 100644 --- a/compiler/psi/src/org/jetbrains/kotlin/resolve/ModifierCheckerHelpers.kt +++ b/compiler/psi/src/org/jetbrains/kotlin/resolve/ModifierCheckerHelpers.kt @@ -132,7 +132,8 @@ val featureDependencies = mapOf( EXPECT_KEYWORD to listOf(LanguageFeature.MultiPlatformProjects), ACTUAL_KEYWORD to listOf(LanguageFeature.MultiPlatformProjects), LATEINIT_KEYWORD to listOf(LanguageFeature.LateinitTopLevelProperties, LanguageFeature.LateinitLocalVariables), - FUN_KEYWORD to listOf(LanguageFeature.FunctionalInterfaceConversion) + FUN_KEYWORD to listOf(LanguageFeature.FunctionalInterfaceConversion), + DATA_KEYWORD to listOf(LanguageFeature.DataObjects) ) val featureDependenciesTargets = mapOf( @@ -141,7 +142,8 @@ val featureDependenciesTargets = mapOf( LanguageFeature.LateinitTopLevelProperties to setOf(KotlinTarget.TOP_LEVEL_PROPERTY), LanguageFeature.InlineClasses to setOf(KotlinTarget.CLASS_ONLY), LanguageFeature.JvmInlineValueClasses to setOf(KotlinTarget.CLASS_ONLY), - LanguageFeature.FunctionalInterfaceConversion to setOf(KotlinTarget.INTERFACE) + LanguageFeature.FunctionalInterfaceConversion to setOf(KotlinTarget.INTERFACE), + LanguageFeature.DataObjects to setOf(KotlinTarget.STANDALONE_OBJECT) ) val defaultVisibilityTargets: EnumSet = EnumSet.of( @@ -204,7 +206,7 @@ val possibleTargetMap = mapOf( KotlinTarget.LOCAL_VARIABLE, KotlinTarget.BACKING_FIELD ), - DATA_KEYWORD to EnumSet.of(KotlinTarget.CLASS_ONLY, KotlinTarget.LOCAL_CLASS), + DATA_KEYWORD to EnumSet.of(KotlinTarget.CLASS_ONLY, KotlinTarget.LOCAL_CLASS, KotlinTarget.STANDALONE_OBJECT), INLINE_KEYWORD to EnumSet.of( KotlinTarget.FUNCTION, KotlinTarget.PROPERTY, diff --git a/compiler/testData/codegen/box/dataObjects/equals.kt b/compiler/testData/codegen/box/dataObjects/equals.kt new file mode 100644 index 00000000000..90aa2ab8273 --- /dev/null +++ b/compiler/testData/codegen/box/dataObjects/equals.kt @@ -0,0 +1,15 @@ +// LANGUAGE: +DataObjects +// WITH_STDLIB + +package com.example + +import kotlin.test.* + +data object DataObject + +fun box(): String { + assertEquals(DataObject, DataObject) + assertFalse(DataObject == null) + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/dataObjects/hashCode.kt b/compiler/testData/codegen/box/dataObjects/hashCode.kt new file mode 100644 index 00000000000..ad2826e5e74 --- /dev/null +++ b/compiler/testData/codegen/box/dataObjects/hashCode.kt @@ -0,0 +1,19 @@ +// LANGUAGE: +DataObjects +// WITH_STDLIB + +package com.example + +import kotlin.test.* + +data object DataObject { + data object Inner +} + +fun box(): String { + assertEquals(DataObject.hashCode(), DataObject.hashCode()) + assertNotEquals(DataObject.hashCode(), DataObject.Inner.hashCode()) + assertNotEquals(0, DataObject.hashCode()) + assertNotEquals(0, DataObject.Inner.hashCode()) + + return "OK" +} diff --git a/compiler/testData/codegen/box/dataObjects/multipleInstances.kt b/compiler/testData/codegen/box/dataObjects/multipleInstances.kt new file mode 100644 index 00000000000..7b4c49e3550 --- /dev/null +++ b/compiler/testData/codegen/box/dataObjects/multipleInstances.kt @@ -0,0 +1,18 @@ +// LANGUAGE: +DataObjects +// WITH_STDLIB +// TARGET_BACKEND: JVM_IR + +import kotlin.test.* + +data object DataObject + +val doppelganger = DataObject::class.java.declaredConstructors[0].apply { isAccessible = true }.newInstance() + +fun box(): String { + assertFalse(DataObject === doppelganger) + assertEquals(DataObject, doppelganger) + assertEquals(DataObject.hashCode(), DataObject::class.java.cast(doppelganger).hashCode()) + + return "OK" +} + diff --git a/compiler/testData/codegen/box/dataObjects/serialization.kt b/compiler/testData/codegen/box/dataObjects/serialization.kt new file mode 100644 index 00000000000..62eb0d0495b --- /dev/null +++ b/compiler/testData/codegen/box/dataObjects/serialization.kt @@ -0,0 +1,19 @@ +// LANGUAGE: +DataObjects +// WITH_STDLIB +// TARGET_BACKEND: JVM_IR +// FULL_JDK +// CHECK_BYTECODE_LISTING + +import java.io.* + +data object NonSerializableDataObject + +data object SerializableDataObject: Serializable + +fun box(): String { + ByteArrayOutputStream().use { baos -> + ObjectOutputStream(baos).use { oos -> oos.writeObject(SerializableDataObject) } + ByteArrayInputStream(baos.toByteArray()).use { bais -> assert(java.io.ObjectInputStream(bais).readObject() === SerializableDataObject) } + } + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/dataObjects/serialization.txt b/compiler/testData/codegen/box/dataObjects/serialization.txt new file mode 100644 index 00000000000..429be3eb6e1 --- /dev/null +++ b/compiler/testData/codegen/box/dataObjects/serialization.txt @@ -0,0 +1,28 @@ +@kotlin.Metadata +public final class NonSerializableDataObject { + // source: 'serialization.kt' + public final static @org.jetbrains.annotations.NotNull field INSTANCE: NonSerializableDataObject + static method (): void + private method (): void + public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean + public method hashCode(): int + public @org.jetbrains.annotations.NotNull method toString(): java.lang.String +} + +@kotlin.Metadata +public final class SerializableDataObject { + // source: 'serialization.kt' + public final static @org.jetbrains.annotations.NotNull field INSTANCE: SerializableDataObject + static method (): void + private method (): void + public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean + public method hashCode(): int + private final method readResolve(): java.lang.Object + public @org.jetbrains.annotations.NotNull method toString(): java.lang.String +} + +@kotlin.Metadata +public final class SerializationKt { + // source: 'serialization.kt' + public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String +} diff --git a/compiler/testData/codegen/box/dataObjects/toString.kt b/compiler/testData/codegen/box/dataObjects/toString.kt new file mode 100644 index 00000000000..7819b09f338 --- /dev/null +++ b/compiler/testData/codegen/box/dataObjects/toString.kt @@ -0,0 +1,52 @@ +// LANGUAGE: +DataObjects +// WITH_STDLIB + +package com.example + +import kotlin.test.* + +data object DataObject { + data object Nested +} + +class Foo { + data object Inner +} + +data object Declared { + override fun toString() = "Overriden" +} + +open class WithFinalToString { + final override fun toString() = "FinalToString" +} + +data object InheritedFromClassWithFinalToString: WithFinalToString() + +open class WithOpenToString { + override fun toString() = "OpenToString" +} + +data object InheritedFromClassWithOpenToString: WithOpenToString() + +abstract class WithAbstractToString { + abstract override fun toString(): String +} + +data object InheritedFromClassWithAbstractToString : WithAbstractToString() + +class C { + companion object CC +} + +fun box(): String { + assertEquals("DataObject", DataObject.toString()) + assertEquals("Nested", DataObject.Nested.toString()) + assertEquals("Inner", Foo.Inner.toString()) + assertEquals("Overriden", Declared.toString()) + assertEquals("FinalToString", InheritedFromClassWithFinalToString.toString()) + assertEquals("InheritedFromClassWithOpenToString", InheritedFromClassWithOpenToString.toString()) + assertEquals("InheritedFromClassWithAbstractToString", InheritedFromClassWithAbstractToString.toString()) + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/dataClasses/companionDataObject.kt b/compiler/testData/diagnostics/tests/dataClasses/companionDataObject.kt new file mode 100644 index 00000000000..8d7726bc158 --- /dev/null +++ b/compiler/testData/diagnostics/tests/dataClasses/companionDataObject.kt @@ -0,0 +1,6 @@ +// FIR_IDENTICAL +// LANGUAGE: +DataObjects + +class C { + companion data object Object +} diff --git a/compiler/testData/diagnostics/tests/dataClasses/companionDataObject.txt b/compiler/testData/diagnostics/tests/dataClasses/companionDataObject.txt new file mode 100644 index 00000000000..cf0fb1aff53 --- /dev/null +++ b/compiler/testData/diagnostics/tests/dataClasses/companionDataObject.txt @@ -0,0 +1,16 @@ +package + +public final class C { + public constructor C() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public data companion object Object { + private constructor Object() + public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String + } +} + diff --git a/compiler/testData/diagnostics/tests/dataClasses/dataObject.kt b/compiler/testData/diagnostics/tests/dataClasses/dataObject.kt deleted file mode 100644 index 2c99760e047..00000000000 --- a/compiler/testData/diagnostics/tests/dataClasses/dataObject.kt +++ /dev/null @@ -1,2 +0,0 @@ -// FIR_IDENTICAL -data object Object(val x: Int, val y: Int) diff --git a/compiler/testData/diagnostics/tests/dataClasses/dataObject.txt b/compiler/testData/diagnostics/tests/dataClasses/dataObject.txt deleted file mode 100644 index b270a54a34b..00000000000 --- a/compiler/testData/diagnostics/tests/dataClasses/dataObject.txt +++ /dev/null @@ -1,13 +0,0 @@ -package - -public data object Object { - private constructor Object(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.Int) - public final val x: kotlin.Int - public final val y: kotlin.Int - public final operator /*synthesized*/ fun component1(): kotlin.Int - public final operator /*synthesized*/ fun component2(): kotlin.Int - public final /*synthesized*/ fun copy(/*0*/ x: kotlin.Int = ..., /*1*/ y: kotlin.Int = ...): Object - public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean - public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int - public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String -} diff --git a/compiler/testData/diagnostics/tests/dataClasses/dataObjectDisabled.fir.kt b/compiler/testData/diagnostics/tests/dataClasses/dataObjectDisabled.fir.kt new file mode 100644 index 00000000000..dfa99eac273 --- /dev/null +++ b/compiler/testData/diagnostics/tests/dataClasses/dataObjectDisabled.fir.kt @@ -0,0 +1,2 @@ +// LANGUAGE: -DataObjects +data object Object diff --git a/compiler/testData/diagnostics/tests/dataClasses/dataObjectDisabled.kt b/compiler/testData/diagnostics/tests/dataClasses/dataObjectDisabled.kt new file mode 100644 index 00000000000..782e17fd6ae --- /dev/null +++ b/compiler/testData/diagnostics/tests/dataClasses/dataObjectDisabled.kt @@ -0,0 +1,2 @@ +// LANGUAGE: -DataObjects +data object Object diff --git a/compiler/testData/diagnostics/tests/dataClasses/dataObjectDisabled.txt b/compiler/testData/diagnostics/tests/dataClasses/dataObjectDisabled.txt new file mode 100644 index 00000000000..71427a290cc --- /dev/null +++ b/compiler/testData/diagnostics/tests/dataClasses/dataObjectDisabled.txt @@ -0,0 +1,9 @@ +package + +public data object Object { + private constructor Object() + public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String +} + diff --git a/compiler/testData/diagnostics/tests/dataClasses/dataObjectEnabled.kt b/compiler/testData/diagnostics/tests/dataClasses/dataObjectEnabled.kt new file mode 100644 index 00000000000..40469750931 --- /dev/null +++ b/compiler/testData/diagnostics/tests/dataClasses/dataObjectEnabled.kt @@ -0,0 +1,3 @@ +// LANGUAGE: +DataObjects +// FIR_IDENTICAL +data object Object diff --git a/compiler/testData/diagnostics/tests/dataClasses/dataObjectEnabled.txt b/compiler/testData/diagnostics/tests/dataClasses/dataObjectEnabled.txt new file mode 100644 index 00000000000..71427a290cc --- /dev/null +++ b/compiler/testData/diagnostics/tests/dataClasses/dataObjectEnabled.txt @@ -0,0 +1,9 @@ +package + +public data object Object { + private constructor Object() + public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String +} + diff --git a/compiler/testData/diagnostics/tests/dataClasses/dataObjectLiteral.kt b/compiler/testData/diagnostics/tests/dataClasses/dataObjectLiteral.kt new file mode 100644 index 00000000000..c80e42faed9 --- /dev/null +++ b/compiler/testData/diagnostics/tests/dataClasses/dataObjectLiteral.kt @@ -0,0 +1,10 @@ +// FIR_IDENTICAL +// LANGUAGE: +DataObjects + +interface I { + fun foo() +} + +val o = data object: I { + override fun foo() {} +} diff --git a/compiler/testData/diagnostics/tests/dataClasses/dataObjectLiteral.txt b/compiler/testData/diagnostics/tests/dataClasses/dataObjectLiteral.txt new file mode 100644 index 00000000000..f624cf46ab7 --- /dev/null +++ b/compiler/testData/diagnostics/tests/dataClasses/dataObjectLiteral.txt @@ -0,0 +1,18 @@ +package + +public val o: [Error type: Not found recorded type for data] + +public object `` : I { + private constructor ``() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface I { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/dataClasses/strange.kt b/compiler/testData/diagnostics/tests/dataClasses/strange.kt index a181e424b2d..0998adc6335 100644 --- a/compiler/testData/diagnostics/tests/dataClasses/strange.kt +++ b/compiler/testData/diagnostics/tests/dataClasses/strange.kt @@ -3,8 +3,8 @@ B(2) } -data object Second +data object Second -data interface Third +data interface Third -data annotation class Fourth(val x: Int) \ No newline at end of file +data annotation class Fourth(val x: Int) diff --git a/compiler/testData/diagnostics/tests/dataClasses/strange.txt b/compiler/testData/diagnostics/tests/dataClasses/strange.txt index 7531d4d5010..57fd6e3beac 100644 --- a/compiler/testData/diagnostics/tests/dataClasses/strange.txt +++ b/compiler/testData/diagnostics/tests/dataClasses/strange.txt @@ -11,8 +11,6 @@ public final data enum class First : kotlin.Enum { public final val x: kotlin.Int protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: First): kotlin.Int - public final operator /*synthesized*/ fun component1(): kotlin.Int - public final /*synthesized*/ fun copy(/*0*/ x: kotlin.Int = ...): First public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean protected/*protected and package*/ final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit public final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class! @@ -27,8 +25,6 @@ public final data enum class First : kotlin.Enum { public final data annotation class Fourth : kotlin.Annotation { public constructor Fourth(/*0*/ x: kotlin.Int) public final val x: kotlin.Int - public final operator /*synthesized*/ fun component1(): kotlin.Int - public final /*synthesized*/ fun copy(/*0*/ x: kotlin.Int = ...): Fourth public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String @@ -36,7 +32,6 @@ public final data annotation class Fourth : kotlin.Annotation { public data object Second { private constructor Second() - public final /*synthesized*/ fun copy(): Second public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String @@ -47,3 +42,4 @@ public data interface Third { public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } + diff --git a/compiler/testData/diagnostics/tests/dataObjects/overrideEqualsAndHashCode.kt b/compiler/testData/diagnostics/tests/dataObjects/overrideEqualsAndHashCode.kt new file mode 100644 index 00000000000..a3a780b1c6a --- /dev/null +++ b/compiler/testData/diagnostics/tests/dataObjects/overrideEqualsAndHashCode.kt @@ -0,0 +1,44 @@ +// FIR_IDENTICAL +// LANGUAGE: +DataObjects + +data object Override { + override fun equals(other: Any?): Boolean { + return true + } + + override fun hashCode(): Int { + return 1 + } +} + +open class Base { + open fun hashCode(x: Int) = x +} + +data object NoOverride: Base() { + fun equals(other: Any?, tag: Int): Boolean { + return true + } + + fun hashCode(param: String): Int { + return 1 + } + + override fun hashCode(x: Int) = x + 1 +} + +open class Super { + override fun equals(other: Any?): Boolean { + return super.equals(other) + } + + override fun hashCode(): Int { + return 1 + } +} + +data object OverridenInSuper: Super() { + override fun equals(other: Any?): Boolean { + return super.equals(other) + } +} diff --git a/compiler/testData/diagnostics/tests/dataObjects/overrideEqualsAndHashCode.txt b/compiler/testData/diagnostics/tests/dataObjects/overrideEqualsAndHashCode.txt new file mode 100644 index 00000000000..49dfff5aea2 --- /dev/null +++ b/compiler/testData/diagnostics/tests/dataObjects/overrideEqualsAndHashCode.txt @@ -0,0 +1,40 @@ +package + +public open class Base { + public constructor Base() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open fun hashCode(/*0*/ x: kotlin.Int): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public data object NoOverride : Base { + private constructor NoOverride() + public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final fun equals(/*0*/ other: kotlin.Any?, /*1*/ tag: kotlin.Int): kotlin.Boolean + public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int + public open override /*1*/ fun hashCode(/*0*/ x: kotlin.Int): kotlin.Int + public final fun hashCode(/*0*/ param: kotlin.String): kotlin.Int + public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String +} + +public data object Override { + private constructor Override() + public open override /*1*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String +} + +public data object OverridenInSuper : Super { + private constructor OverridenInSuper() + public open override /*1*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String +} + +public open class Super { + public constructor Super() + public open override /*1*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/testsWithJvmBackend/dataObjects/customReadResolve.kt b/compiler/testData/diagnostics/testsWithJvmBackend/dataObjects/customReadResolve.kt new file mode 100644 index 00000000000..a4d5363c881 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithJvmBackend/dataObjects/customReadResolve.kt @@ -0,0 +1,16 @@ +// !LANGUAGE: +DataObjects +// TARGET_BACKEND: JVM_IR + +import java.io.Serializable + +data object A : Serializable { + private fun readResolve(): Any = this +} + +data object B : Serializable { + private fun readResolve(): B = this +} + +data object C { + private fun readResolve(): Any = this +} diff --git a/compiler/testData/diagnostics/testsWithJvmBackend/dataObjects/customReadResolve.txt b/compiler/testData/diagnostics/testsWithJvmBackend/dataObjects/customReadResolve.txt new file mode 100644 index 00000000000..ec615f4d4c5 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithJvmBackend/dataObjects/customReadResolve.txt @@ -0,0 +1,26 @@ +package + +public data object A : java.io.Serializable { + private constructor A() + public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int + private final fun readResolve(): kotlin.Any + public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String +} + +public data object B : java.io.Serializable { + private constructor B() + public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int + private final fun readResolve(): B + public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String +} + +public data object C { + private constructor C() + public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int + private final fun readResolve(): kotlin.Any + public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String +} + diff --git a/compiler/testData/ir/irText/declarations/parameters/dataClassMembers.fir.kt.txt b/compiler/testData/ir/irText/declarations/parameters/dataClassMembers.fir.kt.txt index 99ac9bd8cf6..6d3ce06ec60 100644 --- a/compiler/testData/ir/irText/declarations/parameters/dataClassMembers.fir.kt.txt +++ b/compiler/testData/ir/irText/declarations/parameters/dataClassMembers.fir.kt.txt @@ -56,3 +56,4 @@ data class Test { } } + diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index 7337e3d46c5..0117bd25956 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -6962,6 +6962,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/dataClasses"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); } + @Test + @TestMetadata("companionDataObject.kt") + public void testCompanionDataObject() throws Exception { + runTest("compiler/testData/diagnostics/tests/dataClasses/companionDataObject.kt"); + } + @Test @TestMetadata("componentNamedComponent1.kt") public void testComponentNamedComponent1() throws Exception { @@ -7035,9 +7041,21 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { } @Test - @TestMetadata("dataObject.kt") - public void testDataObject() throws Exception { - runTest("compiler/testData/diagnostics/tests/dataClasses/dataObject.kt"); + @TestMetadata("dataObjectDisabled.kt") + public void testDataObjectDisabled() throws Exception { + runTest("compiler/testData/diagnostics/tests/dataClasses/dataObjectDisabled.kt"); + } + + @Test + @TestMetadata("dataObjectEnabled.kt") + public void testDataObjectEnabled() throws Exception { + runTest("compiler/testData/diagnostics/tests/dataClasses/dataObjectEnabled.kt"); + } + + @Test + @TestMetadata("dataObjectLiteral.kt") + public void testDataObjectLiteral() throws Exception { + runTest("compiler/testData/diagnostics/tests/dataClasses/dataObjectLiteral.kt"); } @Test @@ -7661,6 +7679,22 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { } } + @Nested + @TestMetadata("compiler/testData/diagnostics/tests/dataObjects") + @TestDataPath("$PROJECT_ROOT") + public class DataObjects { + @Test + public void testAllFilesPresentInDataObjects() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/dataObjects"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); + } + + @Test + @TestMetadata("overrideEqualsAndHashCode.kt") + public void testOverrideEqualsAndHashCode() throws Exception { + runTest("compiler/testData/diagnostics/tests/dataObjects/overrideEqualsAndHashCode.kt"); + } + } + @Nested @TestMetadata("compiler/testData/diagnostics/tests/declarationChecks") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticsTestWithJvmIrBackendGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticsTestWithJvmIrBackendGenerated.java index 4d184255629..c1de6f25a04 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticsTestWithJvmIrBackendGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticsTestWithJvmIrBackendGenerated.java @@ -61,6 +61,22 @@ public class DiagnosticsTestWithJvmIrBackendGenerated extends AbstractDiagnostic runTest("compiler/testData/diagnostics/testsWithJvmBackend/suspendInlineCycle_ir.kt"); } + @Nested + @TestMetadata("compiler/testData/diagnostics/testsWithJvmBackend/dataObjects") + @TestDataPath("$PROJECT_ROOT") + public class DataObjects { + @Test + public void testAllFilesPresentInDataObjects() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/testsWithJvmBackend/dataObjects"), Pattern.compile("^(.+)\\.kts?$"), null, TargetBackend.JVM_IR, true); + } + + @Test + @TestMetadata("customReadResolve.kt") + public void testCustomReadResolve() throws Exception { + runTest("compiler/testData/diagnostics/testsWithJvmBackend/dataObjects/customReadResolve.kt"); + } + } + @Nested @TestMetadata("compiler/testData/diagnostics/testsWithJvmBackend/duplicateJvmSignature") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticsTestWithOldJvmBackendGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticsTestWithOldJvmBackendGenerated.java index 038a0d505f7..573d9c4f20b 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticsTestWithOldJvmBackendGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticsTestWithOldJvmBackendGenerated.java @@ -61,6 +61,16 @@ public class DiagnosticsTestWithOldJvmBackendGenerated extends AbstractDiagnosti runTest("compiler/testData/diagnostics/testsWithJvmBackend/suspendInlineCycle.kt"); } + @Nested + @TestMetadata("compiler/testData/diagnostics/testsWithJvmBackend/dataObjects") + @TestDataPath("$PROJECT_ROOT") + public class DataObjects { + @Test + public void testAllFilesPresentInDataObjects() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/testsWithJvmBackend/dataObjects"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_OLD, true); + } + } + @Nested @TestMetadata("compiler/testData/diagnostics/testsWithJvmBackend/duplicateJvmSignature") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index 310bcc0cf2a..bf84b14cd68 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -13528,6 +13528,34 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { } } + @Nested + @TestMetadata("compiler/testData/codegen/box/dataObjects") + @TestDataPath("$PROJECT_ROOT") + public class DataObjects { + @Test + public void testAllFilesPresentInDataObjects() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/dataObjects"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); + } + + @Test + @TestMetadata("equals.kt") + public void testEquals() throws Exception { + runTest("compiler/testData/codegen/box/dataObjects/equals.kt"); + } + + @Test + @TestMetadata("hashCode.kt") + public void testHashCode() throws Exception { + runTest("compiler/testData/codegen/box/dataObjects/hashCode.kt"); + } + + @Test + @TestMetadata("toString.kt") + public void testToString() throws Exception { + runTest("compiler/testData/codegen/box/dataObjects/toString.kt"); + } + } + @Nested @TestMetadata("compiler/testData/codegen/box/deadCodeElimination") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index b3c8351d781..7cbcafde2db 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -13648,6 +13648,46 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes } } + @Nested + @TestMetadata("compiler/testData/codegen/box/dataObjects") + @TestDataPath("$PROJECT_ROOT") + public class DataObjects { + @Test + public void testAllFilesPresentInDataObjects() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/dataObjects"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); + } + + @Test + @TestMetadata("equals.kt") + public void testEquals() throws Exception { + runTest("compiler/testData/codegen/box/dataObjects/equals.kt"); + } + + @Test + @TestMetadata("hashCode.kt") + public void testHashCode() throws Exception { + runTest("compiler/testData/codegen/box/dataObjects/hashCode.kt"); + } + + @Test + @TestMetadata("multipleInstances.kt") + public void testMultipleInstances() throws Exception { + runTest("compiler/testData/codegen/box/dataObjects/multipleInstances.kt"); + } + + @Test + @TestMetadata("serialization.kt") + public void testSerialization() throws Exception { + runTest("compiler/testData/codegen/box/dataObjects/serialization.kt"); + } + + @Test + @TestMetadata("toString.kt") + public void testToString() throws Exception { + runTest("compiler/testData/codegen/box/dataObjects/toString.kt"); + } + } + @Nested @TestMetadata("compiler/testData/codegen/box/deadCodeElimination") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index fed2f7327c8..aaa88745d14 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -10981,6 +10981,34 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes } } + @TestMetadata("compiler/testData/codegen/box/dataObjects") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class DataObjects extends AbstractLightAnalysisModeTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); + } + + public void testAllFilesPresentInDataObjects() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/dataObjects"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); + } + + @TestMetadata("equals.kt") + public void testEquals() throws Exception { + runTest("compiler/testData/codegen/box/dataObjects/equals.kt"); + } + + @TestMetadata("hashCode.kt") + public void testHashCode() throws Exception { + runTest("compiler/testData/codegen/box/dataObjects/hashCode.kt"); + } + + @TestMetadata("toString.kt") + public void testToString() throws Exception { + runTest("compiler/testData/codegen/box/dataObjects/toString.kt"); + } + } + @TestMetadata("compiler/testData/codegen/box/deadCodeElimination") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt index be45645232c..c96fe945714 100644 --- a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt +++ b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt @@ -263,6 +263,7 @@ enum class LanguageFeature( RefineTypeCheckingOnAssignmentsToJavaFields(KOTLIN_1_8, kind = BUG_FIX), RangeUntilOperator(KOTLIN_1_8), // KT-15613 GenericInlineClassParameter(sinceVersion = KOTLIN_1_8, kind = UNSTABLE_FEATURE), // KT-32162 + DataObjects(KOTLIN_1_8), // KT-4107 // 1.9 diff --git a/core/compiler.common/src/org/jetbrains/kotlin/descriptors/annotations/KotlinTarget.kt b/core/compiler.common/src/org/jetbrains/kotlin/descriptors/annotations/KotlinTarget.kt index b9525cb1b51..61bf33bba97 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/descriptors/annotations/KotlinTarget.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/descriptors/annotations/KotlinTarget.kt @@ -34,8 +34,9 @@ enum class KotlinTarget(val description: String, val isDefault: Boolean = true) // includes only top level classes and nested/inner classes (but not enums, objects, interfaces and local classes) CLASS_ONLY("class", false), - // does not include OBJECT_LITERAL but DOES include COMPANION_OBJECT + // does not include OBJECT_LITERAL but DOES include both STANDALONE_OBJECT and COMPANION_OBJECT OBJECT("object", false), + STANDALONE_OBJECT("standalone object", false), COMPANION_OBJECT("companion object", false), INTERFACE("interface", false), ENUM_CLASS("enum class", false), @@ -84,7 +85,7 @@ enum class KotlinTarget(val description: String, val isDefault: Boolean = true) val LOCAL_CLASS_LIST = listOf(LOCAL_CLASS, CLASS) val CLASS_LIST = listOf(CLASS_ONLY, CLASS) val COMPANION_OBJECT_LIST = listOf(COMPANION_OBJECT, OBJECT, CLASS) - val OBJECT_LIST = listOf(OBJECT, CLASS) + val OBJECT_LIST = listOf(STANDALONE_OBJECT, OBJECT, CLASS) val INTERFACE_LIST = listOf(INTERFACE, CLASS) val ENUM_LIST = listOf(ENUM_CLASS, CLASS) val ENUM_ENTRY_LIST = listOf(ENUM_ENTRY, PROPERTY, FIELD) diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java index c61fa00228e..48080389343 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java @@ -10116,6 +10116,34 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { } } + @Nested + @TestMetadata("compiler/testData/codegen/box/dataObjects") + @TestDataPath("$PROJECT_ROOT") + public class DataObjects { + @Test + public void testAllFilesPresentInDataObjects() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/dataObjects"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true); + } + + @Test + @TestMetadata("equals.kt") + public void testEquals() throws Exception { + runTest("compiler/testData/codegen/box/dataObjects/equals.kt"); + } + + @Test + @TestMetadata("hashCode.kt") + public void testHashCode() throws Exception { + runTest("compiler/testData/codegen/box/dataObjects/hashCode.kt"); + } + + @Test + @TestMetadata("toString.kt") + public void testToString() throws Exception { + runTest("compiler/testData/codegen/box/dataObjects/toString.kt"); + } + } + @Nested @TestMetadata("compiler/testData/codegen/box/deadCodeElimination") @TestDataPath("$PROJECT_ROOT") diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java index 7018d4dd62e..8ee5a658539 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java @@ -10158,6 +10158,34 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { } } + @Nested + @TestMetadata("compiler/testData/codegen/box/dataObjects") + @TestDataPath("$PROJECT_ROOT") + public class DataObjects { + @Test + public void testAllFilesPresentInDataObjects() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/dataObjects"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true); + } + + @Test + @TestMetadata("equals.kt") + public void testEquals() throws Exception { + runTest("compiler/testData/codegen/box/dataObjects/equals.kt"); + } + + @Test + @TestMetadata("hashCode.kt") + public void testHashCode() throws Exception { + runTest("compiler/testData/codegen/box/dataObjects/hashCode.kt"); + } + + @Test + @TestMetadata("toString.kt") + public void testToString() throws Exception { + runTest("compiler/testData/codegen/box/dataObjects/toString.kt"); + } + } + @Nested @TestMetadata("compiler/testData/codegen/box/deadCodeElimination") @TestDataPath("$PROJECT_ROOT") diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java index 623c73fe145..108acbd2025 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java @@ -8996,6 +8996,34 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest } } + @TestMetadata("compiler/testData/codegen/box/dataObjects") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class DataObjects extends AbstractIrCodegenBoxWasmTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath); + } + + public void testAllFilesPresentInDataObjects() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/dataObjects"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.WASM, true); + } + + @TestMetadata("equals.kt") + public void testEquals() throws Exception { + runTest("compiler/testData/codegen/box/dataObjects/equals.kt"); + } + + @TestMetadata("hashCode.kt") + public void testHashCode() throws Exception { + runTest("compiler/testData/codegen/box/dataObjects/hashCode.kt"); + } + + @TestMetadata("toString.kt") + public void testToString() throws Exception { + runTest("compiler/testData/codegen/box/dataObjects/toString.kt"); + } + } + @TestMetadata("compiler/testData/codegen/box/deadCodeElimination") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/JsEqualsHashcodeToStringGenerator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/JsEqualsHashcodeToStringGenerator.java index 22ada7de42d..f71b7552080 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/JsEqualsHashcodeToStringGenerator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/JsEqualsHashcodeToStringGenerator.java @@ -16,7 +16,9 @@ import org.jetbrains.kotlin.js.backend.ast.*; import org.jetbrains.kotlin.js.translate.context.TranslationContext; import org.jetbrains.kotlin.js.translate.utils.JsAstUtils; import org.jetbrains.kotlin.js.translate.utils.UtilsKt; +import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.psi.KtClassOrObject; +import org.jetbrains.kotlin.psi.KtObjectDeclaration; import org.jetbrains.kotlin.psi.KtParameter; import org.jetbrains.kotlin.resolve.source.PsiSourceElementKt; @@ -35,6 +37,11 @@ abstract class JsEqualsHashcodeToStringGenerator extends DataClassMethodGenerato @Override public void generateToStringMethod(@NotNull FunctionDescriptor function, @NotNull List classProperties) { + if (getDeclaration() instanceof KtObjectDeclaration) { + generateJsMethod(function).getBody().getStatements().add(new JsReturn(new JsStringLiteral(getDeclaration().getName()))); + return; + } + // TODO: relax this limitation, with the data generation logic fixed. assert !classProperties.isEmpty(); JsFunction functionObj = generateJsMethod(function); @@ -65,6 +72,14 @@ abstract class JsEqualsHashcodeToStringGenerator extends DataClassMethodGenerato @Override public void generateHashCodeMethod(@NotNull FunctionDescriptor function, @NotNull List classProperties) { JsFunction functionObj = generateJsMethod(function); + if (classProperties.isEmpty()) { + FqName fqName = getDeclaration().getFqName(); + JsExpression returnExpression = new JsIntLiteral(fqName != null ? fqName.hashCode() : 0); + JsReturn returnStatement = new JsReturn(returnExpression); + returnStatement.setSource(getDeclaration()); + functionObj.getBody().getStatements().add(returnStatement); + return; + } List statements = functionObj.getBody().getStatements(); @@ -92,8 +107,8 @@ abstract class JsEqualsHashcodeToStringGenerator extends DataClassMethodGenerato @Override public void generateEqualsMethod(@NotNull FunctionDescriptor function, @NotNull List classProperties) { - assert !classProperties.isEmpty(); JsFunction functionObj = generateJsMethod(function); + JsFunctionScope funScope = functionObj.getScope(); JsName paramName = funScope.declareName("other"); @@ -120,9 +135,8 @@ abstract class JsEqualsHashcodeToStringGenerator extends DataClassMethodGenerato fieldChain = and(fieldChain, next); } } - assert fieldChain != null; - JsExpression returnExpression = or(referenceEqual, and(isNotNull, and(otherIsObject, and(prototypeEqual, fieldChain)))); + JsExpression returnExpression = or(referenceEqual, and(isNotNull, and(otherIsObject, fieldChain != null ? and(prototypeEqual, fieldChain) : prototypeEqual))); JsReturn returnStatement = new JsReturn(returnExpression); returnStatement.setSource(getDeclaration()); functionObj.getBody().getStatements().add(returnStatement); diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java index 9dd93e72829..dfa5f1b6b37 100644 --- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java @@ -11102,6 +11102,36 @@ public class NativeCodegenBoxTestGenerated extends AbstractNativeCodegenBoxTest } } + @Nested + @TestMetadata("compiler/testData/codegen/box/dataObjects") + @TestDataPath("$PROJECT_ROOT") + @Tag("codegen") + @UseExtTestCaseGroupProvider() + public class DataObjects { + @Test + public void testAllFilesPresentInDataObjects() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/dataObjects"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true); + } + + @Test + @TestMetadata("equals.kt") + public void testEquals() throws Exception { + runTest("compiler/testData/codegen/box/dataObjects/equals.kt"); + } + + @Test + @TestMetadata("hashCode.kt") + public void testHashCode() throws Exception { + runTest("compiler/testData/codegen/box/dataObjects/hashCode.kt"); + } + + @Test + @TestMetadata("toString.kt") + public void testToString() throws Exception { + runTest("compiler/testData/codegen/box/dataObjects/toString.kt"); + } + } + @Nested @TestMetadata("compiler/testData/codegen/box/deadCodeElimination") @TestDataPath("$PROJECT_ROOT") diff --git a/plugins/kapt3/kapt3-compiler/testData/converter/nestedClasses2.kt b/plugins/kapt3/kapt3-compiler/testData/converter/nestedClasses2.kt index 47748c47fc6..3c90a9a3c12 100644 --- a/plugins/kapt3/kapt3-compiler/testData/converter/nestedClasses2.kt +++ b/plugins/kapt3/kapt3-compiler/testData/converter/nestedClasses2.kt @@ -32,7 +32,7 @@ class Experiment { annotation class Type @Type - data class Group(s: String) + data class Group(var s: String) } class Foo { diff --git a/plugins/kapt3/kapt3-compiler/testData/converter/nestedClasses2.txt b/plugins/kapt3/kapt3-compiler/testData/converter/nestedClasses2.txt index d59a60be5cd..b954ee0bd8a 100644 --- a/plugins/kapt3/kapt3-compiler/testData/converter/nestedClasses2.txt +++ b/plugins/kapt3/kapt3-compiler/testData/converter/nestedClasses2.txt @@ -100,6 +100,8 @@ public final class Experiment { @kotlin.Metadata() @Experiment.Type() public static final class Group { + @org.jetbrains.annotations.NotNull() + private java.lang.String s; @org.jetbrains.annotations.NotNull() public final Experiment.Group copy(@org.jetbrains.annotations.NotNull() @@ -107,10 +109,41 @@ public final class Experiment { return null; } + @java.lang.Override() + public boolean equals(@org.jetbrains.annotations.Nullable() + java.lang.Object other) { + return false; + } + + @java.lang.Override() + public int hashCode() { + return 0; + } + + @org.jetbrains.annotations.NotNull() + @java.lang.Override() + public java.lang.String toString() { + return null; + } + public Group(@org.jetbrains.annotations.NotNull() java.lang.String s) { super(); } + + @org.jetbrains.annotations.NotNull() + public final java.lang.String component1() { + return null; + } + + @org.jetbrains.annotations.NotNull() + public final java.lang.String getS() { + return null; + } + + public final void setS(@org.jetbrains.annotations.NotNull() + java.lang.String p0) { + } } } diff --git a/plugins/kapt3/kapt3-compiler/testData/converter/nestedClasses2_ir.txt b/plugins/kapt3/kapt3-compiler/testData/converter/nestedClasses2_ir.txt index 3805239f566..cf445ac6b6e 100644 --- a/plugins/kapt3/kapt3-compiler/testData/converter/nestedClasses2_ir.txt +++ b/plugins/kapt3/kapt3-compiler/testData/converter/nestedClasses2_ir.txt @@ -100,12 +100,28 @@ public final class Experiment { @kotlin.Metadata() @Experiment.Type() public static final class Group { + @org.jetbrains.annotations.NotNull() + private java.lang.String s; public Group(@org.jetbrains.annotations.NotNull() java.lang.String s) { super(); } + @org.jetbrains.annotations.NotNull() + public final java.lang.String getS() { + return null; + } + + public final void setS(@org.jetbrains.annotations.NotNull() + java.lang.String p0) { + } + + @org.jetbrains.annotations.NotNull() + public final java.lang.String component1() { + return null; + } + @org.jetbrains.annotations.NotNull() public final Experiment.Group copy(@org.jetbrains.annotations.NotNull() java.lang.String s) { diff --git a/plugins/kapt3/kapt3-compiler/testData/converter/nestedClassesNonRootPackage.kt b/plugins/kapt3/kapt3-compiler/testData/converter/nestedClassesNonRootPackage.kt index 22d71e13f2c..e9223f4278f 100644 --- a/plugins/kapt3/kapt3-compiler/testData/converter/nestedClassesNonRootPackage.kt +++ b/plugins/kapt3/kapt3-compiler/testData/converter/nestedClassesNonRootPackage.kt @@ -38,7 +38,7 @@ class Experiment { annotation class Type @Type - data class Group(s: String) + data class Group(val s: String) } class Foo { diff --git a/plugins/kapt3/kapt3-compiler/testData/converter/nestedClassesNonRootPackage.txt b/plugins/kapt3/kapt3-compiler/testData/converter/nestedClassesNonRootPackage.txt index d720558f1e6..e743d183b3d 100644 --- a/plugins/kapt3/kapt3-compiler/testData/converter/nestedClassesNonRootPackage.txt +++ b/plugins/kapt3/kapt3-compiler/testData/converter/nestedClassesNonRootPackage.txt @@ -103,6 +103,8 @@ public final class Experiment { @kotlin.Metadata() @test.Experiment.Type() public static final class Group { + @org.jetbrains.annotations.NotNull() + private final java.lang.String s = null; @org.jetbrains.annotations.NotNull() public final test.Experiment.Group copy(@org.jetbrains.annotations.NotNull() @@ -110,10 +112,37 @@ public final class Experiment { return null; } + @java.lang.Override() + public boolean equals(@org.jetbrains.annotations.Nullable() + java.lang.Object other) { + return false; + } + + @java.lang.Override() + public int hashCode() { + return 0; + } + + @org.jetbrains.annotations.NotNull() + @java.lang.Override() + public java.lang.String toString() { + return null; + } + public Group(@org.jetbrains.annotations.NotNull() java.lang.String s) { super(); } + + @org.jetbrains.annotations.NotNull() + public final java.lang.String component1() { + return null; + } + + @org.jetbrains.annotations.NotNull() + public final java.lang.String getS() { + return null; + } } } diff --git a/plugins/kapt3/kapt3-compiler/testData/converter/nestedClassesNonRootPackage_ir.txt b/plugins/kapt3/kapt3-compiler/testData/converter/nestedClassesNonRootPackage_ir.txt index 2150b459203..287803066e5 100644 --- a/plugins/kapt3/kapt3-compiler/testData/converter/nestedClassesNonRootPackage_ir.txt +++ b/plugins/kapt3/kapt3-compiler/testData/converter/nestedClassesNonRootPackage_ir.txt @@ -103,12 +103,24 @@ public final class Experiment { @kotlin.Metadata() @test.Experiment.Type() public static final class Group { + @org.jetbrains.annotations.NotNull() + private final java.lang.String s = null; public Group(@org.jetbrains.annotations.NotNull() java.lang.String s) { super(); } + @org.jetbrains.annotations.NotNull() + public final java.lang.String getS() { + return null; + } + + @org.jetbrains.annotations.NotNull() + public final java.lang.String component1() { + return null; + } + @org.jetbrains.annotations.NotNull() public final test.Experiment.Group copy(@org.jetbrains.annotations.NotNull() java.lang.String s) {