Converted ConstraintSystem to Kotlin

This commit is contained in:
Svetlana Isakova
2014-07-21 13:16:53 +04:00
parent 38d38e14c8
commit 578f6d4811
9 changed files with 390 additions and 641 deletions
@@ -428,8 +428,8 @@ public class Renderers {
Function<TypeBoundsImpl.Bound, String> renderBound = new Function<TypeBoundsImpl.Bound, String>() {
@Override
public String fun(TypeBoundsImpl.Bound bound) {
String arrow = bound.kind == LOWER_BOUND ? ">: " : bound.kind == UPPER_BOUND ? "<: " : ":= ";
return arrow + RENDER_TYPE.render(bound.type) + '(' + bound.position + ')';
String arrow = bound.getKind() == LOWER_BOUND ? ">: " : bound.getKind() == UPPER_BOUND ? "<: " : ":= ";
return arrow + RENDER_TYPE.render(bound.getConstrainingType()) + '(' + bound.getPosition() + ')';
}
};
Name typeVariableName = typeBounds.getTypeVariable().getName();
@@ -134,7 +134,7 @@ public class CallCompleter(
trace: BindingTrace
) {
fun updateSystemIfSuccessful(update: (ConstraintSystem) -> Boolean) {
val copy = getConstraintSystem()!!.copy()
val copy = (getConstraintSystem() as ConstraintSystemImpl).copy()
if (update(copy)) {
setConstraintSystem(copy)
}
@@ -34,6 +34,7 @@ public class ConstraintPosition {
private static final Map<Integer, ConstraintPosition> valueParameterPositions = new HashMap<Integer, ConstraintPosition>();
private static final Map<Integer, ConstraintPosition> typeBoundPositions = new HashMap<Integer, ConstraintPosition>();
@NotNull
public static ConstraintPosition getValueParameterPosition(int index) {
ConstraintPosition position = valueParameterPositions.get(index);
if (position == null) {
@@ -43,6 +44,7 @@ public class ConstraintPosition {
return position;
}
@NotNull
public static ConstraintPosition getTypeBoundPosition(int index) {
ConstraintPosition position = typeBoundPositions.get(index);
if (position == null) {
@@ -74,6 +76,7 @@ public class ConstraintPosition {
}
}
@NotNull
public static ConstraintPosition getCompoundConstraintPosition(ConstraintPosition... positions) {
return new CompoundConstraintPosition(Arrays.asList(positions));
}
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
* Copyright 2010-2014 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.
@@ -14,30 +14,24 @@
* limitations under the License.
*/
package org.jetbrains.jet.lang.resolve.calls.inference;
package org.jetbrains.jet.lang.resolve.calls.inference
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeSubstitutor;
import org.jetbrains.jet.lang.types.Variance;
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor
import org.jetbrains.jet.lang.types.Variance
import org.jetbrains.jet.lang.types.JetType
import org.jetbrains.jet.lang.types.TypeSubstitutor
import java.util.Map;
import java.util.Set;
public interface ConstraintSystem {
public trait ConstraintSystem {
/**
* Registers variables in a constraint system.
*/
void registerTypeVariables(@NotNull Map<TypeParameterDescriptor, Variance> typeVariables);
public fun registerTypeVariables(typeVariables: Map<TypeParameterDescriptor, Variance>)
/**
* Returns a set of all registered type variables.
*/
@NotNull
Set<TypeParameterDescriptor> getTypeVariables();
public fun getTypeVariables(): Set<TypeParameterDescriptor>
/**
* Adds a constraint that the constraining type is a subtype of the subject type.<p/>
@@ -46,7 +40,7 @@ public interface ConstraintSystem {
* For example, for {@code "fun <T> id(t: T) {}"} to infer <tt>T</tt> in invocation <tt>"id(1)"</tt>
* should be generated a constraint <tt>"Int is a subtype of T"</tt> where T is a subject type, and Int is a constraining type.
*/
void addSubtypeConstraint(@Nullable JetType constrainingType, @NotNull JetType subjectType, @NotNull ConstraintPosition constraintPosition);
public fun addSubtypeConstraint(constrainingType: JetType?, subjectType: JetType, constraintPosition: ConstraintPosition)
/**
* Adds a constraint that the constraining type is a supertype of the subject type. <p/>
@@ -55,17 +49,15 @@ public interface ConstraintSystem {
* For example, for {@code "fun <T> create() : T"} to infer <tt>T</tt> in invocation <tt>"val i: Int = create()"</tt>
* should be generated a constraint <tt>"Int is a supertype of T"</tt> where T is a subject type, and Int is a constraining type.
*/
void addSupertypeConstraint(@Nullable JetType constrainingType, @NotNull JetType subjectType, @NotNull ConstraintPosition constraintPosition);
public fun addSupertypeConstraint(constrainingType: JetType?, subjectType: JetType, constraintPosition: ConstraintPosition)
@NotNull
ConstraintSystemStatus getStatus();
public fun getStatus(): ConstraintSystemStatus
/**
* Returns the resulting type constraints of solving the constraint system for specific type variable. <p/>
* Returns null if the type variable was not registered.
*/
@NotNull
TypeBounds getTypeBounds(@NotNull TypeParameterDescriptor typeVariable);
public fun getTypeBounds(typeVariable: TypeParameterDescriptor): TypeBounds
/**
* Returns a result of solving the constraint system (mapping from the type variable to the resulting type projection). <p/>
@@ -76,16 +68,11 @@ public interface ConstraintSystem {
* If the addition of the 'expected type' constraint made the system fail,
* this constraint is not included in the resulting substitution.
*/
@NotNull
TypeSubstitutor getResultingSubstitutor();
public fun getResultingSubstitutor(): TypeSubstitutor
/**
* Returns a current result of solving the constraint system (mapping from the type variable to the resulting type projection).
* If there is no information for type parameter, returns type projection for DONT_CARE type.
*/
@NotNull
TypeSubstitutor getCurrentSubstitutor();
@NotNull
ConstraintSystem copy();
}
public fun getCurrentSubstitutor(): TypeSubstitutor
}
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
* Copyright 2010-2014 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.
@@ -14,464 +14,337 @@
* limitations under the License.
*/
package org.jetbrains.jet.lang.resolve.calls.inference;
package org.jetbrains.jet.lang.resolve.calls.inference
import kotlin.Function1;
import kotlin.KotlinPackage;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor;
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
import org.jetbrains.jet.lang.types.checker.TypeCheckingProcedure;
import org.jetbrains.jet.lang.types.checker.TypingConstraints;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import org.jetbrains.jet.utils.UtilsPackage;
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor
import org.jetbrains.jet.lang.types.TypeProjection
import org.jetbrains.jet.lang.types.JetType
import org.jetbrains.jet.lang.types.TypeUtils
import org.jetbrains.jet.lang.types.TypeUtils.DONT_CARE
import org.jetbrains.jet.lang.types.TypeProjectionImpl
import org.jetbrains.jet.lang.types.TypeSubstitutor
import org.jetbrains.jet.lang.types.ErrorUtils
import org.jetbrains.jet.lang.types.Variance
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl.ConstraintKind
import org.jetbrains.jet.lang.types.checker.TypeCheckingProcedure
import org.jetbrains.jet.lang.types.checker.TypingConstraints
import org.jetbrains.jet.lang.types.TypeConstructor
import java.util.LinkedHashMap
import java.util.HashSet
import org.jetbrains.jet.lang.resolve.calls.inference.TypeBounds.BoundKind.*
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl.ConstraintKind.*
import java.util.HashMap
import java.util.ArrayList
import org.jetbrains.kotlin.util.sure
import java.util.*;
public class ConstraintSystemImpl : ConstraintSystem {
import static org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl.ConstraintKind.EQUAL;
import static org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl.ConstraintKind.SUB_TYPE;
import static org.jetbrains.jet.lang.resolve.calls.inference.TypeBounds.Bound;
import static org.jetbrains.jet.lang.resolve.calls.inference.TypeBounds.BoundKind.*;
import static org.jetbrains.jet.lang.types.TypeUtils.DONT_CARE;
public class ConstraintSystemImpl implements ConstraintSystem {
public enum ConstraintKind {
SUB_TYPE, EQUAL
public enum class ConstraintKind {
SUB_TYPE
EQUAL
}
private final Map<TypeParameterDescriptor, TypeBoundsImpl> typeParameterBounds =
new LinkedHashMap<TypeParameterDescriptor, TypeBoundsImpl>();
private final Set<ConstraintPosition> errorConstraintPositions = new HashSet<ConstraintPosition>();
private boolean hasErrorInConstrainingTypes;
private val typeParameterBounds = LinkedHashMap<TypeParameterDescriptor, TypeBoundsImpl>()
private val errorConstraintPositions = HashSet<ConstraintPosition>()
private var hasErrorInConstrainingTypes: Boolean = false
private final ConstraintSystemStatus constraintSystemStatus = new ConstraintSystemStatus() {
private val constraintSystemStatus = object : ConstraintSystemStatus {
// for debug ConstraintsUtil.getDebugMessageForStatus might be used
@Override
public boolean isSuccessful() {
return !hasContradiction() && !hasUnknownParameters();
override fun isSuccessful() = !hasContradiction() && !hasUnknownParameters()
override fun hasContradiction() = hasTypeConstructorMismatch() || hasConflictingConstraints()
override fun hasViolatedUpperBound(): Boolean {
if (isSuccessful()) return false
return getSystemWithoutWeakConstraints().getStatus().isSuccessful()
}
@Override
public boolean hasContradiction() {
return hasTypeConstructorMismatch() || hasConflictingConstraints();
}
@Override
public boolean hasViolatedUpperBound() {
if (isSuccessful()) return false;
return getSystemWithoutWeakConstraints().getStatus().isSuccessful();
}
@Override
public boolean hasConflictingConstraints() {
for (TypeBoundsImpl typeBounds : typeParameterBounds.values()) {
if (typeBounds.getValues().size() > 1) return true;
override fun hasConflictingConstraints(): Boolean {
for (typeBounds in typeParameterBounds.values()) {
if (typeBounds.getValues().size() > 1) return true
}
return false;
return false
}
@Override
public boolean hasUnknownParameters() {
for (TypeBoundsImpl typeBounds : typeParameterBounds.values()) {
override fun hasUnknownParameters(): Boolean {
for (typeBounds in typeParameterBounds.values()) {
if (typeBounds.isEmpty()) {
return true;
return true
}
}
return false;
return false
}
@Override
public boolean hasTypeConstructorMismatch() {
return !errorConstraintPositions.isEmpty();
}
override fun hasTypeConstructorMismatch() = !errorConstraintPositions.isEmpty()
@Override
public boolean hasTypeConstructorMismatchAt(@NotNull ConstraintPosition constraintPosition) {
return errorConstraintPositions.contains(constraintPosition);
}
override fun hasTypeConstructorMismatchAt(constraintPosition: ConstraintPosition) =
errorConstraintPositions.contains(constraintPosition)
@Override
public boolean hasOnlyErrorsFromPosition(ConstraintPosition constraintPosition) {
if (isSuccessful()) return false;
ConstraintSystem systemWithoutConstraintsFromPosition = filterConstraintsOut(constraintPosition);
override fun hasOnlyErrorsFromPosition(constraintPosition: ConstraintPosition): Boolean {
if (isSuccessful()) return false
val systemWithoutConstraintsFromPosition = filterConstraintsOut(constraintPosition)
if (systemWithoutConstraintsFromPosition.getStatus().isSuccessful()) {
return true;
return true
}
if (errorConstraintPositions.size() == 1 && errorConstraintPositions.contains(constraintPosition)) {
// e.g. if systemWithoutConstraintsFromPosition has unknown type parameters, it's not successful
return true;
return true
}
return false;
return false
}
@Override
public boolean hasErrorInConstrainingTypes() {
return hasErrorInConstrainingTypes;
}
};
override fun hasErrorInConstrainingTypes() = hasErrorInConstrainingTypes
}
@NotNull
private static Map<TypeParameterDescriptor, TypeProjection> getParameterToInferredValueMap(
@NotNull Map<TypeParameterDescriptor, TypeBoundsImpl> typeParameterBounds,
@NotNull Function1<TypeParameterDescriptor, TypeProjection> getDefaultTypeProjection
) {
Map<TypeParameterDescriptor, TypeProjection> substitutionContext =
UtilsPackage.newHashMapWithExpectedSize(typeParameterBounds.size());
for (Map.Entry<TypeParameterDescriptor, TypeBoundsImpl> entry : typeParameterBounds.entrySet()) {
TypeParameterDescriptor typeParameter = entry.getKey();
TypeBounds typeBounds = entry.getValue();
TypeProjection typeProjection;
JetType value = typeBounds.getValue();
if (value != null && !TypeUtils.containsSpecialType(value, TypeUtils.DONT_CARE)) {
typeProjection = new TypeProjectionImpl(value);
private fun getParameterToInferredValueMap(typeParameterBounds: Map<TypeParameterDescriptor, TypeBoundsImpl>, getDefaultTypeProjection: Function1<TypeParameterDescriptor, TypeProjection>): Map<TypeParameterDescriptor, TypeProjection> {
val substitutionContext = HashMap<TypeParameterDescriptor, TypeProjection>()
for ((typeParameter, typeBounds) in typeParameterBounds) {
val typeProjection: TypeProjection
val value = typeBounds.getValue()
if (value != null && !TypeUtils.containsSpecialType(value, DONT_CARE)) {
typeProjection = TypeProjectionImpl(value)
}
else {
typeProjection = getDefaultTypeProjection.invoke(typeParameter);
typeProjection = getDefaultTypeProjection.invoke(typeParameter)
}
substitutionContext.put(typeParameter, typeProjection);
substitutionContext.put(typeParameter, typeProjection)
}
return substitutionContext;
return substitutionContext
}
private TypeSubstitutor replaceUninferredBy(@NotNull Function1<TypeParameterDescriptor, TypeProjection> getDefaultValue) {
return TypeUtils.makeSubstitutorForTypeParametersMap(getParameterToInferredValueMap(typeParameterBounds, getDefaultValue));
private fun replaceUninferredBy(getDefaultValue: (TypeParameterDescriptor) -> TypeProjection): TypeSubstitutor {
return TypeUtils.makeSubstitutorForTypeParametersMap(getParameterToInferredValueMap(typeParameterBounds, getDefaultValue))
}
private TypeSubstitutor replaceUninferredBy(@NotNull final JetType defaultValue) {
return replaceUninferredBy(
new Function1<TypeParameterDescriptor, TypeProjection>() {
@Override
public TypeProjection invoke(TypeParameterDescriptor descriptor) {
return new TypeProjectionImpl(defaultValue);
}
}
);
private fun replaceUninferredBy(defaultValue: JetType): TypeSubstitutor {
return replaceUninferredBy { TypeProjectionImpl(defaultValue) }
}
private TypeSubstitutor replaceUninferredBySpecialErrorType() {
return replaceUninferredBy(
new Function1<TypeParameterDescriptor, TypeProjection>() {
@Override
public TypeProjection invoke(TypeParameterDescriptor descriptor) {
return new TypeProjectionImpl(ErrorUtils.createUninferredParameterType(descriptor));
}
}
);
private fun replaceUninferredBySpecialErrorType(): TypeSubstitutor {
return replaceUninferredBy { TypeProjectionImpl(ErrorUtils.createUninferredParameterType(it)) }
}
@NotNull
@Override
public ConstraintSystemStatus getStatus() {
return constraintSystemStatus;
}
override fun getStatus(): ConstraintSystemStatus = constraintSystemStatus
@Override
public void registerTypeVariables(@NotNull Map<TypeParameterDescriptor, Variance> typeVariables) {
for (Map.Entry<TypeParameterDescriptor, Variance> entry : typeVariables.entrySet()) {
TypeParameterDescriptor typeVariable = entry.getKey();
Variance positionVariance = entry.getValue();
typeParameterBounds.put(typeVariable, new TypeBoundsImpl(typeVariable, positionVariance));
override fun registerTypeVariables(typeVariables: Map<TypeParameterDescriptor, Variance>) {
for ((typeVariable, positionVariance) in typeVariables) {
typeParameterBounds.put(typeVariable, TypeBoundsImpl(typeVariable, positionVariance))
}
TypeSubstitutor constantSubstitutor = TypeUtils.makeConstantSubstitutor(typeParameterBounds.keySet(), DONT_CARE);
for (Map.Entry<TypeParameterDescriptor, TypeBoundsImpl> entry : typeParameterBounds.entrySet()) {
TypeParameterDescriptor typeVariable = entry.getKey();
TypeBoundsImpl typeBounds = entry.getValue();
for (JetType declaredUpperBound : typeVariable.getUpperBounds()) {
if (KotlinBuiltIns.getInstance().getNullableAnyType().equals(declaredUpperBound)) continue; //todo remove this line (?)
JetType substitutedBound = constantSubstitutor.substitute(declaredUpperBound, Variance.INVARIANT);
val constantSubstitutor = TypeUtils.makeConstantSubstitutor(typeParameterBounds.keySet(), DONT_CARE)
for ((typeVariable, typeBounds) in typeParameterBounds) {
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) {
typeBounds.addBound(UPPER_BOUND, substitutedBound, ConstraintPosition.getTypeBoundPosition(typeVariable.getIndex()));
typeBounds.addBound(UPPER_BOUND, substitutedBound, ConstraintPosition.getTypeBoundPosition(typeVariable.getIndex()))
}
}
}
}
@Override
@NotNull
public ConstraintSystem copy() {
return createNewConstraintSystemFromThis(
UtilsPackage.<TypeParameterDescriptor>identity(),
new Function1<TypeBoundsImpl, TypeBoundsImpl>() {
@Override
public TypeBoundsImpl invoke(TypeBoundsImpl typeBounds) {
return typeBounds.copy();
}
},
UtilsPackage.<ConstraintPosition>alwaysTrue()
);
public fun copy(): ConstraintSystem = createNewConstraintSystemFromThis({ it }, { it.copy() }, { true })
public fun substituteTypeVariables(typeVariablesMap: (TypeParameterDescriptor) -> TypeParameterDescriptor?): ConstraintSystem {
// type bounds are proper types and don't contain other variables
return createNewConstraintSystemFromThis(typeVariablesMap, { it }, { true })
}
@NotNull
public ConstraintSystem substituteTypeVariables(@NotNull Function1<TypeParameterDescriptor, TypeParameterDescriptor> typeVariablesMap) {
return createNewConstraintSystemFromThis(
typeVariablesMap,
// type bounds are proper types and don't contain other variables
UtilsPackage.<TypeBoundsImpl>identity(),
UtilsPackage.<ConstraintPosition>alwaysTrue()
);
public fun filterConstraintsOut(vararg excludePositions: ConstraintPosition): ConstraintSystem {
val positions = excludePositions.toSet()
return filterConstraints { !positions.contains(it) }
}
@NotNull
public ConstraintSystem filterConstraintsOut(@NotNull final ConstraintPosition excludePosition) {
return filterConstraints(new Function1<ConstraintPosition, Boolean>() {
@Override
public Boolean invoke(ConstraintPosition constraintPosition) {
return !excludePosition.equals(constraintPosition);
public fun filterConstraints(condition: (ConstraintPosition) -> Boolean): ConstraintSystem {
return createNewConstraintSystemFromThis({ it }, { it.filter(condition) }, condition)
}
public fun getSystemWithoutWeakConstraints(): ConstraintSystem {
return filterConstraints {
constraintPosition ->
// 'isStrong' for compound means 'has some strong constraints'
// but for testing absence of weak constraints we need 'has only strong constraints' here
if (constraintPosition is ConstraintPosition.CompoundConstraintPosition) {
val position = constraintPosition as ConstraintPosition.CompoundConstraintPosition
position.consistsOfOnlyStrongConstraints()
}
});
}
@NotNull
private ConstraintSystem filterConstraints(@NotNull final Function1<ConstraintPosition, Boolean> condition) {
return createNewConstraintSystemFromThis(
UtilsPackage.<TypeParameterDescriptor>identity(),
new Function1<TypeBoundsImpl, TypeBoundsImpl>() {
@Override
public TypeBoundsImpl invoke(TypeBoundsImpl typeBounds) {
return typeBounds.filter(condition);
}
},
condition
);
}
@NotNull
public ConstraintSystem getSystemWithoutWeakConstraints() {
return filterConstraints(new Function1<ConstraintPosition, Boolean>() {
@Override
public Boolean invoke(ConstraintPosition constraintPosition) {
// 'isStrong' for compound means 'has some strong constraints'
// but for testing absence of weak constraints we need 'has only strong constraints' here
if (constraintPosition instanceof ConstraintPosition.CompoundConstraintPosition) {
ConstraintPosition.CompoundConstraintPosition position =
(ConstraintPosition.CompoundConstraintPosition) constraintPosition;
return position.consistsOfOnlyStrongConstraints();
}
return constraintPosition.isStrong();
else {
constraintPosition.isStrong()
}
});
}
@NotNull
private ConstraintSystem createNewConstraintSystemFromThis(
@NotNull Function1<TypeParameterDescriptor, TypeParameterDescriptor> substituteTypeVariable,
@NotNull Function1<TypeBoundsImpl, TypeBoundsImpl> replaceTypeBounds,
@NotNull Function1<ConstraintPosition, Boolean> filterConstraintPosition
) {
ConstraintSystemImpl newSystem = new ConstraintSystemImpl();
for (Map.Entry<TypeParameterDescriptor, TypeBoundsImpl> entry : typeParameterBounds.entrySet()) {
TypeParameterDescriptor typeParameter = entry.getKey();
TypeBoundsImpl typeBounds = entry.getValue();
TypeParameterDescriptor newTypeParameter = substituteTypeVariable.invoke(typeParameter);
assert newTypeParameter != null;
newSystem.typeParameterBounds.put(newTypeParameter, replaceTypeBounds.invoke(typeBounds));
}
newSystem.errorConstraintPositions.addAll(KotlinPackage.filter(errorConstraintPositions, filterConstraintPosition));
}
private fun createNewConstraintSystemFromThis(
substituteTypeVariable: (TypeParameterDescriptor) -> TypeParameterDescriptor?,
replaceTypeBounds: (TypeBoundsImpl) -> TypeBoundsImpl,
filterConstraintPosition: (ConstraintPosition) -> Boolean
): ConstraintSystem {
val newSystem = ConstraintSystemImpl()
for ((typeParameter, typeBounds) in typeParameterBounds) {
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;
return newSystem;
newSystem.hasErrorInConstrainingTypes = hasErrorInConstrainingTypes
return newSystem
}
@Override
public void addSupertypeConstraint(
@Nullable JetType constrainingType,
@NotNull JetType subjectType,
@NotNull ConstraintPosition constraintPosition
) {
if (constrainingType != null && TypeUtils.noExpectedType(constrainingType)) return;
override fun addSupertypeConstraint(constrainingType: JetType?, subjectType: JetType, constraintPosition: ConstraintPosition) {
if (constrainingType != null && TypeUtils.noExpectedType(constrainingType)) return
addConstraint(SUB_TYPE, subjectType, constrainingType, constraintPosition);
addConstraint(SUB_TYPE, subjectType, constrainingType, constraintPosition)
}
@Override
public void addSubtypeConstraint(
@Nullable JetType constrainingType,
@NotNull JetType subjectType,
@NotNull ConstraintPosition constraintPosition
) {
addConstraint(SUB_TYPE, constrainingType, subjectType, constraintPosition);
override fun addSubtypeConstraint(constrainingType: JetType?, subjectType: JetType, constraintPosition: ConstraintPosition) {
addConstraint(SUB_TYPE, constrainingType, subjectType, constraintPosition)
}
private void addConstraint(
@NotNull ConstraintKind constraintKind,
@Nullable JetType subType,
@Nullable JetType superType,
@NotNull final ConstraintPosition constraintPosition
) {
TypeCheckingProcedure typeCheckingProcedure = new TypeCheckingProcedure(new TypingConstraints() {
@Override
public boolean assertEqualTypes(
@NotNull JetType a, @NotNull JetType b, @NotNull TypeCheckingProcedure typeCheckingProcedure
) {
doAddConstraint(EQUAL, a, b, constraintPosition, typeCheckingProcedure);
return true;
private fun addConstraint(constraintKind: ConstraintKind, subType: JetType?, superType: JetType?, constraintPosition: ConstraintPosition) {
val typeCheckingProcedure = TypeCheckingProcedure(object : TypingConstraints {
override fun assertEqualTypes(a: JetType, b: JetType, typeCheckingProcedure: TypeCheckingProcedure): Boolean {
doAddConstraint(EQUAL, a, b, constraintPosition, typeCheckingProcedure)
return true
}
@Override
public boolean assertEqualTypeConstructors(
@NotNull TypeConstructor a, @NotNull TypeConstructor b
) {
return a.equals(b);
override fun assertEqualTypeConstructors(a: TypeConstructor, b: TypeConstructor): Boolean {
return a == b
}
@Override
public boolean assertSubtype(
@NotNull JetType subtype, @NotNull JetType supertype, @NotNull TypeCheckingProcedure typeCheckingProcedure
) {
doAddConstraint(SUB_TYPE, subtype, supertype, constraintPosition, typeCheckingProcedure);
return true;
override fun assertSubtype(subtype: JetType, supertype: JetType, typeCheckingProcedure: TypeCheckingProcedure): Boolean {
doAddConstraint(SUB_TYPE, subtype, supertype, constraintPosition, typeCheckingProcedure)
return true
}
@Override
public boolean noCorrespondingSupertype(
@NotNull JetType subtype, @NotNull JetType supertype
) {
errorConstraintPositions.add(constraintPosition);
return true;
override fun noCorrespondingSupertype(subtype: JetType, supertype: JetType): Boolean {
errorConstraintPositions.add(constraintPosition)
return true
}
});
doAddConstraint(constraintKind, subType, superType, constraintPosition, typeCheckingProcedure);
})
doAddConstraint(constraintKind, subType, superType, constraintPosition, typeCheckingProcedure)
}
private boolean isErrorOrSpecialType(@Nullable JetType type) {
private fun isErrorOrSpecialType(type: JetType?): Boolean {
if (TypeUtils.isDontCarePlaceholder(type) || ErrorUtils.isUninferredParameter(type)) {
return true;
return true
}
if (type == null || (type.isError() && type != TypeUtils.PLACEHOLDER_FUNCTION_TYPE)) {
hasErrorInConstrainingTypes = true;
return true;
hasErrorInConstrainingTypes = true
return true
}
return false;
return false
}
private void doAddConstraint(
@NotNull ConstraintKind constraintKind,
@Nullable JetType subType,
@Nullable JetType superType,
@NotNull ConstraintPosition constraintPosition,
@NotNull TypeCheckingProcedure typeCheckingProcedure
private fun doAddConstraint(
constraintKind: ConstraintKind,
subType: JetType?,
superType: JetType?,
constraintPosition: ConstraintPosition,
typeCheckingProcedure: TypeCheckingProcedure
) {
if (isErrorOrSpecialType(subType) || isErrorOrSpecialType(superType)) return
if (subType == null || superType == null) return
if (isErrorOrSpecialType(subType) || isErrorOrSpecialType(superType)) return;
assert subType != null && superType != null;
assert superType != TypeUtils.PLACEHOLDER_FUNCTION_TYPE : "The type for " + constraintPosition + " shouldn't be a placeholder for function type";
assert(superType != TypeUtils.PLACEHOLDER_FUNCTION_TYPE) {
"The type for " + constraintPosition + " shouldn't be a placeholder for function type"
}
if (subType == TypeUtils.PLACEHOLDER_FUNCTION_TYPE) {
if (!KotlinBuiltIns.isFunctionOrExtensionFunctionType(superType)) {
if (isMyTypeVariable(superType)) {
// a constraint binds type parameter and any function type, so there is no new info and no error
return;
return
}
errorConstraintPositions.add(constraintPosition);
errorConstraintPositions.add(constraintPosition)
}
return;
return
}
// todo temporary hack
// function literal without declaring receiver type { x -> ... }
// can be considered as extension function if one is expected
// (special type constructor for function/ extension function should be introduced like PLACEHOLDER_FUNCTION_TYPE)
if (constraintKind == SUB_TYPE && KotlinBuiltIns.isFunctionType(subType) && KotlinBuiltIns.isExtensionFunctionType(superType)) {
subType = createCorrespondingExtensionFunctionType(subType, DONT_CARE);
val newSubType = if (constraintKind == SUB_TYPE
&& KotlinBuiltIns.isFunctionType(subType)
&& KotlinBuiltIns.isExtensionFunctionType(superType)) {
createCorrespondingExtensionFunctionType(subType, DONT_CARE)
}
else {
subType : JetType
}
// can be equal for the recursive invocations:
// fun <T> foo(i: Int) : T { ... return foo(i); } => T <: T
if (isMyTypeVariable(subType) && isMyTypeVariable(superType) && JetTypeChecker.DEFAULT.equalTypes(subType, superType)) return;
fun simplifyConstraint(subType: JetType, superType: JetType) {
// can be equal for the recursive invocations:
// fun <T> foo(i: Int) : T { ... return foo(i); } => T <: T
if (subType == superType) return
//todo temporary hack KT-6320
if (isMyTypeVariable(subType) && isMyTypeVariable(superType)) return;
assert !isMyTypeVariable(subType) || !isMyTypeVariable(superType) :
"The constraint shouldn't contain different type variables on both sides: " + subType + " <: " + superType;
assert(!isMyTypeVariable(subType) || !isMyTypeVariable(superType)) {
"The constraint shouldn't contain different type variables on both sides: " + subType + " <: " + superType
}
if (isMyTypeVariable(subType)) {
generateTypeParameterConstraint(subType, superType, constraintKind == SUB_TYPE ? UPPER_BOUND : EXACT_BOUND, constraintPosition);
return;
if (isMyTypeVariable(subType)) {
val boundKind = if (constraintKind == SUB_TYPE) UPPER_BOUND else EXACT_BOUND
generateTypeParameterConstraint(subType, superType, boundKind, constraintPosition)
return
}
if (isMyTypeVariable(superType)) {
val boundKind = if (constraintKind == SUB_TYPE) LOWER_BOUND else EXACT_BOUND
generateTypeParameterConstraint(superType, subType, boundKind, constraintPosition)
return
}
// if superType is nullable and subType is not nullable, unsafe call error will be generated later,
// but constraint system should be solved anyway
typeCheckingProcedure.isSubtypeOf(TypeUtils.makeNotNullable(subType), TypeUtils.makeNotNullable(superType))
}
if (isMyTypeVariable(superType)) {
generateTypeParameterConstraint(superType, subType, constraintKind == SUB_TYPE ? LOWER_BOUND : EXACT_BOUND, constraintPosition);
return;
}
// if superType is nullable and subType is not nullable, unsafe call error will be generated later,
// but constraint system should be solved anyway
typeCheckingProcedure.isSubtypeOf(TypeUtils.makeNotNullable(subType), TypeUtils.makeNotNullable(superType));
simplifyConstraint(newSubType, superType)
}
private void generateTypeParameterConstraint(
@NotNull JetType parameterType,
@NotNull JetType constrainingType,
@NotNull TypeBoundsImpl.BoundKind boundKind,
@NotNull ConstraintPosition constraintPosition
private fun generateTypeParameterConstraint(
parameterType: JetType,
constrainingType: JetType,
boundKind: TypeBounds.BoundKind,
constraintPosition: ConstraintPosition
) {
// Here we are handling the case when T! gets a bound Foo (or Foo?)
// In this case, type parameter T is supposed to get the bound Foo!
// Example:
// val c: Collection<Foo> = Collections.singleton(null : Foo?)
// Constraints for T are:
// Foo? <: T!
// Foo >: T!
// both Foo and Foo? transform to Foo! here
if (TypesPackage.isFlexible(parameterType)) {
CustomTypeVariable typeVariable = TypesPackage.getCustomTypeVariable(parameterType);
if (typeVariable != null) {
constrainingType = typeVariable.substitutionResult(constrainingType);
}
}
TypeBoundsImpl typeBounds = getTypeBounds(parameterType);
assert typeBounds != null : "constraint should be generated only for type variables";
val typeBounds = getTypeBounds(parameterType).sure("constraint should be generated only for type variables")
if (!parameterType.isMarkedNullable() || !constrainingType.isMarkedNullable()) {
typeBounds.addBound(boundKind, constrainingType, constraintPosition);
return;
typeBounds.addBound(boundKind, constrainingType, constraintPosition)
return
}
// For parameter type T:
// constraint T? = Int? should transform to T >: Int and T <: Int?
// constraint T? >: Int? should transform to T >: Int
JetType notNullConstrainingType = TypeUtils.makeNotNullable(constrainingType);
val notNullConstrainingType = TypeUtils.makeNotNullable(constrainingType)
if (boundKind == EXACT_BOUND || boundKind == LOWER_BOUND) {
typeBounds.addBound(LOWER_BOUND, notNullConstrainingType, constraintPosition);
typeBounds.addBound(LOWER_BOUND, notNullConstrainingType, constraintPosition)
}
// constraint T? <: Int? should transform to T <: Int?
if (boundKind == EXACT_BOUND || boundKind == UPPER_BOUND) {
typeBounds.addBound(UPPER_BOUND, constrainingType, constraintPosition);
typeBounds.addBound(UPPER_BOUND, constrainingType, constraintPosition)
}
}
public void processDeclaredBoundConstraints() {
for (Map.Entry<TypeParameterDescriptor, TypeBoundsImpl> entry : typeParameterBounds.entrySet()) {
TypeParameterDescriptor typeParameterDescriptor = entry.getKey();
TypeBoundsImpl typeBounds = entry.getValue();
for (JetType declaredUpperBound : typeParameterDescriptor.getUpperBounds()) {
public fun processDeclaredBoundConstraints() {
for ((typeParameterDescriptor, typeBounds) in typeParameterBounds) {
for (declaredUpperBound in typeParameterDescriptor.getUpperBounds()) {
//todo order matters here
Collection<Bound> bounds = new ArrayList<Bound>(typeBounds.getBounds());
for (Bound bound : bounds) {
val bounds = ArrayList(typeBounds.bounds)
for (bound in bounds) {
if (bound.kind == LOWER_BOUND || bound.kind == EXACT_BOUND) {
ConstraintPosition position = ConstraintPosition.getCompoundConstraintPosition(
ConstraintPosition.getTypeBoundPosition(typeParameterDescriptor.getIndex()), bound.position);
addSubtypeConstraint(bound.type, declaredUpperBound, position);
val position = ConstraintPosition.getCompoundConstraintPosition(ConstraintPosition.getTypeBoundPosition(typeParameterDescriptor.getIndex()), bound.position)
addSubtypeConstraint(bound.constrainingType, declaredUpperBound, position)
}
}
ClassifierDescriptor declarationDescriptor = declaredUpperBound.getConstructor().getDeclarationDescriptor();
if (declarationDescriptor instanceof TypeParameterDescriptor && typeParameterBounds.containsKey(declarationDescriptor)) {
TypeBoundsImpl typeBoundsForUpperBound = typeParameterBounds.get(declarationDescriptor);
for (Bound bound : typeBoundsForUpperBound.getBounds()) {
val declarationDescriptor = declaredUpperBound.getConstructor().getDeclarationDescriptor()
if (declarationDescriptor is TypeParameterDescriptor && typeParameterBounds.containsKey(declarationDescriptor)) {
val typeBoundsForUpperBound = typeParameterBounds.get(declarationDescriptor)
for (bound in typeBoundsForUpperBound!!.bounds) {
if (bound.kind == UPPER_BOUND || bound.kind == EXACT_BOUND) {
ConstraintPosition position = ConstraintPosition.getCompoundConstraintPosition(
ConstraintPosition.getTypeBoundPosition(typeParameterDescriptor.getIndex()), bound.position);
typeBounds.addBound(UPPER_BOUND, bound.type, position);
val position = ConstraintPosition.getCompoundConstraintPosition(ConstraintPosition.getTypeBoundPosition(typeParameterDescriptor.getIndex()), bound.position)
typeBounds.addBound(UPPER_BOUND, bound.constrainingType, position)
}
}
}
@@ -479,64 +352,47 @@ public class ConstraintSystemImpl implements ConstraintSystem {
}
}
@NotNull
@Override
public Set<TypeParameterDescriptor> getTypeVariables() {
return typeParameterBounds.keySet();
override fun getTypeVariables() = typeParameterBounds.keySet()
override fun getTypeBounds(typeVariable: TypeParameterDescriptor): TypeBounds {
return typeParameterBounds.get(typeVariable).sure(
"TypeParameterDescriptor is not a type variable for constraint system: $typeVariable")
}
@Override
@NotNull
public TypeBounds getTypeBounds(@NotNull TypeParameterDescriptor typeVariable) {
TypeBoundsImpl typeBounds = typeParameterBounds.get(typeVariable);
assert typeBounds != null : "TypeParameterDescriptor is not a type variable for constraint system: " + typeVariable;
return typeBounds;
}
@Nullable
private TypeBoundsImpl getTypeBounds(@NotNull JetType type) {
ClassifierDescriptor parameterDescriptor = type.getConstructor().getDeclarationDescriptor();
if (parameterDescriptor instanceof TypeParameterDescriptor) {
return typeParameterBounds.get(parameterDescriptor);
private fun getTypeBounds(type: JetType): TypeBoundsImpl? {
val parameterDescriptor = type.getConstructor().getDeclarationDescriptor()
if (parameterDescriptor is TypeParameterDescriptor) {
return typeParameterBounds.get(parameterDescriptor)
}
return null;
return null
}
private boolean isMyTypeVariable(@NotNull JetType type) {
ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
return descriptor instanceof TypeParameterDescriptor && typeParameterBounds.get(descriptor) != null;
private fun isMyTypeVariable(type: JetType): Boolean {
val descriptor = type.getConstructor().getDeclarationDescriptor()
return descriptor is TypeParameterDescriptor && typeParameterBounds.get(descriptor) != null
}
@NotNull
@Override
public TypeSubstitutor getResultingSubstitutor() {
return replaceUninferredBySpecialErrorType();
}
override fun getResultingSubstitutor() = replaceUninferredBySpecialErrorType()
@NotNull
@Override
public TypeSubstitutor getCurrentSubstitutor() {
return replaceUninferredBy(TypeUtils.DONT_CARE);
}
override fun getCurrentSubstitutor() = replaceUninferredBy(TypeUtils.DONT_CARE)
@NotNull
public static JetType createCorrespondingExtensionFunctionType(@NotNull JetType functionType, @NotNull JetType receiverType) {
assert KotlinBuiltIns.isFunctionType(functionType);
private fun createCorrespondingExtensionFunctionType(functionType: JetType, receiverType: JetType): JetType {
assert(KotlinBuiltIns.isFunctionType(functionType))
List<TypeProjection> typeArguments = functionType.getArguments();
assert !typeArguments.isEmpty();
val typeArguments = functionType.getArguments()
assert(!typeArguments.isEmpty())
val arguments = ArrayList<JetType>()
// excluding the last type argument of the function type, which is the return type
int index = 0;
int lastIndex = typeArguments.size() - 1;
List<JetType> arguments = new ArrayList<JetType>(lastIndex);
for (TypeProjection typeArgument : typeArguments) {
var index = 0
val lastIndex = typeArguments.size() - 1
for (typeArgument in typeArguments) {
if (index < lastIndex) {
arguments.add(typeArgument.getType());
arguments.add(typeArgument.getType())
}
index++;
index++
}
JetType returnType = typeArguments.get(lastIndex).getType();
return KotlinBuiltIns.getInstance().getFunctionType(functionType.getAnnotations(), receiverType, arguments, returnType);
val returnType = typeArguments.get(lastIndex).getType()
return KotlinBuiltIns.getInstance().getFunctionType(functionType.getAnnotations(), receiverType, arguments, returnType)
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
* Copyright 2010-2014 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.
@@ -14,24 +14,18 @@
* limitations under the License.
*/
package org.jetbrains.jet.lang.resolve.calls.inference;
package org.jetbrains.jet.lang.resolve.calls.inference
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeSubstitutor;
public interface ConstraintSystemStatus {
public trait ConstraintSystemStatus {
/**
* Returns <tt>true</tt> if constraint system has a solution (has no contradiction and has enough information to infer each registered type variable).
*/
boolean isSuccessful();
public fun isSuccessful(): Boolean
/**
* Return <tt>true</tt> if constraint system has no contradiction (it can be not successful because of the lack of information for a type variable).
*/
boolean hasContradiction();
public fun hasContradiction(): Boolean
/**
* Returns <tt>true</tt> if type constraints for some type variable are contradicting. <p/>
@@ -41,7 +35,7 @@ public interface ConstraintSystemStatus {
* - <tt>"R is a supertype of Int"</tt> <p/>
* - <tt>"List&lt;R&gt; is a supertype of List&lt;String&gt;"</tt> which leads to <tt>"R is equal to String"</tt>
*/
boolean hasConflictingConstraints();
public fun hasConflictingConstraints(): Boolean
/**
* Returns <tt>true</tt> if contradiction of type constraints comes from declared bounds for type parameters.
@@ -51,7 +45,7 @@ public interface ConstraintSystemStatus {
*
* It's the special case of 'hasConflictingConstraints' case.
*/
boolean hasViolatedUpperBound();
public fun hasViolatedUpperBound(): Boolean
/**
* Returns <tt>true</tt> if there is no information for some registered type variable.
@@ -59,7 +53,7 @@ public interface ConstraintSystemStatus {
* For example, for <pre>fun &lt;E&gt; newList()</pre> in invocation <tt>"val nl = newList()"</tt>
* there is no information to infer type variable <tt>E</tt>.
*/
boolean hasUnknownParameters();
public fun hasUnknownParameters(): Boolean
/**
* Returns <tt>true</tt> if some constraint cannot be processed because of type constructor mismatch.
@@ -67,7 +61,7 @@ public interface ConstraintSystemStatus {
* For example, for <pre>fun &lt;R&gt; foo(t: List&lt;R&gt;) {}</pre> in invocation <tt>foo(hashSet("s"))</tt>
* there is type constructor mismatch: <tt>"HashSet&lt;String&gt; cannot be a subtype of List&lt;R&gt;"</tt>.
*/
boolean hasTypeConstructorMismatch();
public fun hasTypeConstructorMismatch(): Boolean
/**
* Returns <tt>true</tt> if there is type constructor mismatch error at a specific {@code constraintPosition}.
@@ -76,17 +70,17 @@ public interface ConstraintSystemStatus {
* there is type constructor mismatch: <tt>"HashSet&lt;String&gt; cannot be a subtype of List&lt;R&gt;"</tt>
* at a constraint position {@code ConstraintPosition.getValueParameterPosition(0)}.
*/
boolean hasTypeConstructorMismatchAt(@NotNull ConstraintPosition constraintPosition);
public fun hasTypeConstructorMismatchAt(constraintPosition: ConstraintPosition): Boolean
/**
* Returns <tt>true</tt> if there is type constructor mismatch only in constraintPosition or
* constraint system is successful without constraints from this position.
*/
boolean hasOnlyErrorsFromPosition(ConstraintPosition constraintPosition);
public fun hasOnlyErrorsFromPosition(constraintPosition: ConstraintPosition): Boolean
/**
* Returns <tt>true</tt> if there is an error in constraining types. <p/>
* Is used not to generate type inference error if there was one in argument types.
*/
boolean hasErrorInConstrainingTypes();
}
public fun hasErrorInConstrainingTypes(): Boolean
}
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
* Copyright 2010-2014 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.
@@ -14,47 +14,30 @@
* limitations under the License.
*/
package org.jetbrains.jet.lang.resolve.calls.inference;
package org.jetbrains.jet.lang.resolve.calls.inference
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.Variance;
import org.jetbrains.jet.lang.types.Variance
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor
import org.jetbrains.jet.lang.types.JetType
import java.util.Collection;
public trait TypeBounds {
public val varianceOfPosition: Variance
public interface TypeBounds {
@NotNull
Variance getVarianceOfPosition();
public val typeVariable: TypeParameterDescriptor
@NotNull
TypeParameterDescriptor getTypeVariable();
public val bounds: Collection<Bound>
@NotNull
Collection<Bound> getBounds();
public fun isEmpty(): Boolean
boolean isEmpty();
public fun getValue(): JetType?
@Nullable
JetType getValue();
public fun getValues(): Collection<JetType>
@NotNull
Collection<JetType> getValues();
enum BoundKind {
LOWER_BOUND, UPPER_BOUND, EXACT_BOUND
public enum class BoundKind {
LOWER_BOUND
UPPER_BOUND
EXACT_BOUND
}
class Bound {
public final JetType type;
public final BoundKind kind;
public final ConstraintPosition position;
public Bound(@NotNull JetType type, @NotNull BoundKind kind, @NotNull ConstraintPosition position) {
this.type = type;
this.kind = kind;
this.position = position;
}
}
}
public class Bound(public val constrainingType: JetType, public val kind: BoundKind, public val position: ConstraintPosition)
}
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
* Copyright 2010-2014 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.
@@ -14,238 +14,163 @@
* limitations under the License.
*/
package org.jetbrains.jet.lang.resolve.calls.inference;
package org.jetbrains.jet.lang.resolve.calls.inference
import kotlin.Function1;
import kotlin.KotlinPackage;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
import org.jetbrains.jet.lang.resolve.constants.IntegerValueTypeConstructor;
import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
import org.jetbrains.jet.utils.UtilsPackage;
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor
import org.jetbrains.jet.lang.types.Variance
import org.jetbrains.jet.lang.resolve.calls.inference.TypeBounds.Bound
import org.jetbrains.jet.lang.types.JetType
import org.jetbrains.jet.lang.resolve.calls.inference.TypeBounds.BoundKind
import org.jetbrains.jet.lang.types.ErrorUtils
import org.jetbrains.jet.lang.types.CommonSupertypes
import org.jetbrains.jet.lang.types.TypeUtils
import org.jetbrains.jet.lang.types.checker.JetTypeChecker
import org.jetbrains.jet.lang.resolve.constants.IntegerValueTypeConstructor
import java.util.LinkedHashSet
import org.jetbrains.jet.lang.resolve.calls.inference.TypeBounds.BoundKind.*
import org.jetbrains.jet.utils.addIfNotNull
import java.util.*;
public class TypeBoundsImpl(
override val typeVariable: TypeParameterDescriptor,
override val varianceOfPosition: Variance
) : TypeBounds {
override val bounds = LinkedHashSet<Bound>()
import static org.jetbrains.jet.lang.resolve.calls.inference.TypeBounds.BoundKind.LOWER_BOUND;
private var resultValues: Collection<JetType>? = null
public class TypeBoundsImpl implements TypeBounds {
private final TypeParameterDescriptor typeVariable;
private final Variance varianceOfPosition;
private final Set<Bound> bounds = new LinkedHashSet<Bound>();
private Collection<JetType> resultValues;
public TypeBoundsImpl(
@NotNull TypeParameterDescriptor typeVariable,
@NotNull Variance varianceOfPosition
) {
this.typeVariable = typeVariable;
this.varianceOfPosition = varianceOfPosition;
public fun addBound(kind: BoundKind, constrainingType: JetType, position: ConstraintPosition) {
resultValues = null
bounds.add(Bound(constrainingType, kind, position))
}
@NotNull
@Override
public Variance getVarianceOfPosition() {
return varianceOfPosition;
override fun isEmpty(): Boolean {
return getValues().isEmpty()
}
public void addBound(@NotNull BoundKind kind, @NotNull JetType type, @NotNull ConstraintPosition position) {
resultValues = null;
bounds.add(new Bound(type, kind, position));
private fun filterBounds(bounds: Collection<Bound>, kind: BoundKind): Set<JetType> {
return filterBounds(bounds, kind, null)
}
@Override
public boolean isEmpty() {
return getValues().isEmpty();
}
@NotNull
@Override
public TypeParameterDescriptor getTypeVariable() {
return typeVariable;
}
@Override
@NotNull
public Collection<Bound> getBounds() {
return bounds;
}
@NotNull
private static Set<JetType> filterBounds(
@NotNull Collection<Bound> bounds,
@NotNull BoundKind kind
) {
return filterBounds(bounds, kind, null);
}
@NotNull
private static Set<JetType> filterBounds(
@NotNull Collection<Bound> bounds,
@NotNull BoundKind kind,
@Nullable Collection<JetType> errorValues
) {
Set<JetType> result = new LinkedHashSet<JetType>();
for (Bound bound : bounds) {
private fun filterBounds(bounds: Collection<Bound>, kind: BoundKind, errorValues: MutableCollection<JetType>?): Set<JetType> {
val result = LinkedHashSet<JetType>()
for (bound in bounds) {
if (bound.kind == kind) {
if (!ErrorUtils.containsErrorType(bound.type)) {
result.add(bound.type);
if (!ErrorUtils.containsErrorType(bound.constrainingType)) {
result.add(bound.constrainingType)
}
else if (errorValues != null) {
errorValues.add(bound.type);
else {
errorValues?.add(bound.constrainingType)
}
}
}
return result;
return result
}
/*package*/ TypeBoundsImpl copy() {
TypeBoundsImpl typeBounds = new TypeBoundsImpl(typeVariable, varianceOfPosition);
typeBounds.bounds.addAll(bounds);
typeBounds.resultValues = resultValues;
return typeBounds;
fun copy(): TypeBoundsImpl {
val typeBounds = TypeBoundsImpl(typeVariable, varianceOfPosition)
typeBounds.bounds.addAll(bounds)
typeBounds.resultValues = resultValues
return typeBounds
}
@NotNull
public TypeBoundsImpl filter(@NotNull final Function1<ConstraintPosition, Boolean> condition) {
TypeBoundsImpl result = new TypeBoundsImpl(typeVariable, varianceOfPosition);
result.bounds.addAll(KotlinPackage.filter(bounds, new Function1<Bound, Boolean>() {
@Override
public Boolean invoke(Bound bound) {
return condition.invoke(bound.position);
}
}));
return result;
public fun filter(condition: (ConstraintPosition) -> Boolean): TypeBoundsImpl {
val result = TypeBoundsImpl(typeVariable, varianceOfPosition)
result.bounds.addAll(bounds.filter { condition(it.position) })
return result
}
@Nullable
@Override
public JetType getValue() {
Collection<JetType> values = getValues();
override fun getValue(): JetType? {
val values = getValues()
if (values.size() == 1) {
return values.iterator().next();
return values.iterator().next()
}
return null;
return null
}
@NotNull
@Override
public Collection<JetType> getValues() {
override fun getValues(): Collection<JetType> {
if (resultValues == null) {
resultValues = computeValues();
resultValues = computeValues()
}
return resultValues;
return resultValues!!
}
@NotNull
private Collection<JetType> computeValues() {
Set<JetType> values = new LinkedHashSet<JetType>();
private fun computeValues(): Collection<JetType> {
val values = LinkedHashSet<JetType>()
if (bounds.isEmpty()) {
return Collections.emptyList();
return listOf()
}
boolean hasStrongBound = KotlinPackage.any(bounds, new Function1<Bound, Boolean>() {
@Override
public Boolean invoke(Bound bound) {
return bound.position.isStrong();
}
});
val hasStrongBound = bounds.any { it.position.isStrong() }
if (!hasStrongBound) {
return Collections.emptyList();
return listOf()
}
Set<JetType> exactBounds = filterBounds(bounds, BoundKind.EXACT_BOUND, values);
JetType bestFit = TypesPackage.singleBestRepresentative(exactBounds);
if (bestFit != null) {
if (tryPossibleAnswer(bestFit)) {
return Collections.singleton(bestFit);
val exactBounds = filterBounds(bounds, EXACT_BOUND, values)
if (exactBounds.size() == 1) {
val exactBound = exactBounds.iterator().next()
if (tryPossibleAnswer(exactBound)) {
return setOf(exactBound)
}
}
values.addAll(exactBounds);
values.addAll(exactBounds)
Collection<JetType> numberLowerBounds = new LinkedHashSet<JetType>();
Collection<JetType> generalLowerBounds = new LinkedHashSet<JetType>();
filterNumberTypes(filterBounds(bounds, LOWER_BOUND, values), numberLowerBounds, generalLowerBounds);
val (numberLowerBounds, generalLowerBounds) =
filterBounds(bounds, LOWER_BOUND, values).partition { it.getConstructor() is IntegerValueTypeConstructor }
JetType superTypeOfLowerBounds = CommonSupertypes.commonSupertypeForNonDenotableTypes(generalLowerBounds);
val superTypeOfLowerBounds = CommonSupertypes.commonSupertypeForNonDenotableTypes(generalLowerBounds)
if (tryPossibleAnswer(superTypeOfLowerBounds)) {
return Collections.singleton(superTypeOfLowerBounds);
return setOf(superTypeOfLowerBounds!!)
}
UtilsPackage.addIfNotNull(values, superTypeOfLowerBounds);
values.addIfNotNull(superTypeOfLowerBounds)
//todo
//fun <T> foo(t: T, consumer: Consumer<T>): T
//foo(1, c: Consumer<Any>) - infer Int, not Any here
JetType superTypeOfNumberLowerBounds = TypeUtils.commonSupertypeForNumberTypes(numberLowerBounds);
val superTypeOfNumberLowerBounds = TypeUtils.commonSupertypeForNumberTypes(numberLowerBounds)
if (tryPossibleAnswer(superTypeOfNumberLowerBounds)) {
return Collections.singleton(superTypeOfNumberLowerBounds);
return setOf(superTypeOfNumberLowerBounds!!)
}
UtilsPackage.addIfNotNull(values, superTypeOfNumberLowerBounds);
values.addIfNotNull(superTypeOfNumberLowerBounds)
if (superTypeOfLowerBounds != null && superTypeOfNumberLowerBounds != null) {
JetType superTypeOfAllLowerBounds = CommonSupertypes.commonSupertypeForNonDenotableTypes(
Arrays.asList(superTypeOfLowerBounds, superTypeOfNumberLowerBounds)
);
val superTypeOfAllLowerBounds = CommonSupertypes.commonSupertypeForNonDenotableTypes(listOf(superTypeOfLowerBounds, superTypeOfNumberLowerBounds))
if (tryPossibleAnswer(superTypeOfAllLowerBounds)) {
return Collections.singleton(superTypeOfAllLowerBounds);
return setOf(superTypeOfAllLowerBounds!!)
}
}
Set<JetType> upperBounds = filterBounds(bounds, BoundKind.UPPER_BOUND, values);
JetType intersectionOfUpperBounds = TypeUtils.intersect(JetTypeChecker.DEFAULT, upperBounds);
val upperBounds = filterBounds(bounds, TypeBounds.BoundKind.UPPER_BOUND, values)
val intersectionOfUpperBounds = TypeUtils.intersect(JetTypeChecker.DEFAULT, upperBounds)
if (!upperBounds.isEmpty() && intersectionOfUpperBounds != null) {
if (tryPossibleAnswer(intersectionOfUpperBounds)) {
return Collections.singleton(intersectionOfUpperBounds);
return setOf(intersectionOfUpperBounds)
}
}
values.addAll(filterBounds(bounds, BoundKind.UPPER_BOUND));
values.addAll(filterBounds(bounds, TypeBounds.BoundKind.UPPER_BOUND))
return values;
return values
}
private static void filterNumberTypes(
@NotNull Collection<JetType> types,
@NotNull Collection<JetType> numberTypes,
@NotNull Collection<JetType> otherTypes
) {
for (JetType type : types) {
if (type.getConstructor() instanceof IntegerValueTypeConstructor) {
numberTypes.add(type);
}
else {
otherTypes.add(type);
private fun tryPossibleAnswer(possibleAnswer: JetType?): Boolean {
if (possibleAnswer == null) return false
if (!possibleAnswer.getConstructor().isDenotable()) return false
for (bound in bounds) {
when (bound.kind) {
LOWER_BOUND -> if (!JetTypeChecker.DEFAULT.isSubtypeOf(bound.constrainingType, possibleAnswer)) {
return false
}
UPPER_BOUND -> if (!JetTypeChecker.DEFAULT.isSubtypeOf(possibleAnswer, bound.constrainingType)) {
return false
}
EXACT_BOUND -> if (!JetTypeChecker.DEFAULT.equalTypes(bound.constrainingType, possibleAnswer)) {
return false
}
}
}
return true
}
private boolean tryPossibleAnswer(@Nullable JetType possibleAnswer) {
if (possibleAnswer == null) return false;
if (!possibleAnswer.getConstructor().isDenotable()) return false;
for (Bound bound : bounds) {
switch (bound.kind) {
case LOWER_BOUND:
if (!JetTypeChecker.DEFAULT.isSubtypeOf(bound.type, possibleAnswer)) {
return false;
}
break;
case UPPER_BOUND:
if (!JetTypeChecker.DEFAULT.isSubtypeOf(possibleAnswer, bound.type)) {
return false;
}
break;
case EXACT_BOUND:
if (!JetTypeChecker.DEFAULT.equalTypes(bound.type, possibleAnswer)) {
return false;
}
break;
}
}
return true;
}
}
}
@@ -711,6 +711,7 @@ public class TypeUtils {
});
}
@NotNull
public static TypeSubstitutor makeSubstitutorForTypeParametersMap(
@NotNull final Map<TypeParameterDescriptor, TypeProjection> substitutionContext
) {