From c0ad67c4f96a980a0138aac94ae0912a954017da Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Fri, 30 Sep 2022 14:51:58 +0300 Subject: [PATCH] [FIR] Generate java declarations for record components of java records ^KT-53964 Fixed --- .../api/fir/components/KtFirScopeProvider.kt | 4 +- ...CompilerTestFE10TestdataTestGenerated.java | 12 ++ ...irOldFrontendDiagnosticsTestGenerated.java | 12 ++ ...DiagnosticsWithLightTreeTestGenerated.java | 12 ++ .../runners/ir/Fir2IrTextTestGenerated.java | 16 +++ .../ir/LightTreeFir2IrTextTestGenerated.java | 16 +++ .../kotlin/fir/java/FirJavaFacade.kt | 117 ++++++++++++++++-- .../jetbrains/kotlin/fir/java/JavaUtils.kt | 3 + .../java/enhancement/SignatureEnhancement.kt | 9 +- .../kotlin/fir/resolve/calls/Synthetics.kt | 48 ++++--- .../fir/resolve/calls/tower/TowerLevels.kt | 6 +- .../org/jetbrains/kotlin/fir/ClassMembers.kt | 7 ++ .../org/jetbrains/kotlin/KtSourceElement.kt | 16 +++ .../recordDifferentPropertyOverride.kt | 1 - .../recordDifferentSyntheticProperty.kt | 1 - .../records/recordPropertyAccess.kt | 1 - .../sealed/javaRecordsViaKotlinReflection.kt | 1 - .../jvmRecord/disabledFeature.fir.kt | 10 +- .../javaRecordWithExplicitComponent.kt | 22 ++++ ...aRecordWithExplicitComponent.overrides.txt | 3 + .../javaRecordWithExplicitComponent.txt | 12 ++ .../jvmRecord/javaRecordWithGeneric.kt | 31 +++++ .../jvmRecord/javaRecordWithGeneric.txt | 24 ++++ .../jvmRecord/simpleRecords.fir.kt | 19 --- .../jvmRecord/simpleRecords.kt | 27 ++-- .../jvmRecord/simpleRecords.overrides.txt | 5 + .../jvmRecord/simpleRecords.txt | 11 +- .../javaRecordComponentAccess.fir.ir.txt | 13 ++ .../javaRecordComponentAccess.fir.kt.txt | 7 ++ .../javaRecordComponentAccess.ir.txt | 13 ++ .../jvmRecord/javaRecordComponentAccess.kt | 13 ++ .../javaRecordComponentAccess.kt.txt | 7 ++ .../test/runners/DiagnosticTestGenerated.java | 12 ++ .../test/runners/ir/IrTextTestGenerated.java | 16 +++ .../klib/KlibTextTestCaseGenerated.java | 13 ++ 35 files changed, 469 insertions(+), 71 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/javaRecordWithExplicitComponent.kt create mode 100644 compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/javaRecordWithExplicitComponent.overrides.txt create mode 100644 compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/javaRecordWithExplicitComponent.txt create mode 100644 compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/javaRecordWithGeneric.kt create mode 100644 compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/javaRecordWithGeneric.txt delete mode 100644 compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/simpleRecords.fir.kt create mode 100644 compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/simpleRecords.overrides.txt create mode 100644 compiler/testData/ir/irText/declarations/jvmRecord/javaRecordComponentAccess.fir.ir.txt create mode 100644 compiler/testData/ir/irText/declarations/jvmRecord/javaRecordComponentAccess.fir.kt.txt create mode 100644 compiler/testData/ir/irText/declarations/jvmRecord/javaRecordComponentAccess.ir.txt create mode 100644 compiler/testData/ir/irText/declarations/jvmRecord/javaRecordComponentAccess.kt create mode 100644 compiler/testData/ir/irText/declarations/jvmRecord/javaRecordComponentAccess.kt.txt diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirScopeProvider.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirScopeProvider.kt index 5c80ac3ca8b..7b0bd7453d3 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirScopeProvider.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirScopeProvider.kt @@ -180,7 +180,7 @@ internal class KtFirScopeProvider( return KtCompositeTypeScope( listOfNotNull( convertToKtTypeScope(firTypeScope), - FirSyntheticPropertiesScope.createIfSyntheticNamesProviderIsDefined(firSession, firTypeScope)?.let { convertToKtTypeScope(it) } + FirSyntheticPropertiesScope.createIfSyntheticNamesProviderIsDefined(firSession, type.coneType, firTypeScope)?.let { convertToKtTypeScope(it) } ), token ) @@ -278,4 +278,4 @@ private class EnumEntryContainingNamesAwareScope(private val originalScope: FirC override fun processDeclaredConstructors(processor: (FirConstructorSymbol) -> Unit) { // enum entries does not have constructors } -} \ No newline at end of file +} 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 083946023c8..2cd5daadd0e 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 @@ -32013,6 +32013,18 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag runTest("compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/irrelevantFields.kt"); } + @Test + @TestMetadata("javaRecordWithExplicitComponent.kt") + public void testJavaRecordWithExplicitComponent() throws Exception { + runTest("compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/javaRecordWithExplicitComponent.kt"); + } + + @Test + @TestMetadata("javaRecordWithGeneric.kt") + public void testJavaRecordWithGeneric() throws Exception { + runTest("compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/javaRecordWithGeneric.kt"); + } + @Test @TestMetadata("jvmRecordDescriptorStructure.kt") public void testJvmRecordDescriptorStructure() throws Exception { 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 a331e7668a8..571d6738660 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 @@ -32013,6 +32013,18 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti runTest("compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/irrelevantFields.kt"); } + @Test + @TestMetadata("javaRecordWithExplicitComponent.kt") + public void testJavaRecordWithExplicitComponent() throws Exception { + runTest("compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/javaRecordWithExplicitComponent.kt"); + } + + @Test + @TestMetadata("javaRecordWithGeneric.kt") + public void testJavaRecordWithGeneric() throws Exception { + runTest("compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/javaRecordWithGeneric.kt"); + } + @Test @TestMetadata("jvmRecordDescriptorStructure.kt") public void testJvmRecordDescriptorStructure() throws Exception { 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 442679d4105..f436205f938 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 @@ -32013,6 +32013,18 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac runTest("compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/irrelevantFields.kt"); } + @Test + @TestMetadata("javaRecordWithExplicitComponent.kt") + public void testJavaRecordWithExplicitComponent() throws Exception { + runTest("compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/javaRecordWithExplicitComponent.kt"); + } + + @Test + @TestMetadata("javaRecordWithGeneric.kt") + public void testJavaRecordWithGeneric() throws Exception { + runTest("compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/javaRecordWithGeneric.kt"); + } + @Test @TestMetadata("jvmRecordDescriptorStructure.kt") public void testJvmRecordDescriptorStructure() throws Exception { 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 7696759e209..6d94be62d9a 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 @@ -942,6 +942,22 @@ public class Fir2IrTextTestGenerated extends AbstractFir2IrTextTest { } } + @Nested + @TestMetadata("compiler/testData/ir/irText/declarations/jvmRecord") + @TestDataPath("$PROJECT_ROOT") + public class JvmRecord { + @Test + public void testAllFilesPresentInJvmRecord() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/ir/irText/declarations/jvmRecord"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); + } + + @Test + @TestMetadata("javaRecordComponentAccess.kt") + public void testJavaRecordComponentAccess() throws Exception { + runTest("compiler/testData/ir/irText/declarations/jvmRecord/javaRecordComponentAccess.kt"); + } + } + @Nested @TestMetadata("compiler/testData/ir/irText/declarations/multiplatform") @TestDataPath("$PROJECT_ROOT") 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 efb9110da96..429005f9624 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 @@ -942,6 +942,22 @@ public class LightTreeFir2IrTextTestGenerated extends AbstractLightTreeFir2IrTex } } + @Nested + @TestMetadata("compiler/testData/ir/irText/declarations/jvmRecord") + @TestDataPath("$PROJECT_ROOT") + public class JvmRecord { + @Test + public void testAllFilesPresentInJvmRecord() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/ir/irText/declarations/jvmRecord"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); + } + + @Test + @TestMetadata("javaRecordComponentAccess.kt") + public void testJavaRecordComponentAccess() throws Exception { + runTest("compiler/testData/ir/irText/declarations/jvmRecord/javaRecordComponentAccess.kt"); + } + } + @Nested @TestMetadata("compiler/testData/ir/irText/declarations/multiplatform") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaFacade.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaFacade.kt index 2481f93b8d4..5b44bda03ee 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaFacade.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaFacade.kt @@ -5,8 +5,7 @@ package org.jetbrains.kotlin.fir.java -import org.jetbrains.kotlin.KtFakeSourceElement -import org.jetbrains.kotlin.KtFakeSourceElementKind +import org.jetbrains.kotlin.* import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.EffectiveVisibility @@ -46,7 +45,6 @@ import org.jetbrains.kotlin.load.java.JvmAnnotationNames import org.jetbrains.kotlin.load.java.structure.* import org.jetbrains.kotlin.load.java.structure.impl.JavaElementImpl import org.jetbrains.kotlin.name.* -import org.jetbrains.kotlin.toKtPsiSourceElement import org.jetbrains.kotlin.types.Variance.INVARIANT import org.jetbrains.kotlin.util.OperatorNameConventions @@ -231,7 +229,7 @@ abstract class FirJavaFacade( val classIsAnnotation = javaClass.classKind == ClassKind.ANNOTATION_CLASS val moduleData = getModuleDataForClass(javaClass) return buildJavaClass { - source = (javaClass as? JavaElementImpl<*>)?.psi?.toKtPsiSourceElement() + source = javaClass.toSourceElement() this.moduleData = moduleData symbol = classSymbol name = javaClass.name @@ -292,6 +290,7 @@ abstract class FirJavaFacade( for (javaMethod in javaClass.methods) { if (javaMethod.isObjectMethodInInterface()) continue val firJavaMethod = convertJavaMethodToFir( + javaClass, javaMethod, classId, javaTypeParameterStack, @@ -360,6 +359,17 @@ abstract class FirJavaFacade( moduleData = moduleData, ) } + if (javaClass.isRecord) { + createDeclarationsForJavaRecord( + javaClass, + classId, + moduleData, + javaTypeParameterStack, + dispatchReceiver, + classTypeParameters, + declarations + ) + } }.apply { if (modality == Modality.SEALED) { val inheritors = javaClass.permittedTypes.mapNotNull { classifierType -> @@ -378,6 +388,80 @@ abstract class FirJavaFacade( } } } + + if (javaClass.isRecord) { + this.isJavaRecord = true + } + } + } + + private fun createDeclarationsForJavaRecord( + javaClass: JavaClass, + classId: ClassId, + moduleData: FirModuleData, + javaTypeParameterStack: JavaTypeParameterStack, + classType: ConeClassLikeType, + classTypeParameters: List, + destination: MutableList + ) { + val functionsByName = destination.filterIsInstance().groupBy { it.name } + + for (recordComponent in javaClass.recordComponents) { + val name = recordComponent.name + if (functionsByName[name].orEmpty().any { it.valueParameters.isEmpty() }) continue + + val componentId = CallableId(classId, name) + destination += buildJavaMethod { + this.moduleData = moduleData + source = recordComponent.toSourceElement(KtFakeSourceElementKind.JavaRecordComponentFunction) + symbol = FirNamedFunctionSymbol(componentId) + this.name = name + isFromSource = recordComponent.isFromSource + returnTypeRef = recordComponent.type.toFirJavaTypeRef(session, javaTypeParameterStack) + annotationBuilder = { emptyList() } + status = FirResolvedDeclarationStatusImpl( + Visibilities.Public, + Modality.FINAL, + EffectiveVisibility.Public + ) + dispatchReceiverType = classType + }.apply { + isJavaRecordComponent = true + } + } + + destination += buildJavaConstructor { + source = javaClass.toSourceElement(KtFakeSourceElementKind.ImplicitJavaRecordConstructor) + this.moduleData = moduleData + isFromSource = javaClass.isFromSource + + val constructorId = CallableId(classId, classId.shortClassName) + symbol = FirConstructorSymbol(constructorId) + status = FirResolvedDeclarationStatusImpl( + Visibilities.Public, + Modality.FINAL, + EffectiveVisibility.Public + ) + visibility = Visibilities.Public + isPrimary = true + returnTypeRef = classType.toFirResolvedTypeRef() + dispatchReceiverType = null + typeParameters += classTypeParameters.toRefs() + annotationBuilder = { emptyList() } + + javaClass.recordComponents.mapTo(valueParameters) { component -> + buildJavaValueParameter { + source = component.toSourceElement(KtFakeSourceElementKind.ImplicitRecordConstructorParameter) + this.moduleData = moduleData + isFromSource = component.isFromSource + returnTypeRef = component.type.toFirJavaTypeRef(session, javaTypeParameterStack) + name = component.name + isVararg = component.isVararg + annotationBuilder = { emptyList() } + } + } + }.apply { + containingClassForStaticMemberAttr = classType.lookupTag } } @@ -393,7 +477,7 @@ abstract class FirJavaFacade( val returnType = javaField.type return when { javaField.isEnumEntry -> buildEnumEntry { - source = (javaField as? JavaElementImpl<*>)?.psi?.toKtPsiSourceElement() + source = javaField.toSourceElement() this.moduleData = moduleData symbol = FirEnumEntrySymbol(fieldId) name = fieldName @@ -416,7 +500,7 @@ abstract class FirJavaFacade( containingClassForStaticMemberAttr = ConeClassLikeLookupTagImpl(classId) } else -> buildJavaField { - source = (javaField as? JavaElementImpl<*>)?.psi?.toKtPsiSourceElement() + source = javaField.toSourceElement() this.moduleData = moduleData symbol = FirFieldSymbol(fieldId) name = fieldName @@ -456,6 +540,7 @@ abstract class FirJavaFacade( } private fun convertJavaMethodToFir( + containingClass: JavaClass, javaMethod: JavaMethod, classId: ClassId, javaTypeParameterStack: JavaTypeParameterStack, @@ -468,7 +553,7 @@ abstract class FirJavaFacade( val returnType = javaMethod.returnType return buildJavaMethod { this.moduleData = moduleData - source = (javaMethod as? JavaElementImpl<*>)?.psi?.toKtPsiSourceElement() + source = javaMethod.toSourceElement() symbol = methodSymbol name = methodName isFromSource = javaMethod.isFromSource @@ -505,6 +590,9 @@ abstract class FirJavaFacade( if (javaMethod.isStatic) { containingClassForStaticMemberAttr = ConeClassLikeLookupTagImpl(classId) } + if (containingClass.isRecord && valueParameters.isEmpty() && containingClass.recordComponents.any { it.name == methodName }) { + isJavaRecordComponent = true + } } } @@ -514,8 +602,7 @@ abstract class FirJavaFacade( moduleData: FirModuleData, ): FirJavaValueParameter = buildJavaValueParameter { - source = (javaMethod as? JavaElementImpl<*>)?.psi - ?.toKtPsiSourceElement(KtFakeSourceElementKind.ImplicitJavaAnnotationConstructor) + source = javaMethod.toSourceElement(KtFakeSourceElementKind.ImplicitJavaAnnotationConstructor) this.moduleData = moduleData isFromSource = javaMethod.isFromSource returnTypeRef = firJavaMethod.returnTypeRef @@ -536,7 +623,7 @@ abstract class FirJavaFacade( ): FirJavaConstructor { val constructorSymbol = FirConstructorSymbol(constructorId) return buildJavaConstructor { - source = (javaConstructor as? JavaElementImpl<*>)?.psi?.toKtPsiSourceElement() + source = javaConstructor?.toSourceElement() this.moduleData = moduleData isFromSource = javaClass.isFromSource symbol = constructorSymbol @@ -559,7 +646,7 @@ abstract class FirJavaFacade( type = ownerClassBuilder.buildSelfTypeRef() } dispatchReceiverType = if (isThisInner) outerClassSymbol?.defaultType() else null - typeParameters += classTypeParameters.map { buildConstructedClassTypeParameterRef { symbol = it.symbol } } + typeParameters += classTypeParameters.toRefs() if (javaConstructor != null) { this.typeParameters += javaConstructor.typeParameters.convertTypeParameters(javaTypeParameterStack, constructorSymbol, moduleData) @@ -612,4 +699,12 @@ abstract class FirJavaFacade( private fun FqName.topLevelName() = asString().substringBefore(".") + + private fun JavaElement.toSourceElement(sourceElementKind: KtSourceElementKind = KtRealSourceElementKind): KtSourceElement? { + return (this as? JavaElementImpl<*>)?.psi?.toKtPsiSourceElement(sourceElementKind) + } + + private fun List.toRefs(): List { + return this.map { buildConstructedClassTypeParameterRef { symbol = it.symbol } } + } } diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaUtils.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaUtils.kt index 981f8f8dccc..985936281f4 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaUtils.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaUtils.kt @@ -8,6 +8,9 @@ package org.jetbrains.kotlin.fir.java import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.declarations.FirDeclarationDataKey +import org.jetbrains.kotlin.fir.declarations.FirDeclarationDataRegistry +import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind import org.jetbrains.kotlin.fir.expressions.FirArrayOfCall diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/SignatureEnhancement.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/SignatureEnhancement.kt index e09770bd8c3..db16bee0993 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/SignatureEnhancement.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/SignatureEnhancement.kt @@ -253,6 +253,8 @@ class FirSignatureEnhancement( annotations += valueParameter.annotations } } + var isJavaRecordComponent = false + val function = when (firMethod) { is FirJavaConstructor -> { val symbol = FirConstructorSymbol(methodId) @@ -296,6 +298,7 @@ class FirSignatureEnhancement( } } is FirJavaMethod -> { + isJavaRecordComponent = firMethod.isJavaRecordComponent ?: false FirSimpleFunctionBuilder().apply { source = firMethod.source moduleData = this@FirSignatureEnhancement.moduleData @@ -316,7 +319,11 @@ class FirSignatureEnhancement( }.apply { annotations += firMethod.annotations deprecationsProvider = annotations.getDeprecationsProviderFromAnnotations(fromJava = true, session.firCachesFactory) - }.build() + }.build().apply { + if (isJavaRecordComponent) { + this.isJavaRecordComponent = true + } + } return function.symbol } diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/calls/Synthetics.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/calls/Synthetics.kt index 473bca2165c..b7b36e9b284 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/calls/Synthetics.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/calls/Synthetics.kt @@ -12,15 +12,9 @@ import org.jetbrains.kotlin.fir.declarations.synthetic.buildSyntheticProperty import org.jetbrains.kotlin.fir.declarations.utils.isStatic import org.jetbrains.kotlin.fir.scopes.* import org.jetbrains.kotlin.fir.symbols.SyntheticSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirSyntheticPropertySymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol -import org.jetbrains.kotlin.fir.types.ConeClassLikeType +import org.jetbrains.kotlin.fir.symbols.impl.* +import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.ConeNullability.NOT_NULL -import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef -import org.jetbrains.kotlin.fir.types.typeContext -import org.jetbrains.kotlin.fir.types.withNullability import org.jetbrains.kotlin.name.CallableId import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.StandardClassIds @@ -46,28 +40,51 @@ class FirSyntheticFunctionSymbol( class FirSyntheticPropertiesScope private constructor( val session: FirSession, private val baseScope: FirTypeScope, + private val dispatchReceiverType: ConeKotlinType, private val syntheticNamesProvider: FirSyntheticNamesProvider ) : FirContainingNamesAwareScope() { companion object { fun createIfSyntheticNamesProviderIsDefined( session: FirSession, + dispatchReceiverType: ConeKotlinType, baseScope: FirTypeScope ): FirSyntheticPropertiesScope? { - val syntheticNamesProvider = session.syntheticNamesProvider - return if (syntheticNamesProvider != null) - FirSyntheticPropertiesScope(session, baseScope, syntheticNamesProvider) - else - null + val syntheticNamesProvider = session.syntheticNamesProvider ?: return null + return FirSyntheticPropertiesScope( + session, + baseScope, + dispatchReceiverType, + syntheticNamesProvider + ) } } override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) { val getterNames = syntheticNamesProvider.possibleGetterNamesByPropertyName(name) + var getterFound = false for (getterName in getterNames) { baseScope.processFunctionsByName(getterName) { - checkGetAndCreateSynthetic(name, getterName, it, processor) + checkGetAndCreateSynthetic(name, getterName, it, needCheckForSetter = true, processor) + getterFound = true } } + if (!getterFound && shouldSearchForJavaRecordComponents()) { + baseScope.processFunctionsByName(name) { + if (it.fir.isJavaRecordComponent == true) { + checkGetAndCreateSynthetic(name, name, it, needCheckForSetter = false, processor) + } + } + } + } + + private fun shouldSearchForJavaRecordComponents(): Boolean { + /* + * Fast path: if dispatch receiver type is simple type and corresponding + * class is not a java record then there is no need to additional + * search for record components + */ + val dispatchSymbol = dispatchReceiverType.toRegularClassSymbol(session) ?: return true + return dispatchSymbol.fir.isJavaRecord ?: false } override fun getCallableNames(): Set = baseScope.getCallableNames().flatMapTo(hashSetOf()) { propertyName -> @@ -80,6 +97,7 @@ class FirSyntheticPropertiesScope private constructor( propertyName: Name, getterName: Name, getterSymbol: FirFunctionSymbol<*>, + needCheckForSetter: Boolean, processor: (FirVariableSymbol<*>) -> Unit ) { if (getterSymbol !is FirNamedFunctionSymbol) return @@ -94,7 +112,7 @@ class FirSyntheticPropertiesScope private constructor( if (!getterSymbol.hasJavaOverridden()) return var matchingSetter: FirSimpleFunction? = null - if (getterReturnType != null) { + if (needCheckForSetter && getterReturnType != null) { val setterName = syntheticNamesProvider.setterNameByGetterName(getterName) baseScope.processFunctionsByName(setterName, fun(setterSymbol: FirNamedFunctionSymbol) { if (matchingSetter != null) return diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerLevels.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerLevels.kt index 8d9c303d8be..a1dafcf554e 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerLevels.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerLevels.kt @@ -105,7 +105,11 @@ class MemberScopeTowerLevel( } if (givenExtensionReceiverOptions.isEmpty()) { - val withSynthetic = FirSyntheticPropertiesScope.createIfSyntheticNamesProviderIsDefined(session, scope) + val withSynthetic = FirSyntheticPropertiesScope.createIfSyntheticNamesProviderIsDefined( + session, + dispatchReceiverValue.type, + scope + ) withSynthetic?.processScopeMembers { symbol -> empty = false output.consumeCandidate(symbol, dispatchReceiverValue, givenExtensionReceiverOptions = emptyList(), scope) diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/ClassMembers.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/ClassMembers.kt index 18b258c1dee..cf7b7283c1d 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/ClassMembers.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/ClassMembers.kt @@ -131,3 +131,10 @@ val FirCallableDeclaration.propertyIfAccessor: FirCallableDeclaration val FirCallableDeclaration.propertyIfBackingField: FirCallableDeclaration get() = (this as? FirBackingField)?.propertySymbol?.fir ?: this + +private object IsJavaRecordKey : FirDeclarationDataKey() +var FirRegularClass.isJavaRecord: Boolean? by FirDeclarationDataRegistry.data(IsJavaRecordKey) + +private object IsJavaRecordComponentKey : FirDeclarationDataKey() +var FirFunction.isJavaRecordComponent: Boolean? by FirDeclarationDataRegistry.data(IsJavaRecordComponentKey) + diff --git a/compiler/frontend.common/src/org/jetbrains/kotlin/KtSourceElement.kt b/compiler/frontend.common/src/org/jetbrains/kotlin/KtSourceElement.kt index 196ca836bd5..310e385f1b8 100644 --- a/compiler/frontend.common/src/org/jetbrains/kotlin/KtSourceElement.kt +++ b/compiler/frontend.common/src/org/jetbrains/kotlin/KtSourceElement.kt @@ -191,6 +191,22 @@ sealed class KtFakeSourceElementKind : KtSourceElementKind() { // with a fake source which refers to declared annotation methods object ImplicitAnnotationAnnotationConstructorParameter : KtFakeSourceElementKind() + // for java records implicit constructor is generated + // with a fake source which refers to containing class + object ImplicitJavaRecordConstructor : KtFakeSourceElementKind() + + // for java record constructor implicit parameters are generated + // with a fake source which refers to declared record components + object ImplicitRecordConstructorParameter : KtFakeSourceElementKind() + + // for java records implicit component functions are generated + // with a fake source which refers to corresponding component + object JavaRecordComponentFunction : KtFakeSourceElementKind() + + // for java records implicit component fields are generated + // with a fake source which refers to corresponding component + object JavaRecordComponentField : KtFakeSourceElementKind() + // for the implicit field storing the delegated object for class delegation // with a fake source that refers to the KtExpression that creates the delegate object ClassDelegationField : KtFakeSourceElementKind() diff --git a/compiler/testData/codegen/boxModernJdk/testsWithJava17/records/recordDifferentPropertyOverride.kt b/compiler/testData/codegen/boxModernJdk/testsWithJava17/records/recordDifferentPropertyOverride.kt index c756e55d2ce..9851a7ace63 100644 --- a/compiler/testData/codegen/boxModernJdk/testsWithJava17/records/recordDifferentPropertyOverride.kt +++ b/compiler/testData/codegen/boxModernJdk/testsWithJava17/records/recordDifferentPropertyOverride.kt @@ -1,5 +1,4 @@ // ENABLE_JVM_PREVIEW -// IGNORE_BACKEND_FIR: JVM_IR // FILE: MyRec.java public record MyRec(String name) implements KI { public String getName() { diff --git a/compiler/testData/codegen/boxModernJdk/testsWithJava17/records/recordDifferentSyntheticProperty.kt b/compiler/testData/codegen/boxModernJdk/testsWithJava17/records/recordDifferentSyntheticProperty.kt index 2ce99602ccb..bc1122e1707 100644 --- a/compiler/testData/codegen/boxModernJdk/testsWithJava17/records/recordDifferentSyntheticProperty.kt +++ b/compiler/testData/codegen/boxModernJdk/testsWithJava17/records/recordDifferentSyntheticProperty.kt @@ -1,5 +1,4 @@ // ENABLE_JVM_PREVIEW -// IGNORE_BACKEND_FIR: JVM_IR // FILE: MyRec.java public record MyRec(String name) { public String getName() { diff --git a/compiler/testData/codegen/boxModernJdk/testsWithJava17/records/recordPropertyAccess.kt b/compiler/testData/codegen/boxModernJdk/testsWithJava17/records/recordPropertyAccess.kt index 7f5d6b33f7a..e8e3d869b77 100644 --- a/compiler/testData/codegen/boxModernJdk/testsWithJava17/records/recordPropertyAccess.kt +++ b/compiler/testData/codegen/boxModernJdk/testsWithJava17/records/recordPropertyAccess.kt @@ -1,5 +1,4 @@ // !LANGUAGE: +JvmRecordSupport -// IGNORE_BACKEND_FIR: JVM_IR // ENABLE_JVM_PREVIEW // FILE: MyRec.java public record MyRec(String name) {} diff --git a/compiler/testData/codegen/boxModernJdk/testsWithJava17/sealed/javaRecordsViaKotlinReflection.kt b/compiler/testData/codegen/boxModernJdk/testsWithJava17/sealed/javaRecordsViaKotlinReflection.kt index 46cfac8902f..c9e2395758c 100644 --- a/compiler/testData/codegen/boxModernJdk/testsWithJava17/sealed/javaRecordsViaKotlinReflection.kt +++ b/compiler/testData/codegen/boxModernJdk/testsWithJava17/sealed/javaRecordsViaKotlinReflection.kt @@ -1,5 +1,4 @@ // WITH_REFLECT -// IGNORE_BACKEND_FIR: JVM_IR // ISSUE: KT-47760 // FILE: MyRecord.java diff --git a/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/disabledFeature.fir.kt b/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/disabledFeature.fir.kt index ab7f342a039..8ad8f6e0b9f 100644 --- a/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/disabledFeature.fir.kt +++ b/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/disabledFeature.fir.kt @@ -14,11 +14,11 @@ class MyRec( ) fun foo(jr: JRecord) { - JRecord(1, "") + JRecord(1, "") - jr.x() - jr.y() + jr.x() + jr.y() - jr.x - jr.y + jr.x + jr.y } diff --git a/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/javaRecordWithExplicitComponent.kt b/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/javaRecordWithExplicitComponent.kt new file mode 100644 index 00000000000..54fc17fc227 --- /dev/null +++ b/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/javaRecordWithExplicitComponent.kt @@ -0,0 +1,22 @@ +// FIR_IDENTICAL +// FIR_IDE_IGNORE +// API_VERSION: 1.5 +// LANGUAGE: +JvmRecordSupport +// SCOPE_DUMP: MyRecord:x + +// FILE: MyRecord.java +public record MyRecord(String x) { + public String x() { + System.out.println("hello"); + return x; + } +} + +// FILE: main.kt + +fun takeString(s: String) {} + +fun foo(mr: MyRecord) { + takeString(mr.x) + takeString(mr.x()) +} diff --git a/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/javaRecordWithExplicitComponent.overrides.txt b/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/javaRecordWithExplicitComponent.overrides.txt new file mode 100644 index 00000000000..a7864a4d9ea --- /dev/null +++ b/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/javaRecordWithExplicitComponent.overrides.txt @@ -0,0 +1,3 @@ +MyRecord: + [Enhancement]: public open fun x(): R|kotlin/String!| from Java enhancement scope for /MyRecord [id: 0] + diff --git a/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/javaRecordWithExplicitComponent.txt b/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/javaRecordWithExplicitComponent.txt new file mode 100644 index 00000000000..0b803b074dd --- /dev/null +++ b/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/javaRecordWithExplicitComponent.txt @@ -0,0 +1,12 @@ +package + +public fun foo(/*0*/ mr: MyRecord): kotlin.Unit +public fun takeString(/*0*/ s: kotlin.String): kotlin.Unit + +/*record*/ public final class MyRecord : java.lang.Record { + public constructor MyRecord(/*0*/ x: kotlin.String!) + public abstract override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public abstract override /*1*/ /*fake_override*/ fun toString(): kotlin.String + /*record component*/ public open fun x(): kotlin.String! +} diff --git a/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/javaRecordWithGeneric.kt b/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/javaRecordWithGeneric.kt new file mode 100644 index 00000000000..55e00598d75 --- /dev/null +++ b/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/javaRecordWithGeneric.kt @@ -0,0 +1,31 @@ +// FIR_IDENTICAL +// FIR_IDE_IGNORE + +// FILE: MyInterface.java +public interface MyInterface { + T x(); +} + +// FILE: MyRecord.java +public record MyRecord(T x) implements MyInterface {} + +// FILE: main.kt + +fun takeInt(x: Int) {} +fun takeString(s: String) {} +fun takeAny(a: Any) {} + +fun test_1(mr: MyRecord) { + takeInt(mr.x) + takeInt(mr.x()) +} + +fun test_2(mr: MyRecord) { + takeString(mr.x) + takeString(mr.x()) +} + +fun test_3(mr: MyRecord<*>) { + takeAny(mr.x) + takeAny(mr.x()) +} diff --git a/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/javaRecordWithGeneric.txt b/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/javaRecordWithGeneric.txt new file mode 100644 index 00000000000..e146869a28e --- /dev/null +++ b/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/javaRecordWithGeneric.txt @@ -0,0 +1,24 @@ +package + +public fun takeAny(/*0*/ a: kotlin.Any): kotlin.Unit +public fun takeInt(/*0*/ x: kotlin.Int): kotlin.Unit +public fun takeString(/*0*/ s: kotlin.String): kotlin.Unit +public fun test_1(/*0*/ mr: MyRecord): kotlin.Unit +public fun test_2(/*0*/ mr: MyRecord): kotlin.Unit +public fun test_3(/*0*/ mr: MyRecord<*>): kotlin.Unit + +public interface MyInterface { + 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 abstract fun x(): T! +} + +/*record*/ public final class MyRecord : java.lang.Record, MyInterface { + public constructor MyRecord(/*0*/ x: T!) + public abstract override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public abstract override /*2*/ /*fake_override*/ fun toString(): kotlin.String + /*record component*/ public open override /*1*/ fun x(): T! +} + diff --git a/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/simpleRecords.fir.kt b/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/simpleRecords.fir.kt deleted file mode 100644 index 3b5cac1279c..00000000000 --- a/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/simpleRecords.fir.kt +++ /dev/null @@ -1,19 +0,0 @@ -// FIR_IDE_IGNORE -// !API_VERSION: 1.5 -// !LANGUAGE: +JvmRecordSupport -// FILE: MyRecord.java -public record MyRecord(int x, CharSequence y) { - -} - -// FILE: main.kt - -fun foo(mr: MyRecord) { - MyRecord(1, "") - - mr.x() - mr.y() - - mr.x - mr.y -} diff --git a/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/simpleRecords.kt b/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/simpleRecords.kt index b824b9f131b..4359a58ba1f 100644 --- a/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/simpleRecords.kt +++ b/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/simpleRecords.kt @@ -1,19 +1,26 @@ +// FIR_IDENTICAL // FIR_IDE_IGNORE -// !API_VERSION: 1.5 -// !LANGUAGE: +JvmRecordSupport -// FILE: MyRecord.java -public record MyRecord(int x, CharSequence y) { +// API_VERSION: 1.5 +// LANGUAGE: +JvmRecordSupport +// SCOPE_DUMP: MyRecord:x;y;z -} +// FILE: MyRecord.java +public record MyRecord(CharSequence x, int y, String... z) {} // FILE: main.kt +fun takeInt(x: Int) {} +fun takeCharSequence(s: CharSequence) {} +fun takeStringArray(a: Array) {} + fun foo(mr: MyRecord) { - MyRecord(1, "") + MyRecord("", 1, "a", "b") - mr.x() - mr.y() + takeCharSequence(mr.x()) + takeInt(mr.y()) + takeStringArray(mr.z()) - mr.x - mr.y + takeCharSequence(mr.x) + takeInt(mr.y) + takeStringArray(mr.z) } diff --git a/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/simpleRecords.overrides.txt b/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/simpleRecords.overrides.txt new file mode 100644 index 00000000000..24e23fb0087 --- /dev/null +++ b/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/simpleRecords.overrides.txt @@ -0,0 +1,5 @@ +MyRecord: + [Enhancement]: public final fun x(): R|kotlin/CharSequence!| from Java enhancement scope for /MyRecord [id: 0] + [Enhancement]: public final fun y(): R|kotlin/Int| from Java enhancement scope for /MyRecord [id: 0] + [Enhancement]: public final fun z(): R|ft, kotlin/Array?>| from Java enhancement scope for /MyRecord [id: 0] + diff --git a/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/simpleRecords.txt b/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/simpleRecords.txt index b7fd8e172d0..5ed35fae770 100644 --- a/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/simpleRecords.txt +++ b/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/simpleRecords.txt @@ -1,12 +1,17 @@ package public fun foo(/*0*/ mr: MyRecord): kotlin.Unit +public fun takeCharSequence(/*0*/ s: kotlin.CharSequence): kotlin.Unit +public fun takeInt(/*0*/ x: kotlin.Int): kotlin.Unit +public fun takeStringArray(/*0*/ a: kotlin.Array): kotlin.Unit /*record*/ public final class MyRecord : java.lang.Record { - public constructor MyRecord(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.CharSequence!) + public constructor MyRecord(/*0*/ x: kotlin.CharSequence!, /*1*/ y: kotlin.Int, /*2*/ vararg z: kotlin.String! /*kotlin.Array<(out) kotlin.String!>!*/) public abstract override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public abstract override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public abstract override /*1*/ /*fake_override*/ fun toString(): kotlin.String - /*record component*/ public open fun x(): kotlin.Int - /*record component*/ public open fun y(): kotlin.CharSequence! + /*record component*/ public open fun x(): kotlin.CharSequence! + /*record component*/ public open fun y(): kotlin.Int + /*record component*/ public open fun z(): kotlin.Array<(out) kotlin.String!>! } + diff --git a/compiler/testData/ir/irText/declarations/jvmRecord/javaRecordComponentAccess.fir.ir.txt b/compiler/testData/ir/irText/declarations/jvmRecord/javaRecordComponentAccess.fir.ir.txt new file mode 100644 index 00000000000..78545b9409e --- /dev/null +++ b/compiler/testData/ir/irText/declarations/jvmRecord/javaRecordComponentAccess.fir.ir.txt @@ -0,0 +1,13 @@ +FILE fqName: fileName:/recordPropertyAccess.kt + FUN name:test_1 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 name (): @[FlexibleNullability] kotlin.String? declared in .MyRec' type=@[FlexibleNullability] kotlin.String? origin=GET_PROPERTY + $this: GET_VAR 'rec: .MyRec declared in .test_1' type=.MyRec origin=null + FUN name:test_2 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 name (): @[FlexibleNullability] kotlin.String? declared in .MyRec' type=@[FlexibleNullability] kotlin.String? origin=null + $this: GET_VAR 'rec: .MyRec declared in .test_2' type=.MyRec origin=null diff --git a/compiler/testData/ir/irText/declarations/jvmRecord/javaRecordComponentAccess.fir.kt.txt b/compiler/testData/ir/irText/declarations/jvmRecord/javaRecordComponentAccess.fir.kt.txt new file mode 100644 index 00000000000..39fc17fcd02 --- /dev/null +++ b/compiler/testData/ir/irText/declarations/jvmRecord/javaRecordComponentAccess.fir.kt.txt @@ -0,0 +1,7 @@ +fun test_1(rec: MyRec) { + rec.name() /*~> Unit */ +} + +fun test_2(rec: MyRec) { + rec.name() /*~> Unit */ +} diff --git a/compiler/testData/ir/irText/declarations/jvmRecord/javaRecordComponentAccess.ir.txt b/compiler/testData/ir/irText/declarations/jvmRecord/javaRecordComponentAccess.ir.txt new file mode 100644 index 00000000000..510d7e0a4bc --- /dev/null +++ b/compiler/testData/ir/irText/declarations/jvmRecord/javaRecordComponentAccess.ir.txt @@ -0,0 +1,13 @@ +FILE fqName: fileName:/recordPropertyAccess.kt + FUN name:test_1 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 open fun name (): @[FlexibleNullability] kotlin.String? declared in .MyRec' type=@[FlexibleNullability] kotlin.String? origin=GET_PROPERTY + $this: GET_VAR 'rec: .MyRec declared in .test_1' type=.MyRec origin=null + FUN name:test_2 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 open fun name (): @[FlexibleNullability] kotlin.String? declared in .MyRec' type=@[FlexibleNullability] kotlin.String? origin=null + $this: GET_VAR 'rec: .MyRec declared in .test_2' type=.MyRec origin=null diff --git a/compiler/testData/ir/irText/declarations/jvmRecord/javaRecordComponentAccess.kt b/compiler/testData/ir/irText/declarations/jvmRecord/javaRecordComponentAccess.kt new file mode 100644 index 00000000000..cd35408fd8c --- /dev/null +++ b/compiler/testData/ir/irText/declarations/jvmRecord/javaRecordComponentAccess.kt @@ -0,0 +1,13 @@ +// TARGET_BACKEND: JVM_IR +// JDK_KIND: FULL_JDK_17 +// FILE: MyRec.java +public record MyRec(String name) {} + +// FILE: recordPropertyAccess.kt +fun test_1(rec: MyRec) { + rec.name +} + +fun test_2(rec: MyRec) { + rec.name() +} diff --git a/compiler/testData/ir/irText/declarations/jvmRecord/javaRecordComponentAccess.kt.txt b/compiler/testData/ir/irText/declarations/jvmRecord/javaRecordComponentAccess.kt.txt new file mode 100644 index 00000000000..39fc17fcd02 --- /dev/null +++ b/compiler/testData/ir/irText/declarations/jvmRecord/javaRecordComponentAccess.kt.txt @@ -0,0 +1,7 @@ +fun test_1(rec: MyRec) { + rec.name() /*~> Unit */ +} + +fun test_2(rec: MyRec) { + rec.name() /*~> Unit */ +} 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 a1622c5891b..1bfe110bd66 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 @@ -32103,6 +32103,18 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/irrelevantFields.kt"); } + @Test + @TestMetadata("javaRecordWithExplicitComponent.kt") + public void testJavaRecordWithExplicitComponent() throws Exception { + runTest("compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/javaRecordWithExplicitComponent.kt"); + } + + @Test + @TestMetadata("javaRecordWithGeneric.kt") + public void testJavaRecordWithGeneric() throws Exception { + runTest("compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/javaRecordWithGeneric.kt"); + } + @Test @TestMetadata("jvmRecordDescriptorStructure.kt") public void testJvmRecordDescriptorStructure() throws Exception { 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 57a3fec1ca2..4c39305fca5 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 @@ -942,6 +942,22 @@ public class IrTextTestGenerated extends AbstractIrTextTest { } } + @Nested + @TestMetadata("compiler/testData/ir/irText/declarations/jvmRecord") + @TestDataPath("$PROJECT_ROOT") + public class JvmRecord { + @Test + public void testAllFilesPresentInJvmRecord() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/ir/irText/declarations/jvmRecord"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); + } + + @Test + @TestMetadata("javaRecordComponentAccess.kt") + public void testJavaRecordComponentAccess() throws Exception { + runTest("compiler/testData/ir/irText/declarations/jvmRecord/javaRecordComponentAccess.kt"); + } + } + @Nested @TestMetadata("compiler/testData/ir/irText/declarations/multiplatform") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/tests-gen/org/jetbrains/kotlin/klib/KlibTextTestCaseGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/klib/KlibTextTestCaseGenerated.java index af87948cb9b..da27da675e3 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/klib/KlibTextTestCaseGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/klib/KlibTextTestCaseGenerated.java @@ -687,6 +687,19 @@ public class KlibTextTestCaseGenerated extends AbstractKlibTextTestCase { } } + @TestMetadata("compiler/testData/ir/irText/declarations/jvmRecord") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class JvmRecord extends AbstractKlibTextTestCase { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.JS_IR, testDataFilePath); + } + + public void testAllFilesPresentInJvmRecord() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/ir/irText/declarations/jvmRecord"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true); + } + } + @TestMetadata("compiler/testData/ir/irText/declarations/multiplatform") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)