diff --git a/compiler/testData/constraintSystem/checkStatus/typeConstructorMismatch.bounds b/compiler/testData/constraintSystem/checkStatus/typeConstructorMismatch.bounds index 1a59c9c2394..d3c1d075e01 100644 --- a/compiler/testData/constraintSystem/checkStatus/typeConstructorMismatch.bounds +++ b/compiler/testData/constraintSystem/checkStatus/typeConstructorMismatch.bounds @@ -11,7 +11,7 @@ status: -hasContradiction: true -hasErrorInConstrainingTypes: false -hasTypeConstructorMismatch: true --hasTypeInferenceIncorporationError: false +-hasTypeInferenceIncorporationError: true -hasUnknownParameters: true -hasViolatedUpperBound: false -isSuccessful: false diff --git a/compiler/testData/constraintSystem/severalVariables/direct/invariant/varSubDepEq.bounds b/compiler/testData/constraintSystem/severalVariables/direct/invariant/varSubDepEq.bounds index 882513d21b3..36b349629f5 100644 --- a/compiler/testData/constraintSystem/severalVariables/direct/invariant/varSubDepEq.bounds +++ b/compiler/testData/constraintSystem/severalVariables/direct/invariant/varSubDepEq.bounds @@ -10,10 +10,10 @@ P := My* status: -hasCannotCaptureTypesError: false -hasConflictingConstraints: false --hasContradiction: false +-hasContradiction: true -hasErrorInConstrainingTypes: false -hasTypeConstructorMismatch: false --hasTypeInferenceIncorporationError: false +-hasTypeInferenceIncorporationError: true -hasUnknownParameters: true -hasViolatedUpperBound: false -isSuccessful: false diff --git a/compiler/testData/constraintSystem/severalVariables/direct/invariant/varSuperDepEq.bounds b/compiler/testData/constraintSystem/severalVariables/direct/invariant/varSuperDepEq.bounds index e15e5a52141..a57a227b879 100644 --- a/compiler/testData/constraintSystem/severalVariables/direct/invariant/varSuperDepEq.bounds +++ b/compiler/testData/constraintSystem/severalVariables/direct/invariant/varSuperDepEq.bounds @@ -10,10 +10,10 @@ P := My* status: -hasCannotCaptureTypesError: false -hasConflictingConstraints: false --hasContradiction: false +-hasContradiction: true -hasErrorInConstrainingTypes: false -hasTypeConstructorMismatch: false --hasTypeInferenceIncorporationError: false +-hasTypeInferenceIncorporationError: true -hasUnknownParameters: true -hasViolatedUpperBound: false -isSuccessful: false diff --git a/compiler/testData/constraintSystem/severalVariables/recursive/mutuallyRecursive.bounds b/compiler/testData/constraintSystem/severalVariables/recursive/mutuallyRecursive.bounds index ba87365ac36..68d1b96ebeb 100644 --- a/compiler/testData/constraintSystem/severalVariables/recursive/mutuallyRecursive.bounds +++ b/compiler/testData/constraintSystem/severalVariables/recursive/mutuallyRecursive.bounds @@ -10,10 +10,10 @@ P := Two* status: -hasCannotCaptureTypesError: false -hasConflictingConstraints: false --hasContradiction: false +-hasContradiction: true -hasErrorInConstrainingTypes: false -hasTypeConstructorMismatch: false --hasTypeInferenceIncorporationError: false +-hasTypeInferenceIncorporationError: true -hasUnknownParameters: true -hasViolatedUpperBound: false -isSuccessful: false diff --git a/compiler/testData/constraintSystem/severalVariables/reversed/invariant/varSubDepEq.bounds b/compiler/testData/constraintSystem/severalVariables/reversed/invariant/varSubDepEq.bounds index 8fa34297795..236d15a9bd6 100644 --- a/compiler/testData/constraintSystem/severalVariables/reversed/invariant/varSubDepEq.bounds +++ b/compiler/testData/constraintSystem/severalVariables/reversed/invariant/varSubDepEq.bounds @@ -10,10 +10,10 @@ P := My* status: -hasCannotCaptureTypesError: false -hasConflictingConstraints: false --hasContradiction: false +-hasContradiction: true -hasErrorInConstrainingTypes: false -hasTypeConstructorMismatch: false --hasTypeInferenceIncorporationError: false +-hasTypeInferenceIncorporationError: true -hasUnknownParameters: true -hasViolatedUpperBound: false -isSuccessful: false diff --git a/compiler/testData/constraintSystem/severalVariables/reversed/invariant/varSuperDepEq.bounds b/compiler/testData/constraintSystem/severalVariables/reversed/invariant/varSuperDepEq.bounds index 632b3f91681..ea1fff4a0f4 100644 --- a/compiler/testData/constraintSystem/severalVariables/reversed/invariant/varSuperDepEq.bounds +++ b/compiler/testData/constraintSystem/severalVariables/reversed/invariant/varSuperDepEq.bounds @@ -10,10 +10,10 @@ P := My* status: -hasCannotCaptureTypesError: false -hasConflictingConstraints: false --hasContradiction: false +-hasContradiction: true -hasErrorInConstrainingTypes: false -hasTypeConstructorMismatch: false --hasTypeInferenceIncorporationError: false +-hasTypeInferenceIncorporationError: true -hasUnknownParameters: true -hasViolatedUpperBound: false -isSuccessful: false diff --git a/compiler/testData/diagnostics/tests/platformTypes/methodCall/singleton.kt b/compiler/testData/diagnostics/tests/platformTypes/methodCall/singleton.kt index 6505d5bf312..d03b13d7efd 100644 --- a/compiler/testData/diagnostics/tests/platformTypes/methodCall/singleton.kt +++ b/compiler/testData/diagnostics/tests/platformTypes/methodCall/singleton.kt @@ -4,6 +4,6 @@ interface Foo fun test() { var nullable: Foo? = null - val foo: Collection = java.util.Collections.singleton(nullable) + val foo: Collection = java.util.Collections.singleton(nullable) val foo1: Collection = java.util.Collections.singleton(nullable!!) } \ No newline at end of file diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemImpl.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemImpl.kt index 64ab20e08e2..bb55bb1093a 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemImpl.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemImpl.kt @@ -34,6 +34,7 @@ import org.jetbrains.kotlin.resolve.scopes.JetScope import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.ErrorUtils.FunctionPlaceholderTypeConstructor 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.TypeCheckingProcedureCallbacks import org.jetbrains.kotlin.types.typeUtil.getNestedTypeArguments @@ -44,6 +45,8 @@ import java.util.LinkedHashMap public class ConstraintSystemImpl : ConstraintSystem { + data class Constraint(val kind: ConstraintKind, val subtype: JetType, val superType: JetType, val position: ConstraintPosition) + public enum class ConstraintKind { SUB_TYPE, EQUAL @@ -65,13 +68,15 @@ public class ConstraintSystemImpl : ConstraintSystem { public val constraintErrors: List get() = errors + private val initialConstraints = ArrayList() + private val constraintSystemStatus = object : ConstraintSystemStatus { // for debug ConstraintsUtil.getDebugMessageForStatus might be used override fun isSuccessful() = !hasContradiction() && !hasUnknownParameters() - override fun hasContradiction() = hasTypeConstructorMismatch() || hasTypeInferenceIncorporationError() - || hasConflictingConstraints() || hasCannotCaptureTypesError() + override fun hasContradiction() = hasTypeConstructorMismatch() || hasConflictingConstraints() + || hasCannotCaptureTypesError() || hasTypeInferenceIncorporationError() 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 hasTypeInferenceIncorporationError() = errors.any { it is TypeInferenceError } + override fun hasTypeInferenceIncorporationError() = errors.any { it is TypeInferenceError } || !satisfyInitialConstraints() } private fun getParameterToInferredValueMap( @@ -204,6 +209,13 @@ public class ConstraintSystemImpl : ConstraintSystem { } newSystem.externalTypeParameters.addAll(externalTypeParameters.map { substituteTypeVariable(it) ?: it }) 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 } @@ -223,7 +235,7 @@ public class ConstraintSystemImpl : ConstraintSystem { override fun assertEqualTypes(a: JetType, b: JetType, typeCheckingProcedure: TypeCheckingProcedure): Boolean { depth++ - doAddConstraint(EQUAL, a, b, constraintPosition, typeCheckingProcedure) + doAddConstraint(EQUAL, a, b, constraintPosition, typeCheckingProcedure, topLevel = false) depth-- return true @@ -235,7 +247,7 @@ public class ConstraintSystemImpl : ConstraintSystem { override fun assertSubtype(subtype: JetType, supertype: JetType, typeCheckingProcedure: TypeCheckingProcedure): Boolean { depth++ - doAddConstraint(SUB_TYPE, subtype, supertype, constraintPosition, typeCheckingProcedure) + doAddConstraint(SUB_TYPE, subtype, supertype, constraintPosition, typeCheckingProcedure, topLevel = false) depth-- return true } @@ -259,7 +271,7 @@ public class ConstraintSystemImpl : ConstraintSystem { return true } }) - doAddConstraint(constraintKind, subType, superType, constraintPosition, typeCheckingProcedure) + doAddConstraint(constraintKind, subType, superType, constraintPosition, typeCheckingProcedure, topLevel = true) } private fun isErrorOrSpecialType(type: JetType?, constraintPosition: ConstraintPosition): Boolean { @@ -279,7 +291,8 @@ public class ConstraintSystemImpl : ConstraintSystem { subType: JetType?, superType: JetType?, constraintPosition: ConstraintPosition, - typeCheckingProcedure: TypeCheckingProcedure + typeCheckingProcedure: TypeCheckingProcedure, + topLevel: Boolean ) { if (isErrorOrSpecialType(subType, constraintPosition) || isErrorOrSpecialType(superType, constraintPosition)) return if (subType == null || superType == null) return @@ -311,10 +324,10 @@ public class ConstraintSystemImpl : ConstraintSystem { generateTypeParameterBound(superType, subType, constraintKind.toBound().reverse(), constraintPosition) 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 - val subTypeNotNullable = TypeUtils.makeNotNullable(subType) - val superTypeNotNullable = TypeUtils.makeNotNullable(superType) + val subTypeNotNullable = if (topLevel) TypeUtils.makeNotNullable(subType) else subType + val superTypeNotNullable = if (topLevel) TypeUtils.makeNotNullable(superType) else superType val result = if (constraintKind == EQUAL) { typeCheckingProcedure.equalTypes(subTypeNotNullable, superTypeNotNullable) } @@ -323,8 +336,10 @@ public class ConstraintSystemImpl : ConstraintSystem { } if (!result) errors.add(newTypeInferenceOrConstructorMismatchError(constraintPosition)) } + if (topLevel) { + storeInitialConstraint(constraintKind, subType, superType, constraintPosition) + } simplifyConstraint(newSubType, superType) - } fun addBound( @@ -444,6 +459,26 @@ public class ConstraintSystemImpl : ConstraintSystem { 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) { val typeBounds = getTypeBounds(typeVariable) if (typeBounds.isFixed) return diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/TypeBoundsImpl.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/TypeBoundsImpl.kt index 0137e7062cb..cd640e14e55 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/TypeBoundsImpl.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/calls/inference/TypeBoundsImpl.kt @@ -185,17 +185,7 @@ public class TypeBoundsImpl( } fun Collection.substitute(substituteTypeVariable: (TypeParameterDescriptor) -> TypeParameterDescriptor?): List { - val typeSubstitutor = 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) - } - }) - + val typeSubstitutor = createTypeSubstitutor(substituteTypeVariable) return map { //todo captured types val substitutedType = if (it.constrainingType.getConstructor().isDenotable()) { @@ -207,4 +197,17 @@ fun Collection.substitute(substituteTypeVariable: (TypeParameterDescripto Bound(substituteTypeVariable(it.typeVariable) ?: it.typeVariable, type, it.kind, it.position, it.isProper) } }.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) + } + }) } \ No newline at end of file