[FIR] Remove status map from intersection type
This commit is contained in:
@@ -182,44 +182,15 @@ class ConeDefinitelyNotNullType(val original: ConeKotlinType): ConeKotlinType(),
|
||||
* only via ConeTypeIntersector
|
||||
*/
|
||||
class ConeIntersectionType(
|
||||
val constructor: ConeIntersectionTypeConstructor
|
||||
) : ConeKotlinType(), SimpleTypeMarker {
|
||||
val intersectedTypes: Collection<ConeKotlinType>
|
||||
) : ConeKotlinType(), SimpleTypeMarker, TypeConstructorMarker {
|
||||
override val typeArguments: Array<out ConeKotlinTypeProjection>
|
||||
get() = emptyArray()
|
||||
|
||||
override val nullability: ConeNullability
|
||||
get() = ConeNullability.NOT_NULL
|
||||
|
||||
val intersectedTypes: Collection<ConeKotlinType> get() = constructor.intersectedTypes
|
||||
val statusMap: Map<ConeKotlinType, ConeIntersectionTypeConstructor.IntersectionStatus> get() = constructor.statusMap
|
||||
}
|
||||
|
||||
class ConeIntersectionTypeConstructor(
|
||||
val intersectedTypes: Collection<ConeKotlinType>,
|
||||
val statusMap: Map<ConeKotlinType, IntersectionStatus>
|
||||
) : TypeConstructorMarker {
|
||||
val supertypes: Collection<ConeKotlinType> get() = intersectedTypes
|
||||
|
||||
/*
|
||||
* IMPORTANT: use this method only for types from intersectedTypes
|
||||
*/
|
||||
fun getStatus(type: ConeKotlinType): IntersectionStatus {
|
||||
return statusMap[type] ?: error("")
|
||||
}
|
||||
|
||||
enum class IntersectionStatus {
|
||||
FROM_INFERENCE,
|
||||
FROM_SMARTCAST
|
||||
}
|
||||
}
|
||||
|
||||
fun ConeIntersectionTypeConstructor.mapTypes(func: (ConeKotlinType) -> ConeKotlinType): ConeIntersectionTypeConstructor {
|
||||
val newStatusMap = mutableMapOf<ConeKotlinType, ConeIntersectionTypeConstructor.IntersectionStatus>()
|
||||
val newTypes = intersectedTypes.map { type ->
|
||||
val newType = func(type)
|
||||
// TODO: what if some types squash? What status should we choose?
|
||||
newStatusMap[newType] = getStatus(type)
|
||||
newType
|
||||
}
|
||||
return ConeIntersectionTypeConstructor(newTypes, newStatusMap)
|
||||
fun ConeIntersectionType.mapTypes(func: (ConeKotlinType) -> ConeKotlinType): ConeIntersectionType {
|
||||
return ConeIntersectionType(intersectedTypes.map(func))
|
||||
}
|
||||
@@ -164,9 +164,9 @@ fun <T : ConeKotlinType> T.withNullability(nullability: ConeNullability): T {
|
||||
is ConeTypeVariableType -> ConeTypeVariableType(nullability, lookupTag) as T
|
||||
is ConeCapturedType -> ConeCapturedType(captureStatus, lowerType, nullability, constructor) as T
|
||||
is ConeIntersectionType -> when (nullability) {
|
||||
ConeNullability.NULLABLE -> ConeIntersectionType(constructor.mapTypes {
|
||||
ConeNullability.NULLABLE -> this.mapTypes {
|
||||
it.withNullability(nullability)
|
||||
})
|
||||
}
|
||||
ConeNullability.UNKNOWN -> this // TODO: is that correct?
|
||||
ConeNullability.NOT_NULL -> this
|
||||
} as T
|
||||
|
||||
+1
-1
@@ -89,7 +89,7 @@ abstract class AbstractConeSubstitutor : ConeSubstitutor() {
|
||||
substitutedTypes += substitutedType
|
||||
}
|
||||
if (!somethingIsSubstituted) return null
|
||||
return ConeIntersectionType(ConeIntersectionTypeConstructor(substitutedTypes, statusMap))
|
||||
return ConeIntersectionType(substitutedTypes)
|
||||
}
|
||||
|
||||
private fun ConeDefinitelyNotNullType.substituteOriginal(): ConeDefinitelyNotNullType? {
|
||||
|
||||
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.declarations.expandedConeType
|
||||
import org.jetbrains.kotlin.fir.declarations.superConeTypes
|
||||
import org.jetbrains.kotlin.fir.resolve.*
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.ConeInferenceContext
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.ConeTypeVariableTypeConstructor
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.hasNullableSuperType
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
@@ -141,7 +142,7 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
|
||||
is ConeAbbreviatedType -> this.directExpansionType(session)?.typeConstructor()
|
||||
?: ErrorTypeConstructor("Failed to expand alias: ${this}")
|
||||
is ConeLookupTagBasedType -> this.lookupTag.toSymbol(session) ?: ErrorTypeConstructor("Unresolved: ${this.lookupTag}")
|
||||
is ConeIntersectionType -> constructor
|
||||
is ConeIntersectionType -> this
|
||||
else -> error("?: ${this}")
|
||||
}
|
||||
|
||||
@@ -206,7 +207,7 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
|
||||
is ConeCapturedTypeConstructor,
|
||||
is ErrorTypeConstructor,
|
||||
is ConeTypeVariableTypeConstructor,
|
||||
is ConeIntersectionTypeConstructor -> 0
|
||||
is ConeIntersectionType -> 0
|
||||
is FirClassSymbol -> fir.typeParameters.size
|
||||
is FirTypeAliasSymbol -> fir.typeParameters.size
|
||||
else -> error("?!:10")
|
||||
@@ -232,13 +233,13 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
|
||||
is FirClassSymbol -> fir.superConeTypes
|
||||
is FirTypeAliasSymbol -> listOfNotNull(fir.expandedConeType)
|
||||
is ConeCapturedTypeConstructor -> supertypes!!
|
||||
is ConeIntersectionTypeConstructor -> intersectedTypes
|
||||
is ConeIntersectionType -> intersectedTypes
|
||||
else -> error("?!:13")
|
||||
}
|
||||
}
|
||||
|
||||
override fun TypeConstructorMarker.isIntersection(): Boolean {
|
||||
return this is ConeIntersectionTypeConstructor
|
||||
return this is ConeIntersectionType
|
||||
}
|
||||
|
||||
override fun TypeConstructorMarker.isClassTypeConstructor(): Boolean {
|
||||
@@ -279,7 +280,7 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
|
||||
return when (this) {
|
||||
is ConeCapturedTypeConstructor,
|
||||
is ConeTypeVariableTypeConstructor,
|
||||
is ConeIntersectionTypeConstructor -> false
|
||||
is ConeIntersectionType -> false
|
||||
is ConeSymbol -> true
|
||||
else -> true
|
||||
}
|
||||
@@ -381,12 +382,12 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
|
||||
|
||||
override fun intersectTypes(types: List<SimpleTypeMarker>): SimpleTypeMarker {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return ConeTypeIntersector.intersectTypes(this, types as List<ConeKotlinType>) as SimpleTypeMarker
|
||||
return ConeTypeIntersector.intersectTypes(this as ConeInferenceContext, types as List<ConeKotlinType>) as SimpleTypeMarker
|
||||
}
|
||||
|
||||
override fun intersectTypes(types: List<KotlinTypeMarker>): KotlinTypeMarker {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return ConeTypeIntersector.intersectTypes(this, types as List<ConeKotlinType>)
|
||||
return ConeTypeIntersector.intersectTypes(this as ConeInferenceContext, types as List<ConeKotlinType>)
|
||||
}
|
||||
|
||||
private fun prepareClassLikeType(
|
||||
|
||||
@@ -6,32 +6,22 @@
|
||||
package org.jetbrains.kotlin.fir.types
|
||||
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.ConeInferenceContext
|
||||
import org.jetbrains.kotlin.fir.types.ConeIntersectionTypeConstructor.IntersectionStatus
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
import java.util.*
|
||||
import kotlin.collections.LinkedHashSet
|
||||
|
||||
object ConeTypeIntersector {
|
||||
fun intersectTypes(context: ConeTypeContext, types: List<ConeKotlinType>): ConeKotlinType {
|
||||
require(context is ConeInferenceContext)
|
||||
return intersectTypes(context, types, types.map { IntersectionStatus.FROM_INFERENCE })
|
||||
}
|
||||
|
||||
private fun intersectTypes(
|
||||
fun intersectTypes(
|
||||
context: ConeInferenceContext,
|
||||
types: List<ConeKotlinType>,
|
||||
intersectionStatus: List<IntersectionStatus>
|
||||
types: List<ConeKotlinType>
|
||||
): ConeKotlinType {
|
||||
assert(types.size == intersectionStatus.size)
|
||||
|
||||
when (types.size) {
|
||||
0 -> error("Expected some types")
|
||||
1 -> return types.single()
|
||||
}
|
||||
|
||||
val inputTypes = mutableListOf<ConeKotlinType>()
|
||||
val statusMap = mutableMapOf<ConeKotlinType, IntersectionStatus>()
|
||||
flatIntersectionTypes(types, intersectionStatus, inputTypes, statusMap)
|
||||
flatIntersectionTypes(types, inputTypes)
|
||||
|
||||
/**
|
||||
* resultNullability. Value description:
|
||||
@@ -49,19 +39,16 @@ object ConeTypeIntersector {
|
||||
|
||||
val inputTypesWithCorrectNullability = inputTypes.mapTo(LinkedHashSet()) {
|
||||
if (resultNullability == ResultNullability.NOT_NULL) with(context) {
|
||||
val resultType = it.makeDefinitelyNotNullOrNotNull() as ConeKotlinType
|
||||
statusMap[resultType] = statusMap.remove(it)!!
|
||||
resultType
|
||||
it.makeDefinitelyNotNullOrNotNull() as ConeKotlinType
|
||||
} else it
|
||||
}
|
||||
|
||||
return intersectTypesWithoutIntersectionType(context, inputTypesWithCorrectNullability, statusMap)
|
||||
return intersectTypesWithoutIntersectionType(context, inputTypesWithCorrectNullability)
|
||||
}
|
||||
|
||||
private fun intersectTypesWithoutIntersectionType(
|
||||
context: ConeTypeContext,
|
||||
inputTypes: Set<ConeKotlinType>,
|
||||
statusMap: MutableMap<ConeKotlinType, IntersectionStatus>
|
||||
inputTypes: Set<ConeKotlinType>
|
||||
): ConeKotlinType {
|
||||
if (inputTypes.size == 1) return inputTypes.single().type
|
||||
|
||||
@@ -81,7 +68,7 @@ object ConeTypeIntersector {
|
||||
* We want to drop A from that set, because it's useless for type checking. But in case if
|
||||
* A came from inference and B came from smartcast we want to safe both types in intersection
|
||||
*/
|
||||
isStrictSupertype(context, lower, upper) && statusMap[lower]!! <= statusMap[upper]!!
|
||||
isStrictSupertype(context, lower, upper)
|
||||
}
|
||||
assert(filteredEqualTypes.isNotEmpty(), errorMessage)
|
||||
|
||||
@@ -95,11 +82,7 @@ object ConeTypeIntersector {
|
||||
|
||||
if (filteredSuperAndEqualTypes.size < 2) return filteredSuperAndEqualTypes.single()
|
||||
|
||||
val constructor = ConeIntersectionTypeConstructor(
|
||||
filteredSuperAndEqualTypes,
|
||||
filteredSuperAndEqualTypes.associateWithTo(mutableMapOf()) { statusMap[it]!! }
|
||||
)
|
||||
return ConeIntersectionType(constructor)
|
||||
return ConeIntersectionType(filteredSuperAndEqualTypes)
|
||||
}
|
||||
|
||||
private fun filterTypes(
|
||||
@@ -123,32 +106,17 @@ object ConeTypeIntersector {
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
private inline fun MutableMap<ConeKotlinType, IntersectionStatus>.updateStatus(type: ConeKotlinType, status: IntersectionStatus) {
|
||||
// We should keep status FROM_SMARTCAST for correct diagnostic reporting
|
||||
val existingStatus = get(type)
|
||||
if (existingStatus == null) {
|
||||
put(type, status)
|
||||
} else {
|
||||
put(type, minOf(status, existingStatus))
|
||||
}
|
||||
}
|
||||
|
||||
private fun flatIntersectionTypes(
|
||||
inputTypes: List<ConeKotlinType>,
|
||||
intersectionStatus: List<IntersectionStatus>,
|
||||
typeCollector: MutableList<ConeKotlinType>,
|
||||
statusMap: MutableMap<ConeKotlinType, IntersectionStatus>
|
||||
typeCollector: MutableList<ConeKotlinType>
|
||||
) {
|
||||
for ((inputType, status) in inputTypes.zip(intersectionStatus)) {
|
||||
for (inputType in inputTypes) {
|
||||
if (inputType is ConeIntersectionType) {
|
||||
for (type in inputType.intersectedTypes) {
|
||||
typeCollector += type
|
||||
statusMap.updateStatus(type, status)
|
||||
}
|
||||
} else {
|
||||
typeCollector += inputType
|
||||
statusMap.updateStatus(inputType, status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user