[FIR] Remove status map from intersection type

This commit is contained in:
Dmitriy Novozhilov
2019-08-29 11:22:05 +03:00
parent ef4ef08b1d
commit e4938c6c36
5 changed files with 25 additions and 85 deletions
@@ -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
@@ -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)
}
}
}