[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
|
* 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
|
||||||
|
|||||||
+1
-1
@@ -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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user