From 2ba2453062181f69ecb1e77d4d6d2de073912f51 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Fri, 3 Dec 2021 13:36:09 +0300 Subject: [PATCH] ConeFlexibleType: statically require to have simple bounds --- ...JavaGenericVarianceViolationTypeChecker.kt | 6 +++ .../jetbrains/kotlin/fir/types/ConeTypes.kt | 30 ++++++++----- .../fir/java/enhancement/javaTypeUtils.kt | 5 +-- .../kotlin/fir/resolve/TypeExpansionUtils.kt | 7 +++ .../kotlin/fir/types/ConeTypeContext.kt | 4 +- .../kotlin/fir/types/ConeTypePreparator.kt | 18 +++++--- .../jetbrains/kotlin/fir/types/TypeUtils.kt | 45 ++++++++++--------- .../kotlin/fir/resolve/SamResolution.kt | 4 +- ...CreateFreshTypeVariableSubstitutorStage.kt | 2 +- 9 files changed, 76 insertions(+), 45 deletions(-) diff --git a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/expression/FirJavaGenericVarianceViolationTypeChecker.kt b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/expression/FirJavaGenericVarianceViolationTypeChecker.kt index 9eb9762d4ad..38abc6ae544 100644 --- a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/expression/FirJavaGenericVarianceViolationTypeChecker.kt +++ b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/expression/FirJavaGenericVarianceViolationTypeChecker.kt @@ -132,6 +132,12 @@ object FirJavaGenericVarianceViolationTypeChecker : FirFunctionCallChecker() { lowerBound.removeOutProjection(isCovariant), upperBound.removeOutProjection(isCovariant) ) + is ConeSimpleKotlinType -> removeOutProjection(isCovariant) + } + } + + private fun ConeSimpleKotlinType.removeOutProjection(isCovariant: Boolean): ConeSimpleKotlinType { + return when (this) { is ConeCapturedType -> ConeCapturedType( captureStatus, lowerType?.removeOutProjection(isCovariant), diff --git a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypes.kt b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypes.kt index cef192330e4..fa521131f83 100644 --- a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypes.kt +++ b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypes.kt @@ -128,16 +128,10 @@ abstract class ConeClassLikeType : ConeLookupTagBasedType() { } open class ConeFlexibleType( - val lowerBound: ConeKotlinType, - val upperBound: ConeKotlinType + val lowerBound: ConeSimpleKotlinType, + val upperBound: ConeSimpleKotlinType ) : ConeKotlinType(), FlexibleTypeMarker { - init { - val message = { "Bounds violation: $lowerBound, $upperBound" } - require(lowerBound is SimpleTypeMarker, message) - require(upperBound is SimpleTypeMarker, message) - } - override val typeArguments: Array get() = lowerBound.typeArguments @@ -167,8 +161,19 @@ open class ConeFlexibleType( } -fun ConeKotlinType.upperBoundIfFlexible() = (this as? ConeFlexibleType)?.upperBound ?: this -fun ConeKotlinType.lowerBoundIfFlexible() = (this as? ConeFlexibleType)?.lowerBound ?: this +fun ConeKotlinType.upperBoundIfFlexible(): ConeSimpleKotlinType { + return when (this) { + is ConeSimpleKotlinType -> this + is ConeFlexibleType -> upperBound + } +} + +fun ConeKotlinType.lowerBoundIfFlexible(): ConeSimpleKotlinType { + return when (this) { + is ConeSimpleKotlinType -> this + is ConeFlexibleType -> lowerBound + } +} class ConeCapturedTypeConstructor( val projection: ConeTypeProjection, @@ -264,7 +269,10 @@ data class ConeDefinitelyNotNullType(val original: ConeKotlinType) : ConeSimpleK 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 diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/javaTypeUtils.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/javaTypeUtils.kt index e080db8bbe5..03d41c90840 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/javaTypeUtils.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/javaTypeUtils.kt @@ -86,14 +86,13 @@ private fun ClassId.mutableToReadOnly(): ClassId? { return JavaToKotlinClassMap.mutableToReadOnly(this) } -private fun ConeKotlinType.enhanceInflexibleType( +private fun ConeSimpleKotlinType.enhanceInflexibleType( session: FirSession, position: TypeComponentPosition, qualifiers: IndexedJavaTypeQualifiers, index: Int, subtreeSizes: List, -): ConeKotlinType? { - require(this !is ConeFlexibleType) { "$this should not be flexible" } +): ConeSimpleKotlinType? { val shouldEnhance = position.shouldEnhance() if ((!shouldEnhance && typeArguments.isEmpty()) || this !is ConeLookupTagBasedType) { return null diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/TypeExpansionUtils.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/TypeExpansionUtils.kt index f8c2f7ed8fa..4c6c1c1d321 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/TypeExpansionUtils.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/TypeExpansionUtils.kt @@ -49,6 +49,13 @@ fun ConeKotlinType.fullyExpandedType( else -> this } +fun ConeSimpleKotlinType.fullyExpandedType( + useSiteSession: FirSession +): ConeSimpleKotlinType = when (this) { + is ConeClassLikeType -> fullyExpandedType(useSiteSession) + else -> this +} + private fun ConeClassLikeType.fullyExpandedTypeNoCache( useSiteSession: FirSession, expandedConeType: (FirTypeAlias) -> ConeClassLikeType?, diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt index db727f4fa0a..16f90030b5a 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt @@ -104,12 +104,12 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty override fun FlexibleTypeMarker.upperBound(): SimpleTypeMarker { require(this is ConeFlexibleType) - return this.upperBound as SimpleTypeMarker + return this.upperBound } override fun FlexibleTypeMarker.lowerBound(): SimpleTypeMarker { require(this is ConeFlexibleType) - return this.lowerBound as SimpleTypeMarker + return this.lowerBound } override fun SimpleTypeMarker.asCapturedType(): CapturedTypeMarker? { diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ConeTypePreparator.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ConeTypePreparator.kt index 321b5bc57fd..b60446f1d7e 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ConeTypePreparator.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ConeTypePreparator.kt @@ -11,19 +11,25 @@ import org.jetbrains.kotlin.types.AbstractTypePreparator import org.jetbrains.kotlin.types.model.KotlinTypeMarker class ConeTypePreparator(val session: FirSession) : AbstractTypePreparator() { - override fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker { + private fun prepareType(type: ConeSimpleKotlinType): ConeSimpleKotlinType { return when (type) { 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 -> { val lowerBound = prepareType(type.lowerBound) if (lowerBound === type.lowerBound) return type - ConeFlexibleType( - lowerBound as ConeKotlinType, - prepareType(type.upperBound) as ConeKotlinType - ) + ConeFlexibleType(lowerBound, prepareType(type.upperBound)) } - else -> type + is ConeSimpleKotlinType -> prepareType(type) } } } diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt index ceae859f495..bab38ed6fc0 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt @@ -28,6 +28,8 @@ import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator import org.jetbrains.kotlin.types.* 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? { return when (types.size) { @@ -179,20 +181,20 @@ fun coneFlexibleOrSimpleType( lowerBound: ConeKotlinType, upperBound: ConeKotlinType, ): ConeKotlinType { - if (lowerBound is ConeFlexibleType) { - return coneFlexibleOrSimpleType(typeContext, lowerBound.lowerBound, upperBound) - } - if (upperBound is ConeFlexibleType) { - return coneFlexibleOrSimpleType(typeContext, lowerBound, upperBound.upperBound) - } - return when { - AbstractStrictEqualityTypeChecker.strictEqualTypes(typeContext, lowerBound, upperBound) -> lowerBound - else -> ConeFlexibleType(lowerBound, upperBound) + return when (lowerBound) { + is ConeFlexibleType -> coneFlexibleOrSimpleType(typeContext, lowerBound.lowerBound, upperBound) + is ConeSimpleKotlinType -> when (upperBound) { + is ConeFlexibleType -> coneFlexibleOrSimpleType(typeContext, lowerBound, upperBound.upperBound) + is ConeSimpleKotlinType -> when { + AbstractStrictEqualityTypeChecker.strictEqualTypes(typeContext, lowerBound, upperBound) -> lowerBound + else -> ConeFlexibleType(lowerBound, upperBound) + } + } } } fun ConeKotlinType.isExtensionFunctionType(session: FirSession): Boolean { - val type = this.lowerBoundIfFlexible().fullyExpandedType(session) + val type = this.coneLowerBoundIfFlexible().fullyExpandedType(session) return type.attributes.extensionFunctionType != null } @@ -201,7 +203,7 @@ fun FirTypeRef.isExtensionFunctionType(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 } @@ -471,7 +473,7 @@ fun ConeTypeContext.captureFromExpressionInternal(type: ConeKotlinType): ConeKot fun findCorrespondingCapturedArgumentsForType(type: ConeKotlinType) = capturedArgumentsByComponents.find { typeToCapture -> typeToCapture.isSuitableForType(type, this) }?.capturedArguments - fun replaceArgumentsWithCapturedArgumentsByIntersectionComponents(typeToReplace: ConeKotlinType): List { + fun replaceArgumentsWithCapturedArgumentsByIntersectionComponents(typeToReplace: ConeSimpleKotlinType): List { return if (typeToReplace is ConeIntersectionType) { typeToReplace.intersectedTypes.map { componentType -> val capturedArguments = findCorrespondingCapturedArgumentsForType(componentType) @@ -485,15 +487,18 @@ fun ConeTypeContext.captureFromExpressionInternal(type: ConeKotlinType): ConeKot } } - return if (type is ConeFlexibleType) { - val lowerIntersectedType = intersectTypes(replaceArgumentsWithCapturedArgumentsByIntersectionComponents(type.lowerBound)) - .withNullability(type.lowerBound.isMarkedNullable) as ConeKotlinType - val upperIntersectedType = intersectTypes(replaceArgumentsWithCapturedArgumentsByIntersectionComponents(type.upperBound)) - .withNullability(type.upperBound.isMarkedNullable) as ConeKotlinType + return when (type) { + is ConeFlexibleType -> { + val lowerIntersectedType = intersectTypes(replaceArgumentsWithCapturedArgumentsByIntersectionComponents(type.lowerBound)) + .withNullability(ConeNullability.create(type.lowerBound.isMarkedNullable), this) + val upperIntersectedType = intersectTypes(replaceArgumentsWithCapturedArgumentsByIntersectionComponents(type.upperBound)) + .withNullability(ConeNullability.create(type.upperBound.isMarkedNullable), this) - ConeFlexibleType(lowerIntersectedType, upperIntersectedType) - } else { - intersectTypes(replaceArgumentsWithCapturedArgumentsByIntersectionComponents(type)).withNullability(type.isMarkedNullable) as ConeKotlinType + ConeFlexibleType(lowerIntersectedType.coneLowerBoundIfFlexible(), upperIntersectedType.coneUpperBoundIfFlexible()) + } + is ConeSimpleKotlinType -> { + intersectTypes(replaceArgumentsWithCapturedArgumentsByIntersectionComponents(type)).withNullability(type.isMarkedNullable) as ConeKotlinType + } } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SamResolution.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SamResolution.kt index 9242d12263f..fac5df3714a 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SamResolution.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SamResolution.kt @@ -58,8 +58,8 @@ class FirSamResolverImpl( return when (type) { is ConeClassLikeType -> getFunctionTypeForPossibleSamType(type.fullyExpandedType(session)) is ConeFlexibleType -> ConeFlexibleType( - getFunctionTypeForPossibleSamType(type.lowerBound) ?: return null, - getFunctionTypeForPossibleSamType(type.upperBound) ?: return null, + getFunctionTypeForPossibleSamType(type.lowerBound)?.lowerBoundIfFlexible() ?: return null, + getFunctionTypeForPossibleSamType(type.upperBound)?.upperBoundIfFlexible() ?: return null, ) is ConeClassErrorType, is ConeStubType -> null // TODO: support those types as well diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CreateFreshTypeVariableSubstitutorStage.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CreateFreshTypeVariableSubstitutorStage.kt index acde7528981..2603d9ca02f 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CreateFreshTypeVariableSubstitutorStage.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CreateFreshTypeVariableSubstitutorStage.kt @@ -92,7 +92,7 @@ internal object CreateFreshTypeVariableSubstitutorStage : ResolutionStage() { session: FirSession, ): ConeKotlinType { 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)) } else { type