[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 * only via ConeTypeIntersector
*/ */
class ConeIntersectionType( class ConeIntersectionType(
val constructor: ConeIntersectionTypeConstructor val intersectedTypes: Collection<ConeKotlinType>
) : ConeKotlinType(), SimpleTypeMarker { ) : ConeKotlinType(), SimpleTypeMarker, TypeConstructorMarker {
override val typeArguments: Array<out ConeKotlinTypeProjection> override val typeArguments: Array<out ConeKotlinTypeProjection>
get() = emptyArray() get() = emptyArray()
override val nullability: ConeNullability override val nullability: ConeNullability
get() = ConeNullability.NOT_NULL get() = ConeNullability.NOT_NULL
val intersectedTypes: Collection<ConeKotlinType> get() = constructor.intersectedTypes
val statusMap: Map<ConeKotlinType, ConeIntersectionTypeConstructor.IntersectionStatus> get() = constructor.statusMap
} }
class ConeIntersectionTypeConstructor( fun ConeIntersectionType.mapTypes(func: (ConeKotlinType) -> ConeKotlinType): ConeIntersectionType {
val intersectedTypes: Collection<ConeKotlinType>, return ConeIntersectionType(intersectedTypes.map(func))
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)
} }
@@ -164,9 +164,9 @@ fun <T : ConeKotlinType> T.withNullability(nullability: ConeNullability): T {
is ConeTypeVariableType -> ConeTypeVariableType(nullability, lookupTag) as T is ConeTypeVariableType -> ConeTypeVariableType(nullability, lookupTag) as T
is ConeCapturedType -> ConeCapturedType(captureStatus, lowerType, nullability, constructor) as T is ConeCapturedType -> ConeCapturedType(captureStatus, lowerType, nullability, constructor) as T
is ConeIntersectionType -> when (nullability) { is ConeIntersectionType -> when (nullability) {
ConeNullability.NULLABLE -> ConeIntersectionType(constructor.mapTypes { ConeNullability.NULLABLE -> this.mapTypes {
it.withNullability(nullability) it.withNullability(nullability)
}) }
ConeNullability.UNKNOWN -> this // TODO: is that correct? ConeNullability.UNKNOWN -> this // TODO: is that correct?
ConeNullability.NOT_NULL -> this ConeNullability.NOT_NULL -> this
} as T } as T
@@ -89,7 +89,7 @@ abstract class AbstractConeSubstitutor : ConeSubstitutor() {
substitutedTypes += substitutedType substitutedTypes += substitutedType
} }
if (!somethingIsSubstituted) return null if (!somethingIsSubstituted) return null
return ConeIntersectionType(ConeIntersectionTypeConstructor(substitutedTypes, statusMap)) return ConeIntersectionType(substitutedTypes)
} }
private fun ConeDefinitelyNotNullType.substituteOriginal(): ConeDefinitelyNotNullType? { 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.expandedConeType
import org.jetbrains.kotlin.fir.declarations.superConeTypes import org.jetbrains.kotlin.fir.declarations.superConeTypes
import org.jetbrains.kotlin.fir.resolve.* 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.ConeTypeVariableTypeConstructor
import org.jetbrains.kotlin.fir.resolve.calls.hasNullableSuperType import org.jetbrains.kotlin.fir.resolve.calls.hasNullableSuperType
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
@@ -141,7 +142,7 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
is ConeAbbreviatedType -> this.directExpansionType(session)?.typeConstructor() is ConeAbbreviatedType -> this.directExpansionType(session)?.typeConstructor()
?: ErrorTypeConstructor("Failed to expand alias: ${this}") ?: ErrorTypeConstructor("Failed to expand alias: ${this}")
is ConeLookupTagBasedType -> this.lookupTag.toSymbol(session) ?: ErrorTypeConstructor("Unresolved: ${this.lookupTag}") is ConeLookupTagBasedType -> this.lookupTag.toSymbol(session) ?: ErrorTypeConstructor("Unresolved: ${this.lookupTag}")
is ConeIntersectionType -> constructor is ConeIntersectionType -> this
else -> error("?: ${this}") else -> error("?: ${this}")
} }
@@ -206,7 +207,7 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
is ConeCapturedTypeConstructor, is ConeCapturedTypeConstructor,
is ErrorTypeConstructor, is ErrorTypeConstructor,
is ConeTypeVariableTypeConstructor, is ConeTypeVariableTypeConstructor,
is ConeIntersectionTypeConstructor -> 0 is ConeIntersectionType -> 0
is FirClassSymbol -> fir.typeParameters.size is FirClassSymbol -> fir.typeParameters.size
is FirTypeAliasSymbol -> fir.typeParameters.size is FirTypeAliasSymbol -> fir.typeParameters.size
else -> error("?!:10") else -> error("?!:10")
@@ -232,13 +233,13 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
is FirClassSymbol -> fir.superConeTypes is FirClassSymbol -> fir.superConeTypes
is FirTypeAliasSymbol -> listOfNotNull(fir.expandedConeType) is FirTypeAliasSymbol -> listOfNotNull(fir.expandedConeType)
is ConeCapturedTypeConstructor -> supertypes!! is ConeCapturedTypeConstructor -> supertypes!!
is ConeIntersectionTypeConstructor -> intersectedTypes is ConeIntersectionType -> intersectedTypes
else -> error("?!:13") else -> error("?!:13")
} }
} }
override fun TypeConstructorMarker.isIntersection(): Boolean { override fun TypeConstructorMarker.isIntersection(): Boolean {
return this is ConeIntersectionTypeConstructor return this is ConeIntersectionType
} }
override fun TypeConstructorMarker.isClassTypeConstructor(): Boolean { override fun TypeConstructorMarker.isClassTypeConstructor(): Boolean {
@@ -279,7 +280,7 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
return when (this) { return when (this) {
is ConeCapturedTypeConstructor, is ConeCapturedTypeConstructor,
is ConeTypeVariableTypeConstructor, is ConeTypeVariableTypeConstructor,
is ConeIntersectionTypeConstructor -> false is ConeIntersectionType -> false
is ConeSymbol -> true is ConeSymbol -> true
else -> true else -> true
} }
@@ -381,12 +382,12 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
override fun intersectTypes(types: List<SimpleTypeMarker>): SimpleTypeMarker { override fun intersectTypes(types: List<SimpleTypeMarker>): SimpleTypeMarker {
@Suppress("UNCHECKED_CAST") @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 { override fun intersectTypes(types: List<KotlinTypeMarker>): KotlinTypeMarker {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
return ConeTypeIntersector.intersectTypes(this, types as List<ConeKotlinType>) return ConeTypeIntersector.intersectTypes(this as ConeInferenceContext, types as List<ConeKotlinType>)
} }
private fun prepareClassLikeType( private fun prepareClassLikeType(
@@ -6,32 +6,22 @@
package org.jetbrains.kotlin.fir.types package org.jetbrains.kotlin.fir.types
import org.jetbrains.kotlin.fir.resolve.calls.ConeInferenceContext import org.jetbrains.kotlin.fir.resolve.calls.ConeInferenceContext
import org.jetbrains.kotlin.fir.types.ConeIntersectionTypeConstructor.IntersectionStatus
import org.jetbrains.kotlin.types.AbstractTypeChecker import org.jetbrains.kotlin.types.AbstractTypeChecker
import java.util.* import java.util.*
import kotlin.collections.LinkedHashSet import kotlin.collections.LinkedHashSet
object ConeTypeIntersector { object ConeTypeIntersector {
fun intersectTypes(context: ConeTypeContext, types: List<ConeKotlinType>): ConeKotlinType { fun intersectTypes(
require(context is ConeInferenceContext)
return intersectTypes(context, types, types.map { IntersectionStatus.FROM_INFERENCE })
}
private fun intersectTypes(
context: ConeInferenceContext, context: ConeInferenceContext,
types: List<ConeKotlinType>, types: List<ConeKotlinType>
intersectionStatus: List<IntersectionStatus>
): ConeKotlinType { ): ConeKotlinType {
assert(types.size == intersectionStatus.size)
when (types.size) { when (types.size) {
0 -> error("Expected some types") 0 -> error("Expected some types")
1 -> return types.single() 1 -> return types.single()
} }
val inputTypes = mutableListOf<ConeKotlinType>() val inputTypes = mutableListOf<ConeKotlinType>()
val statusMap = mutableMapOf<ConeKotlinType, IntersectionStatus>() flatIntersectionTypes(types, inputTypes)
flatIntersectionTypes(types, intersectionStatus, inputTypes, statusMap)
/** /**
* resultNullability. Value description: * resultNullability. Value description:
@@ -49,19 +39,16 @@ object ConeTypeIntersector {
val inputTypesWithCorrectNullability = inputTypes.mapTo(LinkedHashSet()) { val inputTypesWithCorrectNullability = inputTypes.mapTo(LinkedHashSet()) {
if (resultNullability == ResultNullability.NOT_NULL) with(context) { if (resultNullability == ResultNullability.NOT_NULL) with(context) {
val resultType = it.makeDefinitelyNotNullOrNotNull() as ConeKotlinType it.makeDefinitelyNotNullOrNotNull() as ConeKotlinType
statusMap[resultType] = statusMap.remove(it)!!
resultType
} else it } else it
} }
return intersectTypesWithoutIntersectionType(context, inputTypesWithCorrectNullability, statusMap) return intersectTypesWithoutIntersectionType(context, inputTypesWithCorrectNullability)
} }
private fun intersectTypesWithoutIntersectionType( private fun intersectTypesWithoutIntersectionType(
context: ConeTypeContext, context: ConeTypeContext,
inputTypes: Set<ConeKotlinType>, inputTypes: Set<ConeKotlinType>
statusMap: MutableMap<ConeKotlinType, IntersectionStatus>
): ConeKotlinType { ): ConeKotlinType {
if (inputTypes.size == 1) return inputTypes.single().type 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 * 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 * 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) assert(filteredEqualTypes.isNotEmpty(), errorMessage)
@@ -95,11 +82,7 @@ object ConeTypeIntersector {
if (filteredSuperAndEqualTypes.size < 2) return filteredSuperAndEqualTypes.single() if (filteredSuperAndEqualTypes.size < 2) return filteredSuperAndEqualTypes.single()
val constructor = ConeIntersectionTypeConstructor( return ConeIntersectionType(filteredSuperAndEqualTypes)
filteredSuperAndEqualTypes,
filteredSuperAndEqualTypes.associateWithTo(mutableMapOf()) { statusMap[it]!! }
)
return ConeIntersectionType(constructor)
} }
private fun filterTypes( 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( private fun flatIntersectionTypes(
inputTypes: List<ConeKotlinType>, inputTypes: List<ConeKotlinType>,
intersectionStatus: List<IntersectionStatus>, typeCollector: MutableList<ConeKotlinType>
typeCollector: MutableList<ConeKotlinType>,
statusMap: MutableMap<ConeKotlinType, IntersectionStatus>
) { ) {
for ((inputType, status) in inputTypes.zip(intersectionStatus)) { for (inputType in inputTypes) {
if (inputType is ConeIntersectionType) { if (inputType is ConeIntersectionType) {
for (type in inputType.intersectedTypes) { for (type in inputType.intersectedTypes) {
typeCollector += type typeCollector += type
statusMap.updateStatus(type, status)
} }
} else { } else {
typeCollector += inputType typeCollector += inputType
statusMap.updateStatus(inputType, status)
} }
} }
} }