[API Usage] Inject Refiner into KotlinTypeChecker, use it for subtyping

This commit is contained in:
Dmitriy Novozhilov
2019-07-03 19:35:11 +03:00
committed by Dmitry Savvinov
parent 9047ddfc2f
commit a1b52b2f90
5 changed files with 52 additions and 12 deletions
@@ -22,11 +22,23 @@ import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker.transformToNewTyp
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 allowedTypeVariable: Boolean = true) : ClassicTypeSystemContext, AbstractTypeCheckerContext() {
open class ClassicTypeCheckerContext(
val errorTypeEqualsToAnything: Boolean,
val allowedTypeVariable: Boolean = true,
val kotlinTypeRefiner: KotlinTypeRefiner = KotlinTypeRefiner.Default
) : ClassicTypeSystemContext, AbstractTypeCheckerContext() {
override fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker {
return transformToNewType((type as KotlinType).unwrap())
require(type is KotlinType, type::errorMessage)
return transformToNewType(type.unwrap())
}
@UseExperimental(TypeRefinement::class)
override fun refineType(type: KotlinTypeMarker): KotlinTypeMarker {
require(type is KotlinType, type::errorMessage)
return kotlinTypeRefiner.refineType(type)
}
override val isErrorTypeEqualsToAnything: Boolean
@@ -56,20 +56,24 @@ object ErrorTypesAreEqualToAnything : KotlinTypeChecker {
}
interface NewKotlinTypeChecker : KotlinTypeChecker {
val kotlinTypeRefiner: KotlinTypeRefiner
fun transformToNewType(type: UnwrappedType): UnwrappedType
companion object {
val Default = NewKotlinTypeCheckerImpl()
val Default = NewKotlinTypeCheckerImpl(KotlinTypeRefiner.Default)
}
}
class NewKotlinTypeCheckerImpl() : NewKotlinTypeChecker {
class NewKotlinTypeCheckerImpl(override val kotlinTypeRefiner: KotlinTypeRefiner) : NewKotlinTypeChecker {
override fun isSubtypeOf(subtype: KotlinType, supertype: KotlinType): Boolean =
ClassicTypeCheckerContext(true).isSubtypeOf(subtype.unwrap(), supertype.unwrap()) // todo fix flag errorTypeEqualsToAnything
ClassicTypeCheckerContext(true, kotlinTypeRefiner = kotlinTypeRefiner)
.isSubtypeOf(subtype.unwrap(), supertype.unwrap()) // todo fix flag errorTypeEqualsToAnything
override fun equalTypes(a: KotlinType, b: KotlinType): Boolean =
ClassicTypeCheckerContext(false).equalTypes(a.unwrap(), b.unwrap())
ClassicTypeCheckerContext(false, kotlinTypeRefiner = kotlinTypeRefiner).equalTypes(a.unwrap(), b.unwrap())
fun ClassicTypeCheckerContext.equalTypes(a: UnwrappedType, b: UnwrappedType): Boolean {
return AbstractTypeChecker.equalTypes(this as AbstractTypeCheckerContext, a, b)
@@ -25,6 +25,10 @@ abstract class AbstractTypeCheckerContext : TypeSystemContext {
return type
}
open fun refineType(type: KotlinTypeMarker): KotlinTypeMarker {
return type
}
abstract val isErrorTypeEqualsToAnything: Boolean
protected var argumentsDepth = 0
@@ -157,19 +161,21 @@ object AbstractTypeChecker {
fun isSubtypeOf(context: AbstractTypeCheckerContext, subType: KotlinTypeMarker, superType: KotlinTypeMarker): Boolean {
if (subType === superType) return true
return context.completeIsSubTypeOf(context.prepareType(subType), context.prepareType(superType))
return with(context) { completeIsSubTypeOf(prepareType(refineType(subType)), prepareType(refineType(superType))) }
}
fun equalTypes(context: AbstractTypeCheckerContext, a: KotlinTypeMarker, b: KotlinTypeMarker): Boolean = with(context) {
if (a === b) return true
if (isCommonDenotableType(a) && isCommonDenotableType(b)) {
val simpleA = a.lowerBoundIfFlexible()
if (!areEqualTypeConstructors(a.typeConstructor(), b.typeConstructor())) return false
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 (a.hasFlexibleNullability() || b.hasFlexibleNullability()) return true
if (refinedA.hasFlexibleNullability() || refinedB.hasFlexibleNullability()) return true
return simpleA.isMarkedNullable() == b.lowerBoundIfFlexible().isMarkedNullable()
return simpleA.isMarkedNullable() == refinedB.lowerBoundIfFlexible().isMarkedNullable()
}
}