Check initial constraints in constraint system status

This commit is contained in:
Svetlana Isakova
2015-06-30 14:41:02 +03:00
parent 4c4f99c356
commit 3b85ac90ba
9 changed files with 72 additions and 34 deletions
@@ -11,7 +11,7 @@ status:
-hasContradiction: true -hasContradiction: true
-hasErrorInConstrainingTypes: false -hasErrorInConstrainingTypes: false
-hasTypeConstructorMismatch: true -hasTypeConstructorMismatch: true
-hasTypeInferenceIncorporationError: false -hasTypeInferenceIncorporationError: true
-hasUnknownParameters: true -hasUnknownParameters: true
-hasViolatedUpperBound: false -hasViolatedUpperBound: false
-isSuccessful: false -isSuccessful: false
@@ -10,10 +10,10 @@ P := My<T>*
status: status:
-hasCannotCaptureTypesError: false -hasCannotCaptureTypesError: false
-hasConflictingConstraints: false -hasConflictingConstraints: false
-hasContradiction: false -hasContradiction: true
-hasErrorInConstrainingTypes: false -hasErrorInConstrainingTypes: false
-hasTypeConstructorMismatch: false -hasTypeConstructorMismatch: false
-hasTypeInferenceIncorporationError: false -hasTypeInferenceIncorporationError: true
-hasUnknownParameters: true -hasUnknownParameters: true
-hasViolatedUpperBound: false -hasViolatedUpperBound: false
-isSuccessful: false -isSuccessful: false
@@ -10,10 +10,10 @@ P := My<T>*
status: status:
-hasCannotCaptureTypesError: false -hasCannotCaptureTypesError: false
-hasConflictingConstraints: false -hasConflictingConstraints: false
-hasContradiction: false -hasContradiction: true
-hasErrorInConstrainingTypes: false -hasErrorInConstrainingTypes: false
-hasTypeConstructorMismatch: false -hasTypeConstructorMismatch: false
-hasTypeInferenceIncorporationError: false -hasTypeInferenceIncorporationError: true
-hasUnknownParameters: true -hasUnknownParameters: true
-hasViolatedUpperBound: false -hasViolatedUpperBound: false
-isSuccessful: false -isSuccessful: false
@@ -10,10 +10,10 @@ P := Two<T, P>*
status: status:
-hasCannotCaptureTypesError: false -hasCannotCaptureTypesError: false
-hasConflictingConstraints: false -hasConflictingConstraints: false
-hasContradiction: false -hasContradiction: true
-hasErrorInConstrainingTypes: false -hasErrorInConstrainingTypes: false
-hasTypeConstructorMismatch: false -hasTypeConstructorMismatch: false
-hasTypeInferenceIncorporationError: false -hasTypeInferenceIncorporationError: true
-hasUnknownParameters: true -hasUnknownParameters: true
-hasViolatedUpperBound: false -hasViolatedUpperBound: false
-isSuccessful: false -isSuccessful: false
@@ -10,10 +10,10 @@ P := My<T>*
status: status:
-hasCannotCaptureTypesError: false -hasCannotCaptureTypesError: false
-hasConflictingConstraints: false -hasConflictingConstraints: false
-hasContradiction: false -hasContradiction: true
-hasErrorInConstrainingTypes: false -hasErrorInConstrainingTypes: false
-hasTypeConstructorMismatch: false -hasTypeConstructorMismatch: false
-hasTypeInferenceIncorporationError: false -hasTypeInferenceIncorporationError: true
-hasUnknownParameters: true -hasUnknownParameters: true
-hasViolatedUpperBound: false -hasViolatedUpperBound: false
-isSuccessful: false -isSuccessful: false
@@ -10,10 +10,10 @@ P := My<T>*
status: status:
-hasCannotCaptureTypesError: false -hasCannotCaptureTypesError: false
-hasConflictingConstraints: false -hasConflictingConstraints: false
-hasContradiction: false -hasContradiction: true
-hasErrorInConstrainingTypes: false -hasErrorInConstrainingTypes: false
-hasTypeConstructorMismatch: false -hasTypeConstructorMismatch: false
-hasTypeInferenceIncorporationError: false -hasTypeInferenceIncorporationError: true
-hasUnknownParameters: true -hasUnknownParameters: true
-hasViolatedUpperBound: false -hasViolatedUpperBound: false
-isSuccessful: false -isSuccessful: false
@@ -4,6 +4,6 @@ interface Foo
fun test() { fun test() {
var nullable: Foo? = null var nullable: Foo? = null
val foo: Collection<Foo> = <!TYPE_MISMATCH!>java.util.Collections.singleton(nullable)<!> val foo: Collection<Foo> = java.util.Collections.<!TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH!>singleton<!>(nullable)
val foo1: Collection<Foo> = java.util.Collections.singleton(nullable!!) val foo1: Collection<Foo> = java.util.Collections.singleton(nullable!!)
} }
@@ -34,6 +34,7 @@ import org.jetbrains.kotlin.resolve.scopes.JetScope
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.ErrorUtils.FunctionPlaceholderTypeConstructor import org.jetbrains.kotlin.types.ErrorUtils.FunctionPlaceholderTypeConstructor
import org.jetbrains.kotlin.types.TypeUtils.DONT_CARE import org.jetbrains.kotlin.types.TypeUtils.DONT_CARE
import org.jetbrains.kotlin.types.checker.JetTypeChecker
import org.jetbrains.kotlin.types.checker.TypeCheckingProcedure import org.jetbrains.kotlin.types.checker.TypeCheckingProcedure
import org.jetbrains.kotlin.types.checker.TypeCheckingProcedureCallbacks import org.jetbrains.kotlin.types.checker.TypeCheckingProcedureCallbacks
import org.jetbrains.kotlin.types.typeUtil.getNestedTypeArguments import org.jetbrains.kotlin.types.typeUtil.getNestedTypeArguments
@@ -44,6 +45,8 @@ import java.util.LinkedHashMap
public class ConstraintSystemImpl : ConstraintSystem { public class ConstraintSystemImpl : ConstraintSystem {
data class Constraint(val kind: ConstraintKind, val subtype: JetType, val superType: JetType, val position: ConstraintPosition)
public enum class ConstraintKind { public enum class ConstraintKind {
SUB_TYPE, SUB_TYPE,
EQUAL EQUAL
@@ -65,13 +68,15 @@ public class ConstraintSystemImpl : ConstraintSystem {
public val constraintErrors: List<ConstraintError> public val constraintErrors: List<ConstraintError>
get() = errors get() = errors
private val initialConstraints = ArrayList<Constraint>()
private val constraintSystemStatus = object : ConstraintSystemStatus { private val constraintSystemStatus = object : ConstraintSystemStatus {
// for debug ConstraintsUtil.getDebugMessageForStatus might be used // for debug ConstraintsUtil.getDebugMessageForStatus might be used
override fun isSuccessful() = !hasContradiction() && !hasUnknownParameters() override fun isSuccessful() = !hasContradiction() && !hasUnknownParameters()
override fun hasContradiction() = hasTypeConstructorMismatch() || hasTypeInferenceIncorporationError() override fun hasContradiction() = hasTypeConstructorMismatch() || hasConflictingConstraints()
|| hasConflictingConstraints() || hasCannotCaptureTypesError() || hasCannotCaptureTypesError() || hasTypeInferenceIncorporationError()
override fun hasViolatedUpperBound() = !isSuccessful() && getSystemWithoutWeakConstraints().getStatus().isSuccessful() override fun hasViolatedUpperBound() = !isSuccessful() && getSystemWithoutWeakConstraints().getStatus().isSuccessful()
@@ -91,7 +96,7 @@ public class ConstraintSystemImpl : ConstraintSystem {
override fun hasCannotCaptureTypesError() = errors.any { it is CannotCapture } override fun hasCannotCaptureTypesError() = errors.any { it is CannotCapture }
override fun hasTypeInferenceIncorporationError() = errors.any { it is TypeInferenceError } override fun hasTypeInferenceIncorporationError() = errors.any { it is TypeInferenceError } || !satisfyInitialConstraints()
} }
private fun getParameterToInferredValueMap( private fun getParameterToInferredValueMap(
@@ -204,6 +209,13 @@ public class ConstraintSystemImpl : ConstraintSystem {
} }
newSystem.externalTypeParameters.addAll(externalTypeParameters.map { substituteTypeVariable(it) ?: it }) newSystem.externalTypeParameters.addAll(externalTypeParameters.map { substituteTypeVariable(it) ?: it })
newSystem.errors.addAll(errors.filter { filterConstraintPosition(it.constraintPosition) }.map { it.substituteTypeVariable(substituteTypeVariable) }) newSystem.errors.addAll(errors.filter { filterConstraintPosition(it.constraintPosition) }.map { it.substituteTypeVariable(substituteTypeVariable) })
val typeSubstitutor = createTypeSubstitutor(substituteTypeVariable)
newSystem.initialConstraints.addAll(initialConstraints.filter { filterConstraintPosition(it.position) }.map {
val newSubType = typeSubstitutor.substitute(it.subtype, Variance.INVARIANT)
val newSuperType = typeSubstitutor.substitute(it.superType, Variance.INVARIANT)
if (newSubType != null && newSuperType != null) Constraint(it.kind, newSubType, newSuperType, it.position) else null
})
return newSystem return newSystem
} }
@@ -223,7 +235,7 @@ public class ConstraintSystemImpl : ConstraintSystem {
override fun assertEqualTypes(a: JetType, b: JetType, typeCheckingProcedure: TypeCheckingProcedure): Boolean { override fun assertEqualTypes(a: JetType, b: JetType, typeCheckingProcedure: TypeCheckingProcedure): Boolean {
depth++ depth++
doAddConstraint(EQUAL, a, b, constraintPosition, typeCheckingProcedure) doAddConstraint(EQUAL, a, b, constraintPosition, typeCheckingProcedure, topLevel = false)
depth-- depth--
return true return true
@@ -235,7 +247,7 @@ public class ConstraintSystemImpl : ConstraintSystem {
override fun assertSubtype(subtype: JetType, supertype: JetType, typeCheckingProcedure: TypeCheckingProcedure): Boolean { override fun assertSubtype(subtype: JetType, supertype: JetType, typeCheckingProcedure: TypeCheckingProcedure): Boolean {
depth++ depth++
doAddConstraint(SUB_TYPE, subtype, supertype, constraintPosition, typeCheckingProcedure) doAddConstraint(SUB_TYPE, subtype, supertype, constraintPosition, typeCheckingProcedure, topLevel = false)
depth-- depth--
return true return true
} }
@@ -259,7 +271,7 @@ public class ConstraintSystemImpl : ConstraintSystem {
return true return true
} }
}) })
doAddConstraint(constraintKind, subType, superType, constraintPosition, typeCheckingProcedure) doAddConstraint(constraintKind, subType, superType, constraintPosition, typeCheckingProcedure, topLevel = true)
} }
private fun isErrorOrSpecialType(type: JetType?, constraintPosition: ConstraintPosition): Boolean { private fun isErrorOrSpecialType(type: JetType?, constraintPosition: ConstraintPosition): Boolean {
@@ -279,7 +291,8 @@ public class ConstraintSystemImpl : ConstraintSystem {
subType: JetType?, subType: JetType?,
superType: JetType?, superType: JetType?,
constraintPosition: ConstraintPosition, constraintPosition: ConstraintPosition,
typeCheckingProcedure: TypeCheckingProcedure typeCheckingProcedure: TypeCheckingProcedure,
topLevel: Boolean
) { ) {
if (isErrorOrSpecialType(subType, constraintPosition) || isErrorOrSpecialType(superType, constraintPosition)) return if (isErrorOrSpecialType(subType, constraintPosition) || isErrorOrSpecialType(superType, constraintPosition)) return
if (subType == null || superType == null) return if (subType == null || superType == null) return
@@ -311,10 +324,10 @@ public class ConstraintSystemImpl : ConstraintSystem {
generateTypeParameterBound(superType, subType, constraintKind.toBound().reverse(), constraintPosition) generateTypeParameterBound(superType, subType, constraintKind.toBound().reverse(), constraintPosition)
return return
} }
// if superType is nullable and subType is not nullable, unsafe call or type mismatch error will be generated later, // if subType is nullable and superType is not nullable, unsafe call or type mismatch error will be generated later,
// but constraint system should be solved anyway // but constraint system should be solved anyway
val subTypeNotNullable = TypeUtils.makeNotNullable(subType) val subTypeNotNullable = if (topLevel) TypeUtils.makeNotNullable(subType) else subType
val superTypeNotNullable = TypeUtils.makeNotNullable(superType) val superTypeNotNullable = if (topLevel) TypeUtils.makeNotNullable(superType) else superType
val result = if (constraintKind == EQUAL) { val result = if (constraintKind == EQUAL) {
typeCheckingProcedure.equalTypes(subTypeNotNullable, superTypeNotNullable) typeCheckingProcedure.equalTypes(subTypeNotNullable, superTypeNotNullable)
} }
@@ -323,8 +336,10 @@ public class ConstraintSystemImpl : ConstraintSystem {
} }
if (!result) errors.add(newTypeInferenceOrConstructorMismatchError(constraintPosition)) if (!result) errors.add(newTypeInferenceOrConstructorMismatchError(constraintPosition))
} }
if (topLevel) {
storeInitialConstraint(constraintKind, subType, superType, constraintPosition)
}
simplifyConstraint(newSubType, superType) simplifyConstraint(newSubType, superType)
} }
fun addBound( fun addBound(
@@ -444,6 +459,26 @@ public class ConstraintSystemImpl : ConstraintSystem {
override fun getCurrentSubstitutor() = replaceUninferredBy(TypeUtils.DONT_CARE).setApproximateCapturedTypes() override fun getCurrentSubstitutor() = replaceUninferredBy(TypeUtils.DONT_CARE).setApproximateCapturedTypes()
private fun storeInitialConstraint(constraintKind: ConstraintKind, subType: JetType, superType: JetType, position: ConstraintPosition) {
if (position is CompoundConstraintPosition) return
initialConstraints.add(Constraint(constraintKind, subType, superType, position))
}
private fun satisfyInitialConstraints(): Boolean {
fun JetType.substituteAndMakeNotNullable(): JetType? {
val result = getResultingSubstitutor().substitute(this, Variance.INVARIANT) ?: return null
return TypeUtils.makeNotNullable(result)
}
return initialConstraints.all {
val resultSubType = it.subtype.substituteAndMakeNotNullable() ?: return false
val resultSuperType = it.superType.substituteAndMakeNotNullable() ?: return false
when (it.kind) {
SUB_TYPE -> JetTypeChecker.DEFAULT.isSubtypeOf(resultSubType, resultSuperType)
EQUAL -> JetTypeChecker.DEFAULT.equalTypes(resultSubType, resultSuperType)
}
}
}
fun fixVariable(typeVariable: TypeParameterDescriptor) { fun fixVariable(typeVariable: TypeParameterDescriptor) {
val typeBounds = getTypeBounds(typeVariable) val typeBounds = getTypeBounds(typeVariable)
if (typeBounds.isFixed) return if (typeBounds.isFixed) return
@@ -185,17 +185,7 @@ public class TypeBoundsImpl(
} }
fun Collection<Bound>.substitute(substituteTypeVariable: (TypeParameterDescriptor) -> TypeParameterDescriptor?): List<Bound> { fun Collection<Bound>.substitute(substituteTypeVariable: (TypeParameterDescriptor) -> TypeParameterDescriptor?): List<Bound> {
val typeSubstitutor = TypeSubstitutor.create(object : TypeSubstitution() { val typeSubstitutor = createTypeSubstitutor(substituteTypeVariable)
override fun get(key: TypeConstructor): TypeProjection? {
val descriptor = key.getDeclarationDescriptor()
if (descriptor !is TypeParameterDescriptor) return null
val typeParameterDescriptor = substituteTypeVariable(descriptor) ?: return null
val type = JetTypeImpl(Annotations.EMPTY, typeParameterDescriptor.getTypeConstructor(), false, listOf(), JetScope.Empty)
return TypeProjectionImpl(type)
}
})
return map { return map {
//todo captured types //todo captured types
val substitutedType = if (it.constrainingType.getConstructor().isDenotable()) { val substitutedType = if (it.constrainingType.getConstructor().isDenotable()) {
@@ -207,4 +197,17 @@ fun Collection<Bound>.substitute(substituteTypeVariable: (TypeParameterDescripto
Bound(substituteTypeVariable(it.typeVariable) ?: it.typeVariable, type, it.kind, it.position, it.isProper) Bound(substituteTypeVariable(it.typeVariable) ?: it.typeVariable, type, it.kind, it.position, it.isProper)
} }
}.filterNotNull() }.filterNotNull()
}
fun createTypeSubstitutor(substituteTypeVariable: (TypeParameterDescriptor) -> TypeParameterDescriptor?): TypeSubstitutor {
return TypeSubstitutor.create(object : TypeSubstitution() {
override fun get(key: TypeConstructor): TypeProjection? {
val descriptor = key.getDeclarationDescriptor()
if (descriptor !is TypeParameterDescriptor) return null
val typeParameterDescriptor = substituteTypeVariable(descriptor) ?: return null
val type = JetTypeImpl(Annotations.EMPTY, typeParameterDescriptor.getTypeConstructor(), false, listOf(), JetScope.Empty)
return TypeProjectionImpl(type)
}
})
} }