[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) { when (diagnostic.javaClass) {
NewConstraintError::class.java -> { NewConstraintError::class.java -> {
val constraintError = diagnostic as NewConstraintError 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 val expression = it.argument.psiExpression ?: return
if (reportConstantTypeMismatch(constraintError, expression)) return if (reportConstantTypeMismatch(constraintError, expression)) return
trace.report(Errors.TYPE_MISMATCH.on(expression, constraintError.upperType, constraintError.lowerType)) 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 val typeArgumentReference = (it.typeArgument as SimpleTypeArgumentImpl).typeReference
trace.report(UPPER_BOUND_VIOLATED.on(typeArgumentReference, constraintError.upperType, constraintError.lowerType)) trace.report(UPPER_BOUND_VIOLATED.on(typeArgumentReference, constraintError.upperType, constraintError.lowerType))
} }
@@ -16,8 +16,6 @@
package org.jetbrains.kotlin.resolve.calls.inference.components 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.resolve.calls.inference.model.*
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.CaptureStatus import org.jetbrains.kotlin.types.checker.CaptureStatus
@@ -40,26 +38,26 @@ class ConstraintIncorporator(val typeApproximator: TypeApproximator) {
fun getConstraintsForVariable(typeVariable: NewTypeVariable): Collection<Constraint> 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 // \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 // we shouldn't incorporate recursive constraint -- It is too dangerous
if (constraint.type.contains { it.constructor == typeVariable.freshTypeConstructor }) return if (constraint.type.contains { it.constructor == typeVariable.freshTypeConstructor }) return
directWithVariable(c, typeVariable, constraint, position) directWithVariable(c, typeVariable, constraint)
otherInsideMyConstraint(c, typeVariable, constraint, position) otherInsideMyConstraint(c, typeVariable, constraint)
insideOtherConstraint(c, typeVariable, constraint, position) insideOtherConstraint(c, typeVariable, constraint)
} }
// A <:(=) \alpha <:(=) B => A <: B // 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 // \alpha <: constraint.type
if (constraint.kind != ConstraintKind.LOWER) { if (constraint.kind != ConstraintKind.LOWER) {
c.getConstraintsForVariable(typeVariable).forEach { c.getConstraintsForVariable(typeVariable).forEach {
if (it.kind != ConstraintKind.UPPER) { 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) { if (constraint.kind != ConstraintKind.UPPER) {
c.getConstraintsForVariable(typeVariable).forEach { c.getConstraintsForVariable(typeVariable).forEach {
if (it.kind != ConstraintKind.LOWER) { 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> // \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>() val otherInMyConstraint = SmartSet.create<NewTypeVariable>()
constraint.type.contains { constraint.type.contains {
otherInMyConstraint.addIfNotNull(c.getTypeVariable(it.constructor)) otherInMyConstraint.addIfNotNull(c.getTypeVariable(it.constructor))
@@ -86,19 +84,19 @@ class ConstraintIncorporator(val typeApproximator: TypeApproximator) {
// to avoid ConcurrentModificationException // to avoid ConcurrentModificationException
val otherConstraints = ArrayList(c.getConstraintsForVariable(otherTypeVariable)) val otherConstraints = ArrayList(c.getConstraintsForVariable(otherTypeVariable))
for (otherConstraint in otherConstraints) { 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> // \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) { for (typeVariableWithConstraint in c.allTypeVariablesWithConstraints) {
val constraintsWhichConstraintMyVariable = typeVariableWithConstraint.constraints.filter { val constraintsWhichConstraintMyVariable = typeVariableWithConstraint.constraints.filter {
it.type.contains { it.constructor == typeVariable.freshTypeConstructor } it.type.contains { it.constructor == typeVariable.freshTypeConstructor }
} }
constraintsWhichConstraintMyVariable.forEach { 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, targetVariable: NewTypeVariable,
baseConstraint: Constraint, baseConstraint: Constraint,
otherVariable: NewTypeVariable, otherVariable: NewTypeVariable,
otherConstraint: Constraint, otherConstraint: Constraint
position: IncorporationConstraintPosition
) { ) {
val typeForApproximation = when (otherConstraint.kind) { val typeForApproximation = when (otherConstraint.kind) {
ConstraintKind.EQUALITY -> { ConstraintKind.EQUALITY -> {
@@ -134,10 +131,10 @@ class ConstraintIncorporator(val typeApproximator: TypeApproximator) {
} }
if (baseConstraint.kind != ConstraintKind.UPPER) { 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) { 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) { 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, lowerType)
updateAllowedTypeDepth(c, upperType) updateAllowedTypeDepth(c, upperType)
addSubTypeConstraintAndIncorporateIt(c, lowerType, upperType, position) addSubTypeConstraintAndIncorporateIt(c, lowerType, upperType, incorporationPosition)
} }
fun addInitialEqualityConstraint(c: Context, a: UnwrappedType, b: UnwrappedType, position: ConstraintPosition) { 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, a)
updateAllowedTypeDepth(c, b) updateAllowedTypeDepth(c, b)
addSubTypeConstraintAndIncorporateIt(c, a, b, position) addSubTypeConstraintAndIncorporateIt(c, a, b, incorporationPosition)
addSubTypeConstraintAndIncorporateIt(c, b, a, position) addSubTypeConstraintAndIncorporateIt(c, b, a, incorporationPosition)
} }
private fun addSubTypeConstraintAndIncorporateIt(c: Context, lowerType: UnwrappedType, upperType: UnwrappedType, position: ConstraintPosition) { private fun addSubTypeConstraintAndIncorporateIt(c: Context, lowerType: UnwrappedType, upperType: UnwrappedType, incorporatePosition: IncorporationConstraintPosition) {
val incorporatePosition = IncorporationConstraintPosition(position)
val possibleNewConstraints = Stack<Pair<NewTypeVariable, Constraint>>() 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) typeCheckerContext.runIsSubtypeOf(lowerType, upperType)
while (possibleNewConstraints.isNotEmpty()) { 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 // it is important, that we add constraint here(not inside TypeCheckerContext), because inside incorporation we read constraints
constraints.addConstraint(constraint)?.let { 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( private inner class TypeCheckerContext(
val c: Context, val c: Context,
val position: ConstraintPosition, 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>> = ArrayList()
@@ -159,7 +162,7 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val
} }
// from ConstraintIncorporator.Context // 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)) { if (c.isAllowedType(lowerType) && c.isAllowedType(upperType)) {
runIsSubtypeOf(lowerType, upperType) runIsSubtypeOf(lowerType, upperType)
} }
@@ -40,15 +40,15 @@ class FixVariableConstraintPosition(val variable: NewTypeVariable) : ConstraintP
override fun toString() = "Fix variable $variable" override fun toString() = "Fix variable $variable"
} }
class IncorporationConstraintPosition(val from: ConstraintPosition) : ConstraintPosition() { class IncorporationConstraintPosition(val from: ConstraintPosition, val initialConstraint: InitialConstraint) : ConstraintPosition() {
override fun toString() = "Incorporate $from" override fun toString() = "Incorporate $initialConstraint from position $from"
} }
@Deprecated("Should be used only in SimpleConstraintSystemImpl") @Deprecated("Should be used only in SimpleConstraintSystemImpl")
object SimpleConstraintSystemConstraintPosition : ConstraintPosition() 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) { KotlinCallDiagnostic(ResolutionCandidateApplicability.INAPPLICABLE) {
override fun report(reporter: DiagnosticReporter) = reporter.constraintError(this) override fun report(reporter: DiagnosticReporter) = reporter.constraintError(this)
} }
@@ -78,7 +78,7 @@ enum class ConstraintKind {
class Constraint( class Constraint(
val kind: ConstraintKind, val kind: ConstraintKind,
val type: UnwrappedType, // flexible types here is allowed val type: UnwrappedType, // flexible types here is allowed
val position: ConstraintPosition, val position: IncorporationConstraintPosition,
val typeHashCode: Int = type.hashCode() val typeHashCode: Int = type.hashCode()
) { ) {
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {