Check initial constraints in constraint system status
This commit is contained in:
+1
-1
@@ -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
|
||||||
|
|||||||
+2
-2
@@ -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
|
||||||
|
|||||||
+2
-2
@@ -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
|
||||||
|
|||||||
+2
-2
@@ -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
|
||||||
|
|||||||
+2
-2
@@ -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
|
||||||
|
|||||||
Vendored
+2
-2
@@ -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!!)
|
||||||
}
|
}
|
||||||
+46
-11
@@ -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
|
||||||
|
|||||||
+14
-11
@@ -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)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user