[NI] Improve type inference for T vs Captured(in Smt)

If we has Inv<T> <: Inv<Captured(in Foo)> then we should get:
- T <: Captured(in Foo)
- Captured(in Foo) <: T

Before this commit we got: T <: Foo instead first constraint.
This commit is contained in:
Stanislav Erokhin
2017-06-09 15:59:12 +03:00
committed by Mikhail Zarechenskiy
parent 91241a34d1
commit 915ac32bfb
3 changed files with 17 additions and 9 deletions
@@ -29,8 +29,11 @@ abstract class TypeCheckerContextForConstraintSystem : TypeCheckerContext(errorT
abstract fun addUpperConstraint(typeVariable: TypeConstructor, superType: UnwrappedType)
abstract fun addLowerConstraint(typeVariable: TypeConstructor, subType: UnwrappedType)
override fun shouldCheckOnlyLowerBoundForCapturedType(subType: SimpleType, superType: NewCapturedType) =
subType.contains { it.anyBound(this::isMyTypeVariable) }
override fun getLowerCapturedTypePolicy(subType: SimpleType, superType: NewCapturedType) = when {
isMyTypeVariable(subType) -> LowerCapturedTypePolicy.SKIP_LOWER
subType.contains { it.anyBound(this::isMyTypeVariable) } -> LowerCapturedTypePolicy.CHECK_ONLY_LOWER
else -> LowerCapturedTypePolicy.CHECK_SUBTYPE_AND_LOWER
}
/**
* todo: possible we should override this method, because otherwise OR in subtyping transformed to AND in constraint system
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.CapturedType
import org.jetbrains.kotlin.resolve.calls.inference.CapturedTypeConstructor
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.TypeCheckerContext.LowerCapturedTypePolicy.*
import org.jetbrains.kotlin.types.checker.TypeCheckerContext.SeveralSupertypesWithSameConstructorPolicy.*
import org.jetbrains.kotlin.types.checker.TypeCheckerContext.SupertypesPolicy
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
@@ -160,12 +161,10 @@ object NewKotlinTypeChecker : KotlinTypeChecker {
}
if (superType is NewCapturedType && superType.lowerType != null) {
val subtypeOfLowerType = isSubtypeOf(subType, superType.lowerType)
if (shouldCheckOnlyLowerBoundForCapturedType(subType, superType)) {
return subtypeOfLowerType
}
else if (subtypeOfLowerType) {
return true
when (getLowerCapturedTypePolicy(subType, superType)) {
CHECK_ONLY_LOWER -> return isSubtypeOf(subType, superType.lowerType)
CHECK_SUBTYPE_AND_LOWER -> if(isSubtypeOf(subType, superType.lowerType)) return true
SKIP_LOWER -> { /*do nothing*/ }
}
}
@@ -33,7 +33,7 @@ open class TypeCheckerContext(val errorTypeEqualsToAnything: Boolean, val allowe
return a == b
}
open fun shouldCheckOnlyLowerBoundForCapturedType(subType: SimpleType, superType: NewCapturedType): Boolean = false
open fun getLowerCapturedTypePolicy(subType: SimpleType, superType: NewCapturedType) = LowerCapturedTypePolicy.CHECK_SUBTYPE_AND_LOWER
open val sameConstructorPolicy get() = SeveralSupertypesWithSameConstructorPolicy.INTERSECT_ARGUMENTS_AND_CHECK_AGAIN
internal inline fun <T> runWithArgumentsSettings(subArgument: UnwrappedType, f: TypeCheckerContext.() -> T): T {
@@ -127,5 +127,11 @@ open class TypeCheckerContext(val errorTypeEqualsToAnything: Boolean, val allowe
INTERSECT_ARGUMENTS_AND_CHECK_AGAIN
}
enum class LowerCapturedTypePolicy {
CHECK_ONLY_LOWER,
CHECK_SUBTYPE_AND_LOWER,
SKIP_LOWER
}
val UnwrappedType.isAllowedTypeVariable: Boolean get() = allowedTypeVariable && constructor is NewTypeVariableConstructor
}