[FIR] Generate java declarations for record components of java records

^KT-53964 Fixed
This commit is contained in:
Dmitriy Novozhilov
2022-09-30 14:51:58 +03:00
parent 2ed6e9febf
commit c0ad67c4f9
35 changed files with 469 additions and 71 deletions
@@ -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
}
}
}
@@ -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 {
@@ -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 {
@@ -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 {
@@ -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")
@@ -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")
@@ -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<FirTypeParameter>,
destination: MutableList<FirDeclaration>
) {
val functionsByName = destination.filterIsInstance<FirJavaMethod>().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<FirTypeParameter>.toRefs(): List<FirTypeParameterRef> {
return this.map { buildConstructedClassTypeParameterRef { symbol = it.symbol } }
}
}
@@ -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
@@ -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
}
@@ -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<Name> = 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
@@ -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)
@@ -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)
@@ -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()
@@ -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() {
@@ -1,5 +1,4 @@
// ENABLE_JVM_PREVIEW
// IGNORE_BACKEND_FIR: JVM_IR
// FILE: MyRec.java
public record MyRec(String name) {
public String getName() {
@@ -1,5 +1,4 @@
// !LANGUAGE: +JvmRecordSupport
// IGNORE_BACKEND_FIR: JVM_IR
// ENABLE_JVM_PREVIEW
// FILE: MyRec.java
public record MyRec(String name) {}
@@ -1,5 +1,4 @@
// WITH_REFLECT
// IGNORE_BACKEND_FIR: JVM_IR
// ISSUE: KT-47760
// FILE: MyRecord.java
@@ -14,11 +14,11 @@ class MyRec(
)
fun foo(jr: JRecord) {
JRecord(<!TOO_MANY_ARGUMENTS!>1<!>, <!TOO_MANY_ARGUMENTS!>""<!>)
JRecord(1, "")
jr.<!UNRESOLVED_REFERENCE!>x<!>()
jr.<!UNRESOLVED_REFERENCE!>y<!>()
jr.x()
jr.y()
jr.<!UNRESOLVED_REFERENCE!>x<!>
jr.<!UNRESOLVED_REFERENCE!>y<!>
jr.x
jr.y
}
@@ -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())
}
@@ -0,0 +1,3 @@
MyRecord:
[Enhancement]: public open fun x(): R|kotlin/String!| from Java enhancement scope for /MyRecord [id: 0]
@@ -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!
}
@@ -0,0 +1,31 @@
// FIR_IDENTICAL
// FIR_IDE_IGNORE
// FILE: MyInterface.java
public interface MyInterface<T> {
T x();
}
// FILE: MyRecord.java
public record MyRecord<T>(T x) implements MyInterface<T> {}
// FILE: main.kt
fun takeInt(x: Int) {}
fun takeString(s: String) {}
fun takeAny(a: Any) {}
fun test_1(mr: MyRecord<Int>) {
takeInt(mr.x)
takeInt(mr.x())
}
fun test_2(mr: MyRecord<String>) {
takeString(mr.x)
takeString(mr.x())
}
fun test_3(mr: MyRecord<*>) {
takeAny(mr.x)
takeAny(mr.x())
}
@@ -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.Int>): kotlin.Unit
public fun test_2(/*0*/ mr: MyRecord<kotlin.String>): kotlin.Unit
public fun test_3(/*0*/ mr: MyRecord<*>): kotlin.Unit
public interface MyInterface</*0*/ T : kotlin.Any!> {
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</*0*/ T : kotlin.Any!> : java.lang.Record, MyInterface<T!> {
public constructor MyRecord</*0*/ T : kotlin.Any!>(/*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!
}
@@ -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(<!TOO_MANY_ARGUMENTS!>1<!>, <!TOO_MANY_ARGUMENTS!>""<!>)
mr.<!UNRESOLVED_REFERENCE!>x<!>()
mr.<!UNRESOLVED_REFERENCE!>y<!>()
mr.<!UNRESOLVED_REFERENCE!>x<!>
mr.<!UNRESOLVED_REFERENCE!>y<!>
}
@@ -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<out String>) {}
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)
}
@@ -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<kotlin/String!>, kotlin/Array<out kotlin/String!>?>| from Java enhancement scope for /MyRecord [id: 0]
@@ -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<out kotlin.String>): 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!>!
}
@@ -0,0 +1,13 @@
FILE fqName:<root> fileName:/recordPropertyAccess.kt
FUN name:test_1 visibility:public modality:FINAL <> (rec:<root>.MyRec) returnType:kotlin.Unit
VALUE_PARAMETER name:rec index:0 type:<root>.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 <root>.MyRec' type=@[FlexibleNullability] kotlin.String? origin=GET_PROPERTY
$this: GET_VAR 'rec: <root>.MyRec declared in <root>.test_1' type=<root>.MyRec origin=null
FUN name:test_2 visibility:public modality:FINAL <> (rec:<root>.MyRec) returnType:kotlin.Unit
VALUE_PARAMETER name:rec index:0 type:<root>.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 <root>.MyRec' type=@[FlexibleNullability] kotlin.String? origin=null
$this: GET_VAR 'rec: <root>.MyRec declared in <root>.test_2' type=<root>.MyRec origin=null
@@ -0,0 +1,7 @@
fun test_1(rec: MyRec) {
rec.name() /*~> Unit */
}
fun test_2(rec: MyRec) {
rec.name() /*~> Unit */
}
@@ -0,0 +1,13 @@
FILE fqName:<root> fileName:/recordPropertyAccess.kt
FUN name:test_1 visibility:public modality:FINAL <> (rec:<root>.MyRec) returnType:kotlin.Unit
VALUE_PARAMETER name:rec index:0 type:<root>.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 <root>.MyRec' type=@[FlexibleNullability] kotlin.String? origin=GET_PROPERTY
$this: GET_VAR 'rec: <root>.MyRec declared in <root>.test_1' type=<root>.MyRec origin=null
FUN name:test_2 visibility:public modality:FINAL <> (rec:<root>.MyRec) returnType:kotlin.Unit
VALUE_PARAMETER name:rec index:0 type:<root>.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 <root>.MyRec' type=@[FlexibleNullability] kotlin.String? origin=null
$this: GET_VAR 'rec: <root>.MyRec declared in <root>.test_2' type=<root>.MyRec origin=null
@@ -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()
}
@@ -0,0 +1,7 @@
fun test_1(rec: MyRec) {
rec.name() /*~> Unit */
}
fun test_2(rec: MyRec) {
rec.name() /*~> Unit */
}
@@ -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 {
@@ -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")
@@ -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)