[NI] Do not add useless constraints to constraint system
Skipped constraints: - T <: Any, T >: Nothing - T <: T, T <: T?, T >: T, T <: T!, T! <: T
This commit is contained in:
committed by
Mikhail Zarechenskiy
parent
3a25405088
commit
89ac3bd5cf
+33
-10
@@ -18,12 +18,16 @@ package org.jetbrains.kotlin.resolve.calls.inference.components
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.*
|
import org.jetbrains.kotlin.resolve.calls.inference.model.*
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind.LOWER
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind.UPPER
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
|
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
|
||||||
import org.jetbrains.kotlin.types.*
|
import org.jetbrains.kotlin.types.*
|
||||||
import org.jetbrains.kotlin.types.checker.CaptureStatus
|
import org.jetbrains.kotlin.types.checker.CaptureStatus
|
||||||
import org.jetbrains.kotlin.types.checker.NewCapturedType
|
import org.jetbrains.kotlin.types.checker.NewCapturedType
|
||||||
import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker
|
import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker
|
||||||
import org.jetbrains.kotlin.types.typeUtil.contains
|
import org.jetbrains.kotlin.types.typeUtil.contains
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.isNothing
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.isNullableAny
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val typeApproximator: TypeApproximator) {
|
class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val typeApproximator: TypeApproximator) {
|
||||||
@@ -40,7 +44,7 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun addInitialSubtypeConstraint(c: Context, lowerType: UnwrappedType, upperType: UnwrappedType, position: ConstraintPosition) {
|
fun addInitialSubtypeConstraint(c: Context, lowerType: UnwrappedType, upperType: UnwrappedType, position: ConstraintPosition) {
|
||||||
val initialConstraint = InitialConstraint(lowerType, upperType, ConstraintKind.UPPER, position)
|
val initialConstraint = InitialConstraint(lowerType, upperType, UPPER, position)
|
||||||
val incorporationPosition = IncorporationConstraintPosition(position, initialConstraint)
|
val incorporationPosition = IncorporationConstraintPosition(position, initialConstraint)
|
||||||
c.addInitialConstraint(initialConstraint)
|
c.addInitialConstraint(initialConstraint)
|
||||||
updateAllowedTypeDepth(c, lowerType)
|
updateAllowedTypeDepth(c, lowerType)
|
||||||
@@ -66,6 +70,8 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val
|
|||||||
|
|
||||||
while (possibleNewConstraints.isNotEmpty()) {
|
while (possibleNewConstraints.isNotEmpty()) {
|
||||||
val (typeVariable, constraint) = possibleNewConstraints.pop()
|
val (typeVariable, constraint) = possibleNewConstraints.pop()
|
||||||
|
if (c.shouldWeSkipConstraint(typeVariable, constraint)) continue
|
||||||
|
|
||||||
val constraints = c.notFixedTypeVariables[typeVariable.freshTypeConstructor] ?: typeCheckerContext.fixedTypeVariable(typeVariable)
|
val constraints = c.notFixedTypeVariables[typeVariable.freshTypeConstructor] ?: typeCheckerContext.fixedTypeVariable(typeVariable)
|
||||||
|
|
||||||
// it is important, that we add constraint here(not inside TypeCheckerContext), because inside incorporation we read constraints
|
// it is important, that we add constraint here(not inside TypeCheckerContext), because inside incorporation we read constraints
|
||||||
@@ -93,6 +99,26 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val
|
|||||||
return maxInArguments + 1
|
return maxInArguments + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun Context.shouldWeSkipConstraint(typeVariable: NewTypeVariable, constraint: Constraint): Boolean {
|
||||||
|
assert(constraint.kind != ConstraintKind.EQUALITY)
|
||||||
|
|
||||||
|
val constraintType = constraint.type
|
||||||
|
if (!isAllowedType(constraintType)) return true
|
||||||
|
|
||||||
|
if (constraintType.constructor == typeVariable.freshTypeConstructor) {
|
||||||
|
if (constraintType.lowerIfFlexible().isMarkedNullable && constraint.kind == LOWER) return false // T? <: T
|
||||||
|
|
||||||
|
return true // T <: T(?!)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (constraintType is SimpleType) {
|
||||||
|
if (constraint.kind == UPPER && constraintType.isNullableAny()) return true // T <: Any?
|
||||||
|
if (constraint.kind == LOWER && constraintType.isNothing()) return true // T >: Nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
private fun Context.isAllowedType(type: UnwrappedType) = type.typeDepth() <= maxTypeDepthFromInitialConstraints + ALLOWED_DEPTH_DELTA_FOR_INCORPORATION
|
private fun Context.isAllowedType(type: UnwrappedType) = type.typeDepth() <= maxTypeDepthFromInitialConstraints + ALLOWED_DEPTH_DELTA_FOR_INCORPORATION
|
||||||
|
|
||||||
private inner class TypeCheckerContext(
|
private inner class TypeCheckerContext(
|
||||||
@@ -100,7 +126,7 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val
|
|||||||
val position: IncorporationConstraintPosition,
|
val position: IncorporationConstraintPosition,
|
||||||
val baseLowerType: UnwrappedType,
|
val baseLowerType: UnwrappedType,
|
||||||
val baseUpperType: UnwrappedType,
|
val baseUpperType: UnwrappedType,
|
||||||
val possibleNewConstraints: MutableList<Pair<NewTypeVariable, Constraint>> = ArrayList()
|
val possibleNewConstraints: MutableList<Pair<NewTypeVariable, Constraint>>
|
||||||
) : TypeCheckerContextForConstraintSystem(), ConstraintIncorporator.Context {
|
) : TypeCheckerContextForConstraintSystem(), ConstraintIncorporator.Context {
|
||||||
|
|
||||||
fun runIsSubtypeOf(lowerType: UnwrappedType, upperType: UnwrappedType) {
|
fun runIsSubtypeOf(lowerType: UnwrappedType, upperType: UnwrappedType) {
|
||||||
@@ -115,10 +141,10 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val
|
|||||||
// from TypeCheckerContextForConstraintSystem
|
// from TypeCheckerContextForConstraintSystem
|
||||||
override fun isMyTypeVariable(type: SimpleType): Boolean = c.allTypeVariables.containsKey(type.constructor)
|
override fun isMyTypeVariable(type: SimpleType): Boolean = c.allTypeVariables.containsKey(type.constructor)
|
||||||
override fun addUpperConstraint(typeVariable: TypeConstructor, superType: UnwrappedType) =
|
override fun addUpperConstraint(typeVariable: TypeConstructor, superType: UnwrappedType) =
|
||||||
addConstraint(typeVariable, superType, ConstraintKind.UPPER)
|
addConstraint(typeVariable, superType, UPPER)
|
||||||
|
|
||||||
override fun addLowerConstraint(typeVariable: TypeConstructor, subType: UnwrappedType) =
|
override fun addLowerConstraint(typeVariable: TypeConstructor, subType: UnwrappedType) =
|
||||||
addConstraint(typeVariable, subType, ConstraintKind.LOWER)
|
addConstraint(typeVariable, subType, LOWER)
|
||||||
|
|
||||||
private fun isCapturedTypeFromSubtyping(type: UnwrappedType) =
|
private fun isCapturedTypeFromSubtyping(type: UnwrappedType) =
|
||||||
when ((type as? NewCapturedType)?.captureStatus) {
|
when ((type as? NewCapturedType)?.captureStatus) {
|
||||||
@@ -135,14 +161,14 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val
|
|||||||
var targetType = type
|
var targetType = type
|
||||||
if (type.contains(this::isCapturedTypeFromSubtyping)) {
|
if (type.contains(this::isCapturedTypeFromSubtyping)) {
|
||||||
// TypeVariable <: type -> if TypeVariable <: subType => TypeVariable <: type
|
// TypeVariable <: type -> if TypeVariable <: subType => TypeVariable <: type
|
||||||
if (kind == ConstraintKind.UPPER) {
|
if (kind == UPPER) {
|
||||||
val subType = typeApproximator.approximateToSubType(type, TypeApproximatorConfiguration.SubtypeCapturedTypesApproximation)
|
val subType = typeApproximator.approximateToSubType(type, TypeApproximatorConfiguration.SubtypeCapturedTypesApproximation)
|
||||||
if (subType != null && !KotlinBuiltIns.isNothingOrNullableNothing(subType)) {
|
if (subType != null && !KotlinBuiltIns.isNothingOrNullableNothing(subType)) {
|
||||||
targetType = subType
|
targetType = subType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kind == ConstraintKind.LOWER) {
|
if (kind == LOWER) {
|
||||||
val superType = typeApproximator.approximateToSuperType(type, TypeApproximatorConfiguration.SubtypeCapturedTypesApproximation)
|
val superType = typeApproximator.approximateToSuperType(type, TypeApproximatorConfiguration.SubtypeCapturedTypesApproximation)
|
||||||
if (superType != null && !KotlinBuiltIns.isAnyOrNullableAny(superType)) { // todo rethink error reporting for Any cases
|
if (superType != null && !KotlinBuiltIns.isAnyOrNullableAny(superType)) { // todo rethink error reporting for Any cases
|
||||||
targetType = superType
|
targetType = superType
|
||||||
@@ -155,10 +181,7 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!c.isAllowedType(targetType)) return
|
possibleNewConstraints.add(typeVariable to Constraint(kind, targetType, position))
|
||||||
|
|
||||||
val newConstraint = Constraint(kind, targetType, position)
|
|
||||||
possibleNewConstraints.add(typeVariable to newConstraint)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// from ConstraintIncorporator.Context
|
// from ConstraintIncorporator.Context
|
||||||
|
|||||||
Reference in New Issue
Block a user