Introduced ConstraintError for storing errors in the constraint system

This commit is contained in:
Svetlana Isakova
2015-01-21 21:44:30 +03:00
parent 4f61ead1de
commit 971ad53bcc
2 changed files with 56 additions and 51 deletions
@@ -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)
@@ -31,7 +31,6 @@ import org.jetbrains.kotlin.types.checker.TypeCheckingProcedure
import org.jetbrains.kotlin.types.checker.TypeCheckingProcedureCallbacks
import org.jetbrains.kotlin.types.TypeConstructor
import java.util.LinkedHashMap
import java.util.HashSet
import org.jetbrains.kotlin.resolve.calls.inference.TypeBounds.BoundKind.*
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemImpl.ConstraintKind.*
import java.util.HashMap
@@ -52,9 +51,7 @@ public class ConstraintSystemImpl : ConstraintSystem {
}
private val typeParameterBounds = LinkedHashMap<TypeParameterDescriptor, TypeBoundsImpl>()
private val errorConstraintPositions = HashSet<ConstraintPosition>()
private var hasErrorInConstrainingTypes: Boolean = false
private var cannotCaptureTypesError: Boolean = false
private val errors = ArrayList<ConstraintError>()
private val constraintSystemStatus = object : ConstraintSystemStatus {
// for debug ConstraintsUtil.getDebugMessageForStatus might be used
@@ -63,51 +60,32 @@ public class ConstraintSystemImpl : ConstraintSystem {
override fun hasContradiction() = hasTypeConstructorMismatch() || hasConflictingConstraints() || hasCannotCaptureTypesError()
override fun hasViolatedUpperBound(): Boolean {
if (isSuccessful()) return false
return getSystemWithoutWeakConstraints().getStatus().isSuccessful()
}
override fun hasViolatedUpperBound() = !isSuccessful() && getSystemWithoutWeakConstraints().getStatus().isSuccessful()
override fun hasConflictingConstraints(): Boolean {
for (typeBounds in typeParameterBounds.values()) {
if (typeBounds.getValues().size() > 1) return true
}
return false
}
override fun hasConflictingConstraints() = typeParameterBounds.values().any { it.getValues().size() > 1 }
override fun hasUnknownParameters(): Boolean {
for (typeBounds in typeParameterBounds.values()) {
if (typeBounds.isEmpty()) {
return true
}
}
return false
}
override fun hasUnknownParameters() = typeParameterBounds.values().any { it.isEmpty() }
override fun hasTypeConstructorMismatch() = !errorConstraintPositions.isEmpty()
override fun hasTypeConstructorMismatch() = errors.any { it is TypeConstructorMismatch }
override fun hasTypeConstructorMismatchAt(constraintPosition: ConstraintPosition) =
errorConstraintPositions.contains(constraintPosition)
errors.any { it is TypeConstructorMismatch && it.constraintPosition == constraintPosition }
override fun hasOnlyErrorsFromPosition(constraintPosition: ConstraintPosition): Boolean {
if (isSuccessful()) return false
val systemWithoutConstraintsFromPosition = filterConstraintsOut(constraintPosition)
if (systemWithoutConstraintsFromPosition.getStatus().isSuccessful()) {
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
if (filterConstraintsOut(constraintPosition).getStatus().isSuccessful()) return true
return errors.isNotEmpty() && errors.all { it.constraintPosition == constraintPosition }
}
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>()
for ((typeParameter, typeBounds) in typeParameterBounds) {
val typeProjection: TypeProjection
@@ -116,7 +94,7 @@ public class ConstraintSystemImpl : ConstraintSystem {
typeProjection = TypeProjectionImpl(value)
}
else {
typeProjection = getDefaultTypeProjection.invoke(typeParameter)
typeProjection = getDefaultTypeProjection(typeParameter)
}
substitutionContext.put(typeParameter, typeProjection)
}
@@ -146,8 +124,9 @@ public class ConstraintSystemImpl : ConstraintSystem {
for (declaredUpperBound in typeVariable.getUpperBounds()) {
if (KotlinBuiltIns.getInstance().getNullableAnyType() == declaredUpperBound) continue //todo remove this line (?)
val substitutedBound = constantSubstitutor?.substitute(declaredUpperBound, Variance.INVARIANT)
if (substitutedBound != null && !isErrorOrSpecialType(substitutedBound)) {
typeBounds.addBound(UPPER_BOUND, substitutedBound, TYPE_BOUND_POSITION.position(typeVariable.getIndex()))
val position = 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)
newSystem.typeParameterBounds.put(newTypeParameter!!, replaceTypeBounds(typeBounds))
}
newSystem.errorConstraintPositions.addAll(errorConstraintPositions.filter(filterConstraintPosition))
//todo if 'filterConstraintPosition' is not trivial, it's incorrect to just copy 'hasErrorInConstrainingTypes'
newSystem.hasErrorInConstrainingTypes = hasErrorInConstrainingTypes
newSystem.cannotCaptureTypesError = cannotCaptureTypesError
newSystem.errors.addAll(errors.filter { filterConstraintPosition(it.constraintPosition) })
return newSystem
}
@@ -232,9 +208,10 @@ public class ConstraintSystemImpl : ConstraintSystem {
}
override fun capture(typeVariable: JetType, typeProjection: TypeProjection): Boolean {
if (isMyTypeVariable(typeVariable) && constraintPosition.isCaptureAllowed()) {
val myTypeVariable = getMyTypeVariable(typeVariable)
if (myTypeVariable != null && constraintPosition.isCaptureAllowed()) {
if (!isTopLevel) {
cannotCaptureTypesError = true
errors.add(CannotCapture(constraintPosition, myTypeVariable))
}
generateTypeParameterCaptureConstraint(typeVariable, typeProjection, constraintPosition)
return true
@@ -243,20 +220,20 @@ public class ConstraintSystemImpl : ConstraintSystem {
}
override fun noCorrespondingSupertype(subtype: JetType, supertype: JetType): Boolean {
errorConstraintPositions.add(constraintPosition)
errors.add(TypeConstructorMismatch(constraintPosition))
return true
}
})
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)) {
return true
}
if (type == null || (type.isError() && type != TypeUtils.PLACEHOLDER_FUNCTION_TYPE)) {
hasErrorInConstrainingTypes = true
errors.add(ErrorInConstrainingType(constraintPosition))
return true
}
return false
@@ -269,7 +246,7 @@ public class ConstraintSystemImpl : ConstraintSystem {
constraintPosition: ConstraintPosition,
typeCheckingProcedure: TypeCheckingProcedure
) {
if (isErrorOrSpecialType(subType) || isErrorOrSpecialType(superType)) return
if (isErrorOrSpecialType(subType, constraintPosition) || isErrorOrSpecialType(superType, constraintPosition)) return
if (subType == null || superType == null) return
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
return
}
errorConstraintPositions.add(constraintPosition)
errors.add(TypeConstructorMismatch(constraintPosition))
}
return
}
@@ -379,7 +356,7 @@ public class ConstraintSystemImpl : ConstraintSystem {
val typeVariable = getMyTypeVariable(parameterType)!!
if (!KotlinBuiltIns.isNullableAny(typeVariable.getUpperBoundsAsType())
&& constrainingTypeProjection.getProjectionKind() == Variance.IN_VARIANCE) {
cannotCaptureTypesError = true
errors.add(CannotCapture(constraintPosition, typeVariable))
}
val typeBounds = getTypeBounds(typeVariable)
val typeProjection = if (parameterType.isMarkedNullable()) {