K2: fix CCE during bound conversion for Java raw Kotlin-based type
#KT-56630 Fixed
This commit is contained in:
committed by
Space Team
parent
d1e0a432a5
commit
58959951d3
+6
@@ -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 {
|
||||
|
||||
Vendored
+18
@@ -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|())
|
||||
}
|
||||
Vendored
+16
@@ -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())
|
||||
}
|
||||
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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 }
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user