[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:
+6
@@ -24765,6 +24765,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia
|
|||||||
runTest("compiler/testData/diagnostics/tests/multiplatform/actualMissingConstructor.kt");
|
runTest("compiler/testData/diagnostics/tests/multiplatform/actualMissingConstructor.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("actualTypealiasCycle.kt")
|
||||||
|
public void testActualTypealiasCycle() {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/multiplatform/actualTypealiasCycle.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("actualTypealiasForNotExpectClass.kt")
|
@TestMetadata("actualTypealiasForNotExpectClass.kt")
|
||||||
public void testActualTypealiasForNotExpectClass() {
|
public void testActualTypealiasForNotExpectClass() {
|
||||||
|
|||||||
+6
@@ -24765,6 +24765,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated
|
|||||||
runTest("compiler/testData/diagnostics/tests/multiplatform/actualMissingConstructor.kt");
|
runTest("compiler/testData/diagnostics/tests/multiplatform/actualMissingConstructor.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("actualTypealiasCycle.kt")
|
||||||
|
public void testActualTypealiasCycle() {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/multiplatform/actualTypealiasCycle.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("actualTypealiasForNotExpectClass.kt")
|
@TestMetadata("actualTypealiasForNotExpectClass.kt")
|
||||||
public void testActualTypealiasForNotExpectClass() {
|
public void testActualTypealiasForNotExpectClass() {
|
||||||
|
|||||||
+6
@@ -32,6 +32,12 @@ public class FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated extends Abst
|
|||||||
runTest("compiler/testData/diagnostics/tests/multiplatform/actualMissingConstructor.kt");
|
runTest("compiler/testData/diagnostics/tests/multiplatform/actualMissingConstructor.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("actualTypealiasCycle.kt")
|
||||||
|
public void testActualTypealiasCycle() {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/multiplatform/actualTypealiasCycle.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("actualTypealiasForNotExpectClass.kt")
|
@TestMetadata("actualTypealiasForNotExpectClass.kt")
|
||||||
public void testActualTypealiasForNotExpectClass() {
|
public void testActualTypealiasForNotExpectClass() {
|
||||||
|
|||||||
+6
@@ -32,6 +32,12 @@ public class FirOldFrontendMPPDiagnosticsWithPsiTestGenerated extends AbstractFi
|
|||||||
runTest("compiler/testData/diagnostics/tests/multiplatform/actualMissingConstructor.kt");
|
runTest("compiler/testData/diagnostics/tests/multiplatform/actualMissingConstructor.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("actualTypealiasCycle.kt")
|
||||||
|
public void testActualTypealiasCycle() {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/multiplatform/actualTypealiasCycle.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("actualTypealiasForNotExpectClass.kt")
|
@TestMetadata("actualTypealiasForNotExpectClass.kt")
|
||||||
public void testActualTypealiasForNotExpectClass() {
|
public void testActualTypealiasForNotExpectClass() {
|
||||||
|
|||||||
+3
-6
@@ -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.declarations.utils.isJava
|
||||||
import org.jetbrains.kotlin.fir.expressions.*
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.*
|
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.providers.toSymbol
|
||||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||||
import org.jetbrains.kotlin.fir.scopes.*
|
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.checkers.OptInNames
|
||||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualMatchingCompatibility
|
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualMatchingCompatibility
|
||||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||||
import org.jetbrains.kotlin.types.AbstractTypeRefiner
|
|
||||||
import org.jetbrains.kotlin.types.TypeCheckerState
|
import org.jetbrains.kotlin.types.TypeCheckerState
|
||||||
import org.jetbrains.kotlin.types.Variance
|
import org.jetbrains.kotlin.types.Variance
|
||||||
import org.jetbrains.kotlin.types.model.*
|
import org.jetbrains.kotlin.types.model.*
|
||||||
@@ -346,11 +343,11 @@ class FirExpectActualMatchingContextImpl private constructor(
|
|||||||
return ConeClassLikeTypeImpl(lookupTag, argumentsWithOutProjection, isNullable)
|
return ConeClassLikeTypeImpl(lookupTag, argumentsWithOutProjection, isNullable)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun actualTypeIsSubtypeOfExpectType(expectType: KotlinTypeMarker, actualType: KotlinTypeMarker): Boolean {
|
override fun isSubtypeOf(superType: KotlinTypeMarker, subType: KotlinTypeMarker): Boolean {
|
||||||
return AbstractTypeChecker.isSubtypeOf(
|
return AbstractTypeChecker.isSubtypeOf(
|
||||||
createTypeCheckerState(),
|
createTypeCheckerState(),
|
||||||
subType = actualType,
|
subType = subType,
|
||||||
superType = expectType
|
superType = superType
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -393,11 +393,11 @@ internal abstract class IrExpectActualMatchingContext(
|
|||||||
return typeContext.newTypeCheckerState(errorTypesEqualToAnything = true, stubTypesEqualToAnything = false)
|
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(
|
return AbstractTypeChecker.isSubtypeOf(
|
||||||
createTypeCheckerState(),
|
createTypeCheckerState(),
|
||||||
subType = actualType.actualize(),
|
subType = subType.actualize(),
|
||||||
superType = expectType.actualize()
|
superType = superType.actualize()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-4
@@ -165,10 +165,9 @@ object AbstractExpectActualChecker {
|
|||||||
val expectSupertypes = expectClassSymbol.superTypes.filterNot { it.typeConstructor().isAnyConstructor() }
|
val expectSupertypes = expectClassSymbol.superTypes.filterNot { it.typeConstructor().isAnyConstructor() }
|
||||||
val actualType = actualClassSymbol.defaultType
|
val actualType = actualClassSymbol.defaultType
|
||||||
return expectSupertypes.all { expectSupertype ->
|
return expectSupertypes.all { expectSupertype ->
|
||||||
actualTypeIsSubtypeOfExpectType(
|
val expectType = substitutor.safeSubstitute(expectSupertype)
|
||||||
expectType = substitutor.safeSubstitute(expectSupertype),
|
isSubtypeOf(superType = expectType, subType = actualType) &&
|
||||||
actualType = actualType
|
!isSubtypeOf(superType = actualType, subType = expectType)
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -131,9 +131,9 @@ interface ExpectActualMatchingContext<T : DeclarationSymbolMarker> : TypeSystemC
|
|||||||
dynamicTypesEqualToAnything: Boolean = true
|
dynamicTypesEqualToAnything: Boolean = true
|
||||||
): Boolean
|
): Boolean
|
||||||
|
|
||||||
fun actualTypeIsSubtypeOfExpectType(
|
fun isSubtypeOf(
|
||||||
expectType: KotlinTypeMarker,
|
superType: KotlinTypeMarker,
|
||||||
actualType: KotlinTypeMarker
|
subType: KotlinTypeMarker
|
||||||
): Boolean
|
): Boolean
|
||||||
|
|
||||||
fun RegularClassSymbolMarker.isNotSamInterface(): Boolean
|
fun RegularClassSymbolMarker.isNotSamInterface(): Boolean
|
||||||
|
|||||||
+20
@@ -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
|
||||||
Generated
+6
@@ -24765,6 +24765,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
|||||||
runTest("compiler/testData/diagnostics/tests/multiplatform/actualMissingConstructor.kt");
|
runTest("compiler/testData/diagnostics/tests/multiplatform/actualMissingConstructor.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("actualTypealiasCycle.kt")
|
||||||
|
public void testActualTypealiasCycle() {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/multiplatform/actualTypealiasCycle.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("actualTypealiasForNotExpectClass.kt")
|
@TestMetadata("actualTypealiasForNotExpectClass.kt")
|
||||||
public void testActualTypealiasForNotExpectClass() {
|
public void testActualTypealiasForNotExpectClass() {
|
||||||
|
|||||||
Reference in New Issue
Block a user