[FE, IR] Check annotations on expect and actual enum entries

^KT-60668
^KT-60936
This commit is contained in:
Roman Efremov
2023-08-17 17:34:23 +02:00
committed by Space Team
parent b57940a59b
commit def4388c19
10 changed files with 89 additions and 1 deletions
@@ -758,6 +758,12 @@ public class FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated extends Abst
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/differentOrder.kt");
}
@Test
@TestMetadata("enumEntries.kt")
public void testEnumEntries() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/enumEntries.kt");
}
@Test
@TestMetadata("fakeOverrides.kt")
public void testFakeOverrides() throws Exception {
@@ -758,6 +758,12 @@ public class FirOldFrontendMPPDiagnosticsWithPsiTestGenerated extends AbstractFi
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/differentOrder.kt");
}
@Test
@TestMetadata("enumEntries.kt")
public void testEnumEntries() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/enumEntries.kt");
}
@Test
@TestMetadata("fakeOverrides.kt")
public void testFakeOverrides() throws Exception {
@@ -238,6 +238,10 @@ class FirExpectActualMatchingContextImpl private constructor(
return asSymbol().fir.collectEnumEntries().map { it.name }
}
override fun RegularClassSymbolMarker.collectEnumEntries(): List<DeclarationSymbolMarker> {
return asSymbol().fir.collectEnumEntries().map { it.symbol }
}
override val CallableSymbolMarker.dispatchReceiverType: SimpleTypeMarker?
get() = asSymbol().dispatchReceiverType
override val CallableSymbolMarker.extensionReceiverType: KotlinTypeMarker?
@@ -267,6 +267,10 @@ internal abstract class IrExpectActualMatchingContext(
return asIr().declarations.filterIsInstance<IrEnumEntry>().map { it.name }
}
override fun RegularClassSymbolMarker.collectEnumEntries(): List<DeclarationSymbolMarker> {
return asIr().declarations.filterIsInstance<IrEnumEntry>().map { it.symbol }
}
override val CallableSymbolMarker.dispatchReceiverType: KotlinTypeMarker?
get() = (asIr().parent as? IrClass)?.defaultType
@@ -5,8 +5,10 @@
package org.jetbrains.kotlin.resolve.calls.mpp
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.mpp.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.resolve.checkers.OptInNames
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility
@@ -80,6 +82,9 @@ object AbstractExpectActualAnnotationMatchChecker {
if (checkClassScopesForAnnotationCompatibility) {
checkAnnotationsInClassMemberScope(expectSymbol, actualSymbol)?.let { return it }
}
if (expectSymbol.classKind == ClassKind.ENUM_CLASS && actualSymbol.classKind == ClassKind.ENUM_CLASS) {
checkAnnotationsOnEnumEntries(expectSymbol, actualSymbol)?.let { return it }
}
return null
}
@@ -170,4 +175,27 @@ object AbstractExpectActualAnnotationMatchChecker {
}
return null
}
context (ExpectActualMatchingContext<*>)
private fun checkAnnotationsOnEnumEntries(
expectClassSymbol: RegularClassSymbolMarker,
actualClassSymbol: RegularClassSymbolMarker,
): Incompatibility? {
fun DeclarationSymbolMarker.getEnumEntryName(): Name =
when (this) {
is CallableSymbolMarker -> callableId.callableName
is RegularClassSymbolMarker -> classId.shortClassName
else -> error("Unexpected type $this")
}
val expectEnumEntries = expectClassSymbol.collectEnumEntries()
val actualEnumEntriesByName = actualClassSymbol.collectEnumEntries().associateBy { it.getEnumEntryName() }
for (expectEnumEntry in expectEnumEntries) {
val actualEnumEntry = actualEnumEntriesByName[expectEnumEntry.getEnumEntryName()] ?: continue
areAnnotationsSetOnDeclarationsCompatible(expectEnumEntry, actualEnumEntry)
?.let { return it }
}
return null
}
}
@@ -111,6 +111,7 @@ interface ExpectActualMatchingContext<T : DeclarationSymbolMarker> : TypeSystemC
fun RegularClassSymbolMarker.getMembersForExpectClass(name: Name): List<DeclarationSymbolMarker>
fun RegularClassSymbolMarker.collectEnumEntryNames(): List<Name>
fun RegularClassSymbolMarker.collectEnumEntries(): List<DeclarationSymbolMarker>
val CallableSymbolMarker.dispatchReceiverType: KotlinTypeMarker?
val CallableSymbolMarker.extensionReceiverType: KotlinTypeMarker?
@@ -176,11 +176,14 @@ class ClassicExpectActualMatchingContext(
}
override fun RegularClassSymbolMarker.collectEnumEntryNames(): List<Name> {
return collectEnumEntries().map { it.name }
}
override fun RegularClassSymbolMarker.collectEnumEntries(): List<DeclarationDescriptor> {
return asDescriptor()
.unsubstitutedMemberScope
.getDescriptorsFiltered()
.filter(DescriptorUtils::isEnumEntry)
.map { it.name }
}
override val CallableSymbolMarker.dispatchReceiverType: KotlinTypeMarker?
@@ -0,0 +1,15 @@
// MODULE: m1-common
// FILE: common.kt
annotation class Ann
<!INCOMPATIBLE_MATCHING{JVM}!>expect enum class E {
@Ann
FOO,
<!NO_ACTUAL_FOR_EXPECT{JVM}!>MISSING_ON_ACTUAL<!>
}<!>
// MODULE: m1-jvm()()(m1-common)
// FILE: jvm.kt
actual enum class <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT, ACTUAL_WITHOUT_EXPECT!>E<!> {
<!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>FOO<!>
}
@@ -0,0 +1,15 @@
// MODULE: m1-common
// FILE: common.kt
annotation class Ann
expect enum class E {
@Ann
FOO,
MISSING_ON_ACTUAL
}
// MODULE: m1-jvm()()(m1-common)
// FILE: jvm.kt
actual enum class <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT, ACTUAL_WITHOUT_EXPECT!>E<!> {
FOO
}
@@ -23527,6 +23527,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/differentOrder.kt");
}
@Test
@TestMetadata("enumEntries.kt")
public void testEnumEntries() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/enumEntries.kt");
}
@Test
@TestMetadata("fakeOverrides.kt")
public void testFakeOverrides() throws Exception {