[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.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.types.*
|
||||
import org.jetbrains.kotlin.types.checker.CaptureStatus
|
||||
import org.jetbrains.kotlin.types.checker.NewCapturedType
|
||||
import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker
|
||||
import org.jetbrains.kotlin.types.typeUtil.contains
|
||||
import org.jetbrains.kotlin.types.typeUtil.isNothing
|
||||
import org.jetbrains.kotlin.types.typeUtil.isNullableAny
|
||||
import java.util.*
|
||||
|
||||
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) {
|
||||
val initialConstraint = InitialConstraint(lowerType, upperType, ConstraintKind.UPPER, position)
|
||||
val initialConstraint = InitialConstraint(lowerType, upperType, UPPER, position)
|
||||
val incorporationPosition = IncorporationConstraintPosition(position, initialConstraint)
|
||||
c.addInitialConstraint(initialConstraint)
|
||||
updateAllowedTypeDepth(c, lowerType)
|
||||
@@ -66,6 +70,8 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val
|
||||
|
||||
while (possibleNewConstraints.isNotEmpty()) {
|
||||
val (typeVariable, constraint) = possibleNewConstraints.pop()
|
||||
if (c.shouldWeSkipConstraint(typeVariable, constraint)) continue
|
||||
|
||||
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
|
||||
@@ -93,6 +99,26 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val
|
||||
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 inner class TypeCheckerContext(
|
||||
@@ -100,7 +126,7 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val
|
||||
val position: IncorporationConstraintPosition,
|
||||
val baseLowerType: UnwrappedType,
|
||||
val baseUpperType: UnwrappedType,
|
||||
val possibleNewConstraints: MutableList<Pair<NewTypeVariable, Constraint>> = ArrayList()
|
||||
val possibleNewConstraints: MutableList<Pair<NewTypeVariable, Constraint>>
|
||||
) : TypeCheckerContextForConstraintSystem(), ConstraintIncorporator.Context {
|
||||
|
||||
fun runIsSubtypeOf(lowerType: UnwrappedType, upperType: UnwrappedType) {
|
||||
@@ -115,10 +141,10 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val
|
||||
// from TypeCheckerContextForConstraintSystem
|
||||
override fun isMyTypeVariable(type: SimpleType): Boolean = c.allTypeVariables.containsKey(type.constructor)
|
||||
override fun addUpperConstraint(typeVariable: TypeConstructor, superType: UnwrappedType) =
|
||||
addConstraint(typeVariable, superType, ConstraintKind.UPPER)
|
||||
addConstraint(typeVariable, superType, UPPER)
|
||||
|
||||
override fun addLowerConstraint(typeVariable: TypeConstructor, subType: UnwrappedType) =
|
||||
addConstraint(typeVariable, subType, ConstraintKind.LOWER)
|
||||
addConstraint(typeVariable, subType, LOWER)
|
||||
|
||||
private fun isCapturedTypeFromSubtyping(type: UnwrappedType) =
|
||||
when ((type as? NewCapturedType)?.captureStatus) {
|
||||
@@ -135,14 +161,14 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val
|
||||
var targetType = type
|
||||
if (type.contains(this::isCapturedTypeFromSubtyping)) {
|
||||
// TypeVariable <: type -> if TypeVariable <: subType => TypeVariable <: type
|
||||
if (kind == ConstraintKind.UPPER) {
|
||||
if (kind == UPPER) {
|
||||
val subType = typeApproximator.approximateToSubType(type, TypeApproximatorConfiguration.SubtypeCapturedTypesApproximation)
|
||||
if (subType != null && !KotlinBuiltIns.isNothingOrNullableNothing(subType)) {
|
||||
targetType = subType
|
||||
}
|
||||
}
|
||||
|
||||
if (kind == ConstraintKind.LOWER) {
|
||||
if (kind == LOWER) {
|
||||
val superType = typeApproximator.approximateToSuperType(type, TypeApproximatorConfiguration.SubtypeCapturedTypesApproximation)
|
||||
if (superType != null && !KotlinBuiltIns.isAnyOrNullableAny(superType)) { // todo rethink error reporting for Any cases
|
||||
targetType = superType
|
||||
@@ -155,10 +181,7 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val
|
||||
}
|
||||
}
|
||||
|
||||
if (!c.isAllowedType(targetType)) return
|
||||
|
||||
val newConstraint = Constraint(kind, targetType, position)
|
||||
possibleNewConstraints.add(typeVariable to newConstraint)
|
||||
possibleNewConstraints.add(typeVariable to Constraint(kind, targetType, position))
|
||||
}
|
||||
|
||||
// from ConstraintIncorporator.Context
|
||||
|
||||
Reference in New Issue
Block a user