ConeFlexibleType: statically require to have simple bounds

This commit is contained in:
Mikhail Glukhikh
2021-12-03 13:36:09 +03:00
parent fa8441fb23
commit 2ba2453062
9 changed files with 76 additions and 45 deletions
@@ -132,6 +132,12 @@ object FirJavaGenericVarianceViolationTypeChecker : FirFunctionCallChecker() {
lowerBound.removeOutProjection(isCovariant), lowerBound.removeOutProjection(isCovariant),
upperBound.removeOutProjection(isCovariant) upperBound.removeOutProjection(isCovariant)
) )
is ConeSimpleKotlinType -> removeOutProjection(isCovariant)
}
}
private fun ConeSimpleKotlinType.removeOutProjection(isCovariant: Boolean): ConeSimpleKotlinType {
return when (this) {
is ConeCapturedType -> ConeCapturedType( is ConeCapturedType -> ConeCapturedType(
captureStatus, captureStatus,
lowerType?.removeOutProjection(isCovariant), lowerType?.removeOutProjection(isCovariant),
@@ -128,16 +128,10 @@ abstract class ConeClassLikeType : ConeLookupTagBasedType() {
} }
open class ConeFlexibleType( open class ConeFlexibleType(
val lowerBound: ConeKotlinType, val lowerBound: ConeSimpleKotlinType,
val upperBound: ConeKotlinType val upperBound: ConeSimpleKotlinType
) : ConeKotlinType(), FlexibleTypeMarker { ) : ConeKotlinType(), FlexibleTypeMarker {
init {
val message = { "Bounds violation: $lowerBound, $upperBound" }
require(lowerBound is SimpleTypeMarker, message)
require(upperBound is SimpleTypeMarker, message)
}
override val typeArguments: Array<out ConeTypeProjection> override val typeArguments: Array<out ConeTypeProjection>
get() = lowerBound.typeArguments get() = lowerBound.typeArguments
@@ -167,8 +161,19 @@ open class ConeFlexibleType(
} }
fun ConeKotlinType.upperBoundIfFlexible() = (this as? ConeFlexibleType)?.upperBound ?: this fun ConeKotlinType.upperBoundIfFlexible(): ConeSimpleKotlinType {
fun ConeKotlinType.lowerBoundIfFlexible() = (this as? ConeFlexibleType)?.lowerBound ?: this return when (this) {
is ConeSimpleKotlinType -> this
is ConeFlexibleType -> upperBound
}
}
fun ConeKotlinType.lowerBoundIfFlexible(): ConeSimpleKotlinType {
return when (this) {
is ConeSimpleKotlinType -> this
is ConeFlexibleType -> lowerBound
}
}
class ConeCapturedTypeConstructor( class ConeCapturedTypeConstructor(
val projection: ConeTypeProjection, val projection: ConeTypeProjection,
@@ -264,7 +269,10 @@ data class ConeDefinitelyNotNullType(val original: ConeKotlinType) : ConeSimpleK
companion object companion object
} }
class ConeRawType(lowerBound: ConeKotlinType, upperBound: ConeKotlinType) : ConeFlexibleType(lowerBound, upperBound), RawTypeMarker class ConeRawType(
lowerBound: ConeSimpleKotlinType,
upperBound: ConeSimpleKotlinType
) : ConeFlexibleType(lowerBound, upperBound), RawTypeMarker
/* /*
* Contract of the intersection type: it is flat. It means that * Contract of the intersection type: it is flat. It means that
@@ -86,14 +86,13 @@ private fun ClassId.mutableToReadOnly(): ClassId? {
return JavaToKotlinClassMap.mutableToReadOnly(this) return JavaToKotlinClassMap.mutableToReadOnly(this)
} }
private fun ConeKotlinType.enhanceInflexibleType( private fun ConeSimpleKotlinType.enhanceInflexibleType(
session: FirSession, session: FirSession,
position: TypeComponentPosition, position: TypeComponentPosition,
qualifiers: IndexedJavaTypeQualifiers, qualifiers: IndexedJavaTypeQualifiers,
index: Int, index: Int,
subtreeSizes: List<Int>, subtreeSizes: List<Int>,
): ConeKotlinType? { ): ConeSimpleKotlinType? {
require(this !is ConeFlexibleType) { "$this should not be flexible" }
val shouldEnhance = position.shouldEnhance() val shouldEnhance = position.shouldEnhance()
if ((!shouldEnhance && typeArguments.isEmpty()) || this !is ConeLookupTagBasedType) { if ((!shouldEnhance && typeArguments.isEmpty()) || this !is ConeLookupTagBasedType) {
return null return null
@@ -49,6 +49,13 @@ fun ConeKotlinType.fullyExpandedType(
else -> this else -> this
} }
fun ConeSimpleKotlinType.fullyExpandedType(
useSiteSession: FirSession
): ConeSimpleKotlinType = when (this) {
is ConeClassLikeType -> fullyExpandedType(useSiteSession)
else -> this
}
private fun ConeClassLikeType.fullyExpandedTypeNoCache( private fun ConeClassLikeType.fullyExpandedTypeNoCache(
useSiteSession: FirSession, useSiteSession: FirSession,
expandedConeType: (FirTypeAlias) -> ConeClassLikeType?, expandedConeType: (FirTypeAlias) -> ConeClassLikeType?,
@@ -104,12 +104,12 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
override fun FlexibleTypeMarker.upperBound(): SimpleTypeMarker { override fun FlexibleTypeMarker.upperBound(): SimpleTypeMarker {
require(this is ConeFlexibleType) require(this is ConeFlexibleType)
return this.upperBound as SimpleTypeMarker return this.upperBound
} }
override fun FlexibleTypeMarker.lowerBound(): SimpleTypeMarker { override fun FlexibleTypeMarker.lowerBound(): SimpleTypeMarker {
require(this is ConeFlexibleType) require(this is ConeFlexibleType)
return this.lowerBound as SimpleTypeMarker return this.lowerBound
} }
override fun SimpleTypeMarker.asCapturedType(): CapturedTypeMarker? { override fun SimpleTypeMarker.asCapturedType(): CapturedTypeMarker? {
@@ -11,19 +11,25 @@ import org.jetbrains.kotlin.types.AbstractTypePreparator
import org.jetbrains.kotlin.types.model.KotlinTypeMarker import org.jetbrains.kotlin.types.model.KotlinTypeMarker
class ConeTypePreparator(val session: FirSession) : AbstractTypePreparator() { class ConeTypePreparator(val session: FirSession) : AbstractTypePreparator() {
override fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker { private fun prepareType(type: ConeSimpleKotlinType): ConeSimpleKotlinType {
return when (type) { return when (type) {
is ConeClassLikeType -> type.fullyExpandedType(session) is ConeClassLikeType -> type.fullyExpandedType(session)
else -> type
}
}
override fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker {
if (type !is ConeKotlinType) {
throw AssertionError("Unexpected type in ConeTypePreparator: ${this::class.java}")
}
return when (type) {
is ConeFlexibleType -> { is ConeFlexibleType -> {
val lowerBound = prepareType(type.lowerBound) val lowerBound = prepareType(type.lowerBound)
if (lowerBound === type.lowerBound) return type if (lowerBound === type.lowerBound) return type
ConeFlexibleType( ConeFlexibleType(lowerBound, prepareType(type.upperBound))
lowerBound as ConeKotlinType,
prepareType(type.upperBound) as ConeKotlinType
)
} }
else -> type is ConeSimpleKotlinType -> prepareType(type)
} }
} }
} }
@@ -28,6 +28,8 @@ import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.model.* import org.jetbrains.kotlin.types.model.*
import org.jetbrains.kotlin.fir.types.lowerBoundIfFlexible as coneLowerBoundIfFlexible
import org.jetbrains.kotlin.fir.types.upperBoundIfFlexible as coneUpperBoundIfFlexible
fun ConeInferenceContext.commonSuperTypeOrNull(types: List<ConeKotlinType>): ConeKotlinType? { fun ConeInferenceContext.commonSuperTypeOrNull(types: List<ConeKotlinType>): ConeKotlinType? {
return when (types.size) { return when (types.size) {
@@ -179,20 +181,20 @@ fun coneFlexibleOrSimpleType(
lowerBound: ConeKotlinType, lowerBound: ConeKotlinType,
upperBound: ConeKotlinType, upperBound: ConeKotlinType,
): ConeKotlinType { ): ConeKotlinType {
if (lowerBound is ConeFlexibleType) { return when (lowerBound) {
return coneFlexibleOrSimpleType(typeContext, lowerBound.lowerBound, upperBound) is ConeFlexibleType -> coneFlexibleOrSimpleType(typeContext, lowerBound.lowerBound, upperBound)
} is ConeSimpleKotlinType -> when (upperBound) {
if (upperBound is ConeFlexibleType) { is ConeFlexibleType -> coneFlexibleOrSimpleType(typeContext, lowerBound, upperBound.upperBound)
return coneFlexibleOrSimpleType(typeContext, lowerBound, upperBound.upperBound) is ConeSimpleKotlinType -> when {
} AbstractStrictEqualityTypeChecker.strictEqualTypes(typeContext, lowerBound, upperBound) -> lowerBound
return when { else -> ConeFlexibleType(lowerBound, upperBound)
AbstractStrictEqualityTypeChecker.strictEqualTypes(typeContext, lowerBound, upperBound) -> lowerBound }
else -> ConeFlexibleType(lowerBound, upperBound) }
} }
} }
fun ConeKotlinType.isExtensionFunctionType(session: FirSession): Boolean { fun ConeKotlinType.isExtensionFunctionType(session: FirSession): Boolean {
val type = this.lowerBoundIfFlexible().fullyExpandedType(session) val type = this.coneLowerBoundIfFlexible().fullyExpandedType(session)
return type.attributes.extensionFunctionType != null return type.attributes.extensionFunctionType != null
} }
@@ -201,7 +203,7 @@ fun FirTypeRef.isExtensionFunctionType(session: FirSession): Boolean {
} }
fun ConeKotlinType.isUnsafeVarianceType(session: FirSession): Boolean { fun ConeKotlinType.isUnsafeVarianceType(session: FirSession): Boolean {
val type = this.lowerBoundIfFlexible().fullyExpandedType(session) val type = this.coneLowerBoundIfFlexible().fullyExpandedType(session)
return type.attributes.unsafeVarianceType != null return type.attributes.unsafeVarianceType != null
} }
@@ -471,7 +473,7 @@ fun ConeTypeContext.captureFromExpressionInternal(type: ConeKotlinType): ConeKot
fun findCorrespondingCapturedArgumentsForType(type: ConeKotlinType) = fun findCorrespondingCapturedArgumentsForType(type: ConeKotlinType) =
capturedArgumentsByComponents.find { typeToCapture -> typeToCapture.isSuitableForType(type, this) }?.capturedArguments capturedArgumentsByComponents.find { typeToCapture -> typeToCapture.isSuitableForType(type, this) }?.capturedArguments
fun replaceArgumentsWithCapturedArgumentsByIntersectionComponents(typeToReplace: ConeKotlinType): List<ConeKotlinType> { fun replaceArgumentsWithCapturedArgumentsByIntersectionComponents(typeToReplace: ConeSimpleKotlinType): List<ConeKotlinType> {
return if (typeToReplace is ConeIntersectionType) { return if (typeToReplace is ConeIntersectionType) {
typeToReplace.intersectedTypes.map { componentType -> typeToReplace.intersectedTypes.map { componentType ->
val capturedArguments = findCorrespondingCapturedArgumentsForType(componentType) val capturedArguments = findCorrespondingCapturedArgumentsForType(componentType)
@@ -485,15 +487,18 @@ fun ConeTypeContext.captureFromExpressionInternal(type: ConeKotlinType): ConeKot
} }
} }
return if (type is ConeFlexibleType) { return when (type) {
val lowerIntersectedType = intersectTypes(replaceArgumentsWithCapturedArgumentsByIntersectionComponents(type.lowerBound)) is ConeFlexibleType -> {
.withNullability(type.lowerBound.isMarkedNullable) as ConeKotlinType val lowerIntersectedType = intersectTypes(replaceArgumentsWithCapturedArgumentsByIntersectionComponents(type.lowerBound))
val upperIntersectedType = intersectTypes(replaceArgumentsWithCapturedArgumentsByIntersectionComponents(type.upperBound)) .withNullability(ConeNullability.create(type.lowerBound.isMarkedNullable), this)
.withNullability(type.upperBound.isMarkedNullable) as ConeKotlinType val upperIntersectedType = intersectTypes(replaceArgumentsWithCapturedArgumentsByIntersectionComponents(type.upperBound))
.withNullability(ConeNullability.create(type.upperBound.isMarkedNullable), this)
ConeFlexibleType(lowerIntersectedType, upperIntersectedType) ConeFlexibleType(lowerIntersectedType.coneLowerBoundIfFlexible(), upperIntersectedType.coneUpperBoundIfFlexible())
} else { }
intersectTypes(replaceArgumentsWithCapturedArgumentsByIntersectionComponents(type)).withNullability(type.isMarkedNullable) as ConeKotlinType is ConeSimpleKotlinType -> {
intersectTypes(replaceArgumentsWithCapturedArgumentsByIntersectionComponents(type)).withNullability(type.isMarkedNullable) as ConeKotlinType
}
} }
} }
@@ -58,8 +58,8 @@ class FirSamResolverImpl(
return when (type) { return when (type) {
is ConeClassLikeType -> getFunctionTypeForPossibleSamType(type.fullyExpandedType(session)) is ConeClassLikeType -> getFunctionTypeForPossibleSamType(type.fullyExpandedType(session))
is ConeFlexibleType -> ConeFlexibleType( is ConeFlexibleType -> ConeFlexibleType(
getFunctionTypeForPossibleSamType(type.lowerBound) ?: return null, getFunctionTypeForPossibleSamType(type.lowerBound)?.lowerBoundIfFlexible() ?: return null,
getFunctionTypeForPossibleSamType(type.upperBound) ?: return null, getFunctionTypeForPossibleSamType(type.upperBound)?.upperBoundIfFlexible() ?: return null,
) )
is ConeClassErrorType, is ConeStubType -> null is ConeClassErrorType, is ConeStubType -> null
// TODO: support those types as well // TODO: support those types as well
@@ -92,7 +92,7 @@ internal object CreateFreshTypeVariableSubstitutorStage : ResolutionStage() {
session: FirSession, session: FirSession,
): ConeKotlinType { ): ConeKotlinType {
return if (typeParameter.shouldBeFlexible(session.typeContext)) { return if (typeParameter.shouldBeFlexible(session.typeContext)) {
val notNullType = type.withNullability(ConeNullability.NOT_NULL, session.typeContext) val notNullType = type.withNullability(ConeNullability.NOT_NULL, session.typeContext) as ConeSimpleKotlinType
ConeFlexibleType(notNullType, notNullType.withNullability(ConeNullability.NULLABLE, session.typeContext)) ConeFlexibleType(notNullType, notNullType.withNullability(ConeNullability.NULLABLE, session.typeContext))
} else { } else {
type type