[NI] Add initial constraint to IncorporationConstraintPosition

This commit is contained in:
Stanislav Erokhin
2017-05-04 00:22:45 +03:00
parent c767545d4c
commit cb494c46d7
5 changed files with 36 additions and 35 deletions
@@ -150,12 +150,13 @@ class DiagnosticReporterByTrackingStrategy(
when (diagnostic.javaClass) {
NewConstraintError::class.java -> {
val constraintError = diagnostic as NewConstraintError
(constraintError.position as? ArgumentConstraintPosition)?.let {
val position = constraintError.position.from
(position as? ArgumentConstraintPosition)?.let {
val expression = it.argument.psiExpression ?: return
if (reportConstantTypeMismatch(constraintError, expression)) return
trace.report(Errors.TYPE_MISMATCH.on(expression, constraintError.upperType, constraintError.lowerType))
}
(constraintError.position as? ExplicitTypeParameterConstraintPosition)?.let {
(position as? ExplicitTypeParameterConstraintPosition)?.let {
val typeArgumentReference = (it.typeArgument as SimpleTypeArgumentImpl).typeReference
trace.report(UPPER_BOUND_VIOLATED.on(typeArgumentReference, constraintError.upperType, constraintError.lowerType))
}
@@ -16,8 +16,6 @@
package org.jetbrains.kotlin.resolve.calls.inference.components
import org.jetbrains.kotlin.types.TypeApproximator
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration
import org.jetbrains.kotlin.resolve.calls.inference.model.*
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.CaptureStatus
@@ -40,26 +38,26 @@ class ConstraintIncorporator(val typeApproximator: TypeApproximator) {
fun getConstraintsForVariable(typeVariable: NewTypeVariable): Collection<Constraint>
fun addNewIncorporatedConstraint(lowerType: UnwrappedType, upperType: UnwrappedType, position: IncorporationConstraintPosition)
fun addNewIncorporatedConstraint(lowerType: UnwrappedType, upperType: UnwrappedType)
}
// \alpha is typeVariable, \beta -- other type variable registered in ConstraintStorage
fun incorporate(c: Context, typeVariable: NewTypeVariable, constraint: Constraint, position: IncorporationConstraintPosition) {
fun incorporate(c: Context, typeVariable: NewTypeVariable, constraint: Constraint) {
// we shouldn't incorporate recursive constraint -- It is too dangerous
if (constraint.type.contains { it.constructor == typeVariable.freshTypeConstructor }) return
directWithVariable(c, typeVariable, constraint, position)
otherInsideMyConstraint(c, typeVariable, constraint, position)
insideOtherConstraint(c, typeVariable, constraint, position)
directWithVariable(c, typeVariable, constraint)
otherInsideMyConstraint(c, typeVariable, constraint)
insideOtherConstraint(c, typeVariable, constraint)
}
// A <:(=) \alpha <:(=) B => A <: B
private fun directWithVariable(c: Context, typeVariable: NewTypeVariable, constraint: Constraint, position: IncorporationConstraintPosition) {
private fun directWithVariable(c: Context, typeVariable: NewTypeVariable, constraint: Constraint) {
// \alpha <: constraint.type
if (constraint.kind != ConstraintKind.LOWER) {
c.getConstraintsForVariable(typeVariable).forEach {
if (it.kind != ConstraintKind.UPPER) {
c.addNewIncorporatedConstraint(it.type, constraint.type, position)
c.addNewIncorporatedConstraint(it.type, constraint.type)
}
}
}
@@ -68,14 +66,14 @@ class ConstraintIncorporator(val typeApproximator: TypeApproximator) {
if (constraint.kind != ConstraintKind.UPPER) {
c.getConstraintsForVariable(typeVariable).forEach {
if (it.kind != ConstraintKind.LOWER) {
c.addNewIncorporatedConstraint(constraint.type, it.type, position)
c.addNewIncorporatedConstraint(constraint.type, it.type)
}
}
}
}
// \alpha <: Inv<\beta>, \beta <: Number => \alpha <: Inv<out Number>
private fun otherInsideMyConstraint(c: Context, typeVariable: NewTypeVariable, constraint: Constraint, position: IncorporationConstraintPosition) {
private fun otherInsideMyConstraint(c: Context, typeVariable: NewTypeVariable, constraint: Constraint) {
val otherInMyConstraint = SmartSet.create<NewTypeVariable>()
constraint.type.contains {
otherInMyConstraint.addIfNotNull(c.getTypeVariable(it.constructor))
@@ -86,19 +84,19 @@ class ConstraintIncorporator(val typeApproximator: TypeApproximator) {
// to avoid ConcurrentModificationException
val otherConstraints = ArrayList(c.getConstraintsForVariable(otherTypeVariable))
for (otherConstraint in otherConstraints) {
generateNewConstraint(c, typeVariable, constraint, otherTypeVariable, otherConstraint, position)
generateNewConstraint(c, typeVariable, constraint, otherTypeVariable, otherConstraint)
}
}
}
// \alpha <: Number, \beta <: Inv<\alpha> => \beta <: Inv<out Number>
private fun insideOtherConstraint(c: Context, typeVariable: NewTypeVariable, constraint: Constraint, position: IncorporationConstraintPosition) {
private fun insideOtherConstraint(c: Context, typeVariable: NewTypeVariable, constraint: Constraint) {
for (typeVariableWithConstraint in c.allTypeVariablesWithConstraints) {
val constraintsWhichConstraintMyVariable = typeVariableWithConstraint.constraints.filter {
it.type.contains { it.constructor == typeVariable.freshTypeConstructor }
}
constraintsWhichConstraintMyVariable.forEach {
generateNewConstraint(c, typeVariableWithConstraint.typeVariable, it, typeVariable, constraint, position)
generateNewConstraint(c, typeVariableWithConstraint.typeVariable, it, typeVariable, constraint)
}
}
}
@@ -108,8 +106,7 @@ class ConstraintIncorporator(val typeApproximator: TypeApproximator) {
targetVariable: NewTypeVariable,
baseConstraint: Constraint,
otherVariable: NewTypeVariable,
otherConstraint: Constraint,
position: IncorporationConstraintPosition
otherConstraint: Constraint
) {
val typeForApproximation = when (otherConstraint.kind) {
ConstraintKind.EQUALITY -> {
@@ -134,10 +131,10 @@ class ConstraintIncorporator(val typeApproximator: TypeApproximator) {
}
if (baseConstraint.kind != ConstraintKind.UPPER) {
c.addNewIncorporatedConstraint(approximateCapturedTypes(typeForApproximation, toSuper = false), targetVariable.defaultType, position)
c.addNewIncorporatedConstraint(approximateCapturedTypes(typeForApproximation, toSuper = false), targetVariable.defaultType)
}
if (baseConstraint.kind != ConstraintKind.LOWER) {
c.addNewIncorporatedConstraint(targetVariable.defaultType, approximateCapturedTypes(typeForApproximation, toSuper = true), position)
c.addNewIncorporatedConstraint(targetVariable.defaultType, approximateCapturedTypes(typeForApproximation, toSuper = true))
}
}
@@ -40,25 +40,28 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val
}
fun addInitialSubtypeConstraint(c: Context, lowerType: UnwrappedType, upperType: UnwrappedType, position: ConstraintPosition) {
c.addInitialConstraint(InitialConstraint(lowerType, upperType, ConstraintKind.UPPER, position))
val initialConstraint = InitialConstraint(lowerType, upperType, ConstraintKind.UPPER, position)
val incorporationPosition = IncorporationConstraintPosition(position, initialConstraint)
c.addInitialConstraint(initialConstraint)
updateAllowedTypeDepth(c, lowerType)
updateAllowedTypeDepth(c, upperType)
addSubTypeConstraintAndIncorporateIt(c, lowerType, upperType, position)
addSubTypeConstraintAndIncorporateIt(c, lowerType, upperType, incorporationPosition)
}
fun addInitialEqualityConstraint(c: Context, a: UnwrappedType, b: UnwrappedType, position: ConstraintPosition) {
c.addInitialConstraint(InitialConstraint(a, b, ConstraintKind.EQUALITY, position))
val initialConstraint = InitialConstraint(a, b, ConstraintKind.EQUALITY, position)
val incorporationPosition = IncorporationConstraintPosition(position, initialConstraint)
c.addInitialConstraint(initialConstraint)
updateAllowedTypeDepth(c, a)
updateAllowedTypeDepth(c, b)
addSubTypeConstraintAndIncorporateIt(c, a, b, position)
addSubTypeConstraintAndIncorporateIt(c, b, a, position)
addSubTypeConstraintAndIncorporateIt(c, a, b, incorporationPosition)
addSubTypeConstraintAndIncorporateIt(c, b, a, incorporationPosition)
}
private fun addSubTypeConstraintAndIncorporateIt(c: Context, lowerType: UnwrappedType, upperType: UnwrappedType, position: ConstraintPosition) {
val incorporatePosition = IncorporationConstraintPosition(position)
private fun addSubTypeConstraintAndIncorporateIt(c: Context, lowerType: UnwrappedType, upperType: UnwrappedType, incorporatePosition: IncorporationConstraintPosition) {
val possibleNewConstraints = Stack<Pair<NewTypeVariable, Constraint>>()
val typeCheckerContext = TypeCheckerContext(c, position, lowerType, upperType, possibleNewConstraints)
val typeCheckerContext = TypeCheckerContext(c, incorporatePosition, lowerType, upperType, possibleNewConstraints)
typeCheckerContext.runIsSubtypeOf(lowerType, upperType)
while (possibleNewConstraints.isNotEmpty()) {
@@ -67,7 +70,7 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val
// it is important, that we add constraint here(not inside TypeCheckerContext), because inside incorporation we read constraints
constraints.addConstraint(constraint)?.let {
constraintIncorporator.incorporate(typeCheckerContext, typeVariable, it, incorporatePosition)
constraintIncorporator.incorporate(typeCheckerContext, typeVariable, it)
}
}
}
@@ -94,7 +97,7 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val
private inner class TypeCheckerContext(
val c: Context,
val position: ConstraintPosition,
val position: IncorporationConstraintPosition,
val baseLowerType: UnwrappedType,
val baseUpperType: UnwrappedType,
val possibleNewConstraints: MutableList<Pair<NewTypeVariable, Constraint>> = ArrayList()
@@ -159,7 +162,7 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val
}
// from ConstraintIncorporator.Context
override fun addNewIncorporatedConstraint(lowerType: UnwrappedType, upperType: UnwrappedType, position: IncorporationConstraintPosition) {
override fun addNewIncorporatedConstraint(lowerType: UnwrappedType, upperType: UnwrappedType) {
if (c.isAllowedType(lowerType) && c.isAllowedType(upperType)) {
runIsSubtypeOf(lowerType, upperType)
}
@@ -40,15 +40,15 @@ class FixVariableConstraintPosition(val variable: NewTypeVariable) : ConstraintP
override fun toString() = "Fix variable $variable"
}
class IncorporationConstraintPosition(val from: ConstraintPosition) : ConstraintPosition() {
override fun toString() = "Incorporate $from"
class IncorporationConstraintPosition(val from: ConstraintPosition, val initialConstraint: InitialConstraint) : ConstraintPosition() {
override fun toString() = "Incorporate $initialConstraint from position $from"
}
@Deprecated("Should be used only in SimpleConstraintSystemImpl")
object SimpleConstraintSystemConstraintPosition : ConstraintPosition()
class NewConstraintError(val lowerType: UnwrappedType, val upperType: UnwrappedType, val position: ConstraintPosition):
class NewConstraintError(val lowerType: UnwrappedType, val upperType: UnwrappedType, val position: IncorporationConstraintPosition):
KotlinCallDiagnostic(ResolutionCandidateApplicability.INAPPLICABLE) {
override fun report(reporter: DiagnosticReporter) = reporter.constraintError(this)
}
@@ -78,7 +78,7 @@ enum class ConstraintKind {
class Constraint(
val kind: ConstraintKind,
val type: UnwrappedType, // flexible types here is allowed
val position: ConstraintPosition,
val position: IncorporationConstraintPosition,
val typeHashCode: Int = type.hashCode()
) {
override fun equals(other: Any?): Boolean {