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.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()) {