Introduced ConstraintError for storing errors in the constraint system
This commit is contained in:
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2015 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.resolve.calls.inference
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPosition
|
||||||
|
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||||
|
|
||||||
|
open class ConstraintError(val constraintPosition: ConstraintPosition)
|
||||||
|
|
||||||
|
class TypeConstructorMismatch(constraintPosition: ConstraintPosition): ConstraintError(constraintPosition)
|
||||||
|
|
||||||
|
class ErrorInConstrainingType(constraintPosition: ConstraintPosition): ConstraintError(constraintPosition)
|
||||||
|
|
||||||
|
class CannotCapture(constraintPosition: ConstraintPosition, val typeVariable: TypeParameterDescriptor): ConstraintError(constraintPosition)
|
||||||
+28
-51
@@ -31,7 +31,6 @@ 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.TypeConstructor
|
import org.jetbrains.kotlin.types.TypeConstructor
|
||||||
import java.util.LinkedHashMap
|
import java.util.LinkedHashMap
|
||||||
import java.util.HashSet
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.TypeBounds.BoundKind.*
|
import org.jetbrains.kotlin.resolve.calls.inference.TypeBounds.BoundKind.*
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemImpl.ConstraintKind.*
|
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemImpl.ConstraintKind.*
|
||||||
import java.util.HashMap
|
import java.util.HashMap
|
||||||
@@ -52,9 +51,7 @@ public class ConstraintSystemImpl : ConstraintSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val typeParameterBounds = LinkedHashMap<TypeParameterDescriptor, TypeBoundsImpl>()
|
private val typeParameterBounds = LinkedHashMap<TypeParameterDescriptor, TypeBoundsImpl>()
|
||||||
private val errorConstraintPositions = HashSet<ConstraintPosition>()
|
private val errors = ArrayList<ConstraintError>()
|
||||||
private var hasErrorInConstrainingTypes: Boolean = false
|
|
||||||
private var cannotCaptureTypesError: Boolean = false
|
|
||||||
|
|
||||||
private val constraintSystemStatus = object : ConstraintSystemStatus {
|
private val constraintSystemStatus = object : ConstraintSystemStatus {
|
||||||
// for debug ConstraintsUtil.getDebugMessageForStatus might be used
|
// for debug ConstraintsUtil.getDebugMessageForStatus might be used
|
||||||
@@ -63,51 +60,32 @@ public class ConstraintSystemImpl : ConstraintSystem {
|
|||||||
|
|
||||||
override fun hasContradiction() = hasTypeConstructorMismatch() || hasConflictingConstraints() || hasCannotCaptureTypesError()
|
override fun hasContradiction() = hasTypeConstructorMismatch() || hasConflictingConstraints() || hasCannotCaptureTypesError()
|
||||||
|
|
||||||
override fun hasViolatedUpperBound(): Boolean {
|
override fun hasViolatedUpperBound() = !isSuccessful() && getSystemWithoutWeakConstraints().getStatus().isSuccessful()
|
||||||
if (isSuccessful()) return false
|
|
||||||
return getSystemWithoutWeakConstraints().getStatus().isSuccessful()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hasConflictingConstraints(): Boolean {
|
override fun hasConflictingConstraints() = typeParameterBounds.values().any { it.getValues().size() > 1 }
|
||||||
for (typeBounds in typeParameterBounds.values()) {
|
|
||||||
if (typeBounds.getValues().size() > 1) return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hasUnknownParameters(): Boolean {
|
override fun hasUnknownParameters() = typeParameterBounds.values().any { it.isEmpty() }
|
||||||
for (typeBounds in typeParameterBounds.values()) {
|
|
||||||
if (typeBounds.isEmpty()) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hasTypeConstructorMismatch() = !errorConstraintPositions.isEmpty()
|
override fun hasTypeConstructorMismatch() = errors.any { it is TypeConstructorMismatch }
|
||||||
|
|
||||||
override fun hasTypeConstructorMismatchAt(constraintPosition: ConstraintPosition) =
|
override fun hasTypeConstructorMismatchAt(constraintPosition: ConstraintPosition) =
|
||||||
errorConstraintPositions.contains(constraintPosition)
|
errors.any { it is TypeConstructorMismatch && it.constraintPosition == constraintPosition }
|
||||||
|
|
||||||
override fun hasOnlyErrorsFromPosition(constraintPosition: ConstraintPosition): Boolean {
|
override fun hasOnlyErrorsFromPosition(constraintPosition: ConstraintPosition): Boolean {
|
||||||
if (isSuccessful()) return false
|
if (isSuccessful()) return false
|
||||||
val systemWithoutConstraintsFromPosition = filterConstraintsOut(constraintPosition)
|
if (filterConstraintsOut(constraintPosition).getStatus().isSuccessful()) return true
|
||||||
if (systemWithoutConstraintsFromPosition.getStatus().isSuccessful()) {
|
return errors.isNotEmpty() && errors.all { it.constraintPosition == constraintPosition }
|
||||||
return true
|
|
||||||
}
|
|
||||||
if (errorConstraintPositions.size() == 1 && errorConstraintPositions.contains(constraintPosition)) {
|
|
||||||
// e.g. if systemWithoutConstraintsFromPosition has unknown type parameters, it's not successful
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hasErrorInConstrainingTypes() = hasErrorInConstrainingTypes
|
override fun hasErrorInConstrainingTypes() = errors.any { it is ErrorInConstrainingType }
|
||||||
|
|
||||||
override fun hasCannotCaptureTypesError() = cannotCaptureTypesError
|
override fun hasCannotCaptureTypesError() = errors.any { it is CannotCapture }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getParameterToInferredValueMap(typeParameterBounds: Map<TypeParameterDescriptor, TypeBoundsImpl>, getDefaultTypeProjection: Function1<TypeParameterDescriptor, TypeProjection>): Map<TypeParameterDescriptor, TypeProjection> {
|
private fun getParameterToInferredValueMap(
|
||||||
|
typeParameterBounds: Map<TypeParameterDescriptor, TypeBoundsImpl>,
|
||||||
|
getDefaultTypeProjection: (TypeParameterDescriptor) -> TypeProjection
|
||||||
|
): Map<TypeParameterDescriptor, TypeProjection> {
|
||||||
val substitutionContext = HashMap<TypeParameterDescriptor, TypeProjection>()
|
val substitutionContext = HashMap<TypeParameterDescriptor, TypeProjection>()
|
||||||
for ((typeParameter, typeBounds) in typeParameterBounds) {
|
for ((typeParameter, typeBounds) in typeParameterBounds) {
|
||||||
val typeProjection: TypeProjection
|
val typeProjection: TypeProjection
|
||||||
@@ -116,7 +94,7 @@ public class ConstraintSystemImpl : ConstraintSystem {
|
|||||||
typeProjection = TypeProjectionImpl(value)
|
typeProjection = TypeProjectionImpl(value)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
typeProjection = getDefaultTypeProjection.invoke(typeParameter)
|
typeProjection = getDefaultTypeProjection(typeParameter)
|
||||||
}
|
}
|
||||||
substitutionContext.put(typeParameter, typeProjection)
|
substitutionContext.put(typeParameter, typeProjection)
|
||||||
}
|
}
|
||||||
@@ -146,8 +124,9 @@ public class ConstraintSystemImpl : ConstraintSystem {
|
|||||||
for (declaredUpperBound in typeVariable.getUpperBounds()) {
|
for (declaredUpperBound in typeVariable.getUpperBounds()) {
|
||||||
if (KotlinBuiltIns.getInstance().getNullableAnyType() == declaredUpperBound) continue //todo remove this line (?)
|
if (KotlinBuiltIns.getInstance().getNullableAnyType() == declaredUpperBound) continue //todo remove this line (?)
|
||||||
val substitutedBound = constantSubstitutor?.substitute(declaredUpperBound, Variance.INVARIANT)
|
val substitutedBound = constantSubstitutor?.substitute(declaredUpperBound, Variance.INVARIANT)
|
||||||
if (substitutedBound != null && !isErrorOrSpecialType(substitutedBound)) {
|
val position = TYPE_BOUND_POSITION.position(typeVariable.getIndex())
|
||||||
typeBounds.addBound(UPPER_BOUND, substitutedBound, TYPE_BOUND_POSITION.position(typeVariable.getIndex()))
|
if (substitutedBound != null && !isErrorOrSpecialType(substitutedBound, position)) {
|
||||||
|
typeBounds.addBound(UPPER_BOUND, substitutedBound, position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -193,10 +172,7 @@ public class ConstraintSystemImpl : ConstraintSystem {
|
|||||||
val newTypeParameter = substituteTypeVariable(typeParameter)
|
val newTypeParameter = substituteTypeVariable(typeParameter)
|
||||||
newSystem.typeParameterBounds.put(newTypeParameter!!, replaceTypeBounds(typeBounds))
|
newSystem.typeParameterBounds.put(newTypeParameter!!, replaceTypeBounds(typeBounds))
|
||||||
}
|
}
|
||||||
newSystem.errorConstraintPositions.addAll(errorConstraintPositions.filter(filterConstraintPosition))
|
newSystem.errors.addAll(errors.filter { filterConstraintPosition(it.constraintPosition) })
|
||||||
//todo if 'filterConstraintPosition' is not trivial, it's incorrect to just copy 'hasErrorInConstrainingTypes'
|
|
||||||
newSystem.hasErrorInConstrainingTypes = hasErrorInConstrainingTypes
|
|
||||||
newSystem.cannotCaptureTypesError = cannotCaptureTypesError
|
|
||||||
return newSystem
|
return newSystem
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,9 +208,10 @@ public class ConstraintSystemImpl : ConstraintSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun capture(typeVariable: JetType, typeProjection: TypeProjection): Boolean {
|
override fun capture(typeVariable: JetType, typeProjection: TypeProjection): Boolean {
|
||||||
if (isMyTypeVariable(typeVariable) && constraintPosition.isCaptureAllowed()) {
|
val myTypeVariable = getMyTypeVariable(typeVariable)
|
||||||
|
if (myTypeVariable != null && constraintPosition.isCaptureAllowed()) {
|
||||||
if (!isTopLevel) {
|
if (!isTopLevel) {
|
||||||
cannotCaptureTypesError = true
|
errors.add(CannotCapture(constraintPosition, myTypeVariable))
|
||||||
}
|
}
|
||||||
generateTypeParameterCaptureConstraint(typeVariable, typeProjection, constraintPosition)
|
generateTypeParameterCaptureConstraint(typeVariable, typeProjection, constraintPosition)
|
||||||
return true
|
return true
|
||||||
@@ -243,20 +220,20 @@ public class ConstraintSystemImpl : ConstraintSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun noCorrespondingSupertype(subtype: JetType, supertype: JetType): Boolean {
|
override fun noCorrespondingSupertype(subtype: JetType, supertype: JetType): Boolean {
|
||||||
errorConstraintPositions.add(constraintPosition)
|
errors.add(TypeConstructorMismatch(constraintPosition))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
doAddConstraint(constraintKind, subType, superType, constraintPosition, typeCheckingProcedure)
|
doAddConstraint(constraintKind, subType, superType, constraintPosition, typeCheckingProcedure)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isErrorOrSpecialType(type: JetType?): Boolean {
|
private fun isErrorOrSpecialType(type: JetType?, constraintPosition: ConstraintPosition): Boolean {
|
||||||
if (TypeUtils.isDontCarePlaceholder(type) || ErrorUtils.isUninferredParameter(type)) {
|
if (TypeUtils.isDontCarePlaceholder(type) || ErrorUtils.isUninferredParameter(type)) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == null || (type.isError() && type != TypeUtils.PLACEHOLDER_FUNCTION_TYPE)) {
|
if (type == null || (type.isError() && type != TypeUtils.PLACEHOLDER_FUNCTION_TYPE)) {
|
||||||
hasErrorInConstrainingTypes = true
|
errors.add(ErrorInConstrainingType(constraintPosition))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@@ -269,7 +246,7 @@ public class ConstraintSystemImpl : ConstraintSystem {
|
|||||||
constraintPosition: ConstraintPosition,
|
constraintPosition: ConstraintPosition,
|
||||||
typeCheckingProcedure: TypeCheckingProcedure
|
typeCheckingProcedure: TypeCheckingProcedure
|
||||||
) {
|
) {
|
||||||
if (isErrorOrSpecialType(subType) || isErrorOrSpecialType(superType)) return
|
if (isErrorOrSpecialType(subType, constraintPosition) || isErrorOrSpecialType(superType, constraintPosition)) return
|
||||||
if (subType == null || superType == null) return
|
if (subType == null || superType == null) return
|
||||||
|
|
||||||
assert(superType != TypeUtils.PLACEHOLDER_FUNCTION_TYPE) {
|
assert(superType != TypeUtils.PLACEHOLDER_FUNCTION_TYPE) {
|
||||||
@@ -282,7 +259,7 @@ public class ConstraintSystemImpl : ConstraintSystem {
|
|||||||
// a constraint binds type parameter and any function type, so there is no new info and no error
|
// a constraint binds type parameter and any function type, so there is no new info and no error
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
errorConstraintPositions.add(constraintPosition)
|
errors.add(TypeConstructorMismatch(constraintPosition))
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -379,7 +356,7 @@ public class ConstraintSystemImpl : ConstraintSystem {
|
|||||||
val typeVariable = getMyTypeVariable(parameterType)!!
|
val typeVariable = getMyTypeVariable(parameterType)!!
|
||||||
if (!KotlinBuiltIns.isNullableAny(typeVariable.getUpperBoundsAsType())
|
if (!KotlinBuiltIns.isNullableAny(typeVariable.getUpperBoundsAsType())
|
||||||
&& constrainingTypeProjection.getProjectionKind() == Variance.IN_VARIANCE) {
|
&& constrainingTypeProjection.getProjectionKind() == Variance.IN_VARIANCE) {
|
||||||
cannotCaptureTypesError = true
|
errors.add(CannotCapture(constraintPosition, typeVariable))
|
||||||
}
|
}
|
||||||
val typeBounds = getTypeBounds(typeVariable)
|
val typeBounds = getTypeBounds(typeVariable)
|
||||||
val typeProjection = if (parameterType.isMarkedNullable()) {
|
val typeProjection = if (parameterType.isMarkedNullable()) {
|
||||||
|
|||||||
Reference in New Issue
Block a user