[FE] Review fixes

This commit is contained in:
Victor Petukhov
2022-04-18 12:07:27 +03:00
committed by teamcity
parent c71ae4301c
commit e0a1f1c405
24 changed files with 60 additions and 75 deletions
@@ -5,8 +5,6 @@
package org.jetbrains.kotlin.types
enum class EmptyIntersectionTypeKind { NOT_EMPTY_INTERSECTION, MULTIPLE_CLASSES, SINGLE_FINAL_CLASS }
enum class EmptyIntersectionTypeKind { NOT_EMPTY_INTERSECTION, MULTIPLE_CLASSES } // TODO: add `SINGLE_FINAL_CLASS` later
fun EmptyIntersectionTypeKind.isDefinitelyEmpty(): Boolean = this == EmptyIntersectionTypeKind.MULTIPLE_CLASSES
fun EmptyIntersectionTypeKind.isPossibleEmpty(): Boolean = this == EmptyIntersectionTypeKind.SINGLE_FINAL_CLASS
@@ -321,52 +321,47 @@ interface TypeSystemInferenceExtensionContext : TypeSystemContext, TypeSystemBui
if (this.isEmpty())
return EmptyIntersectionTypeKind.NOT_EMPTY_INTERSECTION
val types = this.withIndex()
val types = this.toList()
for ((i, firstType) in types) {
if (!firstType.typeConstructor().mayCauseEmptyIntersection())
continue
for (i in 0 until types.size) {
val firstType = types[i]
if (!firstType.typeConstructor().mayCauseEmptyIntersection()) continue
val doesFirstTypeContainTypeParameters by lazy { firstType.contains { it.typeConstructor().isTypeParameterTypeConstructor() } }
val firstSubstitutedType by lazy { firstType.eraseContainingTypeParameters() }
for ((j, secondType) in types) {
if (i >= j || !secondType.typeConstructor().mayCauseEmptyIntersection()) continue
for (j in i + 1 until types.size) {
val secondType = types[j]
if (!secondType.typeConstructor().mayCauseEmptyIntersection()) continue
val doesSecondTypeContainTypeParameters = secondType.contains { it.typeConstructor().isTypeParameterTypeConstructor() }
val secondSubstitutedType by lazy { secondType.eraseContainingTypeParameters() }
val anyContainingTypeParameter = doesFirstTypeContainTypeParameters || doesSecondTypeContainTypeParameters
val secondSubstitutedType = secondType.eraseContainingTypeParameters()
when {
!anyContainingTypeParameter && !canHaveSubtype(listOf(firstType, secondType)) ->
return EmptyIntersectionTypeKind.MULTIPLE_CLASSES
anyContainingTypeParameter && !canHaveSubtype(listOf(firstSubstitutedType, secondSubstitutedType)) ->
return EmptyIntersectionTypeKind.MULTIPLE_CLASSES
}
if (!canHaveCommonSubtype(firstSubstitutedType, secondSubstitutedType))
return EmptyIntersectionTypeKind.MULTIPLE_CLASSES
}
}
return EmptyIntersectionTypeKind.NOT_EMPTY_INTERSECTION
}
private fun canHaveSubtype(types: List<KotlinTypeMarker>): Boolean {
val expandedTypes = types.map {
if (it.typeConstructor() is IntersectionTypeConstructorMarker) {
it.typeConstructor().supertypes().toList()
} else listOf(it)
}.flatten().withIndex()
private fun canHaveCommonSubtype(first: KotlinTypeMarker, second: KotlinTypeMarker): Boolean {
fun extractIntersectionComponentsIfNeeded(type: KotlinTypeMarker) =
if (type.typeConstructor() is IntersectionTypeConstructorMarker) {
type.typeConstructor().supertypes().toList()
} else listOf(type)
val expandedTypes = extractIntersectionComponentsIfNeeded(first) + extractIntersectionComponentsIfNeeded(second)
val typeCheckerState = newTypeCheckerState(errorTypesEqualToAnything = true, stubTypesEqualToAnything = true)
for ((i, firstType) in expandedTypes) {
for (i in 0 until expandedTypes.size) {
val firstType = expandedTypes[i]
val firstTypeConstructor = firstType.typeConstructor()
if (!firstTypeConstructor.mayCauseEmptyIntersection())
continue
for ((j, secondType) in expandedTypes) {
if (i >= j) continue
for (j in i + 1 until expandedTypes.size) {
val secondType = expandedTypes[j]
val secondTypeConstructor = secondType.typeConstructor()
if (!secondTypeConstructor.mayCauseEmptyIntersection())
@@ -375,14 +370,12 @@ interface TypeSystemInferenceExtensionContext : TypeSystemContext, TypeSystemBui
if (areEqualTypeConstructors(firstTypeConstructor, secondTypeConstructor) && secondTypeConstructor.parametersCount() == 0)
continue
// Below is determining having subtypes for two classes
// A class type may have only one supertype of class-based type constructor
val superTypeByFirstConstructor = AbstractTypeChecker.findCorrespondingSupertypes(
typeCheckerState, firstType.lowerBoundIfFlexible(), secondTypeConstructor
).takeIf { it.isNotEmpty() }?.single()
).singleOrNull()
val superTypeBySecondConstructor = AbstractTypeChecker.findCorrespondingSupertypes(
typeCheckerState, secondType.lowerBoundIfFlexible(), firstTypeConstructor
).takeIf { it.isNotEmpty() }?.single()
).singleOrNull()
if (superTypeByFirstConstructor == null && superTypeBySecondConstructor == null)
return false
@@ -390,7 +383,7 @@ interface TypeSystemInferenceExtensionContext : TypeSystemContext, TypeSystemBui
if (superTypeByFirstConstructor == null || superTypeBySecondConstructor == null)
continue // first or second is actually subtype of another
if (!areTypeArgumentsCompatibleToHaveSubtypes(superTypeByFirstConstructor, superTypeBySecondConstructor)) {
if (!checkArgumentsOfTypesToBeAbleToHaveCommonSubtype(superTypeByFirstConstructor, superTypeBySecondConstructor)) {
return false
}
}
@@ -417,20 +410,20 @@ interface TypeSystemInferenceExtensionContext : TypeSystemContext, TypeSystemBui
variance1: TypeVariance,
variance2: TypeVariance,
): Boolean {
val argumentOfFirst = firstType.getArgument(argumentIndex).uncaptureIfNeeded()
val parameterOfFirst = firstType.typeConstructor().getParameter(argumentIndex)
fun getEffectiveVariance(type: KotlinTypeMarker): TypeVariance? {
val argument = type.getArgument(argumentIndex).uncaptureIfNeeded()
val parameter = type.typeConstructor().getParameter(argumentIndex)
return AbstractTypeChecker.effectiveVariance(parameter.getVariance(), argument.getVariance())
}
val argumentOfSecond = secondType.getArgument(argumentIndex).uncaptureIfNeeded()
val parameterOfSecond = secondType.typeConstructor().getParameter(argumentIndex)
val effectiveVariance1 = AbstractTypeChecker.effectiveVariance(parameterOfFirst.getVariance(), argumentOfFirst.getVariance())
val effectiveVariance2 = AbstractTypeChecker.effectiveVariance(parameterOfSecond.getVariance(), argumentOfSecond.getVariance())
val effectiveVariance1 = getEffectiveVariance(firstType)
val effectiveVariance2 = getEffectiveVariance(secondType)
return (effectiveVariance1 == variance1 && effectiveVariance2 == variance2)
|| (effectiveVariance1 == variance2 && effectiveVariance2 == variance1)
}
private fun areTypeArgumentsCompatibleToHaveSubtypes(firstType: KotlinTypeMarker, secondType: KotlinTypeMarker): Boolean {
private fun checkArgumentsOfTypesToBeAbleToHaveCommonSubtype(firstType: KotlinTypeMarker, secondType: KotlinTypeMarker): Boolean {
require(firstType.typeConstructor() == secondType.typeConstructor()) {
"Type constructors of the passed types should be the same to compare their arguments"
}
@@ -467,13 +460,13 @@ interface TypeSystemInferenceExtensionContext : TypeSystemContext, TypeSystemBui
if (!isSubtypeOf(argumentTypeOfFirst, argumentTypeOfSecond)) {
return false
}
} else if (!canHaveSubtype(listOf(argumentTypeOfFirst, argumentTypeOfSecond))) {
} else if (!canHaveCommonSubtype(argumentTypeOfFirst, argumentTypeOfSecond)) {
return false
}
}
areArgumentsOfSpecifiedVariances(firstType, secondType, i, TypeVariance.OUT, TypeVariance.OUT)
|| areArgumentsOfSpecifiedVariances(firstType, secondType, i, TypeVariance.IN, TypeVariance.IN) -> {
if (!canHaveSubtype(listOf(argumentTypeOfFirst, argumentTypeOfSecond))) {
if (!canHaveCommonSubtype(argumentTypeOfFirst, argumentTypeOfSecond)) {
return false
}
}