K2: fix CCE during bound conversion for Java raw Kotlin-based type

#KT-56630 Fixed
This commit is contained in:
Mikhail Glukhikh
2023-02-14 15:21:17 +01:00
committed by Space Team
parent d1e0a432a5
commit 58959951d3
8 changed files with 93 additions and 17 deletions
@@ -6699,6 +6699,12 @@ public class DiagnosisCompilerFirTestdataTestGenerated extends AbstractDiagnosis
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/problems/capturedTypeInEquality.kt");
}
@Test
@TestMetadata("classCastWithRawKotlinType.kt")
public void testClassCastWithRawKotlinType() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/problems/classCastWithRawKotlinType.kt");
}
@Test
@TestMetadata("DeepCopyIrTree.kt")
public void testDeepCopyIrTree() throws Exception {
@@ -0,0 +1,18 @@
FILE: test.kt
public abstract interface Inter : R|kotlin/Any| {
}
public open class Apple<T : R|Inter|> : R|Inter| {
public constructor<T : R|Inter|>(): R|Apple<T>| {
super<R|kotlin/Any|>()
}
}
public final class XXX : R|Usage| {
public constructor(): R|XXX| {
super<R|Usage|>()
}
}
public final fun main(): R|kotlin/Unit| {
R|kotlin/io/println|(R|/XXX.XXX|())
}
@@ -0,0 +1,16 @@
// ISSUE: KT-56630
// FILE: Usage.java
public class Usage extends Apple {
}
// FILE: test.kt
interface Inter
open class Apple<T : Inter> : Inter
class XXX : Usage()
fun main() {
println(XXX())
}
@@ -6699,6 +6699,12 @@ public class FirLightTreeDiagnosticsTestGenerated extends AbstractFirLightTreeDi
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/problems/capturedTypeInEquality.kt");
}
@Test
@TestMetadata("classCastWithRawKotlinType.kt")
public void testClassCastWithRawKotlinType() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/problems/classCastWithRawKotlinType.kt");
}
@Test
@TestMetadata("DeepCopyIrTree.kt")
public void testDeepCopyIrTree() throws Exception {
@@ -6699,6 +6699,12 @@ public class FirPsiDiagnosticTestGenerated extends AbstractFirPsiDiagnosticTest
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/problems/capturedTypeInEquality.kt");
}
@Test
@TestMetadata("classCastWithRawKotlinType.kt")
public void testClassCastWithRawKotlinType() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/problems/classCastWithRawKotlinType.kt");
}
@Test
@TestMetadata("DeepCopyIrTree.kt")
public void testDeepCopyIrTree() throws Exception {
@@ -11,7 +11,6 @@ import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
import org.jetbrains.kotlin.fir.java.enhancement.readOnlyToMutable
import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
@@ -194,7 +193,7 @@ private fun JavaClassifierType.toConeKotlinTypeForFlexibleBound(
// Given `C<T : X>`, `C` -> `C<X>..C<*>?`.
when (mode) {
FirJavaTypeConversionMode.ANNOTATION_MEMBER -> Array(classifier.typeParameters.size) { ConeStarProjection }
else -> typeParameterSymbols?.eraseToUpperBounds(session)
else -> typeParameterSymbols?.getProjectionsForRawType(session)
?: Array(classifier.typeParameters.size) { ConeStarProjection }
}
}
@@ -236,7 +236,7 @@ class ConeRawScopeSubstitutor(
return when {
type is ConeTypeParameterType -> {
substituteOrSelf(
listOf(type.lookupTag.symbol).eraseToUpperBounds(useSiteSession)[0] as ConeKotlinType
listOf(type.lookupTag.symbol).getProjectionsForRawType(useSiteSession)[0] as ConeKotlinType
)
}
type is ConeClassLikeType && type.typeArguments.isNotEmpty() -> {
@@ -251,7 +251,7 @@ class ConeRawScopeSubstitutor(
val firClass = type.fullyExpandedType(useSiteSession).lookupTag.toFirRegularClassSymbol(useSiteSession) ?: return null
ConeRawType.create(
type.withArguments(firClass.typeParameterSymbols.eraseToUpperBounds(useSiteSession)),
type.withArguments(firClass.typeParameterSymbols.getProjectionsForRawType(useSiteSession)),
type.replaceArgumentsWithStarProjections()
)
}
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.fir.declarations.utils.isExpect
import org.jetbrains.kotlin.fir.declarations.utils.modality
import org.jetbrains.kotlin.fir.declarations.utils.visibility
import org.jetbrains.kotlin.fir.diagnostics.ConeRecursiveTypeParameterDuringErasureError
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
import org.jetbrains.kotlin.fir.resolve.toSymbol
@@ -630,13 +631,17 @@ fun List<FirTypeParameterSymbol>.eraseToUpperBoundsAssociated(
eraseRecursively: Boolean = false
): Map<FirTypeParameterSymbol, ConeKotlinType> {
val cache = mutableMapOf<FirTypeParameter, ConeKotlinType>()
return associateWith { it.fir.eraseToUpperBound(session, cache, intersectUpperBounds, eraseRecursively) }
return associateWith {
it.fir.eraseToUpperBound(session, cache, intersectUpperBounds, eraseRecursively, boundsShouldBeResolved = true)
}
}
fun List<FirTypeParameterSymbol>.eraseToUpperBounds(session: FirSession): Array<ConeTypeProjection> {
fun List<FirTypeParameterSymbol>.getProjectionsForRawType(session: FirSession): Array<ConeTypeProjection> {
val cache = mutableMapOf<FirTypeParameter, ConeKotlinType>()
return Array(size) { index ->
this[index].fir.eraseToUpperBound(session, cache, intersectUpperBounds = false, eraseRecursively = false)
this[index].fir.eraseToUpperBound(
session, cache, intersectUpperBounds = false, eraseRecursively = false, boundsShouldBeResolved = false
)
}
}
@@ -644,10 +649,11 @@ private fun FirTypeParameter.eraseToUpperBound(
session: FirSession,
cache: MutableMap<FirTypeParameter, ConeKotlinType>,
intersectUpperBounds: Boolean,
eraseRecursively: Boolean
eraseRecursively: Boolean,
boundsShouldBeResolved: Boolean
): ConeKotlinType {
fun eraseAsUpperBound(type: FirResolvedTypeRef) =
type.coneType.eraseAsUpperBound(session, cache, intersectUpperBounds, eraseRecursively)
type.coneType.eraseAsUpperBound(session, cache, intersectUpperBounds, eraseRecursively, boundsShouldBeResolved)
return cache.getOrPut(this) {
// Mark to avoid loops.
@@ -656,7 +662,22 @@ private fun FirTypeParameter.eraseToUpperBound(
if (intersectUpperBounds) {
ConeTypeIntersector.intersectTypes(session.typeContext, symbol.resolvedBounds.map(::eraseAsUpperBound))
} else {
eraseAsUpperBound(symbol.fir.bounds.first() as FirResolvedTypeRef)
val boundTypeRef = bounds.first()
when {
boundTypeRef is FirResolvedTypeRef -> eraseAsUpperBound(boundTypeRef)
// As we currently know, a raw supertype is the only example
// when bounds can be unresolved here (see the branch below).
// This exception is expected to find other possible occurrences, if any.
boundsShouldBeResolved -> throw IllegalStateException(
"Bounds of ${render()} type parameter of ${containingDeclarationSymbol.fir.render()} aren't resolved"
)
// While resolving raw supertype in Java we may encounter a situation
// when this supertype constructor has some type parameters and
// their bounds aren't yet resolved. See KT-56630 and comments inside.
// Yet we are replacing these bounds with just 'Any'.
// TODO: think how can we replace it with more correct decision.
else -> session.builtinTypes.anyType.type
}
}
}
}
@@ -665,6 +686,7 @@ private fun SimpleTypeMarker.eraseArgumentsDeeply(
typeContext: ConeInferenceContext,
cache: MutableMap<FirTypeParameter, ConeKotlinType>,
intersectUpperBounds: Boolean,
boundsShouldBeResolved: Boolean
): ConeKotlinType = with(typeContext) {
replaceArgumentsDeeply { typeArgument ->
if (typeArgument.isStarProjection())
@@ -676,7 +698,7 @@ private fun SimpleTypeMarker.eraseArgumentsDeeply(
typeConstructor as ConeTypeParameterLookupTag
val erasedType = typeConstructor.typeParameterSymbol.fir.eraseToUpperBound(
session, cache, intersectUpperBounds, eraseRecursively = true
session, cache, intersectUpperBounds, eraseRecursively = true, boundsShouldBeResolved = boundsShouldBeResolved
)
if ((erasedType as? ConeErrorType)?.diagnostic is ConeRecursiveTypeParameterDuringErasureError)
@@ -690,12 +712,13 @@ private fun ConeKotlinType.eraseAsUpperBound(
session: FirSession,
cache: MutableMap<FirTypeParameter, ConeKotlinType>,
intersectUpperBounds: Boolean,
eraseRecursively: Boolean
eraseRecursively: Boolean,
boundsShouldBeResolved: Boolean
): ConeKotlinType =
when (this) {
is ConeClassLikeType -> {
if (eraseRecursively) {
eraseArgumentsDeeply(session.typeContext, cache, intersectUpperBounds)
eraseArgumentsDeeply(session.typeContext, cache, intersectUpperBounds, boundsShouldBeResolved)
} else {
withArguments(typeArguments.map { ConeStarProjection }.toTypedArray())
}
@@ -706,17 +729,19 @@ private fun ConeKotlinType.eraseAsUpperBound(
// so there is no exponential complexity here due to cache lookups.
coneFlexibleOrSimpleType(
session.typeContext,
lowerBound.eraseAsUpperBound(session, cache, intersectUpperBounds, eraseRecursively),
upperBound.eraseAsUpperBound(session, cache, intersectUpperBounds, eraseRecursively)
lowerBound.eraseAsUpperBound(session, cache, intersectUpperBounds, eraseRecursively, boundsShouldBeResolved),
upperBound.eraseAsUpperBound(session, cache, intersectUpperBounds, eraseRecursively, boundsShouldBeResolved)
)
is ConeTypeParameterType ->
lookupTag.typeParameterSymbol.fir.eraseToUpperBound(session, cache, intersectUpperBounds, eraseRecursively).let {
lookupTag.typeParameterSymbol.fir.eraseToUpperBound(
session, cache, intersectUpperBounds, eraseRecursively, boundsShouldBeResolved
).let {
if (isNullable) it.withNullability(nullability, session.typeContext) else it
}
is ConeDefinitelyNotNullType ->
original.eraseAsUpperBound(session, cache, intersectUpperBounds, eraseRecursively)
original.eraseAsUpperBound(session, cache, intersectUpperBounds, eraseRecursively, boundsShouldBeResolved)
.makeConeTypeDefinitelyNotNullOrNotNull(session.typeContext)
else -> error("unexpected Java type parameter upper bound kind: $this")