Decouple TypeCheckerContext and TypeSystemContext
This commit is contained in:
committed by
TeamCityServer
parent
53a7dc1126
commit
3909e3c54c
@@ -13,15 +13,12 @@ import org.jetbrains.kotlin.utils.SmartSet
|
||||
import java.util.*
|
||||
|
||||
|
||||
abstract class AbstractTypeCheckerContext : TypeSystemContext {
|
||||
abstract class AbstractTypeCheckerContext() {
|
||||
|
||||
abstract val typeSystemContext: TypeSystemContext
|
||||
|
||||
abstract fun substitutionSupertypePolicy(type: SimpleTypeMarker): SupertypesPolicy
|
||||
|
||||
override fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker {
|
||||
return type
|
||||
}
|
||||
|
||||
open fun refineType(type: KotlinTypeMarker): KotlinTypeMarker {
|
||||
return type
|
||||
}
|
||||
@@ -34,7 +31,6 @@ abstract class AbstractTypeCheckerContext : TypeSystemContext {
|
||||
|
||||
protected var argumentsDepth = 0
|
||||
|
||||
|
||||
internal inline fun <T> runWithArgumentsSettings(subArgument: KotlinTypeMarker, f: AbstractTypeCheckerContext.() -> T): T {
|
||||
if (argumentsDepth > 100) {
|
||||
error("Arguments depth is too high. Some related argument: $subArgument")
|
||||
@@ -46,7 +42,8 @@ abstract class AbstractTypeCheckerContext : TypeSystemContext {
|
||||
return result
|
||||
}
|
||||
|
||||
open fun getLowerCapturedTypePolicy(subType: SimpleTypeMarker, superType: CapturedTypeMarker): LowerCapturedTypePolicy = CHECK_SUBTYPE_AND_LOWER
|
||||
open fun getLowerCapturedTypePolicy(subType: SimpleTypeMarker, superType: CapturedTypeMarker): LowerCapturedTypePolicy =
|
||||
CHECK_SUBTYPE_AND_LOWER
|
||||
|
||||
open fun addSubtypeConstraint(
|
||||
subType: KotlinTypeMarker,
|
||||
@@ -109,7 +106,8 @@ abstract class AbstractTypeCheckerContext : TypeSystemContext {
|
||||
if (!visitedSupertypes.add(current)) continue
|
||||
|
||||
val policy = supertypesPolicy(current).takeIf { it != SupertypesPolicy.None } ?: continue
|
||||
for (supertype in current.typeConstructor().supertypes()) {
|
||||
val supertypes = with(typeSystemContext) { current.typeConstructor().supertypes() }
|
||||
for (supertype in supertypes) {
|
||||
val newType = policy.transformType(this, supertype)
|
||||
if (predicate(newType)) {
|
||||
clear()
|
||||
@@ -133,18 +131,21 @@ abstract class AbstractTypeCheckerContext : TypeSystemContext {
|
||||
|
||||
object UpperIfFlexible : SupertypesPolicy() {
|
||||
override fun transformType(context: AbstractTypeCheckerContext, type: KotlinTypeMarker) =
|
||||
with(context) { type.upperBoundIfFlexible() }
|
||||
with(context.typeSystemContext) { type.upperBoundIfFlexible() }
|
||||
}
|
||||
|
||||
object LowerIfFlexible : SupertypesPolicy() {
|
||||
override fun transformType(context: AbstractTypeCheckerContext, type: KotlinTypeMarker) =
|
||||
with(context) { type.lowerBoundIfFlexible() }
|
||||
with(context.typeSystemContext) { type.lowerBoundIfFlexible() }
|
||||
}
|
||||
|
||||
abstract class DoCustomTransform : SupertypesPolicy()
|
||||
}
|
||||
|
||||
abstract val KotlinTypeMarker.isAllowedTypeVariable: Boolean
|
||||
|
||||
@JvmName("isAllowedTypeVariableBridge")
|
||||
fun isAllowedTypeVariable(type: KotlinTypeMarker): Boolean = type.isAllowedTypeVariable
|
||||
}
|
||||
|
||||
object AbstractTypeChecker {
|
||||
@@ -166,7 +167,7 @@ object AbstractTypeChecker {
|
||||
superConstructor: TypeConstructorMarker
|
||||
): Boolean {
|
||||
if (typeConstructor == superConstructor) return true
|
||||
with(context) {
|
||||
with(context.typeSystemContext) {
|
||||
for (superType in typeConstructor.supertypes()) {
|
||||
if (isSubtypeOfClass(context, superType.typeConstructor(), superConstructor)) {
|
||||
return true
|
||||
@@ -182,7 +183,7 @@ object AbstractTypeChecker {
|
||||
b: KotlinTypeMarker,
|
||||
stubTypesEqualToAnything: Boolean = true
|
||||
): Boolean {
|
||||
return AbstractTypeChecker.equalTypes(context.newBaseTypeCheckerContext(false, stubTypesEqualToAnything), a, b)
|
||||
return equalTypes(context.newBaseTypeCheckerContext(false, stubTypesEqualToAnything), a, b)
|
||||
}
|
||||
|
||||
fun isSubtypeOf(
|
||||
@@ -195,55 +196,61 @@ object AbstractTypeChecker {
|
||||
|
||||
if (!context.customIsSubtypeOf(subType, superType)) return false
|
||||
|
||||
return with(context) {
|
||||
completeIsSubTypeOf(prepareType(refineType(subType)), prepareType(refineType(superType)), isFromNullabilityConstraint)
|
||||
}
|
||||
return completeIsSubTypeOf(
|
||||
context,
|
||||
context.typeSystemContext.prepareType(context.refineType(subType)),
|
||||
context.typeSystemContext.prepareType(context.refineType(superType)),
|
||||
isFromNullabilityConstraint
|
||||
)
|
||||
}
|
||||
|
||||
fun equalTypes(context: AbstractTypeCheckerContext, a: KotlinTypeMarker, b: KotlinTypeMarker): Boolean = with(context) {
|
||||
if (a === b) return true
|
||||
fun equalTypes(context: AbstractTypeCheckerContext, a: KotlinTypeMarker, b: KotlinTypeMarker): Boolean =
|
||||
with(context.typeSystemContext) {
|
||||
if (a === b) return true
|
||||
|
||||
if (isCommonDenotableType(a) && isCommonDenotableType(b)) {
|
||||
val refinedA = refineType(a)
|
||||
val refinedB = refineType(b)
|
||||
val simpleA = refinedA.lowerBoundIfFlexible()
|
||||
if (!areEqualTypeConstructors(refinedA.typeConstructor(), refinedB.typeConstructor())) return false
|
||||
if (simpleA.argumentsCount() == 0) {
|
||||
if (refinedA.hasFlexibleNullability() || refinedB.hasFlexibleNullability()) return true
|
||||
if (isCommonDenotableType(a) && isCommonDenotableType(b)) {
|
||||
val refinedA = context.refineType(a)
|
||||
val refinedB = context.refineType(b)
|
||||
val simpleA = refinedA.lowerBoundIfFlexible()
|
||||
if (!areEqualTypeConstructors(refinedA.typeConstructor(), refinedB.typeConstructor())) return false
|
||||
if (simpleA.argumentsCount() == 0) {
|
||||
if (refinedA.hasFlexibleNullability() || refinedB.hasFlexibleNullability()) return true
|
||||
|
||||
return simpleA.isMarkedNullable() == refinedB.lowerBoundIfFlexible().isMarkedNullable()
|
||||
return simpleA.isMarkedNullable() == refinedB.lowerBoundIfFlexible().isMarkedNullable()
|
||||
}
|
||||
}
|
||||
|
||||
return isSubtypeOf(context, a, b) && isSubtypeOf(context, b, a)
|
||||
}
|
||||
|
||||
return isSubtypeOf(context, a, b) && isSubtypeOf(context, b, a)
|
||||
}
|
||||
|
||||
|
||||
private fun AbstractTypeCheckerContext.completeIsSubTypeOf(
|
||||
private fun completeIsSubTypeOf(
|
||||
context: AbstractTypeCheckerContext,
|
||||
subType: KotlinTypeMarker,
|
||||
superType: KotlinTypeMarker,
|
||||
isFromNullabilityConstraint: Boolean
|
||||
): Boolean {
|
||||
checkSubtypeForSpecialCases(subType.lowerBoundIfFlexible(), superType.upperBoundIfFlexible())?.let {
|
||||
addSubtypeConstraint(subType, superType, isFromNullabilityConstraint)
|
||||
): Boolean = with(context.typeSystemContext) {
|
||||
checkSubtypeForSpecialCases(context, subType.lowerBoundIfFlexible(), superType.upperBoundIfFlexible())?.let {
|
||||
context.addSubtypeConstraint(subType, superType, isFromNullabilityConstraint)
|
||||
return it
|
||||
}
|
||||
|
||||
// we should add constraints with flexible types, otherwise we never get flexible type as answer in constraint system
|
||||
addSubtypeConstraint(subType, superType, isFromNullabilityConstraint)?.let { return it }
|
||||
context.addSubtypeConstraint(subType, superType, isFromNullabilityConstraint)?.let { return it }
|
||||
|
||||
return isSubtypeOfForSingleClassifierType(subType.lowerBoundIfFlexible(), superType.upperBoundIfFlexible())
|
||||
return isSubtypeOfForSingleClassifierType(context, subType.lowerBoundIfFlexible(), superType.upperBoundIfFlexible())
|
||||
}
|
||||
|
||||
private fun AbstractTypeCheckerContext.checkSubtypeForIntegerLiteralType(
|
||||
private fun checkSubtypeForIntegerLiteralType(
|
||||
context: AbstractTypeCheckerContext,
|
||||
subType: SimpleTypeMarker,
|
||||
superType: SimpleTypeMarker
|
||||
): Boolean? {
|
||||
): Boolean? = with(context.typeSystemContext) {
|
||||
if (!subType.isIntegerLiteralType() && !superType.isIntegerLiteralType()) return null
|
||||
|
||||
fun isTypeInIntegerLiteralType(integerLiteralType: SimpleTypeMarker, type: SimpleTypeMarker, checkSupertypes: Boolean): Boolean =
|
||||
integerLiteralType.possibleIntegerTypes().any { possibleType ->
|
||||
(possibleType.typeConstructor() == type.typeConstructor()) || (checkSupertypes && isSubtypeOf(this, type, possibleType))
|
||||
(possibleType.typeConstructor() == type.typeConstructor()) || (checkSupertypes && isSubtypeOf(context, type, possibleType))
|
||||
}
|
||||
|
||||
fun isIntegerLiteralTypeInIntersectionComponents(type: SimpleTypeMarker): Boolean {
|
||||
@@ -276,12 +283,12 @@ object AbstractTypeChecker {
|
||||
return null
|
||||
}
|
||||
|
||||
private fun AbstractTypeCheckerContext.hasNothingSupertype(type: SimpleTypeMarker): Boolean {
|
||||
private fun hasNothingSupertype(context: AbstractTypeCheckerContext, type: SimpleTypeMarker): Boolean = with(context.typeSystemContext) {
|
||||
val typeConstructor = type.typeConstructor()
|
||||
if (typeConstructor.isClassTypeConstructor()) {
|
||||
return typeConstructor.isNothingConstructor()
|
||||
}
|
||||
return anySupertype(type, { it.typeConstructor().isNothingConstructor() }) {
|
||||
return context.anySupertype(type, { it.typeConstructor().isNothingConstructor() }) {
|
||||
if (it.isClassType()) {
|
||||
SupertypesPolicy.None
|
||||
} else {
|
||||
@@ -290,20 +297,24 @@ object AbstractTypeChecker {
|
||||
}
|
||||
}
|
||||
|
||||
private fun AbstractTypeCheckerContext.isSubtypeOfForSingleClassifierType(subType: SimpleTypeMarker, superType: SimpleTypeMarker): Boolean {
|
||||
private fun isSubtypeOfForSingleClassifierType(
|
||||
context: AbstractTypeCheckerContext,
|
||||
subType: SimpleTypeMarker,
|
||||
superType: SimpleTypeMarker
|
||||
): Boolean = with(context.typeSystemContext) {
|
||||
if (AbstractTypeChecker.RUN_SLOW_ASSERTIONS) {
|
||||
assert(subType.isSingleClassifierType() || subType.typeConstructor().isIntersection() || subType.isAllowedTypeVariable) {
|
||||
assert(subType.isSingleClassifierType() || subType.typeConstructor().isIntersection() || context.isAllowedTypeVariable(subType)) {
|
||||
"Not singleClassifierType and not intersection subType: $subType"
|
||||
}
|
||||
assert(superType.isSingleClassifierType() || superType.isAllowedTypeVariable) {
|
||||
assert(superType.isSingleClassifierType() || context .isAllowedTypeVariable(superType)) {
|
||||
"Not singleClassifierType superType: $superType"
|
||||
}
|
||||
}
|
||||
|
||||
if (!AbstractNullabilityChecker.isPossibleSubtype(this, subType, superType)) return false
|
||||
if (!AbstractNullabilityChecker.isPossibleSubtype(context, subType, superType)) return false
|
||||
|
||||
checkSubtypeForIntegerLiteralType(subType.lowerBoundIfFlexible(), superType.upperBoundIfFlexible())?.let {
|
||||
addSubtypeConstraint(subType, superType)
|
||||
checkSubtypeForIntegerLiteralType(context, subType.lowerBoundIfFlexible(), superType.upperBoundIfFlexible())?.let {
|
||||
context.addSubtypeConstraint(subType, superType)
|
||||
return it
|
||||
}
|
||||
|
||||
@@ -312,10 +323,10 @@ object AbstractTypeChecker {
|
||||
if (areEqualTypeConstructors(subType.typeConstructor(), superConstructor) && superConstructor.parametersCount() == 0) return true
|
||||
if (superType.typeConstructor().isAnyConstructor()) return true
|
||||
|
||||
val supertypesWithSameConstructor = findCorrespondingSupertypes(subType, superConstructor)
|
||||
val supertypesWithSameConstructor = findCorrespondingSupertypes(context, subType, superConstructor)
|
||||
when (supertypesWithSameConstructor.size) {
|
||||
0 -> return hasNothingSupertype(subType) // todo Nothing & Array<Number> <: Array<String>
|
||||
1 -> return isSubtypeForSameConstructor(supertypesWithSameConstructor.first().asArgumentList(), superType)
|
||||
0 -> return hasNothingSupertype(context, subType) // todo Nothing & Array<Number> <: Array<String>
|
||||
1 -> return context.isSubtypeForSameConstructor(supertypesWithSameConstructor.first().asArgumentList(), superType)
|
||||
|
||||
else -> { // at least 2 supertypes with same constructors. Such case is rare
|
||||
val newArguments = ArgumentList(superConstructor.parametersCount())
|
||||
@@ -333,10 +344,10 @@ object AbstractTypeChecker {
|
||||
newArguments.add(intersection)
|
||||
}
|
||||
|
||||
if (!anyNonOutParameter && isSubtypeForSameConstructor(newArguments, superType)) return true
|
||||
if (!anyNonOutParameter && context.isSubtypeForSameConstructor(newArguments, superType)) return true
|
||||
|
||||
// TODO: rethink this; now components order in intersection type affects semantic due to run subtyping (which can add constraints) only until the first successful candidate
|
||||
return supertypesWithSameConstructor.any { isSubtypeForSameConstructor(it.asArgumentList(), superType) }
|
||||
return supertypesWithSameConstructor.any { context.isSubtypeForSameConstructor(it.asArgumentList(), superType) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -344,7 +355,7 @@ object AbstractTypeChecker {
|
||||
fun AbstractTypeCheckerContext.isSubtypeForSameConstructor(
|
||||
capturedSubArguments: TypeArgumentListMarker,
|
||||
superType: SimpleTypeMarker
|
||||
): Boolean {
|
||||
): Boolean = with(this.typeSystemContext) {
|
||||
// No way to check, as no index sometimes
|
||||
//if (capturedSubArguments === superType.arguments) return true
|
||||
|
||||
@@ -375,7 +386,7 @@ object AbstractTypeChecker {
|
||||
return true
|
||||
}
|
||||
|
||||
private fun AbstractTypeCheckerContext.isCommonDenotableType(type: KotlinTypeMarker): Boolean =
|
||||
private fun TypeSystemContext.isCommonDenotableType(type: KotlinTypeMarker): Boolean =
|
||||
type.typeConstructor().isDenotable() &&
|
||||
!type.isDynamic() && !type.isDefinitelyNotNullType() &&
|
||||
type.lowerBoundIfFlexible().typeConstructor() == type.upperBoundIfFlexible().typeConstructor()
|
||||
@@ -391,9 +402,13 @@ object AbstractTypeChecker {
|
||||
return null
|
||||
}
|
||||
|
||||
private fun AbstractTypeCheckerContext.checkSubtypeForSpecialCases(subType: SimpleTypeMarker, superType: SimpleTypeMarker): Boolean? {
|
||||
private fun checkSubtypeForSpecialCases(
|
||||
context: AbstractTypeCheckerContext,
|
||||
subType: SimpleTypeMarker,
|
||||
superType: SimpleTypeMarker
|
||||
): Boolean? = with(context.typeSystemContext) {
|
||||
if (subType.isError() || superType.isError()) {
|
||||
if (isErrorTypeEqualsToAnything) return true
|
||||
if (context.isErrorTypeEqualsToAnything) return true
|
||||
|
||||
if (subType.isMarkedNullable() && !superType.isMarkedNullable()) return false
|
||||
|
||||
@@ -404,7 +419,7 @@ object AbstractTypeChecker {
|
||||
)
|
||||
}
|
||||
|
||||
if (subType.isStubType() || superType.isStubType()) return isStubTypeEqualsToAnything
|
||||
if (subType.isStubType() || superType.isStubType()) return context.isStubTypeEqualsToAnything
|
||||
|
||||
// superType might be a definitely notNull type (see KT-42824)
|
||||
val superOriginalType = superType.asDefinitelyNotNullType()?.original() ?: superType
|
||||
@@ -418,9 +433,9 @@ object AbstractTypeChecker {
|
||||
} else {
|
||||
if (superType.isDefinitelyNotNullType()) lowerType.makeDefinitelyNotNullOrNotNull() else lowerType
|
||||
}
|
||||
when (getLowerCapturedTypePolicy(subType, superTypeCaptured)) {
|
||||
CHECK_ONLY_LOWER -> return isSubtypeOf(this, subType, nullableLowerType)
|
||||
CHECK_SUBTYPE_AND_LOWER -> if (isSubtypeOf(this, subType, nullableLowerType)) return true
|
||||
when (context.getLowerCapturedTypePolicy(subType, superTypeCaptured)) {
|
||||
CHECK_ONLY_LOWER -> return isSubtypeOf(context, subType, nullableLowerType)
|
||||
CHECK_SUBTYPE_AND_LOWER -> if (isSubtypeOf(context, subType, nullableLowerType)) return true
|
||||
SKIP_LOWER -> Unit
|
||||
}
|
||||
}
|
||||
@@ -429,17 +444,18 @@ object AbstractTypeChecker {
|
||||
if (superTypeConstructor.isIntersection()) {
|
||||
assert(!superType.isMarkedNullable()) { "Intersection type should not be marked nullable!: $superType" }
|
||||
|
||||
return superTypeConstructor.supertypes().all { isSubtypeOf(this, subType, it) }
|
||||
return superTypeConstructor.supertypes().all { isSubtypeOf(context, subType, it) }
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
private fun AbstractTypeCheckerContext.collectAllSupertypesWithGivenTypeConstructor(
|
||||
private fun collectAllSupertypesWithGivenTypeConstructor(
|
||||
context: AbstractTypeCheckerContext,
|
||||
subType: SimpleTypeMarker,
|
||||
superConstructor: TypeConstructorMarker
|
||||
): List<SimpleTypeMarker> {
|
||||
): List<SimpleTypeMarker> = with(context.typeSystemContext) {
|
||||
subType.fastCorrespondingSupertypes(superConstructor)?.let {
|
||||
return it
|
||||
}
|
||||
@@ -455,7 +471,7 @@ object AbstractTypeChecker {
|
||||
|
||||
val result: MutableList<SimpleTypeMarker> = SmartList()
|
||||
|
||||
anySupertype(subType, { false }) {
|
||||
context.anySupertype(subType, { false }) {
|
||||
|
||||
val current = captureFromArguments(it, CaptureStatus.FOR_SUBTYPING) ?: it
|
||||
|
||||
@@ -468,7 +484,7 @@ object AbstractTypeChecker {
|
||||
SupertypesPolicy.LowerIfFlexible
|
||||
}
|
||||
else -> {
|
||||
substitutionSupertypePolicy(current)
|
||||
context.substitutionSupertypePolicy(current)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -476,8 +492,12 @@ object AbstractTypeChecker {
|
||||
return result
|
||||
}
|
||||
|
||||
private fun AbstractTypeCheckerContext.collectAndFilter(classType: SimpleTypeMarker, constructor: TypeConstructorMarker) =
|
||||
selectOnlyPureKotlinSupertypes(collectAllSupertypesWithGivenTypeConstructor(classType, constructor))
|
||||
private fun collectAndFilter(
|
||||
context: AbstractTypeCheckerContext,
|
||||
classType: SimpleTypeMarker,
|
||||
constructor: TypeConstructorMarker
|
||||
) =
|
||||
selectOnlyPureKotlinSupertypes(context, collectAllSupertypesWithGivenTypeConstructor(context, classType, constructor))
|
||||
|
||||
|
||||
/**
|
||||
@@ -490,7 +510,10 @@ object AbstractTypeChecker {
|
||||
*
|
||||
* More tests: javaAndKotlinSuperType & purelyImplementedCollection folder
|
||||
*/
|
||||
private fun AbstractTypeCheckerContext.selectOnlyPureKotlinSupertypes(supertypes: List<SimpleTypeMarker>): List<SimpleTypeMarker> {
|
||||
private fun selectOnlyPureKotlinSupertypes(
|
||||
context: AbstractTypeCheckerContext,
|
||||
supertypes: List<SimpleTypeMarker>
|
||||
): List<SimpleTypeMarker> = with(context.typeSystemContext) {
|
||||
if (supertypes.size < 2) return supertypes
|
||||
|
||||
val allPureSupertypes = supertypes.filter {
|
||||
@@ -502,22 +525,23 @@ object AbstractTypeChecker {
|
||||
|
||||
// nullability was checked earlier via nullabilityChecker
|
||||
// should be used only if you really sure that it is correct
|
||||
fun AbstractTypeCheckerContext.findCorrespondingSupertypes(
|
||||
fun findCorrespondingSupertypes(
|
||||
context: AbstractTypeCheckerContext,
|
||||
subType: SimpleTypeMarker,
|
||||
superConstructor: TypeConstructorMarker
|
||||
): List<SimpleTypeMarker> {
|
||||
): List<SimpleTypeMarker> = with(context.typeSystemContext) {
|
||||
if (subType.isClassType()) {
|
||||
return collectAndFilter(subType, superConstructor)
|
||||
return collectAndFilter(context, subType, superConstructor)
|
||||
}
|
||||
|
||||
// i.e. superType is not a classType
|
||||
if (!superConstructor.isClassTypeConstructor() && !superConstructor.isIntegerLiteralTypeConstructor()) {
|
||||
return collectAllSupertypesWithGivenTypeConstructor(subType, superConstructor)
|
||||
return collectAllSupertypesWithGivenTypeConstructor(context, subType, superConstructor)
|
||||
}
|
||||
|
||||
// todo add tests
|
||||
val classTypeSupertypes = SmartList<SimpleTypeMarker>()
|
||||
anySupertype(subType, { false }) {
|
||||
context.anySupertype(subType, { false }) {
|
||||
if (it.isClassType()) {
|
||||
classTypeSupertypes.add(it)
|
||||
SupertypesPolicy.None
|
||||
@@ -526,7 +550,7 @@ object AbstractTypeChecker {
|
||||
}
|
||||
}
|
||||
|
||||
return classTypeSupertypes.flatMap { collectAndFilter(it, superConstructor) }
|
||||
return classTypeSupertypes.flatMap { collectAndFilter(context, it, superConstructor) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -534,7 +558,7 @@ object AbstractTypeChecker {
|
||||
object AbstractNullabilityChecker {
|
||||
// this method checks only nullability
|
||||
fun isPossibleSubtype(context: AbstractTypeCheckerContext, subType: SimpleTypeMarker, superType: SimpleTypeMarker): Boolean =
|
||||
context.runIsPossibleSubtype(subType, superType)
|
||||
runIsPossibleSubtype(context, subType, superType)
|
||||
|
||||
fun isSubtypeOfAny(context: TypeCheckerProviderContext, type: KotlinTypeMarker): Boolean =
|
||||
AbstractNullabilityChecker.isSubtypeOfAny(
|
||||
@@ -546,82 +570,93 @@ object AbstractNullabilityChecker {
|
||||
)
|
||||
|
||||
fun isSubtypeOfAny(context: AbstractTypeCheckerContext, type: KotlinTypeMarker): Boolean =
|
||||
with(context) {
|
||||
hasNotNullSupertype(type.lowerBoundIfFlexible(), SupertypesPolicy.LowerIfFlexible)
|
||||
with(context.typeSystemContext) {
|
||||
context.hasNotNullSupertype(type.lowerBoundIfFlexible(), SupertypesPolicy.LowerIfFlexible)
|
||||
}
|
||||
|
||||
private fun AbstractTypeCheckerContext.runIsPossibleSubtype(subType: SimpleTypeMarker, superType: SimpleTypeMarker): Boolean {
|
||||
if (AbstractTypeChecker.RUN_SLOW_ASSERTIONS) {
|
||||
// it makes for case String? & Any <: String
|
||||
assert(subType.isSingleClassifierType() || subType.typeConstructor().isIntersection() || subType.isAllowedTypeVariable) {
|
||||
"Not singleClassifierType and not intersection subType: $subType"
|
||||
}
|
||||
assert(superType.isSingleClassifierType() || superType.isAllowedTypeVariable) {
|
||||
"Not singleClassifierType superType: $superType"
|
||||
private fun runIsPossibleSubtype(context: AbstractTypeCheckerContext, subType: SimpleTypeMarker, superType: SimpleTypeMarker): Boolean =
|
||||
with(context.typeSystemContext) {
|
||||
if (AbstractTypeChecker.RUN_SLOW_ASSERTIONS) {
|
||||
// it makes for case String? & Any <: String
|
||||
assert(
|
||||
subType.isSingleClassifierType() || subType.typeConstructor().isIntersection() || context.isAllowedTypeVariable(
|
||||
subType
|
||||
)
|
||||
) {
|
||||
"Not singleClassifierType and not intersection subType: $subType"
|
||||
}
|
||||
assert(superType.isSingleClassifierType() || context.isAllowedTypeVariable(superType)) {
|
||||
"Not singleClassifierType superType: $superType"
|
||||
}
|
||||
}
|
||||
|
||||
// superType is actually nullable
|
||||
if (superType.isMarkedNullable()) return true
|
||||
|
||||
// i.e. subType is definitely not null
|
||||
if (subType.isDefinitelyNotNullType()) return true
|
||||
|
||||
// i.e. subType is captured type, projection of which is marked not-null
|
||||
if (subType is CapturedTypeMarker && subType.isProjectionNotNull()) return true
|
||||
|
||||
// i.e. subType is not-nullable
|
||||
if (context.hasNotNullSupertype(subType, SupertypesPolicy.LowerIfFlexible)) return true
|
||||
|
||||
// i.e. subType hasn't not-null supertype and isn't definitely not-null, but superType is definitely not-null
|
||||
if (superType.isDefinitelyNotNullType()) return false
|
||||
|
||||
// i.e subType hasn't not-null supertype, but superType has
|
||||
if (context.hasNotNullSupertype(superType, SupertypesPolicy.UpperIfFlexible)) return false
|
||||
|
||||
// both superType and subType hasn't not-null supertype and are not definitely not null.
|
||||
|
||||
/**
|
||||
* If we still don't know, it means, that superType is not classType, for example -- type parameter.
|
||||
*
|
||||
* For captured types with lower bound this function can give to you false result. Example:
|
||||
* class A<T>, A<in Number> => \exist Q : Number <: Q. A<Q>
|
||||
* isPossibleSubtype(Number, Q) = false.
|
||||
* Such cases should be taken in to account in [NewKotlinTypeChecker.isSubtypeOf] (same for intersection types)
|
||||
*/
|
||||
|
||||
// classType cannot has special type in supertype list
|
||||
if (subType.isClassType()) return false
|
||||
|
||||
return hasPathByNotMarkedNullableNodes(context, subType, superType.typeConstructor())
|
||||
}
|
||||
|
||||
// superType is actually nullable
|
||||
if (superType.isMarkedNullable()) return true
|
||||
|
||||
// i.e. subType is definitely not null
|
||||
if (subType.isDefinitelyNotNullType()) return true
|
||||
|
||||
// i.e. subType is captured type, projection of which is marked not-null
|
||||
if (subType is CapturedTypeMarker && subType.isProjectionNotNull()) return true
|
||||
|
||||
// i.e. subType is not-nullable
|
||||
if (hasNotNullSupertype(subType, SupertypesPolicy.LowerIfFlexible)) return true
|
||||
|
||||
// i.e. subType hasn't not-null supertype and isn't definitely not-null, but superType is definitely not-null
|
||||
if (superType.isDefinitelyNotNullType()) return false
|
||||
|
||||
// i.e subType hasn't not-null supertype, but superType has
|
||||
if (hasNotNullSupertype(superType, SupertypesPolicy.UpperIfFlexible)) return false
|
||||
|
||||
// both superType and subType hasn't not-null supertype and are not definitely not null.
|
||||
|
||||
/**
|
||||
* If we still don't know, it means, that superType is not classType, for example -- type parameter.
|
||||
*
|
||||
* For captured types with lower bound this function can give to you false result. Example:
|
||||
* class A<T>, A<in Number> => \exist Q : Number <: Q. A<Q>
|
||||
* isPossibleSubtype(Number, Q) = false.
|
||||
* Such cases should be taken in to account in [NewKotlinTypeChecker.isSubtypeOf] (same for intersection types)
|
||||
*/
|
||||
|
||||
// classType cannot has special type in supertype list
|
||||
if (subType.isClassType()) return false
|
||||
|
||||
return hasPathByNotMarkedNullableNodes(subType, superType.typeConstructor())
|
||||
}
|
||||
|
||||
fun AbstractTypeCheckerContext.hasNotNullSupertype(type: SimpleTypeMarker, supertypesPolicy: SupertypesPolicy) =
|
||||
anySupertype(type, {
|
||||
(it.isClassType() && !it.isMarkedNullable()) || it.isDefinitelyNotNullType()
|
||||
}) {
|
||||
if (it.isMarkedNullable()) SupertypesPolicy.None else supertypesPolicy
|
||||
with(typeSystemContext) {
|
||||
anySupertype(type, {
|
||||
(it.isClassType() && !it.isMarkedNullable()) || it.isDefinitelyNotNullType()
|
||||
}) {
|
||||
if (it.isMarkedNullable()) SupertypesPolicy.None else supertypesPolicy
|
||||
}
|
||||
}
|
||||
|
||||
fun TypeCheckerProviderContext.hasPathByNotMarkedNullableNodes(start: SimpleTypeMarker, end: TypeConstructorMarker) =
|
||||
newBaseTypeCheckerContext(errorTypesEqualToAnything = false, stubTypesEqualToAnything = true)
|
||||
.hasPathByNotMarkedNullableNodes(start, end)
|
||||
|
||||
fun AbstractTypeCheckerContext.hasPathByNotMarkedNullableNodes(start: SimpleTypeMarker, end: TypeConstructorMarker) =
|
||||
anySupertype(
|
||||
start,
|
||||
{ isApplicableAsEndNode(it, end) },
|
||||
{ if (it.isMarkedNullable()) SupertypesPolicy.None else SupertypesPolicy.LowerIfFlexible }
|
||||
hasPathByNotMarkedNullableNodes(
|
||||
newBaseTypeCheckerContext(errorTypesEqualToAnything = false, stubTypesEqualToAnything = true), start, end
|
||||
)
|
||||
|
||||
private fun AbstractTypeCheckerContext.isApplicableAsEndNode(type: SimpleTypeMarker, end: TypeConstructorMarker): Boolean {
|
||||
if (type.isNothing()) return true
|
||||
if (type.isMarkedNullable()) return false
|
||||
fun hasPathByNotMarkedNullableNodes(context: AbstractTypeCheckerContext, start: SimpleTypeMarker, end: TypeConstructorMarker) =
|
||||
with(context.typeSystemContext) {
|
||||
context.anySupertype(
|
||||
start,
|
||||
{ isApplicableAsEndNode(context, it, end) },
|
||||
{ if (it.isMarkedNullable()) SupertypesPolicy.None else SupertypesPolicy.LowerIfFlexible }
|
||||
)
|
||||
}
|
||||
|
||||
if (isStubTypeEqualsToAnything && type.isStubType()) return true
|
||||
private fun isApplicableAsEndNode(context: AbstractTypeCheckerContext, type: SimpleTypeMarker, end: TypeConstructorMarker): Boolean =
|
||||
with(context.typeSystemContext) {
|
||||
if (type.isNothing()) return true
|
||||
if (type.isMarkedNullable()) return false
|
||||
|
||||
return areEqualTypeConstructors(type.typeConstructor(), end)
|
||||
}
|
||||
if (context.isStubTypeEqualsToAnything && type.isStubType()) return true
|
||||
|
||||
return areEqualTypeConstructors(type.typeConstructor(), end)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -393,24 +393,28 @@ public class OverridingUtil {
|
||||
"Should be the same number of type parameters: " + firstParameters + " vs " + secondParameters;
|
||||
|
||||
NewKotlinTypeCheckerImpl typeChecker = new NewKotlinTypeCheckerImpl(kotlinTypeRefiner);
|
||||
OverridingUtilTypeCheckerContext context = createTypeCheckerContext(firstParameters, secondParameters);
|
||||
ClassicTypeCheckerContext context = createTypeCheckerContext(firstParameters, secondParameters);
|
||||
|
||||
return new Pair<NewKotlinTypeCheckerImpl, ClassicTypeCheckerContext>(typeChecker, context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private OverridingUtilTypeCheckerContext createTypeCheckerContext(
|
||||
private ClassicTypeCheckerContext createTypeCheckerContext(
|
||||
@NotNull List<TypeParameterDescriptor> firstParameters,
|
||||
@NotNull List<TypeParameterDescriptor> secondParameters
|
||||
) {
|
||||
if (firstParameters.isEmpty()) return new OverridingUtilTypeCheckerContext(null);
|
||||
if (firstParameters.isEmpty()) {
|
||||
return (ClassicTypeCheckerContext) new OverridingUtilTypeSystemContext(null, equalityAxioms, kotlinTypeRefiner)
|
||||
.newBaseTypeCheckerContext(true, true);
|
||||
}
|
||||
|
||||
Map<TypeConstructor, TypeConstructor> matchingTypeConstructors = new HashMap<TypeConstructor, TypeConstructor>();
|
||||
for (int i = 0; i < firstParameters.size(); i++) {
|
||||
matchingTypeConstructors.put(firstParameters.get(i).getTypeConstructor(), secondParameters.get(i).getTypeConstructor());
|
||||
}
|
||||
|
||||
return new OverridingUtilTypeCheckerContext(matchingTypeConstructors);
|
||||
return (ClassicTypeCheckerContext) new OverridingUtilTypeSystemContext(matchingTypeConstructors, equalityAxioms, kotlinTypeRefiner)
|
||||
.newBaseTypeCheckerContext(true, true);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -977,34 +981,6 @@ public class OverridingUtil {
|
||||
return maxVisibility;
|
||||
}
|
||||
|
||||
private class OverridingUtilTypeCheckerContext extends ClassicTypeCheckerContext {
|
||||
private final @Nullable Map<TypeConstructor, TypeConstructor> matchingTypeConstructors;
|
||||
|
||||
public OverridingUtilTypeCheckerContext(@Nullable Map<TypeConstructor, TypeConstructor> matchingTypeConstructors) {
|
||||
super(
|
||||
/* errorTypesEqualsToAnything = */ true,
|
||||
/* stubTypesEqualsToAnything = */ true,
|
||||
/* allowedTypeVariable = */ true,
|
||||
kotlinTypeRefiner
|
||||
);
|
||||
this.matchingTypeConstructors = matchingTypeConstructors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areEqualTypeConstructors(@NotNull TypeConstructor a, @NotNull TypeConstructor b) {
|
||||
return super.areEqualTypeConstructors(a, b) || areEqualTypeConstructorsByAxioms(a, b);
|
||||
}
|
||||
|
||||
private boolean areEqualTypeConstructorsByAxioms(@NotNull TypeConstructor a, @NotNull TypeConstructor b) {
|
||||
if (equalityAxioms.equals(a, b)) return true;
|
||||
if (matchingTypeConstructors == null) return false;
|
||||
|
||||
TypeConstructor img1 = matchingTypeConstructors.get(a);
|
||||
TypeConstructor img2 = matchingTypeConstructors.get(b);
|
||||
return (img1 != null && img1.equals(b)) || (img2 != null && img2.equals(a));
|
||||
}
|
||||
}
|
||||
|
||||
public static class OverrideCompatibilityInfo {
|
||||
public enum Result {
|
||||
OVERRIDABLE,
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve
|
||||
|
||||
import org.jetbrains.kotlin.types.AbstractTypeCheckerContext
|
||||
import org.jetbrains.kotlin.types.TypeConstructor
|
||||
import org.jetbrains.kotlin.types.checker.ClassicTypeCheckerContext
|
||||
import org.jetbrains.kotlin.types.checker.ClassicTypeSystemContext
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner
|
||||
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
|
||||
|
||||
class OverridingUtilTypeSystemContext(
|
||||
val matchingTypeConstructors: Map<TypeConstructor, TypeConstructor>?,
|
||||
private val equalityAxioms: KotlinTypeChecker.TypeConstructorEquality,
|
||||
val kotlinTypeRefiner: KotlinTypeRefiner
|
||||
) : ClassicTypeSystemContext {
|
||||
|
||||
override fun areEqualTypeConstructors(c1: TypeConstructorMarker, c2: TypeConstructorMarker): Boolean {
|
||||
require(c1 is TypeConstructor)
|
||||
require(c2 is TypeConstructor)
|
||||
return super.areEqualTypeConstructors(c1, c2) || areEqualTypeConstructorsByAxioms(c1, c2)
|
||||
}
|
||||
|
||||
override fun newBaseTypeCheckerContext(
|
||||
errorTypesEqualToAnything: Boolean,
|
||||
stubTypesEqualToAnything: Boolean
|
||||
): AbstractTypeCheckerContext {
|
||||
return ClassicTypeCheckerContext(
|
||||
errorTypesEqualToAnything,
|
||||
stubTypesEqualToAnything,
|
||||
allowedTypeVariable = true,
|
||||
kotlinTypeRefiner,
|
||||
this
|
||||
)
|
||||
}
|
||||
|
||||
private fun areEqualTypeConstructorsByAxioms(a: TypeConstructor, b: TypeConstructor): Boolean {
|
||||
if (equalityAxioms.equals(a, b)) return true
|
||||
if (matchingTypeConstructors == null) return false
|
||||
val img1 = matchingTypeConstructors[a]
|
||||
val img2 = matchingTypeConstructors[b]
|
||||
return img1 != null && img1 == b || img2 != null && img2 == a
|
||||
}
|
||||
}
|
||||
+4
-27
@@ -16,24 +16,18 @@
|
||||
|
||||
package org.jetbrains.kotlin.types.checker
|
||||
|
||||
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||
import org.jetbrains.kotlin.types.model.SimpleTypeMarker
|
||||
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
|
||||
import org.jetbrains.kotlin.types.refinement.TypeRefinement
|
||||
|
||||
open class ClassicTypeCheckerContext(
|
||||
val errorTypeEqualsToAnything: Boolean,
|
||||
val stubTypeEqualsToAnything: Boolean = true,
|
||||
val allowedTypeVariable: Boolean = true,
|
||||
val kotlinTypeRefiner: KotlinTypeRefiner = KotlinTypeRefiner.Default
|
||||
) : ClassicTypeSystemContext, AbstractTypeCheckerContext() {
|
||||
|
||||
override fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker {
|
||||
require(type is KotlinType, type::errorMessage)
|
||||
return NewKotlinTypeChecker.Default.transformToNewType(type.unwrap())
|
||||
}
|
||||
val kotlinTypeRefiner: KotlinTypeRefiner = KotlinTypeRefiner.Default,
|
||||
override val typeSystemContext: ClassicTypeSystemContext = SimpleClassicTypeSystemContext
|
||||
) : AbstractTypeCheckerContext() {
|
||||
|
||||
@OptIn(TypeRefinement::class)
|
||||
override fun refineType(type: KotlinTypeMarker): KotlinTypeMarker {
|
||||
@@ -47,25 +41,8 @@ open class ClassicTypeCheckerContext(
|
||||
override val isStubTypeEqualsToAnything: Boolean
|
||||
get() = stubTypeEqualsToAnything
|
||||
|
||||
override fun areEqualTypeConstructors(c1: TypeConstructorMarker, c2: TypeConstructorMarker): Boolean {
|
||||
require(c1 is TypeConstructor, c1::errorMessage)
|
||||
require(c2 is TypeConstructor, c2::errorMessage)
|
||||
return areEqualTypeConstructors(c1, c2)
|
||||
}
|
||||
|
||||
open fun areEqualTypeConstructors(a: TypeConstructor, b: TypeConstructor): Boolean = when {
|
||||
/*
|
||||
* For integer literal types we have special rules for constructor's equality,
|
||||
* so we have to check it manually
|
||||
* For example: Int in ILT.possibleTypes -> ILT == Int
|
||||
*/
|
||||
a is IntegerLiteralTypeConstructor -> a.checkConstructor(b)
|
||||
b is IntegerLiteralTypeConstructor -> b.checkConstructor(a)
|
||||
else -> a == b
|
||||
}
|
||||
|
||||
override fun substitutionSupertypePolicy(type: SimpleTypeMarker): SupertypesPolicy.DoCustomTransform {
|
||||
return classicSubstitutionSupertypePolicy(type)
|
||||
return typeSystemContext.classicSubstitutionSupertypePolicy(type)
|
||||
}
|
||||
|
||||
override val KotlinTypeMarker.isAllowedTypeVariable: Boolean get() = this is UnwrappedType && allowedTypeVariable && constructor is NewTypeVariableConstructor
|
||||
|
||||
@@ -341,7 +341,7 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext, TypeSy
|
||||
errorTypesEqualToAnything: Boolean,
|
||||
stubTypesEqualToAnything: Boolean
|
||||
): AbstractTypeCheckerContext {
|
||||
return ClassicTypeCheckerContext(errorTypesEqualToAnything, stubTypesEqualToAnything)
|
||||
return ClassicTypeCheckerContext(errorTypesEqualToAnything, stubTypesEqualToAnything, typeSystemContext = this)
|
||||
}
|
||||
|
||||
override fun nullableNothingType(): SimpleTypeMarker {
|
||||
@@ -485,8 +485,8 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext, TypeSy
|
||||
}
|
||||
|
||||
override fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker {
|
||||
require(type is UnwrappedType, type::errorMessage)
|
||||
return NewKotlinTypeChecker.Default.transformToNewType(type)
|
||||
require(type is KotlinType, type::errorMessage)
|
||||
return NewKotlinTypeChecker.Default.transformToNewType(type.unwrap())
|
||||
}
|
||||
|
||||
override fun DefinitelyNotNullTypeMarker.original(): SimpleTypeMarker {
|
||||
|
||||
Reference in New Issue
Block a user