[FIR, IR] Check for strict subtypes during actualization

^KT-65775 Fixed
Review: https://jetbrains.team/p/kt/reviews/14906/timeline
This commit is contained in:
Nikita Bobko
2024-03-12 17:34:47 +01:00
committed by Space Team
parent 0fec50135f
commit a8275c99a3
12 changed files with 102 additions and 16 deletions
@@ -24765,6 +24765,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia
runTest("compiler/testData/diagnostics/tests/multiplatform/actualMissingConstructor.kt");
}
@Test
@TestMetadata("actualTypealiasCycle.kt")
public void testActualTypealiasCycle() {
runTest("compiler/testData/diagnostics/tests/multiplatform/actualTypealiasCycle.kt");
}
@Test
@TestMetadata("actualTypealiasForNotExpectClass.kt")
public void testActualTypealiasForNotExpectClass() {
@@ -24765,6 +24765,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated
runTest("compiler/testData/diagnostics/tests/multiplatform/actualMissingConstructor.kt");
}
@Test
@TestMetadata("actualTypealiasCycle.kt")
public void testActualTypealiasCycle() {
runTest("compiler/testData/diagnostics/tests/multiplatform/actualTypealiasCycle.kt");
}
@Test
@TestMetadata("actualTypealiasForNotExpectClass.kt")
public void testActualTypealiasForNotExpectClass() {
@@ -32,6 +32,12 @@ public class FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated extends Abst
runTest("compiler/testData/diagnostics/tests/multiplatform/actualMissingConstructor.kt");
}
@Test
@TestMetadata("actualTypealiasCycle.kt")
public void testActualTypealiasCycle() {
runTest("compiler/testData/diagnostics/tests/multiplatform/actualTypealiasCycle.kt");
}
@Test
@TestMetadata("actualTypealiasForNotExpectClass.kt")
public void testActualTypealiasForNotExpectClass() {
@@ -32,6 +32,12 @@ public class FirOldFrontendMPPDiagnosticsWithPsiTestGenerated extends AbstractFi
runTest("compiler/testData/diagnostics/tests/multiplatform/actualMissingConstructor.kt");
}
@Test
@TestMetadata("actualTypealiasCycle.kt")
public void testActualTypealiasCycle() {
runTest("compiler/testData/diagnostics/tests/multiplatform/actualTypealiasCycle.kt");
}
@Test
@TestMetadata("actualTypealiasForNotExpectClass.kt")
public void testActualTypealiasForNotExpectClass() {
@@ -15,8 +15,6 @@ import org.jetbrains.kotlin.fir.declarations.utils.isExpect
import org.jetbrains.kotlin.fir.declarations.utils.isJava
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.resolve.providers.getRegularClassSymbolByClassId
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.toSymbol
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.scopes.*
@@ -35,7 +33,6 @@ import org.jetbrains.kotlin.resolve.calls.mpp.ExpectActualMatchingContext.Annota
import org.jetbrains.kotlin.resolve.checkers.OptInNames
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualMatchingCompatibility
import org.jetbrains.kotlin.types.AbstractTypeChecker
import org.jetbrains.kotlin.types.AbstractTypeRefiner
import org.jetbrains.kotlin.types.TypeCheckerState
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.model.*
@@ -346,11 +343,11 @@ class FirExpectActualMatchingContextImpl private constructor(
return ConeClassLikeTypeImpl(lookupTag, argumentsWithOutProjection, isNullable)
}
override fun actualTypeIsSubtypeOfExpectType(expectType: KotlinTypeMarker, actualType: KotlinTypeMarker): Boolean {
override fun isSubtypeOf(superType: KotlinTypeMarker, subType: KotlinTypeMarker): Boolean {
return AbstractTypeChecker.isSubtypeOf(
createTypeCheckerState(),
subType = actualType,
superType = expectType
subType = subType,
superType = superType
)
}
@@ -393,11 +393,11 @@ internal abstract class IrExpectActualMatchingContext(
return typeContext.newTypeCheckerState(errorTypesEqualToAnything = true, stubTypesEqualToAnything = false)
}
override fun actualTypeIsSubtypeOfExpectType(expectType: KotlinTypeMarker, actualType: KotlinTypeMarker): Boolean {
override fun isSubtypeOf(superType: KotlinTypeMarker, subType: KotlinTypeMarker): Boolean {
return AbstractTypeChecker.isSubtypeOf(
createTypeCheckerState(),
subType = actualType.actualize(),
superType = expectType.actualize()
subType = subType.actualize(),
superType = superType.actualize()
)
}
@@ -165,10 +165,9 @@ object AbstractExpectActualChecker {
val expectSupertypes = expectClassSymbol.superTypes.filterNot { it.typeConstructor().isAnyConstructor() }
val actualType = actualClassSymbol.defaultType
return expectSupertypes.all { expectSupertype ->
actualTypeIsSubtypeOfExpectType(
expectType = substitutor.safeSubstitute(expectSupertype),
actualType = actualType
)
val expectType = substitutor.safeSubstitute(expectSupertype)
isSubtypeOf(superType = expectType, subType = actualType) &&
!isSubtypeOf(superType = actualType, subType = expectType)
}
}
@@ -131,9 +131,9 @@ interface ExpectActualMatchingContext<T : DeclarationSymbolMarker> : TypeSystemC
dynamicTypesEqualToAnything: Boolean = true
): Boolean
fun actualTypeIsSubtypeOfExpectType(
expectType: KotlinTypeMarker,
actualType: KotlinTypeMarker
fun isSubtypeOf(
superType: KotlinTypeMarker,
subType: KotlinTypeMarker
): Boolean
fun RegularClassSymbolMarker.isNotSamInterface(): Boolean
@@ -0,0 +1,20 @@
// MODULE: m1-common
// FILE: common.kt
open class A {}
<!EXPECT_ACTUAL_INCOMPATIBILITY{JVM}("B; B; some supertypes are missing in the actual declaration")!>expect class B : A<!>
expect open class A2() {}
<!EXPECT_ACTUAL_INCOMPATIBILITY{JVM}("B2; B2; some supertypes are missing in the actual declaration")!>expect open class B2 : A2 {}<!>
expect open class A3
// MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt
actual typealias <!ACTUAL_WITHOUT_EXPECT("actual typealias B = A; The following declaration is incompatible because some supertypes are missing in the actual declaration: expect class B : A")!>B<!> = A
actual typealias A2 = B2
actual open class <!ACTUAL_WITHOUT_EXPECT("actual class B2 : Any; The following declaration is incompatible because some supertypes are missing in the actual declaration: expect class B2 : A2")!>B2<!> {}
actual typealias A3 = Any
@@ -0,0 +1,20 @@
// MODULE: m1-common
// FILE: common.kt
open class A {}
expect class B : A
expect open class A2() {}
expect open class B2 : <!CYCLIC_INHERITANCE_HIERARCHY{JVM}!>A2<!> {}
expect open class A3
// MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt
actual typealias <!ACTUAL_WITHOUT_EXPECT!>B<!> = A
actual typealias A2 = B2
actual open class B2 {}
actual typealias A3 = Any
@@ -0,0 +1,20 @@
// MODULE: m1-common
// FILE: common.kt
open class A {}
expect class B : A
expect open class A2() {}
expect open class B2 : A2 {}
expect open class A3
// MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt
actual typealias <!ACTUAL_WITHOUT_EXPECT!>B<!> = A
actual typealias A2 = B2
actual open class <!ACTUAL_WITHOUT_EXPECT!>B2<!> {}
actual typealias A3 = Any
@@ -24765,6 +24765,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/multiplatform/actualMissingConstructor.kt");
}
@Test
@TestMetadata("actualTypealiasCycle.kt")
public void testActualTypealiasCycle() {
runTest("compiler/testData/diagnostics/tests/multiplatform/actualTypealiasCycle.kt");
}
@Test
@TestMetadata("actualTypealiasForNotExpectClass.kt")
public void testActualTypealiasForNotExpectClass() {