[FIR] Substitute parameter bounds when checking EXPANSIVE_INHERITANCE

^KT-63649 Fixed
This commit is contained in:
Brian Norman
2023-11-21 09:33:19 -06:00
committed by Space Team
parent 3f8505a090
commit f9933adf5e
7 changed files with 85 additions and 4 deletions
@@ -9753,6 +9753,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/declarationChecks/nonExpansiveInheritanceRestriction"), Pattern.compile("^(.+)\\.(kt|kts)$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true);
}
@Test
@TestMetadata("Comparable.kt")
public void testComparable() throws Exception {
runTest("compiler/testData/diagnostics/tests/declarationChecks/nonExpansiveInheritanceRestriction/Comparable.kt");
}
@Test
@TestMetadata("JavaWithKotlin.kt")
public void testJavaWithKotlin() throws Exception {
@@ -9753,6 +9753,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/declarationChecks/nonExpansiveInheritanceRestriction"), Pattern.compile("^(.+)\\.(kt|kts)$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true);
}
@Test
@TestMetadata("Comparable.kt")
public void testComparable() throws Exception {
runTest("compiler/testData/diagnostics/tests/declarationChecks/nonExpansiveInheritanceRestriction/Comparable.kt");
}
@Test
@TestMetadata("JavaWithKotlin.kt")
public void testJavaWithKotlin() throws Exception {
@@ -9747,6 +9747,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/declarationChecks/nonExpansiveInheritanceRestriction"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true, "multiplatform");
}
@Test
@TestMetadata("Comparable.kt")
public void testComparable() throws Exception {
runTest("compiler/testData/diagnostics/tests/declarationChecks/nonExpansiveInheritanceRestriction/Comparable.kt");
}
@Test
@TestMetadata("JavaWithKotlin.kt")
public void testJavaWithKotlin() throws Exception {
@@ -9753,6 +9753,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/declarationChecks/nonExpansiveInheritanceRestriction"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true, "multiplatform");
}
@Test
@TestMetadata("Comparable.kt")
public void testComparable() throws Exception {
runTest("compiler/testData/diagnostics/tests/declarationChecks/nonExpansiveInheritanceRestriction/Comparable.kt");
}
@Test
@TestMetadata("JavaWithKotlin.kt")
public void testJavaWithKotlin() throws Exception {
@@ -12,6 +12,8 @@ import org.jetbrains.kotlin.fir.analysis.checkers.collectUpperBounds
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
import org.jetbrains.kotlin.fir.scopes.impl.toConeType
import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
@@ -19,6 +21,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.utils.DFS
import org.jetbrains.kotlin.utils.SmartSet
import org.jetbrains.kotlin.utils.addToStdlib.runIf
/**
* @see org.jetbrains.kotlin.resolve.NonExpansiveInheritanceRestrictionChecker
@@ -81,6 +84,7 @@ object FirNonExpansiveInheritanceRestrictionChecker : FirRegularClassChecker() {
val visitedSymbols = SmartSet.create<FirClassifierSymbol<*>>()
fun visit(symbol: FirRegularClassSymbol) {
val typeParameters = symbol.typeParameterSymbols
if (typeParameters.isEmpty()) return
// For each type parameter T, let ST be the set of all constituent types of all immediate supertypes of the owner of T.
// If T appears as a constituent type of a simple type argument A in a generic type in ST, add an edge from T
@@ -89,10 +93,16 @@ object FirNonExpansiveInheritanceRestrictionChecker : FirRegularClassChecker() {
for (constituentType in symbol.resolvedSuperTypes.flatMap { it.constituentTypes() }) {
val constituentTypeSymbol = constituentType.toRegularClassSymbol(session) ?: continue
if (visitedSymbols.add(constituentTypeSymbol)) visit(constituentTypeSymbol)
if (constituentTypeSymbol.typeParameterSymbols.size != constituentType.typeArguments.size) continue
for ((i, typeProjection) in constituentType.typeArguments.withIndex()) {
val constituentTypeParameterSymbol = constituentTypeSymbol.typeParameterSymbols[i]
val parameters = constituentTypeSymbol.typeParameterSymbols
val arguments = constituentType.typeArguments.asList()
if (parameters.size != arguments.size) continue
val substitutor = runIf(arguments.any { it.kind != ProjectionKind.INVARIANT }) {
substitutorByType(parameters, arguments, session)
}
for ((i, typeProjection) in arguments.withIndex()) {
val constituentTypeParameterSymbol = parameters[i]
if (typeProjection.kind == ProjectionKind.INVARIANT) {
val constituents = typeProjection.type!!.constituentTypes()
@@ -109,7 +119,7 @@ object FirNonExpansiveInheritanceRestrictionChecker : FirRegularClassChecker() {
// upper bounds of a skolem type variable Q in a skolemization of a projected generic type in ST, add an
// expanding edge from T to V, where V is the type parameter corresponding to Q.
val bounds = SmartSet.create<ConeKotlinType>()
constituentTypeParameterSymbol.resolvedBounds.mapTo(bounds) { it.type }
constituentTypeParameterSymbol.resolvedBounds.mapNotNullTo(bounds) { substitutor!!.substituteOrNull(it.type) }
typeProjection.type?.let(bounds::add)
val boundClosure = bounds.flatMapTo(SmartSet.create()) { it.collectUpperBounds() }
@@ -173,3 +183,22 @@ private fun ConeKotlinType.constituentTypes(): Set<ConeKotlinType> {
forEachType { constituentTypes.add(it) }
return constituentTypes
}
private fun substitutorByType(
parameters: List<FirTypeParameterSymbol>,
arguments: List<ConeTypeProjection>,
session: FirSession,
): ConeSubstitutor {
require(parameters.size == arguments.size)
val substitution = buildMap {
for (index in parameters.indices) {
val argumentType = arguments[index].type
if (argumentType != null) {
put(parameters[index], argumentType)
}
}
}
return substitutorByMap(substitution, session)
}
@@ -0,0 +1,22 @@
// FIR_IDENTICAL
// SKIP_TXT
// ISSUE: KT-63649
interface Kind
interface System<S : System<S>>
interface Units<
K : Kind,
S : System<S>,
U : Units<K, S, U, M>,
M : Measure<K, S, U, M>,
>
: Comparable<Units<K, S, *, *>>
interface Measure<
K : Kind,
S : System<S>,
U : Units<K, S, U, M>,
M : Measure<K, S, U, M>,
>
: Comparable<Measure<K, S, *, *>>
@@ -9753,6 +9753,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/declarationChecks/nonExpansiveInheritanceRestriction"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true);
}
@Test
@TestMetadata("Comparable.kt")
public void testComparable() throws Exception {
runTest("compiler/testData/diagnostics/tests/declarationChecks/nonExpansiveInheritanceRestriction/Comparable.kt");
}
@Test
@TestMetadata("JavaWithKotlin.kt")
public void testJavaWithKotlin() throws Exception {