[FIR] Unbind type parameter erasing from java
This commit is contained in:
committed by
teamcity
parent
f31cf90de2
commit
313da6f41e
@@ -224,38 +224,3 @@ private fun JavaClassifierType.argumentsMakeSenseOnlyForMutableContainer(
|
|||||||
|
|
||||||
return mutableLastParameterVariance != Variance.OUT_VARIANCE
|
return mutableLastParameterVariance != Variance.OUT_VARIANCE
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun List<FirTypeParameterSymbol>.eraseToUpperBounds(session: FirSession): Array<ConeTypeProjection> {
|
|
||||||
val cache = mutableMapOf<FirTypeParameter, ConeKotlinType>()
|
|
||||||
return Array(size) { index -> this[index].fir.eraseToUpperBound(session, cache) }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun FirTypeParameter.eraseToUpperBound(session: FirSession, cache: MutableMap<FirTypeParameter, ConeKotlinType>): ConeKotlinType {
|
|
||||||
return cache.getOrPut(this) {
|
|
||||||
// Mark to avoid loops.
|
|
||||||
cache[this] = ConeErrorType(ConeIntermediateDiagnostic("self-recursive type parameter $name"))
|
|
||||||
// We can assume that Java type parameter bounds are already converted.
|
|
||||||
symbol.resolvedBounds.first().coneType.eraseAsUpperBound(session, cache)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun ConeKotlinType.eraseAsUpperBound(session: FirSession, cache: MutableMap<FirTypeParameter, ConeKotlinType>): ConeKotlinType =
|
|
||||||
when (this) {
|
|
||||||
is ConeClassLikeType ->
|
|
||||||
withArguments(typeArguments.map { ConeStarProjection }.toTypedArray())
|
|
||||||
is ConeFlexibleType ->
|
|
||||||
// If one bound is a type parameter, the other is probably the same type parameter,
|
|
||||||
// so there is no exponential complexity here due to cache lookups.
|
|
||||||
coneFlexibleOrSimpleType(
|
|
||||||
session.typeContext,
|
|
||||||
lowerBound.eraseAsUpperBound(session, cache),
|
|
||||||
upperBound.eraseAsUpperBound(session, cache)
|
|
||||||
)
|
|
||||||
is ConeTypeParameterType ->
|
|
||||||
lookupTag.typeParameterSymbol.fir.eraseToUpperBound(session, cache).let {
|
|
||||||
if (isNullable) it.withNullability(nullability, session.typeContext) else it
|
|
||||||
}
|
|
||||||
is ConeDefinitelyNotNullType ->
|
|
||||||
original.eraseAsUpperBound(session, cache).makeConeTypeDefinitelyNotNullOrNotNull(session.typeContext)
|
|
||||||
else -> error("unexpected Java type parameter upper bound kind: $this")
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.fir.declarations.utils.isEnumClass
|
|||||||
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
|
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.modality
|
import org.jetbrains.kotlin.fir.declarations.utils.modality
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.visibility
|
import org.jetbrains.kotlin.fir.declarations.utils.visibility
|
||||||
|
import org.jetbrains.kotlin.fir.diagnostics.ConeRecursiveTypeParameterDuringErasureError
|
||||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap
|
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap
|
||||||
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
|
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
|
||||||
@@ -681,3 +682,94 @@ private fun lowerThanBound(context: ConeInferenceContext, argument: ConeKotlinTy
|
|||||||
|
|
||||||
fun KotlinTypeMarker.isSubtypeOf(context: TypeCheckerProviderContext, type: KotlinTypeMarker?): Boolean =
|
fun KotlinTypeMarker.isSubtypeOf(context: TypeCheckerProviderContext, type: KotlinTypeMarker?): Boolean =
|
||||||
type != null && AbstractTypeChecker.isSubtypeOf(context, this, type)
|
type != null && AbstractTypeChecker.isSubtypeOf(context, this, type)
|
||||||
|
|
||||||
|
fun List<FirTypeParameterSymbol>.eraseToUpperBoundsAssociated(
|
||||||
|
session: FirSession,
|
||||||
|
intersectUpperBounds: Boolean = false,
|
||||||
|
eraseRecursively: Boolean = false
|
||||||
|
): Map<FirTypeParameterSymbol, ConeKotlinType> {
|
||||||
|
val cache = mutableMapOf<FirTypeParameter, ConeKotlinType>()
|
||||||
|
return associateWith { it.fir.eraseToUpperBound(session, cache, intersectUpperBounds, eraseRecursively) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun List<FirTypeParameterSymbol>.eraseToUpperBounds(session: FirSession): Array<ConeTypeProjection> {
|
||||||
|
val cache = mutableMapOf<FirTypeParameter, ConeKotlinType>()
|
||||||
|
return Array(size) { index ->
|
||||||
|
this[index].fir.eraseToUpperBound(session, cache, intersectUpperBounds = false, eraseRecursively = false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun FirTypeParameter.eraseToUpperBound(
|
||||||
|
session: FirSession,
|
||||||
|
cache: MutableMap<FirTypeParameter, ConeKotlinType>,
|
||||||
|
intersectUpperBounds: Boolean,
|
||||||
|
eraseRecursively: Boolean
|
||||||
|
): ConeKotlinType {
|
||||||
|
fun eraseAsUpperBound(type: FirResolvedTypeRef) =
|
||||||
|
type.coneType.eraseAsUpperBound(session, cache, intersectUpperBounds, eraseRecursively)
|
||||||
|
|
||||||
|
return cache.getOrPut(this) {
|
||||||
|
// Mark to avoid loops.
|
||||||
|
cache[this] = ConeErrorType(ConeRecursiveTypeParameterDuringErasureError(name))
|
||||||
|
// We can assume that Java type parameter bounds are already converted.
|
||||||
|
if (intersectUpperBounds) {
|
||||||
|
ConeTypeIntersector.intersectTypes(session.typeContext, symbol.resolvedBounds.map(::eraseAsUpperBound))
|
||||||
|
} else {
|
||||||
|
eraseAsUpperBound(symbol.resolvedBounds.first())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun SimpleTypeMarker.eraseArgumentsDeeply(
|
||||||
|
typeContext: ConeInferenceContext,
|
||||||
|
cache: MutableMap<FirTypeParameter, ConeKotlinType>,
|
||||||
|
intersectUpperBounds: Boolean,
|
||||||
|
): ConeKotlinType = with(typeContext) {
|
||||||
|
replaceArgumentsDeeply { typeArgument ->
|
||||||
|
val typeConstructor = typeArgument.getType().typeConstructor().takeIf { it.isTypeParameterTypeConstructor() }
|
||||||
|
?: return@replaceArgumentsDeeply typeArgument
|
||||||
|
|
||||||
|
typeConstructor as ConeTypeParameterLookupTag
|
||||||
|
|
||||||
|
val erasedType = typeConstructor.typeParameterSymbol.fir.eraseToUpperBound(
|
||||||
|
session, cache, intersectUpperBounds, eraseRecursively = true
|
||||||
|
)
|
||||||
|
|
||||||
|
if ((erasedType as? ConeErrorType)?.diagnostic is ConeRecursiveTypeParameterDuringErasureError)
|
||||||
|
return@replaceArgumentsDeeply ConeStarProjection
|
||||||
|
|
||||||
|
erasedType.toTypeProjection(ProjectionKind.OUT)
|
||||||
|
} as ConeKotlinType
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ConeKotlinType.eraseAsUpperBound(
|
||||||
|
session: FirSession,
|
||||||
|
cache: MutableMap<FirTypeParameter, ConeKotlinType>,
|
||||||
|
intersectUpperBounds: Boolean,
|
||||||
|
eraseRecursively: Boolean
|
||||||
|
): ConeKotlinType =
|
||||||
|
when (this) {
|
||||||
|
is ConeClassLikeType -> {
|
||||||
|
if (eraseRecursively) {
|
||||||
|
eraseArgumentsDeeply(session.typeContext, cache, intersectUpperBounds)
|
||||||
|
} else {
|
||||||
|
withArguments(typeArguments.map { ConeStarProjection }.toTypedArray())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is ConeFlexibleType ->
|
||||||
|
// If one bound is a type parameter, the other is probably the same type parameter,
|
||||||
|
// 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)
|
||||||
|
)
|
||||||
|
is ConeTypeParameterType ->
|
||||||
|
lookupTag.typeParameterSymbol.fir.eraseToUpperBound(session, cache, intersectUpperBounds, eraseRecursively).let {
|
||||||
|
if (isNullable) it.withNullability(nullability, session.typeContext) else it
|
||||||
|
}
|
||||||
|
is ConeDefinitelyNotNullType ->
|
||||||
|
original.eraseAsUpperBound(session, cache, intersectUpperBounds, eraseRecursively)
|
||||||
|
.makeConeTypeDefinitelyNotNullOrNotNull(session.typeContext)
|
||||||
|
else -> error("unexpected Java type parameter upper bound kind: $this")
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user