From 6623456d2aa16b797a15416ae5d0ded8f9861b01 Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Mon, 19 Sep 2022 14:52:39 +0300 Subject: [PATCH] [FIR] Properly support @JvmRecord ^KT-53867 Fixed --- ...rDesignatedSupertypeResolverTransformer.kt | 2 +- .../declaration/FirJvmRecordChecker.kt | 6 +- .../fir/session/ComponentsContainers.kt | 3 + .../runners/ir/Fir2IrTextTestGenerated.java | 6 + .../ir/LightTreeFir2IrTextTestGenerated.java | 6 + .../kotlin/fir/java/JvmSupertypeUpdater.kt | 104 ++++++++++++++++++ .../fir/declarations/FirAnnotationUtils.kt | 14 +++ .../transformers/FirSupertypesResolution.kt | 22 +++- .../transformers/PlatformSupertypeUpdater.kt | 17 +++ ...erRequiredAnnotationsResolveTransformer.kt | 4 +- .../asJava/ultraLightClasses/jvmRecord.kt | 4 +- .../records/bytecodeShapeForJava.kt | 1 - .../records/propertiesOverrides.kt | 1 - ...tiesOverridesAllCompatibilityJvmDefault.kt | 5 +- .../propertiesOverridesEnableJvmDefault.kt | 1 - .../dataClassWithJvmRecord.fir.ir.txt | 98 +++++++++++++++++ .../dataClassWithJvmRecord.fir.kt.txt | 47 ++++++++ .../jvmRecord/dataClassWithJvmRecord.ir.txt | 98 +++++++++++++++++ .../jvmRecord/dataClassWithJvmRecord.kt | 11 ++ .../jvmRecord/dataClassWithJvmRecord.kt.txt | 47 ++++++++ compiler/tests-common-new/build.gradle.kts | 11 +- .../test/runners/ir/IrTextTestGenerated.java | 6 + .../jetbrains/kotlin/name/StandardClassIds.kt | 5 + 23 files changed, 490 insertions(+), 29 deletions(-) create mode 100644 compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JvmSupertypeUpdater.kt create mode 100644 compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/PlatformSupertypeUpdater.kt create mode 100644 compiler/testData/ir/irText/declarations/jvmRecord/dataClassWithJvmRecord.fir.ir.txt create mode 100644 compiler/testData/ir/irText/declarations/jvmRecord/dataClassWithJvmRecord.fir.kt.txt create mode 100644 compiler/testData/ir/irText/declarations/jvmRecord/dataClassWithJvmRecord.ir.txt create mode 100644 compiler/testData/ir/irText/declarations/jvmRecord/dataClassWithJvmRecord.kt create mode 100644 compiler/testData/ir/irText/declarations/jvmRecord/dataClassWithJvmRecord.kt.txt diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedSupertypeResolverTransformer.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedSupertypeResolverTransformer.kt index e4447e93bd4..1d41680e7ca 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedSupertypeResolverTransformer.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedSupertypeResolverTransformer.kt @@ -61,7 +61,7 @@ internal class LLFirDesignatedSupertypeResolverTransformer( } private inner class DesignatedFirApplySupertypesTransformer(classDesignation: FirDeclarationDesignation) : - FirApplySupertypesTransformer(supertypeComputationSession) { + FirApplySupertypesTransformer(supertypeComputationSession, session, scopeSession) { val declarationTransformer = LLFirDeclarationTransformer(classDesignation) diff --git a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirJvmRecordChecker.kt b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirJvmRecordChecker.kt index 7d6f44b2303..cb248f0e423 100644 --- a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirJvmRecordChecker.kt +++ b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirJvmRecordChecker.kt @@ -25,13 +25,13 @@ import org.jetbrains.kotlin.fir.types.coneType import org.jetbrains.kotlin.fir.types.coneTypeSafe import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.JvmNames.JVM_RECORD_ANNOTATION_CLASS_ID +import org.jetbrains.kotlin.name.StandardClassIds object FirJvmRecordChecker : FirRegularClassChecker() { - private val JAVA_RECORD_CLASS_ID = ClassId.fromString("java/lang/Record") - override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) { declaration.superTypeRefs.firstOrNull()?.let { typeRef -> - if (typeRef.coneTypeSafe()?.classId == JAVA_RECORD_CLASS_ID) { + // compiler automatically adds java.lang.Record supertype, so we should check only for explicit type declarations + if (typeRef.source != null && typeRef.coneTypeSafe()?.classId == StandardClassIds.Java.Record) { reporter.reportOn(typeRef.source, FirJvmErrors.ILLEGAL_JAVA_LANG_RECORD_SUPERTYPE, context) return } diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/ComponentsContainers.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/ComponentsContainers.kt index 5bf7c2dd35b..95463fe39eb 100644 --- a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/ComponentsContainers.kt +++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/ComponentsContainers.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.fir.declarations.SealedClassInheritorsProviderImpl import org.jetbrains.kotlin.fir.extensions.* import org.jetbrains.kotlin.fir.java.FirJavaVisibilityChecker import org.jetbrains.kotlin.fir.java.FirJvmDefaultModeComponent +import org.jetbrains.kotlin.fir.java.JvmSupertypeUpdater import org.jetbrains.kotlin.fir.java.enhancement.FirAnnotationTypeQualifierResolver import org.jetbrains.kotlin.fir.java.enhancement.FirEnhancedSymbolsStorage import org.jetbrains.kotlin.fir.resolve.* @@ -30,6 +31,7 @@ import org.jetbrains.kotlin.fir.resolve.inference.InferenceComponents import org.jetbrains.kotlin.fir.resolve.providers.impl.FirQualifierResolverImpl import org.jetbrains.kotlin.fir.resolve.providers.impl.FirTypeResolverImpl import org.jetbrains.kotlin.fir.resolve.transformers.FirCompilerLazyDeclarationResolver +import org.jetbrains.kotlin.fir.resolve.transformers.PlatformSupertypeUpdater import org.jetbrains.kotlin.fir.resolve.transformers.plugin.GeneratedClassIndex import org.jetbrains.kotlin.fir.scopes.FirOverrideService import org.jetbrains.kotlin.fir.scopes.FirPlatformClassMapper @@ -85,6 +87,7 @@ fun FirSession.registerCommonJavaComponents(javaModuleResolver: JavaModuleResolv FirJvmDefaultModeComponent::class, FirJvmDefaultModeComponent(languageVersionSettings.getFlag(JvmAnalysisFlags.jvmDefaultMode)) ) + register(PlatformSupertypeUpdater::class, JvmSupertypeUpdater(this)) } // -------------------------- Resolve components -------------------------- diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/Fir2IrTextTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/Fir2IrTextTestGenerated.java index 6d94be62d9a..49f9e55175d 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/Fir2IrTextTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/Fir2IrTextTestGenerated.java @@ -951,6 +951,12 @@ public class Fir2IrTextTestGenerated extends AbstractFir2IrTextTest { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/ir/irText/declarations/jvmRecord"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @Test + @TestMetadata("dataClassWithJvmRecord.kt") + public void testDataClassWithJvmRecord() throws Exception { + runTest("compiler/testData/ir/irText/declarations/jvmRecord/dataClassWithJvmRecord.kt"); + } + @Test @TestMetadata("javaRecordComponentAccess.kt") public void testJavaRecordComponentAccess() throws Exception { diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/LightTreeFir2IrTextTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/LightTreeFir2IrTextTestGenerated.java index 429005f9624..88a1e7c5cc3 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/LightTreeFir2IrTextTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/LightTreeFir2IrTextTestGenerated.java @@ -951,6 +951,12 @@ public class LightTreeFir2IrTextTestGenerated extends AbstractLightTreeFir2IrTex KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/ir/irText/declarations/jvmRecord"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @Test + @TestMetadata("dataClassWithJvmRecord.kt") + public void testDataClassWithJvmRecord() throws Exception { + runTest("compiler/testData/ir/irText/declarations/jvmRecord/dataClassWithJvmRecord.kt"); + } + @Test @TestMetadata("javaRecordComponentAccess.kt") public void testJavaRecordComponentAccess() throws Exception { diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JvmSupertypeUpdater.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JvmSupertypeUpdater.kt new file mode 100644 index 00000000000..4120b776eb1 --- /dev/null +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JvmSupertypeUpdater.kt @@ -0,0 +1,104 @@ +/* + * 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.java + +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.fir.FirElement +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.declarations.FirClass +import org.jetbrains.kotlin.fir.declarations.FirConstructor +import org.jetbrains.kotlin.fir.declarations.FirRegularClass +import org.jetbrains.kotlin.fir.declarations.hasAnnotationSafe +import org.jetbrains.kotlin.fir.declarations.utils.isData +import org.jetbrains.kotlin.fir.expressions.FirDelegatedConstructorCall +import org.jetbrains.kotlin.fir.expressions.FirStatement +import org.jetbrains.kotlin.fir.java.JvmSupertypeUpdater.DelegatedConstructorCallTransformer.Companion.recordType +import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference +import org.jetbrains.kotlin.fir.resolve.ScopeSession +import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol +import org.jetbrains.kotlin.fir.resolve.transformers.PlatformSupertypeUpdater +import org.jetbrains.kotlin.fir.resolvedTypeFromPrototype +import org.jetbrains.kotlin.fir.scopes.getDeclaredConstructors +import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope +import org.jetbrains.kotlin.fir.types.* +import org.jetbrains.kotlin.fir.types.impl.FirImplicitBuiltinTypeRef +import org.jetbrains.kotlin.fir.visitors.FirTransformer +import org.jetbrains.kotlin.fir.visitors.transformSingle +import org.jetbrains.kotlin.name.StandardClassIds + +class JvmSupertypeUpdater(private val session: FirSession) : PlatformSupertypeUpdater() { + private val jvmRecordUpdater = DelegatedConstructorCallTransformer(session) + + override fun updateSupertypesIfNeeded(firClass: FirClass, scopeSession: ScopeSession) { + if (!(firClass is FirRegularClass && firClass.isData && firClass.hasAnnotationSafe(StandardClassIds.Annotations.JvmRecord))) return + var anyFound = false + var hasExplicitSuperClass = false + val newSuperTypeRefs = firClass.superTypeRefs.mapTo(mutableListOf()) { + when { + it is FirImplicitBuiltinTypeRef && it.id == StandardClassIds.Any -> { + anyFound = true + it.withReplacedConeType(recordType) + } + it.coneType.toRegularClassSymbol(session)?.classKind == ClassKind.CLASS -> { + hasExplicitSuperClass = true + it + } + else -> it + } + } + if (!anyFound && !hasExplicitSuperClass) { + newSuperTypeRefs += recordType.toFirResolvedTypeRef() + } + + if (anyFound || !hasExplicitSuperClass) { + firClass.replaceSuperTypeRefs(newSuperTypeRefs) + firClass.transformSingle(jvmRecordUpdater, scopeSession) + } + } + + private class DelegatedConstructorCallTransformer(private val session: FirSession) : FirTransformer() { + companion object { + val recordType = StandardClassIds.Java.Record.constructClassLikeType(emptyArray(), isNullable = false) + } + + override fun transformElement(element: E, data: ScopeSession): E { + return element + } + + override fun transformRegularClass(regularClass: FirRegularClass, data: ScopeSession): FirStatement { + return regularClass.transformDeclarations(this, data) + } + + override fun transformConstructor(constructor: FirConstructor, data: ScopeSession): FirStatement { + return constructor.transformDelegatedConstructor(this, data) + } + + override fun transformDelegatedConstructorCall( + delegatedConstructorCall: FirDelegatedConstructorCall, + data: ScopeSession + ): FirStatement { + val constructedTypeRef = delegatedConstructorCall.constructedTypeRef + if (constructedTypeRef is FirImplicitTypeRef || constructedTypeRef.coneTypeSafe()?.isAny == true) { + delegatedConstructorCall.replaceConstructedTypeRef(constructedTypeRef.resolvedTypeFromPrototype(recordType)) + } + + val recordConstructorSymbol = recordType.lookupTag.toFirRegularClassSymbol(session) + ?.unsubstitutedScope(session, data, withForcedTypeCalculator = false) + ?.getDeclaredConstructors() + ?.firstOrNull { it.fir.valueParameters.isEmpty() } + + if (recordConstructorSymbol != null) { + val newReference = buildResolvedNamedReference { + name = StandardClassIds.Java.Record.shortClassName + resolvedSymbol = recordConstructorSymbol + } + delegatedConstructorCall.replaceCalleeReference(newReference) + } + return delegatedConstructorCall + } + } + +} diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/FirAnnotationUtils.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/FirAnnotationUtils.kt index 9d8bdf99210..8070daa213b 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/FirAnnotationUtils.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/FirAnnotationUtils.kt @@ -26,9 +26,15 @@ private fun FirAnnotation.toAnnotationLookupTag(): ConeClassLikeLookupTag? = // this cast fails when we have generic-typed annotations @T (annotationTypeRef.coneType as? ConeClassLikeType)?.lookupTag +private fun FirAnnotation.toAnnotationLookupTagSafe(): ConeClassLikeLookupTag? = + annotationTypeRef.coneTypeSafe()?.lookupTag + fun FirAnnotation.toAnnotationClassId(): ClassId? = toAnnotationLookupTag()?.classId +fun FirAnnotation.toAnnotationClassIdSafe(): ClassId? = + toAnnotationLookupTagSafe()?.classId + private fun FirAnnotation.toAnnotationClass(session: FirSession): FirRegularClass? = toAnnotationLookupTag()?.toSymbol(session)?.fir as? FirRegularClass @@ -99,6 +105,10 @@ fun FirDeclaration.hasAnnotation(classId: ClassId): Boolean { return annotations.hasAnnotation(classId) } +fun FirDeclaration.hasAnnotationSafe(classId: ClassId): Boolean { + return annotations.hasAnnotationSafe(classId) +} + fun FirBasedSymbol<*>.hasAnnotation(classId: ClassId): Boolean { return resolvedAnnotationsWithClassIds.hasAnnotation(classId) } @@ -107,6 +117,10 @@ fun List.hasAnnotation(classId: ClassId): Boolean { return this.any { it.toAnnotationClassId() == classId } } +fun List.hasAnnotationSafe(classId: ClassId): Boolean { + return this.any { it.toAnnotationClassIdSafe() == classId } +} + fun FirBasedSymbol.getAnnotationByClassId(classId: ClassId): FirAnnotation? where D : FirAnnotationContainer, D : FirDeclaration { return fir.getAnnotationByClassId(classId) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSupertypesResolution.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSupertypesResolution.kt index 073aa2cf60f..a261729d0b3 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSupertypesResolution.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSupertypesResolution.kt @@ -8,26 +8,28 @@ package org.jetbrains.kotlin.fir.resolve.transformers import kotlinx.collections.immutable.PersistentList import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toPersistentList +import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.utils.expandedConeType import org.jetbrains.kotlin.fir.declarations.utils.isCompanion +import org.jetbrains.kotlin.fir.declarations.utils.isData import org.jetbrains.kotlin.fir.declarations.utils.superConeTypes import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind +import org.jetbrains.kotlin.fir.expressions.FirDelegatedConstructorCall import org.jetbrains.kotlin.fir.expressions.FirStatement import org.jetbrains.kotlin.fir.extensions.FirSupertypeGenerationExtension import org.jetbrains.kotlin.fir.extensions.extensionService import org.jetbrains.kotlin.fir.extensions.supertypeGenerators +import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.dfa.cfg.isLocalClassOrAnonymousObject import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeTypeParameterSupertype import org.jetbrains.kotlin.fir.resolve.providers.firProvider import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.LocalClassesNavigationInfo -import org.jetbrains.kotlin.fir.scopes.FirScope -import org.jetbrains.kotlin.fir.scopes.createImportingScopes -import org.jetbrains.kotlin.fir.scopes.getNestedClassifierScope +import org.jetbrains.kotlin.fir.scopes.* import org.jetbrains.kotlin.fir.scopes.impl.FirMemberTypeParameterScope import org.jetbrains.kotlin.fir.scopes.impl.nestedClassifierScope import org.jetbrains.kotlin.fir.scopes.impl.wrapNestedClassifierScopeWithSubstitutionForSuperType @@ -40,7 +42,9 @@ import org.jetbrains.kotlin.fir.types.impl.FirImplicitBuiltinTypeRef import org.jetbrains.kotlin.fir.visitors.FirDefaultTransformer import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor import org.jetbrains.kotlin.fir.visitors.FirTransformer +import org.jetbrains.kotlin.fir.visitors.transformSingle import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.StandardClassIds import org.jetbrains.kotlin.types.model.TypeArgumentMarker import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addToStdlib.safeAs @@ -65,7 +69,7 @@ open class FirSupertypeResolverTransformer( protected val supertypeComputationSession = SupertypeComputationSession() private val supertypeResolverVisitor = FirSupertypeResolverVisitor(session, supertypeComputationSession, scopeSession) - private val applySupertypesTransformer = FirApplySupertypesTransformer(supertypeComputationSession) + private val applySupertypesTransformer = FirApplySupertypesTransformer(supertypeComputationSession, session, scopeSession) override fun transformElement(element: E, data: Any?): E { return element @@ -101,13 +105,16 @@ fun F.runSupertypeResolvePhaseForLocalClass( this.accept(supertypeResolverVisitor, null) supertypeComputationSession.breakLoops(session) - val applySupertypesTransformer = FirApplySupertypesTransformer(supertypeComputationSession) + val applySupertypesTransformer = FirApplySupertypesTransformer(supertypeComputationSession, session, scopeSession) return this.transform(applySupertypesTransformer, null) } open class FirApplySupertypesTransformer( - private val supertypeComputationSession: SupertypeComputationSession + private val supertypeComputationSession: SupertypeComputationSession, + private val session: FirSession, + private val scopeSession: ScopeSession ) : FirDefaultTransformer() { + override fun transformElement(element: E, data: Any?): E { return element } @@ -133,8 +140,11 @@ open class FirApplySupertypesTransformer( // TODO: Replace with an immutable version or transformer firClass.replaceSuperTypeRefs(supertypeRefs) } + + session.platformSupertypeUpdater?.updateSupertypesIfNeeded(firClass, scopeSession) } + override fun transformAnonymousObject(anonymousObject: FirAnonymousObject, data: Any?): FirStatement { applyResolvedSupertypesToClass(anonymousObject) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/PlatformSupertypeUpdater.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/PlatformSupertypeUpdater.kt new file mode 100644 index 00000000000..b512f2a1cb6 --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/PlatformSupertypeUpdater.kt @@ -0,0 +1,17 @@ +/* + * 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.resolve.transformers + +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.FirSessionComponent +import org.jetbrains.kotlin.fir.declarations.FirClass +import org.jetbrains.kotlin.fir.resolve.ScopeSession + +abstract class PlatformSupertypeUpdater : FirSessionComponent { + abstract fun updateSupertypesIfNeeded(firClass: FirClass, scopeSession: ScopeSession) +} + +val FirSession.platformSupertypeUpdater: PlatformSupertypeUpdater? by FirSession.nullableSessionComponentAccessor() diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/plugin/FirCompilerRequiredAnnotationsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/plugin/FirCompilerRequiredAnnotationsResolveTransformer.kt index dcfd3df46c4..67fbcd95f68 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/plugin/FirCompilerRequiredAnnotationsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/plugin/FirCompilerRequiredAnnotationsResolveTransformer.kt @@ -32,8 +32,10 @@ import org.jetbrains.kotlin.fir.visitors.transformSingle import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.name.StandardClassIds import org.jetbrains.kotlin.name.StandardClassIds.Annotations.Deprecated import org.jetbrains.kotlin.name.StandardClassIds.Annotations.DeprecatedSinceKotlin +import org.jetbrains.kotlin.name.StandardClassIds.Annotations.JvmRecord import org.jetbrains.kotlin.name.StandardClassIds.Annotations.WasExperimental class FirCompilerRequiredAnnotationsResolveProcessor( @@ -154,7 +156,7 @@ private class FirAnnotationResolveTransformer( ) { companion object { private val REQUIRED_ANNOTATIONS: Set = setOf( - Deprecated, DeprecatedSinceKotlin, WasExperimental + Deprecated, DeprecatedSinceKotlin, WasExperimental, JvmRecord ) private val REQUIRED_ANNOTATION_NAMES: Set = REQUIRED_ANNOTATIONS.mapTo(mutableSetOf()) { it.shortClassName } diff --git a/compiler/testData/asJava/ultraLightClasses/jvmRecord.kt b/compiler/testData/asJava/ultraLightClasses/jvmRecord.kt index e8f7561eec8..453a460ec77 100644 --- a/compiler/testData/asJava/ultraLightClasses/jvmRecord.kt +++ b/compiler/testData/asJava/ultraLightClasses/jvmRecord.kt @@ -2,9 +2,11 @@ // API_VERSION: 1.5 // JVM_TARGET: 17 // COMPILER_ARGUMENTS: -XXLanguage:+JvmRecordSupport -Xjvm-enable-preview +// IGNORE_FIR +// reason: test framework does not support using JDK 17 as dependency package pkg @JvmRecord data class MyRec(val name: String) // JDK 15 should be used to compile this file -// COMPILATION_ERRORS \ No newline at end of file +// COMPILATION_ERRORS diff --git a/compiler/testData/codegen/boxModernJdk/testsWithJava17/records/bytecodeShapeForJava.kt b/compiler/testData/codegen/boxModernJdk/testsWithJava17/records/bytecodeShapeForJava.kt index e900ea34175..c1cd2657e8f 100644 --- a/compiler/testData/codegen/boxModernJdk/testsWithJava17/records/bytecodeShapeForJava.kt +++ b/compiler/testData/codegen/boxModernJdk/testsWithJava17/records/bytecodeShapeForJava.kt @@ -1,6 +1,5 @@ // !API_VERSION: 1.5 // !LANGUAGE: +JvmRecordSupport -// IGNORE_BACKEND_FIR: JVM_IR // ENABLE_JVM_PREVIEW // FILE: JavaClass.java public class JavaClass { diff --git a/compiler/testData/codegen/boxModernJdk/testsWithJava17/records/propertiesOverrides.kt b/compiler/testData/codegen/boxModernJdk/testsWithJava17/records/propertiesOverrides.kt index 77cd845c58a..fc5732c6682 100644 --- a/compiler/testData/codegen/boxModernJdk/testsWithJava17/records/propertiesOverrides.kt +++ b/compiler/testData/codegen/boxModernJdk/testsWithJava17/records/propertiesOverrides.kt @@ -1,6 +1,5 @@ // !API_VERSION: 1.5 // !LANGUAGE: +JvmRecordSupport -// IGNORE_BACKEND_FIR: JVM_IR // ENABLE_JVM_PREVIEW // FILE: JavaClass.java diff --git a/compiler/testData/codegen/boxModernJdk/testsWithJava17/records/propertiesOverridesAllCompatibilityJvmDefault.kt b/compiler/testData/codegen/boxModernJdk/testsWithJava17/records/propertiesOverridesAllCompatibilityJvmDefault.kt index 32a73115509..9a01631a6b2 100644 --- a/compiler/testData/codegen/boxModernJdk/testsWithJava17/records/propertiesOverridesAllCompatibilityJvmDefault.kt +++ b/compiler/testData/codegen/boxModernJdk/testsWithJava17/records/propertiesOverridesAllCompatibilityJvmDefault.kt @@ -1,8 +1,5 @@ -// !API_VERSION: 1.5 -// !LANGUAGE: +JvmRecordSupport // ENABLE_JVM_PREVIEW -// IGNORE_BACKEND_FIR: JVM_IR -// !JVM_DEFAULT_MODE: all-compatibility +// JVM_DEFAULT_MODE: all-compatibility // FILE: JavaClass.java public class JavaClass { diff --git a/compiler/testData/codegen/boxModernJdk/testsWithJava17/records/propertiesOverridesEnableJvmDefault.kt b/compiler/testData/codegen/boxModernJdk/testsWithJava17/records/propertiesOverridesEnableJvmDefault.kt index 413f5dc21f6..39e4a9094fd 100644 --- a/compiler/testData/codegen/boxModernJdk/testsWithJava17/records/propertiesOverridesEnableJvmDefault.kt +++ b/compiler/testData/codegen/boxModernJdk/testsWithJava17/records/propertiesOverridesEnableJvmDefault.kt @@ -1,7 +1,6 @@ // !API_VERSION: 1.5 // !LANGUAGE: +JvmRecordSupport // ENABLE_JVM_PREVIEW -// IGNORE_BACKEND_FIR: JVM_IR // !JVM_DEFAULT_MODE: enable // FILE: JavaClass.java diff --git a/compiler/testData/ir/irText/declarations/jvmRecord/dataClassWithJvmRecord.fir.ir.txt b/compiler/testData/ir/irText/declarations/jvmRecord/dataClassWithJvmRecord.fir.ir.txt new file mode 100644 index 00000000000..44f19eb5dea --- /dev/null +++ b/compiler/testData/ir/irText/declarations/jvmRecord/dataClassWithJvmRecord.fir.ir.txt @@ -0,0 +1,98 @@ +FILE fqName: fileName:/dataClassWithJvmRecord.kt + CLASS CLASS name:MyRec modality:FINAL visibility:public [data] superTypes:[java.lang.Record] + annotations: + JvmRecord + $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.MyRec + CONSTRUCTOR visibility:public <> (name:kotlin.String) returnType:.MyRec [primary] + VALUE_PARAMETER name:name index:0 type:kotlin.String + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'protected/*protected and package*/ constructor () declared in java.lang.Record' + INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:MyRec modality:FINAL visibility:public [data] superTypes:[java.lang.Record]' + PROPERTY name:name visibility:public modality:FINAL [val] + FIELD PROPERTY_BACKING_FIELD name:name type:kotlin.String visibility:private [final] + EXPRESSION_BODY + GET_VAR 'name: kotlin.String declared in .MyRec.' type=kotlin.String origin=INITIALIZE_PROPERTY_FROM_PARAMETER + FUN DEFAULT_PROPERTY_ACCESSOR name: visibility:public modality:FINAL <> ($this:.MyRec) returnType:kotlin.String + correspondingProperty: PROPERTY name:name visibility:public modality:FINAL [val] + $this: VALUE_PARAMETER name: type:.MyRec + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun (): kotlin.String declared in .MyRec' + GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:name type:kotlin.String visibility:private [final]' type=kotlin.String origin=null + receiver: GET_VAR ': .MyRec declared in .MyRec.' type=.MyRec origin=null + FUN name:component1 visibility:public modality:FINAL <> ($this:.MyRec) returnType:kotlin.String [operator] + $this: VALUE_PARAMETER name: type:.MyRec + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun component1 (): kotlin.String [operator] declared in .MyRec' + GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:name type:kotlin.String visibility:private [final]' type=kotlin.String origin=null + receiver: GET_VAR ': .MyRec declared in .MyRec.component1' type=.MyRec origin=null + FUN name:copy visibility:public modality:FINAL <> ($this:.MyRec, name:kotlin.String) returnType:.MyRec + $this: VALUE_PARAMETER name: type:.MyRec + VALUE_PARAMETER name:name index:0 type:kotlin.String + EXPRESSION_BODY + GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:name type:kotlin.String visibility:private [final]' type=kotlin.String origin=null + receiver: GET_VAR ': .MyRec declared in .MyRec.copy' type=.MyRec origin=null + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun copy (name: kotlin.String): .MyRec declared in .MyRec' + CONSTRUCTOR_CALL 'public constructor (name: kotlin.String) [primary] declared in .MyRec' type=.MyRec origin=null + name: GET_VAR 'name: kotlin.String declared in .MyRec.copy' type=kotlin.String origin=null + FUN GENERATED_DATA_CLASS_MEMBER name:equals visibility:public modality:OPEN <> ($this:.MyRec, other:kotlin.Any?) returnType:kotlin.Boolean + overridden: + public open fun equals (other: kotlin.Any?): kotlin.Boolean [operator] declared in kotlin.Any + $this: VALUE_PARAMETER GENERATED_DATA_CLASS_MEMBER name: type:.MyRec + VALUE_PARAMETER GENERATED_DATA_CLASS_MEMBER name:other index:0 type:kotlin.Any? + BLOCK_BODY + WHEN type=kotlin.Unit origin=null + BRANCH + if: CALL 'public final fun EQEQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQEQ + arg0: GET_VAR ': .MyRec declared in .MyRec.equals' type=.MyRec origin=null + arg1: GET_VAR 'other: kotlin.Any? declared in .MyRec.equals' type=kotlin.Any? origin=null + then: RETURN type=kotlin.Nothing from='public open fun equals (other: kotlin.Any?): kotlin.Boolean declared in .MyRec' + CONST Boolean type=kotlin.Boolean value=true + WHEN type=kotlin.Unit origin=null + BRANCH + if: TYPE_OP type=kotlin.Boolean origin=NOT_INSTANCEOF typeOperand=.MyRec + GET_VAR 'other: kotlin.Any? declared in .MyRec.equals' type=kotlin.Any? origin=null + then: RETURN type=kotlin.Nothing from='public open fun equals (other: kotlin.Any?): kotlin.Boolean declared in .MyRec' + CONST Boolean type=kotlin.Boolean value=false + VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:.MyRec [val] + TYPE_OP type=.MyRec origin=CAST typeOperand=.MyRec + GET_VAR 'other: kotlin.Any? declared in .MyRec.equals' type=kotlin.Any? origin=null + WHEN type=kotlin.Unit origin=null + BRANCH + if: CALL 'public final fun not (): kotlin.Boolean [operator] declared in kotlin.Boolean' type=kotlin.Boolean origin=EXCLEQ + $this: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EXCLEQ + arg0: GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:name type:kotlin.String visibility:private [final]' type=kotlin.String origin=null + receiver: GET_VAR ': .MyRec declared in .MyRec.equals' type=.MyRec origin=null + arg1: GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:name type:kotlin.String visibility:private [final]' type=kotlin.String origin=null + receiver: GET_VAR 'val tmp_0: .MyRec [val] declared in .MyRec.equals' type=.MyRec origin=null + then: RETURN type=kotlin.Nothing from='public open fun equals (other: kotlin.Any?): kotlin.Boolean declared in .MyRec' + CONST Boolean type=kotlin.Boolean value=false + RETURN type=kotlin.Nothing from='public open fun equals (other: kotlin.Any?): kotlin.Boolean declared in .MyRec' + CONST Boolean type=kotlin.Boolean value=true + FUN GENERATED_DATA_CLASS_MEMBER name:hashCode visibility:public modality:OPEN <> ($this:.MyRec) returnType:kotlin.Int + overridden: + public open fun hashCode (): kotlin.Int declared in kotlin.Any + $this: VALUE_PARAMETER GENERATED_DATA_CLASS_MEMBER name: type:.MyRec + BLOCK_BODY + RETURN type=kotlin.Nothing from='public open fun hashCode (): kotlin.Int declared in .MyRec' + CALL 'public open fun hashCode (): kotlin.Int [fake_override] declared in kotlin.String' type=kotlin.Int origin=null + $this: GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:name type:kotlin.String visibility:private [final]' type=kotlin.String origin=null + receiver: GET_VAR ': .MyRec declared in .MyRec.hashCode' type=.MyRec origin=null + FUN GENERATED_DATA_CLASS_MEMBER name:toString visibility:public modality:OPEN <> ($this:.MyRec) returnType:kotlin.String + overridden: + public open fun toString (): kotlin.String declared in kotlin.Any + $this: VALUE_PARAMETER GENERATED_DATA_CLASS_MEMBER name: type:.MyRec + BLOCK_BODY + RETURN type=kotlin.Nothing from='public open fun toString (): kotlin.String declared in .MyRec' + STRING_CONCATENATION type=kotlin.String + CONST String type=kotlin.String value="MyRec(" + CONST String type=kotlin.String value="name=" + GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:name type:kotlin.String visibility:private [final]' type=kotlin.String origin=null + receiver: GET_VAR ': .MyRec declared in .MyRec.toString' type=.MyRec origin=null + CONST String type=kotlin.String value=")" + FUN name:test visibility:public modality:FINAL <> (rec:.MyRec) returnType:kotlin.Unit + VALUE_PARAMETER name:rec index:0 type:.MyRec + BLOCK_BODY + TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + CALL 'public final fun (): kotlin.String declared in .MyRec' type=kotlin.String origin=GET_PROPERTY + $this: GET_VAR 'rec: .MyRec declared in .test' type=.MyRec origin=null diff --git a/compiler/testData/ir/irText/declarations/jvmRecord/dataClassWithJvmRecord.fir.kt.txt b/compiler/testData/ir/irText/declarations/jvmRecord/dataClassWithJvmRecord.fir.kt.txt new file mode 100644 index 00000000000..7844b5916f4 --- /dev/null +++ b/compiler/testData/ir/irText/declarations/jvmRecord/dataClassWithJvmRecord.fir.kt.txt @@ -0,0 +1,47 @@ +@JvmRecord +data class MyRec : Record { + constructor(name: String) /* primary */ { + super/*Record*/() + /* () */ + + } + + val name: String + field = name + get + + operator fun component1(): String { + return .#name + } + + fun copy(name: String = .#name): MyRec { + return MyRec(name = name) + } + + override fun equals(other: Any?): Boolean { + when { + EQEQEQ(arg0 = , arg1 = other) -> return true + } + when { + other !is MyRec -> return false + } + val tmp0_other_with_cast: MyRec = other as MyRec + when { + EQEQ(arg0 = .#name, arg1 = tmp0_other_with_cast.#name).not() -> return false + } + return true + } + + override fun hashCode(): Int { + return .#name.hashCode() + } + + override fun toString(): String { + return "MyRec(" + "name=" + .#name + ")" + } + +} + +fun test(rec: MyRec) { + rec.() /*~> Unit */ +} diff --git a/compiler/testData/ir/irText/declarations/jvmRecord/dataClassWithJvmRecord.ir.txt b/compiler/testData/ir/irText/declarations/jvmRecord/dataClassWithJvmRecord.ir.txt new file mode 100644 index 00000000000..c735be307d2 --- /dev/null +++ b/compiler/testData/ir/irText/declarations/jvmRecord/dataClassWithJvmRecord.ir.txt @@ -0,0 +1,98 @@ +FILE fqName: fileName:/dataClassWithJvmRecord.kt + CLASS CLASS name:MyRec modality:FINAL visibility:public [data] superTypes:[java.lang.Record] + annotations: + JvmRecord + $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.MyRec + CONSTRUCTOR visibility:public <> (name:kotlin.String) returnType:.MyRec [primary] + VALUE_PARAMETER name:name index:0 type:kotlin.String + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'protected/*protected and package*/ constructor () declared in java.lang.Record' + INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:MyRec modality:FINAL visibility:public [data] superTypes:[java.lang.Record]' + PROPERTY name:name visibility:public modality:FINAL [val] + FIELD PROPERTY_BACKING_FIELD name:name type:kotlin.String visibility:private [final] + EXPRESSION_BODY + GET_VAR 'name: kotlin.String declared in .MyRec.' type=kotlin.String origin=INITIALIZE_PROPERTY_FROM_PARAMETER + FUN DEFAULT_PROPERTY_ACCESSOR name: visibility:public modality:FINAL <> ($this:.MyRec) returnType:kotlin.String + correspondingProperty: PROPERTY name:name visibility:public modality:FINAL [val] + $this: VALUE_PARAMETER name: type:.MyRec + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun (): kotlin.String declared in .MyRec' + GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:name type:kotlin.String visibility:private [final]' type=kotlin.String origin=null + receiver: GET_VAR ': .MyRec declared in .MyRec.' type=.MyRec origin=null + FUN GENERATED_DATA_CLASS_MEMBER name:component1 visibility:public modality:FINAL <> ($this:.MyRec) returnType:kotlin.String [operator] + $this: VALUE_PARAMETER name: type:.MyRec + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun component1 (): kotlin.String [operator] declared in .MyRec' + GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:name type:kotlin.String visibility:private [final]' type=kotlin.String origin=null + receiver: GET_VAR ': .MyRec declared in .MyRec.component1' type=.MyRec origin=null + FUN GENERATED_DATA_CLASS_MEMBER name:copy visibility:public modality:FINAL <> ($this:.MyRec, name:kotlin.String) returnType:.MyRec + $this: VALUE_PARAMETER name: type:.MyRec + VALUE_PARAMETER name:name index:0 type:kotlin.String + EXPRESSION_BODY + GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:name type:kotlin.String visibility:private [final]' type=kotlin.String origin=null + receiver: GET_VAR ': .MyRec declared in .MyRec.copy' type=.MyRec origin=null + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun copy (name: kotlin.String): .MyRec declared in .MyRec' + CONSTRUCTOR_CALL 'public constructor (name: kotlin.String) [primary] declared in .MyRec' type=.MyRec origin=null + name: GET_VAR 'name: kotlin.String declared in .MyRec.copy' type=kotlin.String origin=null + FUN GENERATED_DATA_CLASS_MEMBER name:toString visibility:public modality:OPEN <> ($this:.MyRec) returnType:kotlin.String + overridden: + public abstract fun toString (): @[EnhancedNullability] kotlin.String declared in java.lang.Record + $this: VALUE_PARAMETER name: type:.MyRec + BLOCK_BODY + RETURN type=kotlin.Nothing from='public open fun toString (): kotlin.String declared in .MyRec' + STRING_CONCATENATION type=kotlin.String + CONST String type=kotlin.String value="MyRec(" + CONST String type=kotlin.String value="name=" + GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:name type:kotlin.String visibility:private [final]' type=kotlin.String origin=null + receiver: GET_VAR ': .MyRec declared in .MyRec.toString' type=.MyRec origin=null + CONST String type=kotlin.String value=")" + FUN GENERATED_DATA_CLASS_MEMBER name:hashCode visibility:public modality:OPEN <> ($this:.MyRec) returnType:kotlin.Int + overridden: + public abstract fun hashCode (): kotlin.Int declared in java.lang.Record + $this: VALUE_PARAMETER name: type:.MyRec + BLOCK_BODY + RETURN type=kotlin.Nothing from='public open fun hashCode (): kotlin.Int declared in .MyRec' + CALL 'public open fun hashCode (): kotlin.Int [fake_override] declared in kotlin.String' type=kotlin.Int origin=null + $this: GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:name type:kotlin.String visibility:private [final]' type=kotlin.String origin=null + receiver: GET_VAR ': .MyRec declared in .MyRec.hashCode' type=.MyRec origin=null + FUN GENERATED_DATA_CLASS_MEMBER name:equals visibility:public modality:OPEN <> ($this:.MyRec, other:kotlin.Any?) returnType:kotlin.Boolean [operator] + overridden: + public abstract fun equals (other: @[EnhancedNullability] kotlin.Any?): kotlin.Boolean [operator] declared in java.lang.Record + $this: VALUE_PARAMETER name: type:.MyRec + VALUE_PARAMETER name:other index:0 type:kotlin.Any? + BLOCK_BODY + WHEN type=kotlin.Unit origin=null + BRANCH + if: CALL 'public final fun EQEQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQEQ + arg0: GET_VAR ': .MyRec declared in .MyRec.equals' type=.MyRec origin=null + arg1: GET_VAR 'other: kotlin.Any? declared in .MyRec.equals' type=kotlin.Any? origin=null + then: RETURN type=kotlin.Nothing from='public open fun equals (other: kotlin.Any?): kotlin.Boolean [operator] declared in .MyRec' + CONST Boolean type=kotlin.Boolean value=true + WHEN type=kotlin.Unit origin=null + BRANCH + if: TYPE_OP type=kotlin.Boolean origin=NOT_INSTANCEOF typeOperand=.MyRec + GET_VAR 'other: kotlin.Any? declared in .MyRec.equals' type=kotlin.Any? origin=null + then: RETURN type=kotlin.Nothing from='public open fun equals (other: kotlin.Any?): kotlin.Boolean [operator] declared in .MyRec' + CONST Boolean type=kotlin.Boolean value=false + VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:.MyRec [val] + TYPE_OP type=.MyRec origin=CAST typeOperand=.MyRec + GET_VAR 'other: kotlin.Any? declared in .MyRec.equals' type=kotlin.Any? origin=null + WHEN type=kotlin.Unit origin=null + BRANCH + if: CALL 'public final fun not (): kotlin.Boolean [operator] declared in kotlin.Boolean' type=kotlin.Boolean origin=EXCLEQ + $this: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EXCLEQ + arg0: GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:name type:kotlin.String visibility:private [final]' type=kotlin.String origin=null + receiver: GET_VAR ': .MyRec declared in .MyRec.equals' type=.MyRec origin=null + arg1: GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:name type:kotlin.String visibility:private [final]' type=kotlin.String origin=null + receiver: GET_VAR 'val tmp_0: .MyRec [val] declared in .MyRec.equals' type=.MyRec origin=null + then: RETURN type=kotlin.Nothing from='public open fun equals (other: kotlin.Any?): kotlin.Boolean [operator] declared in .MyRec' + CONST Boolean type=kotlin.Boolean value=false + RETURN type=kotlin.Nothing from='public open fun equals (other: kotlin.Any?): kotlin.Boolean [operator] declared in .MyRec' + CONST Boolean type=kotlin.Boolean value=true + FUN name:test visibility:public modality:FINAL <> (rec:.MyRec) returnType:kotlin.Unit + VALUE_PARAMETER name:rec index:0 type:.MyRec + BLOCK_BODY + TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + CALL 'public final fun (): kotlin.String declared in .MyRec' type=kotlin.String origin=GET_PROPERTY + $this: GET_VAR 'rec: .MyRec declared in .test' type=.MyRec origin=null diff --git a/compiler/testData/ir/irText/declarations/jvmRecord/dataClassWithJvmRecord.kt b/compiler/testData/ir/irText/declarations/jvmRecord/dataClassWithJvmRecord.kt new file mode 100644 index 00000000000..98b2a8ce582 --- /dev/null +++ b/compiler/testData/ir/irText/declarations/jvmRecord/dataClassWithJvmRecord.kt @@ -0,0 +1,11 @@ +// TARGET_BACKEND: JVM_IR +// JDK_KIND: FULL_JDK_17 +// WITH_STDLIB +// JVM_TARGET: 17 + +@JvmRecord +data class MyRec(val name: String) + +fun test(rec: MyRec) { + rec.name +} diff --git a/compiler/testData/ir/irText/declarations/jvmRecord/dataClassWithJvmRecord.kt.txt b/compiler/testData/ir/irText/declarations/jvmRecord/dataClassWithJvmRecord.kt.txt new file mode 100644 index 00000000000..ba59a70d228 --- /dev/null +++ b/compiler/testData/ir/irText/declarations/jvmRecord/dataClassWithJvmRecord.kt.txt @@ -0,0 +1,47 @@ +@JvmRecord +data class MyRec : Record { + constructor(name: String) /* primary */ { + super/*Record*/() + /* () */ + + } + + val name: String + field = name + get + + operator fun component1(): String { + return .#name + } + + fun copy(name: String = .#name): MyRec { + return MyRec(name = name) + } + + override fun toString(): String { + return "MyRec(" + "name=" + .#name + ")" + } + + override fun hashCode(): Int { + return .#name.hashCode() + } + + override operator fun equals(other: Any?): Boolean { + when { + EQEQEQ(arg0 = , arg1 = other) -> return true + } + when { + other !is MyRec -> return false + } + val tmp0_other_with_cast: MyRec = other as MyRec + when { + EQEQ(arg0 = .#name, arg1 = tmp0_other_with_cast.#name).not() -> return false + } + return true + } + +} + +fun test(rec: MyRec) { + rec.() /*~> Unit */ +} diff --git a/compiler/tests-common-new/build.gradle.kts b/compiler/tests-common-new/build.gradle.kts index 7e1c3649351..9f6e81886d4 100644 --- a/compiler/tests-common-new/build.gradle.kts +++ b/compiler/tests-common-new/build.gradle.kts @@ -39,20 +39,11 @@ dependencies { optInToExperimentalCompilerApi() -val generationRoot = projectDir.resolve("tests-gen") - sourceSets { "main" { none() } "test" { projectDefault() - this.java.srcDir(generationRoot.name) - } -} - -if (kotlinBuildProperties.isInJpsBuildIdeaSync) { - apply(plugin = "idea") - idea { - this.module.generatedSourceDirs.add(generationRoot) + generatedTestDir() } } diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ir/IrTextTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ir/IrTextTestGenerated.java index 4c39305fca5..4b55f1f7a4f 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ir/IrTextTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ir/IrTextTestGenerated.java @@ -951,6 +951,12 @@ public class IrTextTestGenerated extends AbstractIrTextTest { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/ir/irText/declarations/jvmRecord"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @Test + @TestMetadata("dataClassWithJvmRecord.kt") + public void testDataClassWithJvmRecord() throws Exception { + runTest("compiler/testData/ir/irText/declarations/jvmRecord/dataClassWithJvmRecord.kt"); + } + @Test @TestMetadata("javaRecordComponentAccess.kt") public void testJavaRecordComponentAccess() throws Exception { diff --git a/core/compiler.common/src/org/jetbrains/kotlin/name/StandardClassIds.kt b/core/compiler.common/src/org/jetbrains/kotlin/name/StandardClassIds.kt index ffbafe158cc..28affb65b73 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/name/StandardClassIds.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/name/StandardClassIds.kt @@ -157,6 +157,7 @@ object StandardClassIds { val JvmField = "JvmField".jvmId() val JvmDefault = "JvmDefault".jvmId() val JvmRepeatable = "JvmRepeatable".jvmId() + val JvmRecord = "JvmRecord".jvmId() val RawTypeAnnotation = "RawType".internalIrId() val FlexibleNullability = "FlexibleNullability".internalIrId() @@ -202,6 +203,10 @@ object StandardClassIds { val not = "not".callableId(Boolean) } + + object Java { + val Record = "Record".javaLangId() + } } private fun String.baseId() = ClassId(StandardClassIds.BASE_KOTLIN_PACKAGE, Name.identifier(this))